Clojure: перебирание вектора векторов, чтобы найти первый вектор, который удовлетворяет определенному условию
Чтобы выучить Clojure, я работаю над маленькой игрой в крестики-нолики. После завершения первой части игры с относительной легкостью, я изо всех сил пытался построить интеллектуальный компьютерный плеер.
Для теста, который я пишу, чтобы помочь в этом, я хочу проверить, что компьютер выбирает место 9, если это очередь компьютера, и это доска:
X / O / 3
4 / X / O
7 | 8 | 9
Чтобы начать игру, доска определяется следующим образом, как карта с парами ключ-значение представление местоположения на доске и содержимого этого пространства:
(def board {1 "1" 2 "2" 3 "3" 4 "4" 5 "5" 6 "6" 7 "7" 8 "8" 9 "9"})
У меня было несколько мыслей о том, как решить эту проблему. Один из них состоял в том, чтобы определить выигрышные наборы следующим образом:
(def winning-sets
[[(board 1) (board 2) (board 3)],
[(board 4) (board 5) (board 6)],
[(board 7) (board 8) (board 9)],
[(board 1) (board 4) (board 7)],
[(board 2) (board 5) (board 8)],
[(board 3) (board 6) (board 9)],
[(board 1) (board 5) (board 9)],
[(board 3) (board 5) (board 7)]])
Перебираем каждое множество:
(for [set winning-sets]
(filter #(= symbol %) set))
Но это кажется неправильным...Я не знаю, куда бы я пошел оттуда. Проблему, которую я пытаюсь решить, можно описать следующим образом:
Попросите компьютер просмотреть 8 выигрышных наборов и найти один набор, в котором есть два ваших символа и одно открытое место.
Я довольно новичок в Clojure, поэтому я просто не уверен, что понимаю, как лучше всего подойти к этой проблеме. Я смотрел на ClojureDocs (проверяя итерационные функции, такие какfor
и loop
и case
), но не смог сделать эту работу.
Каким будет лучший способ перебрать эти выигрышные наборы, в настоящее время в векторной форме, и найти набор, который имеет два определенных символа и один открывающий? Или было бы лучше, чтобы ... хранить выигрышные наборы в другой структуре данных?
примечание: Я прочитал ответы на этот вопрос , но не смог применить их к своему.
1 ответ:
Прежде всего, я советую вам использовать эту структуру для позиции правления:
Где X -(def board [[1 1 0] [0 0 0] [1 0 1]])
1
, O --1
, а пустая ячейка -0
. Доска в моем примере имеет только символы X (для упрощения). Далее,Это "выигрышные" наборы координат. Вы можете вычислить это при необходимости, но для 3x3 этот список действительно не так велик. В этом смысле ответ на ваш вопрос будет(def winning-sets '([[0 0] [0 1] [0 2]] [[1 0] [1 1] [1 2]] [[2 0] [2 1] [2 2]] [[0 0] [1 0] [2 0]] [[0 1] [1 1] [2 1]] [[0 2] [1 2] [2 2]] [[0 0] [1 1] [2 2]] [[0 2] [1 1] [2 0]]))
(defn check [target combo] (= (map #(count (filter (partial = %) combo)) [target 0]) '(2 1))) (defn extract [coords] (apply vector (map (fn [[f s]] ((board f) s)) coords))) (filter #(check 1 (extract %)) winning-sets)
Если вы выполните этот код в REPL, вы увидите
user=> (filter #(check 1 (extract %)) winning-sets) ([[0 0] [0 1] [0 2]] [[2 0] [2 1] [2 2]] [[0 0] [1 0] [2 0]] [[0 0] [1 1] [2 2]])
Который выглядит так: правильный ответ (2 горизонтальные линии, 1 вертикальная и 1 диагональная). Код груб, и есть несколько способов сделать его более красивым и многоразовым. Должен ли я объяснить, что происходит, или код достаточно ясен?