Files
2019-10-30 19:41:13 +03:00

159 lines
3.3 KiB
Go

// Copyright © 2018 Inanc Gumus
// Learn Go Programming Course
// License: https://creativecommons.org/licenses/by-nc-sa/4.0/
//
// For more tutorials : https://learngoprogramming.com
// In-person training : https://www.linkedin.com/in/inancgumus/
// Follow me on twitter: https://twitter.com/inancgumus
package main
import (
"bufio"
"fmt"
"io/ioutil"
"os"
"strconv"
"strings"
rainbow "github.com/guineveresaenger/golang-rainbow"
)
const (
maxTurn = 9
// skin options :-)
empty = " "
player1 = " X "
player2 = " O "
header = "---+---+---"
footer = "---+---+---"
separator = "|"
banner = `
~~~~~~~~~~~~~~~
TIC~TAC~TOE
~~~~~~~~~~~~~~~`
)
// -------------------------------------------------
// INITIALIZE THE GAME
// -------------------------------------------------
var (
turn int
won bool
board = [3][3]string{
{empty, empty, empty},
{empty, empty, empty},
{empty, empty, empty},
}
player = player1
// for saving the replay.log
inputs []byte
)
func main() {
rainbow.Rainbow(banner, strings.Count(banner, "\n"))
in := bufio.NewScanner(os.Stdin)
for {
// -------------------------------------------------
// PRINT THE BOARD AND THE PROMPT
// -------------------------------------------------
fmt.Printf("\n %s\n", header)
for _, line := range board {
fmt.Printf(" %s\n", strings.Join(line[:], separator))
fmt.Printf(" %s\n", footer)
}
// -------------------------------------------------
// IS THERE A WINNER? OR IS IT A TIE?
// -------------------------------------------------
for _, m := range [2]string{player1, player2} {
b, mmm := board, strings.Repeat(m, 3)
won = /* horizontals */
strings.Join(b[0][:], "") == mmm ||
strings.Join(b[1][:], "") == mmm ||
strings.Join(b[2][:], "") == mmm ||
/* verticals */
b[0][0]+b[1][0]+b[2][0] == mmm ||
b[0][1]+b[1][1]+b[2][1] == mmm ||
b[0][2]+b[1][2]+b[2][2] == mmm ||
/* diagonals */
b[0][0]+b[1][1]+b[2][2] == mmm ||
b[0][2]+b[1][1]+b[2][0] == mmm
if won {
player = m
break
}
}
if won {
player = strings.TrimSpace(player)
fmt.Printf("\n>>> WINNER: %s\n", player)
break
} else if turn++; turn == maxTurn+1 {
fmt.Printf("\n>>> TIE!\n")
break
}
// -------------------------------------------------
// CHECK THE MOVE AND PLAY
// -------------------------------------------------
// get the input
fmt.Printf("\nPLAYER: %q [1-9]: ", player)
if !in.Scan() {
break
}
// Atoi already return 0 on error; no need to check
// it for the following switch to work
pos, _ := strconv.Atoi(in.Text())
// Save the input for replaying
inputs = append(inputs, byte(pos+48), '\n')
var row int
switch {
case pos >= 1 && pos <= 3:
row = 0
case pos >= 4 && pos <= 6:
row = 1
case pos >= 7 && pos <= 9:
row = 2
default:
fmt.Println("\n>>>", "wrong position!")
continue
}
col := pos - row*3 - 1
if board[row][col] != empty {
fmt.Println("\n>>>", "already played!")
continue
}
// put a mark on the board
board[row][col] = player
// switch to the next player
if player == player1 {
player = player2
} else {
player = player1
}
}
if err := ioutil.WriteFile("replay.log", inputs, 0644); err != nil {
fmt.Fprintf(os.Stderr, "Cannot save replay: %v", err)
}
}