int main( int argc, char *argv[] ) { printf( "have %i args\n", argc ); printf( "first arg: %s\n", argv[0] ); PuzzleState ps; PiecesLeft pl; if( argc == 2 ) { LoadState( ps, pl, argv[1] ); sprintf( solutionfilename, "SOLVED_%s", argv[1] ); printf( "Solving\n"); PrintRemainingPieces( pl ); Solve( pl, ps ); printf( "Unsolvable?\n"); } else { Piece e = pieces[4]; for( int ori = 0; ori < 8; ++ori ) { printf( "Piece rotated %i\n", ori ); PrintPiece( Rot( e, ori ) ); printf( "\n" ); } } }
/* Evaluate the current board position for the side stored in the board * structure. Score for white. (Score for black = -1* this.) We also pass the values * of alpha and beta to this routine on the expectation that we might be able to get a * cutoff if the score is particularly high or low without having to do the time consuming * part of the eval(). */ int EvalMain(Board *B, int alpha, int beta) { int sq,p,npw=0,tpts=B->WPts+B->BPts,sq2,def, score=0; int *SpDef, *SpWon, lazyscore; BITBOARD pieces = B->All; BOOL one_sided; #ifdef DEBUG_EVAL int control = 0, oldscore = 0, contestcount = 0; #endif /* Check for a drawn position */ if (IsDrawnMaterial(B)) return ((Current_Board.side == WHITE) ? (DRAW_SCORE) : -(DRAW_SCORE)); /* Check if the game is theoretically won/lost */ score = IsWonGame(B); #ifdef DEBUG_EVAL if (score != 0) fprintf(stdout,"\nPosition Theoretically Won : %d\n\n",score); #endif /* Check to see if we can just cutoff here - this score is so good that * we needn't bother working it out exactly - it's going to cause a cutoff. * We have to be very careful because the score difference gained by doing * a proper eval here might be huge, therefore we only cutoff if this * position is theoretically won, and beta isn't, or it is theoretically * lost and alpha isn't. We can't just use standard futility cutoffs like * we do below, because in theoretically won positions, the score returned * by LazyEval() will almost always be much larger than EVAL_FUTILITY. */ if (USE_EVAL_SC && score!=0 && ((score > 0 && beta<T_WIN_BOUND) || (score < 0 && alpha>-(T_WIN_BOUND)))) { EvalCuts++; #ifdef DEBUG_EVAL fprintf(stdout,"Early Cut [1] %d (A=%d,B=%d)\n",score,alpha,beta); #endif return score; } /* Get a lazy score evaluation * (material score & simple positional terms plus passed pawns) */ lazyscore = LazyEval(B) + score; /* Check to see if we can just cutoff here. The expectation is that the LazyEval * is alway within EVAL_FUTILITY of the true score. Of course this isn't always * true, but we hope that it is true most of the time. */ if (USE_EVAL_SC && (lazyscore > (beta+EVAL_FUTILITY) || lazyscore < (alpha-EVAL_FUTILITY))) { EvalCuts++; #ifdef DEBUG_EVAL fprintf(stdout,"Early Cut [2] %d (A=%d,B=%d)\n",lazyscore,alpha,beta); #endif return lazyscore; } /* We didn't get a cutoff so we have to be more careful and evaluate the board properly. * Begin with the LazyEval() score we obtained BEFORE any possible truncation due to lack * of mating material (we don't want to do this twice!). */ score += prematscore; #ifdef DEBUG_EVAL fprintf(stdout,"\nFull Eval\n---------\n"); #endif /* Generate arrays storing how many times each side attacks each square on the board. * This takes quite some time, but it is worth the effort! */ GenerateAttacks(B); /* Now loop through all the pieces on the board and sum their contributions. * Also include the contributions of the empty spaces, measuring board * domination and territorial control. * There is the specialised version for the endgame below. */ if (B->Gamestage < Endgame) { /* Work out how much square possession is worth */ SpWon = SpaceWon[B->Gamestage]; SpDef = SpaceDefended[B->Gamestage]; /* Loop through the board */ for (sq=0;sq<64;sq++) { p = B->pieces[sq]; #ifdef DEBUG_EVAL fprintf(stdout,"Square %c%d [",File(sq)+97,8-Rank(sq)); PrintPiece(p); fprintf(stdout,"] : "); #endif switch(p) { /* White Piece */ case (wpawn) : score += TactPawn(sq,B,WHITE); npw += SquareColour[sq]; break; case (wrook) : score += TactRook(sq,B,WHITE); break; case (wknight): score += TactKnight(sq,B,WHITE); break; case (wbishop): score += TactBishop(sq,B,WHITE); break; case (wqueen) : score += TactQueen(sq,B,WHITE); break; case (wking) : score += TactKing(sq,B,WHITE); break; /* Black Piece */ case (bpawn) : score -= TactPawn(sq,B,BLACK); npw += SquareColour[sq]; break; case (brook) : score -= TactRook(sq,B,BLACK); break; case (bknight): score -= TactKnight(sq,B,BLACK); break; case (bbishop): score -= TactBishop(sq,B,BLACK); break; case (bqueen) : score -= TactQueen(sq,B,BLACK); break; case (bking) : score -= TactKing(sq,B,BLACK); break; /* Empty square - reward for possession by one side */ case (empty) : sq2=ConvertSq[sq]; #ifdef DEBUG_EVAL oldscore = score; #endif /* If only one side is attacking a square, then it is won * by that side. Otherwise it can only be defended. */ one_sided = (!(B->WAttacks[sq2]) || !(B->BAttacks[sq2])); def = B->WAttacks[sq2] - B->BAttacks[sq2]; if (one_sided) { if (def>0) score += SpWon[sq]; else if (def<0) score -= SpWon[Flip[sq]]; } else { /* We have no clear winner, so evaluate the ownership of the square (slow!!) */ def = EvaluateOwnership(B,sq); if (def > 0) score += SpDef[sq]; else if (def < 0) score -= SpDef[Flip[sq]]; #ifdef DEBUG_EVAL contestcount++; #endif } #ifdef DEBUG_EVAL control += score-oldscore; fprintf(stdout,"%d", score-oldscore); #endif break; } #ifdef DEBUG_EVAL fprintf(stdout,"\n"); #endif } } /* If we're in the endgame then use this simpler version */ else { /* Loop through the pieces */ while (pieces) { sq = FirstPiece(pieces); p = B->pieces[sq]; #ifdef DEBUG_EVAL fprintf(stdout,"Square %c%d [",File(sq)+97,8-Rank(sq)); PrintPiece(p); fprintf(stdout,"] : "); #endif switch(p) { /* White Piece */ case (wpawn) : score += TactPawn(sq,B,WHITE); break; case (wrook) : score += TactRook(sq,B,WHITE); break; case (wknight): score += TactKnight(sq,B,WHITE); break; case (wbishop): score += TactBishop(sq,B,WHITE); break; case (wqueen) : score += TactQueen(sq,B,WHITE); break; case (wking) : score += TactKing(sq,B,WHITE); break; /* Black Piece */ case (bpawn) : score -= TactPawn(sq,B,BLACK); break; case (brook) : score -= TactRook(sq,B,BLACK); break; case (bknight): score -= TactKnight(sq,B,BLACK); break; case (bbishop): score -= TactBishop(sq,B,BLACK); break; case (bqueen) : score -= TactQueen(sq,B,BLACK); break; case (bking) : score -= TactKing(sq,B,BLACK); break; } RemoveFirst(pieces); #ifdef DEBUG_EVAL fprintf(stdout,"\n"); #endif } } #ifdef DEBUG_EVAL fprintf(stdout,"After Piece Tactics : %d\n",score); fprintf(stdout,"Control Balance = %d\n",control); fprintf(stdout,"Contested Empty Squares : %d\n\n",contestcount); #endif /* Add on general positional score */ if (B->Gamestage <= Middle) score += TacticsPositional(B); /* -- General score modifiers -- */ /* Modifiers for pawns blocking bishops. Your pawns should be on different squares to your * own bishops, but the same as your opponent's */ /* White Bishops */ if (B->WhiteBishops) { /* Only black square bishops */ if (!(B->WhiteBishops & WhiteMask)) score += npw*PAWN_BLOCK; /* Only white square bishops */ else if (!(B->WhiteBishops & BlackMask)) score -= npw*PAWN_BLOCK; /* Bonus for having two bishops (or more) on opposite colours */ else score += TWO_BISHOPS; #ifdef DEBUG_EVAL if (npw!=0) { if (!(B->WhiteBishops & WhiteMask)) fprintf(stdout,"White has only black square bishops : Pawn Block = %d\n",-npw*PAWN_BLOCK); else if (!(B->WhiteBishops & BlackMask)) fprintf(stdout,"White has only white square bishops : Pawn Block = %d\n",npw*PAWN_BLOCK); } if ((B->WhiteBishops & WhiteMask) && (B->WhiteBishops & BlackMask)) fprintf(stdout,"White has a bishop pair [+%d]\n",TWO_BISHOPS); #endif } /* Black Bishops */ if (B->BlackBishops) { /* Only black square bishops */ if (!(B->BlackBishops & WhiteMask)) score -= npw*PAWN_BLOCK; /* Only white square bishops */ else if (!(B->BlackBishops & BlackMask)) score += npw*PAWN_BLOCK; /* Penalty for opponent having two bishops (or more) on opposite colours */ else score -= TWO_BISHOPS; #ifdef DEBUG_EVAL if (npw!=0) { if (!(B->BlackBishops & WhiteMask)) fprintf(stdout,"Black has only black square bishops : Pawn Block = %d\n",npw*PAWN_BLOCK); else if (!(B->BlackBishops & BlackMask)) fprintf(stdout,"Black has only white square bishops : Pawn Block = %d\n",-npw*PAWN_BLOCK); } if ((B->BlackBishops & WhiteMask) && (B->BlackBishops & BlackMask)) fprintf(stdout,"Black has a bishop pair [-%d]\n",TWO_BISHOPS); #endif } /* Penalty for having no pawns */ if (!B->WhitePawns) score -= NO_PAWNS; if (!B->BlackPawns) score += NO_PAWNS; /* If there is no mating material for one side then the score cannot favour that side * (Note - we calculated this in the LazyEval and retained the results) */ if (!wmat) score = min(0,score); if (!bmat) score = max(0,score); #ifdef DEBUG_EVAL if (!wmat) fprintf(stdout,"No mating material for white\n"); if (!bmat) fprintf(stdout,"No mating material for black\n"); #endif #ifdef DRAWISH_ENDINGS /* Test for a 'drawish' ending, and reduce the score if so */ if (Drawish(B)) score = (score * (50+tpts)) / 100; #ifdef DEBUG_EVAL if (Drawish(B)) fprintf(stdout,"Drawish Position (score reduced)\n"); #endif #endif #ifdef DEBUG_EVAL fprintf(stdout,"Final Score : %d [Delta %d]\n",score,score-lazyscore); #endif // Return score, possibly altered by the skill level if (Skill == 10) return score; return score + Random(((10-Skill) * 4) + 1) + 2 * Skill - 20; }