Skip to content

Instantly share code, notes, and snippets.

@QuakePhil
Last active January 2, 2023 11:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save QuakePhil/ef4bf9a722c1c27790119b0959595502 to your computer and use it in GitHub Desktop.
Save QuakePhil/ef4bf9a722c1c27790119b0959595502 to your computer and use it in GitHub Desktop.
Tic-Tac-Toe
/*
Results of my first interaction with chat.openai.com
Some precursor here: https://pastebin.com/00Lvty2b
And here:
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
board := []string{" ", " ", " ", " ", " ", " ", " ", " ", " "}
player := 1
for {
fmt.Println("Current board:")
fmt.Println(board[0] + "|" + board[1] + "|" + board[2])
fmt.Println("-----")
fmt.Println(board[3] + "|" + board[4] + "|" + board[5])
fmt.Println("-----")
fmt.Println(board[6] + "|" + board[7] + "|" + board[8])
fmt.Println("Enter x and y coordinates:")
reader := bufio.NewReader(os.Stdin)
input, _ := reader.ReadString('\n')
coords := strings.Split(strings.TrimSpace(input), " ")
x, _ := strconv.Atoi(coords[0])
y, _ := strconv.Atoi(coords[1])
if player == 1 {
board[(y-1)*3+(x-1)] = "X"
} else {
board[(y-1)*3+(x-1)] = "O"
}
player = 3 - player
}
}
*/
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
var t tictactoe
func init() {
t.winning = make(map[string]bool)
t.solve("---------", 0)
}
func main() {
t.play()
}
type tictactoe struct {
board string
players []byte
turn int
winning map[string]bool
}
func (t *tictactoe) mark(b string, i int, p byte) string {
return b[:i] + string(p) + b[i+1:]
}
func (t *tictactoe) play() {
for t.playing() {
fmt.Printf("==================\n%s\nYour move %c (a-i)\nor pass (enter) to let AI play: ", t.string(), t.player())
index := t.move()
t.board = t.mark(t.board, index, t.player())
}
}
func (t *tictactoe) playing() bool {
if t.turn == 0 {
t.board = "---------"
t.players = []byte{'-', 'X', 'O'}
t.turn = 1
return true
}
if t.winning[t.board] {
fmt.Printf("==================\n%c wins!\n%s\n", t.player(), t.string())
return false
} else if !strings.Contains(t.board, "-") {
fmt.Printf("==================\nIt's a tie!\n%s\n", t.string())
return false
}
t.turn = 3 - t.turn
return true
}
func (t *tictactoe) solve(board string, index int) {
line := func(board string, x, y, z int) bool {
return board[x] != '-' && board[y] == board[x] && board[z] == board[x]
}
if index == 9 {
for i := 0; i < 3; i++ {
// check rows
if line(board, i*3, i*3+1, i*3+2) {
t.winning[board] = true
return
}
// check columns
if line(board, i, i+3, i+6) {
t.winning[board] = true
return
}
}
// check diagonals
if line(board, 0, 4, 8) || line(board, 2, 4, 6) {
t.winning[board] = true
return
}
return
}
for _, p := range []byte{'X', 'O', '-'} {
t.solve(t.mark(board, index, p), index+1)
}
}
func (t tictactoe) move() (last int) {
index, _, _ := bufio.NewReader(os.Stdin).ReadRune()
index -= 'a'
if index >= 0 && index <= 8 && t.board[int(index)] == '-' {
return int(index)
}
fmt.Println("Thinking...")
blocking := -1
// check for winning/blocking move, looking at more valuable squares last
for _, i := range []int{7, 5, 3, 1, 8, 6, 2, 0, 4} {
if t.board[i] == '-' {
if t.winning[t.mark(t.board, i, t.player())] {
return i
}
if t.winning[t.mark(t.board, i, t.opponent())] {
blocking = i
}
last = i
}
}
if blocking != -1 {
return blocking
}
return
}
func (t tictactoe) string() string {
return fmt.Sprintf("abc: %s\ndef: %s\nghi: %s", t.board[:3], t.board[3:6], t.board[6:])
}
func (t tictactoe) player() byte {
return t.players[t.turn]
}
func (t tictactoe) opponent() byte {
return t.players[3-t.turn]
}
@QuakePhil
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment