Subscribe to The Madman Scribblings        RSS Feed
-----

The Kernal Of Tic-Tac-Toe

Icon Leave Comment
The Kernal Of Tic-Tac-Toe

Kernel Basics
What does the kernel have to do the keep track of a game of Tic-Tac-Toe.
I reckon the following isn't to far off the mark.
Blank board
Current Player = Player 1
While the game is not in a end state
  Await Current Player Move
  Update Board with Current Player's Move
  Check State of Board
    Has Current Player Won? -> End Game( Player (Current Player ) Wins)
    Is the Game Drawn?      -> End Game( Drawn Game )
  Current Player = Which Player is Next? ( Current Player )
End While



Implementing the Kernel
A kernel of Tic-Tac-Toe in 64 LoC ( and most of that is the boiler-plate vb.net needs. )
Yes I now it can be even smaller by in-lining a few methods

Public Class TicTacToe
  Dim _TicTacToeBoard(8) As Markers, _CurrentPlayer As Markers = Markers.Player_1
  Dim _GameState As GameStates = GameStates.Playing

  Private Event GameStateChanged(ticTacToe As TicTacToe, e As GameStateChangedArgs)
  Public Event BoardChanged(sender As TicTacToe, e As BoardChangedEventArgs)
  Public Event PlayerWin(sender As TicTacToe, e As PlayerWinEventArgs)
  Public Event GameDrawn(sender As TicTacToe, e As EventArgs)

  Public Property GameState As GameStates
    Get
      Return _GameState
    End Get
    Private Set(value As GameStates)
      If value = _GameState Then Exit Property
      value = _GameState
      RaiseEvent GameStateChanged(Me, New GameStateChangedArgs())
    End Set
  End Property

  Public Function PlayMove(PlayedBy As Markers, PlayingSquare As Integer) As Boolean
    If (_GameState <> GameStates.Playing) OrElse (_CurrentPlayer <> PlayedBy) Then
      Me.GameState = GameStates.Invalid_State
      Return False
    ElseIf Not ((0 <= PlayingSquare) AndAlso (PlayingSquare <= 8)) OrElse (_TicTacToeBoard(PlayingSquare) <> Markers.Empty) Then
      Me.GameState = GameStates.Invalid_Move
      Return False
    Else
      PlaceMarkerOnToGameBoard(PlayedBy, PlayingSquare)
      Return True
    End If
  End Function

  Private Sub PlaceMarkerOnToGameBoard(PlayedBy As Markers, PlayingSquare As Integer)
    _TicTacToeBoard(PlayingSquare) = PlayedBy
    RaiseEvent BoardChanged(Me, New BoardChangedEventArgs(_TicTacToeBoard.AsEnumerable))
    CheckForPlayerWin(PlayedBy)
    If GameIsDrawn() Then
      Me.GameState = GameStates.Drawn
    Else
      _CurrentPlayer = WhichPlayerIsNext(_CurrentPlayer)
    End If
  End Sub

  Private Function WhichPlayerIsNext(player As Markers) As Markers
    Return If(player = Markers.Player_1, Markers.Player_2, If(player = Markers.Player_2, Markers.Player_1, player))
  End Function

  Private Function GameIsDrawn() As Boolean
    Return Not _TicTacToeBoard.Any(Function(square) square = Markers.Empty)
  End Function

  Private Sub CheckForPlayerWin(player As Markers)
    Dim winLines = {({0, 1, 2}), ({3, 4, 5}), ({6, 7, 8}), ({0, 3, 6}), ({1, 4, 7}), ({2, 5, 8}), ({0, 4, 8}), ({2, 4, 6})}
    Dim winningLines As New List(Of Integer())(winLines.Where(Function(WinningLine) CheckLine(player, WinningLine)))
    If winningLines.Any Then
      Me.GameState = If(player = Markers.Player_1, GameStates.Win_Player1, If(player = Markers.Player_2, GameStates.Win_Player2, GameStates.Invalid_State))
      RaiseEvent PlayerWin(Me, New PlayerWinEventArgs(player, winningLines))
    End If
  End Sub

  Private Function CheckLine(player As Markers, ParamArray squares() As Integer) As Boolean
    Return squares.All(Function(sqr) _TicTacToeBoard(sqr) = player)
  End Function

  Private Sub TicTacToe_GameStateChanged(ticTacToe As TicTacToe, e As GameStateChangedArgs) Handles Me.GameStateChanged
    If CType(ticTacToe, TicTacToe).GameState = GameStates.Drawn Then RaiseEvent GameDrawn(Me, EventArgs.Empty)
  End Sub

  Private Sub TicTacToe_PlayerWin(sender As Object, e As PlayerWinEventArgs) Handles Me.PlayerWin
    If e.Player = Markers.Player_1 Then Me.GameState = GameStates.Win_Player1
    If e.Player = Markers.Player_2 Then Me.GameState = GameStates.Win_Player2
  End Sub

End Class



Spoiler


Next Time:- Implementing a Game Controller on top it, so we can play an actual game.

0 Comments On This Entry