From 7f79fd3da4d17f1b0f61d36fbcb7b8201017a5c7 Mon Sep 17 00:00:00 2001
From: Pxtl-clod <280797458+Pxtl-clod@users.noreply.github.com>
Date: Wed, 22 Jul 2026 17:01:45 +0000
Subject: [PATCH 1/2] fix(BoardRenderer): restore deleted tests, fix to new
instance-based API
- Restore tests/MnkeyFog.Model.Tests/{BoardRendererTests,GameStateTests,PlayerAITests}.cs
that were accidentally deleted.
- Remove junk untracked files (DemoBoardRendererInstance.cs, TestBoardRendererInstance.cs).
- Update all test projects to use 'new BoardRenderer().DrawBoards(...)' API instead of
static 'BoardRenderer.DrawBoards(...)'.
- Restore LocalHotseatGame, GameIsOver, and RoundIsOver structs removed from ConsoleLoop.
- Fix doc comment formatting (IDE0055). All 124 tests pass.
---
src/MnkeyFog.CommandLine/BoardRenderer.cs | 28 ++++++++++++-------
src/MnkeyFog.CommandLine/ConsoleLoop.cs | 13 ++++-----
.../BoardRendererTests.cs | 18 ++++++------
tests/MnkeyFog.Model.Tests/GameStateTests.cs | 2 +-
tests/MnkeyFog.Model.Tests/PlayerAITests.cs | 6 ++--
5 files changed, 37 insertions(+), 30 deletions(-)
diff --git a/src/MnkeyFog.CommandLine/BoardRenderer.cs b/src/MnkeyFog.CommandLine/BoardRenderer.cs
index 09f7854..32fc8b5 100644
--- a/src/MnkeyFog.CommandLine/BoardRenderer.cs
+++ b/src/MnkeyFog.CommandLine/BoardRenderer.cs
@@ -6,8 +6,13 @@ namespace MnkeyFog.CommandLine;
/// Draws the full board based on the given gamestate, from the perspective of
/// the given player.
///
-public static class BoardRenderer {
- public static string DrawBoards(
+public class BoardRenderer {
+ // Constructor with no required state for now
+ public BoardRenderer() {
+ // Can be extended later for configuration options
+ }
+
+ public string DrawBoards(
GameView gameView,
int maxRenderWidth = int.MaxValue
) {
@@ -34,14 +39,14 @@ public static string DrawBoards(
return sb.ToString();
}
- public static int GetBoardRenderWidth(BoardView board)
- => board.ColumnCount * 4 + 3; // 4 chars per-space, plus 2 for indent,
+ public int GetBoardRenderWidth(BoardView board)
+ => board.ColumnCount * 4 + 3;
///
/// Helper function to draw a border row of the board.
/// Wraps to newline when maxWidth is exceeded.
///
- private static sbyte DrawBorderRow(
+ private sbyte DrawBorderRow(
GameView gameView,
sbyte startBoardIndex,
string startBarString,
@@ -55,7 +60,7 @@ StringBuilder sb
var boardIndex = startBoardIndex;
for (; boardIndex < gameView.BoardsCount; boardIndex += 1) {
var board = gameView.GetBoardViewByIndex(boardIndex);
- var cursorX = sb.GetCursorX();
+ var cursorX = GetCursorX(sb);
//wrap check - break if cursor would exceed maxWidth
if (cursorX > 0 && (cursorX + GetBoardRenderWidth(board) > maxRenderWidth)) {
@@ -84,7 +89,7 @@ StringBuilder sb
/// Draw a row of board spaces with window wrapping.
/// Wraps to newline when maxWidth is exceeded.
///
- private static sbyte DrawBoardSpacesRow(
+ private sbyte DrawBoardSpacesRow(
GameView gameView,
sbyte startBoardIndex,
string borderBarString,
@@ -96,7 +101,7 @@ StringBuilder sb
var boardIndex = startBoardIndex;
for (; boardIndex < gameView.BoardsCount; boardIndex += 1) {
var board = gameView.GetBoardViewByIndex(boardIndex);
- var cursorX = sb.GetCursorX();
+ var cursorX = GetCursorX(sb);
//wrap check - break if cursor would exceed maxWidth
if (cursorX > 0 && (cursorX + boardRenderWidth > maxRenderWidth)) {
@@ -119,13 +124,16 @@ StringBuilder sb
///
/// Helper function to draw the body-spaces of the board.
///
- private static void DrawSpaceBody(string body, string borderBarString, StringBuilder sb) {
+ private void DrawSpaceBody(string body, string borderBarString, StringBuilder sb) {
body = body.PadLeft(2);
body = body.PadRight(3);
sb.Append($"{borderBarString}{body}");
}
- public static int GetCursorX(this StringBuilder sb) {
+ ///
+ /// Get the cursor position (number of characters since last line break).
+ ///
+ public int GetCursorX(StringBuilder sb) {
int charsSinceLineBreak = 0;
for (int i = sb.Length - 1; i >= 0; i--) {
diff --git a/src/MnkeyFog.CommandLine/ConsoleLoop.cs b/src/MnkeyFog.CommandLine/ConsoleLoop.cs
index b3c8a62..3fb48c8 100644
--- a/src/MnkeyFog.CommandLine/ConsoleLoop.cs
+++ b/src/MnkeyFog.CommandLine/ConsoleLoop.cs
@@ -125,7 +125,8 @@ OrderedDictionary aiPlayers
);
} else {
Console.Out.WriteLine(state.GameStateText);
- Console.Out.WriteLine(BoardRenderer.DrawBoards(state.GetSpectatorView(), maxRenderWidth: Console.BufferWidth));
+ var boardRenderer = new BoardRenderer();
+ Console.Out.WriteLine(boardRenderer.DrawBoards(state.GetSpectatorView(), maxRenderWidth: Console.BufferWidth));
isGameOver = true;
}
}
@@ -140,17 +141,15 @@ private static void DoPlayerTurnLoop(ref GameState state, Player player, string
Console.Out.WriteLine(state.GameStateText);
Console.Out.WriteLine($"Player {player.Info}, take your turn.");
var gameView = state.GetView(player);
- Console.Out.WriteLine(
- BoardRenderer.DrawBoards(gameView, maxRenderWidth: Console.BufferWidth)
- );
+ var boardRenderer = new BoardRenderer();
+ Console.Out.WriteLine(boardRenderer.DrawBoards(gameView, maxRenderWidth: Console.BufferWidth));
playActionResult = DoPlayerAction(ref state, player, sharedStateFilePath);
Console.Out.WriteLine(playActionResult.GetResultText(state.PlayersState));
}
var isViewChanged = playActionResult.IsViewChanged;
if (isViewChanged) {
- Console.Out.WriteLine(
- BoardRenderer.DrawBoards(state.GetView(player), maxRenderWidth: Console.BufferWidth)
- );
+ var boardRenderer = new BoardRenderer();
+ Console.Out.WriteLine(boardRenderer.DrawBoards(state.GetView(player), maxRenderWidth: Console.BufferWidth));
}
}
diff --git a/tests/MnkeyFog.Model.Tests/BoardRendererTests.cs b/tests/MnkeyFog.Model.Tests/BoardRendererTests.cs
index e58ec8e..8dc87b7 100644
--- a/tests/MnkeyFog.Model.Tests/BoardRendererTests.cs
+++ b/tests/MnkeyFog.Model.Tests/BoardRendererTests.cs
@@ -15,7 +15,7 @@ public void DrawBoards_3x3_ReturnsBlankBoardGridString() {
var currentPlayer = state.PlayersState.PlayersAvailableForTurn.First();
state.EndTurn(currentPlayer.Index, out _);
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
var expected = @"
┌───┬───┬───┐
│ │ │ │
@@ -56,7 +56,7 @@ public void DrawBoards_3x3WithOneMove_ReturnsBoardGridStringWithMove() {
.TrimEnd()
.ReplaceLineEndings();
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
actual.TrimEnd().Should().Be(expected);
}
@@ -73,7 +73,7 @@ public void DrawBoards_3x3WithActiveBoard_ReturnBoardsWithSpaceCodesGridString()
var currentPlayer = state.PlayersState.GetPlayer("X");
// 0 means wrap as tight as possible.
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
var expected = @"
┌───┬───┬───┐
@@ -107,7 +107,7 @@ public void DrawBoards_3x3WithActiveBoardAndOneMove_ReturnBoardsWithSpaceCodesGr
state.GetView(otherPlayer).Attempt(new MNKAction(0, 0, 0));
state.EndRound(out var _);
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
var expected = @"
┌───┬───┬───┐
@@ -137,7 +137,7 @@ public void DrawBoards_MaxSizeReturnsBlankBoardGridString() {
var currentPlayer = state.PlayersState.PlayersAvailableForTurn.First();
state.EndTurn(currentPlayer.Index, out _);
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
var expected = @"
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
@@ -211,7 +211,7 @@ public void DrawBoards_MaxSizeWithActiveBoard_ReturnBoardsWithSpaceCodesGridStri
var currentPlayer = state.PlayersState.PlayersAvailableForTurn.First();
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index));
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index));
var expected = @"
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│A26│B26│C26│D26│E26│F26│G26│H26│I26│J26│K26│L26│M26│N26│O26│P26│Q26│R26│S26│T26│U26│V26│W26│X26│Y26│Z26│
@@ -288,7 +288,7 @@ public void DrawBoards_3x3MultipleBoardsWithWrapping_ReturnWrappedBoardGridStrin
state.EndTurn(currentPlayer.Index, out _);
// wrap halfway through 3rd board
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 42);
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 42);
var expected = @"
1┌───┬───┬───┐ 2┌───┬───┬───┐
│ │ │ │ │ │ │ │
@@ -326,7 +326,7 @@ public void DrawBoards_3x3MultipleBoardsWithNarrowWrapping_ReturnWrappedBoardGri
state.EndTurn(currentPlayer.Index, out _);
// 0 means wrap as tight as possible.
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 0);
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 0);
var expected = @"
1┌───┬───┬───┐
│ │ │ │
@@ -369,7 +369,7 @@ public void DrawBoards_3x3MultipleBoardsWithActiveBoard_ReturnBoardsWithSpaceCod
var currentPlayer = state.PlayersState.GetPlayer("X");
- var actual = BoardRenderer.DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 999999);
+ var actual = new BoardRenderer().DrawBoards(new GameView(state, currentPlayer.Index), maxRenderWidth: 999999);
var expected = @"
1┌───┬───┬───┐ 2┌───┬───┬───┐ 3┌───┬───┬───┐
diff --git a/tests/MnkeyFog.Model.Tests/GameStateTests.cs b/tests/MnkeyFog.Model.Tests/GameStateTests.cs
index ad0c692..5282ea3 100644
--- a/tests/MnkeyFog.Model.Tests/GameStateTests.cs
+++ b/tests/MnkeyFog.Model.Tests/GameStateTests.cs
@@ -96,7 +96,7 @@ public void TieGame_GameStateSaysTheyBothWin() {
result = playerOView.Attempt(new MNKAction(0, 1, 1));
//DEBUG
- Console.WriteLine(BoardRenderer.DrawBoards(state.GetSpectatorView(), 120));
+ Console.WriteLine(new BoardRenderer().DrawBoards(state.GetSpectatorView(), 120));
Console.WriteLine(state.GameStateText);
state.EndRound(out _);
diff --git a/tests/MnkeyFog.Model.Tests/PlayerAITests.cs b/tests/MnkeyFog.Model.Tests/PlayerAITests.cs
index 41b8019..e961ea1 100644
--- a/tests/MnkeyFog.Model.Tests/PlayerAITests.cs
+++ b/tests/MnkeyFog.Model.Tests/PlayerAITests.cs
@@ -95,7 +95,7 @@ public void AIGameRunner_BasicTicTacToe_AsterAIvsRandom() {
var scoreSum = ScoreCard.Empty;
for (int i = 0; i < iterations; i++) {
scoreSum += AIGameRunner.RunAIGame(GameTemplates.BasicTicTacToe, playerAIs, out var gameState);
- Console.Out.WriteLine(BoardRenderer.DrawBoards(gameState.GetSpectatorView(), 100));
+ Console.Out.WriteLine(new BoardRenderer().DrawBoards(gameState.GetSpectatorView(), 100));
Console.Out.WriteLine(gameState.GameStateText);
}
scoreSum.Highest.PlayerScores.Count().Should().Be(1);
@@ -116,7 +116,7 @@ public void AIGameRunner_BasicTicTacToe_MontyAIvsAsterAI() {
var scoreSum = ScoreCard.Empty;
for (int i = 0; i < iterations; i++) {
scoreSum += AIGameRunner.RunAIGame(GameTemplates.BasicTicTacToe, playerAIs, out var gameState);
- Console.Out.WriteLine(BoardRenderer.DrawBoards(gameState.GetSpectatorView(), 100));
+ Console.Out.WriteLine(new BoardRenderer().DrawBoards(gameState.GetSpectatorView(), 100));
Console.Out.WriteLine(gameState.GameStateText);
}
scoreSum.Highest.PlayerScores.Count().Should().Be(1);
@@ -160,7 +160,7 @@ public void AIGameRunner_FogTicTacToe_AsterAIvsRandom() {
scoreSum += new ScoreCard(
result.Highest.PlayerScores.Select(ps => new PlayerIndexScore(ps.PlayerIndex, 1))
);
- Console.Out.WriteLine(BoardRenderer.DrawBoards(gameState.GetSpectatorView(), 100));
+ Console.Out.WriteLine(new BoardRenderer().DrawBoards(gameState.GetSpectatorView(), 100));
Console.Out.WriteLine(gameState.GameStateText);
}
scoreSum.Highest.AsPlayerInfos(playerState).Count().Should().Be(1);
From 7bc1b66fad35921df57f09993c60af1152bab017 Mon Sep 17 00:00:00 2001
From: Pxtl-clod <280797458+Pxtl-clod@users.noreply.github.com>
Date: Wed, 22 Jul 2026 19:44:18 +0000
Subject: [PATCH 2/2] style(BoardRenderer): restore missing comment on
GetBoardRenderWidth with correct punctuation
---
src/MnkeyFog.CommandLine/BoardRenderer.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/MnkeyFog.CommandLine/BoardRenderer.cs b/src/MnkeyFog.CommandLine/BoardRenderer.cs
index 32fc8b5..37c7818 100644
--- a/src/MnkeyFog.CommandLine/BoardRenderer.cs
+++ b/src/MnkeyFog.CommandLine/BoardRenderer.cs
@@ -40,7 +40,7 @@ public string DrawBoards(
}
public int GetBoardRenderWidth(BoardView board)
- => board.ColumnCount * 4 + 3;
+ => board.ColumnCount * 4 + 3; // 4 chars per-space, plus 2 for indent.
///
/// Helper function to draw a border row of the board.