locked
Tic Tac Toe in Visual Basic RRS feed

  • Question

  • I'm trying to create a game of Tic Tac Toe with the following instructions.

    1. Played between a human and a computer.

    2. Uses two views (a GUI view and a text view using the console).

    3. Uses two controllers( one where the user clicks on the GUI and another where the user uses the keys 1-9 on the keyboard to select a particular square.

    4. Use a module that holds a 2D array to keep track of the state of the game.

    And here's how the game is supposed to go:

    1. Welcome the player and present an empty Tic Tac Toe grid (both on the GUI form and the console).

    2. Indicate in both the console and the GUI that it's X's turn.

    3. The first player picks what position they want either with the keyboard (1-9) or by clicking directly on the GUI.

    4. If the position isn't already filled, then let the computer take it's turn.

    5. If the position is filled, indicate this with a message box or label and must choose again.

    6. If the player now has a winning position, indicate that they won with a message box or label.

    I'm having lots of problems getting this done, especially with the array and creating the console text view.

    Here's the code I have so far:

    Public Class Form1 Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load MessageBox.Show("Welcome to Tic Tac Toe! Would you like to play a game?") gameArray(0, 0) = "1" gameArray(0, 1) = "2" gameArray(0, 2) = "3" gameArray(1, 0) = "4" gameArray(1, 1) = "5" gameArray(1, 2) = "6" gameArray(2, 0) = "7" gameArray(2, 1) = "8" gameArray(2, 2) = "9" End Sub Private Sub printView() Console.WriteLine(Button1.Text & "|" & Button2.Text & "|" & Button3.Text) Console.WriteLine("----------------") Console.WriteLine(Button4.Text & "|" & Button5.Text & "|" & Button6.Text) Console.WriteLine("----------------") Console.WriteLine(Button7.Text & "|" & Button8.Text & "|" & Button9.Text) End Sub Private Sub Form1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles MyBase.KeyPress, Button1.KeyPress Console.WriteLine(e.KeyChar) Select Case e.KeyChar Case "1" Button1.Text = "X" Case "2" Button2.Text = "X" Case "3" Button3.Text = "X" Case "4" Button4.Text = "X" Case "5" Button5.Text = "X" Case "6" Button6.Text = "X" Case "7" Button7.Text = "X" Case "8" Button8.Text = "X" Case "9" Button9.Text = "X" End Select printView() End Sub End Class

    And here is my module with the 2D array:

    Module Module1
        Const intMAX_ROWS As Integer = 2
        Const intMAX_COL As Integer = 2
        Public gameArray(intMAX_ROWS, intMAX_COL) As String
    
        Button1.Text = gameArray(0,0) 
        Button2.Text = gameArray(0,1)
        Button3.Text = gameArray(0,2)
        Button4.Text = gameArray(1,0)
        Button5.Text = gameArray(1,1)
        Button6.Text = gameArray(1,2)
        Button7.Text = gameArray(2,0)
        Button8.Text = gameArray(2,1)
        Button9.Text = gameArray(2,2)
    
    End Module
    Any help would be greatly appreciated.



    Wednesday, April 9, 2014 7:07 AM

Answers

  • I'm still really new to this and have never worked with arrays before (worked with some one dimensional arrays in Java, but I wasn't good at it and have never dealt with either in Visual Basic). I do know that it's a 3X3 grid.

    The display is a 3x3 grid.  That does not mean that the best form of data organisation for the state of the game is 3x3 - maybe it is, maybe it isn't.  There is no particular reason that the display format should dictate how you manage you data - that should be controlled by the processing that you intend to apply to that data.   In this case, the game play that I mentioned is more important than the display.   How do you intend to manage things like selecting the best next move, detecting a winning situation, and working out who the winner is?

    These questions have nothing to do with VB - it's to do with understanding the problem and designing the solution.

    • Proposed as answer by Reed KimbleMVP Wednesday, April 9, 2014 5:01 PM
    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Wednesday, April 9, 2014 8:36 AM
  • As Acamar has stated, using a multidimensional array to store the game state information may or may not be the best way to proceed... and in this case it probably is not.

    While you can still setup an example of a Tic-Tac-Toe game that uses a multidimensional state array for demonstration purposes, the actual logic for a Tic-Tac-Toe game would be easier to implement using simple integers to hold bit-flag values.  You essentially have nine bits of data and all possible "winning combinations" can represented by the integer with that particular bit pattern.  Organizing those nine bits into a grid pattern is simply a conceptual issue which is handled when the output is rendered to the screen (again, as Acamar has stated).

    So just for fun, and because it can't possibly be used as the actual solution to this requirement (if the requirement is to demonstrate multidimensional arrays), here is a simple example of a console program to play Tic-Tac-Toe against an unintelligent AI (the AI simply makes random choices and does not try to actually block the player from winning - you could certainly expand it to do so though).

    Module Module1
    
        'State data is oganized as 9 bits in a 3x3 grid:
        '
        '               084
        '             /
        ' 001 002 004 - 007
        ' 008 016 032 - 056
        ' 064 128 256 - 448
        ' --- --- ---
        ' 073 146 292 \
        '               273
    
        'Moves made for each player can be stored as bit flags.
        Private xSquares As Integer
        Private oSquares As Integer
    
        'A winning series of moves is equal to the sum of the three flag values,
        ' so all possible winning combinations can be predetermined.
        Private wins() As Integer = {7, 56, 448, 73, 146, 292, 84, 273}
        'Computer AI needs a random number generator.
        Private aiRandom As New Random(42)
    
        Sub Main()
            Reset() 'setup the first game
            Dim info As ConsoleKeyInfo = Console.ReadKey 'start reading player input
            Dim aiMoved As Boolean 'if the AI can't move, the game is at a draw
            While Not info.Key = ConsoleKey.Escape 'process the game loop until the player quits
                If info.KeyChar > "0"c AndAlso info.KeyChar <= "9"c Then 'only respond to keys 1-9
                    Dim bit As Integer = Val(info.KeyChar) - 1 'get the bit flag represented by the key number
                    If Not xSquares = (xSquares Or 2 ^ bit) AndAlso Not oSquares = (oSquares Or 2 ^ bit) Then 'only proceed if this is a valid move
                        xSquares = (xSquares Or 2 ^ bit) 'record the move for player 1
                        aiMoved = AiTakeTurn() 'let player 2 take a turn
                    End If
                End If
                DrawGrid() 'update the play view
                Dim winner As Integer = CheckWin() 'check for a winner
                If winner > 0 Then 'if winner is 1 or 2, someone won the game
                    Console.WriteLine()
                    Console.WriteLine(String.Format("Player {0} Wins! (press any key to play again)", winner))
                    Console.ReadKey()
                    Reset()
                ElseIf Not aiMoved Then 'if winner is 0 and the AI can't move, the game is at a draw
                    Console.WriteLine()
                    Console.WriteLine("Draw! (press any key to play again)")
                    Console.ReadKey()
                    Reset()
                End If
                info = Console.ReadKey
            End While
        End Sub
    
        'control player 2
        Private Function AiTakeTurn() As Boolean
            Dim possible As New List(Of Integer)({0, 1, 2, 3, 4, 5, 6, 7, 8}) 'make a list of all possible moves
            While possible.Count > 0 'try to make a move while any possibilities remain
                Dim index As Integer = aiRandom.Next(0, possible.Count) 'generate a random number in range
                Dim bit As Integer = possible(index) 'get the bit flag
                possible.RemoveAt(index) 'remove the possibility
                If Not xSquares = (xSquares Or 2 ^ bit) AndAlso Not oSquares = (oSquares Or 2 ^ bit) Then 'check if the move is valid
                    oSquares = (oSquares Or 2 ^ bit) 'record the move for player 2
                    Return True
                End If
            End While
            Return False
        End Function
    
        Public Function CheckWin() As Integer
            'for each possible winning value, check to see if either player matches the bit flags
            For Each win As Integer In wins
                If xSquares = (xSquares Or win) Then Return 1
                If oSquares = (oSquares Or win) Then Return 2
            Next
            Return 0
        End Function
    
        'draw the play grid of Xs and Os using numbers for squares not yet chosen by a player
        Private Sub DrawGrid()
            For y As Integer = 0 To 2
                For x As Integer = 0 To 2
                    Console.SetCursorPosition(3 + x, 3 + y)
                    Dim idx As Integer = y * 3 + x
                    Dim c As Char
                    If xSquares = (xSquares Or 2 ^ idx) Then
                        c = "X"c
                    ElseIf oSquares = (oSquares Or 2 ^ idx) Then
                        c = "O"c
                    Else
                        c = (idx + 1).ToString.Chars(0)
                    End If
                    Console.Write(c)
                Next
            Next
            Console.SetCursorPosition(3, 7)
            Console.Write("Choose a square: ")
        End Sub
    
        'setup a new game
        Private Sub Reset()
            xSquares = 0
            oSquares = 0
            Console.Clear()
            Console.WriteLine("Let's play TIC-TAC-TOE! (press ESC to quit)")
            DrawGrid()
        End Sub
    End Module
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Wednesday, April 9, 2014 5:00 PM
  • If you look at this thread, near the bottom is a Tic-Tac-Toe game that Iron Razerz posted - it is simple and efficient and should give you some good ideas.

    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Friday, April 11, 2014 3:09 AM

All replies

  • Is this homework?

    Hello. I'm old and retired. I like to program if you could call what I do programming. However I'd like to code for you! If you've got the dime then I've got the time. Call me, landline, @ BR-549.

    Wednesday, April 9, 2014 7:30 AM
  • Not really, I mean it's for a class but not actually for a grade. We're covering 2D arrays and had to write programs as examples of some of the things that could be done with a multidimensional array. Our professor will then take some of his favorites to assign to one of his other classes.
    Wednesday, April 9, 2014 7:36 AM
  • I'm trying to create a game of Tic Tac Toe with the following instructions.

    The task is complex enough to justify a formal design process.

    Your state array needs to represent three values - Blank, X or O. A string array is possible, but an integer array would be simpler.   Better would be an array of enum, which means you can use meaningful labels for the value.   Then you can create and test functions to display this state in GUI and console - that should come before you start coding for user input. 

    You need to consider whether this state array should be 1x9 or 3x3 - it's not obvious.   The GUI display depends on the layout at design time, and displaying a 1x9 array in 3 rows for the console display is trivial, so the display does not dictate a 3x3 format.   It's likely that user input processing and game play (selecting the computer's move, detecting a finsihed game, deciding who won) will dictate the format of the state array, so you need to consider how that is going to work.

    If you buttons are in an array that matches the state array then there will be a 1 to 1 correspondence between array indexes, which will simplify things a lot.

    Wednesday, April 9, 2014 7:56 AM
  • Tanks for all the input. I'm still really new to this and have never worked with arrays before (worked with some one dimensional arrays in Java, but I wasn't good at it and have never dealt with either in Visual Basic). I do know that it's a 3X3 grid. I made the mistake of thinking this was going to be simple and now I've barely gotten anything done and I have to have it turned in by 8 in the morning :-(
    Wednesday, April 9, 2014 8:03 AM
  • I'm still really new to this and have never worked with arrays before (worked with some one dimensional arrays in Java, but I wasn't good at it and have never dealt with either in Visual Basic). I do know that it's a 3X3 grid.

    The display is a 3x3 grid.  That does not mean that the best form of data organisation for the state of the game is 3x3 - maybe it is, maybe it isn't.  There is no particular reason that the display format should dictate how you manage you data - that should be controlled by the processing that you intend to apply to that data.   In this case, the game play that I mentioned is more important than the display.   How do you intend to manage things like selecting the best next move, detecting a winning situation, and working out who the winner is?

    These questions have nothing to do with VB - it's to do with understanding the problem and designing the solution.

    • Proposed as answer by Reed KimbleMVP Wednesday, April 9, 2014 5:01 PM
    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Wednesday, April 9, 2014 8:36 AM
  • This is one of those times when I know what needs to be done, but can't seem to write a program that will actually do it.

    I know that when one user clicks on a button (or presses the corresponding key for the button), the program first has to check if the button has already been clicked and is therefore occupied, if the button has not been clicked, then the program sets the text of the button to an X. This also would then need to put an X in the corresponding index of the array. The program would then have to go through all the possible winning situations to see if the user had a winning move. This would then repeat with the computer taking its turn. This would go back and forth until one of the winning sequence has been matched or until the board and array are full, this would result in a "cat" or a tie.

    It's kind of tedious, but here's what I've come up with to check for a winner.

    Private Sub checkwin()
    
            If (btn1.Text = "X") And (btn2.Text = "X") And (btn3.Text = "X") Then MsgBox("X WINS!")
            If (btn4.Text = "X") And (btn5.Text = "X") And (btn6.Text = "X") Then MsgBox("X WINS!")
            If (btn7.Text = "X") And (btn8.Text = "X") And (btn9.Text = "X") Then MsgBox("X WINS!")
            If (btn1.Text = "X") And (btn4.Text = "X") And (btn7.Text = "X") Then MsgBox("X WINS!")
            If (btn2.Text = "X") And (btn5.Text = "X") And (btn8.Text = "X") Then MsgBox("X WINS!")
            If (btn3.Text = "X") And (btn6.Text = "X") And (btn9.Text = "X") Then MsgBox("X WINS!")
            If (btn1.Text = "X") And (btn5.Text = "X") And (btn9.Text = "X") Then MsgBox("X WINS!")
            If (btn3.Text = "X") And (btn5.Text = "X") And (btn7.Text = "X") Then MsgBox("X WINS!")
    
            If (btn1.Text = "O") And (btn2.Text = "O") And (btn3.Text = "O") Then MsgBox("O WINS!")
            If (btn4.Text = "O") And (btn5.Text = "O") And (btn6.Text = "O") Then MsgBox("O WINS!")
            If (btn7.Text = "O") And (btn8.Text = "O") And (btn9.Text = "O") Then MsgBox("O WINS!")
            If (btn1.Text = "O") And (btn4.Text = "O") And (btn7.Text = "O") Then MsgBox("O WINS!")
            If (btn2.Text = "O") And (btn5.Text = "O") And (btn8.Text = "O") Then MsgBox("O WINS!")
            If (btn3.Text = "O") And (btn6.Text = "O") And (btn9.Text = "O") Then MsgBox("O WINS!")
            If (btn1.Text = "O") And (btn5.Text = "O") And (btn9.Text = "O") Then MsgBox("O WINS!")
            If (btn3.Text = "O") And (btn5.Text = "O") And (btn7.Text = "O") Then MsgBox("O WINS!")
        End Sub

    Wednesday, April 9, 2014 8:49 AM
  • As Acamar has stated, using a multidimensional array to store the game state information may or may not be the best way to proceed... and in this case it probably is not.

    While you can still setup an example of a Tic-Tac-Toe game that uses a multidimensional state array for demonstration purposes, the actual logic for a Tic-Tac-Toe game would be easier to implement using simple integers to hold bit-flag values.  You essentially have nine bits of data and all possible "winning combinations" can represented by the integer with that particular bit pattern.  Organizing those nine bits into a grid pattern is simply a conceptual issue which is handled when the output is rendered to the screen (again, as Acamar has stated).

    So just for fun, and because it can't possibly be used as the actual solution to this requirement (if the requirement is to demonstrate multidimensional arrays), here is a simple example of a console program to play Tic-Tac-Toe against an unintelligent AI (the AI simply makes random choices and does not try to actually block the player from winning - you could certainly expand it to do so though).

    Module Module1
    
        'State data is oganized as 9 bits in a 3x3 grid:
        '
        '               084
        '             /
        ' 001 002 004 - 007
        ' 008 016 032 - 056
        ' 064 128 256 - 448
        ' --- --- ---
        ' 073 146 292 \
        '               273
    
        'Moves made for each player can be stored as bit flags.
        Private xSquares As Integer
        Private oSquares As Integer
    
        'A winning series of moves is equal to the sum of the three flag values,
        ' so all possible winning combinations can be predetermined.
        Private wins() As Integer = {7, 56, 448, 73, 146, 292, 84, 273}
        'Computer AI needs a random number generator.
        Private aiRandom As New Random(42)
    
        Sub Main()
            Reset() 'setup the first game
            Dim info As ConsoleKeyInfo = Console.ReadKey 'start reading player input
            Dim aiMoved As Boolean 'if the AI can't move, the game is at a draw
            While Not info.Key = ConsoleKey.Escape 'process the game loop until the player quits
                If info.KeyChar > "0"c AndAlso info.KeyChar <= "9"c Then 'only respond to keys 1-9
                    Dim bit As Integer = Val(info.KeyChar) - 1 'get the bit flag represented by the key number
                    If Not xSquares = (xSquares Or 2 ^ bit) AndAlso Not oSquares = (oSquares Or 2 ^ bit) Then 'only proceed if this is a valid move
                        xSquares = (xSquares Or 2 ^ bit) 'record the move for player 1
                        aiMoved = AiTakeTurn() 'let player 2 take a turn
                    End If
                End If
                DrawGrid() 'update the play view
                Dim winner As Integer = CheckWin() 'check for a winner
                If winner > 0 Then 'if winner is 1 or 2, someone won the game
                    Console.WriteLine()
                    Console.WriteLine(String.Format("Player {0} Wins! (press any key to play again)", winner))
                    Console.ReadKey()
                    Reset()
                ElseIf Not aiMoved Then 'if winner is 0 and the AI can't move, the game is at a draw
                    Console.WriteLine()
                    Console.WriteLine("Draw! (press any key to play again)")
                    Console.ReadKey()
                    Reset()
                End If
                info = Console.ReadKey
            End While
        End Sub
    
        'control player 2
        Private Function AiTakeTurn() As Boolean
            Dim possible As New List(Of Integer)({0, 1, 2, 3, 4, 5, 6, 7, 8}) 'make a list of all possible moves
            While possible.Count > 0 'try to make a move while any possibilities remain
                Dim index As Integer = aiRandom.Next(0, possible.Count) 'generate a random number in range
                Dim bit As Integer = possible(index) 'get the bit flag
                possible.RemoveAt(index) 'remove the possibility
                If Not xSquares = (xSquares Or 2 ^ bit) AndAlso Not oSquares = (oSquares Or 2 ^ bit) Then 'check if the move is valid
                    oSquares = (oSquares Or 2 ^ bit) 'record the move for player 2
                    Return True
                End If
            End While
            Return False
        End Function
    
        Public Function CheckWin() As Integer
            'for each possible winning value, check to see if either player matches the bit flags
            For Each win As Integer In wins
                If xSquares = (xSquares Or win) Then Return 1
                If oSquares = (oSquares Or win) Then Return 2
            Next
            Return 0
        End Function
    
        'draw the play grid of Xs and Os using numbers for squares not yet chosen by a player
        Private Sub DrawGrid()
            For y As Integer = 0 To 2
                For x As Integer = 0 To 2
                    Console.SetCursorPosition(3 + x, 3 + y)
                    Dim idx As Integer = y * 3 + x
                    Dim c As Char
                    If xSquares = (xSquares Or 2 ^ idx) Then
                        c = "X"c
                    ElseIf oSquares = (oSquares Or 2 ^ idx) Then
                        c = "O"c
                    Else
                        c = (idx + 1).ToString.Chars(0)
                    End If
                    Console.Write(c)
                Next
            Next
            Console.SetCursorPosition(3, 7)
            Console.Write("Choose a square: ")
        End Sub
    
        'setup a new game
        Private Sub Reset()
            xSquares = 0
            oSquares = 0
            Console.Clear()
            Console.WriteLine("Let's play TIC-TAC-TOE! (press ESC to quit)")
            DrawGrid()
        End Sub
    End Module
    


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Wednesday, April 9, 2014 5:00 PM
  • If you look at this thread, near the bottom is a Tic-Tac-Toe game that Iron Razerz posted - it is simple and efficient and should give you some good ideas.

    • Marked as answer by Carl Cai Tuesday, April 15, 2014 7:14 AM
    Friday, April 11, 2014 3:09 AM