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 f8aa57e

Browse files
committed
Added tictactoe
1 parent bfd0a69 commit f8aa57e

File tree

1 file changed

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

1 file changed

+139
-5
lines changed

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

Lines changed: 139 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,146 @@ func solveTSP<T>(cities: [T], distances: [T: [T: Int]]) -> (solution: [T], dista
142142
let vtTSP = solveTSP(cities: vtCities, distances: vtDistances)
143143
print("The shortest path is \(vtTSP.solution) in \(vtTSP.distance) miles.")
144144

145-
//func dog(test: inout [String]) {
146-
// test.append("hello")
147-
//
148-
//}
145+
/// Phone Number Mnemonics
146+
147+
let phoneMapping: [Character: [Character]] = ["1": ["1"], "2": ["a", "b", "c"], "3": ["d", "e", "f"], "4": ["g", "h", "i"], "5": ["j", "k", "l"], "6": ["m", "n", "o"], "7": ["p", "q", "r", "s"], "8": ["t", "u", "v"], "9": ["w", "x", "y", "z"], "0": ["0"]]
148+
149+
150+
// return all of the possible characters combos, given a mapping, for a given number
151+
func stringToPossibilities(_ s: String, mapping: [Character: [Character]]) -> [[Character]]{
152+
let possibilities = s.characters.flatMap{ mapping[0ドル] }
153+
print(possibilities)
154+
return combineAllPossibilities(possibilities)
155+
}
156+
157+
// takes a set of possible characters for each position and finds all possible permutations
158+
func combineAllPossibilities(_ possibilities: [[Character]]) -> [[Character]] {
159+
guard let possibility = possibilities.first else { return [[]] }
160+
var permutations: [[Character]] = possibility.map { [0ドル] } // turn each into an array
161+
for possibility in possibilities[1..<possibilities.count] where possibility != [] {
162+
let toRemove = permutations.count // temp
163+
for permutation in permutations {
164+
for c in possibility { // try adding every letter
165+
var newPermutation: [Character] = permutation // need a mutable copy
166+
newPermutation.append(c) // add character on the end
167+
permutations.append(newPermutation) // new combo ready
168+
}
169+
}
170+
permutations.removeFirst(toRemove) // remove combos missing new last letter
171+
}
172+
return permutations
173+
}
174+
175+
let permutations = stringToPossibilities("1440787", mapping: phoneMapping)
176+
177+
/// Tic-tac-toe
178+
179+
enum Piece: String {
180+
case X = "X"
181+
case O = "O"
182+
case E = ""
183+
var opposite: Piece {
184+
switch self {
185+
case .X:
186+
return .O
187+
case .O:
188+
return .X
189+
case .E:
190+
return .E
191+
}
192+
}
193+
}
194+
195+
// a move is an integer 0-9 indicating a place to put a piece
196+
typealias Move = Int
197+
198+
struct Board {
199+
let position: [Piece]
200+
let turn: Piece
201+
let lastMove: Move
202+
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+
208+
// by default the board is empty and X goes first
209+
// lastMove being -1 is a marker of a start position
210+
init(position: [Piece] = [.E, .E, .E, .E, .E, .E, .E, .E, .E], turn: Piece = .X, lastMove: Int = -1) {
211+
self.position = position
212+
self.turn = turn
213+
self.lastMove = lastMove
214+
}
215+
216+
// location can be 0-8, indicating where to move
217+
// return a new board with the move played
218+
func move(_ location: Move) -> Board {
219+
var tempPosition = position
220+
tempPosition[location] = turn
221+
return Board(position: tempPosition, turn: turn.opposite, lastMove: location)
222+
}
223+
224+
var isWin: Bool {
225+
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
234+
235+
}
236+
237+
var isDraw: Bool {
238+
return !isWin && legalMoves.count == 0
239+
}
240+
}
241+
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) }
245+
246+
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+
}
252+
return bestEval
253+
} else { // minimizing
254+
var worstEval: (eval: Int, bestMove: Move) = (Int.max, -1)
255+
for move in board.legalMoves {
256+
let result = minimax(board.move(move), maximizing: true)
257+
if result.eval < worstEval.eval { worstEval = result }
258+
}
259+
return worstEval
260+
}
261+
}
262+
263+
// win in 1 move
264+
let toWinEasyPosition: [Piece] = [.X, .O, .X,
265+
.X, .E, .O,
266+
.E, .E, .O]
267+
let testBoard1: Board = Board(position: toWinEasyPosition, turn: .X, lastMove: 8)
268+
let answer1 = minimax(testBoard1, maximizing: true)
269+
print(answer1.bestMove)
149270

150-
// City 0
271+
// must block O's win
272+
let toBlockPosition: [Piece] = [.X, .E, .E,
273+
.E, .E, .O,
274+
.E, .X, .O]
275+
let testBoard2: Board = Board(position: toBlockPosition, turn: .X, lastMove: 8)
276+
let answer2 = minimax(testBoard2, maximizing: true)
277+
print(answer2.bestMove)
151278

279+
// find the best move to win in 2 moves
280+
let toWinHardPosition: [Piece] = [.X, .E, .E,
281+
.E, .E, .O,
282+
.O, .X, .E]
283+
let testBoard3: Board = Board(position: toWinHardPosition, turn: .X, lastMove: 6)
284+
let answer3 = minimax(testBoard3, maximizing: true)
285+
print(answer3.bestMove)
152286
//: [Next](@next)
153287

0 commit comments

Comments
(0)

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