HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Tic-Tactics implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationtictactics

Problem

I've tried to take the shortest, simplest path to a C# solution to the Ultimate Tic-Tac-Toe challenge. This implementation plays in the console. I admit the game logic could be hived off into a separate method, but I'm not sure that would be an improvement. I also admit that the fields should be tighter than public, but that's neither here nor there.

I would appreciate feedback on:

  • How readable people find this solution;



  • Any suggestions to make the code more succinct;



  • Any other comments people would care to make.



```
void Main()
{
var mb = new MetaBoard();
var board = -1;
var player = Who.X;
while (WinFor(mb) == Who.Neither && mb.Boards.Any(x => WinFor(x) == Who.Neither)) {
mb.Write();
Console.WriteLine(player + " to play.");
// Choose a board if we've just started or the current board is finished.
while (board == -1 || mb[board] != Who.Neither) board = InputNum("an unfinished board");
var cell = -1;
// Choose an empty cell on the board.
while (cell == -1 || mb.Boards[board][cell] != Who.Neither) cell = InputNum("an empty cell on board " + (board + 1));
Console.WriteLine();
mb.Play(board, cell, player);
// The next board is decided by the cell just played. Swap turns between the players.
board = cell;
player = (player == Who.X ? Who.O : Who.X);
}
mb.Write();
Console.WriteLine(WinFor(mb) + " wins!");
}

static int InputNum(string what) {
var i = -1;
do {
Console.Write("Choose " + what + " [1-9]: ");
} while (!int.TryParse(Console.ReadLine().Trim(), out i) || i Min(board[line[0]], Min(board[line[1]], board[line[2]])))
.FirstOrDefault(who => who != Who.Neither);
}

class Board: IBoard { // A 3x3 grid of cells.
public Who[] Cells = new Who[9];
public Who this[int i] { get { return Cells[i]; } }
public void Play(int i, Who who) { Cells[i] = who; }
}

class MetaBoard: IBoard { // A 3x3

Solution

This doesn't strike me as particularly readable, although it is definitely succinct. Here are a few of the things I noticed that I think could be improved:

-
The name Min() for a method that determines if someone has filled a row is very confusing.

-
WinFor() should be a method on IBoard rather than a static method that takes an IBoard.

-
The variable names in MetaBoard.Write()are also confusing and something like outerRow and innerColumn would be more informative that rr and c.

-
The quadruple foreach loop in the MetaBoard.Write() scares me. I realize what it is doing, but that many nested loops is a code smell. You might want to create a method on IBoard that prints out board contents line-by-line so that you can append them to each other and control when you insert padding and newlines.

-
If you're going to do that, you may consider extracting out a BoardPrinter class or something similar to encapsulate that behavior.

-
The size of the board is hard-coded and although it isn't a requirement, redesigning this to support different-sized boards will make a more flexible design. (I got this idea in a review for my Ultimate Tic-Tac-Toe entry and am happy I re-worked it).

This will require removing Lines and calculating them manually. As a side note, indices for diagonals can be calculated by consecutively adding the (board width + 1) for downward-right and the (board width - 1) for downward-left diagonals. It took me a while to figure that out.

-
The use of Board[] as the type for the MetaBoard.Boards property indicates to me that the IBoard interface is not as useful as it should be (since MetaBoard is tightly coupled to Board). If you pull out the printing so that it can be done line-by-line as I suggested earlier, you could go back to using IBoard. If done carefully, you could nest MetaBoards within MetaBoards (for the Ultimate in Ultimate Tic-Tac-Toe).

-
I don't see where you restrict players from selecting an already completed board.

I know I'm basically ruining the brevity if you implement my comments, but I am impressed with how you managed to keep it so short. It was fun to review, thanks for sharing!

Context

StackExchange Code Review Q#41123, answer score: 8

Revisions (0)

No revisions yet.