Last active
September 18, 2017 01:47
-
-
Save arthurmco/a1b854bece22a7a21dae7cc040734292 to your computer and use it in GitHub Desktop.
tic tac toe game in go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
) | |
type Board [3][3]rune | |
type Player struct { | |
name string | |
choosenchar rune | |
score uint | |
} | |
func main() { | |
var b Board | |
board_clear(&b) | |
fmt.Println("TicTacToe game") | |
fmt.Print("Your name: ") | |
var name string | |
fmt.Scanln(&name) | |
human := Player{name: name, choosenchar: 'O'} | |
ai := Player{name: "AI", choosenchar: 'X'} | |
for { | |
winner := board_get_winner(&b, &human, &ai) | |
if winner != nil { | |
fmt.Printf("Game Over. %s won!\n", winner.name) | |
break | |
} | |
if board_is_full(&b) { | |
fmt.Println("Game Over. Tie") | |
break | |
} | |
fmt.Printf("%s turn\n", human.name) | |
human_process(&b, &human) | |
board_show(&b) | |
fmt.Println("Computer turn") | |
ai_process(&b, &ai) | |
board_show(&b) | |
} | |
} | |
func board_show(b *Board) { | |
for y := 0; y < 3; y++ { | |
for x := 0; x < 3; x++ { | |
fmt.Print(string(b[y][x])) | |
if x < 2 { | |
fmt.Print(" | ") | |
} else { | |
fmt.Println("") | |
} | |
} | |
} | |
} | |
/* Gets two players. Returns the winner */ | |
func board_get_winner(b *Board, p1, p2 *Player) *Player { | |
p1_diagonal, p2_diagonal := true, true | |
p1_diagonal_rev, p2_diagonal_rev := true, true | |
for y := 0; y < 3; y++ { | |
/* Check for horizontal wins */ | |
if b[y][0] == p1.choosenchar && b[y][1] == p1.choosenchar && b[y][2] == p1.choosenchar { | |
return p1 | |
} | |
if b[y][0] == p2.choosenchar && b[y][1] == p2.choosenchar && b[y][2] == p2.choosenchar { | |
return p2 | |
} | |
for x := 0; x < 3; x++ { | |
/* Check for vertical wins */ | |
if b[0][x] == p1.choosenchar && b[1][x] == p1.choosenchar && b[2][x] == p1.choosenchar { | |
return p1 | |
} | |
if b[0][x] == p2.choosenchar && b[1][x] == p2.choosenchar && b[2][x] == p2.choosenchar { | |
return p2 | |
} | |
/* Check for diagonal wins... differently */ | |
if x == y { | |
p1_diagonal = p1_diagonal && (b[y][x] == p1.choosenchar) | |
p2_diagonal = p2_diagonal && (b[y][x] == p2.choosenchar) | |
p1_diagonal_rev = p1_diagonal_rev && (b[y][2-x] == p1.choosenchar) | |
p2_diagonal_rev = p2_diagonal_rev && (b[y][2-x] == p2.choosenchar) | |
} | |
} | |
} | |
if p1_diagonal || p1_diagonal_rev { | |
return p1 | |
} | |
if p2_diagonal || p2_diagonal_rev { | |
return p2 | |
} | |
return nil | |
} | |
func board_clear(b *Board) { | |
for y := 0; y < 3; y++ { | |
for x := 0; x < 3; x++ { | |
b[y][x] = ' ' | |
} | |
} | |
} | |
func board_is_full(b *Board) bool { | |
for y := 0; y < 3; y++ { | |
for x := 0; x < 3; x++ { | |
if b[y][x] == ' ' { | |
return false | |
} | |
} | |
} | |
return true | |
} | |
func human_process(b *Board, human *Player) { | |
var x, y uint | |
for { | |
fmt.Print("Type wished position (y x): ") | |
num, err := fmt.Scanf("%v %v", &y, &x) | |
if num < 2 { | |
fmt.Println("Error: Invalid format: ", err.Error()) | |
continue | |
} | |
if x >= 3 { | |
num = 0 | |
fmt.Println("xpos too high! Remember that positions start at zero") | |
continue | |
} | |
if y >= 3 { | |
num = 0 | |
fmt.Println("ypos too high! Remember that positions start at zero") | |
continue | |
} | |
if b[y][x] != ' ' { | |
num = 0 | |
fmt.Println("Place already occupied") | |
continue | |
} | |
break | |
} | |
b[y][x] = human.choosenchar | |
} | |
type scoreDest struct { | |
score, desty, destx int | |
} | |
func ai_process(b *Board, ai *Player) { | |
scores := make(map[string]scoreDest) | |
/* Process the 'likeliness' of different possible positions | |
Shows its likeliness, ie, the most likely ones are the ones that have the | |
most number of 'human' choosenchars, because the human might trying to draw | |
a line | |
*/ | |
for y := 0; y < 3; y++ { | |
if b[y][0] != ' ' && b[y][2] != ' ' && b[y][1] == ' ' { | |
fmt.Println(">> Path x1") | |
b[y][1] = ai.choosenchar | |
score := 0 | |
for _, v := range b[y] { | |
if v != ai.choosenchar && v != ' ' { | |
score += 5 | |
} else if v == ai.choosenchar { | |
score += 2 | |
} else { | |
score += 1 | |
} | |
} | |
scores["x1" + string(y)] = scoreDest{score, y, 1} | |
} | |
if b[y][0] != ' ' && b[y][1] != ' ' && b[y][2] == ' ' { | |
fmt.Println(">> Path x2") | |
score := 0 | |
for _, v := range b[y] { | |
if v != ai.choosenchar && v != ' ' { | |
score += 5 | |
} else if v == ai.choosenchar { | |
score += 2 | |
} else { | |
score += 1 | |
} | |
} | |
scores["x2" + string(y)] = scoreDest{score, y, 2} | |
} | |
for x := 0; x < 3; x++ { | |
if b[0][x] != ' ' && b[1][x] != ' ' && b[2][x] == ' ' { | |
fmt.Println(">> Path y1") | |
score := 0 | |
for _, v := range [3]rune{b[0][x], b[1][x], b[2][x]} { | |
if v != ai.choosenchar && v != ' ' { | |
score += 5 | |
} else if v == ai.choosenchar { | |
score += 2 | |
} else { | |
score += 1 | |
} | |
} | |
scores["y1" + string(x)] = scoreDest{score, 2, x} | |
} | |
if b[0][x] != ' ' && b[1][x] == ' ' { | |
fmt.Println(">> Path y2") | |
score := 0 | |
for _, v := range [3]rune{b[0][x], b[1][x], b[2][x]} { | |
if v != ai.choosenchar && v != ' ' { | |
score += 5 | |
} else if v == ai.choosenchar { | |
score += 2 | |
} else { | |
score += 1 | |
} | |
} | |
scores["y2" + string(x)] = scoreDest{score, 1, x} | |
} | |
if b[y][x] == ' ' { | |
fmt.Println(">> Path generic") | |
scores["g" + string(y) + string(x)] = scoreDest{1, y, x} | |
} | |
} | |
} | |
/* Iterate over every score, get the bigger and return them */ | |
var maxscore scoreDest = scoreDest{0, 0, 0} | |
for _, sitem := range scores { | |
if sitem.score > maxscore.score { | |
maxscore = sitem | |
} | |
} | |
if b[maxscore.desty][maxscore.destx] == ' ' { | |
b[maxscore.desty][maxscore.destx] = ai.choosenchar | |
} else { | |
fmt.Println("No more places!") | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment