Skip to content

Commit

Permalink
Implemented iterative deepening
Browse files Browse the repository at this point in the history
  • Loading branch information
Orbital-Web committed Jul 19, 2023
1 parent 7a8c557 commit 91c7a58
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 12 deletions.
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Raphael
A GUI-based Chess Player as well as a Chess Engine, coded in C++ and [SFML](https://www.sfml-dev.org/).

The engine is still a work in progress and will be updated as time goes by. [Scroll to the bottom](https://github.com/Orbital-Web/Raphael#raphael-1) to see a list of features currently implemented.
The engine is still a work in progress and will be updated as time goes by (though it is already quite competent). Its main features are negamax with alpha-beta pruning, transposition table, and iterative deepening. [Scroll to the bottom](https://github.com/Orbital-Web/Raphael#raphael-1) to see a full list of features currently implemented.

<p align="center">
<img src="https://github.com/Orbital-Web/Raphael/blob/c0396fcec6b3221369353dcabe812fb068a03534/Demo.png" alt="demo of Raphael" width=400/>
Expand Down Expand Up @@ -46,16 +46,16 @@ The Human Player is an extension of `cge::GamePlayer` which will return a move b


### Raphael
Raphael is an extension of `cge::GamePlayer` which will use a negamax search tree to return the best move it can find.
Raphael is an extension of `cge::GamePlayer` which at its core uses a negamax search tree to return the best move it can find.

**General Improvements**
**General Optimizations**
- [x] Alpha-beta pruning (`v1.0.0+`)
- [x] Move ordering (`v1.0.0+`)
- [x] Transposition table (`v1.0.0+`)
- [ ] Iterative deepening
- [x] Iterative deepening (`v1.0.0+`)
- [ ] Opening book
- [x] Quiescence with capture (`v1.0.0+`)
- [ ] Quiescence with check
- [x] Quiescence with captures (`v1.0.0+`)
- [ ] Quiescence with checks
- [ ] Time management
- [ ] Pondering

Expand Down
1 change: 0 additions & 1 deletion src/GameEngine/GameEngine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#include "chess.hpp"
#include <SFML/Graphics.hpp>
#include <SFML/Audio.hpp>
#include <thread>
#include <future>
#include <sstream>
#include <iomanip>
Expand Down
2 changes: 1 addition & 1 deletion src/GameEngine/GamePlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class GamePlayer {
GamePlayer(std::string name_in): name(name_in) {}

// Returns a valid move string. Should return immediately if halt becomes true
virtual chess::Move get_move(chess::Board board, int t_remain, sf::Event& event, bool& halt) = 0;
virtual chess::Move get_move(chess::Board board, float t_remain, sf::Event& event, bool& halt) = 0;

// macros
#define whiteturn (board.sideToMove() == chess::Color::WHITE) // [bool] curently white's turn
Expand Down
2 changes: 1 addition & 1 deletion src/GameEngine/HumanPlayer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class HumanPlayer: public GamePlayer {


// Asks the human to return a move using the UI. Should return immediately if halt becomes true
chess::Move get_move(chess::Board board, int t_remain, sf::Event& event, bool& halt) {
chess::Move get_move(chess::Board board, float t_remain, sf::Event& event, bool& halt) {
auto sq_from = chess::NO_SQ;
auto sq_to = chess::NO_SQ;

Expand Down
73 changes: 70 additions & 3 deletions src/Raphael/Raphael_v1.0.0.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include "../GameEngine/chess.hpp"
#include <SFML/Graphics.hpp>
#include <string>
#include <future>
#include <chrono>



Expand All @@ -19,6 +21,7 @@ class v1_0_0: public cge::GamePlayer {
int score;
};
TranspositionTable tt;
chess::Move itermove; // best move from previous iteration



Expand All @@ -31,12 +34,70 @@ class v1_0_0: public cge::GamePlayer {


// Uses Negamax to return the best move. Should return immediately if halt becomes true
chess::Move get_move(chess::Board board, int t_remain, sf::Event& event, bool& halt) {
chess::Move get_move(chess::Board board, float t_remain, sf::Event& event, bool& halt) {
tt.clear();
return negamax(board, 4, -INT_MAX, INT_MAX, halt).move;
return iterative_deepening(board, t_remain, halt);
}

private:
// Uses iterative deepening on Negamax to find best move
chess::Move iterative_deepening(chess::Board& board, const float t_remain, bool& halt) {
int depth = 1;
itermove = chess::Move::NO_MOVE;
Searchres res = {0, 0};

// stop search after an appropriate duration
int duration = search_time(t_remain);
auto _ = std::async(manage_time, std::ref(halt), duration);

// begin iterative deepening
while (!halt) {
auto iterres = negamax(board, depth, -INT_MAX, INT_MAX, halt);

// not timeout
if (!halt)
res = iterres;

// checkmate, no need to continue
if (abs(res.score)>=1073641824) {
// get absolute evaluation (i.e, set to white's perspective)
if (!whiteturn == (res.score > 0))
depth *= -1;
printf("Eval: #%d\n", depth);
halt = true;
return res.move;
}

itermove = res.move;
depth++;
}
// get absolute evaluation (i.e, set to white's perspective)
if (!whiteturn)
res.score *= -1;
printf("Eval: %.2f\tDepth %d\n", res.score/100.0, depth-1);
return res.move;
}


// Estimates the time (ms) it should spend on searching a move
int search_time(const float t_remain) {
return 5000;
}


// Sets halt to true if duration (ms) passes
// Must be called asynchronously
static void manage_time(bool& halt, const int duration) {
auto start = std::chrono::high_resolution_clock::now();
while (!halt) {
auto now = std::chrono::high_resolution_clock::now();
auto dtime = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
if (dtime >= duration)
halt = true;
}
}


// The Negamax search algorithm to search for the best move
Searchres negamax(chess::Board& board, unsigned int depth, int alpha, int beta, bool& halt) {
// timeout
Expand Down Expand Up @@ -164,8 +225,14 @@ class v1_0_0: public cge::GamePlayer {

// Assigns a score to the given move
void score_move(chess::Move& move, const chess::Board& board) const {
int score = 0;
// prioritize best move from previous iteraton
if (move == itermove) {
move.setScore(INT16_MAX);
return;
}

// calculate score
int score = 0;
int from = (int)board.at(move.from());
int to = (int)board.at(move.to());

Expand Down

0 comments on commit 91c7a58

Please sign in to comment.