2021-02-16 11:56:34 +11:00
// TODO: trap ctrl-c
2021-02-17 23:30:12 +11:00
// TODO: trap ctrl-d
// TODO: taktak
2021-02-16 11:56:34 +11:00
# include <ctype.h>
# include <math.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <time.h>
# include "tak.h"
# define MAXSTACK 10
# define MAXW 8
# define MAXH 8
# define MAX_CMD_LEN 100
# define MAXPLAYERS 2
# define FORMAT_ROWHEAD "%c "
# define FORMAT_ROWTAIL "| %c"
# define FORMAT_COLHEAD "| %c "
# define FORMAT_COLTAIL "| %c "
//#define FORMAT_OWNER "| %c%c |"
//#define FORMAT_STACK "|[%-10s]|"
# define FORMAT_OWNER "| %s%c%c%s "
# define FORMAT_STACK "| %-10s "
2021-02-17 21:50:31 +11:00
# define FORMAT_AIVAL "| %s%5d%s / %2d "
2021-02-16 11:56:34 +11:00
# define LINEPART "--------------"
# define TRUE (-1)
# define FALSE (0)
# define ALL (-1)
2021-02-17 23:30:12 +11:00
# define ANY (-1)
2021-02-21 17:19:03 +11:00
# define NOBOLD (0)
2021-02-16 11:56:34 +11:00
# define BLACK "\e[0;30m"
# define BLUE "\e[0;36m"
# define RED "\e[0;31m"
# define YELLOW "\e[0;33m"
# define BOLD "\e[1m"
//#define BLUE "\e[0;34m"
# define GREEN "\e[0;32m"
# define reset "\e[0m"
char board [ MAXW * MAXH ] [ MAXBOARDSTRLEN ] ;
2021-02-21 17:19:03 +11:00
int lastmove [ MAXW * MAXH ] ; // how many tiles were moved here last turn
2021-02-16 11:56:34 +11:00
int aivalue [ MAXW * MAXH ] ;
2021-02-17 21:50:31 +11:00
int aidef [ MAXW * MAXH ] ;
# define BLOCKED -999
2021-02-16 11:56:34 +11:00
char cmdbuf [ MAX_CMD_LEN ] ;
2021-02-17 21:50:31 +11:00
char aireason [ MAXW * MAXH ] [ 2048 ] ;
2021-02-16 11:56:34 +11:00
int tilesleft [ MAXPLAYERS ] ;
int capsleft [ MAXPLAYERS ] ;
int hasroad [ MAXPLAYERS ] ;
int gamepoints [ MAXPLAYERS ] ;
int roundpoints [ MAXPLAYERS ] ;
int ai [ MAXPLAYERS ] ;
// for game log
char topofmove = ' ' ;
int flattened = FALSE ;
2021-02-17 21:50:31 +11:00
int tak [ MAXPLAYERS ] ;
2021-02-16 11:56:34 +11:00
char movelog [ 256 ] ;
int debug = FALSE ;
2021-02-17 21:50:31 +11:00
int xmod [ ] = { 0 , 1 , 0 , - 1 } ; /// nesw
int ymod [ ] = { 1 , 0 , - 1 , 0 } ; /// nesw
2021-02-16 11:56:34 +11:00
enum direction { NORTH = 0 , EAST = 1 , SOUTH = 2 , WEST = 3 } ;
int size = 5 ;
int w = 5 ;
int h = 5 ;
int curround , numrounds ;
int turnnumber = 0 ;
int firstturn = 0 ; // who goes first
int gameover = 0 ;
int turn = 0 ;
int winner = - 1 ;
void init ( void ) {
int x , y ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
strcpy ( board [ y * w + x ] , " " ) ;
}
}
}
2021-02-21 17:19:03 +11:00
void setlastmove ( int x , int y , int ntiles ) {
lastmove [ y * w + x ] = ntiles ;
}
2021-02-16 11:56:34 +11:00
int setupround ( void ) {
int i ;
int x , y ;
int starttiles , startcaps ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
strcpy ( board [ y * w + x ] , " " ) ;
2021-02-21 17:19:03 +11:00
setlastmove ( x , y , 0 ) ;
2021-02-16 11:56:34 +11:00
}
}
gameover = 0 ;
turn = firstturn ;
turnnumber = 1 ;
starttiles = getstarttiles ( size ) ;
startcaps = getstartcapstones ( size ) ;
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
tilesleft [ i ] = starttiles ;
capsleft [ i ] = startcaps ;
hasroad [ i ] = FALSE ;
roundpoints [ i ] = 0 ;
2021-02-17 21:50:31 +11:00
tak [ i ] = FALSE ;
2021-02-16 11:56:34 +11:00
}
ai [ 0 ] = FALSE ;
2021-02-17 21:50:31 +11:00
//ai[1] = FALSE;
ai [ 1 ] = TRUE ;
2021-02-16 11:56:34 +11:00
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
roundpoints [ i ] = 0 ;
}
winner = - 1 ;
printf ( " %s======================= \n " , BOLD ) ;
printf ( " ===== ROUND %2d/%2d ===== \n " , curround , numrounds ) ;
printf ( " =======================%s \n \n " , reset ) ;
printf ( " %s%s%s%s%s is playing first this round.%s \n \n " , getpcol ( turn ) , BOLD , getpname ( turn ) , reset , BOLD , reset ) ;
return FALSE ;
}
int setupgame ( int sz , int nrounds ) {
int i ;
if ( ( sz < 3 ) | | ( sz > 8 ) | | ( sz = = 7 ) ) {
printf ( " error - board size must be between 3 and 8 (but not 7). \n " ) ;
return TRUE ;
}
w = h = size = sz ;
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
roundpoints [ i ] = 0 ;
gamepoints [ i ] = 0 ;
}
curround = 1 ;
numrounds = nrounds ;
winner = - 1 ;
return FALSE ;
}
void cleanup ( void ) {
int x , y ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
strcpy ( board [ y * w + x ] , " " ) ;
}
}
// fix colours
printf ( " %s " , reset ) ; fflush ( stdout ) ;
}
char getmodxy ( int x , int y ) {
return getmod ( board [ y * w + x ] ) ;
}
char getmod ( char * stack ) {
char ch = 0 ;
if ( ! stack ) return ' ' ;
ch = stack [ strlen ( stack ) - 1 ] ;
if ( ismod ( ch ) ) {
return modprintable ( ch ) ;
}
return ' ' ;
}
2021-02-21 17:19:03 +11:00
// boolean
int hasmod ( char * stack ) {
if ( getmod ( stack ) = = ' ' ) {
return FALSE ;
}
return TRUE ;
}
2021-02-16 11:56:34 +11:00
char modprintable ( char mod ) {
switch ( mod ) {
case ' C ' :
case ' k ' :
mod = ' ^ ' ;
break ;
case ' S ' :
case ' s ' :
mod = ' | ' ;
break ;
}
return mod ;
}
char counttiles ( char * stack ) {
int pos , count = 0 ;
if ( ! stack ) return 0 ;
for ( pos = 0 ; stack [ pos ] ; pos + + ) {
if ( ! ismod ( stack [ pos ] ) ) count + + ;
}
return count ;
}
2021-02-17 21:50:31 +11:00
int getownernumxy ( int x , int y ) {
return getpnum ( getownerxy ( x , y ) ) ;
}
char getownerxy ( int x , int y ) {
char * s ;
s = board [ y * w + x ] ;
return getowner ( s ) ;
}
2021-02-16 11:56:34 +11:00
char getowner ( char * stack ) {
int pos ;
if ( ! stack ) return ' ' ;
for ( pos = strlen ( stack ) - 1 ; pos > = 0 ; pos - - ) {
if ( ! ismod ( stack [ pos ] ) ) break ;
}
if ( pos < 0 ) return ' ' ;
return stack [ pos ] ;
}
int isdir ( char ch ) {
switch ( ch ) {
case ' > ' :
case ' < ' :
case ' + ' :
case ' - ' :
return TRUE ;
}
return FALSE ;
}
int ismod ( char ch ) {
switch ( ch ) {
case ' C ' :
case ' k ' :
case ' ^ ' :
case ' S ' :
case ' s ' :
case ' | ' :
return TRUE ;
}
return FALSE ;
}
char * getdirname ( int dir ) {
switch ( dir ) {
case ' > ' :
return " right " ;
case ' < ' :
return " left " ;
case ' + ' :
return " up " ;
case ' - ' :
return " down " ;
}
return " UNKNOWN_DIR " ;
}
char * getmodname ( int mod ) {
switch ( mod ) {
case ' C ' :
case ' k ' :
case ' ^ ' :
return " capstone " ;
case ' S ' :
case ' | ' :
return " standing stone " ;
}
return " flatstone " ;
}
char * readcmd ( char * cmd ) {
char turntext [ 64 ] ;
2021-02-21 17:19:03 +11:00
int x , y ;
// clear out last move
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
setlastmove ( x , y , 0 ) ;
}
}
2021-02-16 11:56:34 +11:00
if ( turnnumber = = 1 ) {
sprintf ( turntext , " SETUP: %s%s%s placing %s%s's%s initial tile " , getpcol ( turn ) , getpname ( turn ) , reset , getpcol ( 1 - turn ) , getpname ( 1 - turn ) , reset ) ;
printf ( " R%d/%d-T%d. %s %s==> " , curround , numrounds , turnnumber , turntext , getpcol ( turn ) ) ;
} else {
sprintf ( turntext , " %s%s's%s turn " , getpcol ( turn ) , getpname ( turn ) , reset ) ;
printf ( " R%d/%d-T%d. %s (%s%sstones:%s%s%d %scapstones%s%s:%d%s) %s==> " , curround , numrounds , turnnumber ,
turntext , getpcol ( turn ) , BOLD , reset , getpcol ( turn ) , tilesleft [ turn ] , BOLD , reset , getpcol ( turn ) , capsleft [ turn ] , reset ,
getpcol ( turn ) ) ;
}
printf ( " %s " , BOLD ) ;
if ( ai [ turn ] ) {
2021-02-17 21:50:31 +11:00
genaicmd ( cmd , TRUE , ( turnnumber = = 1 ) ? TRUE : FALSE ) ;
2021-02-16 11:56:34 +11:00
printf ( " %s \n " , cmd ) ;
} else {
fgets ( cmd , MAX_CMD_LEN , stdin ) ;
if ( cmd ) {
cmd [ strlen ( cmd ) - 1 ] = 0 ;
2021-02-21 17:19:03 +11:00
} else {
clearerr ( stdin ) ;
2021-02-16 11:56:34 +11:00
}
}
printf ( " %s " , reset ) ;
return cmd ;
}
2021-02-17 21:50:31 +11:00
int rowhasmod ( int sx , int sy , char mod , int who ) {
int count = 0 ;
int x ;
if ( ! isvalidxy ( sx , sy ) ) {
return 0 ;
}
for ( x = 0 ; x < w ; x + + ) {
if ( getmodxy ( x , sy ) = = mod ) {
2021-02-17 23:30:12 +11:00
if ( who = = ANY | | getownernumxy ( x , sy ) = = who ) {
count + + ;
}
2021-02-17 21:50:31 +11:00
}
}
return count ;
}
int colhasmod ( int sx , int sy , char mod , int who ) {
int count = 0 ;
int y ;
if ( ! isvalidxy ( sx , sy ) ) {
return 0 ;
}
for ( y = 0 ; y < h ; y + + ) {
if ( getmodxy ( sx , y ) = = mod ) {
2021-02-17 23:30:12 +11:00
if ( who = = ANY | | getownernumxy ( sx , y ) = = who ) {
count + + ;
}
2021-02-17 21:50:31 +11:00
}
}
return count ;
}
int countownedinrow ( int sx , int sy , int who ) {
int count = 0 ;
int x ;
char * s ;
if ( ! isvalidxy ( sx , sy ) ) {
return 0 ;
}
for ( x = 0 ; x < w ; x + + ) {
if ( x ! = sx ) {
s = board [ sy * w + x ] ;
if ( getpnum ( getowner ( s ) ) = = who ) {
count + + ;
}
}
}
return count ;
}
int countownedincol ( int sx , int sy , int who ) {
int count = 0 ;
int y ;
char * s ;
if ( ! isvalidxy ( sx , sy ) ) {
return 0 ;
}
for ( y = 0 ; y < h ; y + + ) {
if ( y ! = sy ) {
s = board [ y * w + sx ] ;
if ( getpnum ( getowner ( s ) ) = = who ) {
count + + ;
}
}
}
return count ;
}
int countadjacent ( int x , int y , int who ) {
int count = 0 , d ;
int newx , newy ;
char * s ;
if ( ! isvalidxy ( x , y ) ) {
return 0 ;
}
for ( d = 0 ; d < = 3 ; d + + ) {
newx = x + xmod [ d ] ;
newy = y + ymod [ d ] ;
//printf("* checking %d,%d for spaces owned by who=%d\n",newx,newy,who);
if ( isvalidxy ( newx , newy ) ) {
//printf("* %d,%d is valid\n",newx,newy);
s = board [ newy * w + newx ] ;
//printf("* %d,%d is owned by: %c (player %d)\n",newx,newy,getowner(s),getpnum(getowner(s)));
if ( getpnum ( getowner ( s ) ) = = who ) {
count + + ;
}
}
}
return count ;
}
void aiupdatetile ( int x , int y ) {
int multi ;
int xpos , ypos ;
int idx = y * w + x ;
int n , a , b , c ;
char temp [ 1024 ] ;
xytopos ( x , y , & xpos , & ypos ) ;
if ( ! canplacetile ( turn , x , y , ' ' , NULL ) & &
! canmoveanyto ( turn , x , y , NULL , TRUE ) ) {
aivalue [ idx ] = BLOCKED ;
} else if ( xywouldgivewinto ( turn , x , y ) ) { // would make us win
modaivalue ( x , y , 999 , " would make us win " ) ;
modaivalue_around ( x , y , 10 , " would make us win " ) ; //adjust surrounding
modaidef_around ( x , y , 1 ) ;
modaidef ( x , y , - 999 ) ;
} else if ( xywouldgivewinto ( 1 - turn , x , y ) ) { // would make other player win
modaivalue ( x , y , 800 , " would give win to other player " ) ;
modaivalue_around ( x , y , 12 , " would give win to other player " ) ; //adjust surrounding
modaidef ( x , y , 10 ) ;
modaidef_around ( x , y , 2 ) ;
}
// if we already own it, probably dont want to go there
if ( getownernumxy ( x , y ) = = turn ) {
modaivalue ( x , y , - 15 , " we own this space already " ) ;
2021-02-21 17:19:03 +11:00
/*
2021-02-17 21:50:31 +11:00
} else {
n = countadjacent ( x , y , turn ) ;
// modify based on adjacent controlled locations
snprintf ( temp , 1024 , " we own %d adjacent cells " , n ) ;
modaivalue ( x , y , n * 1 , temp ) ; // controlled by us
2021-02-21 17:19:03 +11:00
*/
2021-02-17 21:50:31 +11:00
}
if ( getownernumxy ( x , y ) = = turn ) {
multi = 1 ;
} else {
multi = 2 ;
}
n = countadjacent ( x , y , 1 - turn ) ;
snprintf ( temp , 1024 , " other player owns %d adjacent cells " , n ) ;
modaivalue ( x , y , n * multi , temp ) ; // controlled by other player
modaidef_around ( x , y , countadjacent ( x , y , 1 - turn ) * 1 ) ;
// If we DONT own this location, consider other stones in the same row/col
if ( getownernumxy ( x , y ) ! = turn ) {
2021-02-17 23:30:12 +11:00
// walls actively count against value
// row
n = countownedinrow ( x , y , turn ) ;
2021-02-17 21:50:31 +11:00
snprintf ( temp , 1024 , " we own %d cells in this row " , n ) ;
modaivalue ( x , y , n * 6 , temp ) ;
2021-02-21 17:19:03 +11:00
n = rowhasmod ( x , y , ' | ' , turn ) + rowhasmod ( x , y , ' | ' , 1 - turn ) ;
2021-02-17 23:30:12 +11:00
snprintf ( temp , 1024 , " %d walls in this row " , n ) ;
modaivalue ( x , y , - ( n * 7 ) , temp ) ;
2021-02-21 17:19:03 +11:00
n = rowhasmod ( x , y , ' ^ ' , 1 - turn ) ;
2021-02-17 23:30:12 +11:00
snprintf ( temp , 1024 , " %d opposing capstones in this row " , n ) ;
modaivalue ( x , y , - ( n * 10 ) , temp ) ;
// col
n = countownedincol ( x , y , turn ) ;
snprintf ( temp , 1024 , " we own %d cells in this col " , n ) ;
2021-02-17 21:50:31 +11:00
modaivalue ( x , y , n * 6 , temp ) ;
2021-02-17 23:30:12 +11:00
n = colhasmod ( x , y , ' | ' , ANY ) ;
snprintf ( temp , 1024 , " %d walls in this col " , n ) ;
modaivalue ( x , y , - ( n * 7 ) , temp ) ;
n = colhasmod ( x , y , ' ^ ' , 1 - turn ) ;
snprintf ( temp , 1024 , " %d opposing capstones in this col " , n ) ;
modaivalue ( x , y , - ( n * 10 ) , temp ) ;
2021-02-17 21:50:31 +11:00
// opponent tiles in row, offset by our walls/caps
multi = 2 ;
a = rowhasmod ( x , y , ' ^ ' , turn ) ;
multi - = a ;
b = rowhasmod ( x , y , ' | ' , turn ) ;
multi - = b ;
if ( getownernumxy ( x , y ) = = ' ' ) { // cells noone owns are more valuable
c = 1 ;
multi + = 1 ;
} else {
c = 0 ;
}
n = countownedinrow ( x , y , 1 - turn ) - rowhasmod ( x , y , ' | ' , 1 - turn ) ; // don't include their walls
snprintf ( temp , 1024 , " other player has %d cells in row (we have %d caps + %d walls == %d multiplier) " , n , a , b , multi ) ;
if ( multi > 0 ) {
modaivalue ( x , y , n * multi , temp ) ;
}
modaidef ( x , y , n * 1 ) ;
// opponent tiles in col, offset by our walls/caps
multi = 2 ;
a = colhasmod ( x , y , ' ^ ' , turn ) ;
multi - = a ;
b = colhasmod ( x , y , ' | ' , turn ) ;
multi - = b ;
if ( getownernumxy ( x , y ) = = ' ' ) { // cells noone owns are more valuable
c = 1 ;
multi + = 1 ;
} else {
c = 0 ;
}
n = countownedincol ( x , y , 1 - turn ) - colhasmod ( x , y , ' | ' , 1 - turn ) ; // don't include their walls
snprintf ( temp , 1024 , " other player has %d cells in col (empty=%d, we have %d caps + %d walls == %d multiplier) " , n , c , a , b , multi ) ;
if ( multi > 0 ) {
modaivalue ( x , y , n * multi , temp ) ;
}
modaidef ( x , y , n * 1 ) ;
}
// reduce defence required for each or our caps in this row/col
a = colhasmod ( x , y , ' ^ ' , turn ) ;
b = rowhasmod ( x , y , ' ^ ' , turn ) ;
modaidef ( x , y , ( a + b ) * - 1 ) ;
a = colhasmod ( x , y , ' | ' , turn ) ;
b = rowhasmod ( x , y , ' | ' , turn ) ;
modaidef ( x , y , ( a + b ) * - 1 ) ;
}
char * genaicmd ( char * cmd , int showdb , int useworst ) {
2021-02-16 11:56:34 +11:00
int x , y , best ;
int ncandidates ;
int candidate [ MAXW * MAXH ] ;
int sel , xsel , ysel , xpossel , ypossel ;
// zero all priorities
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
aivalue [ y * w + x ] = 500 ;
2021-02-17 21:50:31 +11:00
aidef [ y * w + x ] = 0 ;
strcpy ( aireason [ y * w + x ] , " " ) ;
2021-02-16 11:56:34 +11:00
}
}
// mark anywhere we definitely cannot go
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
2021-02-17 21:50:31 +11:00
aiupdatetile ( x , y ) ;
2021-02-16 11:56:34 +11:00
}
}
// determine the best priority
2021-02-17 21:50:31 +11:00
if ( useworst ) best = 99999 ;
else best = - 1 ;
2021-02-16 11:56:34 +11:00
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
2021-02-17 21:50:31 +11:00
if ( aivalue [ y * w + x ] ! = BLOCKED ) {
if ( useworst ) {
if ( aivalue [ y * w + x ] < best ) best = aivalue [ y * w + x ] ;
} else {
if ( aivalue [ y * w + x ] > best ) best = aivalue [ y * w + x ] ;
}
2021-02-16 11:56:34 +11:00
}
}
}
if ( showdb ) {
showaivalues ( best ) ;
}
2021-02-17 21:50:31 +11:00
//printf("*** best value is = %d\n", best);
2021-02-16 11:56:34 +11:00
// pick randomly from the best priority
ncandidates = 0 ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
if ( aivalue [ y * w + x ] = = best ) {
candidate [ ncandidates + + ] = y * w + x ;
}
}
}
2021-02-17 21:50:31 +11:00
//printf("*** ncandidates = %d\n", ncandidates);
2021-02-16 11:56:34 +11:00
if ( ncandidates = = 0 ) {
sprintf ( cmd , " \\ r " ) ;
} else {
char str [ 256 ] ;
sel = rand ( ) % ncandidates ;
idxtoxy ( candidate [ sel ] , & xsel , & ysel ) ;
xytopos ( xsel , ysel , & xpossel , & ypossel ) ;
// we place a tile here or move here?
2021-02-17 21:50:31 +11:00
if ( canplacetile ( turn , xsel , ysel , ' ' , NULL ) ) {
char mod = ' ' ;
2021-02-21 17:19:03 +11:00
int chance = aidef [ ysel * w + xsel ] * 10 ;
2021-02-17 21:50:31 +11:00
// wall or cap?
if ( pctchance ( chance ) ) {
if ( ( capsleft [ turn ] > 0 ) & &
pctchance ( chance ) & &
canplacetile ( turn , xsel , ysel , ' ^ ' , NULL ) ) {
mod = ' ^ ' ;
} else if ( canplacetile ( turn , xsel , ysel , ' | ' , NULL ) ) {
mod = ' | ' ;
}
}
// place
if ( mod = = ' ' ) {
sprintf ( cmd , " %c%c " , xpossel , ypossel ) ;
} else {
sprintf ( cmd , " %c%c%c " , mod , xpossel , ypossel ) ;
}
} else if ( canmoveanyto ( turn , xsel , ysel , str , TRUE ) ) {
2021-02-16 11:56:34 +11:00
// move
sprintf ( cmd , " %s " , str ) ;
}
}
return cmd ;
}
2021-02-17 21:50:31 +11:00
int pctchance ( int num ) {
if ( rand ( ) % 100 < num ) {
return TRUE ;
}
return FALSE ;
}
2021-02-16 11:56:34 +11:00
int xywouldgivewinto ( int who , int tx , int ty ) {
char board2 [ MAXW * MAXH ] [ MAXBOARDSTRLEN ] ;
int x , y , wouldwin = FALSE ;
// take copy of board
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
strcpy ( board2 [ y * w + x ] , board [ y * w + x ] ) ;
}
}
2021-02-21 17:19:03 +11:00
// if player COULD go there,
2021-02-16 11:56:34 +11:00
// force owner of given position to given player
2021-02-21 17:19:03 +11:00
if ( canplacetile ( who , tx , ty , ' ' , NULL ) | |
canmoveanyto ( who , tx , ty , NULL , FALSE ) ) {
strcat ( board2 [ ty * w + tx ] , getpstr ( who ) ) ;
if ( playerhasroads ( who , board2 ) ) {
wouldwin = TRUE ;
}
2021-02-16 11:56:34 +11:00
}
return wouldwin ;
}
void idxtoxy ( int idx , int * x , int * y ) {
if ( x ) * x = idx % w ;
if ( y ) * y = idx / w ;
}
2021-02-17 21:50:31 +11:00
int modaidef ( int x , int y , int amt ) {
int idx = y * w + x ;
if ( ! isvalidxy ( x , y ) ) {
return TRUE ;
}
aidef [ idx ] + = amt ;
return FALSE ;
}
int modaivalue ( int x , int y , int amt , char * reason ) {
char temp [ 512 ] ;
2021-02-16 11:56:34 +11:00
int idx = y * w + x ;
2021-02-17 21:50:31 +11:00
if ( ! isvalidxy ( x , y ) ) {
return TRUE ;
}
2021-02-16 11:56:34 +11:00
if ( aivalue [ idx ] = = BLOCKED ) {
return TRUE ;
}
aivalue [ idx ] + = amt ;
2021-02-17 21:50:31 +11:00
snprintf ( temp , 512 , " [%s%-3d] %s \n " , ( amt > 0 ) ? " + " : " " , amt , reason ? reason : " <unspecified> " ) ;
strcat ( aireason [ idx ] , temp ) ;
return FALSE ;
}
int modaivalue_around ( int x , int y , int amt , char * reason ) {
int newx , newy , d ;
int xpos , ypos ;
char localreason [ 1024 ] ;
if ( ! isvalidxy ( x , y ) ) {
return TRUE ;
}
xytopos ( x , y , & xpos , & ypos ) ;
snprintf ( localreason , 1024 , " (from adjacent tile %c%c): %s " , xpos , ypos , reason ) ;
for ( d = 0 ; d < = 3 ; d + + ) {
newx = x + xmod [ d ] ;
newy = y + ymod [ d ] ;
modaivalue ( newx , newy , amt , localreason ) ;
}
return FALSE ;
}
int modaidef_around ( int x , int y , int amt ) {
int newx , newy , d ;
if ( ! isvalidxy ( x , y ) ) {
return TRUE ;
}
for ( d = 0 ; d < = 3 ; d + + ) {
newx = x + xmod [ d ] ;
newy = y + ymod [ d ] ;
modaidef ( newx , newy , amt ) ;
}
2021-02-16 11:56:34 +11:00
return FALSE ;
}
int isboardfull ( ) {
int x , y ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
if ( ! counttiles ( board [ y * w + x ] ) ) return FALSE ;
}
}
return TRUE ;
}
void updateroadstatus ( void ) {
int i ;
// update road status for each player
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
hasroad [ i ] = playerhasroads ( i , board ) ;
}
}
int checkendgame ( void ) {
int i ;
// someone resigned?
if ( gotwinner ( ) ) return TRUE ;
// either player has a road?
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
if ( hasroad [ i ] ) return TRUE ;
}
// any player out of tiles? (most flatstones wins)
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
if ( tilesleft [ i ] < 0 ) return TRUE ;
if ( capsleft [ i ] < 0 ) return TRUE ;
}
// board covered? (most flatstones wins)
if ( isboardfull ( ) ) {
return TRUE ;
}
2021-02-17 21:50:31 +11:00
2021-02-16 11:56:34 +11:00
return FALSE ;
}
2021-02-17 21:50:31 +11:00
void checkfortak ( int who ) {
int x , y ;
// check for 'tak' condition
tak [ who ] = FALSE ;
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
if ( xywouldgivewinto ( who , x , y ) ) {
2021-02-17 23:30:12 +11:00
if ( canplacetile ( who , x , y , ' ' , NULL ) | |
canmoveanyto ( who , x , y , NULL , FALSE ) ) {
tak [ who ] = TRUE ;
}
2021-02-17 21:50:31 +11:00
}
}
}
}
2021-02-16 11:56:34 +11:00
int getstartcapstones ( int sz ) {
switch ( sz ) {
case 3 :
case 4 :
return 0 ;
case 5 :
case 6 :
return 1 ;
case 8 :
return 2 ;
}
return - 1 ;
}
int getstarttiles ( int sz ) {
switch ( sz ) {
case 3 :
return 10 ;
case 4 :
return 15 ;
case 5 :
return 21 ;
case 6 :
return 30 ;
case 8 :
return 50 ;
}
return - 1 ;
}
int nextround ( void ) {
curround + + ;
// swap who goes first.
firstturn = 1 - firstturn ;
return 0 ;
}
int nextturn ( void ) {
turn = 1 - turn ;
if ( turn = = firstturn ) {
turnnumber + + ;
}
// reset game log variables?
topofmove = ' ' ;
flattened = FALSE ;
return 0 ;
}
char getpchar ( int n ) {
if ( ( n = = 0 ) | | ( n = = ' b ' ) ) {
return ' b ' ;
} else {
return ' r ' ;
}
}
char * getpcol ( int pnum ) {
switch ( pnum ) {
case 0 :
case ' b ' :
return BLUE ;
case 1 :
case ' r ' :
return RED ;
}
return reset ;
}
char * getpstr ( int n ) {
if ( ( n = = 0 ) | | ( n = = ' b ' ) ) {
return " b " ;
} else {
return " r " ;
}
}
char * getpname ( int n ) {
if ( ( n = = 0 ) | | ( n = = ' b ' ) ) {
return " blue " ;
} else {
return " red " ;
}
}
int getpnum ( int n ) {
if ( ( n = = 0 ) | | ( n = = ' b ' ) ) {
return 0 ;
} else if ( ( n = = 1 ) | | ( n = = ' r ' ) ) {
return 1 ;
} else {
return - 1 ;
}
}
void xytopos ( int x , int y , int * xch , int * ych ) {
if ( xch ) * xch = ' a ' + x ;
if ( ych ) * ych = ' 1 ' + y ;
}
void postoxy ( int xch , int ych , int * x , int * y ) {
if ( x ) * x = xch - ' a ' ;
if ( y ) * y = ych - ' 1 ' ;
}
int movetile ( int count , char xch , char ych , char dir , char * dropstr ) {
int pos , newpos , x , y , mod , origcount ;
int newxch , newych ;
char countstr [ 4 ] ;
2021-02-21 17:19:03 +11:00
char moving [ MAXSTACK * 30 ] ;
char dropping [ MAXSTACK * 30 ] ;
2021-02-16 11:56:34 +11:00
char * bpos , * newbpos , * p , * dp , * mp ;
int pass ;
2021-02-17 21:50:31 +11:00
int xmodamt , ymodamt ;
2021-02-16 11:56:34 +11:00
int numtomove ;
char err [ 256 ] ;
postoxy ( xch , ych , & x , & y ) ;
if ( ! isvalidxypos ( xch , ych ) ) {
printf ( " * invalid cell reference '%c%c' \n " , xch , ych ) ;
return TRUE ;
}
// remember the top tile mod, so we can log it in the game log
topofmove = getmodxy ( x , y ) ;
normalise ( & topofmove ) ;
pos = y * w + x ;
bpos = board [ pos ] ;
origcount = counttiles ( bpos ) ;
if ( count = = ALL ) {
// if no count specified, move max stack limit
if ( origcount < = size ) {
count = origcount ;
strcpy ( countstr , " ALL " ) ;
} else {
count = size ;
sprintf ( countstr , " %d " , count ) ;
}
} else {
sprintf ( countstr , " %d " , count ) ;
}
if ( ! canmovefrom ( turn , x , y , err ) ) {
printf ( " * %s can't move %s tiles %s from %c%c - %s \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , err ) ;
return TRUE ;
}
// validate count
if ( count > origcount ) {
printf ( " * %s can't move %s tiles %s from %c%c - only %d there \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , origcount ) ;
return TRUE ;
}
2021-02-17 21:50:31 +11:00
dirtoxy ( dir , & xmodamt , & ymodamt ) ;
2021-02-16 11:56:34 +11:00
numtomove = count ;
// First pass: validate each step
for ( pass = 0 ; pass < = 1 ; pass + + ) {
int remaining , numtodrop ;
if ( pass = = 1 ) {
if ( debug ) printf ( " - %s%s%s is moving %d tiles %s from %c%c, dropping %s \n " , getpcol ( turn ) , getpname ( turn ) , reset , count , getdirname ( dir ) , xch , ych , strlen ( dropstr ) ? dropstr : " * " ) ;
}
//printf("PASS %d\n",pass);
postoxy ( xch , ych , & x , & y ) ;
// pick up stack of tiles to move
p = bpos + strlen ( bpos ) - 1 ;
//printf("debug: bpos is: %s\n", bpos);
//printf("debug: p is: %s\n", p);
if ( ismod ( * p ) ) p - - ;
p - = ( count - 1 ) ;
//printf("debug: new p is: %s\n", p);
strcpy ( moving , p ) ;
if ( pass = = 1 ) {
// actually remove tiles from source location
* p = 0 ;
}
// begin at start of drop string
dp = dropstr ;
// start dropping from bottom of moving stack
mp = moving ;
newxch = xch ;
newych = ych ;
while ( ( remaining = counttiles ( mp ) ) ) {
//printf("remaining in mp: %d\n",remaining);;
//printf("move %s from %d,%d (%c%c)", getdirname(dir), x,y,newxch,newych);
2021-02-17 21:50:31 +11:00
x + = xmodamt ;
y + = ymodamt ;
2021-02-16 11:56:34 +11:00
// still on the board?
if ( ! isvalidxy ( x , y ) ) {
printf ( " * %s can't move %s tiles %s from %c%c - would move off board with %d tiles remaining \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , remaining ) ;
return TRUE ;
}
xytopos ( x , y , & newxch , & newych ) ;
newpos = y * w + x ;
newbpos = board [ newpos ] ;
//printf("now at %d,%d (%c%c)", x,y,newxch,newych);
mod = getmod ( newbpos ) ;
if ( ! canmoveto ( turn , x , y , err ) ) {
printf ( " * %s can't move %s tiles %s from %c%c - %s \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , err ) ;
return TRUE ;
} else if ( ( mod = = ' | ' ) & & ( remaining > 1 ) ) {
// stack of > 1 moving onto standing stone
printf ( " * %s can't move %s tiles %s from %c%c - %d tiles blocked by %s standing stone at %c%c \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , remaining , getpname ( getowner ( newbpos ) ) , newxch , newych ) ;
return TRUE ;
} else if ( ( mod = = ' | ' ) & & ( getmod ( mp ) ! = ' ^ ' ) ) {
// non-capstone moving onto standing stone
printf ( " * %s can't move %s tiles %s from %c%c - only capstone can move onto %s standing stone at %c%c \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , getpname ( getowner ( newbpos ) ) , newxch , newych ) ;
return TRUE ;
} else if ( ( mod = = ' | ' ) & & ( remaining = = 1 ) & & ( getmod ( mp ) = = ' ^ ' ) ) {
// single capstone moving onto a standing stone
if ( pass = = 1 ) {
if ( debug ) printf ( " - %s%s%s capstone flattens %s%s%s standing stone at %c%c! \n " , getpcol ( turn ) , getpname ( turn ) , reset ,
getpcol ( getowner ( newbpos ) ) , getpname ( getowner ( newbpos ) ) , reset ,
newxch , newych ) ;
newbpos [ strlen ( newbpos ) - 1 ] = 0 ; ;
flattened = TRUE ;
}
}
// drop tiles
if ( ! dp | | * dp = = 0 ) {
numtodrop = remaining ;
} else {
numtodrop = * dp - ' 0 ' ;
}
if ( numtodrop > remaining ) {
printf ( " * %s can't move %s tiles %s from %c%c with '%s' - want to drop %d tiles at %c%c but only %d remain \n " , getpname ( turn ) , countstr , getdirname ( dir ) , xch , ych , dropstr , numtodrop , newxch , newych , remaining ) ;
return TRUE ;
}
// construct string of tiles to drop
strncpy ( dropping , mp , numtodrop ) ;
dropping [ numtodrop ] = 0 ;
// retain top capstone/standingstone
if ( ismod ( * ( mp + numtodrop ) ) ) {
strncat ( dropping , mp + numtodrop , 1 ) ;
mp + + ; // havk
}
if ( pass = = 1 ) {
2021-02-21 17:19:03 +11:00
char colorstr [ MAXSTACK * 30 ] ;
2021-02-16 11:56:34 +11:00
// add ansi color codes
2021-02-21 17:19:03 +11:00
makecolorstr ( dropping , colorstr , NOBOLD ) ;
2021-02-16 11:56:34 +11:00
if ( debug ) {
printf ( " - dropping '%s' (%d) at %c%c. remaining: '%s' (%d) \n " ,
colorstr , numtodrop , newxch , newych ,
( mp + numtodrop ) , counttiles ( mp + numtodrop ) ) ;
}
// actually drop tiles here
strcat ( newbpos , dropping ) ;
2021-02-21 17:19:03 +11:00
if ( numtodrop > 0 ) {
setlastmove ( x , y , numtodrop ) ;
}
2021-02-16 11:56:34 +11:00
}
// remove dropped tiles from moving stack
mp + = numtodrop ;
// advance to next drop count entry
dp + + ;
}
}
2021-02-21 17:19:03 +11:00
2021-02-16 11:56:34 +11:00
return FALSE ;
}
void dirtoxy ( char dir , int * x , int * y ) {
* x = 0 ;
* y = 0 ;
switch ( dir ) {
case ' > ' :
* x = 1 ;
* y = 0 ;
break ;
case ' < ' :
* x = - 1 ;
* y = 0 ;
break ;
case ' + ' :
* x = 0 ;
* y = 1 ;
break ;
case ' - ' :
* x = 0 ;
* y = - 1 ;
break ;
}
}
int placetile ( int who , char xch , char ych , char mod ) {
int pos , x , y ;
char * bpos ;
char err [ 256 ] ;
if ( mod ) mod = modprintable ( mod ) ;
postoxy ( xch , ych , & x , & y ) ;
pos = y * w + x ;
bpos = board [ pos ] ;
if ( ! canplacetile ( who , x , y , mod , err ) ) {
// is this space available?
printf ( " * %s \n " , err ) ;
return TRUE ;
}
if ( debug ) printf ( " -- placing %s %s at %c%c \n " , getpname ( who ) , getmodname ( mod ) , xch , ych ) ;
strcat ( bpos , getpstr ( who ) ) ;
if ( mod ) {
strncat ( bpos , & mod , 1 ) ;
}
if ( mod = = ' ^ ' ) {
capsleft [ who ] - - ;
} else {
tilesleft [ who ] - - ;
}
2021-02-21 17:19:03 +11:00
setlastmove ( x , y , 1 ) ;
2021-02-16 11:56:34 +11:00
return FALSE ;
}
int canplacetile ( int who , int x , int y , int mod , char * why ) {
int idx , xch , ych ;
char * bpos ;
xytopos ( x , y , & xch , & ych ) ;
idx = y * w + x ;
bpos = board [ idx ] ;
if ( why ) strcpy ( why , " " ) ;
// placing capstone on first turn?
if ( turnnumber = = 1 & & ( ( mod = = ' | ' ) | | ( mod = = ' ^ ' ) ) ) {
if ( why ) sprintf ( why , " can't place %s %s at %c%c - can only place flat tiles during setup, mod is '%c' \n " , getpname ( who ) , getmodname ( mod ) , xch , ych , mod ) ;
return FALSE ;
}
if ( ( mod = = ' ^ ' ) & & ( capsleft [ who ] < = 0 ) ) {
if ( why ) sprintf ( why , " can't place %s %s at %c%c - no capstones left \n " , getpname ( who ) , getmodname ( mod ) , xch , ych ) ;
return FALSE ;
}
if ( strlen ( bpos ) > 0 ) {
if ( why ) sprintf ( why , " can't place %s %s at %c%c - not free \n " , getpname ( who ) , getmodname ( mod ) , xch , ych ) ;
return FALSE ;
}
return TRUE ;
}
2021-02-17 21:50:31 +11:00
int canmoveanyto ( int who , int tx , int ty , char * why , int safe ) {
2021-02-16 11:56:34 +11:00
int x , y ;
if ( ! canmoveto ( who , tx , ty , why ) ) return FALSE ;
if ( why ) strcpy ( why , " " ) ;
// for each tile we control, see if it can move to given spot
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
int ok = TRUE ;
int count ;
if ( ( x = = tx ) & & ( y = = ty ) ) {
ok = FALSE ;
}
if ( ok & & ( x ! = tx ) & & ( y ! = ty ) ) { // same row/col
ok = FALSE ;
}
2021-02-17 21:50:31 +11:00
if ( ok ) {
if ( safe ) {
2021-02-21 17:19:03 +11:00
if ( ! willmovefrom ( who , x , y , why ) ) { // got somethong which is safe to move here
2021-02-17 21:50:31 +11:00
ok = FALSE ;
}
} else {
2021-02-21 17:19:03 +11:00
if ( ! canmovefrom ( who , x , y , why ) ) { // got somethong to move here
2021-02-17 21:50:31 +11:00
ok = FALSE ;
}
}
2021-02-16 11:56:34 +11:00
}
count = counttiles ( board [ y * w + x ] ) ;
if ( ok & & ( x = = tx ) & & abs ( tx - x ) > count ) { // distance ok?
ok = FALSE ;
}
if ( ok & & ( y = = ty ) & & abs ( ty - y ) > count ) { // distance ok?
ok = FALSE ;
}
// can this stack get one of our color to there???
2021-02-17 21:50:31 +11:00
if ( ok & & canmakedropstr ( who , x , y , tx , ty , why ) ) {
2021-02-16 11:56:34 +11:00
return TRUE ;
}
}
}
return FALSE ;
}
int canmakedropstr ( int who , int sx , int sy , int dx , int dy , char * str ) { // return TRUE if we succeeded
int count , maxtry , trystacksize , d ;
char moving [ MAXSTACK * 2 ] ;
char * mp ;
char * p ;
char * spos ;
int smod ;
char localstr [ 256 ] ;
2021-02-17 23:30:12 +11:00
int db = FALSE ;
int sizes [ 3 ] [ MAXSTACK ] ;
int scount [ 3 ] ;
int tryidx , n , i ;
2021-02-16 11:56:34 +11:00
spos = board [ sy * w + sx ] ;
smod = getmod ( spos ) ;
count = counttiles ( board [ sy * w + sx ] ) ;
if ( count < 1 ) {
return FALSE ;
}
if ( count > size ) maxtry = size ;
else maxtry = count ;
// which dir?
if ( ( sx = = dx ) & & ( sy < dy ) ) {
d = 0 ;
} else if ( ( sx = = dx ) & & ( sy > dy ) ) {
d = 2 ;
} else if ( ( sy = = dy ) & & ( sx > dx ) ) {
d = 3 ;
} else if ( ( sy = = dy ) & & ( sx < dx ) ) {
d = 1 ;
} else {
return FALSE ;
}
2021-02-17 23:30:12 +11:00
// try sizes that leave us in control of the initial tile
// first.
for ( i = 0 ; i < = 2 ; i + + ) { // 0 good, 1 bad, 2 good then bad
scount [ i ] = 0 ;
}
if ( db ) {
printf ( " db: ** maxtry is.%d \n " , maxtry ) ;
}
2021-02-16 11:56:34 +11:00
for ( trystacksize = 1 ; trystacksize < = maxtry ; trystacksize + + ) {
2021-02-17 23:30:12 +11:00
p = spos + strlen ( spos ) - 1 ;
if ( ismod ( * p ) ) p - - ;
p - = ( trystacksize - 1 ) ; // we're on the 1st tile that's moving
if ( p > spos & & ( * ( p - 1 ) = = getpchar ( who ) ) ) {
// we own top of remaining stack
sizes [ 0 ] [ scount [ 0 ] + + ] = trystacksize ;
} else {
// the other player owns it
sizes [ 1 ] [ scount [ 1 ] + + ] = trystacksize ;
}
}
// combine lists, first good then bad
for ( i = 0 ; i < = 1 ; i + + ) {
for ( n = 0 ; n < scount [ i ] ; n + + ) {
sizes [ 2 ] [ scount [ 2 ] + + ] = sizes [ i ] [ n ] ;
}
}
if ( db ) {
printf ( " db: ** stack sizes to try: " ) ;
for ( tryidx = 0 ; tryidx < scount [ 2 ] ; tryidx + + ) {
printf ( " %d(%c) " , sizes [ 2 ] [ tryidx ] ,
tryidx > = scount [ 0 ] ? ' b ' : ' g ' ) ;
}
printf ( " \n " ) ;
}
// try each stack size
for ( tryidx = 0 ; tryidx < scount [ 2 ] ; tryidx + + ) {
2021-02-16 11:56:34 +11:00
int x , y ;
int stillgood = TRUE ;
int xch , ych ;
2021-02-17 23:30:12 +11:00
trystacksize = sizes [ 2 ] [ tryidx ] ;
2021-02-16 11:56:34 +11:00
// pick up stack of tiles to move
p = spos + strlen ( spos ) - 1 ;
if ( ismod ( * p ) ) p - - ;
p - = ( trystacksize - 1 ) ;
strcpy ( moving , p ) ;
mp = moving ;
// max distance we can move before hitting wall/cap/edge?
x = sx ; y = sy ;
xytopos ( x , y , & xch , & ych ) ;
stillgood = TRUE ;
sprintf ( localstr , " %d%c%c%c " , trystacksize , xch , ych , getdirchar ( d ) ) ;
while ( stillgood ) {
// move one cell toward dst
x + = xmod [ d ] ;
y + = ymod [ d ] ;
if ( ! isvalidxy ( x , y ) | | getmodxy ( x , y ) = = ' ^ ' | |
( getmodxy ( x , y ) = = ' | ' & & ( smod ! = ' ^ ' | | counttiles ( mp ) ! = 1 ) ) ) {
// hit a blocker - stop
stillgood = FALSE ;
} else {
// are we there yet
if ( x = = dx & & y = = dy ) {
char temp [ 64 ] ;
// dump the rest here and we're done
sprintf ( temp , " %1d " , counttiles ( mp ) ) ;
strcat ( localstr , temp ) ;
if ( str ) strcpy ( str , localstr ) ;
return TRUE ;
2021-02-17 21:50:31 +11:00
// TODO: go further to control more locations
2021-02-16 11:56:34 +11:00
} else {
char * z ;
// not there yet.
// must drop at least one
2021-02-17 21:50:31 +11:00
// TODO: figure out how many we can drop and
// still reach dst
2021-02-16 11:56:34 +11:00
//z = strchr(mp, getpchar(who));
// stone to drop.
z = mp ; // drop 1
if ( z ) {
// if match, drop so it's on top
int numtodrop = ( z - moving ) + 1 ;
2021-02-17 21:50:31 +11:00
int didsomething = TRUE ;
char temp [ 10 ] , owner ;
// would dropping this amt let the
// other player win?
while ( didsomething ) {
didsomething = FALSE ;
owner = * ( z + numtodrop - 1 ) ;
if ( getpnum ( owner ) = = 1 - who ) {
if ( xywouldgivewinto ( 1 - who , x , y ) ) {
if ( + + numtodrop > = counttiles ( mp ) ) {
break ;
}
didsomething = TRUE ;
}
}
}
2021-02-16 11:56:34 +11:00
// no more tiles in moving stack??
if ( numtodrop > = counttiles ( mp ) ) {
// this stack size.
stillgood = FALSE ;
} else {
2021-02-17 21:50:31 +11:00
sprintf ( temp , " %1d " , numtodrop ) ;
strcat ( localstr , temp ) ;
if ( db ) printf ( " db: ** numtodrop: %d. tiles in stack: %d (%s) \n " , numtodrop , counttiles ( mp ) , mp ) ;
2021-02-16 11:56:34 +11:00
// remove dropped tiles from moving stack
mp + = numtodrop ;
if ( db ) printf ( " db: ** new tiles in stack: %d (%s) \n " , counttiles ( mp ) , mp ) ;
}
} else {
// if not, fail this stack size.
stillgood = FALSE ;
}
}
}
}
}
return FALSE ;
}
char getdirchar ( int dir ) {
switch ( dir ) {
case 1 :
return ' > ' ;
case 3 :
return ' < ' ;
case 0 :
return ' + ' ;
case 2 :
return ' - ' ;
}
return ' = ' ;
}
2021-02-17 21:50:31 +11:00
int willmovefrom ( int who , int x , int y , char * why ) {
// would moving away from here make the other player win?
if ( xywouldgivewinto ( who , x , y ) ) {
if ( why ) sprintf ( why , " Moving away would open up a win to other player " ) ;
return FALSE ;
}
return canmovefrom ( who , x , y , why ) ;
}
2021-02-16 11:56:34 +11:00
int canmovefrom ( int who , int x , int y , char * why ) {
int mod ;
int idx , xch , ych ;
char * bpos ;
xytopos ( x , y , & xch , & ych ) ;
idx = y * w + x ;
bpos = board [ idx ] ;
mod = getmod ( bpos ) ;
if ( why ) strcpy ( why , " " ) ;
2021-02-17 21:50:31 +11:00
if ( turnnumber = = 1 ) {
if ( why ) sprintf ( why , " cant move on first setup turn. \n " ) ;
return FALSE ;
}
2021-02-16 11:56:34 +11:00
// is there anything at the source location?
if ( ! strlen ( bpos ) ) {
2021-02-17 21:50:31 +11:00
if ( why ) sprintf ( why , " empty source location \n " ) ;
2021-02-16 11:56:34 +11:00
return FALSE ;
}
// does the other player own the source location?
if ( getowner ( bpos ) = = getpchar ( 1 - who ) ) {
2021-02-17 21:50:31 +11:00
if ( why ) sprintf ( why , " not owner of source location \n " ) ;
2021-02-16 11:56:34 +11:00
return FALSE ;
}
return TRUE ;
}
int canmoveto ( int who , int x , int y , char * why ) {
int mod ;
int idx , xch , ych ;
char * bpos ;
xytopos ( x , y , & xch , & ych ) ;
idx = y * w + x ;
bpos = board [ idx ] ;
mod = getmod ( bpos ) ;
if ( why ) strcpy ( why , " " ) ;
2021-02-17 21:50:31 +11:00
if ( turnnumber = = 1 ) {
if ( why ) sprintf ( why , " cant move on first setup turn. \n " ) ;
return FALSE ;
}
2021-02-16 11:56:34 +11:00
if ( mod = = ' ^ ' ) {
// capstone?
2021-02-17 21:50:31 +11:00
if ( why ) sprintf ( why , " %s capstone at %c%c \n " , getpname ( getowner ( bpos ) ) , xch , ych ) ;
2021-02-16 11:56:34 +11:00
return FALSE ;
}
return TRUE ;
}
int isvalidxy ( int x , int y ) {
if ( x > = 0 & & x < w & & y > = 0 & & y < w ) {
return TRUE ;
}
return FALSE ;
}
int isvalidxypos ( char x , char y ) {
char firstx = ' a ' ;
char lastx = ' a ' + w - 1 ;
char firsty = ' 1 ' ;
char lasty = ' 1 ' + h - 1 ;
if ( x > = firstx & & x < = lastx & & y > = firsty & & y < = lasty ) {
return TRUE ;
}
return FALSE ;
}
int parsecmd ( char * cmd ) {
int err = FALSE ;
int mod = 0 ;
char * p = cmd ;
if ( ! p ) return TRUE ;
if ( ! strcmp ( cmd , " \\ r " ) ) {
// resign
winner = 1 - turn ;
logmove ( turn , cmd , ' ' ) ;
return FALSE ;
2021-02-17 21:50:31 +11:00
} else if ( strstr ( cmd , " \\ W " ) ) { // check if loc would give us a win
2021-02-16 11:56:34 +11:00
int xpos , ypos , x , y , wouldwin ;
p = cmd + 3 ;
xpos = p [ 0 ] ;
ypos = p [ 1 ] ;
postoxy ( xpos , ypos , & x , & y ) ;
wouldwin = xywouldgivewinto ( turn , x , y ) ;
printf ( " *** would %c%c give us a win? %s \n " , xpos , ypos ,
wouldwin ? " YES " : " no " ) ;
return TRUE ;
2021-02-17 21:50:31 +11:00
} else if ( ! strcmp ( cmd , " \\ b " ) ) {
showboard ( ) ;
return TRUE ;
} else if ( strstr ( cmd , " \\ w " ) ) {
int xpos , ypos , x , y ;
p = cmd + 3 ;
xpos = p [ 0 ] ;
ypos = p [ 1 ] ;
postoxy ( xpos , ypos , & x , & y ) ;
printf ( " %sAI thoughts for %s%c%c%s%s: [%s%d%s%s] \n " , YELLOW , BOLD , xpos , ypos , reset , YELLOW , BOLD , aivalue [ y * w + x ] , reset , YELLOW ) ;
printf ( " %s%s \n " , aireason [ y * w + x ] , reset ) ;
return TRUE ;
} else if ( ! strcmp ( cmd , " \\ s " ) ) {
showscores ( " Current " ) ;
return TRUE ;
2021-02-16 11:56:34 +11:00
} else if ( strstr ( cmd , " \\ m " ) ) { // check if we can move to loc
char temp [ 256 ] ;
int xpos , ypos , x , y ;
p = cmd + 3 ;
xpos = p [ 0 ] ;
ypos = p [ 1 ] ;
postoxy ( xpos , ypos , & x , & y ) ;
2021-02-17 21:50:31 +11:00
if ( canmoveanyto ( turn , x , y , temp , FALSE ) ) {
2021-02-16 11:56:34 +11:00
printf ( " *** %c%c is reachable: %s \n " , xpos , ypos , temp ) ;
} else {
printf ( " *** can't move to %c%c \n " , xpos , ypos ) ;
}
2021-02-17 21:50:31 +11:00
return TRUE ;
} else if ( strstr ( cmd , " \\ c " ) ) { // count adjacent tiles to loc
int xpos , ypos , x , y , num , i ;
p = cmd + 3 ;
xpos = p [ 0 ] ;
ypos = p [ 1 ] ;
postoxy ( xpos , ypos , & x , & y ) ;
for ( i = 0 ; i < = 1 ; i + + ) {
num = countadjacent ( x , y , i ) ;
printf ( " %c%c has %d adjacent %s%s%s controlled locations. \n " , xpos , ypos , num , getpcol ( i ) , getpname ( i ) , reset ) ;
}
2021-02-16 11:56:34 +11:00
return TRUE ;
} else if ( ! strcmp ( cmd , " \\ a " ) ) { // simlulate AI move for us, with debug info
char cmd [ 256 ] ;
2021-02-17 21:50:31 +11:00
genaicmd ( cmd , TRUE , FALSE ) ;
printf ( " %sAI suggested move for %s%s%s%s: %s%s%s%s \n " , YELLOW , getpcol ( turn ) , getpname ( turn ) , reset , YELLOW , getpcol ( turn ) , BOLD , cmd , reset ) ;
2021-02-16 11:56:34 +11:00
return TRUE ;
}
if ( ismod ( p [ 0 ] ) ) {
mod = p [ 0 ] ;
p + + ;
}
if ( strchr ( p , ' q ' ) ) {
gameover = TRUE ;
} else if ( isalpha ( p [ 0 ] ) & & isdigit ( p [ 1 ] ) & & isdir ( p [ 2 ] ) ) {
// move all tiles in direction
int xpos = p [ 0 ] ;
int ypos = p [ 1 ] ;
int dir = p [ 2 ] ;
if ( movetile ( ALL , xpos , ypos , dir , p + 3 ) ) err = TRUE ;
} else if ( isdigit ( p [ 0 ] ) & & isalpha ( p [ 1 ] ) & & isdigit ( p [ 2 ] ) & & isdir ( p [ 3 ] ) ) {
// move x tiles in direction
int count = p [ 0 ] - ' 0 ' ;
int xpos = p [ 1 ] ;
int ypos = p [ 2 ] ;
int dir = p [ 3 ] ;
if ( count > size ) {
printf ( " * can't move more than %d tiles \n " , size ) ;
err = TRUE ;
} else {
if ( movetile ( count , xpos , ypos , dir , p + 4 ) ) err = TRUE ;
}
} else if ( ( strlen ( p ) = = 2 ) & & isalpha ( p [ 0 ] ) & & isdigit ( p [ 1 ] ) ) {
// place tile
int xpos = p [ 0 ] ;
int ypos = p [ 1 ] ;
if ( isvalidxypos ( xpos , ypos ) ) {
if ( placetile ( ( turnnumber = = 1 ) ? ( 1 - turn ) : turn , xpos , ypos , mod ) ) err = TRUE ;
} else {
printf ( " * invalid cell reference '%c%c' \n " , xpos , ypos ) ;
err = TRUE ;
}
} else {
printf ( " * bad command '%s' \n " , cmd ) ;
err = TRUE ;
}
if ( err & & ai [ turn ] ) {
char temp [ 10 ] ;
printf ( " ...ai made an error?! " ) ;
fgets ( temp , MAX_CMD_LEN , stdin ) ;
exit ( 1 ) ;
}
if ( ! err ) {
2021-02-17 21:50:31 +11:00
checkfortak ( turn ) ;
2021-02-17 23:30:12 +11:00
checkfortak ( 1 - turn ) ;
2021-02-16 11:56:34 +11:00
logmove ( turn , cmd , topofmove ) ;
}
return err ;
}
2021-02-21 17:19:03 +11:00
char * makecolorstr ( char * orig , char * newstr , int lastmovecount ) {
char * p , * curcol , * boldstart = NULL ;
if ( lastmovecount > 0 ) {
int count = 0 ;
for ( p = orig + strlen ( orig ) - 1 ; p > = orig ; p - - ) {
if ( * p = = getpchar ( 0 ) | | * p = = getpchar ( 1 ) ) {
count + + ;
if ( count = = lastmovecount ) {
boldstart = p ;
break ;
}
}
}
}
// printf("\nmcs(): got lmc = %d, boldidx = %d\n",lastmovecount, boldidx);
2021-02-16 11:56:34 +11:00
strcpy ( newstr , " " ) ;
for ( p = orig ; * p ; p + + ) {
if ( ! ismod ( * p ) ) {
curcol = getpcol ( getpchar ( * p ) ) ;
strcat ( newstr , curcol ) ;
}
2021-02-21 17:19:03 +11:00
if ( boldstart & & p > = boldstart & & * p ! = ' ' ) {
strcat ( newstr , BOLD ) ;
}
2021-02-16 11:56:34 +11:00
strncat ( newstr , p , 1 ) ;
}
strcat ( newstr , reset ) ;
return newstr ;
}
void showaivalues ( int best ) {
int x , y ;
char ch ;
2021-02-17 21:50:31 +11:00
printf ( " \n " ) ;
2021-02-16 11:56:34 +11:00
printf ( FORMAT_ROWHEAD , ' ' ) ;
ch = ' a ' ;
for ( x = 0 ; x < w ; x + + ) {
printf ( FORMAT_COLHEAD , ch + + ) ;
}
printf ( FORMAT_ROWTAIL , ' ' ) ;
printf ( " \n " ) ;
line ( ) ;
ch = ' 1 ' + h - 1 ;
for ( y = h - 1 ; y > = 0 ; y - - ) {
// show ai priority values
printf ( FORMAT_ROWHEAD , ch ) ;
for ( x = 0 ; x < w ; x + + ) {
int val = aivalue [ y * w + x ] ;
2021-02-17 21:50:31 +11:00
int def = aidef [ y * w + x ] ;
char * col ;
if ( val = = best ) {
col = GREEN ;
} else if ( val = = BLOCKED ) {
col = RED ;
} else {
col = YELLOW ;
}
printf ( FORMAT_AIVAL , col , val , reset , def ) ;
2021-02-16 11:56:34 +11:00
}
printf ( FORMAT_ROWTAIL , ch ) ;
printf ( " \n " ) ;
// TODO: move this to a function
// show board stack
2021-02-21 17:19:03 +11:00
showboardrow ( board , y ) ;
2021-02-16 11:56:34 +11:00
ch - - ;
}
printf ( FORMAT_ROWHEAD , ' ' ) ;
ch = ' a ' ;
for ( x = 0 ; x < w ; x + + ) {
printf ( FORMAT_COLHEAD , ch + + ) ;
}
printf ( FORMAT_ROWTAIL , ' ' ) ;
printf ( " \n " ) ;
/*
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
showboardbinary ( i ) ;
}
*/
}
2021-02-21 17:19:03 +11:00
void showboardrow ( char ( * b ) [ MAXBOARDSTRLEN ] , int y ) {
int x , ch ;
xytopos ( 0 , y , NULL , & ch ) ;
printf ( FORMAT_ROWHEAD , ch ) ;
for ( x = 0 ; x < w ; x + + ) {
char * str = board [ y * w + x ] ;
// show stack
if ( str ) {
char origstr [ MAXSTACK * 30 ] ;
char colorstr [ MAXSTACK * 30 ] ;
sprintf ( origstr , FORMAT_STACK , str ? str : " " ) ;
// add ansi color codes
makecolorstr ( origstr , colorstr , lastmove [ y * w + x ] ) ;
printf ( " %s " , colorstr ) ;
} else {
printf ( FORMAT_STACK , " " ) ;
}
}
printf ( FORMAT_ROWTAIL , ch ) ;
printf ( " \n " ) ;
line ( ) ;
}
2021-02-16 11:56:34 +11:00
void showboard ( void ) {
2021-02-17 23:30:12 +11:00
int x , y , i ;
2021-02-16 11:56:34 +11:00
char ch ;
2021-02-17 23:30:12 +11:00
printf ( " \n %sRound %d - Turn %d (%s%s%s%s): " , BOLD , curround , turnnumber , getpcol ( turn ) , BOLD , getpname ( turn ) , reset ) ;
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
if ( tak [ i ] ) {
printf ( " %s---Tak:%s%s%s " , getpcol ( i ) , BOLD , getpname ( i ) , reset ) ;
}
}
printf ( " \n " ) ;
2021-02-16 11:56:34 +11:00
printf ( FORMAT_ROWHEAD , ' ' ) ;
ch = ' a ' ;
for ( x = 0 ; x < w ; x + + ) {
printf ( FORMAT_COLHEAD , ch + + ) ;
}
printf ( FORMAT_ROWTAIL , ' ' ) ;
printf ( " \n " ) ;
line ( ) ;
ch = ' 1 ' + h - 1 ;
for ( y = h - 1 ; y > = 0 ; y - - ) {
2021-02-21 17:19:03 +11:00
showboardrow ( board , y ) ;
2021-02-16 11:56:34 +11:00
ch - - ;
}
printf ( FORMAT_ROWHEAD , ' ' ) ;
ch = ' a ' ;
for ( x = 0 ; x < w ; x + + ) {
printf ( FORMAT_COLHEAD , ch + + ) ;
}
printf ( FORMAT_ROWTAIL , ' ' ) ;
printf ( " \n " ) ;
/*
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
showboardbinary ( i ) ;
}
*/
}
int xtoleftshift ( int num ) {
return ( w - num - 1 ) ;
}
void showboardbinary ( int pnum ) {
int x , y ;
int line [ h ] ;
int allones = pow ( 2 , w ) - 1 ;
int hline = 0 , vline = allones ;
char ch ;
printf ( " Binary board for %s: \n " , getpname ( pnum ) ) ;
// show top heading
printf ( " - " ) ;
ch = ' a ' ;
for ( x = 0 ; x < w ; x + + ) {
printf ( " %c " , ch + + ) ;
}
printf ( " \n " ) ;
ch = ' 1 ' + h - 1 ;
for ( y = h - 1 ; y > = 0 ; y - - ) {
line [ y ] = 0 ;
for ( x = 0 ; x < w ; x + + ) {
char * str = board [ y * w + x ] ;
if ( ( getmod ( str ) ! = ' | ' ) & & getowner ( str ) ! = ' ' & & ( getpnum ( getowner ( str ) ) = = pnum ) ) {
int this ;
this = 1 < < xtoleftshift ( x ) ;
line [ y ] | = this ;
}
}
printbinaryline ( ch - - , line [ y ] , TRUE ) ;
}
//printbinaryline('X', vline);
for ( y = h - 1 ; y > = 0 ; y - - ) {
hline | = line [ y ] ;
vline & = line [ y ] ;
//printbinaryline('x', vline);
}
/*
printf ( " raw: \n " ) ;
ch = ' 1 ' + h - 1 ;
for ( y = h - 1 ; y > = 0 ; y - - ) {
line [ y ] = 0 ;
printf ( " %c - " , ch - - ) ;
// show line
for ( x = 0 ; x < w ; x + + ) {
char * str = board [ y * w + x ] ;
if ( ( getmod ( str ) ! = ' | ' ) & & getowner ( str ) ! = ' ' & & ( getpnum ( getowner ( str ) ) = = pnum ) ) {
printf ( " %d " , 1 ) ;
} else {
printf ( " %d " , 0 ) ;
}
}
printf ( " \n " ) ;
}
*/
printf ( " horizontal line: \n " ) ;
printbinaryline ( ' H ' , hline , FALSE ) ;
printf ( " - %s \n " , ( hline = = allones ) ? " YES " : " " ) ;
// all 1s = yes
printf ( " vertical line: \n " ) ;
printbinaryline ( ' V ' , vline , FALSE ) ;
printf ( " - %s \n " , ( vline ) ? " YES " : " " ) ;
// all 1s = yes
}
2021-02-17 21:50:31 +11:00
void roadlog ( char * dname , int dir , int xch , int ych , int newx , int newy ) {
int newxch , newych ;
xytopos ( newx , newy , & newxch , & newych ) ;
fprintf ( stderr , " ** db: Checking %s (dir %d xm=%d,ym=%d) from %c%c (%c%c == %d,%d) \n " , dname , dir , xmod [ dir ] , ymod [ dir ] , xch , ych , newxch , newych , newx , newy ) ;
}
2021-02-16 11:56:34 +11:00
int xyvalidforroad ( char ( * b ) [ MAXBOARDSTRLEN ] , int who , int x , int y ) {
char * cell ;
cell = b [ y * w + x ] ;
if ( isvalidxy ( x , y ) & & ( getpnum ( getowner ( cell ) ) = = who ) & & ( getmod ( cell ) ! = ' | ' ) ) {
return TRUE ;
}
return FALSE ;
}
int checkxyforroad ( char ( * b ) [ MAXBOARDSTRLEN ] , int who , int sx , int sy , int sd ) {
int x , y , newx , newy , d , xch , ych , newxch , newych ;
int startxch , startych ;
int startdir , done , turncount ;
int db = 0 ;
int visited [ MAXW * MAXH ] ;
// mark everywhere as not visited
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
visited [ y * w + x ] = 0 ;
}
}
x = sx ;
y = sy ;
d = sd ;
startdir = d ;
xytopos ( x , y , & xch , & ych ) ;
startxch = xch ;
startych = ych ;
if ( db ) fprintf ( stderr , " ** db: looking for %s roads from %c%c (owned by %c / %d) \n " , getpname ( who ) , xch , ych , getowner ( b [ sy * w + sx ] ) , getpnum ( getowner ( b [ sy * w + sx ] ) ) ) ;
2021-02-17 21:50:31 +11:00
// check initial cell
if ( ! xyvalidforroad ( b , who , x , y ) ) {
if ( db ) fprintf ( stderr , " ** db: %c%c not valid for road - stopping \n " , xch , ych ) ;
return FALSE ;
}
2021-02-16 11:56:34 +11:00
if ( getpnum ( getowner ( b [ sy * w + sx ] ) ) ! = who ) {
if ( db ) fprintf ( stderr , " ** db: %s doesn't own %c%c - stopping \n " , getpname ( who ) , xch , ych ) ;
return FALSE ;
}
done = FALSE ;
turncount = 0 ;
while ( ! done ) {
int moved = FALSE ;
int leftdir , rightdir ;
// figure out where left/right is.
leftdir = ( d - 1 ) ; if ( leftdir < 0 ) leftdir = 3 ;
rightdir = ( d + 1 ) ; if ( rightdir > = 4 ) rightdir = 0 ;
2021-02-17 21:50:31 +11:00
// is there a valid cell to the left?
newx = x + xmod [ leftdir ] ;
newy = y + ymod [ leftdir ] ;
if ( db ) roadlog ( " left " , leftdir , xch , ych , newx , newy ) ;
2021-02-16 11:56:34 +11:00
if ( xyvalidforroad ( b , who , newx , newy ) ) {
x = newx ;
y = newy ;
2021-02-17 21:50:31 +11:00
d = leftdir ;
2021-02-16 11:56:34 +11:00
moved = TRUE ;
2021-02-17 21:50:31 +11:00
}
if ( ! moved ) { // forward?
newx = x + xmod [ d ] ;
newy = y + ymod [ d ] ;
2021-02-16 11:56:34 +11:00
2021-02-17 21:50:31 +11:00
if ( db ) roadlog ( " forward " , d , xch , ych , newx , newy ) ;
if ( xyvalidforroad ( b , who , newx , newy ) ) {
x = newx ;
y = newy ;
moved = TRUE ;
}
}
if ( ! moved ) { // right
newx = x + xmod [ rightdir ] ;
newy = y + ymod [ rightdir ] ;
if ( db ) roadlog ( " right " , rightdir , xch , ych , newx , newy ) ;
if ( xyvalidforroad ( b , who , newx , newy ) ) {
x = newx ;
y = newy ;
d = rightdir ;
moved = TRUE ;
}
}
if ( ! moved ) { // reverse direction
if ( - - d < 0 ) d = 3 ;
if ( - - d < 0 ) d = 3 ;
newx = x + xmod [ d ] ;
newy = y + ymod [ d ] ;
2021-02-16 11:56:34 +11:00
2021-02-17 21:50:31 +11:00
if ( db ) roadlog ( " backward " , d , xch , ych , newx , newy ) ;
2021-02-16 11:56:34 +11:00
if ( xyvalidforroad ( b , who , newx , newy ) ) {
x = newx ;
y = newy ;
moved = TRUE ;
}
}
2021-02-17 21:50:31 +11:00
if ( ! moved ) {
if ( db ) fprintf ( stderr , " ** db: Couldn't turn around - no roads. \n " ) ;
}
2021-02-16 11:56:34 +11:00
if ( moved ) {
2021-02-17 21:50:31 +11:00
xytopos ( x , y , & newxch , & newych ) ;
2021-02-16 11:56:34 +11:00
if ( db ) fprintf ( stderr , " ** db: %c%c is owned by us, moving there. \n " , newxch , newych ) ;
xch = newxch ;
ych = newych ;
turncount = 0 ;
// back to start?
if ( ( x = = sx ) & & ( y = = sy ) ) {
if ( db ) fprintf ( stderr , " ** db: We're back at the start (%c%c) - no roads. \n " , startxch , startych ) ;
done = TRUE ;
// other side?
} else if ( ( sx = = 0 ) & & ( x = = w - 1 ) ) {
if ( db ) fprintf ( stderr , " ** db: Horizontal w->e path from from %c%c to %c%c! \n " , startxch , startych , xch , ych ) ;
return TRUE ;
} else if ( ( sx = = w - 1 ) & & ( x = = 0 ) ) {
if ( db ) fprintf ( stderr , " ** db: Horizontal e->w path from from %c%c to %c%c! \n " , startxch , startych , xch , ych ) ;
return TRUE ;
} else if ( ( sy = = 0 ) & & ( y = = h - 1 ) ) {
if ( db ) fprintf ( stderr , " ** db: Vertical s->n path from from %c%c to %c%c! \n " , startxch , startych , xch , ych ) ;
return TRUE ;
} else if ( ( sy = = h - 1 ) & & ( y = = 0 ) ) {
if ( db ) fprintf ( stderr , " ** db: Vertical n->s path from from %c%c to %c%c! \n " , startxch , startych , xch , ych ) ;
return TRUE ;
}
} else {
// didn't move?
done = TRUE ;
}
}
if ( db ) fprintf ( stderr , " ** db: No roads found. Returning false. \n " ) ;
return FALSE ;
}
int playerhasroads ( int pnum , char ( * b ) [ ] ) {
int x , y ;
// check for roads from bottom to top
for ( x = 0 ; x < w ; x + + ) {
if ( checkxyforroad ( b , pnum , x , 0 , NORTH ) ) return TRUE ;
}
// check for roads from left to right
for ( y = h - 1 ; y > = 0 ; y - - ) {
if ( checkxyforroad ( b , pnum , 0 , y , EAST ) ) return TRUE ;
}
return FALSE ;
}
void printbinaryline ( char prefix , int num , int wantcr ) {
int x ;
// show line number
printf ( " %c - " , prefix ) ;
// show line
for ( x = 0 ; x < w ; x + + ) {
if ( num & ( 1 < < xtoleftshift ( x ) ) ) {
printf ( " %d " , 1 ) ;
} else {
printf ( " %d " , 0 ) ;
}
}
if ( wantcr ) printf ( " \n " ) ;
}
void line ( void ) {
int x ;
for ( x = 0 ; x < w ; x + + ) {
printf ( " %s " , LINEPART ) ;
}
printf ( " \n " ) ;
}
int gotwinner ( void ) {
if ( winner > = 0 ) {
return TRUE ;
}
return FALSE ;
}
2021-02-17 21:50:31 +11:00
void determinefinalwinner ( void ) {
if ( gamepoints [ 0 ] > gamepoints [ 1 ] ) {
winner = 0 ;
} else if ( gamepoints [ 1 ] > gamepoints [ 0 ] ) {
winner = 1 ;
} else {
winner = - 1 ;
}
if ( winner = = - 1 ) {
} else {
printf ( " %s** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **%s \n " , getpcol ( winner ) , reset ) ;
printf ( " %s ***** %s%s%s is the victor! %s*****%s \n " ,
getpcol ( winner ) , BOLD , getpname ( winner ) , reset ,
getpcol ( winner ) , reset ) ;
printf ( " %s** ** ** ** ** ** ** ** ** ** ** ** ** ** ** ** **%s \n " , getpcol ( winner ) , reset ) ;
}
// show totals
showscores ( " Final " ) ;
// TODO: bold this
printf ( " \n %s--- Press ENTER to end ---%s \n " , BOLD , reset ) ;
// wait for key
fgets ( cmdbuf , MAX_CMD_LEN , stdin ) ;
}
2021-02-16 11:56:34 +11:00
void determinewinner ( void ) {
int x , y , i ;
int flatstones [ MAXPLAYERS ] ;
int stonepoints , sizepoints ;
// win by roads?
if ( ! gotwinner ( ) ) {
if ( hasroad [ 0 ] & & hasroad [ 1 ] ) {
// current turn wins a tie
winner = turn ;
} else if ( hasroad [ 0 ] ) {
winner = 0 ;
} else if ( hasroad [ 1 ] ) {
winner = 1 ;
}
}
if ( ! gotwinner ( ) ) {
// count flatstones
for ( y = 0 ; y < h ; y + + ) {
for ( x = 0 ; x < w ; x + + ) {
if ( ! getmod ( board [ y * w + x ] ) ) {
flatstones [ getpnum ( getowner ( board [ y * w + x ] ) ) ] + + ;
}
}
}
if ( flatstones [ 0 ] > flatstones [ 1 ] ) {
winner = 0 ;
} else if ( flatstones [ 0 ] < flatstones [ 1 ] ) {
winner = 0 ;
} else {
// current turn wins a tie
winner = turn ;
}
}
if ( ! gotwinner ( ) ) {
// shouldn't be possible...
winner = turn ;
}
// only winner gets points
// 1 point for every board square (size*size)
// 1 point for each of their remaining tiles
sizepoints = ( size * size ) ;
stonepoints = tilesleft [ winner ] ;
roundpoints [ winner ] = sizepoints + stonepoints ;
printf ( " %s*** %s%s%s%s%s wins round %d and earns %d points (%d from board size, %d from remaining tiles)%s \n " , BOLD , getpcol ( winner ) , BOLD , getpname ( winner ) , reset , BOLD , curround ,
roundpoints [ winner ] , sizepoints , stonepoints , reset ) ;
// update totals
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
gamepoints [ i ] + = roundpoints [ i ] ;
}
// show totals
2021-02-17 21:50:31 +11:00
showscores ( " Current " ) ;
2021-02-16 11:56:34 +11:00
// TODO: bold this
printf ( " \n %s--- Press ENTER for next round ---%s \n " , BOLD , reset ) ;
// wait for key
fgets ( cmdbuf , MAX_CMD_LEN , stdin ) ;
}
2021-02-17 21:50:31 +11:00
void showscores ( char * str ) {
2021-02-16 11:56:34 +11:00
int i ;
char temp [ 64 ] ;
2021-02-17 21:50:31 +11:00
printf ( " %s scores: \n " , str ) ;
2021-02-16 11:56:34 +11:00
for ( i = 0 ; i < MAXPLAYERS ; i + + ) {
sprintf ( temp , " %s%12s%s " , getpcol ( i ) , getpname ( i ) , reset ) ;
printf ( " %s: %s%d points%s \n " , temp , getpcol ( i ) , gamepoints [ i ] , reset ) ;
}
}
void pickfirstplayer ( ) {
if ( rand ( ) % 2 = = 0 ) firstturn = 0 ; else firstturn = 1 ;
}
int normalise ( char * a ) {
int donesomething = FALSE ;
if ( ! a ) return FALSE ;
switch ( * a ) {
case ' ^ ' :
case ' k ' :
* a = ' C ' ; donesomething = TRUE ; break ;
case ' s ' :
case ' | ' :
* a = ' S ' ; donesomething = TRUE ; break ;
}
return donesomething ;
}
void logmove ( int who , char * txt , char append ) {
char temp [ 256 ] ;
char * p ;
// use standard notation as per https://ustak.org/portable-tak-notation/
strcpy ( temp , txt ) ;
for ( p = temp ; * p ; p + + ) {
normalise ( p ) ;
}
if ( ( append = = ' S ' ) | | ( append = = ' C ' ) ) {
strncat ( temp , & append , 1 ) ;
}
if ( flattened ) {
strcat ( temp , " * " ) ;
}
2021-02-17 21:50:31 +11:00
if ( tak [ who ] ) {
strcat ( temp , " ' " ) ;
}
2021-02-16 11:56:34 +11:00
// first player's turn?
if ( who = = firstturn ) {
sprintf ( movelog , " %s " , temp ) ;
2021-02-17 21:50:31 +11:00
printf ( " %s%s%d.%s%s %s ...%s \n " , YELLOW , BOLD , turnnumber , reset , YELLOW , movelog , reset ) ;
2021-02-16 11:56:34 +11:00
} else {
strcat ( movelog , " " ) ;
strcat ( movelog , temp ) ;
printf ( " %s%s%d.%s%s %s%s \n " , YELLOW , BOLD , turnnumber , reset , YELLOW , movelog , reset ) ;
}
}
int main ( int argc , char * argv [ ] ) {
init ( ) ;
atexit ( cleanup ) ;
if ( setupgame ( 5 , 2 ) ) {
exit ( 1 ) ;
}
srand ( time ( NULL ) ) ;
pickfirstplayer ( ) ; // randomize 'firstturn'
while ( curround < = numrounds ) {
setupround ( ) ;
while ( ! gameover ) {
showboard ( ) ;
for ( readcmd ( cmdbuf ) ; parsecmd ( cmdbuf ) ; readcmd ( cmdbuf ) ) ;
updateroadstatus ( ) ;
if ( checkendgame ( ) ) {
showboard ( ) ;
determinewinner ( ) ;
gameover = 1 ;
}
nextturn ( ) ;
}
nextround ( ) ;
}
2021-02-17 21:50:31 +11:00
determinefinalwinner ( ) ;
2021-02-16 11:56:34 +11:00
}