Skip to content

Commit

Permalink
merge {Moonwalker316:main}: Fix for SebLague#327
Browse files Browse the repository at this point in the history
  • Loading branch information
VitorA29 committed Aug 17, 2023
1 parent ff1e732 commit b6630d1
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ public enum PlayerType
}

// Game state
readonly Random rng;
Random rng;
int gameID;
bool isPlaying;
Board board;
public ChessPlayer PlayerWhite { get; private set; }
public ChessPlayer PlayerBlack {get;private set;}
public ChessPlayer PlayerBlack { get; private set; }

float lastMoveMadeTime;
bool isWaitingToPlayMove;
Expand All @@ -42,7 +42,7 @@ public enum PlayerType
readonly string[] botMatchStartFens;
int botMatchGameIndex;
public BotMatchStats BotStatsA { get; private set; }
public BotMatchStats BotStatsB {get;private set;}
public BotMatchStats BotStatsB { get; private set; }
bool botAPlaysWhite;


Expand All @@ -60,6 +60,9 @@ public enum PlayerType
long maxMemoryUsed = 0;
public bool fastForward;

int totalMovesPlayed = 0;
public int trueTotalMovesPlayed = 0;

public ChallengeController()
{
Log($"Launching Chess-Challenge version {Settings.Version}");
Expand All @@ -71,6 +74,7 @@ public ChallengeController()
boardUI = new BoardUI();
board = new Board();
pgns = new();
fastForward = false;

BotStatsA = new BotMatchStats("IBot");
BotStatsB = new BotMatchStats("IBot");
Expand Down Expand Up @@ -147,7 +151,11 @@ void BotThinkerThread()

Move GetBotMove()
{

totalMovesPlayed++;

API.Board botBoard = new(board);

try
{
API.Timer timer = new(PlayerToMove.TimeRemainingMs, PlayerNotOnMove.TimeRemainingMs, GameDurationMilliseconds, IncrementMilliseconds);
Expand Down Expand Up @@ -298,15 +306,16 @@ void PlayMove(Move move)

void EndGame(GameResult result, bool log = true, bool autoStartNextBotMatch = true)
{
trueTotalMovesPlayed += totalMovesPlayed;
totalMovesPlayed = 0;
if (isPlaying)
{
isPlaying = false;
isWaitingToPlayMove = false;
gameID = -1;

if (log)
{
Log("Game Over: " + result, false, ConsoleColor.Blue);
Log("Game Over: " + result + " Match: " + CurrGameNumber, false, ConsoleColor.Blue);
}

string pgn = PGNCreator.CreatePGN(board, result, GetPlayerName(PlayerWhite), GetPlayerName(PlayerBlack));
Expand All @@ -322,16 +331,24 @@ void EndGame(GameResult result, bool log = true, bool autoStartNextBotMatch = tr
if (botMatchGameIndex < numGamesToPlay && autoStartNextBotMatch)
{
botAPlaysWhite = !botAPlaysWhite;
const int startNextGameDelayMs = 600;
System.Timers.Timer autoNextTimer = new(startNextGameDelayMs);
int originalGameID = gameID;
autoNextTimer.Elapsed += (s, e) => AutoStartNextBotMatchGame(originalGameID, autoNextTimer);
autoNextTimer.AutoReset = false;
autoNextTimer.Start();

if (fastForward)
{
StartNewGame(PlayerBlack.PlayerType, PlayerWhite.PlayerType);
}
else
{
const int startNextGameDelayMs = 600;
System.Timers.Timer autoNextTimer = new(startNextGameDelayMs);
int originalGameID = gameID;
autoNextTimer.Elapsed += (s, e) => AutoStartNextBotMatchGame(originalGameID, autoNextTimer);
autoNextTimer.AutoReset = false;
autoNextTimer.Start();
}
}
else if (autoStartNextBotMatch)
{
fastForward = false;
Log("Match finished", false, ConsoleColor.Blue);
}
}
Expand Down Expand Up @@ -377,31 +394,41 @@ void UpdateStats(BotMatchStats stats, bool isWhiteStats)

public void Update()
{
if (isPlaying)

do
{
PlayerWhite.Update();
PlayerBlack.Update();
if (isPlaying)
{
PlayerWhite.Update();
PlayerBlack.Update();

PlayerToMove.UpdateClock(Raylib.GetFrameTime());
if (PlayerToMove.TimeRemainingMs <= 0)
PlayerToMove.UpdateClock(Raylib.GetFrameTime() + MinMoveDelay);
if (PlayerToMove.TimeRemainingMs <= 0)
{
EndGame(PlayerToMove == PlayerWhite ? GameResult.WhiteTimeout : GameResult.BlackTimeout);
}
else
{
if (isWaitingToPlayMove && (Raylib.GetTime() >= playMoveTime || fastForward))
{
isWaitingToPlayMove = false;
PlayMove(moveToPlay);
}
}
}

if (hasBotTaskException)
{
EndGame(PlayerToMove == PlayerWhite ? GameResult.WhiteTimeout : GameResult.BlackTimeout);
hasBotTaskException = false;
botExInfo.Throw();
}
else

if (PlayerWhite.IsHuman || PlayerBlack.IsHuman)
{
if (isWaitingToPlayMove && Raylib.GetTime() > playMoveTime)
{
isWaitingToPlayMove = false;
PlayMove(moveToPlay);
}
fastForward = false;
}
}

if (hasBotTaskException)
{
hasBotTaskException = false;
botExInfo.Throw();
}
} while (fastForward && isWaitingToPlayMove);
}

public void Draw()
Expand Down
3 changes: 2 additions & 1 deletion Chess-Challenge/src/Framework/Application/Core/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ public static class Settings
public const int GameDurationMilliseconds = 60 * 1000;
public const int IncrementMilliseconds = 0 * 1000;
public const float MinMoveDelay = 0.01f;
public static readonly bool RunBotsOnSeparateThread = true;
public static bool RunBotsOnSeparateThread = true; // IF NOT IN FAST FORWARD, TURN THIS ON - It's no longer readonly

// Display settings
public const bool DisplayBoardCoordinates = true;
public static readonly Vector2 ScreenSizeSmall = new(1280, 720);
public static readonly Vector2 ScreenSizeBig = new(1920, 1080);
public static readonly Vector2 ScreenSizeXS = new (400, 200);

// Other settings
public const int MaxTokenCount = 1024;
Expand Down
89 changes: 83 additions & 6 deletions Chess-Challenge/src/Framework/Application/UI/MatchStatsUI.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Raylib_cs;
using Raylib_cs;
using System.Numerics;
using System;
using static System.Formats.Asn1.AsnWriter;

namespace ChessChallenge.Application
{
Expand All @@ -14,7 +15,10 @@ public static void DrawMatchStats(ChallengeController controller)
int regularFontSize = UIHelper.ScaleInt(35);
int headerFontSize = UIHelper.ScaleInt(45);
Color col = new(180, 180, 180, 255);
Vector2 startPos = UIHelper.Scale(new Vector2(1500, 250));
Color white = new(225, 225, 225, 225);
Color red = new Color(200, 0, 0, 255);
Color green = new Color(0, 200, 0, 255);
Vector2 startPos = UIHelper.Scale(new Vector2(1500, 150));
float spacingY = UIHelper.Scale(35);

DrawNextText($"Game {controller.CurrGameNumber} of {controller.TotalGameCount}", headerFontSize, Color.WHITE);
Expand All @@ -23,22 +27,95 @@ public static void DrawMatchStats(ChallengeController controller)
DrawStats(controller.BotStatsA);
startPos.Y += spacingY * 2;
DrawStats(controller.BotStatsB);


startPos.Y += spacingY * 2;

string eloDifference = CalculateElo(controller.BotStatsA.NumWins, controller.BotStatsA.NumDraws, controller.BotStatsA.NumLosses);
string errorMargin = CalculateErrorMargin(controller.BotStatsA.NumWins, controller.BotStatsA.NumDraws, controller.BotStatsA.NumLosses);

DrawNextText($"Elo Difference:", headerFontSize, Color.WHITE);
DrawNextText($"{eloDifference} {errorMargin}", regularFontSize, Color.GRAY);

void DrawStats(ChallengeController.BotMatchStats stats)
{
DrawNextText(stats.BotName + ":", nameFontSize, Color.WHITE);
DrawNextText($"Score: +{stats.NumWins} ={stats.NumDraws} -{stats.NumLosses}", regularFontSize, col);
DrawNextText($"Score: +{stats.NumWins} ={stats.NumDraws} -{stats.NumLosses}", regularFontSize, white);
DrawNextText($"Num Timeouts: {stats.NumTimeouts}", regularFontSize, col);
DrawNextText($"Num Illegal Moves: {stats.NumIllegalMoves}", regularFontSize, col);
DrawNextText($"Winrate: {(float)stats.NumWins / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, green);
DrawNextText($"Draw rate: {(float)stats.NumDraws / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, white);
DrawNextText($"Loss rate: {(float)stats.NumLosses / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, red);
}

DrawNextText($"Average moves per game: {controller.trueTotalMovesPlayed / controller.CurrGameNumber - 1}", regularFontSize, white);


void DrawNextText(string text, int fontSize, Color col)
{
UIHelper.DrawText(text, startPos, fontSize, 1, col);
startPos.Y += spacingY;
}
}
}

private static string CalculateElo(int wins, int draws, int losses)
{
double score = wins + draws / 2;
int totalGames = wins + draws + losses;
double difference = CalculateEloDifference(score / totalGames);
if ((int)difference == -2147483648)
{
if (difference > 0) return "+Inf";
else return "-Inf";
}

return $"{(int)difference}";
}

private static double CalculateEloDifference(double percentage)
{
return -400 * Math.Log(1 / percentage - 1) / 2.302;
}

private static string CalculateErrorMargin(int wins, int draws, int losses)
{
double total = wins + draws + losses;
double winP = wins / total;
double drawP = draws / total;
double lossP = losses / total;

double percentage = (wins + draws / 2) / total;
double winDev = winP * Math.Pow(1 - percentage, 2);
double drawsDev = drawP * Math.Pow(0.5 - percentage, 2);
double lossesDev = lossP * Math.Pow(0 - percentage, 2);

double stdDeviation = Math.Sqrt(winDev + drawsDev + lossesDev) / Math.Sqrt(total);

double confidenceP = 0.95;
double minConfidenceP = (1 - confidenceP) / 2;
double maxConfidenceP = 1 - minConfidenceP;
double devMin = percentage + PhiInv(minConfidenceP) * stdDeviation;
double devMax = percentage + PhiInv(maxConfidenceP) * stdDeviation;

double difference = CalculateEloDifference(devMax) - CalculateEloDifference(devMin);
double margin = Math.Round(difference / 2);
if (double.IsNaN(margin)) return "";
return $"+/- {margin}";
}

private static double PhiInv(double p)
{
return Math.Sqrt(2) * CalculateInverseErrorFunction(2 * p - 1);
}

private static double CalculateInverseErrorFunction(double x)
{
double a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
double y = Math.Log(1 - x * x);
double z = 2 / (Math.PI * a) + y / 2;

double ret = Math.Sqrt(Math.Sqrt(z * z - y / a) - z);
if (x < 0) return -ret;
return ret;
}
}
}
}
12 changes: 12 additions & 0 deletions Chess-Challenge/src/Framework/Application/UI/MenuUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,22 @@ public static void DrawButtons(ChallengeController controller)
{
Program.SetWindowSize(isBigWindow ? Settings.ScreenSizeSmall : Settings.ScreenSizeBig);
}

if(NextButtonInRow("Smallerer Window", ref buttonPos, spacing, buttonSize))
{
Program.SetWindowSize(Settings.ScreenSizeXS);
}

if (NextButtonInRow("Exit (ESC)", ref buttonPos, spacing, buttonSize))
{
Environment.Exit(0);
}
if (NextButtonInRow("Fast forward", ref buttonPos, spacing, buttonSize))
{
controller.fastForward = !controller.fastForward;
if(controller.fastForward) Settings.RunBotsOnSeparateThread = false;
else Settings.RunBotsOnSeparateThread = true;
}

bool NextButtonInRow(string name, ref Vector2 pos, float spacingY, Vector2 size)
{
Expand Down

0 comments on commit b6630d1

Please sign in to comment.