我正在尝试用中级学生语言制作一个类似于Scheme的Tic Tac Toe游戏。如果可能的话,我想使用我定义的数据类型使其工作,但必要时会更改。在我的下面的代码中,我已经创建了许多函数,这些函数让我接近我想要的位置:
只是一个抬头,我设计这个tic tac toe游戏的方式是使用“选择3个数字(1到9之间)加上15”方法 - 我愿意改变它。< / em>的
我迷失了,我不知道下一步该做什么。我想要的是我的主要minimax函数返回下一步,如果它是计算机的轮次,将最小化得分,并在玩家轮到时最大化得分。
(define-struct board [turn compmoves playermoves remaining])
; A Board is a (make-game symbol [List-of Number] [List-of Number] [List-of Number])
; interpretation -> who's turn is it, which spaces have been played by computer,
; which spaces have been played by the player, and
; which spaces remain
;Winning combinations (order doesn't matter,
;and this is reflected in the 'game-over?' function
(define winr1 '(8 1 6))
(define winr2 '(3 5 7))
(define winr3 '(4 9 2))
(define winc1 '(8 3 4))
(define winc2 '(1 5 9))
(define winc3 '(6 7 2))
(define wind1 '(8 5 2))
(define wind2 '(4 5 6))
(define a-win (list winr1 winr1 winr3 winc1 winc2 winc3 wind1 wind2))
(define BOARD0 (make-board 'player '(9 3 1) '(4 8 6) '(2 5 7)))
(define BOARD1 (make-board 'player '(8 6 5 9) '(1 3 7 4 2) '()))
(define BOARD2 (make-board 'player '(4 2 5 8) '(1 9 6) '(3 7)))
;Board -> Number
;evaluates a game tree
;NOT SURE WHAT TO DO HERE
#;(define (minimax board)
(cond
[(game-over? board) (evaluate board)]
[else minimax ?]))
;(check-expect (minimax BOARD1) 0)
;(check-expect (minimax BOARD2) -1)
;Board -> [List-of Board]
;returns a list of potential boards
(define (potential-moves board)
(local (;Number -> [List-of Number]
;takes a referenced nummber in a list
;and adds it to another list
(define (add-move n)
(cond
[(player-turn? board)(cons (list-ref (board-remaining board) n)
(board-playermoves board))]
[else (cons (list-ref (board-remaining board) n)
(board-compmoves board))]))
;Number [List-of Number] -> [List-of Number]
;returns a list without the nth term
(define (extract n xs)
(cond
[(= n 0)(rest xs)]
[else (cons (first xs) (extract (sub1 n) (rest xs)))]))
)
(build-list (length (board-remaining board))
(λ (i) (make-board (next-player (board-turn board))
(if (not (player-turn? board))
(add-move i)
(board-compmoves board))
(if (player-turn? board)
(add-move i)
(board-playermoves board))
(extract i (board-remaining board)))))))
;Symbol -> Symbol
;changes the turn
(define (next-player s)
(if (symbol=? s 'player)
'computer
'player))
(check-expect (next-player 'player) 'computer)
(check-expect (next-player 'computer) 'player)
;Board -> Number
;evaluates the board
(define (evaluate board)
(cond
[(empty? (board-remaining board)) 0]
[(player-turn? board) -1]
[else 1]))
(check-expect (evaluate BOARD1) 0)
(check-expect (evaluate BOARD2) -1)
;Board -> Boolean
;the game is over if
; - there are no more moves remaining,
; - the player has a winning combination, or
; - the computer has a winning combination
(define (game-over? board)
(or (empty? (board-remaining board))
(ormap (λ (win) (in-moves? win (board-compmoves board))) a-win)
(ormap (λ (win) (in-moves? win (board-playermoves board))) a-win)))
(check-expect (game-over? BOARD1) true)
(check-expect (game-over? BOARD2) true)
;[List-of Number] [List-of Number] -> Boolean
;are the values from the first list in the second, in any order?
(define (in-moves? combo moves)
(andmap (λ (number) (member? number moves)) combo))
(check-expect (in-moves? '(4 5 6) '(4 1 8 6 5 3 2)) true)
;Board -> Boolean
;determines if it's the player's turn
(define (player-turn? board)
(symbol=? 'player (board-turn board)))
(check-expect (player-turn? BOARD1) true)
;Board -> Boolean
;determines if it's the computer's turn
(define (computer-turn? board)
(symbol=? 'computer (board-turn board)))
(check-expect (computer-turn? BOARD2) false)
答案 0 :(得分:1)
Minimax的主要部分是对董事会的深入评估。我的意思是找出如果两个球员都能完美比赛,谁会赢。
如果游戏结束(因为玩家连续三次或者棋盘已满),很容易找出胜利者是谁。否则算法会尝试所有可能的移动并评估结果板,然后选择最佳结果。
这是计算机评估算法的草图。给定一个棋盘(假设它是计算机轮到),如果计算机将赢,则返回-1,如果玩家将赢(或已赢)则返回1,如果游戏以平局结束则返回0。 / p>
function computer_evaluate(board):
if player has three in a row:
return 1 # player won
if there are no more moves:
return 0 # draw
for each board in possible moves:
calculate player_evaluate(new board)
return best (i.e. minimum) of player evaluations
注意:
evaluate
函数的作用。原因是玩家的最后一步移动可能会填补董事会并同时完成一行,在这种情况下,他们仍然赢了。计算player_evaluation
的算法非常相似。如果玩家将获胜(或者已经赢了),它需要一个玩家轮流的棋盘,如果玩家将获胜,则返回-1;如果玩家将获胜,则返回1;如果游戏将以平局结束,则返回0。
function player_evaluate(board):
if computer has three in a row:
return -1 # computer won
if there are no more moves:
return 0 # draw
for each board in possible moves:
calculate computer_evaluate(new board)
return best (i.e. maximum) of computer evaluations
如果我们知道玩家将采取什么行动,我们只需要考虑这一举动。然而,没有办法告诉他们选择哪一个,所以尝试了所有可能的动作,并假设玩家将选择最好的一个。
这两个函数非常相似,将它们组合成一个minimax
函数是有意义的。
在上一节中,我描述了如何对董事会进行深入评估并确定谁将获胜。然而,计算机还需要知道哪一步会带来最佳结果。
要获取该信息,函数computer_evaluate
应返回最佳分数和导致该分数的移动。
potential-moves
的实现在compmoves
开始时插入最新的移动,因此很容易找到与潜在棋盘相对应的移动。例如,如果最小化玩家评估的棋盘为(make-board 'player '(5 9 3 1) '(2 4 8 6) '(7))
,则计算机的最佳移动为5
。
你可能想要编写一个函数find-min-by
,它接受一个评分函数和一个元素列表,并返回一个包含得分最低的元素及其得分的对。例如,
(define (demo-score elem) (- (% remainder 3) 1)) ; returns -1, 0, or +1
(find-min-by demo-score '(1234 69 100 101))
; => (69, -1), since (demo-score 69) = -1
Minimax算法上有很多优秀的资源,所以如果你被困住了看看。