G5KXCVILVVZVQAAVLZQJ2OKJ6LHNICSSKLDNCA3LXVUAMPWJDYRQC package tictactoeimport ("fmt""os")const debug = true// WinSize sets how many we need next to each otherconst WinSize = 3// Runes for record typesconst (Empty rune = '_'Pl1 rune = 'x'Pl2 rune = 'o')func debugPrinter(format string, a ...interface{}) {if debug {fmt.Fprintf(os.Stderr, format+"\n", a...)}}
package tictactoeimport ("math""testing""github.com/stretchr/testify/assert")func TestMinimax(t *testing.T) {var testCases = []struct {scores []intexpected int}{{[]int{3, 5}, 5},{[]int{3, 5, 2, 9}, 3},{[]int{3, 5, 2, 9, 12, 5, 23, 23}, 12},{[]int{3, 5, 2, 9, 1, 2, 3}, 3},}for _, tc := range testCases {height := math.Log2(float64(len(tc.scores)))t.Run("Minimax", func(t *testing.T) {//debugPrinter("len(scores): %d, height: %v int(height): %d", len(tc.scores), height, int(height))assert.Equal(t, tc.expected, minimax(0, 0, true, tc.scores, int(height)))})}}
package tictactoe// minimax is for retrieving the optimal value for maximizer// depth is the current depth in the game tree// nodeIndex is the current index of node in scores// scores stores the Game Tree// isMax is true if the current move is a maximizer// height is the max height of the Game Treefunc minimax(depth, nodeIndex int, isMax bool, scores []int, height int) int {// terminate if end of the tree reachedif depth == height {return scores[nodeIndex]}if isMax {left := minimax(depth+1, nodeIndex*2, false, scores, height)right := minimax(depth+1, nodeIndex*2+1, false, scores, height)return max(left, right)} else {left := minimax(depth+1, nodeIndex*2, true, scores, height)right := minimax(depth+1, nodeIndex*2+1, true, scores, height)return min(left, right)}}func max(a, b int) int {if a > b {return a}return b}func min(a, b int) int {if a < b {return a}return b}
module tictactoego 1.15require github.com/stretchr/testify v1.6.1
package tictactoeimport ("testing""github.com/stretchr/testify/assert")func TestEvaluate(t *testing.T) {var testCases = []struct {description stringboard [][]runeexpected int}{{"Nothing", [][]rune{{Pl1, Pl1, Pl2}, {Empty, Empty, Empty}, {Empty, Empty, Empty}}, 0},{"Pl1 row", [][]rune{{Pl1, Pl1, Pl1}, {Empty, Empty, Empty}, {Empty, Empty, Empty}}, 10},{"Pl2 col", [][]rune{{Pl1, Pl1, Pl1}, {Pl2, Empty, Empty}, {Pl2, Empty, Empty}}, -10},{"Pl1 diag", [][]rune{{Pl2, Pl1, Pl1}, {Empty, Pl1, Empty}, {Pl1, Empty, Empty}}, 10},}for _, tc := range testCases {t.Run("Evaluate"+tc.description, func(t *testing.T) {assert.Equal(t, tc.expected, evaluate(tc.board))})}}
package tictactoefunc evaluate(board [][]rune) int {for row := range board {for col := range board[row] {if checkRow(board, row, col, WinSize, Pl1) == WinSize {return +10} else if checkRow(board, row, col, WinSize, Pl2) == WinSize {return -10}if checkCol(board, row, col, WinSize, Pl1) == WinSize {return +10} else if checkCol(board, row, col, WinSize, Pl2) == WinSize {return -10}if checkDiag(board, row, col, WinSize, Pl1) == WinSize {return +10} else if checkDiag(board, row, col, WinSize, Pl2) == WinSize {return -10}}}return 0}func checkRow(board [][]rune, row, col, winsize int, player rune) (goodness int) {for i := 0; i < winsize; i++ {if row+i < len(board[col]) {if board[row+i][col] == player {goodness++} else {return goodness}}}return goodness}func checkCol(board [][]rune, row, col, winsize int, player rune) (goodness int) {for j := 0; j < winsize; j++ {if col+j < len(board[row]) {if board[row][col+j] == player {goodness++} else {return goodness}}}return goodness}func checkDiag(board [][]rune, row, col, winsize int, player rune) (goodness int) {for k := 0; k < winsize; k++ {if row+k < len(board[col]) && col+k < len(board[row]) {if board[row+k][col+k] == player {goodness++} else {return goodness}}}return goodness}
for k := 0; k < len(str)/2+1; k++ {if k > 0 {go palWorker(str, k, results)jobs++}
for k := 1; k < len(str)/2+1; k++ {wg.Add(1)go func(char string, num int) {defer wg.Done()results <- palWorker(char, num)}(str, k)
for {select {case candidate := <-results:jobs--if len(candidate) > len(longest) {longest = candidate}if jobs == 0 {close(results)return longest}
go func() {wg.Wait()close(results)}()for candidate := range results {if len(candidate) > len(longest) {longest = candidate