Ostatnio aktywny 1750245234

Hazel's Avatar Hazel zrewidował ten Gist 1750245234. Przejdź do rewizji

1 file changed, 264 insertions

tictactoe_bot_dynamic_size(stworzono plik)

@@ -0,0 +1,264 @@
1 + package main
2 +
3 + import (
4 + "fmt"
5 + "strconv"
6 + "strings"
7 + )
8 +
9 + const (
10 + cellEmpty = " "
11 + cellUser = "U"
12 + cellBot = "B"
13 + )
14 +
15 + func boardToString(board [][]string) string {
16 + maxRowLength := 0
17 + rowStrings := make([]string, len(board)+1)
18 + for i, row := range board {
19 + if len(row) > maxRowLength {
20 + maxRowLength = len(row)
21 + }
22 +
23 + rowIndex := strconv.Itoa(i)
24 + if i < 10 {
25 + rowIndex += " "
26 + }
27 + rowStrings[i+1] = rowIndex + strings.Join(row, "|")
28 + }
29 +
30 + columnIndices := make([]string, maxRowLength)
31 + for i := 0; i < maxRowLength; i++ {
32 + rowIndex := strconv.Itoa(i)
33 + if i < 10 {
34 + rowIndex = " " + rowIndex
35 + }
36 + columnIndices[i] = rowIndex
37 + }
38 + rowStrings[0] = "/" + strings.Join(columnIndices, "")
39 +
40 + return strings.Join(rowStrings, "\n")
41 + }
42 +
43 + func createBoard(size int) [][]string {
44 + board := make([][]string, size)
45 +
46 + for r := 0; r < size; r++ {
47 + rowSlice := make([]string, size)
48 + for i := range rowSlice {
49 + rowSlice[i] = cellEmpty
50 + }
51 +
52 + board[r] = rowSlice
53 + }
54 +
55 + return board
56 + }
57 +
58 + func changeCellUserInput(board *[][]string) {
59 + var row *[]string
60 +
61 + for {
62 + var rowIndex int
63 + fmt.Print("row: ")
64 + fmt.Scanln(&rowIndex)
65 +
66 + if 0 <= rowIndex && rowIndex < len(*board) {
67 + row = &(*board)[rowIndex]
68 + break
69 + } else {
70 + fmt.Println("The value needs to be in the range of the board rows.")
71 + continue
72 + }
73 + }
74 +
75 + for {
76 + var colIndex int
77 + fmt.Print("col: ")
78 + fmt.Scanln(&colIndex)
79 +
80 + if 0 <= colIndex && colIndex < len(*row) {
81 + if (*row)[colIndex] != " " {
82 + fmt.Println("This cell is already occupied.")
83 + defer changeCellUserInput(board)
84 + break
85 + }
86 +
87 + (*row)[colIndex] = cellUser
88 + break
89 + } else {
90 + fmt.Println("The value needs to be in the range of the board columns.")
91 + continue
92 + }
93 + }
94 + }
95 +
96 + func getWinningCombinations(board *[][]string) [][]*string {
97 + // there are 8 winning combinations in total
98 + winningCombinations := make([][]*string, len(*board)*2+2)
99 +
100 + // board_size row wins | board_size col wins
101 + for i, _ := range *board {
102 + row := make([]*string, len(*board))
103 + col := make([]*string, len(*board))
104 +
105 + for j, _ := range *board {
106 + row[j] = &(*board)[i][j]
107 + col[j] = &(*board)[j][i]
108 + }
109 +
110 + winningCombinations[i*2] = row
111 + winningCombinations[i*2+1] = col
112 + }
113 +
114 + // 2 vertical wins
115 + a := make([]*string, len(*board))
116 + b := make([]*string, len(*board))
117 + for i, _ := range *board {
118 + a[i] = &(*board)[i][i]
119 + b[i] = &(*board)[i][len(*board)-i-1]
120 + }
121 + winningCombinations[len(*board)*2] = a
122 + winningCombinations[len(*board)*2+1] = b
123 +
124 + return winningCombinations
125 + }
126 +
127 + type combinationStat struct {
128 + totalCells int
129 + emptyCells int
130 + userCells int
131 + botCells int
132 +
133 + isWinnable bool
134 + emptyCellRefs []*string
135 + }
136 +
137 + func calculateCombinationStats(combination []*string) combinationStat {
138 + c := combinationStat{}
139 +
140 + for _, cell := range combination {
141 + c.totalCells++
142 + switch *cell {
143 + case cellEmpty:
144 + c.emptyCells++
145 + c.emptyCellRefs = append(c.emptyCellRefs, cell)
146 + case cellBot:
147 + c.botCells++
148 + case cellUser:
149 + c.userCells++
150 + }
151 + }
152 +
153 + c.isWinnable = c.userCells == 0 || c.botCells == 0
154 +
155 + return c
156 + }
157 +
158 + func changeCellBotInput(winningCombinations [][]*string) {
159 + combinationStats := make([]combinationStat, len(winningCombinations))
160 + for i, combination := range winningCombinations {
161 + combinationStats[i] = calculateCombinationStats(combination)
162 + }
163 +
164 + // now count the still possible wins each pointer has
165 + cellScores := make(map[*string]int)
166 + for _, c := range combinationStats {
167 + score := 0
168 + if c.userCells == 0 {
169 + score = 1 + (c.totalCells - c.emptyCells)
170 + } else if c.botCells == 0 {
171 + score = c.totalCells - c.emptyCells
172 + }
173 +
174 + for _, emptyCell := range c.emptyCellRefs {
175 + cellScores[emptyCell] += score * score
176 + }
177 + }
178 +
179 + bestCellScore := 0
180 + var bestCell *string
181 + for cell, cellScore := range cellScores {
182 + if cellScore > bestCellScore {
183 + bestCellScore = cellScore
184 + bestCell = cell
185 + }
186 + }
187 +
188 + *bestCell = cellBot
189 + }
190 +
191 + type boardData struct {
192 + isWin bool
193 + isPat bool
194 +
195 + winningUser string
196 + }
197 +
198 + func analyzeWin(winningCombinations [][]*string) boardData {
199 + b := boardData{}
200 +
201 + winnable := false
202 + for _, combination := range winningCombinations {
203 + c := calculateCombinationStats(combination)
204 +
205 + if c.botCells == c.totalCells {
206 + b.isWin = true
207 + b.winningUser = cellBot
208 + return b
209 + }
210 + if c.userCells == c.totalCells {
211 + b.isWin = true
212 + b.winningUser = cellUser
213 + return b
214 + }
215 +
216 + if c.botCells == 0 || c.userCells == 0 {
217 + winnable = true
218 + }
219 + }
220 +
221 + if !winnable {
222 + b.isPat = true
223 + }
224 +
225 + return b
226 + }
227 +
228 + func main() {
229 + board := createBoard(4)
230 + winningCombinations := getWinningCombinations(&board)
231 +
232 + currentUser := 0
233 + for {
234 + fmt.Println()
235 + fmt.Println(boardToString(board))
236 +
237 + bd := analyzeWin(winningCombinations)
238 + if bd.isWin {
239 + fmt.Println()
240 + switch bd.winningUser {
241 + case cellBot:
242 + fmt.Println("THE BOT WINS!!")
243 + case cellUser:
244 + fmt.Println("CONGRATULATION, YOU WIN!!")
245 + }
246 + break
247 + }
248 + if bd.isPat {
249 + fmt.Println()
250 + fmt.Println("GAME OVER. NEITHER ONE WON")
251 + break
252 + }
253 +
254 + if currentUser == 0 {
255 + fmt.Println()
256 + fmt.Println("it's your turn human")
257 + changeCellUserInput(&board)
258 + } else {
259 + changeCellBotInput(winningCombinations)
260 + }
261 +
262 + currentUser = (currentUser + 1) % 2
263 + }
264 + }
Nowsze Starsze