Browse Source

Implement bomb logic

Thomas Dy 8 years ago
parent
commit
fc5d54ebd2
2 changed files with 83 additions and 1 deletions
  1. 48 1
      src/bombnet/game.clj
  2. 35 0
      test/bombnet/game_test.clj

+ 48 - 1
src/bombnet/game.clj

@@ -1,5 +1,6 @@
 (ns bombnet.game
-  (:require [clojure.test :refer [is with-test]]))
+  (:require [clojure.test :refer [is with-test]])
+  (:require [clojure.set :refer :all]))
 
 (defn new-board [w h]
   (let [should-wall (fn [row col]
@@ -83,3 +84,49 @@
       (if (= players valid-players)
         proposed-state
         (recur (assoc state :players valid-players))))))
+
+(defn ^:private offset [pos dir] (mapv + pos dir))
+
+(with-test
+  (defn explode-bomb-helper [board start dir power acc]
+    (let [pos (offset start dir)]
+      (if (or (zero? power) (= (get-cell board pos) "#"))
+        acc
+        (recur board pos dir (- power 1) (conj acc pos)))))
+  (let [board (new-board 7 7)]
+    (is (= #{[1 2] [1 3]}
+           (explode-bomb-helper board [1 1] [0 1] 2 #{})))
+    (is (= #{[1 2] [1 3] [1 4] [1 5]}
+           (explode-bomb-helper board [1 1] [0 1] 99 #{})))))
+
+(defn explode-bomb [board bomb]
+  (let [{:keys [power pos]} bomb
+        dirs (if (:diagonal? bomb)
+               [[1 1] [-1 -1] [1 -1] [-1 1]]
+               [[1 0] [0 1] [-1 0] [0 -1]])]
+    (reduce #(explode-bomb-helper board pos %2 power %) #{pos} dirs)))
+
+(defn explode-bombs
+  ([state] (explode-bombs state #{}))
+  ([state prev-explosion]
+   (if-let [exploding (seq (filter #(zero? (:counter %)) (:bombs state)))]
+     (let [{:keys [board players bombs]} state
+           bomb (first exploding)
+           other-bombs (filter #(not= bomb %) bombs)
+           explosion (explode-bomb board bomb)
+           new-bombs (mapv (fn [bomb]
+                            (if (explosion (:pos bomb))
+                              (assoc bomb :counter 0)
+                              bomb))
+                          other-bombs)
+           new-players (mapv (fn [player]
+                              (if (explosion (:pos player))
+                                (assoc player :dead? true)
+                                player))
+                            players)]
+       (recur
+         (-> state
+             (assoc :players new-players)
+             (assoc :bombs new-bombs))
+         (union prev-explosion explosion)))
+     (assoc state :explosion prev-explosion))))

+ 35 - 0
test/bombnet/game_test.clj

@@ -96,3 +96,38 @@
           new-state (perform-movement state)]
       (is (= [1 1] (get-in new-state [:players 0 :pos])))
       (is (= [2 1] (get-in new-state [:players 1 :pos]))))))
+
+(deftest bomb-test
+  (testing "People die when they are killed"
+    (let [troll-bomb {:pos [5 5] :counter 99 :power 0}
+          state {:board (new-board 7 7)
+                 :players [{:id 1 :pos [1 1]}
+                           {:id 2 :pos [5 5]}]
+                 :bombs [{:pos [1 1] :counter 0 :power 2}
+                         troll-bomb]}
+          new-state (explode-bombs state)]
+      (is (get-in new-state [:players 0 :dead?]))
+      (is (= [troll-bomb] (:bombs new-state)))
+      (is (= #{[1 1] [1 2] [1 3] [2 1] [3 1]} (:explosion new-state)))))
+  (testing "Chain explode bombs"
+    (let [state {:board (new-board 7 7)
+                 :players [{:id 1 :pos [1 5]}]
+                 :bombs [{:pos [1 1] :counter 0 :power 2}
+                         {:pos [1 3] :counter 2 :power 2}]}
+          new-state (explode-bombs state)]
+      (is (get-in new-state [:players 0 :dead?]))
+      (is (empty? (:bombs new-state)))
+      (is (= #{[1 1] [1 2] [1 3] [2 1] [3 1]
+               [1 4] [1 5] [2 3] [3 3]}
+             (:explosion new-state)))))
+  (testing "Diagonal bombs"
+    (let [scared-bomb {:pos [1 3] :counter 99 :power 0}
+          state {:board (new-board 7 7)
+                 :players [{:id 1 :pos [1 1]}]
+                 :bombs [{:pos [1 2] :counter 0 :power 3 :diagonal? true}
+                         scared-bomb]}
+          new-state (explode-bombs state)]
+      (is (not (get-in new-state [:players 0 :dead?])))
+      (is (= [scared-bomb] (:bombs new-state)))
+      (is (= #{[1 2] [2 1] [2 3] [3 4] [4 5]}
+             (:explosion new-state))))))