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

175 lines
2.8 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"
"os"
"strconv"
"strings"
)
func main() {
fmt.Println(`
~~~~~~~~~~~~~~~
TIC~TAC~TOE
~~~~~~~~~~~~~~~`)
loop(bufio.NewScanner(os.Stdin))
}
const (
// skin options :-)
emptyMark = "☆"
mark1 = "💀"
mark2 = "🎈"
maxTurn = 9
)
type game struct {
board [][]string
turn int
player string
buf strings.Builder
}
func loop(in *bufio.Scanner) {
g := newGame()
for {
g.prompt()
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())
msg := g.play(pos)
if msg != "" {
fmt.Println("\n>>>", msg)
continue
}
if msg := g.finito(); msg != "" {
fmt.Printf("\n%s%s\n", g, msg)
break
}
g.next()
}
}
func newGame() *game {
return &game{
player: mark1,
board: [][]string{
{emptyMark, emptyMark, emptyMark},
{emptyMark, emptyMark, emptyMark},
{emptyMark, emptyMark, emptyMark},
},
}
}
func (g *game) prompt() {
fmt.Printf("\n%s%s [1-9]: ", g, g.player)
}
func (g *game) String() string {
g.buf.Reset()
g.buf.WriteRune('\n')
g.buf.WriteString("---+----+---\n")
for _, line := range g.board {
g.buf.WriteString(strings.Join(line, " | "))
g.buf.WriteRune('\n')
g.buf.WriteString("---+----+---\n")
}
return g.buf.String()
}
func (g *game) play(pos int) string {
var row int
switch {
case pos >= 7 && pos <= 9:
row = 2
case pos >= 4 && pos <= 6:
row = 1
case pos >= 1 && pos <= 3:
row = 0
default:
return "wrong position"
}
col := pos - row*3 - 1
if g.board[row][col] != emptyMark {
return "already played!"
}
// put the player
g.board[row][col] = g.player
return ""
}
func (g *game) finito() string {
g.turn++
switch {
case g.won():
return fmt.Sprintf("WINNER: %s", g.player)
case g.turn == maxTurn:
return "TIE!"
}
return ""
}
func (g *game) won() (won bool) {
for _, m := range [2]string{mark1, mark2} {
b, mmm := g.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 {
return true
}
}
return false
}
func (g *game) next() {
if g.player == mark1 {
g.player = mark2
} else {
g.player = mark1
}
}