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 board26;
int store2;
int i;
int orig_side,orig_pit,their_pit,opp;
int stones=0;
char temp;
int walk=0; /* to walk through the result */
char error10="error";
char result45+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;
i=walk=0;
while (vboardi!='\0') {
temp=0;
while (vboardi!=' '&& vboardi!='\0') {
if (vboardi<'0'||vboardi>'9') {
return "error";
}
temp=temp*10+vboardi-'0';
i++;
if (temp>36) {
return "error";
}
}
if (walk<12) {
boardwalk/6walk%6=(int) temp;
} else {
store13-walk=(int) temp;
}
walk++;
i++;
if (walk>13) {
break;
}
}
for (i=0;i<sizeof(result);i++) {resulti='\0';}
/* initialization ending */
/* begin moving */
stones=boardsidepit;
if (stones == 0) {
/* for debugging */
/* error5=vboardside*6+pit;
error6='a'+(char)(side*6+pit); */
return "error";
}
pit++;
while (stones > 0) {
/* decrement the origin from one stone */
stones--;
boardorig_sideorig_pit--;
if (pit >= 6) {
/* in that case we put a stone into one of the 2 stores. */
storeside++;
/* 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 = ++boardsidepit;
/* See if we captured any opponent stones */
if (stones==0 && player==side && i == 1) {
opp=!side;
their_pit=5-pit;
/* capture_opposite */
if (boardopptheir_pit!=0) {
storeside+=1+boardopptheir_pit;
boardsidepit=0;
boardopptheir_pit=0;
}
break;
}
pit++;
}
}
/* converting board, go_again and store for returning a string list-like */
temp=(char)go_again;
if (temp>10) {
return "error";
}
temp='0'+temp;
result0=temp;
walk=1;
for (i=0;i<14;i++) {
if (i<12) {
temp=(char)boardi/6i%6;
} else {
temp=(char)store13-i;
}
resultwalk=' ';
walk++;
if (temp>99) {
return "error";
}
if (temp>=10) {
resultwalk='0'+(temp/10);
walk++;
temp=temp%10;
}
resultwalk='0'+temp;
walk++;
}
resultwalk='\0';
return result;
}It takes as arguments : the board, which is a list of numbers converted to a string (char* type), and two integers : side and go_again, both booleans. The result returned is a string containing :
as if it was a list. (numbers are separated by a space)
Here is the tcl wrapping :
# cmove is our C proc
set res [cmove $board $player $pit]
if {[string equal $res error]} {
error "error in move"
}
return [list [lindex $res 0] [lrange $res 1 end]]Of course I created a similar cproc which simulates the other game mode.
Compiling issues
Having MinGW/MSys on my WindowsME machine, what was needed for compiling under the DOS console is :
set PATH=%PATH%;d:\mingw\bin;d:\tcl\bin tclsh critcl.kit -lib cmancala cmancala.tcl
, where cmancala.tcl is our cproc definition. Then to access the cmove proc :
tclsh % load cmancala.dll % cmove [split 33333333333300 ""] 0 0 0 0 4 4 4 3 3 3 3 3 3 3 3 0 0
That's it !