| /* |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are met: |
| |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| |
| * Redistributions in binary form must reproduce the above copyright |
| notice, this list of conditions and the following disclaimer in the |
| documentation and/or other materials provided with the distribution. |
| |
| * Neither the name of "The Computer Language Benchmarks Game" nor the |
| name of "The Computer Language Shootout Benchmarks" nor the names of |
| its contributors may be used to endorse or promote products derived |
| from this software without specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* The Computer Language Benchmarks Game |
| http://shootout.alioth.debian.org/ |
| |
| contributed by Michael Barker |
| based on a Java contribution by Luzius Meisser |
| |
| convert to C by dualamd |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <pthread.h> |
| |
| |
| enum Colour |
| { |
| blue = 0, |
| red = 1, |
| yellow = 2, |
| Invalid = 3 |
| }; |
| |
| const char* ColourName[] = {"blue", "red", "yellow"}; |
| const int STACK_SIZE = 32*1024; |
| |
| typedef unsigned int BOOL; |
| const BOOL TRUE = 1; |
| const BOOL FALSE = 0; |
| |
| int CreatureID = 0; |
| |
| |
| enum Colour doCompliment(enum Colour c1, enum Colour c2) |
| { |
| switch (c1) |
| { |
| case blue: |
| switch (c2) |
| { |
| case blue: |
| return blue; |
| case red: |
| return yellow; |
| case yellow: |
| return red; |
| default: |
| goto errlb; |
| } |
| case red: |
| switch (c2) |
| { |
| case blue: |
| return yellow; |
| case red: |
| return red; |
| case yellow: |
| return blue; |
| default: |
| goto errlb; |
| } |
| case yellow: |
| switch (c2) |
| { |
| case blue: |
| return red; |
| case red: |
| return blue; |
| case yellow: |
| return yellow; |
| default: |
| goto errlb; |
| } |
| default: |
| break; |
| } |
| |
| errlb: |
| printf("Invalid colour\n"); |
| exit( 1 ); |
| } |
| |
| /* convert integer to number string: 1234 -> "one two three four" */ |
| char* formatNumber(int n, char* outbuf) |
| { |
| int ochar = 0, ichar = 0; |
| int i; |
| char tmp[64]; |
| |
| const char* NUMBERS[] = |
| { |
| "zero", "one", "two", "three", "four", "five", |
| "six", "seven", "eight", "nine" |
| }; |
| |
| ichar = sprintf(tmp, "%d", n); |
| |
| for (i = 0; i < ichar; i++) |
| ochar += sprintf( outbuf + ochar, " %s", NUMBERS[ tmp[i] - '0' ] ); |
| |
| return outbuf; |
| } |
| |
| |
| struct MeetingPlace |
| { |
| pthread_mutex_t mutex; |
| int meetingsLeft; |
| struct Creature* firstCreature; |
| }; |
| |
| struct Creature |
| { |
| pthread_t ht; |
| pthread_attr_t stack_att; |
| |
| struct MeetingPlace* place; |
| int count; |
| int sameCount; |
| |
| enum Colour colour; |
| int id; |
| |
| BOOL two_met; |
| BOOL sameid; |
| }; |
| |
| |
| void MeetingPlace_Init(struct MeetingPlace* m, int meetings ) |
| { |
| pthread_mutex_init( &m->mutex, 0 ); |
| m->meetingsLeft = meetings; |
| m->firstCreature = 0; |
| } |
| |
| |
| BOOL Meet( struct Creature* cr) |
| { |
| BOOL retval = TRUE; |
| |
| struct MeetingPlace* mp = cr->place; |
| pthread_mutex_lock( &(mp->mutex) ); |
| |
| if ( mp->meetingsLeft > 0 ) |
| { |
| if ( mp->firstCreature == 0 ) |
| { |
| cr->two_met = FALSE; |
| mp->firstCreature = cr; |
| } |
| else |
| { |
| struct Creature* first; |
| enum Colour newColour; |
| |
| first = mp->firstCreature; |
| newColour = doCompliment( cr->colour, first->colour ); |
| |
| cr->sameid = cr->id == first->id; |
| cr->colour = newColour; |
| cr->two_met = TRUE; |
| |
| first->sameid = cr->sameid; |
| first->colour = newColour; |
| first->two_met = TRUE; |
| |
| mp->firstCreature = 0; |
| mp->meetingsLeft--; |
| } |
| } |
| else |
| retval = FALSE; |
| |
| pthread_mutex_unlock( &(mp->mutex) ); |
| return retval; |
| } |
| |
| |
| void* CreatureThreadRun(void* param) |
| { |
| struct Creature* cr = (struct Creature*)param; |
| |
| while (TRUE) |
| { |
| if ( Meet(cr) ) |
| { |
| while (cr->two_met == FALSE) |
| sched_yield(); |
| |
| if (cr->sameid) |
| cr->sameCount++; |
| cr->count++; |
| } |
| else |
| break; |
| } |
| |
| return 0; |
| } |
| |
| void Creature_Init( struct Creature *cr, struct MeetingPlace* place, enum Colour colour ) |
| { |
| cr->place = place; |
| cr->count = cr->sameCount = 0; |
| |
| cr->id = ++CreatureID; |
| cr->colour = colour; |
| cr->two_met = FALSE; |
| |
| pthread_attr_init( &cr->stack_att ); |
| pthread_attr_setstacksize( &cr->stack_att, STACK_SIZE ); |
| pthread_create( &cr->ht, &cr->stack_att, &CreatureThreadRun, (void*)(cr) ); |
| } |
| |
| /* format meeting times of each creature to string */ |
| char* Creature_getResult(struct Creature* cr, char* str) |
| { |
| char numstr[256]; |
| formatNumber(cr->sameCount, numstr); |
| |
| sprintf( str, "%u%s", cr->count, numstr ); |
| return str; |
| } |
| |
| |
| void runGame( int n_meeting, int ncolor, const enum Colour* colours ) |
| { |
| int i; |
| int total = 0; |
| char str[256]; |
| |
| struct MeetingPlace place; |
| struct Creature *creatures = (struct Creature*) calloc( ncolor, sizeof(struct Creature) ); |
| |
| MeetingPlace_Init( &place, n_meeting ); |
| |
| /* print initial color of each creature */ |
| for (i = 0; i < ncolor; i++) |
| { |
| printf( "%s ", ColourName[ colours[i] ] ); |
| Creature_Init( &(creatures[i]), &place, colours[i] ); |
| } |
| printf("\n"); |
| |
| /* wait for them to meet */ |
| for (i = 0; i < ncolor; i++) |
| pthread_join( creatures[i].ht, 0 ); |
| |
| /* print meeting times of each creature */ |
| for (i = 0; i < ncolor; i++) |
| { |
| printf( "%s\n", Creature_getResult(&(creatures[i]), str) ); |
| total += creatures[i].count; |
| } |
| |
| /* print total meeting times, should equal n_meeting */ |
| printf( "%s\n\n", formatNumber(total, str) ); |
| |
| /* cleaup & quit */ |
| pthread_mutex_destroy( &place.mutex ); |
| free( creatures ); |
| } |
| |
| |
| void printColours( enum Colour c1, enum Colour c2 ) |
| { |
| printf( "%s + %s -> %s\n", |
| ColourName[c1], |
| ColourName[c2], |
| ColourName[doCompliment(c1, c2)] ); |
| } |
| |
| void printColoursTable(void) |
| { |
| printColours(blue, blue); |
| printColours(blue, red); |
| printColours(blue, yellow); |
| printColours(red, blue); |
| printColours(red, red); |
| printColours(red, yellow); |
| printColours(yellow, blue); |
| printColours(yellow, red); |
| printColours(yellow, yellow); |
| } |
| |
| int main(int argc, char** argv) |
| { |
| int n = (argc == 2) ? atoi(argv[1]) : 600; |
| |
| printColoursTable(); |
| printf("\n"); |
| |
| const enum Colour r1[] = { blue, red, yellow }; |
| const enum Colour r2[] = { blue, red, yellow, |
| red, yellow, blue, |
| red, yellow, red, blue }; |
| |
| runGame( n, sizeof(r1) / sizeof(r1[0]), r1 ); |
| runGame( n, sizeof(r2) / sizeof(r2[0]), r2 ); |
| |
| return 0; |
| } |