Skip to content

Instantly share code, notes, and snippets.

@ifnotak
Last active January 3, 2024 23:09
Show Gist options
  • Save ifnotak/bff3cb779c337274d2a3462c630f4d74 to your computer and use it in GitHub Desktop.
Save ifnotak/bff3cb779c337274d2a3462c630f4d74 to your computer and use it in GitHub Desktop.
Tic Tac Toe Golang Implementation
/* Original work Copyright (c), March 2019
* Abdullah G. Khalil <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*/
package main
import (
"fmt"
"log"
"os"
"os/exec"
)
const (
playerX int8 = -1 // Player X
playerO int8 = 1 // Player O
)
type ticTacToe struct {
board [][]int8
size uint8
}
func main() {
t := newTicTacToe()
t.play()
}
func newTicTacToe() (t ticTacToe) {
// Read board size
fmt.Printf("Enter board size: ")
_, err := fmt.Scan(&t.size)
if err != nil {
log.Fatal(err)
}
if t.size < 3 {
log.Fatal("Too small for a Tic Tac Toe board!")
}
// Supports up to MAX(SIZE) = MAX(UINT8) = 255
if t.size > 30 { // 30 is reasonable
log.Fatal("Too big for your time and possibly your screen!")
}
t.board = make([][]int8, t.size)
for i := range t.board {
t.board[i] = make([]int8, t.size)
}
return
}
func (t ticTacToe) win(r, c uint8) (win int8) {
var rSum, cSum, dSum, adSum int8
for i := range t.board {
// Check row
if i == int(r) {
for _, v := range t.board[r] {
rSum += v
}
}
// Check column
cSum += t.board[i][c]
// Check diagonal, if part of diagonal
if r == c {
dSum += t.board[i][i]
}
// Check anti-diagonal, if part of anti-diagonal,
if r+c == t.size-1 {
adSum += t.board[i][int(t.size)-1-i]
}
}
if rSum == int8(t.size) || cSum == int8(t.size) || dSum == int8(t.size) || adSum == int8(t.size) {
return playerO
}
if -rSum == int8(t.size) || -cSum == int8(t.size) || -dSum == int8(t.size) || -adSum == int8(t.size) {
return playerX
}
return
}
func (t ticTacToe) readPlayer(player uint8) (r, c uint8, err error) {
var p string
if player == 0 {
p = "X"
} else {
p = "O"
}
fmt.Printf("Player %s, choose cell: ", p)
var cell uint16
_, err = fmt.Scan(&cell)
if err != nil {
log.Fatal(err)
}
if cell == 0 || cell > uint16(t.size)*uint16(t.size) {
err = fmt.Errorf("Value must be between 1 & %d", uint16(t.size)*uint16(t.size))
return
}
cell--
r = uint8(cell / uint16(t.size)) // row
c = uint8(cell % uint16(t.size)) // col
if t.board[r][c] != 0 {
err = fmt.Errorf("Call is already occupied")
return
}
if player == 0 {
t.board[r][c] = playerX
} else {
t.board[r][c] = playerO
}
return
}
func (t ticTacToe) play() {
count := uint8(0)
var err error
for {
fmt.Println(t)
if err != nil {
fmt.Println(err)
}
var r, c uint8
r, c, err = t.readPlayer(count % 2)
if err != nil {
continue
}
count++
// No player will win before at least (size*2)-1 plays
if count < (t.size*2)-1 {
continue
}
// If number of plays is equal to board size,
// and no player has won, then it's a Draw!
if uint16(count) == uint16(t.size)*uint16(t.size) {
fmt.Println(t)
fmt.Println("Draw!")
return
}
win := t.win(r, c)
if win != 0 {
fmt.Println(t)
if win == playerX {
fmt.Println("Player X won!")
} else {
fmt.Println("Player O won!")
}
return
}
}
}
func (t ticTacToe) String() (s string) {
clearLinux()
for r := range t.board {
for c := range t.board[r] {
if t.board[r][c] == playerX {
s += fmt.Sprint(" X ")
} else if t.board[r][c] == playerO {
s += fmt.Sprint(" O ")
} else {
s += fmt.Sprintf("%03d ", (int(r)*int(t.size))+int(c)+1)
}
}
s += "\n\n"
}
return
}
func clearLinux() {
cmd := exec.Command("clear")
cmd.Stdout = os.Stdout
cmd.Run()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment