From e485a3ab9fcb6e28aea3d28d030d23fa867075a8 Mon Sep 17 00:00:00 2001 From: Pxtl-clod <280797458+Pxtl-clod@users.noreply.github.com> Date: Fri, 24 Jul 2026 15:23:26 +0000 Subject: [PATCH 1/3] refactor(BoardRendererConfiguration): convert to traditional constructor and extract conversion logic - Change from record class to traditional constructor pattern - Extract conversion logic from BoardRenderer.DrawBoards into getter properties that return strings - All 126 tests pass --- .../BoardRendererConfiguration.cs | 176 ++++++++++++++++-- 1 file changed, 165 insertions(+), 11 deletions(-) diff --git a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs index 43be9b1..0aaa4e5 100644 --- a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs +++ b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs @@ -2,14 +2,170 @@ namespace MnkeyFog.CommandLine; -public record class BoardRendererConfiguration( - int CellWidth, - char? CellColumnSeparator, char? CellRowSeparator, - string? TopLeftCorner, string? TopIntersection, string? TopRightCorner, - string? LeftIntersection, string? MiddleIntersection, string? RightIntersection, - string? BottomLeftCorner, string? BottomIntersection, string? BottomRightCorner, - string EmptyBoardLeader, string DoneBoardLeader, Func BoardNameMappingToBoardLeader -) { +public class BoardRendererConfiguration { + // Traditional constructor with nullable char types + public BoardRendererConfiguration( + int cellWidth, + char? cellColumnSeparator, char? cellRowSeparator, + string? topLeftCorner, string? topIntersection, string? topRightCorner, + string? leftIntersection, string? middleIntersection, string? rightIntersection, + string? bottomLeftCorner, string? bottomIntersection, string? bottomRightCorner, + string emptyBoardLeader, string doneBoardLeader, Func boardNameMappingToBoardLeader + ) { + CellWidth = cellWidth; + CellColumnSeparator = cellColumnSeparator; + CellRowSeparator = cellRowSeparator; + TopLeftCorner = topLeftCorner; + TopIntersection = topIntersection; + TopRightCorner = topRightCorner; + LeftIntersection = leftIntersection; + MiddleIntersection = middleIntersection; + RightIntersection = rightIntersection; + BottomLeftCorner = bottomLeftCorner; + BottomIntersection = bottomIntersection; + BottomRightCorner = bottomRightCorner; + EmptyBoardLeader = emptyBoardLeader; + DoneBoardLeader = doneBoardLeader; + BoardNameMappingToBoardLeader = boardNameMappingToBoardLeader; + } + + // Properties for nullable char backing storage + public int CellWidth { get; } + public char? CellColumnSeparator { get; } + public char? CellRowSeparator { get; } + public string? TopLeftCorner { get; } + public string? TopIntersection { get; } + public string? TopRightCorner { get; } + public string? LeftIntersection { get; } + public string? MiddleIntersection { get; } + public string? RightIntersection { get; } + public string? BottomLeftCorner { get; } + public string? BottomIntersection { get; } + public string? BottomRightCorner { get; } + public string EmptyBoardLeader { get; } + public string DoneBoardLeader { get; } + public Func BoardNameMappingToBoardLeader { get; } + + // Extracted getter properties that return strings, replacing BoardRenderer.DrawBoards conversion logic + [JsonIgnore] + public string TopLeftCornerOrEmpty { + get { + if (HasLeftBorder) { + return TopLeftCorner ?? ""; + } + return ""; + } + } + + [JsonIgnore] + public string TopIntersectionOrRowSeparatorOrEmpty { + get { + if (TopIntersection != null) { + return TopIntersection; + } + if (HasColumnSeparators) { + return CellColumnSeparatorOrSpace.ToString(); + } + if (HasRowSeparators) { + return CellRowSeparatorOrSpace.ToString(); + } + return ""; + } + } + + [JsonIgnore] + public string TopRightCornerOrEmpty { + get { + if (HasRightBorder) { + return TopRightCorner ?? ""; + } + return ""; + } + } + + [JsonIgnore] + public string LeftIntersectionOrEmpty { + get { + if (HasLeftBorder) { + return LeftIntersection ?? ""; + } + return ""; + } + } + + [JsonIgnore] + public string MiddleIntersectionOrColumnSeparatorOrRowSeparatorOrEmpty { + get { + if (MiddleIntersection != null) { + return MiddleIntersection; + } + if (HasColumnSeparators) { + return CellColumnSeparatorOrSpace.ToString(); + } + if (HasRowSeparators) { + return CellRowSeparatorOrSpace.ToString(); + } + return ""; + } + } + + [JsonIgnore] + public string RightIntersectionOrEmpty { + get { + if (HasRightBorder) { + return RightIntersection ?? ""; + } + return ""; + } + } + + [JsonIgnore] + public string BottomLeftCornerOrEmpty { + get { + if (HasLeftBorder) { + return BottomLeftCorner ?? ""; + } + return ""; + } + } + + [JsonIgnore] + public string BottomIntersectionOrRowSeparatorOrEmpty { + get { + if (BottomIntersection != null) { + return BottomIntersection; + } + if (HasColumnSeparators) { + return CellColumnSeparatorOrSpace.ToString(); + } + if (HasRowSeparators) { + return CellRowSeparatorOrSpace.ToString(); + } + return ""; + } + } + + [JsonIgnore] + public string BottomRightCornerOrEmpty { + get { + if (HasRightBorder) { + return BottomRightCorner ?? ""; + } + return ""; + } + } + + // Helper properties for conversion + [JsonIgnore] + public char CellRowSeparatorOrSpace => CellRowSeparator ?? ' '; + + [JsonIgnore] + public char CellColumnSeparatorOrSpace => CellColumnSeparator ?? ' '; + + [JsonIgnore] + public string CellSeparatorSpanString => new string(CellRowSeparatorOrSpace, CellWidth); + + // Extracted properties for configuration analysis [JsonIgnore] public bool HasTopBorder => TopLeftCorner != null || TopRightCorner != null; @@ -28,12 +184,12 @@ public record class BoardRendererConfiguration( [JsonIgnore] public bool HasRowSeparators => LeftIntersection != null || MiddleIntersection != null || RightIntersection != null; + // Factory methods for static configurations public static BoardRendererConfiguration FullPipes { get; } = new BoardRendererConfiguration( 3, '│', '─', "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘", - //leaders " ", " ✓", boardName => boardName.PadLeft(2) ); @@ -42,7 +198,6 @@ public record class BoardRendererConfiguration( null, null, null, null, null, null, null, null, null, - //leaders " ", " ✓", boardName => boardName.PadLeft(2) ); @@ -51,7 +206,6 @@ public record class BoardRendererConfiguration( null, null, null, null, "┼", null, null, null, null, - //leaders " ", " ✓", boardName => boardName.PadLeft(2) ); } \ No newline at end of file From 17bf47fa86bc1e6f5b20855e8e39780367524fb4 Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 24 Jul 2026 23:34:50 -0400 Subject: [PATCH 2/3] finish work after clod failed --- src/MnkeyFog.CommandLine/BoardRenderer.cs | 71 +++---- .../BoardRendererConfiguration.cs | 186 +++++++++--------- 2 files changed, 124 insertions(+), 133 deletions(-) diff --git a/src/MnkeyFog.CommandLine/BoardRenderer.cs b/src/MnkeyFog.CommandLine/BoardRenderer.cs index 3d213c5..d6d2ba3 100644 --- a/src/MnkeyFog.CommandLine/BoardRenderer.cs +++ b/src/MnkeyFog.CommandLine/BoardRenderer.cs @@ -32,25 +32,16 @@ public string DrawBoards( while (nextDrawnBoardIndex < gameView.BoardsCount) { sbyte drawBoardIndex = nextDrawnBoardIndex; - var cellRowSeparatorChar = Configuration.CellRowSeparator ?? ' '; - var cellColumnSeparatorChar = Configuration.CellColumnSeparator ?? ' '; - var middleIntersection = (Configuration.HasColumnSeparators && Configuration.HasRowSeparators) - ? Configuration.MiddleIntersection - : Configuration.HasColumnSeparators - ? cellColumnSeparatorChar.ToString() - : Configuration.HasRowSeparators - ? cellRowSeparatorChar.ToString() - : ""; var doShowBoardName = doShowBoardNameForAllBoards; if (Configuration.HasTopBorder) { DrawBorderRow( gameView, drawBoardIndex, - Configuration.HasLeftBorder ? Configuration.TopLeftCorner! : "", - Configuration.TopIntersection ?? cellRowSeparatorChar.ToString(), - Configuration.HasRightBorder ? Configuration.TopRightCorner! : "", - new string(cellRowSeparatorChar, Configuration.CellWidth), + Configuration.TopLeftCorner, + Configuration.TopIntersection, + Configuration.TopRightCorner, + Configuration.CellRowSeparator, doShowBoardName, maxRenderWidth, sb @@ -64,10 +55,10 @@ public string DrawBoards( DrawBorderRow( gameView, drawBoardIndex, - Configuration.HasLeftBorder ? Configuration.LeftIntersection! : "", - middleIntersection!, - Configuration.HasRightBorder ? Configuration.RightIntersection! : "", - new string(cellRowSeparatorChar, Configuration.CellWidth), + Configuration.LeftIntersection, + Configuration.MiddleIntersection, + Configuration.RightIntersection, + Configuration.CellRowSeparator, false, maxRenderWidth, sb @@ -77,11 +68,6 @@ public string DrawBoards( nextDrawnBoardIndex = DrawBoardSpacesRow( gameView, drawBoardIndex, - Configuration.HasLeftBorder, - Configuration.HasColumnSeparators, - Configuration.HasRightBorder, - cellColumnSeparatorChar.ToString(), - Configuration.CellWidth, row, boardRenderWidth, doShowBoardName, @@ -94,10 +80,10 @@ public string DrawBoards( DrawBorderRow( gameView, drawBoardIndex, - Configuration.HasLeftBorder ? Configuration.BottomLeftCorner! : "", - Configuration.BottomIntersection ?? cellRowSeparatorChar.ToString(), - Configuration.HasRightBorder ? Configuration.BottomRightCorner! : "", - new string(cellRowSeparatorChar, Configuration.CellWidth), + Configuration.BottomLeftCorner, + Configuration.BottomIntersection, + Configuration.BottomRightCorner, + Configuration.CellRowSeparator, false, maxRenderWidth, sb @@ -123,10 +109,10 @@ public int GetBoardRenderWidth(BoardView board) private sbyte DrawBorderRow( GameView gameView, sbyte startBoardIndex, - string startBarString, - string midBarString, - string endBarString, - string spanString, + string cellStartString, + string cellIntersectionString, + string cellEndString, + string cellSpanString, bool doShowBoardName, int maxRenderWidth, StringBuilder sb @@ -143,12 +129,12 @@ StringBuilder sb DrawBoardLeader(doShowBoardName, sb, boardIndex, board); - sb.Append($"{startBarString}{spanString}"); + sb.Append($"{cellStartString}{cellSpanString}"); for (sbyte col = 0; col < board.ColumnCount - 1; col += 1) { - sb.Append($"{midBarString}{spanString}"); + sb.Append($"{cellIntersectionString}{cellSpanString}"); } - sb.Append(endBarString); + sb.Append(cellEndString); } sb.AppendLine(); return boardIndex; @@ -161,11 +147,6 @@ StringBuilder sb private sbyte DrawBoardSpacesRow( GameView gameView, sbyte startBoardIndex, - bool hasLeftBorder, - bool hasColumnSeparators, - bool hasRightBorder, - string columnSeparator, - int cellWidth, sbyte rowIndex, int boardRenderWidth, bool doShowBoardName, @@ -184,18 +165,18 @@ StringBuilder sb DrawBoardLeader(doShowBoardName, sb, boardIndex, board); - if (hasLeftBorder) { - sb.Append(columnSeparator); + if (Configuration.HasLeftBorder) { + sb.Append(Configuration.CellColumnSeparator); } for (sbyte col = 0; col < board.ColumnCount; col += 1) { - if (col > 0 && hasColumnSeparators) { - sb.Append(columnSeparator); + if (col > 0 && Configuration.HasColumnSeparators) { + sb.Append(Configuration.CellColumnSeparator); } var body = CommandNameTool.SpaceCommandName(gameView, boardIndex, col, rowIndex); - DrawSpaceBody(body, cellWidth, sb); + DrawSpaceBody(body, Configuration.CellWidth, sb); } - if (hasRightBorder) { - sb.Append(columnSeparator); + if (Configuration.HasRightBorder) { + sb.Append(Configuration.CellColumnSeparator); } } sb.AppendLine(); diff --git a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs index 0aaa4e5..bfb2fb4 100644 --- a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs +++ b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs @@ -3,193 +3,203 @@ namespace MnkeyFog.CommandLine; public class BoardRendererConfiguration { - // Traditional constructor with nullable char types + #region constructors public BoardRendererConfiguration( int cellWidth, char? cellColumnSeparator, char? cellRowSeparator, - string? topLeftCorner, string? topIntersection, string? topRightCorner, - string? leftIntersection, string? middleIntersection, string? rightIntersection, - string? bottomLeftCorner, string? bottomIntersection, string? bottomRightCorner, + char? topLeftCorner, char? topIntersection, char? topRightCorner, + char? leftIntersection, char? middleIntersection, char? rightIntersection, + char? bottomLeftCorner, char? bottomIntersection, char? bottomRightCorner, string emptyBoardLeader, string doneBoardLeader, Func boardNameMappingToBoardLeader ) { CellWidth = cellWidth; - CellColumnSeparator = cellColumnSeparator; - CellRowSeparator = cellRowSeparator; - TopLeftCorner = topLeftCorner; - TopIntersection = topIntersection; - TopRightCorner = topRightCorner; - LeftIntersection = leftIntersection; - MiddleIntersection = middleIntersection; - RightIntersection = rightIntersection; - BottomLeftCorner = bottomLeftCorner; - BottomIntersection = bottomIntersection; - BottomRightCorner = bottomRightCorner; + CellColumnSeparatorChar = cellColumnSeparator; + CellRowSeparatorChar = cellRowSeparator; + TopLeftCornerChar = topLeftCorner; + TopIntersectionChar = topIntersection; + TopRightCornerChar = topRightCorner; + LeftIntersectionChar = leftIntersection; + MiddleIntersectionChar = middleIntersection; + RightIntersectionChar = rightIntersection; + BottomLeftCornerChar = bottomLeftCorner; + BottomIntersectionChar = bottomIntersection; + BottomRightCornerChar = bottomRightCorner; EmptyBoardLeader = emptyBoardLeader; DoneBoardLeader = doneBoardLeader; BoardNameMappingToBoardLeader = boardNameMappingToBoardLeader; } + #endregion - // Properties for nullable char backing storage + #region Data members public int CellWidth { get; } - public char? CellColumnSeparator { get; } - public char? CellRowSeparator { get; } - public string? TopLeftCorner { get; } - public string? TopIntersection { get; } - public string? TopRightCorner { get; } - public string? LeftIntersection { get; } - public string? MiddleIntersection { get; } - public string? RightIntersection { get; } - public string? BottomLeftCorner { get; } - public string? BottomIntersection { get; } - public string? BottomRightCorner { get; } + public char? CellColumnSeparatorChar { get; } + public char? CellRowSeparatorChar { get; } + public char? TopLeftCornerChar { get; } + public char? TopIntersectionChar { get; } + public char? TopRightCornerChar { get; } + public char? LeftIntersectionChar { get; } + public char? MiddleIntersectionChar { get; } + public char? RightIntersectionChar { get; } + public char? BottomLeftCornerChar { get; } + public char? BottomIntersectionChar { get; } + public char? BottomRightCornerChar { get; } public string EmptyBoardLeader { get; } public string DoneBoardLeader { get; } public Func BoardNameMappingToBoardLeader { get; } + #endregion + + private readonly string FinalFailoverString = " "; + + #region Calculated members - // Extracted getter properties that return strings, replacing BoardRenderer.DrawBoards conversion logic [JsonIgnore] - public string TopLeftCornerOrEmpty { + public string TopLeftCorner { get { - if (HasLeftBorder) { - return TopLeftCorner ?? ""; + if (HasLeftBorder && HasTopBorder) { + return TopLeftCornerChar?.ToString() ?? FinalFailoverString; } return ""; } } [JsonIgnore] - public string TopIntersectionOrRowSeparatorOrEmpty { + public string TopIntersection { get { - if (TopIntersection != null) { - return TopIntersection; - } - if (HasColumnSeparators) { - return CellColumnSeparatorOrSpace.ToString(); - } - if (HasRowSeparators) { - return CellRowSeparatorOrSpace.ToString(); + if (HasTopBorder) { + if (HasColumnSeparators) { + return TopIntersectionChar?.ToString() ?? FinalFailoverString; + } else { + return CellRowSeparatorChar?.ToString() ?? FinalFailoverString; + } } return ""; } } [JsonIgnore] - public string TopRightCornerOrEmpty { + public string TopRightCorner { get { - if (HasRightBorder) { - return TopRightCorner ?? ""; + if (HasRightBorder && HasTopBorder) { + return TopRightCornerChar?.ToString() ?? FinalFailoverString; } return ""; } } [JsonIgnore] - public string LeftIntersectionOrEmpty { + public string LeftIntersection { get { if (HasLeftBorder) { - return LeftIntersection ?? ""; + if (HasRowSeparators) { + return LeftIntersectionChar?.ToString() ?? FinalFailoverString; + } else { + return CellColumnSeparatorChar?.ToString() ?? FinalFailoverString; + } } return ""; } } [JsonIgnore] - public string MiddleIntersectionOrColumnSeparatorOrRowSeparatorOrEmpty { + public string MiddleIntersection { get { - if (MiddleIntersection != null) { - return MiddleIntersection; - } - if (HasColumnSeparators) { - return CellColumnSeparatorOrSpace.ToString(); - } - if (HasRowSeparators) { - return CellRowSeparatorOrSpace.ToString(); + if (HasColumnSeparators && HasRowSeparators) { + return MiddleIntersectionChar?.ToString() ?? FinalFailoverString; + } else if (HasRowSeparators) { + return CellRowSeparatorChar?.ToString() ?? FinalFailoverString; + } else if (HasColumnSeparators) { + return CellColumnSeparatorChar?.ToString() ?? FinalFailoverString; } return ""; } } [JsonIgnore] - public string RightIntersectionOrEmpty { + public string RightIntersection { get { if (HasRightBorder) { - return RightIntersection ?? ""; + if (HasRowSeparators) { + return RightIntersectionChar?.ToString() ?? FinalFailoverString; + } else { + return CellColumnSeparatorChar?.ToString() ?? FinalFailoverString; + } } return ""; } } + [JsonIgnore] - public string BottomLeftCornerOrEmpty { + public string BottomLeftCorner { get { - if (HasLeftBorder) { - return BottomLeftCorner ?? ""; + if (HasLeftBorder && HasBottomBorder) { + return BottomLeftCornerChar?.ToString() ?? FinalFailoverString; } return ""; } } [JsonIgnore] - public string BottomIntersectionOrRowSeparatorOrEmpty { + public string BottomIntersection { get { - if (BottomIntersection != null) { - return BottomIntersection; - } - if (HasColumnSeparators) { - return CellColumnSeparatorOrSpace.ToString(); - } - if (HasRowSeparators) { - return CellRowSeparatorOrSpace.ToString(); + if (HasBottomBorder) { + if (HasColumnSeparators) { + return BottomIntersectionChar?.ToString() ?? FinalFailoverString; + } else { + return CellRowSeparatorChar?.ToString() ?? FinalFailoverString; + } } return ""; } } [JsonIgnore] - public string BottomRightCornerOrEmpty { + public string BottomRightCorner { get { - if (HasRightBorder) { - return BottomRightCorner ?? ""; + if (HasRightBorder && HasBottomBorder) { + return BottomRightCornerChar?.ToString() ?? FinalFailoverString; } return ""; } } - // Helper properties for conversion - [JsonIgnore] - public char CellRowSeparatorOrSpace => CellRowSeparator ?? ' '; - [JsonIgnore] - public char CellColumnSeparatorOrSpace => CellColumnSeparator ?? ' '; + public string CellRowSeparator + => HasRowSeparators + ? new string(CellRowSeparatorChar ?? FinalFailoverString[0], CellWidth) + : ""; [JsonIgnore] - public string CellSeparatorSpanString => new string(CellRowSeparatorOrSpace, CellWidth); + public string CellColumnSeparator + => HasColumnSeparators + ? (CellColumnSeparatorChar.ToString() ?? FinalFailoverString) + : ""; - // Extracted properties for configuration analysis [JsonIgnore] - public bool HasTopBorder => TopLeftCorner != null || TopRightCorner != null; + public bool HasTopBorder => TopLeftCornerChar != null || TopRightCornerChar != null; [JsonIgnore] - public bool HasBottomBorder => BottomLeftCorner != null || BottomRightCorner != null; + public bool HasBottomBorder => BottomLeftCornerChar != null || BottomRightCornerChar != null; [JsonIgnore] - public bool HasLeftBorder => TopLeftCorner != null || BottomLeftCorner != null; + public bool HasLeftBorder => TopLeftCornerChar != null || BottomLeftCornerChar != null; [JsonIgnore] - public bool HasRightBorder => TopRightCorner != null || BottomRightCorner != null; + public bool HasRightBorder => TopRightCornerChar != null || BottomRightCornerChar != null; [JsonIgnore] - public bool HasColumnSeparators => TopIntersection != null || MiddleIntersection != null || BottomIntersection != null; + public bool HasColumnSeparators => TopIntersectionChar != null || MiddleIntersectionChar != null || BottomIntersectionChar != null; [JsonIgnore] - public bool HasRowSeparators => LeftIntersection != null || MiddleIntersection != null || RightIntersection != null; + public bool HasRowSeparators => LeftIntersectionChar != null || MiddleIntersectionChar != null || RightIntersectionChar != null; + #endregion // Factory methods for static configurations public static BoardRendererConfiguration FullPipes { get; } = new BoardRendererConfiguration( 3, '│', '─', - "┌", "┬", "┐", - "├", "┼", "┤", - "└", "┴", "┘", + '┌', '┬', '┐', + '├', '┼', '┤', + '└', '┴', '┘', " ", " ✓", boardName => boardName.PadLeft(2) ); @@ -204,7 +214,7 @@ public string BottomRightCornerOrEmpty { public static BoardRendererConfiguration HashPipes { get; } = new BoardRendererConfiguration( 3, '│', '─', null, null, null, - null, "┼", null, + null, '┼', null, null, null, null, " ", " ✓", boardName => boardName.PadLeft(2) ); From c7e206f08ff677e2ce5c30fdc9b16caf8091c476 Mon Sep 17 00:00:00 2001 From: openhands Date: Sat, 25 Jul 2026 10:31:34 -0400 Subject: [PATCH 3/3] re-add record modifier --- src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs index bfb2fb4..5927085 100644 --- a/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs +++ b/src/MnkeyFog.CommandLine/BoardRendererConfiguration.cs @@ -2,7 +2,7 @@ namespace MnkeyFog.CommandLine; -public class BoardRendererConfiguration { +public record class BoardRendererConfiguration { #region constructors public BoardRendererConfiguration( int cellWidth,