Created
March 30, 2014 18:10
-
-
Save luisgerhorst/9877138 to your computer and use it in GitHub Desktop.
2048 in Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(def grid (insert [[nil nil nil nil] | |
[nil nil nil nil] | |
[nil nil nil nil] | |
[nil nil nil nil]])) | |
;; Grid functions. | |
(defn move | |
"Moves all field to the choosen direction, merges fields and inserts field value for random free location. Returns nil if game is over. Returns same grid if move doesn't change the grid." | |
[grid direction] | |
(if (can-move grid) | |
(try-move grid direction) | |
nil)) | |
(defn try-move | |
[grid direction] | |
(case direction | |
:left (try-move-with-function grid move-left) | |
:rigth (try-move-with-function grid move-rigth) | |
:top (try-move-with-function grid move-top) | |
:bottom (try-move-with-function grid move-bottom))) | |
(defn try-move-with-function | |
[grid function] | |
(let [moved (function grid)] | |
(if (= moved grid) | |
grid | |
(insert moved)))) | |
(defn can-move | |
[grid] | |
(not (= grid | |
(try-move grid :left) | |
(try-move grid :rigth) | |
(try-move grid :top) | |
(try-move grid :bottom)))) | |
(defn insert | |
"Inserts 2 or 4 at random free location." | |
[grid] | |
(assoc-in grid (rand-nth (get-empty-coordinates grid)) (rand-nth [2 4]))) | |
(defn get-empty-coordinates | |
[grid] | |
(loop [empty-fields [] | |
y 0] | |
(if (= y 4) | |
empty-fields | |
(recur (into empty-fields (loop [empty-fields [] | |
x 0] | |
(if (= x 4) | |
empty-fields | |
(recur (if (get-in grid [y x]) | |
empty-fields | |
(conj empty-fields [y x])) (inc x))))) (inc y))))) | |
(defn move-left | |
[grid] | |
(vec (map merge-row grid))) | |
(defn move-rigth | |
[grid] | |
(vec (map (comp vec rseq) (move-left (vec (map (comp vec rseq) grid)))))) | |
(defn move-top | |
[grid] | |
(vec (apply map vector (move-left (vec (apply map vector grid)))))) | |
(defn move-bottom | |
[grid] | |
(vec (apply map vector (move-rigth (vec (apply map vector grid)))))) | |
(defn merge-row | |
"Move all field in the row to the left and merge fields with the same value" | |
[row] | |
(loop [merged-row (merge-compressed-row (filter identity row))] | |
(if (< (count merged-row) 4) | |
(recur (conj merged-row nil)) | |
merged-row))) | |
(defn merge-compressed-row | |
[row] | |
"Merge field in compressed row (row without empty fields)" | |
(reduce (fn [merged field] | |
(if (number? field) | |
(conj merged field) | |
(conj merged (reduce + field)))) | |
[] | |
(pair-compressed-row row))) | |
(defn pair-compressed-row | |
"Creates vector with equal fields paired into subvectors" | |
[row] | |
(reduce (fn [paired field] | |
(if (and (= field (last paired)) (number? (last paired))) | |
(set-last paired [field field]) | |
(conj paired field))) | |
[] | |
row)) | |
(defn set-last | |
"Sets the last item of the vector to value" | |
[vector value] | |
(if (= (count vector) 0) | |
[value] | |
(assoc vector (- (count vector) 1) value))) | |
;; Grid test funcions. | |
(defn random-game | |
"Makes as many random moves as possible and returns final grid and number of moves." | |
[grid] | |
(loop [g grid | |
i 0] | |
(let [moved (move g (rand-nth [:left :rigth :top :bottom]))] | |
(if (or (not moved) (= i 500)) | |
{:moves i :final-grid g} | |
(recur moved (inc i)))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm pretty new to Clojure so I hope my code isn't that bad. Try
move
,insert
andrandom-game
ongrid
.