From 25156e7ac79a76c7eb39b0586d650254095bdd83 Mon Sep 17 00:00:00 2001 From: Quinten Kock Date: Fri, 19 Jun 2020 01:26:00 +0200 Subject: [PATCH] Fix move generation I think --- ArduChess.ino | 52 +++++++++++++++++++++++++++++++++++++++++++++ Board.h | 5 +++-- Config.h | 2 ++ Movegen.h | 59 +++++++++++++++++++++++++++------------------------ Types.h | 8 +++++++ 5 files changed, 96 insertions(+), 30 deletions(-) diff --git a/ArduChess.ino b/ArduChess.ino index d69b802..766d39f 100644 --- a/ArduChess.ino +++ b/ArduChess.ino @@ -9,6 +9,58 @@ #include "Movegen.h" #include "Types.h" +unsigned int pseudo_perft(byte depth) { + // only checks pseudolegality + // but, it should work overall + if(depth == 0) return 1; + Serial.print(F("Start a PERFT ")); + Serial.print(depth); + Serial.println('-'); + print(); + unsigned int move_count = 0; + Movegen gen; + Move m; + do { + m = gen.next_move(); + //make(m); + move_count += pseudo_perft(depth-1); + //unmake(); + } while (m.sq_from != 255); + return move_count - 1; +} + +void perft_test() { + for(byte i = 0; i < 2; i++) { + Serial.print(F("Perft ")); + Serial.print(i); + Serial.print(F(": ")); + Serial.println(pseudo_perft(i)); + } +} + +void debug_movegen() { + Movegen gen = Movegen(); + Move m; + do { + DEBUG("start movegen"); + m = gen.next_move(); + Serial.print(F("FROM ")); + Serial.print(m.sq_from, HEX); + Serial.print(F(" TO ")); + Serial.print(m.sq_to, HEX); + Serial.print(F(" PROMOTE ")); + Serial.println(m.pc_prom); + if(m.sq_from != 255) { + DEBUG("make"); + make(m); + print(); + DEBUG("unmake"); + unmake(); + DEBUG("unmake done"); + } + } while (m.sq_from != 255); +} + void debug_castle() { print(); make({0x06, 0x25, P_EMPTY}); print(); diff --git a/Board.h b/Board.h index ed0f4bc..7f89c6e 100644 --- a/Board.h +++ b/Board.h @@ -34,7 +34,7 @@ #define PTR_UNMOVE_LAST 0x7F byte field[128]; -byte PTR_UNMOVE = PTR_UNMOVE_START; +byte PTR_UNMOVE; const byte field_default_value[] PROGMEM = BOARD_DEFAULT_VALUE; @@ -42,6 +42,7 @@ void board_init() { for(int i = 0; i < 128; i++) { field[i] = pgm_read_byte_near(field_default_value + i); } + PTR_UNMOVE = PTR_UNMOVE_START; field[PTR_SIDE_AND_CASTLERIGHT] = 0b11110; // all castle rights allowed, white to move field[PTR_W_KING] = 0x04; // e1 field[PTR_B_KING] = 0x74; // e8 @@ -267,7 +268,7 @@ void unmake() { field[PTR_SIDE_AND_CASTLERIGHT] |= 0b01 << castleright_offset; } - int sq_diff = (int)sq_to - (int)u.sq_from; + int sq_diff = (int)sq_to - (int)sq_from; int sq_diff_abs = abs(sq_diff); if((field[sq_from] & 0x7) == W_KING && sq_diff_abs == 2) { // we castled diff --git a/Config.h b/Config.h index 6e29856..82a9435 100644 --- a/Config.h +++ b/Config.h @@ -5,3 +5,5 @@ // PANIC_BLINK makes the Arduino blink an error code when it panics. // Costs a lot of flash though (around 700 bytes) //#define _ACF_PANIC_BLINK + +#define _ACF_DEBUG_PRINT diff --git a/Movegen.h b/Movegen.h index 7ae883f..eddebf9 100644 --- a/Movegen.h +++ b/Movegen.h @@ -25,7 +25,7 @@ class Movegen { }; Move Movegen::next_move() { - while(square <= 0x7F) { + while(square <= 0x77) { if(square & 0x88) square += 8; byte piece_type = field[square] & 0x7; @@ -37,14 +37,11 @@ Move Movegen::next_move() { // there is an own piece to investigate Move m; if(piece_type == W_PAWN) { - Serial.println("GENERATE PAWN"); m = generate_pawn(); } else if(piece_type & 0b0100) { - Serial.println("GENERATE SLIDING"); // bishop, rook and queen are 01xx. m = generate_sliding(piece_type); } else { - Serial.println("GENERATE NONSLIDING"); m = generate_non_sliding(piece_type); } if(m.sq_to != 255) { @@ -125,6 +122,8 @@ Move Movegen::generate_non_sliding(byte piece_type) { } Move Movegen::generate_pawn() { + // TODO: implement capture promotion + byte color = black_moving(); byte offset; byte target; @@ -166,19 +165,21 @@ Move Movegen::generate_pawn() { offset = color ? -0x11 : 0xF; target_square = square + offset; target = field[target_square]; - if(target && (target & 0x8) != (field[square] & 0x8)) { - // normal capture allowded - return Move{square, target_square, P_EMPTY}; - } else if(field[PTR_ENPASSANT]) { - // note that EP being legal only happens - // when the target field is empty. so this saves some effort. - byte ep_col = field[PTR_ENPASSANT] & 0x7; - if( - ep_col == (target_square & 0x7) && - (square & 0x70) == (color ? 0x30 : 0x40) - ) { - // EP-capture possible + if(!(target_square & 0x88)) { + if(target && (target & 0x8) != (field[square] & 0x8)) { + // normal capture allowded return Move{square, target_square, P_EMPTY}; + } else if(field[PTR_ENPASSANT]) { + // note that EP being legal only happens + // when the target field is empty. so this saves some effort. + byte ep_col = field[PTR_ENPASSANT] & 0x7; + if( + ep_col == (target_square & 0x7) && + (square & 0x70) == (color ? 0x30 : 0x40) + ) { + // EP-capture possible + return Move{square, target_square, P_EMPTY}; + } } } // fall through @@ -188,19 +189,21 @@ Move Movegen::generate_pawn() { offset = color ? -0xF : 0x11; target_square = square + offset; target = field[target_square]; - if(target && (target & 0x8) != (field[square] & 0x8)) { - // normal capture allowded - return Move{square, target_square, P_EMPTY}; - } else if(field[PTR_ENPASSANT]) { - // note that EP being legal only happens - // when the target field is empty. so this saves some effort. - byte ep_col = field[PTR_ENPASSANT] & 0x7; - if( - ep_col == (target_square & 0x7) && - (square & 0x70) == (color ? 0x30 : 0x40) - ) { - // EP-capture possible + if(!(target_square & 0x88)) { + if(target && (target & 0x8) != (field[square] & 0x8)) { + // normal capture allowded return Move{square, target_square, P_EMPTY}; + } else if(field[PTR_ENPASSANT]) { + // note that EP being legal only happens + // when the target field is empty. so this saves some effort. + byte ep_col = field[PTR_ENPASSANT] & 0x7; + if( + ep_col == (target_square & 0x7) && + (square & 0x70) == (color ? 0x30 : 0x40) + ) { + // EP-capture possible + return Move{square, target_square, P_EMPTY}; + } } } // fall through diff --git a/Types.h b/Types.h index 99aeba5..fdf2202 100644 --- a/Types.h +++ b/Types.h @@ -1,6 +1,14 @@ #ifndef __TYPES_H_INC #define __TYPES_H_INC +#include "Config.h"" + +#ifdef _ACF_DEBUG_PRINT +#define DEBUG(x) Serial.println(F(x)); Serial.flush() +#else +#define DEBUG(x) +#endif + enum Piece: byte { P_EMPTY = 0b0000, P_ANY = 0b1000,