Tic-Tac-Toe Game GoLang Implementation
June 23, 2021 • ☕️ 3 min read • 🏷 computer, software
Translated by author into: English
Tic-Tac-Toe (sometimes known as X and O) is a game in which two players try to draw a row, column or diagonal on a 3x3 board using their symbols (X and O).
Players take turns making moves and try to line up their symbols horizontally, vertically or diagonally. Whoever can rank wins the game or the game ends in a draw :)
Below is the code that enables the tic-tak-toe game in GoLang to be played by two people on the console:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
const (
empty = " "
x = "X"
o = "O"
)
type game struct {
board [][]string
}
// newGame returns a created game object.
func newGame() *game {
g := &game{}
g.board = make([][]string, 3)
for i := range g.board {
g.board[i] = make([]string, 3)
for j := range g.board[i] {
g.board[i][j] = empty
}
}
return g
}
// playMove makes the move a player would make on the board.
func (g *game) playMove(x, y int, player string) error {
if x < 0 || x > 2 || y < 0 || y > 2 {
return fmt.Errorf("Invalid move")
}
if g.board[x][y] != empty {
return fmt.Errorf("That space is already taken")
}
g.board[x][y] = player
return nil
}
// drawBoard is used to draw the board.
func (g *game) drawBoard() {
fmt.Println(" 0 1 2")
for i, row := range g.board {
fmt.Printf("%d ", i)
fmt.Println(strings.Join(row, "|"))
}
}
// checkWin checks if there is a winner.
func (g *game) checkWin() string {
// Check rows
for _, row := range g.board {
if row[0] != empty && row[0] == row[1] && row[1] == row[2] {
return row[0]
}
}
// Check columns
for i := 0; i < 3; i++ {
if g.board[0][i] != empty && g.board[0][i] == g.board[1][i] && g.board[1][i] == g.board[2][i] {
return g.board[0][i]
}
}
// Check diagonals
if g.board[0][0] != empty && g.board[0][0] == g.board[1][1] && g.board[1][1] == g.board[2][2] {
return g.board[0][0]
}
if g.board[0][2] != empty && g.board[0][2] == g.board[1][1] && g.board[1][1] == g.board[2][0] {
return g.board[0][2]
}
return empty
}
func main() {
g := newGame()
reader := bufio.NewReader(os.Stdin)
fmt.Println("Welcome to Tic-Tac-Toe!")
fmt.Println("Player 1 is X and Player 2 is O")
fmt.Println("Enter your moves in the format 'x y' (without quotes)")
for i := 0; i < 9; i++ {
player := x
if i%2 == 1 {
player = o
}
fmt.Printf("Player %s's turn: ", player)
text, _ := reader.ReadString('\n')
text = strings.TrimSpace(text)
parts := strings.Split(text, " ")
if len(parts) != 2 {
fmt.Println("Invalid input")
i--
continue
}
x, err := strconv.Atoi(parts[0])
if err != nil {
fmt.Println("Invalid input")
i--
continue
}
y, err := strconv.Atoi(parts[1])
if err != nil {
fmt.Println("Invalid input")
i--
continue
}
err = g.playMove(x, y, player)
if err != nil {
fmt.Println(err)
i--
continue
}
g.drawBoard()
winner := g.checkWin()
if winner != empty {
fmt.Printf("Player %s wins!\n", winner)
break
}
}
if g.checkWin() == empty {
fmt.Println("It's a draw!")
}
}
When the program is run, it will give an output like the one below. Players enter the coordinates into the console to make their moves. For example, if a player (X) wants to move to the point (0, 1) on the board, he enters “0 1” (without spaces and quotes). The board updates and the next player tries to make a move. The game continues and if a player wins by drawing their three symbols on the board or if all squares are filled and the game ends in a draw.
Example game
> go run main.go
Welcome to Tic-Tac-Toe!
Player 1 is X and Player 2 is O
Enter your moves in the format 'x y' (without quotes)
Player X's turn: 0 1
0 1 2
0 |X|
1 | |
2 | |
Player O's turn: 1 1
0 1 2
0 |X|
1 |O|
2 | |
Player X's turn: 2 0
0 1 2
0 |X|
1 |O|
2 X| |
Player O's turn: 0 0
0 1 2
0 O|X|
1 |O|
2 X| |
Player X's turn: 2 1
0 1 2
0 O|X|
1 |O|
2 X|X|
Player O's turn: 2 2
0 1 2
0 O|X|
1 |O|
2 X|X|O
Player O wins!