Сначала давайте рассмотрим некоторые проблемы в вашем примере, которые необходимо будет решить до распараллеливания этого кода.
sum-of-evens
использует def
внутри функции, что почти всегда является ошибкой. Может показаться, что это дает желаемый эффект, но это неправильный способ его достижения. def
s обычно используются для значений уровня пространства имен (на том же уровне, что и ваша функция defn
s). Мы можем изменить рефакторинг sum-of-evens
, чтобы не полагаться на непреднамеренное побочное действие через def
:
(defn sum-of-evens [v]
(loop [v v
index 1
evens []]
(if (seq v)
(recur (rest v)
(inc index)
(if (even? index) ;; add a binding to loop, not a def
(conj evens (first v))
evens)) ;; pass unchanged value when necessary
(reduce + evens))))
Но мы можем еще больше упростить эту функцию с помощью keep-indexed
:
(defn sum-of-evens [coll]
(->> coll
(keep-indexed (fn [i v] (when (even? (inc i))
v)))
(apply +)))
И когда мы делаем то же самое для sum-of-odds
, мы видим, что функции почти идентичны, за исключением условия, которое они используют: odd?
против even?
. Мы можем сделать другую функцию, которая принимает предикатную функцию:
(defn sum-by-index-pred [f coll]
(->> coll
(keep-indexed (fn [i v] (when (f i) v)))
(apply +)))
;; using partial application and function composition
(def sum-of-evens (partial sum-by-index-pred (comp even? inc)))
(def sum-of-odds (partial sum-by-index-pred (comp odd? inc)))
Глядя на реализацию player-one
и player-two
, они кажутся взаимно рекурсивными. Я не понимаю, как вы могли бы распараллелить это, чтобы сделать это быстрее, потому что каждый ход зависит от результата предыдущего хода; нечего распараллеливать.
Я бы предложил рефакторинг, чтобы ваши правила игры и состояние вычислялись в одном месте, а не взаимно рекурсивными функциями.
(loop [scores (array-map :player-1 0 :player-2 0)
turns (cycle (keys scores))
vs (shuffle (range 100))]
(if (seq vs)
(let [higher-odds? (> (sum-of-odds vs) (sum-of-evens vs))
scores (if higher-odds?
(update scores (first turns) + (first vs))
(update scores (first turns) + (last vs)))
remain (if higher-odds?
(rest vs)
(butlast vs))]
(recur scores (rest turns) remain))
(prn scores)))
;; {:player-1 2624, :player-2 2326}
Я не уверен, сохраняет ли это исходную игровую логику, но она должна быть близкой, и она обобщает ее для более чем двух игроков. Попробуйте добавить :player-3 0
к началу scores
.