gnome-chess/tests/test-chess-game.vala
2015-05-05 21:36:54 +05:30

191 lines
8.1 KiB
Vala

/* -*- Mode: vala; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2010-2013 Robert Ancell
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation, either version 2 of the License, or (at your option) any later
* version. See http://www.gnu.org/copyleft/gpl.html the full text of the
* license.
*/
class GNOMEChess
{
static int test_count = 0;
static int failure_count = 0;
private static void test_good_move (string fen, string move, string result_fen,
ChessResult result = ChessResult.IN_PROGRESS,
ChessRule rule = ChessRule.CHECKMATE,
bool verify_san = false)
{
ChessState state = new ChessState (fen);
test_count++;
if (!state.move (move))
{
stderr.printf ("%d. FAIL %s + %s is an invalid move\n", test_count, fen, move);
failure_count++;
return;
}
if (state.get_fen () != result_fen)
{
stderr.printf ("%d. FAIL %s + %s has state %s not %s\n", test_count, fen, move, state.get_fen (), result_fen);
failure_count++;
return;
}
// We don't typically want to test this since get_san returns exactly one canonical SAN,
// but some test cases want to verify that slightly different notations are accepted.
if (verify_san && state.last_move.get_san () != move)
{
stderr.printf ("%d. FAIL %s + %s has SAN move %s\n", test_count, fen, move, state.last_move.get_san ());
failure_count++;
return;
}
ChessRule move_rule;
var move_result = state.get_result (out move_rule);
if (move_result != result || move_rule != rule)
{
stderr.printf ("%d. FAIL %s + %s has result %s not %s\n", test_count, fen, move, move_result.to_string (), result.to_string ());
failure_count++;
return;
}
stderr.printf ("%d. PASS %s + %s is valid\n", test_count, fen, move);
}
private static void test_bad_move (string fen, string move)
{
ChessState state = new ChessState (fen);
test_count++;
if (state.move (move, false))
{
stderr.printf ("%d. FAIL %s + %s is valid\n", test_count, fen, move);
failure_count++;
return;
}
stderr.printf ("%d. PASS %s + %s is invalid\n", test_count, fen, move);
}
public static int main (string[] args)
{
/* Pawn move */
test_good_move ("8/8/8/8/8/8/P7/8 w - - 0 1", "a3",
"8/8/8/8/8/P7/8/8 b - - 0 1");
/* Pawn march */
test_good_move ("8/8/8/8/8/8/P7/8 w - - 0 1", "a4",
"8/8/8/8/P7/8/8/8 b - a3 0 1");
/* Pawn march only allowed from baseline */
test_bad_move ("8/8/8/8/8/P7/8/8 w - - 0 1", "a2a5");
/* Pawn promotion */
test_good_move ("8/P7/8/8/8/8/8/8 w - - 0 1", "a8=Q",
"Q7/8/8/8/8/8/8/8 b - - 0 1");
test_good_move ("8/P7/8/8/8/8/8/8 w - - 0 1", "a7a8q",
"Q7/8/8/8/8/8/8/8 b - - 0 1");
test_good_move ("8/P7/8/8/8/8/8/8 w - - 0 1", "a7a8N",
"N7/8/8/8/8/8/8/8 b - - 0 1");
/* En passant */
test_good_move ("8/8/8/pP6/8/8/8/8 w - a6 0 1", "bxa6",
"8/8/P7/8/8/8/8/8 b - - 0 1");
/* Can't en passant if wasn't allowed */
test_bad_move ("8/8/8/pP6/8/8/8/8 w - - 0 1", "b5a6");
/* Can't capture en passant unless we are a pawn */
test_good_move ("8/8/8/pQ6/8/8/8/8 w - a6 0 1", "Qa6",
"8/8/Q7/p7/8/8/8/8 b - - 1 1");
test_bad_move ("8/8/8/pQ6/8/8/8/8 w - a6 0 1", "bxa6");
/* Castle kingside */
test_good_move ("8/8/8/8/8/8/8/4K2R w K - 0 1", "O-O",
"8/8/8/8/8/8/8/5RK1 b - - 1 1");
/* Castle queenside */
test_good_move ("8/8/8/8/8/8/8/R3K3 w Q - 0 1", "O-O-O",
"8/8/8/8/8/8/8/2KR4 b - - 1 1");
/* Can't castle if pieces moved */
test_bad_move ("8/8/8/8/8/8/8/4K2R w - - 0 1", "O-O");
/* Can't castle if piece misplaced (shouldn't occur as then the castle flag would not be there) */
test_bad_move ("8/8/8/8/8/8/8/4K3 w K - 0 1", "O-O");
test_bad_move ("8/8/8/8/8/8/8/5K2 w K - 0 1", "O-O");
/* Can't castle when in check */
test_bad_move ("4r3/8/8/8/8/8/8/4K2R w K - 0 1", "O-O");
/* Can't move across square that would put into check */
test_bad_move ("5r2/8/8/8/8/8/8/4K2R w K - 0 1", "O-O");
test_bad_move ("8/8/8/8/8/8/6p1/4K2R w K - 0 1", "O-O");
test_bad_move ("8/8/8/8/8/8/4p3/R3K3 w Q - 0 1", "O-O-O");
/* Can't move into check */
test_bad_move ("4r3/8/8/8/8/8/4R3/4K3 w - - 0 1", "e2f2");
/* Check */
test_good_move ("k7/8/8/8/8/8/8/1R6 w - - 0 1", "Ra1+",
"k7/8/8/8/8/8/8/R7 b - - 1 1");
/* Checkmate */
test_good_move ("k7/8/8/8/8/8/1R6/1R6 w - - 0 1", "Ra1#",
"k7/8/8/8/8/8/1R6/R7 b - - 1 1", ChessResult.WHITE_WON, ChessRule.CHECKMATE);
/* Not checkmate (piece can be moved to intercept) */
test_good_move ("k7/7r/8/8/8/8/1R6/1R6 w - - 0 1", "Ra1+",
"k7/7r/8/8/8/8/1R6/R7 b - - 1 1", ChessResult.IN_PROGRESS);
/* Stalemate */
test_good_move ("k7/8/7R/8/8/8/8/1R6 w - - 0 1", "Rh7",
"k7/7R/8/8/8/8/8/1R6 b - - 1 1", ChessResult.DRAW, ChessRule.STALEMATE);
/* Insufficient material - King vs. King */
test_good_move ("k7/7p/7K/8/8/8/8/8 w - - 0 1", "Kxh7",
"k7/7K/8/8/8/8/8/8 b - - 0 1", ChessResult.DRAW, ChessRule.INSUFFICIENT_MATERIAL);
/* Insufficient material - King and knight vs. King */
test_good_move ("k7/7p/7K/8/8/8/8/7N w - - 0 1", "Kxh7",
"k7/7K/8/8/8/8/8/7N b - - 0 1", ChessResult.DRAW, ChessRule.INSUFFICIENT_MATERIAL);
/* Sufficient if a knight on each side */
test_good_move("k7/7p/7K/8/8/8/8/6Nn w - - 0 1", "Kxh7",
"k7/7K/8/8/8/8/8/6Nn b - - 0 1", ChessResult.IN_PROGRESS);
/* A bishop would suffice as well */
test_good_move("k7/7p/7K/8/8/8/8/6Nb w - - 0 1", "Kxh7",
"k7/7K/8/8/8/8/8/6Nb b - - 0 1", ChessResult.IN_PROGRESS);
/* Insufficient material - King and n same-color bishops vs. King and n same-color bishops */
test_good_move("k2b1b1b/6bp/7K/4B1B1/8/8/8/8 w - - 0 1", "Kxh7",
"k2b1b1b/6bK/8/4B1B1/8/8/8/8 b - - 0 1", ChessResult.DRAW, ChessRule.INSUFFICIENT_MATERIAL);
/* Sufficient if the players' bishops are on opposite colors */
test_good_move("k2b1b1b/6bp/7K/5B1B/8/8/8/8 w - - 0 1", "Kxh7",
"k2b1b1b/6bK/8/5B1B/8/8/8/8 b - - 0 1", ChessResult.IN_PROGRESS);
/* Still sufficient with only one bishop per player, opposite colors */
test_good_move("k6b/6bp/7K/7B/8/8/8/8 w - - 0 1", "Kxh7",
"k6b/6bK/8/7B/8/8/8/8 b - - 0 1", ChessResult.IN_PROGRESS);
/* Sufficient if one player has a bishop on each color */
test_good_move("k2b1b1b/6bp/7K/6BB/8/8/8/8 w - - 0 1", "Kxh7",
"k2b1b1b/6bK/8/6BB/8/8/8/8 b - - 0 1", ChessResult.IN_PROGRESS);
// FIXME: Need to be able to test claim draw
/* Claim draw due to 50 move rule */
//test_good_move ("p7/8/8/8/8/8/8/P7 w - - 100 1", "draw",
// "p7/8/8/8/8/8/8/P7 w - - 100 1", ChessResult.DRAW, ChessRule.FIFTY_MOVES);
/* Need 100 halfmoves for 50 move rule */
//test_bad_move ("p7/8/8/8/8/8/8/P7 w - - 99 1", "draw");
/* Three fold repetition */
// FIXME: Need a test for three fold repetition
stdout.printf ("%d/%d tests successful\n", test_count - failure_count, test_count);
return failure_count;
}
}