From 21e956519ed01adc637e9eacad64605fd44f1b44 Mon Sep 17 00:00:00 2001 From: Quinten Kock Date: Sat, 20 Jun 2020 03:26:33 +0200 Subject: [PATCH] Impl UCI bench and perft --- ArduChess.ino | 162 ------------------------------------------------ Tasks.h | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++ Uci.h | 27 ++++++++ 3 files changed, 194 insertions(+), 162 deletions(-) create mode 100644 Tasks.h diff --git a/ArduChess.ino b/ArduChess.ino index 7e16aca..d42bba4 100644 --- a/ArduChess.ino +++ b/ArduChess.ino @@ -10,168 +10,6 @@ #include "Types.h" #include "Uci.h" -unsigned long pseudo_perft(byte depth) { - // only checks pseudolegality - // but, it should work overall - if(depth == 0) return 1; - if(depth == 3) blink(); - unsigned long move_count = 0; - Movegen gen; - Move m; - - while (true) { - m = gen.next_move(); - if(m.sq_to != 255) { - make(m); - move_count += pseudo_perft(depth-1); - unmake(); - } else { - break; - } - } - return move_count; -} - -void perft_test() { - for(byte i = 0; i < 5; i++) { - Serial.print(F("Perft ")); - Serial.print(i); - Serial.print(F(": ")); - Serial.println(pseudo_perft(i)); - } -} - -void debug_movegen() { - make({0x14, 0x34, P_EMPTY}); - 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(); - make({0x76, 0x55, P_EMPTY}); print(); - make({0x16, 0x26, P_EMPTY}); print(); - make({0x63, 0x43, P_EMPTY}); print(); - make({0x05, 0x16, P_EMPTY}); print(); - make({0x62, 0x42, P_EMPTY}); print(); - make({0x04, 0x06, P_EMPTY}); print(); - unmake(); print(); - unmake(); print(); - unmake(); print(); - unmake(); print(); - unmake(); print(); - unmake(); print(); - unmake(); print(); -} - -void debug_ep() { - print(); - make({0x14, 0x34, P_EMPTY}); - print(); - make({0x64, 0x54, P_EMPTY}); - print(); - make({0x34, 0x44, P_EMPTY}); - print(); - make({0x63, 0x43, P_EMPTY}); - print(); - make({0x44, 0x53, P_EMPTY}); - print(); - unmake(); - print(); - unmake(); - print(); - unmake(); - print(); - unmake(); - print(); - unmake(); - print(); -} - -void bench() { - unsigned long startTime = micros(); - - make({0x14, 0x34, P_EMPTY}); - make({0x64, 0x54, P_EMPTY}); - make({0x34, 0x44, P_EMPTY}); - make({0x63, 0x43, P_EMPTY}); - make({0x44, 0x53, P_EMPTY}); - unmake(); - unmake(); - unmake(); - unmake(); - unmake(); - - make({0x06, 0x25, P_EMPTY}); - make({0x76, 0x55, P_EMPTY}); - make({0x16, 0x26, P_EMPTY}); - make({0x63, 0x43, P_EMPTY}); - make({0x05, 0x16, P_EMPTY}); - make({0x62, 0x42, P_EMPTY}); - make({0x04, 0x06, P_EMPTY}); - unmake(); - unmake(); - unmake(); - unmake(); - unmake(); - unmake(); - unmake(); - - - unsigned long elapsed = micros() - startTime; - Serial.print(elapsed); - Serial.println(F(" microseconds for make/unmake")); - - for(int i = 1; i <= 4; i++) { - startTime = millis(); - pseudo_perft(i); - elapsed = millis() - startTime; - Serial.print(elapsed); - Serial.print(F(" milliseconds for pseudo_perft(")); - Serial.print(i); - Serial.println(')'); - } - - Movegen gen; - Move move[20]; - startTime = micros(); - for(int i = 0; i < 20; i++) { - move[i] = gen.next_move(); - } - elapsed = micros() - startTime; - Serial.print(elapsed); - Serial.println(F(" microseconds for movegen(init_pos)")); - - startTime = micros(); - for(int i = 0; i < 20; i++) { - make(move[i]); - unmake(); - } - elapsed = micros() - startTime; - Serial.print(elapsed); - Serial.println(F(" microseconds for make/unmake(init_pos)")); -} - - void setup() { // put your setup code here, to run once: board_init(); diff --git a/Tasks.h b/Tasks.h new file mode 100644 index 0000000..c33f886 --- /dev/null +++ b/Tasks.h @@ -0,0 +1,167 @@ +#ifndef __TASKS_H_INC +#define __TASKS_H_INC + +unsigned long pseudo_perft(byte depth) { + // only checks pseudolegality + // but, it should work overall + if(depth == 0) return 1; + if(depth == 3) blink(); + unsigned long move_count = 0; + Movegen gen; + Move m; + + while (true) { + m = gen.next_move(); + if(m.sq_to != 255) { + Board::make(m); + move_count += pseudo_perft(depth-1); + Board::unmake(); + } else { + break; + } + } + return move_count; +} + +void perft_test() { + for(byte i = 0; i < 5; i++) { + Serial.print(F("Perft ")); + Serial.print(i); + Serial.print(F(": ")); + Serial.println(pseudo_perft(i)); + } +} + +void debug_movegen() { + Board::make({0x14, 0x34, P_EMPTY}); + 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"); + Board::make(m); + Board::print(); + DEBUG("unmake"); + Board::unmake(); + DEBUG("unmake done"); + } + } while (m.sq_from != 255); +} + +void debug_castle() { + Board::print(); + Board::make({0x06, 0x25, P_EMPTY}); Board::print(); + Board::make({0x76, 0x55, P_EMPTY}); Board::print(); + Board::make({0x16, 0x26, P_EMPTY}); Board::print(); + Board::make({0x63, 0x43, P_EMPTY}); Board::print(); + Board::make({0x05, 0x16, P_EMPTY}); Board::print(); + Board::make({0x62, 0x42, P_EMPTY}); Board::print(); + Board::make({0x04, 0x06, P_EMPTY}); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); + Board::unmake(); Board::print(); +} + +void debug_ep() { + Board::print(); + Board::make({0x14, 0x34, P_EMPTY}); + Board::print(); + Board::make({0x64, 0x54, P_EMPTY}); + Board::print(); + Board::make({0x34, 0x44, P_EMPTY}); + Board::print(); + Board::make({0x63, 0x43, P_EMPTY}); + Board::print(); + Board::make({0x44, 0x53, P_EMPTY}); + Board::print(); + Board::unmake(); + Board::print(); + Board::unmake(); + Board::print(); + Board::unmake(); + Board::print(); + Board::unmake(); + Board::print(); + Board::unmake(); + Board::print(); +} + +void bench() { + // TODO reduce code size of this (by moving repeated constants from here to PROGMEM and loops?) + + unsigned long startTime = micros(); + + Board::make({0x14, 0x34, P_EMPTY}); + Board::make({0x64, 0x54, P_EMPTY}); + Board::make({0x34, 0x44, P_EMPTY}); + Board::make({0x63, 0x43, P_EMPTY}); + Board::make({0x44, 0x53, P_EMPTY}); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + + Board::make({0x06, 0x25, P_EMPTY}); + Board::make({0x76, 0x55, P_EMPTY}); + Board::make({0x16, 0x26, P_EMPTY}); + Board::make({0x63, 0x43, P_EMPTY}); + Board::make({0x05, 0x16, P_EMPTY}); + Board::make({0x62, 0x42, P_EMPTY}); + Board::make({0x04, 0x06, P_EMPTY}); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + Board::unmake(); + + + unsigned long elapsed = micros() - startTime; + Serial.print(elapsed); + Serial.println(F(" microseconds for make/unmake")); + + for(int i = 1; i <= 4; i++) { + startTime = millis(); + pseudo_perft(i); + elapsed = millis() - startTime; + Serial.print(elapsed); + Serial.print(F(" milliseconds for pseudo_perft(")); + Serial.print(i); + Serial.println(')'); + } + + Movegen gen; + Move move[20]; + startTime = micros(); + for(int i = 0; i < 20; i++) { + move[i] = gen.next_move(); + } + elapsed = micros() - startTime; + Serial.print(elapsed); + Serial.println(F(" microseconds for movegen(init_pos)")); + + startTime = micros(); + for(int i = 0; i < 20; i++) { + Board::make(move[i]); + Board::unmake(); + } + elapsed = micros() - startTime; + Serial.print(elapsed); + Serial.println(F(" microseconds for make/unmake(init_pos)")); +} + +#endif \ No newline at end of file diff --git a/Uci.h b/Uci.h index 1de76db..9027023 100644 --- a/Uci.h +++ b/Uci.h @@ -1,6 +1,8 @@ #ifndef __UCI_H_INC #define __UCI_H_INC +#include "Tasks.h" + #define PS2(s) ([]{ static const char c[] PROGMEM = (s); return &c[0]; }()) typedef void uci_return; @@ -11,6 +13,15 @@ struct uci_cmd { uci_handler handler; }; +void clear_line() { + int peek = Serial.peek(); + if(peek == -1) return; + + do { + peek = Serial.read(); + } while(peek != '\n'); +} + uci_return uci_hello() { Serial.println(F("id name ArduChess\nid author Quinten Kock\nuciok")); } @@ -23,6 +34,15 @@ uci_return uci_unknown() { Serial.println(F("Not an UCI command")); } +uci_return uci_perft() { + int depth = Serial.parseInt(); + unsigned long result = pseudo_perft(depth); + Serial.print(F("perft(")); + Serial.print(depth); + Serial.print(F(") result: ")); + Serial.println(result); +} + const char UCI_COMMAND_uci[] PROGMEM = "uci"; const char UCI_COMMAND_debug[] PROGMEM = "debug"; const char UCI_COMMAND_isready[] PROGMEM = "isready"; @@ -33,6 +53,9 @@ const char UCI_COMMAND_go[] PROGMEM = "go"; const char UCI_COMMAND_stop[] PROGMEM = "stop"; const char UCI_COMMAND_ponderhit[] PROGMEM = "ponderhit"; const char UCI_COMMAND_quit[] PROGMEM = "quit"; +const char UCI_COMMAND_bench[] PROGMEM = "bench"; +const char UCI_COMMAND_perft[] PROGMEM = "perft"; + const uci_cmd UCI_COMMANDS[] PROGMEM = { {UCI_COMMAND_uci, &uci_hello}, @@ -45,6 +68,8 @@ const uci_cmd UCI_COMMANDS[] PROGMEM = { {UCI_COMMAND_stop, &uci_unimpl}, {UCI_COMMAND_ponderhit, &uci_unimpl}, {UCI_COMMAND_quit, &uci_unimpl}, + {UCI_COMMAND_bench, &bench}, + {UCI_COMMAND_perft, &uci_perft}, }; const uci_cmd UCI_INVALID = {PS2(""), &uci_unknown}; @@ -87,7 +112,9 @@ uci_return handle_uci() { String command = read_word(); uci_cmd handler = get_uci_command(command.c_str()); handler.handler(); + clear_line(); } } + #endif