Skip to content

Commit b6630d1

Browse files
committed
merge {Moonwalker316:main}: Fix for SebLague#327
1 parent ff1e732 commit b6630d1

File tree

4 files changed

+153
-36
lines changed

4 files changed

+153
-36
lines changed

Chess-Challenge/src/Framework/Application/Core/ChallengeController.cs

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@ public enum PlayerType
2525
}
2626

2727
// Game state
28-
readonly Random rng;
28+
Random rng;
2929
int gameID;
3030
bool isPlaying;
3131
Board board;
3232
public ChessPlayer PlayerWhite { get; private set; }
33-
public ChessPlayer PlayerBlack {get;private set;}
33+
public ChessPlayer PlayerBlack { get; private set; }
3434

3535
float lastMoveMadeTime;
3636
bool isWaitingToPlayMove;
@@ -42,7 +42,7 @@ public enum PlayerType
4242
readonly string[] botMatchStartFens;
4343
int botMatchGameIndex;
4444
public BotMatchStats BotStatsA { get; private set; }
45-
public BotMatchStats BotStatsB {get;private set;}
45+
public BotMatchStats BotStatsB { get; private set; }
4646
bool botAPlaysWhite;
4747

4848

@@ -60,6 +60,9 @@ public enum PlayerType
6060
long maxMemoryUsed = 0;
6161
public bool fastForward;
6262

63+
int totalMovesPlayed = 0;
64+
public int trueTotalMovesPlayed = 0;
65+
6366
public ChallengeController()
6467
{
6568
Log($"Launching Chess-Challenge version {Settings.Version}");
@@ -71,6 +74,7 @@ public ChallengeController()
7174
boardUI = new BoardUI();
7275
board = new Board();
7376
pgns = new();
77+
fastForward = false;
7478

7579
BotStatsA = new BotMatchStats("IBot");
7680
BotStatsB = new BotMatchStats("IBot");
@@ -147,7 +151,11 @@ void BotThinkerThread()
147151

148152
Move GetBotMove()
149153
{
154+
155+
totalMovesPlayed++;
156+
150157
API.Board botBoard = new(board);
158+
151159
try
152160
{
153161
API.Timer timer = new(PlayerToMove.TimeRemainingMs, PlayerNotOnMove.TimeRemainingMs, GameDurationMilliseconds, IncrementMilliseconds);
@@ -298,15 +306,16 @@ void PlayMove(Move move)
298306

299307
void EndGame(GameResult result, bool log = true, bool autoStartNextBotMatch = true)
300308
{
309+
trueTotalMovesPlayed += totalMovesPlayed;
310+
totalMovesPlayed = 0;
301311
if (isPlaying)
302312
{
303313
isPlaying = false;
304314
isWaitingToPlayMove = false;
305-
gameID = -1;
306315

307316
if (log)
308317
{
309-
Log("Game Over: " + result, false, ConsoleColor.Blue);
318+
Log("Game Over: " + result + " Match: " + CurrGameNumber, false, ConsoleColor.Blue);
310319
}
311320

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

335+
if (fastForward)
336+
{
337+
StartNewGame(PlayerBlack.PlayerType, PlayerWhite.PlayerType);
338+
}
339+
else
340+
{
341+
const int startNextGameDelayMs = 600;
342+
System.Timers.Timer autoNextTimer = new(startNextGameDelayMs);
343+
int originalGameID = gameID;
344+
autoNextTimer.Elapsed += (s, e) => AutoStartNextBotMatchGame(originalGameID, autoNextTimer);
345+
autoNextTimer.AutoReset = false;
346+
autoNextTimer.Start();
347+
}
332348
}
333349
else if (autoStartNextBotMatch)
334350
{
351+
fastForward = false;
335352
Log("Match finished", false, ConsoleColor.Blue);
336353
}
337354
}
@@ -377,31 +394,41 @@ void UpdateStats(BotMatchStats stats, bool isWhiteStats)
377394

378395
public void Update()
379396
{
380-
if (isPlaying)
397+
398+
do
381399
{
382-
PlayerWhite.Update();
383-
PlayerBlack.Update();
400+
if (isPlaying)
401+
{
402+
PlayerWhite.Update();
403+
PlayerBlack.Update();
384404

385-
PlayerToMove.UpdateClock(Raylib.GetFrameTime());
386-
if (PlayerToMove.TimeRemainingMs <= 0)
405+
PlayerToMove.UpdateClock(Raylib.GetFrameTime() + MinMoveDelay);
406+
if (PlayerToMove.TimeRemainingMs <= 0)
407+
{
408+
EndGame(PlayerToMove == PlayerWhite ? GameResult.WhiteTimeout : GameResult.BlackTimeout);
409+
}
410+
else
411+
{
412+
if (isWaitingToPlayMove && (Raylib.GetTime() >= playMoveTime || fastForward))
413+
{
414+
isWaitingToPlayMove = false;
415+
PlayMove(moveToPlay);
416+
}
417+
}
418+
}
419+
420+
if (hasBotTaskException)
387421
{
388-
EndGame(PlayerToMove == PlayerWhite ? GameResult.WhiteTimeout : GameResult.BlackTimeout);
422+
hasBotTaskException = false;
423+
botExInfo.Throw();
389424
}
390-
else
425+
426+
if (PlayerWhite.IsHuman || PlayerBlack.IsHuman)
391427
{
392-
if (isWaitingToPlayMove && Raylib.GetTime() > playMoveTime)
393-
{
394-
isWaitingToPlayMove = false;
395-
PlayMove(moveToPlay);
396-
}
428+
fastForward = false;
397429
}
398-
}
399430

400-
if (hasBotTaskException)
401-
{
402-
hasBotTaskException = false;
403-
botExInfo.Throw();
404-
}
431+
} while (fastForward && isWaitingToPlayMove);
405432
}
406433

407434
public void Draw()

Chess-Challenge/src/Framework/Application/Core/Settings.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@ public static class Settings
1010
public const int GameDurationMilliseconds = 60 * 1000;
1111
public const int IncrementMilliseconds = 0 * 1000;
1212
public const float MinMoveDelay = 0.01f;
13-
public static readonly bool RunBotsOnSeparateThread = true;
13+
public static bool RunBotsOnSeparateThread = true; // IF NOT IN FAST FORWARD, TURN THIS ON - It's no longer readonly
1414

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

2021
// Other settings
2122
public const int MaxTokenCount = 1024;

Chess-Challenge/src/Framework/Application/UI/MatchStatsUI.cs

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
using Raylib_cs;
1+
using Raylib_cs;
22
using System.Numerics;
33
using System;
4+
using static System.Formats.Asn1.AsnWriter;
45

56
namespace ChessChallenge.Application
67
{
@@ -14,7 +15,10 @@ public static void DrawMatchStats(ChallengeController controller)
1415
int regularFontSize = UIHelper.ScaleInt(35);
1516
int headerFontSize = UIHelper.ScaleInt(45);
1617
Color col = new(180, 180, 180, 255);
17-
Vector2 startPos = UIHelper.Scale(new Vector2(1500, 250));
18+
Color white = new(225, 225, 225, 225);
19+
Color red = new Color(200, 0, 0, 255);
20+
Color green = new Color(0, 200, 0, 255);
21+
Vector2 startPos = UIHelper.Scale(new Vector2(1500, 150));
1822
float spacingY = UIHelper.Scale(35);
1923

2024
DrawNextText($"Game {controller.CurrGameNumber} of {controller.TotalGameCount}", headerFontSize, Color.WHITE);
@@ -23,22 +27,95 @@ public static void DrawMatchStats(ChallengeController controller)
2327
DrawStats(controller.BotStatsA);
2428
startPos.Y += spacingY * 2;
2529
DrawStats(controller.BotStatsB);
26-
30+
31+
startPos.Y += spacingY * 2;
32+
33+
string eloDifference = CalculateElo(controller.BotStatsA.NumWins, controller.BotStatsA.NumDraws, controller.BotStatsA.NumLosses);
34+
string errorMargin = CalculateErrorMargin(controller.BotStatsA.NumWins, controller.BotStatsA.NumDraws, controller.BotStatsA.NumLosses);
35+
36+
DrawNextText($"Elo Difference:", headerFontSize, Color.WHITE);
37+
DrawNextText($"{eloDifference} {errorMargin}", regularFontSize, Color.GRAY);
2738

2839
void DrawStats(ChallengeController.BotMatchStats stats)
2940
{
3041
DrawNextText(stats.BotName + ":", nameFontSize, Color.WHITE);
31-
DrawNextText($"Score: +{stats.NumWins} ={stats.NumDraws} -{stats.NumLosses}", regularFontSize, col);
42+
DrawNextText($"Score: +{stats.NumWins} ={stats.NumDraws} -{stats.NumLosses}", regularFontSize, white);
3243
DrawNextText($"Num Timeouts: {stats.NumTimeouts}", regularFontSize, col);
3344
DrawNextText($"Num Illegal Moves: {stats.NumIllegalMoves}", regularFontSize, col);
45+
DrawNextText($"Winrate: {(float)stats.NumWins / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, green);
46+
DrawNextText($"Draw rate: {(float)stats.NumDraws / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, white);
47+
DrawNextText($"Loss rate: {(float)stats.NumLosses / (controller.CurrGameNumber - 1) * 100}%", regularFontSize, red);
3448
}
35-
49+
DrawNextText($"Average moves per game: {controller.trueTotalMovesPlayed / controller.CurrGameNumber - 1}", regularFontSize, white);
50+
51+
3652
void DrawNextText(string text, int fontSize, Color col)
3753
{
3854
UIHelper.DrawText(text, startPos, fontSize, 1, col);
3955
startPos.Y += spacingY;
4056
}
4157
}
4258
}
59+
60+
private static string CalculateElo(int wins, int draws, int losses)
61+
{
62+
double score = wins + draws / 2;
63+
int totalGames = wins + draws + losses;
64+
double difference = CalculateEloDifference(score / totalGames);
65+
if ((int)difference == -2147483648)
66+
{
67+
if (difference > 0) return "+Inf";
68+
else return "-Inf";
69+
}
70+
71+
return $"{(int)difference}";
72+
}
73+
74+
private static double CalculateEloDifference(double percentage)
75+
{
76+
return -400 * Math.Log(1 / percentage - 1) / 2.302;
77+
}
78+
79+
private static string CalculateErrorMargin(int wins, int draws, int losses)
80+
{
81+
double total = wins + draws + losses;
82+
double winP = wins / total;
83+
double drawP = draws / total;
84+
double lossP = losses / total;
85+
86+
double percentage = (wins + draws / 2) / total;
87+
double winDev = winP * Math.Pow(1 - percentage, 2);
88+
double drawsDev = drawP * Math.Pow(0.5 - percentage, 2);
89+
double lossesDev = lossP * Math.Pow(0 - percentage, 2);
90+
91+
double stdDeviation = Math.Sqrt(winDev + drawsDev + lossesDev) / Math.Sqrt(total);
92+
93+
double confidenceP = 0.95;
94+
double minConfidenceP = (1 - confidenceP) / 2;
95+
double maxConfidenceP = 1 - minConfidenceP;
96+
double devMin = percentage + PhiInv(minConfidenceP) * stdDeviation;
97+
double devMax = percentage + PhiInv(maxConfidenceP) * stdDeviation;
98+
99+
double difference = CalculateEloDifference(devMax) - CalculateEloDifference(devMin);
100+
double margin = Math.Round(difference / 2);
101+
if (double.IsNaN(margin)) return "";
102+
return $"+/- {margin}";
103+
}
104+
105+
private static double PhiInv(double p)
106+
{
107+
return Math.Sqrt(2) * CalculateInverseErrorFunction(2 * p - 1);
108+
}
109+
110+
private static double CalculateInverseErrorFunction(double x)
111+
{
112+
double a = 8 * (Math.PI - 3) / (3 * Math.PI * (4 - Math.PI));
113+
double y = Math.Log(1 - x * x);
114+
double z = 2 / (Math.PI * a) + y / 2;
115+
116+
double ret = Math.Sqrt(Math.Sqrt(z * z - y / a) - z);
117+
if (x < 0) return -ret;
118+
return ret;
119+
}
43120
}
44-
}
121+
}

Chess-Challenge/src/Framework/Application/UI/MenuUI.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,10 +73,22 @@ public static void DrawButtons(ChallengeController controller)
7373
{
7474
Program.SetWindowSize(isBigWindow ? Settings.ScreenSizeSmall : Settings.ScreenSizeBig);
7575
}
76+
77+
if(NextButtonInRow("Smallerer Window", ref buttonPos, spacing, buttonSize))
78+
{
79+
Program.SetWindowSize(Settings.ScreenSizeXS);
80+
}
81+
7682
if (NextButtonInRow("Exit (ESC)", ref buttonPos, spacing, buttonSize))
7783
{
7884
Environment.Exit(0);
7985
}
86+
if (NextButtonInRow("Fast forward", ref buttonPos, spacing, buttonSize))
87+
{
88+
controller.fastForward = !controller.fastForward;
89+
if(controller.fastForward) Settings.RunBotsOnSeparateThread = false;
90+
else Settings.RunBotsOnSeparateThread = true;
91+
}
8092

8193
bool NextButtonInRow(string name, ref Vector2 pos, float spacingY, Vector2 size)
8294
{

0 commit comments

Comments
 (0)