Last active 1750171421

Hazel's Avatar Hazel revised this gist 1750171420. Go to revision

1 file changed, 261 insertions

ticktacktoe.go(file created)

@@ -0,0 +1,261 @@
1 + package main
2 +
3 + import (
4 + "fmt"
5 + "strconv"
6 + "strings"
7 + )
8 +
9 + const (
10 + skipBoardCreation = false
11 + skipUserCreation = false
12 + )
13 +
14 + func createBoard(size int) [][]string {
15 + board := make([][]string, size)
16 +
17 + for r := 0; r < size; r++ {
18 + rowSlice := make([]string, size)
19 + for i := range rowSlice {
20 + rowSlice[i] = " "
21 + }
22 +
23 + board[r] = rowSlice
24 + }
25 +
26 + return board
27 + }
28 +
29 + func getBoardDimensions(board [][]string) (rows, columns int) {
30 + rows = len(board)
31 + columns = 0
32 +
33 + for _, row := range board {
34 + if len(row) > columns {
35 + columns = len(row)
36 + }
37 + }
38 +
39 + return
40 + }
41 +
42 + func boardToString(board [][]string) string {
43 + maxRowLength := 0
44 + rowStrings := make([]string, len(board)+1)
45 + for i, row := range board {
46 + if len(row) > maxRowLength {
47 + maxRowLength = len(row)
48 + }
49 +
50 + rowIndex := strconv.Itoa(i)
51 + if i < 10 {
52 + rowIndex += " "
53 + }
54 + rowStrings[i+1] = rowIndex + strings.Join(row, "|")
55 + }
56 +
57 + columnIndices := make([]string, maxRowLength)
58 + for i := 0; i < maxRowLength; i++ {
59 + rowIndex := strconv.Itoa(i)
60 + if i < 10 {
61 + rowIndex = " " + rowIndex
62 + }
63 + columnIndices[i] = rowIndex
64 + }
65 + rowStrings[0] = "/" + strings.Join(columnIndices, "")
66 +
67 + return strings.Join(rowStrings, "\n")
68 + }
69 +
70 + func createBoardUserInput() [][]string {
71 + var size int
72 + for {
73 + fmt.Print("canvas size? ")
74 + fmt.Scanln(&size)
75 + if size < 100 {
76 + return createBoard(size)
77 + } else {
78 + fmt.Println("There can't be more than 99 rows.")
79 + }
80 + }
81 + }
82 +
83 + func createUsersUserInput() []string {
84 + users := []string{}
85 + existingUsers := map[string]bool{}
86 +
87 + fmt.Println("Add users to the game. Users are a single alphabetical char.\nIf you're done submit an empty user.")
88 + for {
89 + fmt.Print("new user: ")
90 + var input string
91 + fmt.Scanln(&input)
92 + input = strings.Trim(input, " \n")
93 +
94 + if len(input) == 0 {
95 + if len(users) == 0 {
96 + fmt.Println("You need to add at least one user.")
97 + } else {
98 + break
99 + }
100 + }
101 +
102 + if len(input) == 1 {
103 + newUser := strings.ToUpper(input)
104 + if _, ok := existingUsers[newUser]; ok {
105 + fmt.Println("This user already exists.")
106 + } else {
107 + existingUsers[newUser] = false
108 + users = append(users, newUser)
109 + }
110 + } else {
111 + fmt.Println("The input can only be one character.")
112 + }
113 + }
114 + return users
115 + }
116 +
117 + func changeCellUserInput(board [][]string, user string) {
118 + var row []string
119 +
120 + for {
121 + var rowIndex int
122 + fmt.Print("row: ")
123 + fmt.Scanln(&rowIndex)
124 +
125 + if 0 <= rowIndex && rowIndex < len(board) {
126 + row = board[rowIndex]
127 + break
128 + } else {
129 + fmt.Println("The value needs to be in the range of the board rows.")
130 + continue
131 + }
132 + }
133 +
134 + for {
135 + var colIndex int
136 + fmt.Print("col: ")
137 + fmt.Scanln(&colIndex)
138 +
139 + if 0 <= colIndex && colIndex < len(row) {
140 + if row[colIndex] != " " {
141 + fmt.Println("This cell is already occupied.")
142 + defer changeCellUserInput(board, user)
143 + break
144 + }
145 +
146 + row[colIndex] = user
147 + break
148 + } else {
149 + fmt.Println("The value needs to be in the range of the board columns.")
150 + continue
151 + }
152 + }
153 + }
154 +
155 + func analyzeWin(board [][]string) string {
156 + for r := range board {
157 + didWin := true
158 + firstItem := board[r][0]
159 + for c := range board[r] {
160 + if board[r][c] != firstItem {
161 + didWin = false
162 + break
163 + }
164 + }
165 +
166 + if didWin && firstItem != " " {
167 + return firstItem
168 + }
169 + }
170 +
171 + for c := range board[0] {
172 + didWin := true
173 + firstItem := board[0][c]
174 + for r := range board {
175 + if board[r][c] != firstItem {
176 + didWin = false
177 + break
178 + }
179 + }
180 +
181 + if didWin && firstItem != " " {
182 + return firstItem
183 + }
184 + }
185 +
186 + size := len(board)
187 + {
188 + didWin := true
189 + firstItem := board[0][0]
190 + for i := 0; i < size; i++ {
191 + if board[i][i] != firstItem {
192 + didWin = false
193 + break
194 + }
195 + }
196 +
197 + if didWin && firstItem != " " {
198 + return firstItem
199 + }
200 + }
201 +
202 + {
203 + didWin := true
204 + firstItem := board[0][size-1]
205 + for i := 0; i < size; i++ {
206 + if board[i][size-i-1] != firstItem {
207 + didWin = false
208 + break
209 + }
210 + }
211 +
212 + if didWin && firstItem != " " {
213 + return firstItem
214 + }
215 + }
216 +
217 + return ""
218 + }
219 +
220 + func main() {
221 + var board [][]string
222 + if skipBoardCreation {
223 + board = createBoard(3)
224 + } else {
225 + board = createBoardUserInput()
226 + fmt.Println()
227 + }
228 +
229 + var users []string
230 + if skipUserCreation {
231 + users = []string{"X", "O"}
232 + } else {
233 + users = createUsersUserInput()
234 + fmt.Println()
235 + }
236 +
237 + printStats := func() {
238 + fmt.Println("Users playing:", strings.Join(users, " "))
239 + rows, columns := getBoardDimensions(board)
240 + fmt.Println("Board Dimension:", rows, columns)
241 + fmt.Println(boardToString(board))
242 + }
243 +
244 + currentUser := 0
245 + for {
246 + fmt.Println()
247 + printStats()
248 +
249 + didWin := analyzeWin(board)
250 + if didWin != "" {
251 + fmt.Println()
252 + fmt.Println(didWin + " WINS!!")
253 + break
254 + }
255 +
256 + fmt.Println()
257 + fmt.Println("it's the turn of " + users[currentUser])
258 + changeCellUserInput(board, users[currentUser])
259 + currentUser = (currentUser + 1) % len(users)
260 + }
261 + }
Newer Older