''[Sarnold] 2005-09-02'' - After playing some time with [Mancala], I improved the AI, but did encounter some perf issues. So I decided to write the most used function in C with [Critcl]. Here is the C procedure for the move : critcl::cproc cmove {char* vboard int player int pit} string { int go_again=0; int side; int board[2][6]; int store[2]; int i; int orig_side,orig_pit,their_pit,opp; int stones=0; char temp; char error[10]="error"; char result[15+1]; /* 12 for the holes, 2 for the stores, 1 for go_again and 1 null-termination */ /* initialization of the board */ orig_side=side=player; orig_pit=pit; for (i=0;i<14;i++) { temp=vboard[i]; if (temp>='0' && temp<='9') { temp=temp-'0'; } else { temp=temp+10-'a'; } if (i<12) { board[i/6][i%6]=(int) temp; } else { store[13-i]=(int) temp; } } for (i=0;i<16;i++) {result[i]='\0';} stones=board[side][pit]; if (stones == 0) { /* for debugging */ /* error[5]=vboard[side*6+pit]; error[6]='a'+(char)(side*6+pit); */ return "error"; } pit++; while (stones > 0) { /* decrement the origin from one stone */ stones--; board[orig_side][orig_pit]--; if (pit >= 6) { /* in that case we put a stone into one of the 2 stores. */ store[side]++; /* when we put the last stone into the store of the opponent, ** it should be the turn of the opponent */ go_again= (side==player || stones!=0); pit=0; side=!side; } else { go_again =0; i = ++board[side][pit]; /* See if we captured any opponent stones */ if (stones==0 && player==side && i == 1) { opp=!side; their_pit=5-pit; /* capture_opposite */ if (board[opp][their_pit]!=0) { store[side]+=1+board[opp][their_pit]; board[side][pit]=0; board[opp][their_pit]=0; } temp=(char)go_again; temp=(temp<10)?'0'+temp:'a'-10+temp; result[0]=temp; for (i=0;i<14;i++) { if (i<12) { temp=(char)board[i/6][i%6]; } else { temp=(char)store[13-i]; } result[i+1]=(temp<10)?'0'+temp:'a'-10+temp; } return result; } pit++; } } /* converting board, go_again and store for returning a base-36 string */ temp=(char)go_again; temp=(temp<10)?'0'+temp:'a'-10+temp; result[0]=temp; for (i=0;i<14;i++) { if (i<12) { temp=(char)board[i/6][i%6]; } else { temp=(char)store[13-i]; } result[i+1]=(temp<10)?'0'+temp:'a'-10+temp; } return result; } It takes as arguments : the board which is a list of number converted to a string (char* type), and two integers : side and go_again, both booleans. The board is translated to a string using base-36 representation. The result returned is a string containing : * go_again, converted to base-36 * the modified board, appended as a string Here is the tcl wrapping : * into the global level: set t "0123456789abcdefghijklmnopqrstuvwxyz" for {set i 0} {$i<36} {incr i} { set coding([string index $t $i]) $i } * into the move proc : set bvalue "" set code "0123456789abcdefghijklmnopqrstuvwxyz" foreach i $board { append bvalue [string index $code $i] } # cmove is our C proc set res [cmove $bvalue $player $pit] if {[string equal $res error]} { error "error in move" } set go_again [string first [string index $res 0] $code] set l [string length [set res [string range $res 1 end]]] for {set i 0} {$i<$l} {incr i} { lset board $i $::coding([string index $res $i]) } return [list $go_again $board] ---- '''Compiling issues''' Having MinGW/MSys on my WindowsME machine, it was needed for compiling that I was in the Msys environment. So I ran Msys and launch this command : /d/tcl/bin/tclsh.exe critcl.kit -force -lib cmancala cmancala.tcl , where ''cmancala.tcl'' is our cproc definition. Then to access the cmove proc : tclsh % load cmancala.dll % cmove 33333333333300 0 0 004443333333300 That's it ! ---- [Category Critcl]