Skip to content

Commit

Permalink
Add prettyprint (#101)
Browse files Browse the repository at this point in the history
Can be activated with "pretty" and deactivated again with "uci", off by default
(Also works in bench, so something like ./build/Molybdenum pretty bench would run bench in pretty mode)
bench 8493466
  • Loading branch information
rn5f107s2 authored Sep 21, 2024
1 parent a0cd8f3 commit fa459c3
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 24 deletions.
56 changes: 56 additions & 0 deletions src/Position.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <string>
#include <array>

#include "Constants.h"
#include "BitStuff.h"
#include "Move.h"
Expand Down Expand Up @@ -40,6 +41,8 @@ class Position {
inline Piece pieceOn(int sq);
inline u64 getOccupied();
template<Color c> u64 getOccupied();
inline std::string moveToSAN(Move move, u64 attacks);
inline int ambigious(Move move, u64 attacks);
private:
Stack<Piece> capturedHistory;
Stack<int> plys50mrHistory;
Expand Down Expand Up @@ -92,5 +95,58 @@ inline bool Position::isCapture(Move move) {
return pieceLocations[to] != NO_PIECE;
}

inline std::string Position::moveToSAN(Move move, u64 attacks) {
int from = extract<FROM>(move);
int to = extract<TO >(move);

if (extract<FLAG>(move) == CASTLING)
return from > to ? "0-0 " : "0-0-0 ";

std::string piece;
std::string toSquare;

if (typeOf(pieceOn(from)) != PAWN) {
piece += std::toupper(pieceToChar(typeOf(pieceOn(from))));

int a = ambigious(move, attacks);

if (a & 1)
piece += char('a' + (fileOf(from)));

if (a & 2)
piece += char('a' + (rankOf(from)));

if (isCapture(move))
piece += "x";
} else {
if (isCapture(move) || extract<FLAG>(move) == ENPASSANT) {
piece += char('a' + (fileOf(from)));
piece += 'x';
}
}


return piece + char('a' + (fileOf(to))) + char('1' + (rankOf(to))) + " ";
}

inline int Position::ambigious(Move move, u64 attacks) {
int from = extract<FROM>(move);
int to = extract<TO >(move);
Piece pc = pieceOn(from);

u64 pieces = getPieces(sideToMove, PieceType(typeOf(pc))) ^ (1ULL << from);
u64 overlap = attacks & pieces;

if (!overlap)
return 0;

if (!(lFIleOf(to) & overlap))
return 1;

if (!(lRankOf(to) & overlap))
return 2;

return 3;
}

#endif //MOLYBDENUM_POSITION_H
6 changes: 5 additions & 1 deletion src/UCI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,17 @@ void UCI::uci([[maybe_unused]] const std::string &args) {
#endif

std::cout << "uciok" << std::endl;
return;
prettyprint = false;
}

void UCI::isready([[maybe_unused]] const std::string &args) {
std::cout << "readyok" << std::endl;
}

void UCI::pretty([[maybe_unused]] const std::string &args) {
prettyprint = true;
}

void UCI::ucinewgame([[maybe_unused]] const std::string &args) {
if (!threads.done())
return;
Expand Down
2 changes: 2 additions & 0 deletions src/UCI.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class UCI {
commands["eval"] = &UCI::eval;
commands["stop"] = &UCI::stop;
commands["bench"] = &UCI::bench;
commands["pretty"] = &UCI::pretty;
commands["isready"] = &UCI::isready;
commands["goPerft"] = &UCI::goPerft;
commands["position"] = &UCI::position;
Expand All @@ -63,6 +64,7 @@ class UCI {
void eval(const std::string &args);
void stop(const std::string &args);
void bench(const std::string &args);
void pretty(const std::string &args);
void goPerft(const std::string &args);
void isready(const std::string &args);
void position(const std::string &args);
Expand Down
37 changes: 37 additions & 0 deletions src/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <array>
#include <string>
#include <iostream>
#include "Constants.h"

constexpr int MAX_STACK_SIZE = 6000; //Longer then the longest possible chess game
Expand Down Expand Up @@ -140,4 +141,40 @@ inline int stringRoRule50(const std::string& rule50) {
return std::stoi(rule50);
}

enum PaddType {
Back, Front, Equal
};

enum ColorType {
Foreground, Background
};

template<PaddType PT>
inline void paddString(std::string &s, size_t c) {
if constexpr (PT != Equal) {
for (size_t size = s.length(); size < c; size++)
s = (PT == Front) ? (" " + s) : (s + " ");

return;
}

paddString<Front>(s, c / 2);
paddString<Back >(s, c );
}

template<PaddType PT>
inline void zeroPaddString(std::string &s, size_t c) {
for (size_t size = s.length(); size < c; size++)
s = PT ? ("0" + s) : (s + "0");
}

template<ColorType ct>
inline void colorString(std::string &s, int c) {
std::string reset = "\u001b[0m";
std::string prefix[2] = {"\u001b[38;5;", "\u001b[48;5;"};
std::string color = prefix[ct] + std::to_string(c) + "m";

s = color + s + reset;
}

#endif //MOLYBDENUM_UTILITY_H
164 changes: 141 additions & 23 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "Movepicker.h"
#include "searchUtil.h"
#include "thread.h"
#include "Movegen.h"

#include <chrono>
#include <algorithm>
Expand All @@ -16,6 +17,8 @@
Tune tune;
#endif

bool prettyprint = false;

std::string SearchState::outputWDL(Position &pos) {
for (int i = 0; i < pvLength[0]; i++)
pos.makeMove(pvMoves[0][i]);
Expand Down Expand Up @@ -57,6 +60,8 @@ int SearchState::iterativeDeepening(Position &pos, SearchTime &st, int maxDepth
si.clear();
si.st = st;

//prettyInitial();

for (int depth = 1; depth != maxDepth; depth++) {
score = aspirationWindow(score, pos, si, depth);

Expand All @@ -67,39 +72,43 @@ int SearchState::iterativeDeepening(Position &pos, SearchTime &st, int maxDepth
continue;

#ifndef DATAGEN
std::string uciOutput;
auto searchTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - si.st.searchStart).count();
uciOutput += "info depth ";
uciOutput += std::to_string(depth);
if (prettyprint)
prettyPrint(pos, si, score, depth);
else {
std::string uciOutput;
auto searchTime = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - si.st.searchStart).count();
uciOutput += "info depth ";
uciOutput += std::to_string(depth);

uciOutput += " seldepth ";
uciOutput += std::to_string(si.selDepth);
uciOutput += " seldepth ";
uciOutput += std::to_string(si.selDepth);

uciOutput += " currmove ";
uciOutput += moveToString(si.bestRootMove);
uciOutput += " currmove ";
uciOutput += moveToString(si.bestRootMove);

uciOutput += " score ";
uciOutput += abs(score) > MAXMATE ? "mate " : "cp ";
uciOutput += std::to_string(abs(score) > MAXMATE ? mateInPlies(score) : score);
uciOutput += " score ";
uciOutput += abs(score) > MAXMATE ? "mate " : "cp ";
uciOutput += std::to_string(abs(score) > MAXMATE ? mateInPlies(score) : score);

u64 nodeCount = thread->threads->nodes();
u64 nodeCount = thread->threads->nodes();

uciOutput += " nodes ";
uciOutput += std::to_string(nodeCount);
uciOutput += " nodes ";
uciOutput += std::to_string(nodeCount);

uciOutput += " time ";
uciOutput += std::to_string(searchTime);
uciOutput += " time ";
uciOutput += std::to_string(searchTime);

uciOutput += " nps ";
uciOutput += std::to_string((nodeCount / std::max(int(searchTime), 1)) * 1000);
uciOutput += " nps ";
uciOutput += std::to_string((nodeCount / std::max(int(searchTime), 1)) * 1000);

uciOutput += outputWDL(pos);
uciOutput += outputWDL(pos);

uciOutput += " pv ";
for (int i = 0; i < pvLength[0]; i++)
uciOutput += moveToString(pvMoves[0][i]) + " ";
uciOutput += " pv ";
for (int i = 0; i < pvLength[0]; i++)
uciOutput += moveToString(pvMoves[0][i]) + " ";

std::cout << uciOutput << std::endl;
std::cout << uciOutput << std::endl;
}

if (stop<Soft>(st, si)) {
thread->threads->stop();
Expand Down Expand Up @@ -535,3 +544,112 @@ int SearchState::qsearch(int alpha, int beta, Position &pos, SearchInfo &si, Sea

return bestScore;
}

void prettyInitial() {
std::cout << std::endl;
std::cout << " depth time nodes speed score" << std::endl;
std::cout << "_______________________________________________________________________________" << std::endl;
}

// This is pretty print, not pretty code
void SearchState::prettyPrint(Position &pos, SearchInfo &si, int s, int de) {
auto searchTime = std::chrono::steady_clock::now() - si.st.searchStart;
auto searchTimeMinutes = std::chrono::duration_cast<std::chrono::minutes >(searchTime).count();
auto searchTimeSeconds = std::chrono::duration_cast<std::chrono::seconds >(searchTime).count();
auto searchTimeMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(searchTime).count();
u64 nodes = thread->threads->nodes();
u64 nodesPerMillisecond = (nodes / (searchTimeMilliseconds + 1));
std::string temp = std::to_string(abs(s) % 100);
std::vector<std::string> sanPV;

zeroPaddString<Front>(temp, 2);

for (int i = 0; i < pvLength[0]; i++) {
sanPV.push_back(pos.moveToSAN(pvMoves[0][i], getAttacks(typeOf(pos.pieceOn(extract<FROM>(pvMoves[0][i]))),
extract<TO>(pvMoves[0][i]),
pos.getOccupied(),
pos.sideToMove ^ bool(i + 1))));
pos.makeMove(pvMoves[0][i]);
}

std::tuple<float, float, float> wdl = pos.net.getWDL(pos.sideToMove);

for (int i = pvLength[0] - 1; i >= 0; i--)
pos.unmakeMove(pvMoves[0][i]);

bool flip = pvLength[0] & 1;
float w = flip ? std::get<0>(wdl) : std::get<2>(wdl);
float l = flip ? std::get<2>(wdl) : std::get<0>(wdl);
float d = std::get<1>(wdl);

std::string pretty = "";
std::string depth = std::to_string(de);
std::string seperator = "|";
std::string selDepth = std::to_string(si.selDepth);
std::string megaNodes = std::to_string(nodes / 1000000);
std::string decimalNodes = std::to_string((nodes % 100000) / 10000);
std::string dot = ".";
std::string mn = "Mn";
std::string minutes = std::to_string(searchTimeMinutes % 60);
std::string seconds = std::to_string(searchTimeSeconds % 60);
std::string milliseconds = std::to_string((searchTimeMilliseconds % 10000) / 1000);
std::string mnps = std::to_string(nodesPerMillisecond / 1000);
std::string decimalMnps = std::to_string(nodesPerMillisecond % 1000 / 100);
std::string scorePrefix = s > 0 ? "+" : "-";
std::string matePrefix = abs(s) >= MAXMATE ? "M" : "";
std::string score = std::to_string(abs(s) >= MAXMATE ? mateInPlies(s) : (abs(s) / 100));
std::string scoreDecimal = abs(s) >= MAXMATE ? "" : ("." + temp);
std::string completeScore = scorePrefix + matePrefix + score + scoreDecimal;
std::string wPercentage = std::to_string(int(std::roundf(w * 100.0f))) + "% ";
std::string dPercentage = std::to_string(int(std::roundf(d * 100.0f))) + "% ";
std::string lPercentage = std::to_string(int(std::roundf(l * 100.0f))) + "% ";

paddString<Front>(depth , 3);
paddString<Back >(selDepth , 3);
paddString<Front>(megaNodes, 5);
paddString<Front>(minutes, 5);
zeroPaddString<Front>(seconds, 2);
paddString<Front>(mnps, 6);
paddString<Front>(completeScore, 11);
paddString<Back>(completeScore, completeScore.size() + 6);
paddString<Front>(wPercentage, 5);
paddString<Front>(dPercentage, 5);
paddString<Front>(lPercentage, 5);

wPercentage = "W:" + wPercentage;
dPercentage = "D:" + dPercentage;
lPercentage = "L:" + lPercentage;

paddString<Back>(lPercentage, 13);

int evalColorTones[11] = {88, 124, 196, 202, 208, 229, 106, 64, 76, 28, 22};
int evalColorIndex = std::clamp(5+ (s / 25), 0, 10);

colorString<Foreground>(wPercentage, 15);
colorString<Foreground>(dPercentage, 8);
colorString<Foreground>(lPercentage, 16);
colorString<Foreground>(completeScore, evalColorTones[evalColorIndex]);

colorString<Foreground>(sanPV[0], 15);
sanPV[0] = "\033[1m" + sanPV[0] + "\033[0m";

for (size_t i = 1; i < sanPV.size(); i++)
colorString<Foreground>(sanPV[i], 242);

// Eval bar for wdl? Current issue inability to find a way to display percentages on top of bars in a way that make sense

pretty += depth + seperator + selDepth;
pretty += minutes + "m " + seconds + "." + milliseconds + "s ";
pretty += megaNodes + dot + decimalNodes + mn;
pretty += mnps + dot + decimalMnps + "Mn/s";

colorString<Foreground>(pretty, 246);

pretty += completeScore;
pretty += wPercentage + dPercentage + lPercentage;

for (auto &move : sanPV)
pretty += move;

std::cout << pretty << std::endl;
}
6 changes: 6 additions & 0 deletions src/search.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
extern Tune tune;
#endif

extern bool prettyprint;

class Thread;

struct SearchInfo {
Expand Down Expand Up @@ -83,6 +85,8 @@ class SearchState {

Thread* thread;
SearchInfo si;

void prettyPrint(Position &pos, SearchInfo &si, int score, int depth);
};

inline std::array<double, 256> initReductions() {
Expand Down Expand Up @@ -112,4 +116,6 @@ bool stop(SearchTime &st, SearchInfo &si) {
|| (st.limit == Nodes && si.nodeCount >= st.nodeLimit);
}

void prettyInitial();

#endif //MOLYBDENUM_SEARCH_H

0 comments on commit fa459c3

Please sign in to comment.