Updated 2012-08-28 23:53:21 by RLE

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 error[10]="error";
char result[45+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 (vboard[i]!='\0') {
temp=0;
while (vboard[i]!=' '&& vboard[i]!='\0') {
if (vboard[i]<'0'||vboard[i]>'9') {
return "error";
}
temp=temp*10+vboard[i]-'0';
i++;
if (temp>36) {
return "error";
}
}
if (walk<12) {
board[walk/6][walk%6]=(int) temp;
} else  {
store[13-walk]=(int) temp;
}
walk++;
i++;
if (walk>13) {
break;
}
}
for (i=0;i<sizeof(result);i++) {result[i]='\0';}
/* initialization ending */
/* begin moving */
stones=board[side][pit];
if (stones == 0) {
/* for debugging */
/* error[5]=vboard[side*6+pit];
error6='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;
}
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;
result[0]=temp;
walk=1;
for (i=0;i<14;i++) {
if (i<12) {
temp=(char)board[i/6][i%6];
} else  {
temp=(char)store[13-i];
}
result[walk]=' ';
walk++;
if (temp>99) {
return "error";
}
if (temp>=10) {
result[walk]='0'+(temp/10);
walk++;
temp=temp%10;
}
result[walk]='0'+temp;
walk++;
}
result[walk]='\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 :

• go_again at index 0
• the modified board from index 1 to end

as if it was a list. (numbers are separated by a space)

Here is the tcl wrapping :

• into the move proc :
``` # 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