Introduction
This is an implementation of the game Tic-Tac-Toe, written in C#.
Background
I wrote this program as a basic exercise to improve my coding skills. It is admittedly quite simple, but since I am a novice programmer, it was adequately challenging. This article is intended for other novices who are interested in board games and/or Windows Forms, but looking for a simple example to get them started.
If you are not a novice, but you'd like to look at my code and provide constructive criticism, please do! I am not receiving any formal instruction, so any feedback you provide will be greatly appreciated.
Using the code
Simply compile the source files and run the resulting executable. Try resizing the window.
Points of Interest
Program Structure
The program is divided into three classes: Board
, SquareControl
, and TicTacToe
.
The Board class
The game board is represented by a two-dimensional integer array. The public field BoardState
denotes whether the game is in progress, and if not, what the previous outcome was. The possible values for BoardState
are defined by the GameState
enumeration. The public field iEmptySquares
keeps count of the empty squares on the board to facilitate the detection of a draw.
The Board
class provides two public constructors. One creates a new, empty board, while the other creates a new board by copying an existing one. The second constructor is used during the game by the AI.
The CheckBoard()
method is used to check the board for a winner after every call to MakeMove()
.
The SquareControl class
This class inherits from UserControl
, and is used to represent each square in the UI. The OnPaint()
method is overridden.
Initially, I had a flickering problem with SquareControl
objects. To resolve this, I set up double-buffering in the OnPaint()
method. The most commonly prescribed method for double-buffering in Windows Forms involves several calls to the SetStyles()
method to set up automatic double-buffering. However, this didn't work for me, so I did it this way:
Graphics buffer = Graphics.FromImage(bmpBackBuffer);
buffer.SmoothingMode = SmoothingMode.AntiAlias;
Graphics viewable = pea.Graphics;
viewable.DrawImageUnscaled(bmpBackBuffer, 0, 0);
The TicTacToe class
This class represents the main (and only) form of the program. TicTacToe
contains several methods for controlling the game play. For example, the MakeMove()
method is responsible for applying a given move to the Board
object and the appropriate SquareControl
. The Reset()
method is used to reset the Board
and SquareControl
objects in preparation for a new game. TicTacToe
also contains the AI code.
Game AI
The GetBestMove()
method employs the Minimax look-ahead algorithm to determine the best possible move for the computer player. Alpha-beta pruning is used to increase performance. A Google search will turn up plenty of information on this topic.
The look-ahead is executed in a worker thread in order to avoid hanging the UI during the search. When the search is completed, the worker thread makes a callback to the main thread to apply the new move. Check the CalculateComputerMove()
and MakeComputerMove()
methods to see how this is done.
Because the search space for a 3x3 Tic-Tac-Toe game is relatively small, I decided not to limit the depth of the search. This simplified the scoring system used during the look-ahead. In order to adapt the algorithm to boards any larger, a depth limit and a new evaluation function would need to be implemented. You may notice that the computer player occasionally chooses to forgo an immediate win, but only to fork you so that you lose on the computer's next move anyway. I thought about adding a preference to win as soon as possible, but I decided that this behavior was cute.
History
No updates so far.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.