|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T d
Length: 23993 (0x5db9) Types: TextFile Names: »dam.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987 └─⟦this⟧ »EUUGD18/General/Draughts/dam.c«
/* Copyright (C) A.E. Brouwer, Amsterdam, 1977,1985 */ /* Interactive draugths playing program */ /* Version 1.0, AEB, Easter monday 1977 */ /* Version 2.0, AEB&CLP, 770514 */ /* Version 3.0, AEB&CLP, 771203 */ /* Linted and converted to BSD4.2, AEB, 850725 */ #include <setjmp.h> #include <signal.h> #include "damdefs.h" #define MSIZE 3000 #define GSIZE 1000 /* Numbering of the board: 00 01 02 03 04 05 05 06 07 08 09 10 11 12 13 14 15 16 16 17 18 19 20 21 22 23 24 25 26 27 27 28 29 30 31 32 33 34 35 36 37 38 38 39 40 41 42 43 44 45 46 47 48 49 49 50 51 52 53 54 55 56 57 58 59 60 60 61 62 63 64 65 where the fields 0-5, 16, 27, 38, 49, 60-65 constitute the edge of the board. Note: the fields with numbers divisible by 5 form the main diagonal (see 'value(c)'). Conversion tables: */ int conv[51] = { 0, 6, 7, 8, 9,10, 11,12,13,14,15, 17,18,19,20,21, 22,23,24,25,26, 28,29,30,31,32, 33,34,35,36,37, 39,40,41,42,43, 44,45,46,47,48, 50,51,52,53,54, 55,56,57,58,59 }; int reconv[66] = { 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 0, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 0, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 0, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 0, 0, 0, 0, 0, 0 }; int bord[66]; int game[GSIZE]; int *gp = &game[0]; int moves[MSIZE]; int playb,playw; int mvnr = 1; /* odd means black's move */ int endgame = 0; /* endgame strategy */ int fouragnst1 = 0; /* four kings against one */ int lasthap = 1; /* draw if nothing happens for too long */ int drawdel = DRAWWT; /* 3 or 10 or DRAWWT */ int me = WHITE; /* player to move */ int optp = 1; /* frequency of prbord() */ int optg = 0; /* nonzero if game */ int optu = 0; /* print evaluation */ /* bit0: static evaluation of position bit1: static evaluation of each move bit2: evaluation of position bit3: evaluation of each move */ int optf = -1; /* file descriptor of ofile */ int userand = 1; int rdif = 100; /* cannot be much larger */ int rdifmin = 100; /* min used during this game */ int rdmin = 1; /* minimum recursion depth */ int rdmax = 10; /* maximum recursion depth */ int fplevel = 1; /* level of search for free paths */ int captct,captmax, *mpf,*mp0,*mp,possct; extern int *findmove(), *readmove(); extern long lseek(); int debug,crownmv,altermv; int rescct; int wpct,bpct,wkct,bkct; /* global */ int timeb,timew; /* time used by b/w (in seconds) */ int timemax = 10; /* nr of seconds allowed per move */ extern int value2(),value(),evalue(); int (*avalue)() = value; int (*stratw)(),(*stratb)(); int (*(strategies[]))() = { value, value2, evalue }; extern int pb,disp,dirt,prall,prbwait; extern char line[]; extern int rdbord[]; setstrat(w,b) int w,b; { register int i; i = sizeof(strategies)/2; if(w >= i || b >= i){ pmesg("no such strategies\n"); return; } stratw = strategies[w]; stratb = strategies[b]; pmesg("strategies %d(w),%d(b)\n",w,b); } intrup(){ (void) signal(SIGINT,SIG_IGN); /* no more interrupts */ if(disp) delay(); pmesg("?"); rdlin(); rdcomd(line); (void) signal(SIGINT,intrup); if(!mpf){ pmesg("you cannot change the board during an interrupt\n"); reset(); } } int intflg = 0; /* interrupt while non-interruptable */ intrdp(){ intflg++; (void) signal(SIGINT,intrdp); } jmp_buf env; main(argc,argv) int argc; char **argv; { int p; char *ac; initterm(); printf("dam %s version %s\n",VERSION,DATE); optf = open(".outdam",1); /* use it if it exists */ if(optf >= 0) (void) lseek(optf, 0L, 2); /* seek eof */ setstrat(0,1); if(argc == 1){ printf("do you want info? (y/n)\n"); if(answer()) prinfo(); } if(signal(SIGINT, SIG_IGN) != SIG_IGN) (void) signal(SIGINT, intrup); if(setjmp(env)) ; /* Program was reset */ if(mvnr > 1){ prbord(); rdcomd("t"); /* report time used */ if(optf > 0) outgame(); printf("another game?\n"); if(!answer()) exit(0); } sleep(2); init(); /* 2nd time here argc will be one */ while(--argc) { ac = *++argv; if(*ac == '-') ac++; switch(*ac){ case 'p': optp = atoi(++ac); break; case 'g': optg++; break; case ':': debug++; break; case '\0': /* do not use random generator */ userand = 0; printf("no random generator used\n"); break; default: rdcomd(ac); } } argc++; init2(); while(1){ mvnr++; if(optu&3) prsteval(); timebeg(); p = ((me == WHITE) ? playw : playb); if(p == USER) domove(readmove(me)); else domove(findmove(me)); if(me == WHITE) timew += timedif(); else timeb += timedif(); if(optp) if(mvnr%optp == 0) prbord(); me = COL-me; } } reset(){ longjmp(env,1); } init(){ register int i; /* check correctness of conv and reconv */ for(i=1; i<=50; i++) if(reconv[conv[i]] != i) error("conv error"); /* fill edge of the board */ for(i=0; i<66; i++) if(reconv[i] == 0) bord[i] = EDGE; /* initial board position */ for(i=1; i<=20; i++) bord[conv[i]] = BLACK; for(i=21; i<=30; i++) bord[conv[i]] = EMPTY; for(i=31; i<=50; i++) bord[conv[i]] = WHITE; me = WHITE; /* white to move */ rdbord[0] = 0; /* not from file */ timew = timeb = 0; lasthap = mvnr =1; endgame = fouragnst1 = 0; crownmv = altermv = 0; mpf = &moves[0]; gp = &game[0]; prall++; } init2(){ if(!playb && !playw){ printf("do you want me to play black? (y/n)\n"); playb = answer()+1; printf("do you want me to play white? (y/n)\n"); playw = answer()+1; dirt++; } else { if(!playb) playb = USER; if(!playw) playw = USER; } if(!mpf) mpf = moves; else if(optp)prbord(); } /* fatal error routine */ error(s) char *s; { printf("%s\n",s); exit(0); } /* create list of all possible moves */ move(c) int c; { register int i; int c0; possct = 0; captmax = captct = 0; mp = mp0 = mpf; for(i=6; i<60; i++) if(((c0 = bord[i]) & COL) == c) { bord[i] = EMPTY; mp += 3; *mp0 = i+c0; capt(c0,i); mp -= 3; bord[i] = c0; } if(!captmax) { if(c == BLACK) { for(i=6; i<60; i++) if(((c0 = bord[i]) & COL) == c) { if(c0 == BLACK) { hmove(c0,i,5); hmove(c0,i,6); } else { dmove(c0,i,-6); dmove(c0,i,-5); dmove(c0,i,5); dmove(c0,i,6); } }} else for(i=59; i>5; i--) if(((c0 = bord[i]) & COL) == c) { if(c0 == WHITE) { hmove(c0,i,-5); hmove(c0,i,-6); } else { dmove(c0,i,-6); dmove(c0,i,-5); dmove(c0,i,5); dmove(c0,i,6); } } } if(mp > &moves[MSIZE]) error("overflow moves array"); } /* king move in specified direction */ dmove(c,pos,dir) int c,pos,dir; { register int i; for(i = pos+dir; bord[i] == EMPTY; i += dir){ *mp++ = pos+c; *mp++ = i+c; *mp++ = 0; possct++; } } /* piece move */ hmove(c,pos,dir) int c,pos,dir; { register int i; if(bord[i = pos+dir] == EMPTY){ *mp++ = pos + c; *mp++ = prom(c,i); *mp++ = 0; possct++; } } /* partial capture in specified direction */ hcapt(c,pos,dir) int c,pos,dir; { register int i,j; int c1; if(c&DAM){ for(i=pos+dir; (c1=bord[i]) == EMPTY; i += dir); if((c1 & MASK) != DAM+COL-c) return; j = i; bord[i] |= CAPT; captct++; *mp++ = i+c1; while(bord[j += dir] == EMPTY) capt(c,j); bord[i] = c1; captct--; mp--; } else { c1 = bord[i = pos+dir]; if((c1 & MASK) != COL-c) return; if(bord[j=i+dir] != EMPTY) return; bord[i] |= CAPT; captct++; *mp++ = i+c1; capt(c,j); bord[i] = c1; captct--; mp--; } } capt(c,pos) int c,pos; { register int *mp1; hcapt(c,pos,-6); hcapt(c,pos,-5); hcapt(c,pos,5); hcapt(c,pos,6); if(captct == captmax){ if(!captct) return; possct++; *++mp0 = prom(c,pos); *++mp0 = captct; mp0 -= 2; mp1 = mp; do { *mp++ = *mp0++; } while (mp0 != mp1); return; } else if(captct > captmax){ captmax = captct; possct = 1; mp1 = mpf; *mp1++ = *mp0; *mp1++ = prom(c,pos); *mp1++ = captct; mp0 += 3; do { *mp1++ = *mp0++; } while(mp0 != mp); mp0 = mpf; mp = mp1; do { *mp1++ = *mp0++; } while(mp0 != mp); mp = mp1; return; } } prom(c,pos) int c,pos; { if(c&WHITE) { if(pos < 11) c |= DAM; } else if(pos > 54) c |= DAM; return(pos+c); } /* execute actual move */ domove(mvpt) int *mvpt; { register int i; register int *mp1; int ct,ctd,cte; int difflist[66]; /* store move in array game */ mp1 = mvpt; *gp++ = *mp1++; *gp++ = *mp1++; *gp++ = ct = *mp1++; while(ct--) *gp++ = *mp1++; if(gp+4 > &game[GSIZE]) error("overflow game array"); /* change board position */ mp1 = mvpt; bord[((*mp1++) & 0377)] = EMPTY; i = *mp1 & VAL; bord[((*mp1++) & 0377)] = i; ct = *mp1++; if(ct || !(*mvpt & DAM)) lasthap = mvnr; while(ct--) bord[((*mp1++) & 0377)] = EMPTY; /* check for repetition of moves */ ct = cte = 0; ctd = mvnr-lasthap; if(ctd > 3){ for(i=0; i<66; i++) difflist[i]=0; mp1 = gp; while(ctd--){ /* go back one move */ if(*--mp1) error("capture after lasthap"); i = *--mp1; if(i & (difflist[i & 0377] ^= (i&COL))) ct++; else ct--; i = *--mp1; if(i & (difflist[i & 0377] ^= (i&COL))) ct++; else ct--; if(difflist[0] ^= 1) ct++; else ct--; if(!ct) cte++; } if(cte == 2){ pmesg("\nDraw by repetition of moves\n"); reset(); } else if(cte == 1) { pmesg("\nThis is the 2nd occurrence\ of this position\n"); pb = 1; } } /* check for three kings against one */ pdistr(); if((!wpct) && (!bpct) && (wkct+bkct == 4) && ((wkct&bkct) == 1)){ drawdel = 10; ct = (wkct==1 ? WHITE : BLACK); /* single king on main diagonal? */ for(i=10; i<60; i += 5) if(bord[i] & ct){ drawdel = 3; break; } } if(mvnr-lasthap > drawdel*2){ pmesg("\nDraw since nothing happened for %d moves\n", drawdel); reset(); } if(wkct+bkct && wpct+bpct<12) { if(!endgame) setstrat(2,2); /* %% */ endgame++; } if(endgame && ((wkct > 3) && (bkct < 2) || (bkct > 3) && (wkct < 2))) fouragnst1++; } /* he asks for remise, shall we accept it? */ /* very stupid algorithm %% */ remise(){ if(mvnr-lasthap > drawdel*2){ pmesg("I accept\n"); reset(); } else { pmesg("I reject\n"); } } pdistr(){ /* find distribution of white and black pieces */ register int i; wpct = wkct = bpct = bkct = 0; for(i=6; i<60; i++) switch(bord[i] & VAL){ case WHITE: wpct++; break; case BLACK: bpct++; break; case WHITE|DAM: wkct++; break; case BLACK|DAM: bkct++; break; default: break; } } crown(c) int c; { register int i,v; int pct,kct,kseen,save_i[2],sk; pct = kct = kseen = 0; for(i=1; i<=50; i++){ v = bord[conv[i]] & VAL; if(v == EMPTY) continue; if(v & c){ if(kseen++ || (!(v & DAM))) goto err; else sk = i; } else { if(v & DAM) kct++; else if(pct == 2) goto err; else save_i[pct++] = i; } } if((kct + pct == 3) && pct){ drawdel = ((sk/5)*5 == sk ? 3 : 10); lasthap = crownmv = mvnr; pmesg("%d pieces crowned to king\n",pct); pmesg("it will be a draw in %d moves\n",drawdel); while(pct--){ bord[conv[save_i[pct]]] |= DAM; } } else { err: pmesg("crowning my pieces to a king is allowed only\n"); pmesg("if I have 3 pieces among which 1 or 2 kings\n"); } } int rdepth; int res0,res1,res2; /* allowed difference with optimal move */ #define Q 30 int* findmove(c) int c; { int r,res; struct mvv { int *mvp,val0,val1; } mvvals[MVMAX], *mvg; register struct mvv *mvvp; register int *mp1; rescct = 0; move(c); if(!possct){ pmesg("I lost\n"); reset(); } if(possct == 1){ prmove(mpf); return(mpf); } avalue = (me == WHITE ? stratw : stratb); rdepth = 0; res2 = -1; /* first look to a short depth */ rdif -= 40; rdmin--; res = -GIANT; mvvp = mvvals; for(mp1 = mpf; mp1<mp; ){ r = result(mp1,res-Q,GIANT); if(r < -GIANT) r = -GIANT; if(r > res) res = r; mvvp->mvp = mp1; mvvp++->val0 = r; if(mvvp >= mvvals+MVMAX-1){ pmesg("error in findmove: MVMAX too small\n"); break; } mp1 += 2; mp1 += (*mp1++); } /* end of list */ mvvp->mvp = 0; /* sort mvvals */ for(mvvp=mvvals; mp1=(mvvp+1)->mvp; mvvp++){ res1 = (mvvp+1)->val0; test: if(res1 > (res0 = mvvp->val0)){ /* switch */ (mvvp+1)->mvp = mvvp->mvp; (mvvp+1)->val0 = res0; mvvp -> mvp = mp1; mvvp -> val0 = res1; if(mvvp > mvvals){ mvvp--; goto test; } } } /* short term result */ res0 = res; /* now look to full depth */ mvvp = mvvals; rdif += 40; rdmin++; res = -GIANT-1; /* force assignment to mvg */ while(mp1 = mvvp->mvp){ r = result(mp1,res-Q,GIANT); if(r < -GIANT) r = -GIANT; if(r > res){ res = r; mvg = mvvp; /* gdct = 1; */ } /* else if(r == res)if(random(++gdct)==0) mvg=mvvp; %% */ mvvp++ -> val1 = r; } /* long term result */ res1 = res; /* final result good? */ if(res1 >= res0-Q) goto ret; /* or short term result not worse than for the others? */ if(mvg->val0 >= res0-30) goto ret; /* this seems a bad move at first sight; see whether it is really necessary */ rdif += (mp-mpf); res2 = result(mvg->mvp, res1-PVAL, res1+PVAL); rdif -= (mp-mpf); if(res2 >= res1-Q) goto ret; /* a bad move after all, take the one that seems best */ r = -GIANT-1; mvvp = mvvals; while(mvvp->val0 >= res0-Q){ if(mvvp->val1 > r){ r = mvvp->val1; mvg = mvvp; } mvvp++; } ret: if(optu&8){ disp = 0; /* print value of each move */ mvvp = mvvals; while(mp1 = mvvp->mvp){ prmove(mp1); printf(mvvp == mvg ? "####" : "****"); printf(" %d %d\n",mvvp->val0,mvvp->val1); mvvp++; } putchar('\n'); } prmove(mvg->mvp); if(optu&4) preval(mvg->val1); return(mvg->mvp); } preval(r) int r; { pmesg("value: %d\n",r); pmesg("res[i]: %d %d %d\n",res0,res1,res2); pmesg("#calls: %d\n",rescct); } /* deliver either evaluation or answer '<a' or '>b' */ result(mvpt,a,b) int *mvpt,a,b; { register int i; register int *mp1; int c,ct0,ct,r,res,*mpf0,fp; rescct++; mp1 = mvpt; c = *mp1 & COL; bord[((*mp1++) & 0377)] = EMPTY; i = *mp1 & VAL; bord[((*mp1++) & 0377)] = i; ct0 = ct = *mp1++; while(ct--) bord[((*mp1++) & 0377)] = EMPTY; if(!ct0) rdepth++; fp = (rdepth/2 == fplevel ? freepath(c) : 0); a += fp; b += fp; if(ct0 || (rdepth<rdmin)) goto go_on; if((mp-moves > rdif) || (rdepth >= rdmax)) goto eval; goto go_on; eval: res = (*avalue)(c); goto unmove; go_on: mpf0 = mpf; mpf = mp; move(COL-c); res = b+1; for(mp1=mpf; mp1<mp; ){ r = -result(mp1,-res,-a); if(r < res){ res = r; if(res < a) break; } mp1 += 2; mp1 += (*mp1++); } mp = mpf; mpf = mpf0; unmove: mp1 = mvpt; i = *mp1++; /* be careful; perhaps start and final position are the same! */ bord[((*mp1++) & 0377)] = EMPTY; bord[i & 0377] = i & VAL; ct = *mp1++; while(ct--){ i = *mp1 & VAL; bord[((*mp1++) & 0377)] = i; } if(!ct0) rdepth--; return(res-fp); } /* evaluation of position after recursion */ int info[66] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 0, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 0, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 0, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 0, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 0, 0, 0, 0, 0, 0 }; /* valuations for the columns: index is fldnr%11 */ /* weight center */ int valar1[11] = { 0, 2, 4, 3, 1, UNDEF, 1, 3, 4, 2, 0 }; /* weight distribution */ int valar2[11] = { -5, -3, -1, 2, 4, UNDEF, -4, -2, 1, 3, 5 }; value(c){ int sum,v,oc; register int d,*bp,*ip; oc = COL - c; sum = 0; ip = &info[6]; for(bp = &bord[6]; bp < &bord[60]; ){ d = *bp++ & VAL; v = *ip++; if(d == EMPTY) continue; if(d == EDGE) continue; if(d&DAM){ v = DVAL; /* increase value if on main diagonal */ if((bp-bord)%5 == 1) v += DMVAL; } else { if(d == WHITE) v = 11-v; v += PVAL; } if(d & oc) v = -v; sum += v; } return(sum); } /* evaluation of position after recursion */ /* value of tripods : the value of the field they point to */ int info2[66] = { 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 5, 7, 8, 6, 2, 2, 7, 9, 8, 6, 0, 7, 9, 10, 8, 2, 2, 9, 11, 10, 8, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0 }; int vcentrw,vcentrb,vequidw,vequidb,vtempw,vtempb; value2(c){ int sum,v,oc; register int d,*bp,i; oc = COL - c; sum = 0; vcentrw = vcentrb = vequidw = vequidb = vtempw = vtempb = 0; for(bp = bord; bp < &bord[6]; bp++){ sum += trip(5,BLACK,bp); sum += trip(6,BLACK,bp); } if(c == WHITE) sum = -sum; for(i=6; i<60; (i++,bp++)){ d = *bp & VAL; if(d == EMPTY) continue; if(d == EDGE) { v = trip(-5,WHITE,bp); v += trip(-6,WHITE,bp); v -= trip(5,BLACK,bp); v -= trip(6,BLACK,bp); sum += (c == WHITE ? v : -v); continue; } if(d&DAM){ v = DVAL; /* increase value if on main diagonal */ if((i/5)*5 == i) v += DMVAL; } else { v = PVAL; if(d == WHITE){ vtempw += info[65-i]; v += trip(-5,WHITE,bp); v += trip(-6,WHITE,bp); vequidw += valar2[i%11]; vcentrw += valar1[i%11]; } else { vtempb += info[i]; v += trip(5,BLACK,bp); v += trip(6,BLACK,bp); vequidb += valar2[i%11]; vcentrb += valar1[i%11]; } } if(d & oc) v = -v; sum += v; } for( ;bp < &bord[66]; bp++){ v = trip(-5,WHITE,bp); v += trip(-6,WHITE,bp); sum += (c == WHITE ? v : -v); } if(vequidw < 0) vequidw = -vequidw; if(vequidb < 0) vequidb = -vequidb; v = vcentrw-vcentrb-vequidw+vequidb+vtempw-vtempb; sum += (c == WHITE ? v : -v); return(sum); } evalue(c){ int sum,v,oc,i; register int d,*bp,*ip; oc = COL-c; sum = 0; ip = &info[6]; for(bp = &bord[6]; bp < &bord[60]; ){ d = *bp++ & VAL; v = *ip++; if(d == EMPTY) continue; if(d == EDGE) continue; /* if opponent has a king then traps are valuable */ if((d==WHITE && bkct) || (d==BLACK && wkct)) v += trap(-5,d&COL,bp) + trap(-6,d&COL,bp) + trap( 5,d&COL,bp) + trap( 6,d&COL,bp); if(d&DAM) { v = DVAL; if((bp-bord)%5 == 1) v += DMVAL; if(fouragnst1){ i = (bp-bord)%6; if(i <= 1) v += DMVAL; switch(bp-bord){ case 6+1: case 11+1: case 54+1: case 59+1: v += DMVAL/2; } } } else { if(d == WHITE) v = 11-v; v += PVAL; } if(d & oc) v = -v; sum += v; } return(sum); } prsteval(){ int rdmax0,rdmin0; register int *mp1; if(optu&1) printf("static eval: %d\n",value2(me)); if(optu&2){ rdmax0 = rdmax; rdmin0 = rdmin; rdmax = rdmin = 1; rdepth = 0; disp = 0; avalue = value2; move(me); for(mp1=mpf; mp1<mp; ){ printf("%4d ", result(mp1,-GIANT,GIANT)); printf("(%2d %2d %2d / %2d %2d %2d) ", vtempw-vtempb,vcentrw,vequidw, vtempb-vtempw,vcentrb,vequidb ); prmove(mp1); if((mvnr&1)==0) putchar('\n'); /* %% */ mp1 += 2; mp1 += (*mp1++); } printf("\n"); rdmax = rdmax0; rdmin = rdmin0; } } /* test for X XY where Y=X or Y=Edge */ trap(dir,col,nbp) int dir,col,*nbp; { register int *bp,w,v; bp = nbp+dir; if(*bp != EMPTY) return(0); bp += dir; if(((w = *bp)&COL) != col) return(0); bp += dir; if(!(*bp & col)) return(0); /* value is number of empty fields covered by trap */ v = 0; bp = nbp-dir; while(*bp == EMPTY){ v += TPVAL; bp -= dir; } /* extra bonus if base of trap is a king */ if(w & DAM) v += (v/2); return(v); } trip(dir,col,nbp) int dir,col,*nbp; { register int *bp; int tv1,tv2; tv2 = 0; bp = nbp+dir; if(*bp != col) return(0); bp += dir; if(*bp != col) return(0); tv1 = (col == WHITE ? info2[65-(bp+dir-bord)] : info2[bp+dir-bord]); if(bp[dir] == col) tv1 >>= 1; if(dir < 0) dir = -dir; dir = 11-dir; /* interchange 5 and 6 */ if(bp[dir] == col && ((bp[dir+dir] & col) == 0)) tv2++; else if(bp[-dir]== col && ((bp[-dir-dir]& col) == 0)) tv2++; return(tv2 ? 2 : tv1); } /* check for free path (for oc) to a king */ int freect,frlngt,flth; /* 'real' free path */ int freect2,frlngt2,fbcct; /* free paths discarding backward captures */ int fpval[11] = { 0, /* 0 cannot occur */ PVAL, /* 1 is already seen as a king in recursion %% */ PVAL, /* 2 */ PVAL-10, /* 3 */ PVAL-20, /* 4 */ PVAL/2, /* 5 */ 30,30, /* 6,7 */ 15,15, /* 8,9 */ 0 /* 10, i.e. no free paths */ }; int fpval2[11] = { 0, 0, /* 0,1 cannot occur */ PVAL/2, /* 2 */ PVAL/3, /* 3 */ 10,10, /* 4,5 */ 5,5, /* 6,7 */ 2,2, /* 8,9 */ 0 /* 10 */ }; freepath(c) int c; { register int *bp,*nbp,i; int nbord[66],oc; oc = COL-c; /* copy */ bp = bord; nbp = nbord; while(bp < &bord[66]) *nbp++ = *bp++; /* swell */ for(nbp = &nbord[6]; nbp < &nbord[60]; nbp++){ if((*nbp & COL) == c){ if(*nbp & DAM) { dmark(nbp, -6); dmark(nbp, -5); dmark(nbp, 5); dmark(nbp, 6); } else { if(c == WHITE){ nbp[-6] |= FLAGS; nbp[-5] |= FLAGS; nbp[5] |= FLAG; nbp[6] |= FLAG; } else { nbp[-6] |= FLAG; nbp[-5] |= FLAG; nbp[5] |= FLAGS; nbp[6] |= FLAGS; } } *nbp = EDGE; } } /* but note: points on the border are always safe */ nbp = nbord; for(i = 6; i<10; i++) nbp[i] &= VAL; for( ; i<65; i += 10){ nbp[i++] &= VAL; nbp[i] &= VAL; } for(i = 56; i<60; i++) nbp[i] &= VAL; /* determine strong component of last line */ freect = flth = freect2 = fbcct = 0; frlngt = frlngt2 = 10; /* shortest freepath: +inf */ if(c == WHITE){ for(nbp = &nbord[55]; nbp < &nbord[60]; nbp++) reach(oc,nbp,-6); } else for(nbp = &nbord[6]; nbp < &nbord[11]; nbp++) reach(oc,nbp,5); if(debug){ /* %% */ pmesg("fct: %d, fct2: %d, fl: %d, fl2: %d,\ flth: %d=0, fbcct: %d=0\n", freect,freect2,frlngt,frlngt2,flth,fbcct); } if(freect) return(fpval[frlngt]); return(fpval2[frlngt2]); } dmark(nbp,d) int *nbp,d; { register int *bp; bp = nbp + d; while((*bp & COL) == EMPTY){ *bp = FLAGS; bp += d; } } reach(oc,nbp,d) int oc,*nbp,d; { register int *bp,v; bp = nbp; v = *bp & VAL; if(v == EDGE) return; if(v == oc) { if(fbcct == 0){ freect++; if(frlngt > flth) frlngt=flth; } else { freect2++; if(frlngt2 > flth) frlngt2=flth; } } if(v != EMPTY) return; /* %% */ if((*bp & FLAG) == 0){ flth++; reach(oc,bp+d,d); reach(oc,bp+d+1,d); flth--; if(fbcct == 0) *bp = EDGE; else *bp |= FLAG2; /* dont look for semifree paths */ } else if((*bp & FLAG2) == 0){ fbcct++; flth++; reach(oc,bp+d,d); reach(oc,bp+d+1,d); flth--; fbcct--; *bp = EDGE; /* dont return to this field */ } else *bp = EDGE; } /* construct position after move k */ backup(k) int k; { register int i,*gp0; int mvno,c,ct; /* the validity of k was checked by the caller */ if(rdbord[0]) for(i=6; i<60; i++){ if(bord[i] != EDGE) bord[i] = rdbord[i]; } else { for(i=1; i<=20; i++) bord[conv[i]] = BLACK; for(i=21;i<=30; i++) bord[conv[i]] = EMPTY; for(i=31;i<=50; i++) bord[conv[i]] = WHITE; } gp0 = game; mvno = mvnr; mvnr = 1; while(k--){ mvnr++; c = *gp0 & COL; if(mvnr == crownmv) crown(c); /* yields output %% */ bord[(*gp0++) & 0377] = EMPTY; i = *gp0 & VAL; bord[(*gp0++) & 0377] = i; ct = *gp0++; while(ct--) bord[(*gp0++) & 0377] = EMPTY; } mvnr++; if((mvno+mvnr) & 1) me = COL-me; mpf = 0; /* the position has changed */ gp = gp0; if(lasthap > mvnr) lasthap = mvnr; if(crownmv > mvnr) crownmv = 0; } /* * Implemented rules: * * a) If the same position occurs thrice (with the same * player to move) it is a draw. * b) If a player has 3 pieces among which at least one * king and his opponent has one king only, his opponent * may crown all these pieces (which action does not * count for a move). Immediately rule c) becomes applicable. * c) If the position is 3 kings against 1 king then after * (single king on main diagonal ? 3 : 10) * moves the game ends in a draw. * * In addition to these we use for PDP against PDP play the rule: * * z) If during DRAWWT moves no piece has been captured and only * kings have moved it is a draw. * */