@@ -142,12 +142,146 @@ func solveTSP<T>(cities: [T], distances: [T: [T: Int]]) -> (solution: [T], dista
142142let vtTSP = solveTSP ( cities: vtCities, distances: vtDistances)
143143print ( " 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