Skip to content

Instantly share code, notes, and snippets.

@tgoossens
Created December 4, 2012 22:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgoossens/4209494 to your computer and use it in GitHub Desktop.
Save tgoossens/4209494 to your computer and use it in GitHub Desktop.
Board game
Idea
------
I'm redesigning last years project in java (course: OOP)
Long story short:
I have a "board" ,"robot" "item", "wall"
a board contains pieces at certain positions
a robot must be able to pickup an item and use it/ drop it again
a robot can move forward and backward,
a robot can rotate clockwise or anticlockwise
For now
------
I'm experimenting how far I can go in not using any refs, atoms (or identity in general). I have still no clear opinion (2 months of clojure programming) on whether this is a good thing or not.
But at the moment i'm having a hard time trying to think what must happen when a robot picks up an item, then the board needs to get updated (remove the robot "value" from the board and put it on again etc)
(ns roborally.piece)
;PIECES
;everything is an 'piece'
(derive ::robot ::piece)
(derive ::wall ::piece)
(derive ::item ::piece)
;items
(derive ::battery ::item)
(defn create-piece [] {:type ::piece))
(defn create-wall []
(merge
(create-piece)
{:type ::wall}))
(defn energy-carrier [energy maxenergy]
{:energy energy
:maxenergy maxenergy})
(defn create-battery [energy maxenergy]
(merge
(energy-carrier energy maxenergy)
(create-piece)
{ :type ::battery}))
(defn create-robot [energy maxenergy]
(merge
(energy-carrier energy maxenergy)
(create-piece)
:type ::robot
:items []}))
(defn create-wall [energy]
(merge
(create-piece)
{:type ::wall}))
;ENERGY
(defn charge [{:keys [energy] :as container} charge-fn]
(assoc container :energy (charge-fn energy)))
(defn charge-exact [value] (fn [energy] value))
(defn drain [amount]
(fn [energy]
(if (> amount energy)
0
(- energy amount))))
(defn recharge [amount]
(fn [energy]
(+ energy amount)))
(defn transfer-energy [{:keys [energy maxenergy] :as from} {:keys [energy maxenergy] :as to}]
(let [amount (min (:energy from) (- (:maxenergy to) (:energy to)))]
[(charge from (drain amount)) (charge to (recharge amount))]))
;ITEMS
(defn change-items [{:keys [items] :as carrier} item-fn]
(assoc carrier :items (item-fn items)))
;probably more useful to represent items in a map: piece ->
(defn drop-item [item]
(fn [items] (remove #(= item %) items)))
(defn add-item
([item] (fn [items] (conj items item))))
(ns roborally.pieceboard)
(defn board [width height]
{:pieces {[0 0] '()}
:height height
:width width })
(derive ::piece ::orientable)
(defn addpiece [pieces piece [x y] ]
(assoc pieces [x y] (conj pieces piece)))
(defn inrange? [board [x y]]
(let [height (:height board)
width (:width board)]
(and (>= x 0) (>= y 0)
(< y height)
(< x width))))
(defn remove-first [pred coll]
(let [[a b]
(split-with #(not (pred %))
coll)] (concat a (rest b))))
(defn hasposition? [board position]
(contains? (:pieces board) position))
(defmulti place-on-board (fn [board piece [x y]] (:type piece)))
;checking in range should happen on higher level
(defmethod place-on-board ::piece
[board piece position]
(assoc board :pieces
(assoc (:pieces board) position (conj
(if (hasposition? board position)
((:pieces board) position)
'())
(place piece position)))))
(defn remove-piece [{:keys [position] :as piece}]
(fn [pieces]
(let [pieces-at-pos (pieces position)]
(assoc pieces position
(remove-first #(= piece %) pieces-at-pos)))))
(defn update-pieces [board update-fn]
(assoc board :pieces (update-fn (:pieces board))))
(defn swap-piece [board piece newpiece]
"Swap new value of a piece which stays at the same place"
(place-on-board
(update-pieces (:pieces board) (remove-piece piece))
newpiece
(:position piece)))
;problems here
(defn move-on-board [board {:keys [position orientation] :as piece} move-fn]
(place-on-board
(update-pieces board (remove-piece piece))
piece
(move-fn position orientation)))
;ORIENTATION
(defn orientation-to-vector [orientation]
({:north [0 -1]
:east [1 0]
:south [0 1]
:west [-1 0]} orientation))
(defn invert-orientation [orientation]
({:north :south
:east :west
:south :north
:west :east} orientation))
(defn clockwise [orientation]
({:north :east
:east :south
:south :west
:west :north} orientation))
(defn anticlockwise [orientation]
(invert-orientation (clockwise orientation)))
(defn turn [{:keys [orientation] :as piece} rotate-fn ]
(assoc piece :orientation (rotate-fn orientation)))
;POSITION
(defn place [{:keys [position] :as piece} position]
(assoc piece :position position))
(defn forward [position orientation]
(vec (map + position (orientation-to-vector orientation))))
(defn backward [position orientation]
(vec (map - position (orientation-to-vector orientation))))
(defn move [{:keys [position orientation] :as piece} move-fn]
(assoc piece :position (move-fn position orientation)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment