Implementation of the Minimax algorithm in Clojure - a conditional function with several recursive calls

This question and another question of my kind merged into one after I understood a few things, so I revised this question.

What I'm trying to accomplish using my function is described below.

  • Iterate over all the spots. If it is open, select a location with the current player symbol.
  • If this move makes the game win and it flips to the computer, add a spot key-value pair (integer) and a spot counter (integer, 1 in this case) to the scored-spots hash map.
  • Read and call the same function, passing it a new scored-spots hash card, a panel with remote removal, the same player and the same symbol.
  • If, however, the game is not won, go to the next conditional expression and check it.
  • Follow the following conditional operators in the same way as with different estimates (winnings with a computer revolution are 1, winnings with a human revolution are -1, a tie is 0).
  • If none of the conditional statements evaluates to true, then recursion is the same (the scored-spots hash map will not be different in this case).

Here is the code I tried, but this does not return the values ​​I expect.

Note:
board is a hash map as follows: {0 "0", 1 "1", 2 "2"} (spot location - spot value)
sym is a character such as "X" or "O"
current-player is a keyword, for example :computer or :human
scored-spots is a hash map like this: {}

 (defn score-spots [board sym current-player scored-spots] (for [spot (keys board)] (if (some #(= % (.toString spot)) (filter #(not= "O" %) (filter #(not= "X" %) (vals board)))) (let [board (assoc board spot sym)] (cond (and (game-won board) (= current-player :computer)) (score-spots board sym current-player (assoc scored-spots spot 1)) (and (game-won board) (= current-player :human)) (score-spots board sym current-player (assoc scored-spots spot -1)) (game-tied board) (score-spots board (switch-symbol sym) (switch-player current-player) (assoc scored-spots spot 0)) :else (score-spots board (switch-symbol sym) (switch-player current-player) scored-spots))) scored-spots)))) 

What I expect as a return value is a hash map with every open space. For example, {1 0, 4 1, 5 -1, 6 -1, 8 0} .

Instead, if I give him this board:
{1 "X" 2 "X" 3 "O" 4 "4" 5 "5" 6 "6" 7 "7" 8 "X" 9 "O"} ,
I get a return value with a large list hash maps.

+4
source share
1 answer

I am relatively new to Clojure and FP in general. Whenever I think of recursion, I always try to think first whether this is possible for map and / or reduce .

In this case, you are trying to score every place. Each spot put together is a blackboard. Therefore, if I can score every place and then put them together, I can complete the task at hand. In terms of reduce I can do something with the element (place) in the collection, and then combine this value into one value (the board is technically only spots without an “X” or “O” for the code below).

Here I rewrite:

 (defn score-spot [scored-spot current-player board] (let [[spot score] scored-spot] (cond (and (game-won board) (= current-player :computer)) {spot 1} (and (game-won board) (= current-player :human)) {spot -1} (game-tied board) {spot 0} :else {spot score}))) (defn score-board [board current-player] (let [spots-to-score (filter #(and (not= "X" (second %)) (not= "O" (second %))) board)] (reduce #(into %1 (score-spot %2 current-player board)) {} spots-to-score))) 

This will give your result, for example, {1 0, 4 1, 5 -1, 6 -1, 8 0}


Edit:

Regarding the need for repetition, you basically want to use mutual recursion. To do this, you can use declare to forward the declaration functions, and then use trampoline ( here a quick tutorial ) for actual recursion.

+2
source

Source: https://habr.com/ru/post/1444668/


All Articles