Browse Source

Preliminary implementation for game manager

Thomas Dy 8 years ago
parent
commit
47bd17b829
2 changed files with 101 additions and 0 deletions
  1. 61 0
      src/bombnet/manager.clj
  2. 40 0
      test/bombnet/manager_test.clj

+ 61 - 0
src/bombnet/manager.clj

@@ -0,0 +1,61 @@
+(ns bombnet.manager
+  (:require [bombnet.game :refer :all]
+            [clojure.set :refer [difference]]))
+
+(defrecord Room [clients players state])
+
+(defrecord Manager [rooms])
+
+(defn new-manager []
+  (->Manager (atom {})))
+
+(defn ^:private get-room [rooms room]
+  (if-let [found-room (get @rooms room)]
+    found-room
+    (let
+      [new-room (->Room {} #{} nil)]
+      (swap! rooms assoc room new-room)
+      new-room)))
+
+(defmacro defn-room [name params & body]
+  (let [actual-params (vec (concat ['{:keys [rooms]} 'room-id]
+                                   params))
+        actual-body `(let [~'room (get-room ~'rooms ~'room-id)
+                           ~'update-room #(swap! ~'rooms assoc ~'room-id %)]
+                       ~@body)]
+    `(defn ~name ~actual-params
+       ~actual-body)))
+
+(defn-room client-join [id channel]
+  (update-room (assoc-in room [:clients id] {:id id :channel channel}))
+  true)
+
+(defn-room client-leave [id]
+  (let [new-room (-> room
+                     (update :clients dissoc id)
+                     (update :players difference #{id}))]
+    (update-room (if (not-empty (:clients new-room)) new-room))
+    true))
+
+(defn-room player-join [id]
+  (let [player-count (count (:players room))]
+    (if (>= player-count 4)
+      false
+      (do
+        (update-room (update room :players conj id))
+        true))))
+
+(defn-room player-leave [id]
+  (update-room (update room :players difference #{id}))
+  true)
+
+(defn-room player-action [id action]
+  (update-room (update room :state bombnet.game/queue-action action id)))
+
+(defn-room start-game []
+  (let [players (filter (:players room) (:clients room))
+        new-state (new-game players)]
+    (update-room (assoc room :state new-state))))
+
+(defn room-status [{:keys [rooms]} room-id]
+  (get @rooms room-id))

+ 40 - 0
test/bombnet/manager_test.clj

@@ -0,0 +1,40 @@
+(ns bombnet.manager-test
+  (:require [clojure.test :refer :all]
+            [bombnet.manager :refer :all]))
+
+(deftest client-test
+  (testing "Clients can join"
+    (let [manager (new-manager)]
+      (is (nil? (room-status manager 12)))
+      (client-join manager 12 100 "chan")
+      (is (= (->Room {100 {:id 100 :channel "chan"}} #{} nil)
+             (room-status manager 12)))))
+  (testing "An empty room is removed"
+    (let [manager (new-manager)]
+      (client-join manager 12 100 "chan")
+      (client-leave manager 12 100)
+      (is (nil? (room-status manager 12)))))
+  (testing "Players leave when the client leaves"
+    (let [manager (new-manager)]
+      (client-join manager 12 100 "chan")
+      (player-join manager 12 100)
+      (is (= (->Room {100 {:id 100 :channel "chan"}} #{100} nil)
+             (room-status manager 12)))
+      (client-join manager 12 101 "chan")
+      (client-leave manager 12 100)
+      (is (= (->Room {101 {:id 101 :channel "chan"}} #{} nil)
+             (room-status manager 12)))))
+  (testing "Only up to 4 players can join"
+    (let [manager (new-manager)]
+      (client-join manager 12 1 "p1")
+      (client-join manager 12 2 "p2")
+      (client-join manager 12 3 "p3")
+      (client-join manager 12 4 "p4")
+      (client-join manager 12 5 "p5")
+      (is (player-join manager 12 1))
+      (is (player-join manager 12 2))
+      (is (player-join manager 12 3))
+      (is (player-join manager 12 4))
+      (is (not (player-join manager 12 5)))
+      (is (player-leave manager 12 4))
+      (is (player-join manager 12 5)))))