split http and parsing VS tictactoe package

This commit is contained in:
Gnieark 2018-07-18 09:05:29 +02:00
parent f153f6e280
commit 84474f8c85
3 changed files with 119 additions and 109 deletions

BIN
goTicTactoeBot Executable file

Binary file not shown.

View File

@ -12,8 +12,10 @@ import (
"net/http" "net/http"
"encoding/json" "encoding/json"
"io/ioutil" "io/ioutil"
"./tictactoe"
) )
//Plate somewhere to put the json encoded map
type Plate struct{ type Plate struct{
Cell00 string `json:"0-0,omitempty"` Cell00 string `json:"0-0,omitempty"`
Cell01 string `json:"0-1,omitempty"` Cell01 string `json:"0-1,omitempty"`
@ -25,8 +27,10 @@ type Plate struct{
Cell21 string `json:"2-1,omitempty"` Cell21 string `json:"2-1,omitempty"`
Cell22 string `json:"2-2,omitempty"` Cell22 string `json:"2-2,omitempty"`
} }
//QuestionMessage Somewhere to put the whole JSON message from botsarena
type QuestionMessage struct { type QuestionMessage struct {
GameId string `json:"game-id,omitempty"` GameID string `json:"game-id,omitempty"`
Action string `json:"action,omitempty"` Action string `json:"action,omitempty"`
Game string `json:"game,omitempty"` Game string `json:"game,omitempty"`
Players int `json:"players,omitempty"` Players int `json:"players,omitempty"`
@ -35,112 +39,6 @@ type QuestionMessage struct {
PlayerIndex int `json:"player-index,omitempty"` PlayerIndex int `json:"player-index,omitempty"`
} }
type Coords struct{
X int
Y int
}
/**
* Give a score to a cell where to play
* @param tmap the grid Values 0 are empty cells
* target. The coords to test
* currentPlayer int. His digit 1 or 2
* @return int the score
*/
func scoreTarget (tmap [3][3] int, target Coords, currentPlayer int) int{
tmap[target.X][target.Y] = currentPlayer
//count the depth
depth :=0
for i := 0; i<3 ; i++{
for j := 0; j<3 ; j++{
if tmap[i][j] > 0 {
depth++
}
}
}
alignments := [8][3]Coords{
{Coords{0,0},Coords{0,1},Coords{0,2}},
{Coords{1,0},Coords{1,1},Coords{1,2}},
{Coords{2,0},Coords{2,1},Coords{2,2}},
{Coords{0,0},Coords{1,0},Coords{2,0}},
{Coords{0,1},Coords{1,1},Coords{2,1}},
{Coords{0,2},Coords{1,2},Coords{2,2}},
{Coords{0,0},Coords{1,1},Coords{2,2}},
{Coords{0,2},Coords{1,1},Coords{2,0}},
}
win:=false
for i:=0; i < len(alignments) ; i++ {
win=true
for j:=0; j < 3 ; j++ {
if tmap[alignments[i][j].X][alignments[i][j].Y] != currentPlayer{
win = false
}
}
if win {
return 100 - depth
}
}
//if it was the last cell
if depth == 9 { return 0}
var newPlayer int
if currentPlayer == 1 {
newPlayer = 2
}else{
newPlayer = 1
}
//recursion there
_ ,nextScore := playOn(tmap,newPlayer)
return -nextScore
}
/**
* return the better cell, and his score where to play
* @param tmap the grid Values 0 are empty cells
* currentPlayer int. His digit 1 or 2
* @return beastCoord,beastScore
*/
func playOn (tmap [3][3]int, currentPlayer int) (Coords,int){
beastScore := -999
beastCoord := Coords{-1,-1}
//scorer les emplacements libres
for i := 0; i < 3; i++ {
for j:= 0; j < 3; j++ {
if tmap[i][j] == 0 {
sc:=scoreTarget(tmap,Coords{i,j},currentPlayer)
if sc > beastScore {
beastScore = sc
beastCoord = Coords{i,j}
}
}
}
}
return beastCoord,beastScore
}
//******** http, and parsing functions *******
func tictactoeSymbolsToInt (symbolToTest string,mySymbol string) int{
switch symbolToTest {
case mySymbol:
return 1
case "":
return 0
case " ":
return 0
default:
return 2
}
}
func parseQuery(w http.ResponseWriter, r *http.Request){ func parseQuery(w http.ResponseWriter, r *http.Request){
@ -174,7 +72,7 @@ func parseQuery(w http.ResponseWriter, r *http.Request){
tmap[2][1] = tictactoeSymbolsToInt(questionMessage.Board.Cell21,questionMessage.You) tmap[2][1] = tictactoeSymbolsToInt(questionMessage.Board.Cell21,questionMessage.You)
tmap[2][2] = tictactoeSymbolsToInt(questionMessage.Board.Cell22,questionMessage.You) tmap[2][2] = tictactoeSymbolsToInt(questionMessage.Board.Cell22,questionMessage.You)
target, score := playOn(tmap, 1) target, score := tictactoe.PlayOn(tmap, 1)
fmt.Fprintf(w, "{\"play\":\"%d-%d\",\"Comment\":\"score %d\"}", target.X, target.Y,score) fmt.Fprintf(w, "{\"play\":\"%d-%d\",\"Comment\":\"score %d\"}", target.X, target.Y,score)
default: default:
@ -183,6 +81,18 @@ func parseQuery(w http.ResponseWriter, r *http.Request){
} }
} }
func tictactoeSymbolsToInt (symbolToTest string,mySymbol string) int{
switch symbolToTest {
case mySymbol:
return 1
case "":
return 0
case " ":
return 0
default:
return 2
}
}
func arena(w http.ResponseWriter, r *http.Request){ func arena(w http.ResponseWriter, r *http.Request){
data, err := ioutil.ReadFile("./arena.html") data, err := ioutil.ReadFile("./arena.html")
if err == nil { if err == nil {
@ -198,3 +108,4 @@ func main() {
http.HandleFunc("/", parseQuery) http.HandleFunc("/", parseQuery)
log.Fatal(http.ListenAndServe(":8080", nil)) log.Fatal(http.ListenAndServe(":8080", nil))
} }

99
tictactoe/tictactoe.go Normal file
View File

@ -0,0 +1,99 @@
/*
* Mini max algorythm for Tictactoe Bot (https://botsArena.tinad.fr or bollosseum)
* By Gnieark https://blog-du-grouik.tinad.fr 2018-06
* I am learning golang it's my first script, don't take it seriously
*/
package tictactoe
//Coords 2D coords
type Coords struct{
X int
Y int
}
/**
* Give a score to a cell where to play
* @param tmap the grid Values 0 are empty cells
* target. The coords to test
* currentPlayer int. His digit 1 or 2
* @return int the score
*/
func scoreTarget (tmap [3][3] int, target Coords, currentPlayer int) int{
tmap[target.X][target.Y] = currentPlayer
//count the depth
depth :=0
for i := 0; i<3 ; i++{
for j := 0; j<3 ; j++{
if tmap[i][j] > 0 {
depth++
}
}
}
alignments := [8][3]Coords{
{Coords{0,0},Coords{0,1},Coords{0,2}},
{Coords{1,0},Coords{1,1},Coords{1,2}},
{Coords{2,0},Coords{2,1},Coords{2,2}},
{Coords{0,0},Coords{1,0},Coords{2,0}},
{Coords{0,1},Coords{1,1},Coords{2,1}},
{Coords{0,2},Coords{1,2},Coords{2,2}},
{Coords{0,0},Coords{1,1},Coords{2,2}},
{Coords{0,2},Coords{1,1},Coords{2,0}},
}
win:=false
for i:=0; i < len(alignments) ; i++ {
win=true
for j:=0; j < 3 ; j++ {
if tmap[alignments[i][j].X][alignments[i][j].Y] != currentPlayer{
win = false
}
}
if win {
return 100 - depth
}
}
//if it was the last cell
if depth == 9 { return 0}
var newPlayer int
if currentPlayer == 1 {
newPlayer = 2
}else{
newPlayer = 1
}
//recursion there
_ ,nextScore := PlayOn(tmap,newPlayer)
return -nextScore
}
// PlayOn return the better cell, and his score where to play
// @param tmap the grid Values 0 are empty cells
// currentPlayer int. His digit 1 or 2
// @return beastCoord,beastScore
func PlayOn (tmap [3][3]int, currentPlayer int) (Coords,int){
beastScore := -999
beastCoord := Coords{-1,-1}
//scorer les emplacements libres
for i := 0; i < 3; i++ {
for j:= 0; j < 3; j++ {
if tmap[i][j] == 0 {
sc:=scoreTarget(tmap,Coords{i,j},currentPlayer)
if sc > beastScore {
beastScore = sc
beastCoord = Coords{i,j}
}
}
}
}
return beastCoord,beastScore
}