PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : schon mal festgestellt? A. Due rechnet falsch - Mega ok!



HaWe
15.11.2014, 20:33
hi,
habt ihr das auch schon mal festgestellt?
der A. Due rechnet falsch - beim Mega ok!
gleicher Code läuft auch als devcpp Konsolenanwendung einwandfrei - nur der Due streikt!
Ist es ein Sketch-Compilier-Fehler? Oder ist mein Due kaputt ???

wenn ich jetzt in beiden Programmen als Zug
d2d4
eingebe, klappt alles wunderbar. (in beiden Fällen score=30000 = default)

wenn ich einen Leerstring eingebe, auch (dann rechnet er automatisch einen Zug aus).

wenn ich aber dann, wenn Schwarz zieht,
bei devcpp z.B. a7a6 eingebe,
klappt es (wieder score=30000 = default)

bei Sketch meldet er einen falschen Zug (score == 0x0f == 15)
und weigert sich, ihn auszuführen!!
und zwar NUR bei schwarz!!
bei Weiß geht wieder alles !!

ich kapiers nicht.
ich war schon schier am verzweifeln!
29327



/************************************************** *************************/
/* micro-Max, */
/* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */
/************************************************** *************************/
/* version 4.8.i Sketch (1953 characters) features: */
/* - recursive negamax search */
/* - all-capture MVV/LVA quiescence search */
/* - (internal) iterative deepening */
/* - best-move-first 'sorting' */
/* - a hash table storing score and best move */
/* - futility pruning */
/* - king safety through magnetic, frozen king in middle-game */
/* - R=2 null-move pruning */
/* - keep hash and repetition-draw detection */
/* - better defense against passers through gradual promotion */
/* - extend check evasions in inner nodes */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR) */
/* - full FIDE rules (expt under-promotion) and move-legality checking */


#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))


#define HTsize (1<<8) // (1<<24)
struct HTab {
int K,
V;
int X,
Y,
D;
} HTarray[HTsize]; /* hash table, HTsize entries*/


#define MAXNODES 60000

int K,
Q,
R,
J,
Z;

long N,
I=30000; /* I=80000: "infinity score" */ ;

int
M=136, /* M=0x88 board system */
S=128, /* dummy square 0x80, highest valid square =127 */
turn=16;

char L,
pval[]={0,2,2,7,-1,8,12,23}, /* relative piece values */
vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
7,-1,11,6,8,3,6}, /* 1st dir. in vector[] per piece*/

bsetup[]={6,3,5,7,4,5,3,6}, /* initial piece setup */
board[129], /* board: half of 16x8+dummy*/
T[1035]; /* hash translation table */

char psymbol[]= ".?+nkbrq?*?NKBRQ";

char mfrom, mto; // current ply from - to
int EPSQ,
RemP; // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int Minimax(int q, int l, int score, int EPC, int prev, int hashkey)
/* (q,l)=window, score, EnPass_sqr.*/
/* prev=prev.dest; J,Z=hashkeys; return score*/
{
int j,
r,
m,
v,
d,
h,
i,
F,
G,
V,
P,
f=J,
g=Z,
C,
s;
char t,
p,
upiece,
x,
y,
X,
Y,
H,
B;

struct HTab *a = HTarray + (J + turn * EPC & HTsize-1); /* lookup pos. in hash table*/

char sbuf[50];



q--; /* adj. window: delay bonus */
turn^=24; /* change sides */
d=a->D;
m=a->V;
X=a->X;
Y=a->Y; /* resume at stored depth */

if(a->K-Z|prev| /* miss: other pos. or empty*/
!(m<=q | X&8&&m>=l | X&S)) /* or window incompatible */
{ d=Y=0; } /* start iter. from scratch */

X&=~M; /* start at best-move hint */

while( d++ < hashkey || d<3 /* iterative deepening loop */
|| prev&K == I
&& ( N<60000 & d<98 /* root: deepen upto time */
|| (K=X, L=Y&~M, d=3)
)
) /* time's up: go do best */
{
x=B=X; /* start scan at prev. best */
h=Y&S; /* request try noncastl. 1st*/
P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3); /* Search null move */
m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P; /* Prune or stand-pat */
N++; /* node count (for timing) */
do
{
upiece=board[x]; /* scan board looking for */
if(upiece & turn) /* own piece (inefficient!)*/
{
r = p = upiece&7; /* p = piece type (set r>0) */
j = vector[p+16]; /* first step vector f.piece*/
while(r = p>2 & r<0 ? -r : -vector[++j] ) /* loop over directions vector[] */
{
labelA: /* resume normal after best */
y=x; /* (x,y)=move */
F=G=S; /* (F,G)=castl.R */

do
{ /* y traverses ray, or: */
H=y=h?Y^h:y+r; /* sneak in prev. best move */

if(y&M)break; /* board edge hit */

m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m; /* bad castling */

if(p<3&y==EPC)H^=16; /* shift capt.sqr. H if e.p.*/

t=board[H];

if(t&turn|p<3&!(y-x&7)-!t)break; /* capt. own, bad pawn mode */
i=37*pval[t&7]+(t&192); /* value of capt. piece t */
m=i<0?I:m; /* K capture */

if(m>=l&d>1) goto labelC; /* abort on fail high */

v=d-1?score:i-p; /* MVV/LVA scoring */

if(d-!t>1) /* remaining depth */
{
v=p<6?board[x+8]-board[y+8]:0; /* center positional pts. */
board[G]=board[H]=board[x]=0;board[y]=upiece|32; /* do move, set non-virgin */
if(!(G&M))board[F]=turn+6,v+=50; /* castling: put R & score */
v-=p-4|R>29?0:20; /* penalize mid-game K move */

if(p<3) /* pawns: */
{
v-=9*((x-2&M||board[x-2]-upiece)+ /* structure, undefended */
(x+2&M||board[x+2]-upiece)-1 /* squares plus bias */
+(board[x^16]==turn+36)) /* kling to non-virgin King */
-(R>>2); /* end-game Pawn-push bonus */
V=y+r+1&S?647-p:2*(upiece&y+16&32); /* promotion or 6/7th bonus */
board[y]+=V;
i+=V; /* change piece, add score */
}

v+= score+i;
V=m>q ? m : q; /* new eval and alpha */
J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S; /* update hash key */
C=d-1-(d>5&p>2&!t&!h);
C=R>29|d<3|P-I?C:d; /* extend 1 ply if in check */
do {
s=C>2|v>V?-Minimax(-l,-V,-v, /* recursive eval. of reply */
F,0,C):v; /* or fail low if futile */
} while( s>q & ++C<d );

v=s;
if(prev&&K-I&&v+I&&x==K&y==L) /* move pending & in root: */
{
Q=-score-i; EPSQ=F; /* exit if legal & found */
a->D=99;a->V=0; /* lock game in hash as draw*/
R+=i>>7;
return l; /* captured non-P material */
}
J=f;
Z=g; /* restore hash key */
board[G]=turn+6;
board[F]=board[y]=0;
board[x]=upiece;
board[H]=t; /* undo move,G can be dummy */
}
if(v>m) /* new best, update max,best*/
{
m=v,X=x,Y=y|S&F; /* mark double move with S */
}
if(h)
{
h=0;
goto labelA; /* redo after doing old best*/
}
if (
x+r-y|upiece&32| /* not 1st step,moved before*/
p>2 & (
p-4|j-7|| /* no P & no lateral K move,*/
board[G=x+3^r>>1&7]-turn-6 /* no virgin R in corner G, */
|| board[G^1] | board[G^2] ) /* no 2 empty sq. next to R */
)
{
t+=p<5;
} /* fake capt. for nonsliding*/
else F=y; /* enable e.p. */

} while(!t); /* if not capt. continue ray*/

}
} // (upiece & turn)

} while((x=x+9&~M)-B); /* next sqr. of board, wrap */

labelC:
if (m>I-M|m<M-I) d=98; /* mate holds to any depth */
m= m+I|P==I ? m : 0; /* best loses K: (stale)mate*/

if(a->D<99) { /* protect game history */
a->K=Z;
a->V=m;
a->D=d; /* always store in hash tab */
a->X=X|8*(m>q)|S*(m<l);
a->Y=Y; /* move, type (bound/exact),*/
}
/* uncomment for Kibitz */
if(!((N-S)%987)) {
sprintf(sbuf, "searched: %d\r",N-S);
Serial.println(sbuf);
}

} // while (iterative deepening loop)

turn^=24; /* change sides back */
mfrom=K; mto=L;
return m+= m<score; /* delayed-loss bonus */
}





void chess()
{
int score, i;
char sbuf[50], sbuf2[50];
char oboard[129];
char oldto, oldEPSQ;
char cstring[20];

K=8;
while(K--)
{
board[K]=(board[K+112]=bsetup[K]+8)+8;
board[K+16]=18;
board[K+96]=9; /* initial board setup*/
L=8;
while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5); /* center-pts table */
} /*(in unused half board[])*/
N=1035;
while(N-->M)T[N]=rand()>>9;

/* play loop */
while(1)
{
N=-1;

Serial.print("\n");
while(++N<121) { /* print board */
sprintf(sbuf," %c", N&8 && (N+=7) ? 10 : psymbol[board[N]&15]);
Serial.print(sbuf);
}

if(turn==16) sprintf(sbuf,"\n> WHITE: "); else sprintf(sbuf,"\n> BLACK: ");
Serial.print(sbuf);

i = 0;
strcpy(cstring,"");
do {
while (Serial.available()==0);
cstring[i] = Serial.read();
if(cstring[i]==13) {
cstring[i]=0;
break;
}
else i++;
} while(i < 10);

K=I;

if(cstring[0]!=0) { /* parse entered move */
K= cstring[0]-16*cstring[1]+799;
L= cstring[2]-16*cstring[3]+799;
}
Serial.println(); Serial.println(cstring); Serial.println();

memcpy(oboard, board, sizeof(board));
oldto=mto;
oldEPSQ=EPSQ;

score=Minimax(-I, I, Q, EPSQ, 1, 3); /* think or check & do*/
Serial.print("\nscore="); Serial.println(score); Serial.println();

// if(score!=15) {
RemP=S;
if(oboard[mto]) RemP=mto;
if(mto==oldEPSQ) RemP=oldto;

sprintf(sbuf,"\n\nmoved: >> %c%c", 'a'+(mfrom&7),'8'-(mfrom>>4) );

if(oboard[mto]) strcat(sbuf," X ");
else strcat(sbuf,"-");

sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
strcat(sbuf, sbuf2);
Serial.print(sbuf);

sprintf(sbuf, " (square %d to %d ) \n", mfrom, mto);
Serial.print("\n\nDEBUG:\n");
sprintf(sbuf2," EPsq: %c%c (%d)\n RemP: %c%c (%d)",
'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ,
'a'+(RemP&7), '8'-(RemP>>4&7), RemP);
strcat(sbuf, sbuf2);
Serial.print(sbuf);
Serial.print("\n\n");
// }
// else printf("\n\nILLEGAL!\n");

}
}




void setup() {
Serial.begin(9600);
}



void loop() {
chess();

while(1);
}




- - - Aktualisiert - - -

hier der gegenseitig angeglichene devcpp Konsolen-Code zum Vergleich:




/************************************************** *************************/
/* micro-Max, */
/* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */
/************************************************** *************************/
/* version 4.8.i (1953 characters) features: */
/* - recursive negamax search */
/* - all-capture MVV/LVA quiescence search */
/* - (internal) iterative deepening */
/* - best-move-first 'sorting' */
/* - a hash table storing score and best move */
/* - futility pruning */
/* - king safety through magnetic, frozen king in middle-game */
/* - R=2 null-move pruning */
/* - keep hash and repetition-draw detection */
/* - better defense against passers through gradual promotion */
/* - extend check evasions in inner nodes */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR) */
/* - full FIDE rules (expt under-promotion) and move-legality checking */


#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))


#define HTsize (1<<8) // (1<<24)
struct HTab {
int K,
V;
int X,
Y,
D;
} HTarray[HTsize]; /* hash table, HTsize entries*/


#define MAXNODES 60000

int K,
Q,
R,
J,
Z;

long N,
I=30000; /* I=80000: "infinity score" */ ;

int M=136, /* M=0x88 board system */
S=128, /* dummy square 0x80, highest valid square =127 */
turn=16;

char L,
pval[]={0,2,2,7,-1,8,12,23}, /* relative piece values */
vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
7,-1,11,6,8,3,6}, /* 1st dir. in vector[] per piece*/

bsetup[]={6,3,5,7,4,5,3,6}, /* initial piece setup */
board[129], /* board: half of 16x8+dummy*/
T[1035]; /* hash translation table */

char psymbol[]= ".?+nkbrq?*?NKBRQ";

char mfrom, mto; // current ply from - to
int EPSQ,
RemP; // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int Minimax(int q, int l, int score, int EPC, int prev, int hashkey)
/* (q,l)=window, score, EnPass_sqr.*/
/* prev=prev.dest; J,Z=hashkeys; return score*/
{
int j,
r,
m,
v,
d,
h,
i,
F,
G,
V,
P,
f=J,
g=Z,
C,
s;
char t,
p,
upiece,
x,
y,
X,
Y,
H,
B;

struct HTab *a = HTarray + (J + turn * EPC & HTsize-1); /* lookup pos. in hash table*/





q--; /* adj. window: delay bonus */
turn^=24; /* change sides */
d=a->D;
m=a->V;
X=a->X;
Y=a->Y; /* resume at stored depth */

if(a->K-Z|prev| /* miss: other pos. or empty*/
!(m<=q | X&8&&m>=l | X&S)) /* or window incompatible */
{ d=Y=0; } /* start iter. from scratch */

X&=~M; /* start at best-move hint */

while( d++ < hashkey || d<3 /* iterative deepening loop */
|| prev&K == I
&& ( N<60000 & d<98 /* root: deepen upto time */
|| (K=X, L=Y&~M, d=3)
)
) /* time's up: go do best */
{
x=B=X; /* start scan at prev. best */
h=Y&S; /* request try noncastl. 1st*/
P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3); /* Search null move */
m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P; /* Prune or stand-pat */
N++; /* node count (for timing) */
do
{
upiece=board[x]; /* scan board looking for */
if(upiece & turn) /* own piece (inefficient!)*/
{
r = p = upiece&7; /* p = piece type (set r>0) */
j = vector[p+16]; /* first step vector f.piece*/
while(r = p>2 & r<0 ? -r : -vector[++j] ) /* loop over directions vector[] */
{
labelA: /* resume normal after best */
y=x; /* (x,y)=move */
F=G=S; /* (F,G)=castl.R */

do
{ /* y traverses ray, or: */
H=y=h?Y^h:y+r; /* sneak in prev. best move */

if(y&M)break; /* board edge hit */

m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m; /* bad castling */

if(p<3&y==EPC)H^=16; /* shift capt.sqr. H if e.p.*/

t=board[H];

if(t&turn|p<3&!(y-x&7)-!t)break; /* capt. own, bad pawn mode */
i=37*pval[t&7]+(t&192); /* value of capt. piece t */
m=i<0?I:m; /* K capture */

if(m>=l&d>1) goto labelC; /* abort on fail high */

v=d-1?score:i-p; /* MVV/LVA scoring */

if(d-!t>1) /* remaining depth */
{
v=p<6?board[x+8]-board[y+8]:0; /* center positional pts. */
board[G]=board[H]=board[x]=0;board[y]=upiece|32; /* do move, set non-virgin */
if(!(G&M))board[F]=turn+6,v+=50; /* castling: put R & score */
v-=p-4|R>29?0:20; /* penalize mid-game K move */

if(p<3) /* pawns: */
{
v-=9*((x-2&M||board[x-2]-upiece)+ /* structure, undefended */
(x+2&M||board[x+2]-upiece)-1 /* squares plus bias */
+(board[x^16]==turn+36)) /* kling to non-virgin King */
-(R>>2); /* end-game Pawn-push bonus */
V=y+r+1&S?647-p:2*(upiece&y+16&32); /* promotion or 6/7th bonus */
board[y]+=V;
i+=V; /* change piece, add score */
}

v+= score+i;
V=m>q ? m : q; /* new eval and alpha */
J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S; /* update hash key */
C=d-1-(d>5&p>2&!t&!h);
C=R>29|d<3|P-I?C:d; /* extend 1 ply if in check */
do {
s=C>2|v>V?-Minimax(-l,-V,-v, /* recursive eval. of reply */
F,0,C):v; /* or fail low if futile */
} while( s>q & ++C<d );

v=s;
if(prev&&K-I&&v+I&&x==K&y==L) /* move pending & in root: */
{
Q=-score-i; EPSQ=F; /* exit if legal & found */
a->D=99;a->V=0; /* lock game in hash as draw*/
R+=i>>7;
return l; /* captured non-P material */
}
J=f;
Z=g; /* restore hash key */
board[G]=turn+6;
board[F]=board[y]=0;
board[x]=upiece;
board[H]=t; /* undo move,G can be dummy */
}
if(v>m) /* new best, update max,best*/
{
m=v,X=x,Y=y|S&F; /* mark double move with S */
}
if(h)
{
h=0;
goto labelA; /* redo after doing old best*/
}
if (
x+r-y|upiece&32| /* not 1st step,moved before*/
p>2 & (
p-4|j-7|| /* no P & no lateral K move,*/
board[G=x+3^r>>1&7]-turn-6 /* no virgin R in corner G, */
|| board[G^1] | board[G^2] ) /* no 2 empty sq. next to R */
)
{
t+=p<5;
} /* fake capt. for nonsliding*/
else F=y; /* enable e.p. */

} while(!t); /* if not capt. continue ray*/

}
} // (upiece & turn)

} while((x=x+9&~M)-B); /* next sqr. of board, wrap */

labelC:
if (m>I-M|m<M-I) d=98; /* mate holds to any depth */
m= m+I|P==I ? m : 0; /* best loses K: (stale)mate*/

if(a->D<99) { /* protect game history */
a->K=Z;
a->V=m;
a->D=d; /* always store in hash tab */
a->X=X|8*(m>q)|S*(m<l);
a->Y=Y; /* move, type (bound/exact),*/
}
/* uncomment for Kibitz */
if(!((N-S)%987)) printf("searched: %d\r",N-S);
/*
if(prev){
printf("%2d ply, %9d searched, score=%6d by %c%c%c%c\n", d-1, N-S, m,
'a'+(X&7),'8'-(X>>4),'a'+(Y&7),'8'-(Y>>4&7)); /* encoded in X S,8 bits
}
*/
} // while (iterative deepening loop)

turn^=24; /* change sides back */
mfrom=K; mto=L;
return m+= m<score; /* delayed-loss bonus */
}






main()
{
int score;
char sbuf[50], sbuf2[50];
char oboard[129];
char oldto, oldEPSQ;
int *key;
int cstring[20];

K=8;
while(K--)
{
board[K]=(board[K+112]=bsetup[K]+8)+8;
board[K+16]=18;
board[K+96]=9; /* initial board setup*/
L=8;
while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5); /* center-pts table */
} /*(in unused half board[])*/
N=1035;
while(N-->M)T[N]=rand()>>9;

/* play loop */
while(1)
{
N=-1;

printf("\n");
while(++N<121) { /* print board */
printf(" %c", N&8 && (N+=7) ? 10 : psymbol[board[N]&15]);
}

if(turn==16) printf("\n> WHITE: "); else printf("\n> BLACK: ");

key=cstring;
while( (*key++ =getchar() ) > 10 ); /* read input line */
K=I; /* invalid move */

if(*cstring-10) { /* parse entered move */
K= cstring[0]-16*cstring[1]+799;
L= cstring[2]-16*cstring[3]+799;
}

memcpy(oboard, board, sizeof(board));
oldto=mto;
oldEPSQ=EPSQ;
score=Minimax(-I,I,Q,EPSQ,1,3); /* think or check & do*/
printf("\n\nscore=%d\n", score);
// if(score!=15) {
RemP=S;
if(oboard[mto]) RemP=mto;
if(mto==oldEPSQ) RemP=oldto;

sprintf(sbuf,"\n\nmoved: >> %c%c", 'a'+(mfrom&7),'8'-(mfrom>>4) );

if(oboard[mto]) strcat(sbuf," X ");
else strcat(sbuf,"-");

sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
strcat(sbuf, sbuf2);
printf(sbuf);

sprintf(sbuf, " (square %d to %d ) \n", mfrom, mto);
printf("\n\nDEBUG:\n");
sprintf(sbuf2," EPsq: %c%c (%d)\n RemP: %c%c (%d)",
'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ,
'a'+(RemP&7), '8'-(RemP>>4&7), RemP);
strcat(sbuf, sbuf2);
printf(sbuf);
printf("\n\n");
// }
// else printf("\n\nILLEGAL!\n");

}
}



- - - Aktualisiert - - -

update:
Sketch 1.5.8 installiert (vorher 1.5.6) - selber Fehler beim Due,
Mega immer noch ok!

MIST!

Kann bitte mal jemand den Code auf einem eigenen Due mal ausprobieren?

Sisor
15.11.2014, 21:05
Das ist definitiv kein Quelltext, den man (ich) auf Anhieb versteht;).

Der Mega hat 8Bit Register, der Due hat nen 32Bit ARM-Controller. Ich rate mal, dass das Problem daher rührt. Ich würde mal mit sizeof() die Datentypengrößen testen.
Sowas:

void setup() {
Serial.begin(9600);
Serial.print("sizeof(HTarray[0]) = ");Serial.println(sizeof(HTarray[0]));
Serial.print("sizeof(char) = ");Serial.println(sizeof(char));
Serial.print("sizeof(int*) = ");Serial.println(sizeof(int*));
//...
}

}

HaWe
15.11.2014, 22:22
ich übergebe ja nur Zahlen (2 isolierte char für das Quadrat, wie z.B. d 2 oder a 7), das kann doch nichts mit der Größe für integer (16 oder 32 bit ) zu tun haben?

Außerdem läuft ja der Code sowohl auf dem 8-bit AVR als auch auf meinem PC (32 oder 64 bit, kA), nur der ARM macht Mist.

Es hilft wirklich nur austesten, es kann ja nur ein Compilerfehler oder ein Hardwarefehler sein.
Compilerfehler müsste jeder mit der 1.5.8 Version anchvollziehen können, Hardwarefehler ist sicher abhängig von Klon oder original (ich habe einen China-Klon).

Mxt
16.11.2014, 08:31
Hallo,

ändert sich etwas, wenn du in dem Code für den Due mal alle int durch int16_t ersetzt ?

Oder wenn du ganz oben, vor das #define eine Zeile mit
#pragma pack(1)
einfügst ?

HaWe
16.11.2014, 09:02
keine Änderung mit int16_t
der PC mit devcpp nutzt aber auch int32 i.Ggs. zu int16 beim AVR.

#pragma pack(1) bringt auch keine Änderung.


immer serselbe Fehler:
Eröffnung:

Weiss: d2d4
OK


Schwarz: a7a6
bei Due: Fehler, wird nicht angenommen / nicht ausgeführt
bei allen anderen: OK.

stattdessen automove: bei allen ok




wieder weiß:
c2c4 bei allen ok

wieder Schwarz:
korrekte manuelle Züge klappen nicht bei Due, aber klappen bei allen anderen.
automatische Züge klappen weiterhin.


man braucht also zum Testen nur die folgenden 2 Schritte:



Weiss:
d2d4


Schwarz:
a7a6



testet es doch mal bitte auf euren Dues,
und ggf. auch auf euren Megas zum Vergleich!

Sisor
16.11.2014, 09:35
Schau doch mal, ob die Eingabe vom Due genauso aufgenommen wird, wie beim Mega.

...
do {
while (Serial.available()==0);
cstring[i] = Serial.read();
if(cstring[i]==13) {
cstring[i]=0;
break;
}
else i++;
} while(i < 10);

K=I;

if(cstring[0]!=0) { /* parse entered move */
K= cstring[0]-16*cstring[1]+799;
L= cstring[2]-16*cstring[3]+799;
}

// DEBUG Ausgabe
Serial.print("DEBUG cstring : "); Serial.println(cstring);
Serial.print("DEBUG K: "); Serial.println(K);
Serial.print("DEBUG L: "); Serial.println(L);
Serial.println(); Serial.println(cstring); Serial.println();
...

HaWe
16.11.2014, 10:19
bei Sketch immer das gleiche, leider stellt Sketch die Nummern als Buchstaben dar (32== Leerzeichen!!)
(da lobe ich mir die ANSI-C-Ausgabe mit printf)

habe jetzt deine Debug Zeilen angepasst, Ergebnis folgt...

Serial.print("DEBUG cstring : "); Serial.println(cstring);
sprintf(sbuf,"\n DEBUG K: %d \n DEBUG L: %d \n", K, L);
Serial.print(sbuf);

edit: im ANSI-C-Code:
printf(" DEBUG %c%c%c%c \n DEBUG K: %d \n DEBUG L: %d \n", cstring[0],cstring[1],cstring[2],cstring[3], K, L);

- - - Aktualisiert - - -




Mega:
======


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
* * * * * * * *
R N B Q K B N R

> WHITE: DEBUG cstring : d2d4

DEBUG K: 99
DEBUG L: 67

d2d4


score=30000



moved: >> d2-d4

DEBUG:
(square 99 to 67 )
EPsq: d3 (83)
RemP: a8 (128)


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> BLACK: DEBUG cstring : a7a6

DEBUG K: 16
DEBUG L: 32

a7a6


score=30000



moved: >> a7-a6

DEBUG:
(square 16 to 32 )
EPsq: a8 (128)
RemP: a8 (128)


r n b q k b n r
. + + + + + + +
+ . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> WHITE: //<<<<<<<<<<<<<<<<<< korrekt ausgeführt, wieder WEISS am Zug!





//--------------------------------------------------------------



Due:
====


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
* * * * * * * *
R N B Q K B N R

> WHITE: DEBUG cstring : d2d4

DEBUG K: 99
DEBUG L: 67

d2d4


score=30000



moved: >> d2-d4

DEBUG:
(square 99 to 67 )
EPsq: d3 (83)
RemP: a8 (128)


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> BLACK: DEBUG cstring : a7a6

DEBUG K: 16
DEBUG L: 32

a7a6


score=15



moved: >> a7-a6

DEBUG:
(square 16 to 32 )
EPsq: d3 (83)
RemP: a8 (128)


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> BLACK: //<<<<<<<<<<<<<<<<<< nicht ausgeführt, bleibt hier hängen














//--------------------------------------------------------------

devcpp:
=======


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
* * * * * * * *
R N B Q K B N R

> WHITE: d2d4
d
DEBUG K: 99
DEBUG L: 67


score=30000


moved: >> d2-d4

DEBUG:
(square 99 to 67 )
EPsq: d3 (83)
RemP: a8 (128)


r n b q k b n r
+ + + + + + + +
. . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> BLACK: a7a6
a
DEBUG K: 16
DEBUG L: 32


score=30000


moved: >> a7-a6

DEBUG:
(square 16 to 32 )
EPsq: a8 (128)
RemP: a8 (128)


r n b q k b n r
. + + + + + + +
+ . . . . . . .
. . . . . . . .
. . . * . . . .
. . . . . . . .
* * * . * * * *
R N B Q K B N R

> WHITE: //<<<<<<<<<<<<<<<<<< korrekt ausgeführt, wieder WEISS am Zug!






K und L (Zug von K nach L) stimmen bei Sketch und devcpp alle überein .




edit: Debugstring für ANSI C geändert:
printf(" DEBUG %c%c%c%c \n DEBUG K: %d \n DEBUG L: %d \n", cstring[0],cstring[1],cstring[2],cstring[3], K, L);
Eingabestring ist im Original-Code ein int-array, kein char-array! Immerhin stimmt aber auch immer das Ergebnis für K und L.
Er müsste bei devcpp eigtl auch von cstring in iarray o.ä. umbenannt werden.
Ich finde allerdings schon, dass hier die Zugeingabe von Muller ein wenig zu sehr "obfuscated" ist, man müsste das mal verbessern - ist momentan aber nicht das Problem.)

Mxt
16.11.2014, 11:40
Der Code scheint in der Tat irgendeine Plattformabhängigkeit zu haben.

Ich habe mir den zweiten Quelltext aus dem ersten Posting (ursprünglich für devcpp) geschnappt und mit Visual Studio unter Windows (als 32-Bit) und mit dem g++ unter Ubuntu auf dem Beaglebone Black übersetzt.

Auch da bekomme ich nach BLACK: a7a6 auf dem Laptop den Score 30000 und unter Linux den Score 15.

====

Zwei Nachträge:

1) Am g++ liegt es nicht, mit CLang kommt das selbe Ergebnis (allerdings 18 Warnungen zum Quelltext ...)

2) Eventuell liegt es an Dingen wie diesem:
#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7)) Da werden irgendwelche Adressen berechnet, möglicherweise werden da Dinge gemacht, die auf ARM so nicht gelten.

HaWe
16.11.2014, 12:01
danke, das ist ja schon mal sehr interessant mit Laptop vs. Beaglebone.

was er hier allerdings macht mit den ganzen Pointern

#define K(A,B) *(int*)(T+A+( B&8 )+S*( B&7 ))

ist mir selber völlig unklar.

wenn man das mal in vernünftigen Code ohne Pointer übersetzen könnte, könnte man mal gucken.... :confused:

Sisor
16.11.2014, 12:51
#define K(A,B) *(int*)(T+A+( B&8 )+S*( B&7 ))

ist im Prinzip das gleiche wie

#define K(A,B) (int)(T+A+( B&8 )+S*( B&7 ))

Warum die Indirektion über den Inhaltsoperator eines Int-Pointers ( *(int*) ) gewählt wurde, ist mir schleierhaft.
Am Ende ist es ein einfacher Int-Cast...

HaWe
16.11.2014, 13:03
danke, habe ich sogleich getestet:

PC devcpp: OK

Arduino Due ARM: selber Fehler.

Arduino Mega AVR: OK.

:mad:

HaWe
16.11.2014, 20:55
hat hier keiner einen Arduino Due zum austesten?

Sisor
16.11.2014, 21:46
Nö, leider nicht...

Peter(TOO)
16.11.2014, 22:40
Hallo HaWe,

Data Missalignment wird von unterschiedlichen CPUs unterschiedlich gehandhabt.

Also ein 16-Bit Zugriff auf eine ungerade Adresse:
1. Es wird ein Trap ausgelöst.
2. Das letzte Adressbit wird einfach als 0 angenommen und der Zugriff auf die gerade Adresse durchgeführt.
2. Es wird auf die ungerade Adresse zugegriffen und anschliessend auf das nächst höhere Byte. Bei e1nem 16-Bit Datenbus führt dies zu zwei Speicherzugriffen.

Hier macht mir das Macro:
#define K(A,B) *(int*)(T+A+( B&8 )+S*( B&7 ))
gerade etwas Sorgen.
T ist als char-Arrary definiert.

T+A kann eine ungerade Adresse erzeugen, welche dann zu einer Adresse eines int umgewandelt wird ....


Beim Cortex-M3 wird's jetzt richtig kompliziert.
Manche Befehle erlauben Zugriffe auf eine Unaligned-Adresse, andere erzeugen einen TRAP.
Über ein Register-Bit kann gefordert werden, dass alle Unaligned-Zugriffe den TRAP erzeugen.
Dann stellt sich noch die Frage, was der Standard-Traphandler macht.
Und natürlich, welchen Code der Compiler erzeugt.

Wie sich der ATMega verhält, weiss ich nicht.

MfG Peter(TOO)

Mxt
17.11.2014, 07:31
Meine Überlegungen gehen in die selbe Richtung, wie die von Peter.

Da der Beaglebone Black die gleiche Ausgabe produziert wie der Due, ist das kein Arduino spezifisches Problem. Der Cortex M3 im Due und der Cortex A8 im Beagle haben beide ARM v7.1 Architektur.

Das sich x86 und ein 8-Bitter ähnlich verhalten, ist nicht so außergewöhnlich. Intels Architektur enthält einiges an 8-Bit Erbe.

Bei dem Makro bin ich mir auch noch nicht sicher. Aber die vielen Warnungen zur Operator-Reihenfolge, die Clang auswirft, könnten auch noch auf andere Probleme im Code deuten. Im Moment habe ich keine Zeit dafür.

HaWe
17.11.2014, 09:21
hi,
danke schon mal für die Antworten!

Das obige *(int *) Makro habe ich ja wie berichtet (bei unveränderten Laufzeit-Verhaltenweisen) schon ersetzt durch

#define K(A,B) (int)(T+A+( B&8 )+S*( B&7 ))

Der Code läuft trotzdem OK für alle automatischen Zugberechnungen und auch für alle manuellen auf AVR und PC, nur die schwarzen Halbzüge machen Probleme auf dem Due.

Da sich unterm Strich nichts am Laufzeitverhalten geändert hat, sehe ich in dem Makro also ehrlich gesagt kein Problem, oder wie sehr ihr das?

Die Logik hinter den manuellen Zügen ist ja:
wenn man einen Zug eingibt, überprüft er ihn in einer abgekürzten Schleife auf Gültigkeit.

wenn man keinen eingibt, wird K auf I (=30000) gesetzt, damit erkennt der Move Generator, dass er selber über Züge nachdenken muss -
und überprüft sie dann auf Gültigkeit (mit derselben abgekürzten Schleife, und den besten gültigen führt er dann aus ).


Ich kann mir nur vorstellen, dass die Ursache ein Compilerfehler (Optimierungsfehler) ist, denn so großartige Pointerakrobatik wird ja nun mit dem umgeschriebenen Makro gar nicht mehr gemacht - das was beibt, ist Standard-ANSI-C.

Zugegebenrmaßen ist ja der von Muller ziemlich schwer verständlich und auf Kürze optimiert, d.h. auf möglichst wenige geschriebene Buchstaben.
Auch setzt er z.B. oft das Bitweise & oder | ein statt das logische && bzw. || ...

Bin deshalb ntl offen für andere Meinungen und Argumente, gerne auch für umgeschriebenen Sourcecode, den ich dann testen kann (und alle, die einen Due haben !


edit:
gerade festgestellt:
Springerzüge wie b8c6 werden akzeptiert, aber kein Bauernzug!
Spricht auch eher für ein Optimierungsproblem (piece < 3 )

- - - Aktualisiert - - -

ps:
gerade festgestellt:

manche automatischen Züge sind auf dem Due auch komplett falsch, z.B.
Bauer a7 X f2

das kann ja gar nicht gehen.

Also ist auch der Gültigkeits-Check für automatische Züge beim Due im A****, ganz egal ob
*(int*) oder nur (int)
im Makro, also immer !

- - - Aktualisiert - - -

also jetzt erst recht:

Bitte gerne Vorschläge für umgeschriebenen Sourcecode, den ich dann testen kann (und alle, die einen Due haben !

Mxt
17.11.2014, 09:34
Ich kann mir nur vorstellen, dass die Ursache ein Compilerfehler (Optimierungsfehler) ist,
Das ist extrem unwahrscheinlich, da mit Clang ein zweiter Compiler exakt die gleiche Programmausgabe produziert. Optimierungen hatte ich gar nicht eingeschaltet.

HaWe
17.11.2014, 09:52
guter Hinweis, stimmt!
hast du denn mit Clang (Beaglebone?) auch ungültige automatische Züge beobachten können, während mit dem PC immer alles OK war ?

Mxt
17.11.2014, 10:01
Ich habe nur ein paar Sachen probiert, jeweils die Windows Konsole parallel zu zwei Putty-Sessions mit der g++ und Clang Variante auf dem Beaglebone. Zwischen den beiden ARM-Linux Programmen gab es keinen Unterschied in der Ausgabe, sie verhielten sich immer gleich und anders als die Windows Version.

HaWe
17.11.2014, 10:05
ich verstehe zuwenig von Linux und putty -
was bedeutet genau "jeweils die Windows Konsole parallel zu zwei Putty-Sessions mit der g++ und Clang Variante auf dem Beaglebone" ?

heißt das, dass sowohl Clang- als auch gpp-Compiler-Code auf dem Beaglebone liefen und beide dieselben falschen Ergebnisse auf dem Beaglebone produzierten?

Mxt
17.11.2014, 10:35
Ich habe den Code mit Visual Studio gestartet, dabei erscheint das Programm in einem Windows Konsolenfenster.

Putty ist ein Terminalprogramm, der Beaglebone hing am USB-Port des Laptops (ohne eigene Tastatur und Bildschirm).

Ich habe also parallel zum Windowsprogramm die beiden Linuxversionen in zwei Fenstern gestartet. Und dann in allen drei Programmen jeweils die gleiche Eingabe gemacht, um zu vergleichen.

P.S. Bin jetzt ggf. ein paar Tage offline.

- - - Aktualisiert - - -



heißt das, dass sowohl Clang- als auch gpp-Compiler-Code auf dem Beaglebone liefen und beide dieselben falschen Ergebnisse auf dem Beaglebone produzierten?
Ja, sie waren nicht zu unterscheiden.

HaWe
17.11.2014, 10:55
ok, ja, dann ist es klar..

hmmm...: Jemand meinte jetzt, es könnte evtl. an little oder big endians liegen... aber wo genau und wie... :?:

Peter(TOO)
17.11.2014, 12:45
Hallo,

hmmm...: Jemand meinte jetzt, es könnte evtl. an little oder big endians liegen... aber wo genau und wie... :?:

Das ist die andere Möglichkeit.

Probleme bekommst du immer dann, wen z.B. char und int gemischt werden. Also du auf de selben Speicherbereich mal als char und mal als int ansprichst, das wird dann nicht mehr portierbar.

Beim besagten Macro passiert aber genau das, T ist als char definiert und dann wird da fröhlich mal als char und mal als int drin rum gestochert.

Ich habe en Code aber nur überflogen und keine Lust da jetzt das Problem zu lösen.

Dazu musst man zuerst einmal die CPUs vergleichen, wie das mit der Endian und dem Alignment ist.

MfG Peter(TOO)

Mxt
17.11.2014, 13:35
Wenn ich etwas Zeit habe, was nicht in den nächsten Tagen sein wird, grabe ich mal meinen Due aus und schaue, ob es da noch Unterschiede zum Beaglebone gibt. Mit Endianess zwischen Beaglebone und PC hatte ich bisher keine Probleme, sollte gleich sein.

HaWe
17.11.2014, 16:32
habe den Programmierer, der das mit endians angesprochen hat, nach einem Test gefragt.
Antwort:

Xander Soldaat It would be easy to devise a simple test.
Print out 0xabcdefab >> 8 on the various platforms and see if you can spot a difference in the outcome.

Ergebnis: kein Unterschied!
Arduino _Due: 11259375
Arduino Mega: 11259375

wenn mir jemand zeigt, wo genau ints mal als ints und mal als bytes angesprochen verden, könnte ich das ja versuchen per type cast
(char)... oder (unsigned char)...
zu korrigieren. Explizites Type cast funktioniert ja auf jeder Plattform korrekt.

Mxt
17.11.2014, 18:01
So, ich bins wieder. :cool:

Die Sache hat mir keine Ruhe gelassen. Ich habe also auch noch meinen Due gesucht und jetzt mit vier Programmen getestet.

Folgende Erkenntnisse:

1) Die im ersten Posting genannten Züge White d2d4 und Black a7a6 akzeptiert nur die PC-Version. Bei Due und beiden Beaglebone Programmen kommt bei a7a6 ein Score 15.

2) Wenn ich die Windows Version mit Leeren Eingaben füttere und die dort berechneten Züge in die drei ARM Programme eingebe, dann funktionieren die. Auch auf dem Due. Ich habe aber keine ganze Partie gespielt, nur ein Dutzend Züge.

3) Alle Programme scheinen immer die selben Züge zu wählen, wenn man sie neu startet und nur leere Eingaben macht. Aber jede Version andere. Der PC beginnt immer mit d2-d4, der Due ( Arduino 1.5.8 ) immer mit f2-f3, BBB g++ mit e2-e3 und BBB Clang mit b1-c3.

Schlussfolgerung: Hier ist "undefined behavior" im Spiel, zumindest bei den drei ARM-Versionen. Da werden irgendwo Sprachkonstrukte verwendet, die nicht wirklich erlaubt sind und wahrscheinlich auf dem PC und er 8-Bit Plattform zufällig funktionieren.

Danach zu suchen macht sicher Arbeit, da wäre ein guter Debugger hilfreich.

HaWe
17.11.2014, 22:11
wenn man nur Harm Geert Mullers Email-Adresse rauskriegen könnte...
Habs bereits probiert, aber
H.Muller@amolf.nl
ist leider ungültig... :(

HaWe
18.11.2014, 17:53
nicht zu glauben, was die Ursache war....

wer mag, teste doch jetzt mal den folgenden Sketch Code auf dem Due (immer noch debug-Stadium ntl):



/************************************************** *************************/
/* micro-Max, */
/* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */
/************************************************** *************************/
/* version 4.8.l Sketch (1953 characters) features: */
/* - recursive negamax search */
/* - all-capture MVV/LVA quiescence search */
/* - (internal) iterative deepening */
/* - best-move-first 'sorting' */
/* - a hash table storing score and best move */
/* - futility pruning */
/* - king safety through magnetic, frozen king in middle-game */
/* - R=2 null-move pruning */
/* - keep hash and repetition-draw detection */
/* - better defense against passers through gradual promotion */
/* - extend check evasions in inner nodes */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR) */
/* - full FIDE rules (expt under-promotion) and move-legality checking */


#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))
// #define K(A,B) (int)(T+A+(B&8)+S*(B&7))

#define HTsize (1<<8) // (1<<24)
struct HTab {
int K,
V;
int X,
Y,
D;
} HTarray[HTsize]; /* hash table, HTsize entries*/


#define MAXNODES 60000

int K,
Q,
R,
J,
Z;

long N,
I=80000; /* I=80000: "infinity score" */ ;

int
M=136, /* M=0x88 board system */
S=128, /* dummy square 0x80, highest valid square =127 */
turn=16;

signed char L,
pval[]={0,2,2,7,-1,8,12,23}, /* relative piece values */
vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
7,-1,11,6,8,3,6}, /* 1st dir. in vector[] per piece*/

bsetup[]={6,3,5,7,4,5,3,6}, /* initial piece setup */
board[129], /* board: half of 16x8+dummy*/
T[1035]; /* hash translation table */

signed char psymbol[]= ".?+nkbrq?*?NKBRQ";

char mfrom, mto; // current ply from - to
int EPSQ,
RemP; // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int Minimax(int q, int l, int score, int EPC, int prev, int hashkey)
/* (q,l)=window, score, EnPass_sqr.*/
/* prev=prev.dest; J,Z=hashkeys; return score*/
{
int j,
r,
m,
v,
d,
h,
i,
F,
G,
V,
P,
f=J,
g=Z,
C,
s;
signed char t,
p,
upiece,
x,
y,
X,
Y,
H,
B;

struct HTab *a = HTarray + (J + turn * EPC & HTsize-1); /* lookup pos. in hash table*/

char sbuf[50];



q--; /* adj. window: delay bonus */
turn^=24; /* change sides */
d=a->D;
m=a->V;
X=a->X;
Y=a->Y; /* resume at stored depth */

if(a->K-Z|prev| /* miss: other pos. or empty*/
!(m<=q | X&8&&m>=l | X&S)) /* or window incompatible */
{ d=Y=0; } /* start iter. from scratch */

X&=~M; /* start at best-move hint */

while( d++ < hashkey || d<3 /* iterative deepening loop */
|| prev&K == I
&& ( N<60000 & d<98 /* root: deepen upto time */
|| (K=X, L=Y&~M, d=3)
)
) /* time's up: go do best */
{
x=B=X; /* start scan at prev. best */
h=Y&S; /* request try noncastl. 1st*/
P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3); /* Search null move */
m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P; /* Prune or stand-pat */
N++; /* node count (for timing) */
do
{
upiece=board[x]; /* scan board looking for */
if(upiece & turn) /* own piece (inefficient!)*/
{
r = p = upiece&7; /* p = piece type (set r>0) */
j = vector[p+16]; /* first step vector f.piece*/
while(r = p>2 & r<0 ? -r : -vector[++j] ) /* loop over directions vector[] */
{
labelA: /* resume normal after best */
y=x; /* (x,y)=move */
F=G=S; /* (F,G)=castl.R */

do
{ /* y traverses ray, or: */
H=y=h?Y^h:y+r; /* sneak in prev. best move */

if(y&M)break; /* board edge hit */

m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m; /* bad castling */

if(p<3&y==EPC)H^=16; /* shift capt.sqr. H if e.p.*/

t=board[H];

if(t&turn|p<3&!(y-x&7)-!t)break; /* capt. own, bad pawn mode */
i=37*pval[t&7]+(t&192); /* value of capt. piece t */
m=i<0?I:m; /* K capture */

if(m>=l&d>1) goto labelC; /* abort on fail high */

v=d-1?score:i-p; /* MVV/LVA scoring */

if(d-!t>1) /* remaining depth */
{
v=p<6?board[x+8]-board[y+8]:0; /* center positional pts. */
board[G]=board[H]=board[x]=0;board[y]=upiece|32; /* do move, set non-virgin */
if(!(G&M))board[F]=turn+6,v+=50; /* castling: put R & score */
v-=p-4|R>29?0:20; /* penalize mid-game K move */

if(p<3) /* pawns: */
{
v-=9*((x-2&M||board[x-2]-upiece)+ /* structure, undefended */
(x+2&M||board[x+2]-upiece)-1 /* squares plus bias */
+(board[x^16]==turn+36)) /* kling to non-virgin King */
-(R>>2); /* end-game Pawn-push bonus */
V=y+r+1&S?647-p:2*(upiece&y+16&32); /* promotion or 6/7th bonus */
board[y]+=V;
i+=V; /* change piece, add score */
}

v+= score+i;
V=m>q ? m : q; /* new eval and alpha */
J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S; /* update hash key */
C=d-1-(d>5&p>2&!t&!h);
C=R>29|d<3|P-I?C:d; /* extend 1 ply if in check */
do {
s=C>2|v>V?-Minimax(-l,-V,-v, /* recursive eval. of reply */
F,0,C):v; /* or fail low if futile */
} while( s>q & ++C<d );

v=s;
if(prev&&K-I&&v+I&&x==K&y==L) /* move pending & in root: */
{
Q=-score-i; EPSQ=F; /* exit if legal & found */
a->D=99;a->V=0; /* lock game in hash as draw*/
R+=i>>7;
return l; /* captured non-P material */
}
J=f;
Z=g; /* restore hash key */
board[G]=turn+6;
board[F]=board[y]=0;
board[x]=upiece;
board[H]=t; /* undo move,G can be dummy */
}
if(v>m) /* new best, update max,best*/
{
m=v,X=x,Y=y|S&F; /* mark double move with S */
}
if(h)
{
h=0;
goto labelA; /* redo after doing old best*/
}
if (
x+r-y|upiece&32| /* not 1st step,moved before*/
p>2 & (
p-4|j-7|| /* no P & no lateral K move,*/
board[G=x+3^r>>1&7]-turn-6 /* no virgin R in corner G, */
|| board[G^1] | board[G^2] ) /* no 2 empty sq. next to R */
)
{
t+=p<5;
} /* fake capt. for nonsliding*/
else F=y; /* enable e.p. */

} while(!t); /* if not capt. continue ray*/

}
} // (upiece & turn)

} while((x=x+9&~M)-B); /* next sqr. of board, wrap */

labelC:
if (m>I-M|m<M-I) d=98; /* mate holds to any depth */
m= m+I|P==I ? m : 0; /* best loses K: (stale)mate*/

if(a->D<99) { /* protect game history */
a->K=Z;
a->V=m;
a->D=d; /* always store in hash tab */
a->X=X|8*(m>q)|S*(m<l);
a->Y=Y; /* move, type (bound/exact),*/
}
/* uncomment for Kibitz */
if(!((N-S)%987)) {
sprintf(sbuf, "searched: %d\n",N-S);
Serial.print(sbuf);
}

} // while (iterative deepening loop)

turn^=24; /* change sides back */
mfrom=K; mto=L;
return m+= m<score; /* delayed-loss bonus */
}





void chess()
{
int score, i;
char sbuf[50], sbuf2[50];
char oboard[129];
char oldto, oldEPSQ;
char cstring[20];

K=8;
while(K--)
{
board[K]=(board[K+112]=bsetup[K]+8)+8;
board[K+16]=18;
board[K+96]=9; /* initial board setup*/
L=8;
while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5); /* center-pts table */
} /*(in unused half board[])*/
N=1035;
while(N-->M)T[N]=rand()>>9;

/* play loop */
while(1)
{
N=-1;

Serial.print("\n");
while(++N<121) { /* print board */
sprintf(sbuf," %c", N&8 && (N+=7) ? 10 : psymbol[board[N]&15]);
Serial.print(sbuf);
}

if(turn==16) sprintf(sbuf,"\n> WHITE: "); else sprintf(sbuf,"\n> BLACK: ");
Serial.print(sbuf);

i = 0;
strcpy(cstring,"");
do {
while (Serial.available()==0);
cstring[i] = Serial.read();
if(cstring[i]==13) {
cstring[i]=0;
break;
}
else i++;
} while(i < 10);

K=I;

if(cstring[0]!=0) { /* parse entered move */
K= cstring[0]-16*cstring[1]+799;
L= cstring[2]-16*cstring[3]+799;
}

Serial.print("\n DEBUG cstring : "); Serial.println(cstring);
sprintf(sbuf,"\n DEBUG K: %d \n DEBUG L: %d \n", K, L);
Serial.print(sbuf);

Serial.println(); Serial.println(cstring); Serial.println();

memcpy(oboard, board, sizeof(board));
oldto=mto;
oldEPSQ=EPSQ;

score=Minimax(-I, I, Q, EPSQ, 1, 3); /* think or check & do*/
Serial.print("\nscore="); Serial.println(score); Serial.println();

// if(ack!=15) {
RemP=S;
if(oboard[mto]) RemP=mto;
if(mto==oldEPSQ) RemP=oldto;

sprintf(sbuf,"\n\nmoved: >> %c%c", 'a'+(mfrom&7),'8'-(mfrom>>4) );

if(oboard[mto]) strcat(sbuf," X ");
else strcat(sbuf,"-");

sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
strcat(sbuf, sbuf2);
Serial.print(sbuf);

sprintf(sbuf, " (square %d to %d ) \n", mfrom, mto);
Serial.print("\n\nDEBUG:\n");
sprintf(sbuf2," EPsq: %c%c (%d)\n RemP: %c%c (%d)",
'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ,
'a'+(RemP&7), '8'-(RemP>>4&7), RemP);
strcat(sbuf, sbuf2);
Serial.print(sbuf);
Serial.print("\n\n");
// }
// else printf("\n\nILLEGAL!\n");

}
}




void setup() {
Serial.begin(9600);
}



void loop() {
chess();

while(1);
}

Peter(TOO)
18.11.2014, 23:49
Hallo,

Und WAS war der Fehler?

Ich habe keine Lust die beiden Listing zu vergleichen :-(

MfG Peter(TOO)

Peter(TOO)
19.11.2014, 00:54
Hallo,

Das wäre dann auf Compilerebene!

ANSI stellt es frei ob char als signed oder unsigned behandelt wird. Die meisten Compiler haben einen Parameter, mit welchem dies umgeschaltet werden kann.

Da ich schon vor 30 Jahren portablen C-Code schreiben musste, verwende ich char gar nie, sondern immer explizit unsigned char oder signed char. Selbiges natürlich gilt auch für int und long.

Der Faulheit halber habe ich dazu Macros in einem eigenen Header, dann schreibe ich uchar und schar, bzw. uint und sint....

Je nachdem welche CPU verwendet wird, ist char auch nicht immer 8-Bit lang.
In den 70er Jahren, als C entstanden ist, gab es auch noch Rechner, mit z.B. 9-, 12-. 18- und 36-Bit Registerbreite.
Heute ist so etwas hauptsächlich noch bei DSP zu finden.

In den ersten K&R Ausgaben stand dazu noch:
an darf nur annehmen, dass
char <= int <= long
ist. Man muss also damit rechnen, dass char auch 36-Bit lang sein kann.

MfG Peter(TOO)

Mxt
19.11.2014, 07:24
Hallo,

ich würde dann bei Code der auf 8- und 32-Bit Arduino laufen soll, besser auf diese neuen Datentypnamen zurückgreifen:
http://en.cppreference.com/w/cpp/types/integer

Dann sieht man besser, was gemeint ist. Den int16_t hatten wir ja weiter oben schon.

HaWe
19.11.2014, 08:50
int16 vers. int32 liegt auf der Hand, aber nachdem ein 8-bit AVR (int16) und auch ein 32 bit PC und ein 64 bit PC (beide int32) funktioniert haben, nur eben der 32bit ARM Cortex nicht, konnte es kaum daran gelegen haben. Trotzdem hatte ich es ntl bereits getestet.

(Und PeterTOO: char ist bei C doch immer 8 bit, nicht 32, zumindest bei gpp, Sketch, ToppersC, devcpp und CLANG und ntl auch hier in allen diesen angesprochenen Plattformen von AVR bis PC - wie kommst du darauf?)

Der hanebüchene Unsinn ist doch, dass Sketch mit demselben Sourcecode einmal für den Mega signed char und für den Due unsigned char compiliert, bloß weil es ARM und nicht AVR ist - welcher normal denkende Mensch, der nicht embedded C mit der Muttermilch aufgesogen hat, kommt denn auf diesen Mist ??
Zumal gerade Sketch für unsigned char einen eigenen Datentyp zur Verfügung stellt, nämlich byte ?!?!

Und Sketch ist schließlich für Arduino-Programmierer, die - behaupte ich mal - überwiegend KEINE Profi-Programmierer sind!
Und ich möchte mal wirklich gerne einen Querschnitt über alle hier jemals von Forumsmitgliedern prorgammierten Codes sehen, ob da wirklich "immer schon" explizit signed oder unsigned vor jedem char steht. Sicher nicht, warum auch?

Noch nicht einmal der Programmierer, sicher Profi, wenn auch nicht hauptberuflich, von dem der hier diskutierte Sourcecode ursprünglich stammt, hat es weder selber gemacht noch irgendwo in seinen über 30 Seiten langen Erklärungen auch nur andeutungsweise auf diese Plattformabhängigkeit hingewiesen.

Aber selbst hier im Forum mit seiner gesammelten Schwarmintelligenz hat NIEMAND vorher auch nur den VERDACHT geäußert, dass es daran liegen könnte.

HINTERHER ist es ntl einfach zu sagen: klar, hab ich gewusst, mache ich immer schon so. Toll.

Diese ARM-(C-Compiler-Programmier-) Leuchter die sich diese gequirlte signed/unsigned char- Schei*** auf derselben (Sketch-) IDE ausgedacht haben sollte man doch wirklich an die Wand stellen, also wirklich... :mad:

Immerhin sind wir jetzt alle klüger (zumindest die, die es seit 30 Jahren nicht sowieso immer schon so gemacht haben) und viele können sicher davon profitieren - auch sicher die, die hier tatkräftig mitgeholfen haben:
an euch dafür nochmal ausdrücklich einen herzlichen Dank ! :cool:

oberallgeier
19.11.2014, 09:36
... char ist bei C doch immer 8 bit, nicht 32, zumindest bei gpp, Sketch, ToppersC, devcpp und CLANG und ...Bei diesen fundamentalen Diskussionen kann ich als kleines Licht in C ja wirklich nicht mitreden. Aber ich weiß ganz gewiss, dass im ANSI-Standard die Größe char als ein Byte bzw. die kleinste, adressierbare Größe einer Maschine definiert ist - und damit keine Festlegung auf eine bestimmte Bitanzahl existiert. In C11 wurden zur Unterstützung von Unicodes dann char16_t und char32_t eingeführt. Andererseits war in den Fünfzigern bei IBM das Byte zeitweise sogar nur sechs Bit groß *ggg*.

Da ich die oben aufgeführten Programmiersprachen nicht oder kaum und C nicht bis in die letzten Ecken kenne und da ich insbesondere mit Compilerbau nur sehr speziell beschäftig war, wundere ich mich jedenfalls nicht über die hier diskutierte Falschrechnerei.

Peter(TOO)
19.11.2014, 14:45
Hallo,


ich würde dann bei Code der auf 8- und 32-Bit Arduino laufen soll, besser auf diese neuen Datentypnamen zurückgreifen:
http://en.cppreference.com/w/cpp/types/integer

Dann sieht man besser, was gemeint ist. Den int16_t hatten wir ja weiter oben schon.

Diese gibt es erst seit ANSI C 2011 als Standard.
Ich bin mich ja auch am umgewöhnen.

1985 gab es noch Macro-Header, damit C wie Pascal aussieht :-(
Es gab da, vor allem in Deutschland, eine Gruppe, welche BEGIN und END besser fand als { und }.

MfG Peter(TOO)

- - - Aktualisiert - - -

Hallo,

(Und PeterTOO: char ist bei C doch immer 8 bit, nicht 32, zumindest bei gpp, Sketch, ToppersC, devcpp und CLANG und ntl auch hier in allen diesen angesprochenen Plattformen von AVR bis PC - wie kommst du darauf?)C

Wie schon K&R macht auch ANSI keine konkreten Vorgaben dazu.

Wie sich ein Compiler konkret verhält ist im Anhang "Compiler-Specific" des Compiler-Manuals beschrieben, dieses Kapitel wird von ANSI vorgeschrieben.

Leider ist auch der ANSI C Standard nicht frei verfügbar, ich zitiere deshalb, was ich so finden kann.

http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf
(Ist zwar C99, das hat sich aber nicht grundlegend geändert)

Seite 3:
The potential for efficient code generation is one of the most important strengths of C. To help ensure that no code explosion occurs for what
appears to be a very simple operation, many operations are defined to be how the target
machine’s hardware does it rather than by a general abstract rule. An example of this
willingness to live with what the machine does can be seen in the rules that govern the widening
of char objects for use in expressions: whether the values of char objects widen to signed or
unsigned quantities typically depends on which byte operation is more efficient on the target
machine.

signed oder unsiged hängt also davon ab, was die CPU effizienter verarbeiten kann. Gibt's da bei der CPU keinen Unterschied, kann der Compilerbauer frei wählen. Selbiges gilt für die Anzahl Bits in einem Byte.

Vielleicht muss ich noch einen Abstecher in die Geschichte machen.
Der Fachbegriff für 8-Bit Worte ist Oktett oder Octet. Wurde von CCITT, heute ITU, mal definiert.
Vor den 70er Jahren gab es nur Worte (Words), das war das was die CPU als kleinste Einheit transportieren konnte, das war praktisch Alles zwischen 8 und 48 Bit, je nach Registergrösse und Busbreite, also CPU abhängig.
Das Byte kam dann erst durch die Hobbycomputer-Scene und meinte damals noch 8-Bit, weil die meisten CPUs einen 8-Bit Bus hatten.
Byte kommt von Bite (Biss, Bissen), das war das was die CPU auf einmal vom Speicher "abbeissen" konnte, also ein Synonym für Wort.


Seite 11:
3. Terms and definitions
The definitions of object, bit, byte, and alignment reflect a strong consensus, reached after
considerable discussion, about the fundamental nature of the memory organization of a C
environment:
• All objects in C must be representable as a contiguous sequence of bytes, each of which
is at least 8 bits wide.
• A char whether signed or unsigned, occupies exactly one byte.
(Thus, for instance, on a machine with 36-bit words, a byte can be defined to consist of 9, 12, 18,
or 36 bits, these numbers being all the exact divisors of 36 which are not less than 8.) These
10 strictures codify the widespread presumption that any object can be treated as an array of
characters, the size of which is given by the sizeof operator with that object’s type as its
operand.

Ein Byte ist nur garantiert nicht kürzer als 8-Bit!

Seite 25:
The macro CHAR_BIT makes available the number of bits in a char object. The C89
Committee saw little utility in adding such macros for other data types.

Macht keinen Sinn, wenn char immer 8-Bit ist ;-)

Seite 65:
6.5.3.4 The sizeof operator
It is fundamental to the correct usage of functions such as malloc and fread that
sizeof(char) be exactly one. In practice, this means that a byte in C terms is the smallest
unit of storage, even if this unit is 36 bits wide; and all objects are composed of an integer
number of these smallest units. Also applies if memory is bit addressable.

Das sollte erst mal reichen.

Die Definition von Byte in C hat sich eigentlich nie geändert. Als C entwickelt wurde war es noch üblich, dass CPUs "komische Wortbreiten" verwendeten. Damals waren auch noch Sektorgrössen von 100 oder 200 Oktetts bei Plattenspeichern üblich.
Das CPUS einheitlich eine Busbreite basierend auf 2er Potenzen haben (8, 16, 32 ...) ist eine neuere Entwicklung, welche erst mit dem Mikroprozessoren begann.
Wie ich schon erwähne, sind davon abweichende Busbreiten vor allem bei DSP zu finden, da geht es rein um die Effizienz.
Allerdings haben z.B. die PICs teilweise auch Bus- und Wortbreiten von 12 Bit.

MfG Peter(TOO)

HaWe
19.11.2014, 15:01
bleiben wir doch bitte mal auf dem Teppich.
Wir reden hier von gängigen Compilern (Sketch, gpp, Clang, devcpp) für AVR, Windows XP oder 7 PCs 32 oder 64 bit, ARM (Cortex) und Beaglebone Black.
Wo ist da bitteschön char mit mehr als 8 bit ??

Also jetzt bitte keine geschichtsträchtigen Dozentenvorträge über Annodazumal und Adam und Eva und irgendwelche Kolibriplattformen.

Es geht auch gar nicht um das, was definiert ist oder nicht oder 8-bit char oder nicht oder mehr oder hin oder her, sondern schlicht darum:

Der Sketch-Mist besteht darin, dass immer char als 8-bit und signed kompiliert wurde und wird (und übrigens auch für die Windows-Plattformen), woran man sich gewöhnt hat, gerade weil es für "unsigned char" ja auch "byte" verwendet (obwohl "byte" kein standardmäßiger C-Datentyp ist) -
jetzt aber wird char von Sketch im selben Sourcecode plötzlich, nur für den Due, mit unsigned übersetzt, und damit fällt auch plötzlich der Unterschied zu "byte".
Nimmt man genau diesen Sourcecode bei weiterhin geöffnetem Editor und wählt als Ziel wieder einen AVR, ist es aber wieder signed wie früher. Selber Code, beides Arduino-Sketch, beides dieselbe Version, beides Arduino-Boards, aber 2 verschiedene Rechenergebnisse.

Natürlich dürfen die (Arduino-) Entwickler mit ihrem Compiler, auf Deutsch gesagt, jeden Scheißdreck machen, gerade wenn es nicht fest definiert ist, und es trotzdem als C verkaufen.
Besser wird es dadurch aber nicht.

Allerdings scheine ich der einzige zu sein, der hier bisher darüber gestolpert ist.

Gut immerhin, dass wir alle es jetzt besser wissen.

Peter(TOO)
19.11.2014, 16:07
Hallo,

bleiben wir doch bitte mal auf dem Teppich.
Wir reden hier von gängigen Compilern (Sketch, gpp, Clang, devcpp) für AVR, Windows XP oder 7 PCs 32 oder 64 bit, ARM (Cortex) und Beaglebone Black.
Wo ist da bitteschön char mit mehr als 8 bit ??

Du hast mir widersprochen und behauptet, dass char in C immer 8-Bit hat.
Dem ist aber, nach Norm, nicht so.
GCC ist da auch unterschiedlich, je nach verwendetem Prozessor.
Hinzu kommt noch, dass sich die unterschiedlichen CPU-Gemeinden auch an "ihren" Standard gewöhnt haben und sich die anderen Compilerhersteller danach richten.
Das erst was ich bei einem Compiler mache, ist ein Blick in das Kapitel "Compiler-Specific"


Es geht auch gar nicht um das, was definiert ist oder nicht oder 8-bit char oder nicht oder mehr oder hin oder her, sondern schlicht darum:

Der Sketch-Mist besteht darin, dass immer char als 8-bit und signed kompiliert wurde und wird (und übrigens auch für die Windows-Plattformen), woran man sich gewöhnt hat, gerade weil es für "unsigned char" ja auch "byte" verwendet (obwohl "byte" kein standardmäßiger C-Datentyp ist) -
jetzt aber wird char von Sketch im selben Sourcecode plötzlich, nur für den Due, mit unsigned übersetzt, und damit fällt auch plötzlich der Unterschied zu "byte".

Natürlich dürfen die (Arduino-) Entwickler mit ihrem Compiler, auf Deutsch gesagt, jeden Scheißdreck machen, gerade wenn es nicht fest definiert ist, und es trotzdem als C verkaufen.
Besser wird es dadurch aber nicht.

Da ist aber ein Problem der Arduino-Entwickler.
Die müssten beim Aufruf des Compilers nur den passenden Toggle setzen.
Nun bekommst du aber Probleme, wenn du Sourcode direkt aus dem ARM-Pool übernimmst :-(


Allerdings scheine ich der einzige zu sein, der hier bisher darüber gestolpert ist.
Gut immerhin, dass wir alle es jetzt besser wissen.

Du hast dich bisher nur noch nicht mit portierbarem Code beschäftigt.
Sorry, dass ich nicht an signed/unsigned gedacht habe, aber dieses Problem hatte ich seit über 20 Jahren nicht mehr, wieso habe ich dir auch geschrieben.

Liegt vermutlich daran, dass ich seit je her immer mit unterschiedlichen CPUs/Mikrocontrollern zu tun hatte.

Ich habe sehr viel portablen Code geschrieben, hauptsächlich Übertragungsprotokolle. Da ist das Hauptproblem die Endian-Geschichte. Aber man kann die Umsetzung in C so schreiben, dass es portabel ist int in char zu verwandeln, allerdings darf man keine Union verwenden.

MfG Peter(TOO)

HaWe
19.11.2014, 19:12
entschuldige bitte, ich mache doch niemanden einen Vorwurf daraus, dass er an diesen blödsinniges signed/unsigned char-Mist nicht gedacht hat!
Im Gegenteil!
Ich finde es nur absolut ärgerlich, dass innerhalb ein und derselben IDE ohne jeden Hinweis der Compiler aus negativen plötzlich positive Zahlen macht, nur weil man als Hobby-Programmierer ein anderes Board im Dropdown-Menü auswählt!!

HaWe
20.11.2014, 00:08
so - zurück zum Code...

wer jetzt mal ein bisschen Schach spielen (testen) möchte auf einen Due mit wirklich akzeptabler Spielstärke bei erträglicher Denkzeit mit bis zu 400000 durchgerechneten Zügen für max 80000 Knoten (willkürlich) und bis zu 8 Halbzügen Denktiefe, etwas "grafisch" aufgepimpt, hier ist der Code:



/************************************************** *************************/
/* micro-Max, */
/* A chess program smaller than 2KB (of non-blank source), by H.G. Muller */
/************************************************** *************************/
/* version 4.8.n Sketch (1953 characters) features: */
/* - recursive negamax search */
/* - all-capture MVV/LVA quiescence search */
/* - (internal) iterative deepening */
/* - best-move-first 'sorting' */
/* - a hash table storing score and best move */
/* - futility pruning */
/* - king safety through magnetic, frozen king in middle-game */
/* - R=2 null-move pruning */
/* - keep hash and repetition-draw detection */
/* - better defense against passers through gradual promotion */
/* - extend check evasions in inner nodes */
/* - reduction of all non-Pawn, non-capture moves except hash move (LMR) */
/* - full FIDE rules (expt under-promotion) and move-legality checking */


#define K(A,B) *(int*)(T+A+(B&8)+S*(B&7))

#define HTsize (1<<12) // wegen RAM, für PC: (1<<24)
struct HTab {
int K,
V;
int X,
Y,
D;
} HTarray[HTsize]; /* hash table, HTsize entries*/


#define MAXNODES 80000 // wegen Zugdauer; für PC: x10 = 800000 = 8e5

int K,
Q,
R,
J,
Z;

int32_t N,
I=80000; /* I=80000: "infinity score" */ ;

int
M=136, /* M=0x88 board system */
S=128, /* dummy square 0x80, highest valid square =127 */
turn=16; // 16=Weiss, 8=Schwarz; turn^=24 wechselt hin unnd her

signed char L,
pval[]={0,2,2,7,-1,8,12,23}, /* relative piece values */
vector[]={-16,-15,-17,0,1,16,0,1,16,15,17,0,14,18,31,33,0, /* step-vector lists */
7,-1,11,6,8,3,6}, /* 1st dir. in vector[] per piece*/

bsetup[]={6,3,5,7,4,5,3,6}, /* initial piece setup */
board[129], /* board: half of 16x8+dummy*/
T[1035]; /* hash translation table */

signed char psymbol[]= ".?+nkbrq?*?NKBRQ";

int mfrom, mto; // current ply from - to
int EPSQ, // e.p. square
RemP; // remove piece




/* recursive minimax search, turn=moving side, n=depth*/

int Minimax(int32_t q, int32_t l, int32_t score, int EPC, int prev, int32_t hashkey)
/* (q,l)=window, score, EnPass_sqr.*/
/* prev=prev.dest; J,Z=hashkeys; return score*/
{
int j,
r,
m,
v,
d,
h,
i,
F,
G,
V,
P,
f=J,
g=Z,
C,
s;
signed char t,
p,
upiece,
x,
y,
X,
Y,
H,
B;

struct HTab *a = HTarray + (J + turn * EPC & HTsize-1); /* lookup pos. in hash table*/

char sbuf[50];



q--; /* adj. window: delay bonus */
turn^=24; /* change sides */
d=a->D;
m=a->V;
X=a->X;
Y=a->Y; /* resume at stored depth */

if(a->K-Z|prev| /* miss: other pos. or empty*/
!(m<=q | X&8&&m>=l | X&S)) /* or window incompatible */
{ d=Y=0; } /* start iter. from scratch */

X&=~M; /* start at best-move hint */

while( d++ < hashkey || d<3 /* iterative deepening loop */
|| prev&K == I
&& ( N<60000 & d<98 /* root: deepen upto time */
|| (K=X, L=Y&~M, d=3)
)
) /* time's up: go do best */
{
x=B=X; /* start scan at prev. best */
h=Y&S; /* request try noncastl. 1st*/
P=d<3 ? I : Minimax(-l,1-l,-score,S,0,d-3); /* Search null move */
m = (-P<l | R>35) ? ( d>2 ? -I : score ) : -P; /* Prune or stand-pat */
N++; /* node count (for timing) */
do
{
upiece=board[x]; /* scan board looking for */
if(upiece & turn) /* own piece (inefficient!)*/
{
r = p = upiece&7; /* p = piece type (set r>0) */
j = vector[p+16]; /* first step vector f.piece*/
while(r = p>2 & r<0 ? -r : -vector[++j] ) /* loop over directions vector[] */
{
labelA: /* resume normal after best */
y=x; /* (x,y)=move */
F=G=S; /* (F,G)=castl.R */

do
{ /* y traverses ray, or: */
H=y=h?Y^h:y+r; /* sneak in prev. best move */

if(y&M)break; /* board edge hit */

m= EPC-S&board[EPC]&&y-EPC<2&EPC-y<2?I:m; /* bad castling */

if(p<3&y==EPC)H^=16; /* shift capt.sqr. H if e.p.*/

t=board[H];

if(t&turn|p<3&!(y-x&7)-!t)break; /* capt. own, bad pawn mode */
i=37*pval[t&7]+(t&192); /* value of capt. piece t */
m=i<0?I:m; /* K capture */

if(m>=l&d>1) goto labelC; /* abort on fail high */

v=d-1?score:i-p; /* MVV/LVA scoring */

if(d-!t>1) /* remaining depth */
{
v=p<6?board[x+8]-board[y+8]:0; /* center positional pts. */
board[G]=board[H]=board[x]=0;board[y]=upiece|32; /* do move, set non-virgin */
if(!(G&M))board[F]=turn+6,v+=50; /* castling: put R & score */
v-=p-4|R>29?0:20; /* penalize mid-game K move */

if(p<3) /* pawns: */
{
v-=9*((x-2&M||board[x-2]-upiece)+ /* structure, undefended */
(x+2&M||board[x+2]-upiece)-1 /* squares plus bias */
+(board[x^16]==turn+36)) /* kling to non-virgin King */
-(R>>2); /* end-game Pawn-push bonus */
V=y+r+1&S?647-p:2*(upiece&y+16&32); /* promotion or 6/7th bonus */
board[y]+=V;
i+=V; /* change piece, add score */
}

v+= score+i;
V=m>q ? m : q; /* new eval and alpha */
J+=K(y+0,board[y])-K(x+0,upiece)-K(H+0,t);
Z+=K(y+8,board[y])-K(x+8,upiece)-K(H+8,t)+G -S; /* update hash key */
C=d-1-(d>5&p>2&!t&!h);
C=R>29|d<3|P-I?C:d; /* extend 1 ply if in check */
do {
s=C>2|v>V?-Minimax(-l,-V,-v, /* recursive eval. of reply */
F,0,C):v; /* or fail low if futile */
} while( s>q & ++C<d );

v=s;
if(prev&&K-I&&v+I&&x==K&y==L) /* move pending & in root: */
{
Q=-score-i; EPSQ=F; /* exit if legal & found */
a->D=99;a->V=0; /* lock game in hash as draw*/
R+=i>>7;
return l; /* captured non-P material */
}
J=f;
Z=g; /* restore hash key */
board[G]=turn+6;
board[F]=board[y]=0;
board[x]=upiece;
board[H]=t; /* undo move,G can be dummy */
}
if(v>m) /* new best, update max,best*/
{
m=v,X=x,Y=y|S&F; /* mark double move with S */
}
if(h)
{
h=0;
goto labelA; /* redo after doing old best*/
}
if (
x+r-y|upiece&32| /* not 1st step,moved before*/
p>2 & (
p-4|j-7|| /* no P & no lateral K move,*/
board[G=x+3^r>>1&7]-turn-6 /* no virgin R in corner G, */
|| board[G^1] | board[G^2] ) /* no 2 empty sq. next to R */
)
{
t+=p<5;
} /* fake capt. for nonsliding*/
else F=y; /* enable e.p. */

} while(!t); /* if not capt. continue ray*/

}
} // (upiece & turn)

} while((x=x+9&~M)-B); /* next sqr. of board, wrap */

labelC:
if (m>I-M|m<M-I) d=98; /* mate holds to any depth */
m= m+I|P==I ? m : 0; /* best loses K: (stale)mate*/

if(a->D<99) { /* protect game history */
a->K=Z;
a->V=m;
a->D=d; /* always store in hash tab */
a->X=X|8*(m>q)|S*(m<l);
a->Y=Y; /* move, type (bound/exact),*/
}
/* uncomment for Kibitz */
//if(prev) sprintf(sbuf, "%2d ply, %9d searched, score=%6d by %c%c%c%c\n",
// d-1, N-S, m, 'a'+(X&7),'8'-(X>>4),'a'+(Y&7),'8'-(Y>>4&7));

if(prev && X!=Y) {
sprintf(sbuf, "\n%2d ply, searched: %9d ", d-1, N-S );
Serial.print(sbuf);
}
else
if( ((N-S)%10000)<1) Serial.print(".");


} // while (iterative deepening loop)

turn^=24; /* change sides back */
mfrom=K; mto=L;
return m+= m<score; /* delayed-loss bonus */
}





void chess()
{
int32_t score, i;
int16_t oldto, oldEPSQ;
char sbuf[50], sbuf2[50];
char cstring[20];
signed char oboard[129], spiece;


K=8;
while(K--)
{
board[K]=(board[K+112]=bsetup[K]+8)+8;
board[K+16]=18;
board[K+96]=9; /* initial board setup*/
L=8;
while(L--)board[16*L+K+8]=(K-4)*(K-4)+(L-3.5)*(L-3.5); /* center-pts table */
} /*(in unused half board[])*/
N=1035;
while(N-->M)T[N]=rand()>>9;

/* play loop */
while(1)
{
N=-1;

Serial.print("\n");

sprintf(sbuf," A B C D E F G H \n --------------- \n"); Serial.print(sbuf);
while(++N<121) { /* print board */
if(N&8 && (N+7!=0) ) {sprintf(sbuf,"%3d \n", 1+((120-N)>>4)); Serial.print(sbuf); N+=7; }
else {
if(N%8==0) {sprintf(sbuf, "%3d ", 1+((120-N)>>4)); Serial.print(sbuf); }
sprintf(sbuf," %c", psymbol[board[N]&15]); Serial.print(sbuf);
}
}
sprintf(sbuf," --------------- \n A B C D E F G H "); Serial.print(sbuf);

if(turn==16) sprintf(sbuf,"\n> WHITE: "); else sprintf(sbuf,"\n> BLACK: ");
Serial.print(sbuf);

i = 0;
strcpy(cstring,"");
do {
while (Serial.available()==0);
cstring[i] = Serial.read();
if(cstring[i]==13) {
cstring[i]=0;
break;
}
else i++;
} while(i < 10);

K=I;

if(cstring[0]!=0) { /* parse entered move */
K= cstring[0]-16*cstring[1]+799;
L= cstring[2]-16*cstring[3]+799;
}
/*
Serial.print("\n DEBUG cstring : "); Serial.print(cstring);
sprintf(sbuf,"\n DEBUG K: %d \n DEBUG L: %d \n", K, L);
Serial.print(sbuf);
*/
memcpy(oboard, board, sizeof(board));
oldto=mto;
oldEPSQ=EPSQ;

score=Minimax(-I, I, Q, EPSQ, 1, 3); /* think or check & do*/

if(score!=15) {
RemP=S;
if(oboard[mto]) RemP=mto;
if(mto==oldEPSQ) RemP=oldto;

spiece=psymbol[board[mto]&15];
if(spiece=='*' || spiece=='+') spiece=' ';
sprintf(sbuf,"\n\nmoved: >> %c %c%c", spiece,'a'+(mfrom&7),'8'-(mfrom>>4) );

if(oboard[mto]) strcat(sbuf," X ");
else strcat(sbuf,"-");

sprintf(sbuf2,"%c%c ", 'a'+(mto&7),'8'-(mto>>4&7));
strcat(sbuf, sbuf2);
Serial.print(sbuf);

sprintf(sbuf, " \nDEBUG: %d to %d \n", mfrom, mto);
Serial.print(sbuf);
sprintf(sbuf," EPsq: %c%c (%3d)\n",
'a'+(EPSQ&7), '8'-(EPSQ>>4&7), EPSQ); Serial.print(sbuf);
sprintf(sbuf," RemP: %c%c (%3d)\n\n",
'a'+(RemP&7), '8'-(RemP>>4&7), RemP); Serial.print(sbuf);
}
else printf("\n\nILLEGAL!\n");

}
}




void setup() {
Serial.begin(9600);
}



void loop() {
chess();

while(1);
}



erstaunlich schlau, die Chess Engine von Muller! :cool:

nun kann mein Schachroboter https://www.youtube.com/watch?v=Cv-yzuebC7E schon fast mit Turnierspielstärke antreten... :)

Klebwax
20.11.2014, 15:22
Wo war denn nun das wirkliche Problem. Ob eine "kleine" Zahl nun als signed oder unsigned char gespeichert wird, ist doch wohl egal. Aber bei welcher Operation läuft das Programm denn falsch? Und sollte man das Programm dann nicht da anpassen, damit es einfach mit chars läuft.

MfG Klebwax

HaWe
20.11.2014, 16:07
das Programm verlangt überwiegend "signed char", weil meist auch negative Werte vorkommen können (-128...+127),
das ist aber auch die Standardeinstellung für char auf AVR und für Windows-PC bzw. Konsole, und daher lief es dort auch problemlos von Anfang an.

Der Fehler war, dass Sketch für den Due "char" aber mit "unsigned char" (== "byte") übersetzt hat, daher bekamen negative Zahlen dann plötzlich positive Werte zugewiesen. Die Zahl "-1" wurde daher z.B. als "255" gelesen.
Daher musste man bei den chars aus dem Ursprungsprogramm überall "signed" davorschreiben.
Man darf es allerdings nicht dort davorschreiben, wo anschließend eine Typen-Konversion zu int oder long stattfindet, denn da steigt dann der Sketch-Compiler wieder aus.
Übrigens: wenn man per Serial Buchstaben-Zeichen ausgibt, kann es mit unsigned char (== "byte") ebenfalls Probleme geben (da wird dann der ASCII-Code des Buchstabens geschrieben, nicht der Buchstabe selber). Das habe ich aber schon sehr früh festgestellt, daher habe ich immer erst sprintf() benutzt bevor ich dann Serial aufgerufen habe. In diesen Fällen musste man jetzt kein "signed" mehr davorschreiben.

Klebwax
20.11.2014, 20:06
Ein char ist halt gut genug, ein character, einen Buchstaben zu speichern. Buchstaben haben nichts ansich, was die Bedeutung eines Vorzeichens hat. Deswegen macht signed oder unsigned bei Buchstaben keinen Sinn und ist für ein char nicht vorgegeben. Überhaupt macht das Rechnen mit Buchstaben keinen Sinn (außer so ein paar Tricks die Groß in Kleinbuchstaben rechnen o.ä.).

Wenn ich eine Ganzzahl, einen Integer, haben möchte, der in 8 Bit passt, dann sollte ich das auch so sagen: int8_t. Da gibts dann keine Zweideutigkeiten oder Compilerabhängigkeiten. Obwohl man bei den heute verfügbaren Speichergrößen das einfach knicken und int nehmen sollte: dann klappts auch mit dem Nachbarn, äh mit jedem anderen Prozessor oder Kompiler

MfG Klebwax

HaWe
20.11.2014, 20:54
Mann, du Roboter-Genie... das ist doch jetzt wirklich müßig, das zum hunderttausendsten Mal jetzt noch mal besserwisserisch aufzuwärmen - danke aber für den netten Versuch ;)

(ps, edit: immerhin ist der Code auch viel älter als 2011, und davor gabs noch gar kein int8_t, char war und ist immer noch ein gültiger Datentyp in C, und signed char mit negativen Werten sicher auch nicht als "negative Buchstaben" zu verstehen - aber auch das ist hier inzwischen völlig belanglos, das Problem ist ja auch darüberhinaus längst erkannt und gelöst. Hier mit "Wort-eigentümlichen" semantischen Begrifflichkeiten zu jonglieren, entbehrt auch jeder Grundlage - was, bitte ist dann ein Bissen? oder ein Wort? Oder ein Unversehrtes? oder ein Langes? Dein Post ist also nicht nur sachlich falsch - sondern auch absolut (!) mehr als flüssig... Naja, manche können es halt nicht lassen...)

Andre_S
21.11.2014, 07:42
Ein char ist halt gut genug, ein character, einen Buchstaben zu speichern. Buchstaben haben nichts ansich, was die Bedeutung eines Vorzeichens hat. Deswegen macht signed oder unsigned bei Buchstaben keinen Sinn und ist für ein char nicht vorgegeben. Überhaupt macht das Rechnen mit Buchstaben keinen Sinn (außer so ein paar Tricks die Groß in Kleinbuchstaben rechnen o.ä.).
...
MfG Klebwax

Hallo,
wir sollten nicht alles verallgemeinern, es trifft halt nicht überall zu…

Auszug aus meiner Entwicklungsumgebung „mikroC für dsPIC:



Type
Size in bytes
Range


Bit
1–bit
0 or 1


Sbit
1–bit
0 or 1


(unsigned) char

1
0 .. 255


signed char
1
- 128 .. 127


(signed) short (int)
1
- 128 .. 127


unsigned short (int)
1
0 .. 255


(signed) int
2
-32768 .. 32767


unsigned (int)
2
0 .. 65535


(signed) long (int)
4
-2147483648 .. 2147483647


unsigned long (int)
4
0 .. 4294967295




Gruß André

HaWe
21.11.2014, 07:49
danke für die Schützenhilfe, aber für Intel x86, Win32, Win64, und AVR von Arduino Micro über Uno und Leonardo bis Mega wird "char" als "signed" behandelt.
Aber wie gesagt, Schnee von gestern. Die tollen Arduino-IDE-Programmierer hätten da in ihr tolles Sketch für gefühlt 10000 verschiedene Boards wenigstens eine Compilerwarnung für den Due einbauen können, wenn sie char jetzt plötzlich anders behandeln als für die 9999 übrigen Boards.

Ich denke, mit deiner Übersicht und diesen abschließenden Worten können wir das Thema schließen und uns jetzt wieder der Zukunft zuwenden. 8-)

(editiert, erst falsch rum gelesen)

Klebwax
21.11.2014, 13:58
Hallo,
wir sollten nicht alles verallgemeinern, es trifft halt nicht überall zu…

Auszug aus meiner Entwicklungsumgebung „mikroC für dsPIC:



Type
Size in bytes
Range


Bit
1–bit
0 or 1


Sbit
1–bit
0 or 1


(unsigned) char

1
0 .. 255


signed char
1
- 128 .. 127


(signed) short (int)
1
- 128 .. 127


unsigned short (int)
1
0 .. 255


(signed) int
2
-32768 .. 32767


unsigned (int)
2
0 .. 65535


(signed) long (int)
4
-2147483648 .. 2147483647


unsigned long (int)
4
0 .. 4294967295




Diese Tabelle hat leider einen kleinen Schönheitsfehler, und der beschreibt auch das ganze Problem hier. Sie gilt nur für mikroC. Es gibt in C keine Vorgabe, ob ein char (ohne einen Zusatz) als signed oder unsigned behandelt wird. Warum, habe ich beschrieben. Jeder Compiler kann es also anders halten, und tut es auch, wie dieser Tread zeigt.

Um diesen und ähnlichen Problemen aus dem Wege zu gehen, gibts nun mal stdint.h.


danke für die Schützenhilfe, aber für Intel x86, Win32, Win64, und AVR von Arduino Micro über Uno und Leonardo bis Mega wird "char" als "signed" behandelt.
Das hängt nicht vom Prozessor ab, sondern vom Compiler

Aber wie gesagt, Schnee von gestern. Die tollen Arduino-IDE-Programmierer hätten da in ihr tolles Sketch für gefühlt 10000 verschiedene Boards wenigstens eine Compilerwarnung für den Due einbauen können, wenn sie char jetzt plötzlich anders behandeln als für die 9999 übrigen Boards.
Die IDE ist nur das Frontend für irgendeinen Compiler, den kann man meist sogar tauschen. Die IDE kann also nicht wissen, wie sich der gerade eingestellte Compiler verhält.

Es ist doch ganz einfach: wer sicher sein will, daß sein char signed ist, muß es explizit hinschreiben! Oder, um mich zu wiederholen, stdint.h.

MfG Klebwax

Andre_S
21.11.2014, 14:46
Hallo,

belassen wir es doch einfach dabei,.. dann passt es "sogar" für microC ;)



... wer sicher sein will, daß sein char signed ist, muß es explizit hinschreiben!
...
MfG Klebwax


Gruß André

HaWe
21.11.2014, 15:05
mein Gott, Klebwax, kleb dir deine Besserwisserei doch irgendwohin.
Für Leute, die erst nichts zur Problemlösung beitragen, und hinterher, wenn alles klar ist, alles nochmal aufwärmen und breittreten, als hätten sie die Weisheit mit Löffeln gefressen, habe ich EINIGE Kategorien zu vergeben.
Klugscheißer und Korinthenkacker sind noch die mildesten.

RoboHolIC
21.11.2014, 21:27
@Klebwax:

Diese Tabelle . . . gilt nur für mikroC. . . Jeder Compiler kann es also anders halten

Um diesen und ähnlichen Problemen aus dem Wege zu gehen, gibts nun mal stdint.h.


Danke Dir und den anderen. Ich hab was gelernt, um irgendwann in Zukunft C-Source pflegbar portabel zu schreiben: nämlich das einziehen einer Abstraktionssebene für die Typbezeichner.

Leider ist Abstraktion nicht jedermanns Sache.
Und Selbstbeherrschung bei sozialen Interaktionen auch nicht.


mein Gott, Klebwax, kleb dir deine Besserwisserei doch . . .
Klugscheißer und Korinthenkacker sind noch die mildesten.