|
|
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 z
Length: 11324 (0x2c3c)
Types: TextFile
Names: »zogo.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/General/Zogo/zogo.c«
#define VERSION "1.1"
#define FORCED 2000L
#define WIN 30000L
#define SNUM 3
/* zogo: 4*4*4 4-in-a-row+gravitation */
long int z[10] = { 0L, FORCED, 100L, 10L, 1L, 0L, 9L, 90L, WIN, 0L };
int board[64];
int move[64],mvct;
char sym[] = ".oxOX@*" ;
int optd,first,noout,user;
extern int readmove(), cmove(), cmove1(), findmove();
int (*(strat[]))() = { &readmove, &cmove, &cmove1, &findmove };
int (*strat1)(), (*strat2)();
/* deliver a random value between 0 and k-1 */
int userand = 1;
random(k){
register int r;
if(!userand) return(0);
r = rand();
if(r<0) r = -r;
r -= (r/k)*k;
return(r);
}
domove(a,b,c,p) int a,b,c,p; {
register int i;
i = 16*a + 4*b + c;
move[mvct] = i;
mvct++;
board[i] = p+2;
prbd();
board[i] = p;
return(four(a,b,c));
}
prbd(){
register int i,j,k;
if(noout) return;
printf("\n\n");
for(i=3; i>=0; i--) prlin(i);
printf("\n");
printf(" aaaa bbbb cccc dddd\n");
printf(" 1234 1234 1234 1234\n");
printf("\n\n");
}
prlin(a) int a; {
register int i,j,k;
for(i=0; i<4; i++){
printf(" ");
for(j=0; j<4; j++) putchar(sym[board[16*i + 4*j + a]]);
}
putchar('\n');
}
readmove(a) int a; {
register int i,j,k;
int c;
err1:
printf("Your move: ");
if(letter(c = getchar())) i = c - 'a'; else goto err;
if(digit(c = getchar())) j = c - '1'; else goto err;
if(getchar() != '\n') goto err;
for(k=0; k<4; k++) if(board[16*i + 4*j + k] == 0) break;
if(k == 4){
printf("you cannot move there\n");
goto err1;
}
if(domove(i,j,k,a)){
noout = 0;
printf("It seems you win\n");
prbd();
exit();
}
return;
err:
if(c == '$' && (c = getchar()) == '%' && (c = getchar()) == '!'
&& (c = getchar()) == '\n')
execl("/bin/sh", "zogo", 0);
while(c != '\n'){
if(c == -1) error("End of input");
c = getchar();
}
printf("strange symbol??\n");
goto err1;
}
letter(c) char c; {
return('a' <= c && c <= 'd');
}
digit(c) char c; {
return('1' <= c && c <= '4');
}
lstat(a,b,c,da,db,dc,p) int a,b,c,da,db,dc,p; {
register int i,j,k;
int ct,tot[3];
tot[0] = tot[1] = tot[2] = 0;
i = a;
j = b;
k = c;
for(ct = 0; ct < 4; ct++){
tot[board[16*i + 4*j + k]]++;
i += da;
j += db;
k += dc;
}
if(tot[p] == 4){ /* someone won - set ! marks */
i = a; j = b; k = c;
for(ct = 0; ct < 4; ct++){
board[16*i + 4*j + k] += 4;
i += da;
j += db;
k += dc;
}
}
if(tot[1] && tot[2]) return(0);
if(tot[p]) return(tot[p]);
return(-tot[3-p]-1);
}
four(a,b,c) int a,b,c; {
register int i,j,k;
int p;
p = board[16*a + 4*b + c];
if(!p) error("four for empty field??");
if(lstat(a,b,0,0,0,1,p) == 4) return(1);
if(lstat(a,0,c,0,1,0,p) == 4) return(1);
if(lstat(0,b,c,1,0,0,p) == 4) return(1);
if(a == b && lstat(0,0,c,1,1,0,p) == 4) return(1);
if(a == c && lstat(0,b,0,1,0,1,p) == 4) return(1);
if(b == c && lstat(a,0,0,0,1,1,p) == 4) return(1);
if(a+b == 3 && lstat(0,3,c,1,-1,0,p) == 4) return(1);
if(a+c == 3 && lstat(3,b,0,-1,0,1,p) == 4) return(1);
if(b+c == 3 && lstat(a,0,3,0,1,-1,p) == 4) return(1);
if(a == c && b == c && lstat(0,0,0,1,1,1,p) == 4) return(1);
if(a+c==3 && b == c && lstat(3,0,0,-1,1,1,p) == 4) return(1);
if(a+b==3 && a == c && lstat(0,3,0,1,-1,1,p) == 4) return(1);
if(a+c==3 && a == b && lstat(3,3,0,-1,-1,1,p) == 4) return(1);
return(0);
}
long int cval(a,b,c,p) int a,b,c,p; {
register int i,j,k;
long int val;
val = 0;
val += z[5 + lstat(0,b,c,1,0,0,p)];
val += z[5 + lstat(a,0,c,0,1,0,p)];
val += z[5 + lstat(a,b,0,0,0,1,p)];
if(a == b) val += z[5 + lstat(0,0,c,1,1,0,p)];
if(a == c) val += z[5 + lstat(0,b,0,1,0,1,p)];
if(b == c) val += z[5 + lstat(a,0,0,0,1,1,p)];
if(a+b == 3) val += z[5 + lstat(0,3,c,1,-1,0,p)];
if(a+c == 3) val += z[5 + lstat(3,b,0,-1,0,1,p)];
if(b+c == 3) val += z[5 + lstat(a,0,3,0,1,-1,p)];
if(a==c && b==c) val += z[5 + lstat(0,0,0,1,1,1,p)];
if(a+c==3 && b==c) val += z[5 + lstat(3,0,0,-1,1,1,p)];
if(a+b==3 && a==c) val += z[5 + lstat(0,3,0,1,-1,1,p)];
if(a+c==3 && a==b) val += z[5 + lstat(3,3,0,-1,-1,1,p)];
return(val);
}
cmove(a) int a; {
register int i,j,k;
int mi,mj,mk,mct;
long int max,v,w;
max = -2L;
for(i=0; i<4; i++) for(j=0; j<4; j++){
for(k=0; k<4; k++) if(!board[16*i + 4*j + k]) break;
if(k == 4) continue;
v = cval(i,j,k,a);
if(k < 3 && v < FORCED){ /* allowed ? */
w = cval(i,j,k+1,3-a);
if(w >= WIN) v = -1L;
else if(w >= FORCED && k < 2){
w = cval(i,j,k+2,a);
if(w >= WIN) v = FORCED - 1L;
}
}
if(v > max || (v == max && random(++mct) == 0)){
if(v > max) mct = 1;
max = v;
mi = i;
mj = j;
mk = k;
}
}
if(max == -2L) error("I cannot find a move");
if(domove(mi,mj,mk,a)){
sarcastic();
}
if(optd) printf("value of move: %D\n", max);
}
sarcastic(){
noout = 0;
printf("As was to be expected, I win\n");
printf("You survived ");
if(mvct < 32) printf("only ");
printf("%d moves", mvct);
if(mvct == 64) printf(" - but I got you in the end!");
else if(mvct > 48) printf(" - not too bad\n");
else if(mvct < 24) printf(" - you'd better try tictactoe\n");
else putchar('\n');
prbd();
exit();
}
cmove1(a) int a; {
z[4] = 5L;
cmove(a);
z[4] = 1L;
}
main(argc,argv) int argc; char **argv; {
register int sn,snum;
sn = 0;
init();
while(argc > 1){
argc--;
argv++;
if(**argv != '-'){ /* strategy numbers */
if(++sn > 2) error("we have only 2 players");
snum = atoi(*argv);
if(snum < 0 || snum > SNUM)
error("we dont have that strategy");
if(sn == 1) strat1 = strat[snum];
else strat2 = strat[snum];
continue;
}
options:
argv[0]++;
switch(argv[0][0]){
case 'a': /* agressive */
z[6] = 12L;
z[7] = 120L;
goto options;
case 'd': /* debug */
optd++;
goto options;
case '1':
case '2':
if(first) error("selfcontradictory options");
first = **argv - '0';
goto options;
case 'n':
noout++;
goto options;
case '\0':
continue;
default:
error("allowed options: -12adn");
}
}
if(sn == 0){
sn++;
strat1 = strat[0];
}
if(strat1 == strat[0]) user |= 1;
if(sn == 1){
if(!user) strat2 = strat[0];
else strat2 = strat[SNUM];
}
if(strat2 == strat[0]) user |= 2;
if(!noout)printf("\t\t Zogo %s\n", VERSION);
if(!noout)printf("** four-in-a-row on a 4*4*4 cube with gravity **\n");
if(!first && (user==0 || user==3)) first = 1; else
if(!first){
if(random(3) != 0){
first = user;
printf("You start -- good luck!\n");
} else {
first = 3-user;
printf("I'll start this time\n");
}
}
if(first & user){
prbd();
}
while(mvct < 64){
if((mvct+first)&1) (*strat1)(1); else (*strat2)(2);
}
printf("A draw -- well played !!\n\n");
if(noout){
noout = 0;
prbd();
}
}
struct px { struct lx *(ll[8]); int cont,win,ghost; } pts[64];
struct lx { struct px *(pp[4]); int dist,fill[5]; } lines[76];
#define blocked fill[0]
init(){
register int i,j,k;
int tvec[2];
time(tvec);
srand(tvec[1]);
for(i=0; i<64; i++) pts[i].cont = pts[i].win = pts[i].ghost = 0;
for(i=0; i<76; i++){
lines[i].dist = 0;
for(j=0; j<5; j++) lines[i].fill[j] = 0;
}
for(i=0; i<4; i++) for(j=0; j<4; j++) for(k=0; k<4; k++){
/* verticals first */
incid(i,j,k,0 + 4*i+j,k);
incid(i,j,k,16 + 4*i+k,j);
incid(i,j,k,32 + 4*j+k,i);
}
for(i=0; i<4; i++) for(j=0; j<4; j++){
incid(i,j,j,48 + i,j);
incid(j,i,j,52 + i,j);
incid(j,j,i,56 + i,j);
incid(i,j,3-j,60 + i,j);
incid(3-j,i,j,64 + i,j);
incid(j,3-j,i,68 + i,j);
}
for(i=0; i<4; i++){
incid(i,i,i,72,i);
incid(i,i,3-i,73,i);
incid(i,3-i,i,74,i);
incid(3-i,i,i,75,i);
}
/* close ll lists with 0 */
for(i=0; i<64; i++){
if(pts[i].cont >= 8) error("8 directions through a point?");
pts[i].ll[ pts[i].cont ] = 0;
pts[i].cont = 0;
}
/* correct distances for vertical lines */
for(i=0; i<16; i++) lines[i].dist = 4;
}
incid(i,j,k,l,x) int i,j,k,l,x; {
register int a;
register struct px *ppt;
register struct lx *lpt;
a = 16*i + 4*j + k;
ppt = &pts[a];
lpt = &lines[l];
lpt->pp[x] = ppt;
lpt->dist += (k+1);
ppt->ll[ ppt->cont++ ] = lpt;
}
xeqmove(pos,a) int pos,a; {
register struct px *ppt;
register struct lx *lpt;
register int d;
int l,e,g;
ppt = &pts[pos];
ppt->cont = a;
g = ppt->ghost;
ppt->ghost = 0;
for(d = 3 - (pos%4); d >= 1; d--){
l = 1; /* skip vertical */
while(lpt = (ppt+d)->ll[l++]) lpt->dist--;
}
l = 0;
while(lpt = ppt->ll[l++]){
lpt->dist--;
if(g & 1) lpt->fill[3]--;
if(g & 2) lpt->fill[4]--;
e = ++(lpt->fill[a]);
if(lpt->fill[3-a]) lpt->blocked = 3;
if(e == 4) return(1); /* someone won */
if(e == 3 && !lpt->fill[3-a]){
for(d=0; d<4; d++) if((lpt->pp[d])->cont == 0) break;
if(d == 4) error("where is the empty field?");
setwin(lpt->pp[d], a);
}
}
return(0);
}
setwin(ppt,a) struct px *ppt; int a; {
register int k,l;
register struct lx *lpt;
if((ppt->win |= a) == 3){
/* block all lines through higher points */
for(k = (ppt-pts)%4 + 1; k < 4; k++){
l = 1;
while(lpt = (ppt+k)->ll[l++]) lpt->blocked = 3;
}
}
l = 0;
while(lpt = ppt->ll[l++]) lpt->blocked |= a;
k = (ppt-pts)%4;
if(k > 0 && !(ppt-1)->cont) setghost(ppt-1, a);
if(k < 3) setghost(ppt+1, a);
if(optd) printf("setwin(%d,%d)\n", ppt-pts, a);
}
setghost(ppt,a) struct px *ppt; int a; {
register int k,l;
register struct lx *lpt;
if(ppt->ghost & a) return;
ppt->ghost |= a;
l = 0;
while(lpt = ppt->ll[l++]) lpt->fill[a+2]++;
if(optd) printf("setghost(%d,%d)\n", ppt-pts, a);
}
#define WIN2 30000
#define FORC2 25000
int zz[11] = { 10, 12, 15, 20, 30, 100, 200, 400, 800, 1600, 3200 };
vmove(pos,a) int pos,a; {
register int l;
register struct px *ppt;
register struct lx *lpt;
int v,v1;
ppt = &pts[pos];
if(ppt->cont) error("vmove considering nonempty field??");
if(ppt->win & a) return(WIN2);
if(ppt->win & (3-a)) return(FORC2);
if(pos%4 != 3 && ((ppt+1)->win & (3-a))) return(-1); /* losing move */
if(pos%4 < 2 && ((ppt+1)->win & a) && ((ppt+2)->win & a))
return(FORC2 - 1); /* win within 2 moves */
v = vmsum(ppt, a);
if(pos%4 != 3){
v1 = vmsum(ppt+1, 3-a);
if(v1 > 2*v) v = 0;
}
return(v);
}
vmsum(ppt, a) struct px *ppt; int a; {
register int v1,l;
register struct lx *lpt;
int v;
v = 0;
l = 0;
while(lpt = ppt->ll[l++]){
v1 = 0;
if(lpt->fill[a]){
if(!(lpt->blocked & a))
v1 = 3*lpt->fill[a] + 2*lpt->fill[a+2];
} else if(lpt->fill[3-a]){
if(!(lpt->blocked & (3-a)))
v1 = 3*lpt->fill[3-a] + 2*lpt->fill[5-a];
} else {
v1 = (lpt->fill[3] + lpt->fill[4]);
}
if(v1<0 || v1>10) error("strange v1");
v1 = zz[v1];
v1 -= (v1 * lpt->dist)/32;
v += v1;
}
return(v);
}
findmove(a) int a; {
register int i,j,k;
int v,vmax,vct,imax;
if(strat1 != strat2 && mvct && xeqmove(move[mvct-1], 3-a))
error("my opponent seems to have won?");
vmax = -2;
for(i=0; i<16; i++){
k = lines[i].dist;
if(k==0) continue;
v = vmove(4*i + (4-k), a);
if(optd) printf("%d: %d / ", i, v);
if(v > vmax || (v == vmax && rand(++vct) == 0)){
if(v > vmax) vct = 1;
vmax = v;
imax = 4*i + (4-k);
}
}
if(optd) printf("max = %d\n", vmax);
if(vmax == -2) error("findmove fails");
i = imax/16; j = (imax%16)/4; k = imax%4;
if(domove(i,j,k,a)){
if(user) sarcastic();
printf("The new strategy won after %d moves\n", mvct);
noout = 0;
prbd();
exit();
}
if(xeqmove(imax,a)) error("impossible");
}
error(s) char *s; {
printf("Fatal error: %s\n", s);
exit(1);
}