Skip to content

Commit

Permalink
Merge pull request #9 from WarFox/styling
Browse files Browse the repository at this point in the history
animation and styling
  • Loading branch information
WarFox committed May 25, 2024
2 parents 620a324 + c64bee7 commit be4c8c4
Show file tree
Hide file tree
Showing 11 changed files with 910 additions and 499 deletions.
725 changes: 476 additions & 249 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
"ci": "npx shadow-cljs compile karma-test && npx karma start --single-run --reporters junit,dots"
},
"dependencies": {
"highlight.js": "11.5.1",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"karma": "6.4.0",
"highlight.js": "^11.5.1",
"karma-chrome-launcher": "3.1.1",
"karma-cljs-test": "0.1.0",
"karma-junit-reporter": "2.0.1",
"shadow-cljs": "2.20.5",
"tailwindcss": "^3.2.2"
"shadow-cljs": "^2.24.1",
"tailwindcss": "^3.3.2"
}
}
2 changes: 1 addition & 1 deletion resources/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset='utf-8'>
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>2048 - game implementation using ClojureScript</title>
<title>2048 - ClojureScript</title>
</head>
<body>
<noscript>
Expand Down
78 changes: 46 additions & 32 deletions src/cljs_2048/board.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
(def random-fill #(rand-nth [2 2 2 4])) ;; Favor 2 for random filling

(def initial-board
[[0 0 0 0]
[0 0 0 0]
[0 0 0 0]
[0 0 0 0]])
[[[0] [0] [0] [0]]
[[0] [0] [0] [0]]
[[0] [0] [0] [0]]
[[0] [0] [0] [0]]])

(defn set-tile
"Set value at given row and column of the board"
[board r c value]
[board r c value state]
(let [row (nth board r)
updated (assoc row c value)]
updated (assoc row c [value state])]
(assoc board r updated)))

(defn get-tile
Expand All @@ -28,19 +28,19 @@
(nth c)))

(defn empty-tiles
"Returns list of [r c] where r is row and c is column index of tile with zero"
"Returns list of [r c] where r is row and c is column index of tile with [0]"
[board]
(for [r (range rows-count)
c (range columns-count)
:when (zero? (get-tile board r c))]
:when (= [0] (get-tile board r c))]
[r c]))

(defn random-tile
"Set 2 or 4 to random empty position of tile"
"Set 2 or 4 to random empty positions of tile"
[board]
(if-let [tiles (seq (empty-tiles board))]
(let [[r c] (rand-nth tiles)]
(set-tile board r c (random-fill)))
(set-tile board r c (random-fill) :random))
board))

(defn with-two-random-tiles
Expand All @@ -66,30 +66,44 @@

(defn fill-zeroes
"If vector v's length is less than n, fill the remaining slots with 0.
Otherwise returns the v. Default fill-count is columns-count."
([v]
(fill-zeroes v columns-count))
([v n]
Otherwise returns the v."
[v n]
(let [fill-count (- n (count v))]
(into v (repeat fill-count 0)))))
(into (vec v) (repeat fill-count [0]))))

(defn combine
"Combines two equal tiles into one in the v and fills remaining with zeroes"
"Combines two equal tiles into one in the vector v and fills remaining with zeroes.
v is a vector of vectors of single integer, for example [[2 :random] [0] [4 :merged] [4]]
[0] means empty slot and all [0] should be trailing in the result.
Add state as :merged when combining two tiles
(combine [[2 :random] [0] [4 :merged] [4]]) ;; => [[2] [8 :merged] [0] [0]]
"
[v]
(loop [[head & remaining] v
acc []]
(cond
(empty? remaining)
(fill-zeroes (conj acc (if head head 0))) ;; head can be nil

(= head (first remaining))
(let [sum (* 2 head)]
(when (pos? sum)
(re-frame/dispatch [::game-events/add-score sum]))
(recur (rest remaining) (conj acc sum)))

:else
(recur remaining (conj acc head)))))
(let [non-zero-v (remove zero? (map first v)) ;; Remove 0 tiles before reduction, work with value not state
merged (reduce (fn [[acc prev] current]
(cond
;; If previous is nil, set current as previous
(nil? prev)
[acc current]

;; If equal, merge and add to accumulator, set nil as previous
(= prev current)
(let [sum (+ prev current)]
(re-frame/dispatch [::game-events/add-score sum])
[(conj acc [sum :merged]) nil])

;; If not equal, add previous to accumulator and current element as previous
:else
[(conj acc [prev]) current]))

[[] nil] ;; Start with empty accumulator and nil previous
non-zero-v) ;; Reduce over non-zero tiles.
;; If last tile is not merged, add it to result
result (first merged)
last (second merged)
final-result (if last (conj result [last]) result)]

(fill-zeroes final-result columns-count)))

(defn reverse-board
"Reverse the board"
Expand All @@ -99,8 +113,8 @@
(defn move-tiles-left
"Move the tiles to left in v, by shifting value to empty tile"
[v]
(-> (filterv pos? v)
(fill-zeroes)))
(-> (filterv #(pos? (first %)) v)
(fill-zeroes columns-count)))

(defn stack-left
[board]
Expand Down
12 changes: 9 additions & 3 deletions src/cljs_2048/game.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@

(defn can-move-sideways?
[v]
(->> (partition-by identity v)
(map count)
(some #(> % 1))))
(or
;; if there is a zero, then we can move
(some #(= [0] %) v)

;; if there are two consecutive equal values, then we can move
(->> (map first v) ;; get the value
(partition-by identity)
(map count)
(some #(> % 1)))))

(defn can-move?
[board]
Expand Down
19 changes: 11 additions & 8 deletions src/cljs_2048/game_events.cljs
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
(ns cljs-2048.game-events
(:require
[day8.re-frame.tracing :refer-macros [fn-traced]]
[re-frame.core :as re-frame]
[cljs-2048.local-storage :as ls]))

(re-frame/reg-event-db
::add-score
(fn-traced
(defn add-score
[db [_ new-score]]
(let [score (+ new-score (:score db))
high-score (max score (:high-score db))]
(ls/set-high-score! high-score) ;; set high-score in local-storage
(assoc db
:score score
:high-score high-score))))
:high-score high-score)))

(defn gameover
[db [_]]
(assoc db :gameover true))

(re-frame/reg-event-db
::add-score
add-score)

(re-frame/reg-event-db
::gameover
(fn-traced
[db [_]]
(assoc db :gameover true)))
gameover)
17 changes: 0 additions & 17 deletions src/cljs_2048/gameover.cljs

This file was deleted.

58 changes: 39 additions & 19 deletions src/cljs_2048/views.cljs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
(ns cljs-2048.views
(:require
[cljs-2048.events :as events]
[cljs-2048.gameover :as gameover]
[cljs-2048.subs :as subs]
[re-frame.core :as re-frame]
[re-pressed.core :as rp]))
Expand All @@ -28,9 +27,17 @@

;; Displaying the game tile
(defn tile-panel
[index value]
^{:key index}
[:div {:class (str "tile tile-" value)}
[row-index col-index [value state]]
^{:key col-index}
[:div {:class (str "tile tile-" value " tile-position-" (inc row-index) "-" (inc col-index)
(cond
(= state :merged)
" tile-merged"

(= state :random)
" tile-new"

:else ""))}
(if (zero? value) "" value)])

;; Panel used to show Score and Best score
Expand All @@ -51,32 +58,44 @@
(let [board (re-frame/subscribe [::subs/board])] ;; Get the current state of the board
[:div.board
;; [:pre (with-out-str (cljs.pprint/pprint @board))] ;; print the board in page for debugging
(map ;; Each row of the board
(fn [value]
[:div.row
(map-indexed ;; Each tile of the row
tile-panel
value)])
@board)
(map-indexed
(fn [row-index row] ;; Each row of the board
^{:key row-index}
[:div.row
(map-indexed (fn [col-index cell]
(tile-panel row-index col-index cell))
row)]);; Each tile of the row
@board)
[:br.clear]]))

(defn gameover-panel []
[:div gameover/view])

(defn score
[]
(let [score (re-frame/subscribe [::subs/score])
high-score (re-frame/subscribe [::subs/high-score])]
[:div.flex.flex-row-reverse
[:div {:class "flex flex-row-reverse"}
(score-panel ::high-score @high-score)
(score-panel ::score @score)]))

(defn gameover-panel []
[:div {:class "relative flex justify-center items-center z-20"}
[:div {:class "w-full h-full bg-gray-900 bg-opacity-60 top-0 fixed sticky-0"}
[:div {:class "2xl:container 2xl:mx-auto py-48 px-4 md:px-28 flex justify-center items-center"}
[:div {:class "w-96 md:w-auto relative flex flex-col justify-center items-center bg-white bg-opacity-60 py-16 px-4 md:px-24 xl:py-24 xl:px-36"}
[:div
[:h1 {:role "main" :class "text-3xl dark:text-white lg:text-4xl font-semibold text-center text-gray-800"}
"Game Over!"]]

(score)

[:div {:class "flex flex-col justify-center items-center"}
[:button.btn-primary {:on-click #(re-frame/dispatch [::events/start-game])} "New Game"]]]]]])

(defn game-panel
[]
(let [gameover (re-frame/subscribe [::subs/gameover])]
[:div.flex.flex-col.items-center
[:div {:class "flex flex-col items-center"}
(when @gameover (gameover-panel))
[:button.btn-primary.bg-blue-200 {:on-click #(re-frame/dispatch [::events/start-game])} "New Game"]
[:button.btn-primary {:on-click #(re-frame/dispatch [::events/start-game])} "New Game"]
[board-panel]]))

(defn header
Expand All @@ -86,7 +105,8 @@
(defn main-panel
[]
(let [name (re-frame/subscribe [::subs/name])]
[:div.container.mx-auto.center
[:div {:class "relative flex min-h-screen flex-col justify-center overflow-hidden bg-gray-50 py-6 sm:py-12"}
[:div {:class "container mx-auto"}
(header @name)
[score]
[score]]
[game-panel]]))
Loading

0 comments on commit be4c8c4

Please sign in to comment.