Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 1b39fca

Browse files
committed
tictactoe fixes
1 parent f8aa57e commit 1b39fca

File tree

1 file changed

+48
-30
lines changed
  • Classic Computer Science Problems in Swift.playground/Pages/Chapter 8.xcplaygroundpage

1 file changed

+48
-30
lines changed

‎Classic Computer Science Problems in Swift.playground/Pages/Chapter 8.xcplaygroundpage/Contents.swift

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -192,19 +192,14 @@ enum Piece: String {
192192
}
193193
}
194194

195-
// a move is an integer 0-9 indicating a place to put a piece
195+
// a move is an integer 0-8 indicating a place to put a piece
196196
typealias Move = Int
197197

198198
struct Board {
199199
let position: [Piece]
200200
let turn: Piece
201201
let lastMove: Move
202202

203-
// the legal moves in a position are all of the empty squares
204-
var legalMoves: [Move] {
205-
return position.indices.filter { position[0ドル] == .E }
206-
}
207-
208203
// by default the board is empty and X goes first
209204
// lastMove being -1 is a marker of a start position
210205
init(position: [Piece] = [.E, .E, .E, .E, .E, .E, .E, .E, .E], turn: Piece = .X, lastMove: Int = -1) {
@@ -221,16 +216,21 @@ struct Board {
221216
return Board(position: tempPosition, turn: turn.opposite, lastMove: location)
222217
}
223218

219+
// the legal moves in a position are all of the empty squares
220+
var legalMoves: [Move] {
221+
return position.indices.filter { position[0ドル] == .E }
222+
}
223+
224224
var isWin: Bool {
225225
return
226-
position[0] == position[1] && position[0] == position[2] && position[0] != .E || // row 0
227-
position[3] == position[4] && position[3] == position[5] && position[3] != .E || // row 1
228-
position[6] == position[7] && position[6] == position[8] && position[6] != .E || // row 2
229-
position[0] == position[3] && position[0] == position[6] && position[0] != .E || // col 0
230-
position[1] == position[4] && position[1] == position[7] && position[1] != .E || // col 1
231-
position[2] == position[5] && position[2] == position[8] && position[2] != .E || // col 2
232-
position[0] == position[4] && position[0] == position[8] && position[0] != .E || // diag 0
233-
position[2] == position[4] && position[2] == position[6] && position[2] != .E // diag 1
226+
position[0] == position[1] && position[0] == position[2] && position[0] != .E || // row 0
227+
position[3] == position[4] && position[3] == position[5] && position[3] != .E || // row 1
228+
position[6] == position[7] && position[6] == position[8] && position[6] != .E || // row 2
229+
position[0] == position[3] && position[0] == position[6] && position[0] != .E || // col 0
230+
position[1] == position[4] && position[1] == position[7] && position[1] != .E || // col 1
231+
position[2] == position[5] && position[2] == position[8] && position[2] != .E || // col 2
232+
position[0] == position[4] && position[0] == position[8] && position[0] != .E || // diag 0
233+
position[2] == position[4] && position[2] == position[6] && position[2] != .E // diag 1
234234

235235
}
236236

@@ -239,49 +239,67 @@ struct Board {
239239
}
240240
}
241241

242-
func minimax(_ board: Board, maximizing: Bool) -> (eval: Int, bestMove: Move) {
243-
if board.isWin { return (1, board.lastMove) }
244-
else if board.isDraw { return (0, board.lastMove) }
242+
// Find the best possible outcome for originalPlayer
243+
func minimax(_ board: Board, maximizing: Bool, originalPlayer: Piece) -> Int {
244+
// Base case — evaluate the position if it is a win or a draw
245+
if board.isWin && originalPlayer == board.turn.opposite { return 1 } // win
246+
else if board.isWin && originalPlayer != board.turn.opposite { return -1 } // loss
247+
else if board.isDraw { return 0 } // draw
245248

249+
// Recursive case — maximize your gains or minimize the opponent's gains
246250
if maximizing {
247-
var bestEval:(eval:Int, bestMove:Move)=(Int.min,-1)
248-
for move in board.legalMoves {
249-
let result = minimax(board.move(move), maximizing: false)
250-
if result.eval >bestEval.eval { bestEval =result}
251+
var bestEval=Int.min
252+
for move in board.legalMoves { // find the move with the highest evaluation
253+
let result = minimax(board.move(move), maximizing: false, originalPlayer: originalPlayer)
254+
bestEval=max(result, bestEval)
251255
}
252256
return bestEval
253257
} else { // minimizing
254-
var worstEval:(eval:Int, bestMove:Move)=(Int.max,-1)
258+
var worstEval=Int.max
255259
for move in board.legalMoves {
256-
let result = minimax(board.move(move), maximizing: true)
257-
if result.eval <worstEval.eval { worstEval =result}
260+
let result = minimax(board.move(move), maximizing: true, originalPlayer: originalPlayer)
261+
worstEval=min(result, worstEval)
258262
}
259263
return worstEval
260264
}
261265
}
262266

267+
// Run minimax on every possible move to find the best one
268+
func findBestMove(_ board: Board) -> Move {
269+
var bestEval = Int.min
270+
var bestMove = -1
271+
for move in board.legalMoves {
272+
let result = minimax(board.move(move), maximizing: false, originalPlayer: board.turn)
273+
if result > bestEval {
274+
bestEval = result
275+
bestMove = move
276+
}
277+
}
278+
return bestMove
279+
}
280+
263281
// win in 1 move
264282
let toWinEasyPosition: [Piece] = [.X, .O, .X,
265283
.X, .E, .O,
266284
.E, .E, .O]
267285
let testBoard1: Board = Board(position: toWinEasyPosition, turn: .X, lastMove: 8)
268-
let answer1 = minimax(testBoard1, maximizing:true)
269-
print(answer1.bestMove)
286+
let answer1 = findBestMove(testBoard1)
287+
print(answer1)
270288

271289
// must block O's win
272290
let toBlockPosition: [Piece] = [.X, .E, .E,
273291
.E, .E, .O,
274292
.E, .X, .O]
275293
let testBoard2: Board = Board(position: toBlockPosition, turn: .X, lastMove: 8)
276-
let answer2 = minimax(testBoard2, maximizing:true)
277-
print(answer2.bestMove)
294+
let answer2 = findBestMove(testBoard2)
295+
print(answer2)
278296

279297
// find the best move to win in 2 moves
280298
let toWinHardPosition: [Piece] = [.X, .E, .E,
281299
.E, .E, .O,
282300
.O, .X, .E]
283301
let testBoard3: Board = Board(position: toWinHardPosition, turn: .X, lastMove: 6)
284-
let answer3 = minimax(testBoard3, maximizing:true)
285-
print(answer3.bestMove)
302+
let answer3 = findBestMove(testBoard3)
303+
print(answer3)
286304
//: [Next](@next)
287305

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /