home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- T7G microscope program using recursive minimax method
- with alpha-beta pruning. Move getmoves function inside/inline
- of find/eval moves. Add "stability" factor to scoring.
- A square is considered stable when it is completely surrounded by other
- pieces.
- Overall scoring.
- GREEN WIN = -1000... > 0=tie > ...1000 = BLUE WIN
- Score = 2*(#blue - #green) + (#blue stable - #green stable)
- */
-
- #include "protos.h"
-
- char dummy[80];
- extern unsigned _stklen=0x9000u; //0xffe0u; // extra stack
- char far Gmaxlevel = 0; // search depth
- unsigned long far Gmovecount;
- unsigned long far Gmovesanalyzed;
- Tmovelist far Gbestmoves;
- int Gcountmovelist=0;
- TWindow2 far *window2;
- TWindow1 far *window1;
- char endgame = FALSE;
-
- // ******** MAIN *********
- void main(void){
-
- Tcurrent far *game,*lastgame;
- Tmovelist far *movelist;
- Tmovelist yourmove;
- clock_t first, second;
- int bestscore;
-
- init_stack_count();
- game=allocTboard();
- lastgame=allocTboard();
-
- window2=(TWindow2 *) farmalloc(sizeof(TWindow2));
- if(window2==NULL) abort();
- window1=(TWindow1 *)farmalloc(sizeof(TWindow1));
- if(window1==NULL) abort();
- initwindow1(); // must call before initwindow2()
- initwindow2();
- initboard(game);
-
-
- while(Gmaxlevel<1 || Gmaxlevel>8)
- {
- puts("Enter maximum level");
- scanf("%d",&Gmaxlevel);
- }
- *lastgame=*game;
- printboard(game);
- yourmove = getmove(game);
- makemove(game,&yourmove);
-
- while(TRUE) // Loop until end of game
- {
- printboard(game);
- yourmove = getmove(game);
- if(yourmove.from == -1) {*game=*lastgame; continue;}
- *lastgame = *game;
- makemove(game,&yourmove);
- printboard(game);
- Gmovesanalyzed = Gmovecount=0;
- bestscore = 999;
- if( (49-game->counttotal)<=3 && endgame==FALSE)
- {
- endgame = TRUE;
- Gmaxlevel +=2;
- }
- _setcursortype(_NOCURSOR);
- first = clock();
- movelist = findmoves(game,Gmaxlevel,&bestscore);
- second = clock();
- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
- if(movelist != NULL)
- {
- printf("Level %d: %lu total moves,%lu analyzed. Score= %+d Time= %f\n",
- Gmaxlevel,
- Gmovecount,
- Gmovesanalyzed,
- bestscore,
- (second-first)/CLK_TCK);
- printf("Thinking: ");
- printmovelist(movelist);
- printf("\n");
- }
- makemove(game,movelist);
- printf("Current Score: Blue= %d, Green= %d, Net= %+d, Stability= %d\n",
- game->countblue, game->counttotal-game->countblue,
- 2*game->countblue-game->counttotal, getboardscore(game));
- _setcursortype(_NORMALCURSOR);
- if(movelist == NULL) {
- puts("*** GAME OVER ***");
- exit(0);
- }
- freelist(movelist);
- }
- }
-
- //******** FINDMOVES ********
- Tmovelist* findmoves(Tcurrent far *a,char level,int far *bestscore)
- // IN:bestscore = opponents bestscore so for this branch
- // OUT:bestscore = this colors new bestscore for this branch
- {
- Tcurrent *current_board;
- Tmovelist *bestmove;
- Tmovelist *current_move;
- Tmovelist *reply;
- Tsquare color;
- int opponent_score;
- int current_score;
- char j,k;
- char moveto,movefrom;
- char rowfrom, colfrom,rowto,colto;
- char anymove;
- char exists[49];
-
- if(level==0) // Analyze and return the final score
- {
- *bestscore = getboardscore(a);
- *bestscore += PIECEWEIGHT*(2*a->countblue- a->counttotal);
- Gmovesanalyzed++;
- return NULL;
- }
-
- color = a->color;
- bestmove = allocmovelist();
- current_move = allocmovelist();
- anymove = FALSE;
-
- // Set the opponents score to beat
- // +-999 insures leftmost branch is always analyzed
- if(color==BLUESQ) current_score = opponent_score = -999;
- else current_score = opponent_score = 999;
-
- current_board=(Tcurrent *) farmalloc(sizeof(Tcurrent));
- if(current_board==NULL) abort();
-
- *current_board = *a; // set current_board
-
- // Get all moves
- for(k=0;k<49;k++) exists[k]=0;
- for(k=0;k<49;k++)
- {
- // if square contains color to be moved
- if(a->board.b[k] == color)
- {
- rowfrom = k/7; colfrom = k%7;
- for(j=1;j<=window2->a[k][0];j++)
- {
- if(a->board.b[ window2->a[k][j] ] == EMPTYSQ)
- { // found possible move
- rowto = window2->a[k][j]/7; colto = window2->a[k][j]%7;
- movefrom = k;
- moveto = window2->a[k][j];
- // Is move a jump?
- if(abs(rowto-rowfrom)<=1 && abs(colto-colfrom)<=1)
- {
- // move is not a jump ; search for duplicate
- if(exists[moveto]==1) continue;
- exists[moveto]=1;
- current_move->jump = FALSE;
- }
- else current_move->jump = TRUE;
- // store current_move
- Gmovecount++;
- anymove = TRUE;
- current_move->next = NULL;
- current_move->to = moveto;
- current_move->from = movefrom;
-
- makemove(current_board,current_move);
- reply = findmoves(current_board,level-1,&opponent_score);
- *current_board =*a; // restore current board
- if(level == Gmaxlevel)
- {
- printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
- printf("Best=%d ",current_score);
- if(abs(current_score)!=999)
- printmove(bestmove);
- printf(" Current=%d ",opponent_score);
- printmove(current_move);
- printf(" ");
- }
- if(color==BLUESQ && opponent_score>current_score)
- {
- current_score = opponent_score; // update best score so far
- freelist(bestmove->next); // free old reply
- *bestmove = *current_move; // store new best move
- bestmove->next = reply; // store new reply
- if(opponent_score>=*bestscore)
- goto nextstep; // dont bother evaluating rest of moves!
- }
- else if(color==GREENSQ && opponent_score<current_score)
- {
- current_score = opponent_score;
- freelist(bestmove->next);
- *bestmove = *current_move;
- bestmove->next = reply;
- if(opponent_score<=*bestscore)
- goto nextstep; // dont bother evaluating rest of moves!
- }
- else freelist(reply); // free bad reply
-
- opponent_score = current_score; // reset "best score" sent to next search
- } //endif possible move
- } //end for(j=startcol...
- } // end if square contains color to be moved
- } //end get all moves (for k)
-
- // If no moves (movelist == NULL) return win/loss
- if(anymove==FALSE)
- {
- // Set score equal to the absolute count...no stability factor
- current_score = PIECEWEIGHT*(2*a->countblue - a->counttotal);
- //if any empty squares on board
- if(emptysquare(a)==TRUE)
- {
- if(color==BLUESQ) current_score = -1000; //NO MOVE:BLUE LOSS
- }
- else
- {
- if(color==BLUESQ)
- {
- if(current_score>0) current_score = 1000; //BLUE WIN
- else current_score = -1000; //BLUE LOSS
- }
- else
- // Figure for GREEN
- {
- if(current_score<0) current_score = -1000; //GREEN WIN
- else current_score = 1000; //GREEN LOSS
- }
- }
- Gmovesanalyzed++;
- freelist(bestmove);
- bestmove = NULL;
- }
-
- nextstep: // label for alpha/beta pruning jump
- ;
-
- freelist(current_move); // free movelist
- *bestscore = current_score; // return bestscore found
- farfree(current_board); // free current_board
- return bestmove; // return bestmove
- }
-
-
- // Makemove and return resulting board
- void makemove(Tcurrent *a,Tmovelist *movelist)
- {
- Tsquare opponent;
- Tsquare color=a->color;
- char countflipped=0;
- char row;
- if(movelist==NULL) return;
- //Set opponent color
- if(color == BLUESQ) opponent=GREENSQ;
- else opponent=BLUESQ;
-
- // Move piece into new square
- a->board.b[movelist->to] = color;
-
- if(movelist->jump == TRUE) a->board.b[movelist->from] = EMPTYSQ;
- else a->counttotal++; // move is not a jump add one to total pieces
-
- // Flip opponents pieces
- for(row=1;row<=window1->a[movelist->to][0];row++)
- if(a->board.b[window1->a[movelist->to][row]] == opponent)
- {
- a->board.b[window1->a[movelist->to][row]] = color;
- countflipped++;
- }
-
- // calculate score
- if(color == BLUESQ)
- {
- a->countblue += countflipped;
- if(movelist->jump==FALSE) a->countblue++;
- }
- else a->countblue -= countflipped;
- a->color = opponent; // set turn to opponent
- return;
- }
-
- int getboardscore(Tcurrent *a)
- // return net "stability" score
- // number stable blue minus stable green
- {
- char stable;
- char i,j;
- int score = 0;
- Tsquare square;
-
- for(i=0;i<49;i++)
- {
- // if square contains color
- square = a->board.b[i];
- if(square == EMPTYSQ)
- continue;
- else
- {
- // is square stable?
- for(stable=TRUE,j=1; j<=window1->a[i][0]; j++)
- {
- if(a->board.b[window1->a[i][j]] == EMPTYSQ)
- {
- stable = FALSE;
- break;
- }
- }
- if(stable == FALSE) continue;
- }
- if(square == BLUESQ)
- score++;
- else
- score--;
- }
- return score;
- }
-
- void printmovelist(Tmovelist *movelist) // print entire move list
- {
- if (movelist==NULL) return;
- if(movelist->jump == TRUE)
- printf("%c%d-",
- 'A'+(movelist->from / (MAXROW+1)),
- (movelist->from % (MAXROW+1))+1);
- printf("%c%d ",
- 'A'+ (movelist->to / (MAXROW+1)),
- (movelist->to % (MAXROW+1))+1);
- printmovelist(movelist->next);
- }
-
- void printmove(Tmovelist *movelist) // print only first move in list
- {
- if(movelist == NULL) return;
- if(movelist->jump == TRUE)
- printf("%c%d-",
- 'A'+(movelist->from / (MAXROW+1)),
- (movelist->from % (MAXROW+1))+1);
- printf("%c%d ",
- 'A'+ (movelist->to / (MAXROW+1)),
- (movelist->to % (MAXROW+1))+1);
- }
-
- Tmovelist getmove(Tcurrent* a) // Get a move from the keyboard
- {
- Tmovelist move;
- char legal=FALSE;
-
- move.next = NULL;
- while(legal==FALSE)
- {
- puts("From? (RowCol) TB for takeback");
- move.from = getsquare();
- if(move.from == -1) return move;
- puts("To?");
- move.to = getsquare();
- if((a->board.board[move.from/7][move.from %7] == a->color)
- &&
- (a->board.board[move.to/7][move.to %7] == EMPTYSQ) )
- legal = TRUE;
- }
- if(abs(move.from/7 - move.to/7) == 2 || abs(move.to%7 - move.from%7) == 2)
- move.jump = TRUE;
- else move.jump = FALSE;
- return move;
- }
-
- char getsquare(void)
- {
- char input[80];
- char row = -1;
- char col = -1;
- while((row<MINROW || row>MAXROW) && (col<MINCOL || col>MAXCOL))
- {
- gets(input);
- row = toupper(input[0])-'A';
- col = toupper(input[1]) - '1';
- if(row==19 && col==17) return -1;
- }
- return row*(MAXROW+1)+col;
- }
-
- void initboard(Tcurrent *a)
- // Initialize board for start of game
- {
- int row,col;
- for(row=MINROW;row<=MAXROW;row++)
- for(col=MINCOL;col<=MAXCOL;col++)
- {
- a->board.board[row][col] = EMPTYSQ;
- }
- a->board.board[MINROW][MINCOL] = BLUESQ;
- a->board.board[MINROW][MAXCOL] = GREENSQ;
- a->board.board[MAXROW][MINCOL] = GREENSQ;
- a->board.board[MAXROW][MAXCOL] = BLUESQ;
- a->countblue = 2;
- a->counttotal = 4;
- a->color = BLUESQ;
- }
-
- void printboard(Tcurrent *a)
- {
- int i,j;
- printf(" 1 2 3 4 5 6 7\n");
- printf(" * * * * * * *\n");
- for(i=MINROW;i<=MAXROW;i++)
- {
- printf(" %c* ",'A'+i);
- for(j=MINCOL;j<=MAXCOL;j++)
- {
- switch(a->board.board[i][j])
- {
- case (EMPTYSQ):
- printf(" ");
- break;
- case (GREENSQ):
- printf("G ");
- break;
- case (BLUESQ) :
- printf("B ");
- break;
- default :
- printf("? ");
- }
- }
- printf("*\n");
- }
- printf(" * * * * * * *\n");
- }
-
- char emptysquare(Tcurrent *a)
- // Check for any empty square on the board
- {
- char i;
-
- for(i=0;i<49;i++) if(a->board.b[i] == EMPTYSQ) return TRUE;
- return FALSE;
- }
-
- void initwindow1(void) // precompute 1 square "windows"
- {
- char i,j,k,count,row,col,index;
- char startrow,endrow,startcol,endcol;
-
- count=0;
- for(k=0;k<49;k++)
- {
- // determine limits of search
- row = k/7; col=k%7;
- startrow = row - 1;
- if(startrow<MINROW) startrow = MINROW;
- endrow = row + 1;
- if(endrow>MAXROW) endrow = MAXROW;
- startcol = col - 1;
- if(startcol<MINCOL) startcol = MINCOL;
- endcol = col + 1;
- if(endcol>MAXCOL) endcol = MAXCOL;
-
- // search for empty squares
-
- for(i=startrow;i<=endrow;i++)
- for(j=startcol;j<=endcol;j++)
- {
- index = 7*i+j;
- if(index!=k)
- {
- count++;
- if(k<0 || k>49 || count<0 || count>8) abort();
- window1->a[k][count] = index;
- }
- }
- if(k<0 || k>49) abort();
- window1->a[k][0] = count;
- count=0;
- }
- }
-
- void initwindow2(void) // precompute 2 square "windows"
- {
- char i,j,k,count,row,col,index;
- char startrow,endrow,startcol,endcol;
-
- count=0;
- for(k=0;k<49;k++)
- {
- // determine limits of search
- row = k/7; col=k%7;
- startrow = row - 2;
- if(startrow<MINROW) startrow = MINROW;
- endrow = row + 2;
- if(endrow>MAXROW) endrow = MAXROW;
- startcol = col - 2;
- if(startcol<MINCOL) startcol = MINCOL;
- endcol = col + 2;
- if(endcol>MAXCOL) endcol = MAXCOL;
- count = window1->a[k][0];
- // load all squares next to this square first
- for(i=1;i<=count;i++) window2->a[k][i] = window1->a[k][i];
- // search for empty squares
- for(i=startrow;i<=endrow;i++)
- for(j=startcol;j<=endcol;j++)
- {
- // Eliminate adjacent squares (we already have them)
- if(abs(i-row)<=1 && abs(j-col)<=1) continue;
- index = 7*i+j;
- if(index!=k)
- {
- count++;
- if(k<0 || k>49 || count<0 || count>25) abort();
- window2->a[k][count] = index;
- }
- }
- if(k<0 || k>49) abort();
- window2->a[k][0] = count;
- }
- }
-
- Tmovelist *allocmovelist(void)
- {
- Tmovelist *newmovelist;
-
- newmovelist = (Tmovelist *) farmalloc(sizeof(Tmovelist));
- if (newmovelist==NULL) abort();
- newmovelist->next=NULL;
- newmovelist->jump = FALSE;
- return newmovelist;
- }
-
- Tcurrent *allocTboard(void)
- {
- Tcurrent *newTboard;
-
- newTboard = (Tcurrent *) farmalloc(sizeof(Tcurrent));
- if (newTboard==NULL) abort();
- return newTboard;
- }
-
- void freeTboard(Tcurrent *aboard)
- {
- farfree(aboard);
- aboard = NULL;
- }
-
- void freelist(Tmovelist* movelist)
- {
- if(movelist == NULL) return;
- freelist(movelist->next);
- movelist->next=NULL;
- farfree(movelist);
- }
-
- #define SIZE_OF_EMULATOR 415 // Account for floating
- // point emulator
- #define FILL_CHAR 0xFF // Character used to mark
- // the stack
-
- #pragma warn -aus // Turn off unecessary
- #pragma warn -use // warnings
-
- /*
- / ************************************************************* \
- | Marks all possible stack space not currently in use by |
- | setting the values to 0xff. |
- \ ************************************************************* / */
- void init_stack_count(void)
- {
- char far *sp; // far memory model stack
- // pointer
- //char near *nsp; // near memory model stack
- // pointer
- extern unsigned __brklvl; // Internal variable marking
- // top of
- // the near heap.
-
- #if defined(__COMPACT__) || \
- defined(__LARGE__) || \
- defined(__HUGE__)
- #undef _HEAP_
-
- sp = MK_FP( _SS, _SP - 1 ); // initialize sp to point to
- // the next available space on
- // the stack.
-
- while( sp > (char far *)SIZE_OF_EMULATOR ) //Check
- // for stack overflow
- {
- *sp = FILL_CHAR; // Initialize unused stack
- // space
- sp--;
- }
- #else // similar for near data
- // memory model
- nsp = (char *) _SP - 1; // Initialize pointer
- while( nsp > (char *)__brklvl)// Check for stack overflow
- {
- *nsp = FILL_CHAR; // Assign fill character
- nsp--; // advance pointer
- }
- #endif
- return;
- }
- /*
- / ************************************************************* \
- | Goes though stack space counting unused (unmodified) |
- | values meaning that space on the stack was not used. |
- \ ************************************************************* / */
- void stack_count( void )
- {
- unsigned count= 0; // Amount of unused stack
- // space
- //unsigned mcount = 0; // Amount of used Heap space
- char far *sp; // Far memory model pointer
- //char *nsp; // Near memory model pointer
-
-
- #if defined(__COMPACT__) || \
- defined(__LARGE__) || \
- defined(__HUGE__)
-
- sp = MK_FP( _SS, SIZE_OF_EMULATOR+1); // Initialize the
- // pointer
- if( _SP > SIZE_OF_EMULATOR ) // Check for stack
- // overflow
- {
- while( sp < MK_FP(_SS,_SP) ) // Check for stack
- // overflow
- {
- if( *sp != (char) FILL_CHAR ) // compare pointer
- //value to
- // fill character
- break;
- count++; // count unused
- // stack space
- sp++; // increment pointer
- }
- }
- #else
- extern unsigned __brklvl; // End of near heap
- extern unsigned __heapbase; // Beginning of near heap
- if( _SP > __brklvl ) // Check for stack
- // overflow
- {
- nsp = (char *) __brklvl + 1;
- while( nsp < (char *)_SP ) // While we don't run
- // into the
- // current stack.
- {
- if( *nsp != (char) FILL_CHAR && count < 3)
- // Count near heap used
- mcount++;
- // else count unused
- 9 // stack
- else if( *(nsp + 1) == (char)FILL_CHAR &&
- *(nsp + 2) == (char) FILL_CHAR )
- count++; // Count unused bytes
- nsp++;
- }
- }
- count += 2;
- #endif
-
-
- #ifdef _HEAP_ // print amount of used
- // stack
- printf("\nHeap Used = %u bytes", (__brklvl - __heapbase +
- mcount));
- #endif // print amount of unused
- // stack
- printf("\nStack not used = %u bytes" , count);
- return;
- }
-
- void heapchk(void){
- stack_count();
- printf("coreleft=%lu \n",farcoreleft());
- printf("Movelists allocated = %d, %d bytes\n",Gcountmovelist,Gcountmovelist*sizeof(Tmovelist));
- if( heapcheck() == _HEAPCORRUPT )
- {
- printf( " **** Heap is corrupted. ****\n" );
- abort();
- }
- else
- printf( "Heap is OK.\n" );
- getch();
- }
-