I'm trying to define a function that receives a pair of x-y coordinates and a direction which a robot is facing (:north, :east, :south and :west).
I defined a map called directions which holds the valid values (and which will be used later for movement).
(def directions {:north {:x 0 :y 1} :east {:x 1 :y 0} :south {:x 0 :y -1} :west {:x -1 :y 0}})
And for validation purposes, I created a :pre clause to prevent invalid values for such parameters:
(defn create-robot
"Creates a Robot representation, containing its position (x,y) and directions which it is facing"
[x y direction]
{:pre [(int? x) (>= x 0)
(int? y) (>= y 0)
(contains? directions direction)]}
(Robot. x y direction))
Now, here's the problem: when I run my test, it fails because of this contains? validation. The thing is, I'm using a valid value for my test, still, it is failing.
(let [robot (create-robot 1 2 :north)]
(expect 1 (:x robot))
(expect 2 (:y robot))
(expect :north (:direction robot)))
It gives me the following error:
Error refreshing environment: java.lang.AssertionError: Assert failed: (contains? directions direction)
Would someone be able to tell me what is wrong? Am I expecting too much from preconditions?
Thanks and Cheers.
Update
As required by #Alan Thompson, I added a println
(defn create-robot
"Creates a Robot representation, containing its position (x,y) and directions which it is facing"
[x y direction]
{:pre [(int? x) (>= x 0)
(int? y) (>= y 0)
(or (println direction) true)
(or (println (directions direction)) true)
(or (println (str "Contains? " (contains? directions direction))) true)
(contains? directions direction)]}
(Robot. x y direction))
And the result shows as expected (except that this time the test passes):
*************** Running tests ***************
:reloading (jaegers.domain jaegers.core jaegers.core-test)
:north
{:x 0, :y 1}
Contains? true
:north
{:x 0, :y 1}
Contains? true
Ran 18 tests containing 18 assertions in 5 msecs
0 failures, 0 errors.
Tests completed at 19:17:38.593
I don't understand how it works now.
I never use the expectations lib. Instead, I like a slightly more convenient version of clojure.test. Here is your code, which works as expected:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test) )
(defrecord Robot [x y direction])
(def directions {:north {:x 0 :y 1}
:east {:x 1 :y 0}
:south {:x 0 :y -1}
:west {:x -1 :y 0}})
(defn create-robot
"Creates a Robot representation, containing its position (x,y) and directions which it is facing"
[x y direction]
{:pre [(int? x) (>= x 0)
(int? y) (>= y 0)
(contains? directions direction)]}
(Robot. x y direction))
; Now, here's the problem: when I run my test, it fails because of this contains? validation. The thing is, I'm using a valid value for my test, still, it is failing.
(dotest
(let [robot (create-robot 1 2 :north)]
(is= 1 (spyx (:x robot)))
(is= 2 (spyx (:y robot)))
(is= :north (spyx (:direction robot)))))
The spyx just prints to the console to verify visually what is happening:
-----------------------------------
Clojure 1.10.1 Java 12.0.1
-----------------------------------
Testing tst.demo.core
(:x robot) => 1
(:y robot) => 2
(:direction robot) => :north
Ran 2 tests containing 3 assertions.
0 failures, 0 errors.
Passed all tests
Finished at 16:52:59.262 (run time: 0.054s)
Not sure what went wrong with your first attempt. Try it again or try my version to get more info.
Also, you never said what the Robot class does. Is that a Java class? If so, it could be related.
Related
I have a vector of vectors [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]] containing x,y positions of detected plates.
How do I retrieve the x position of plate p3?
It seems to be a simple task but I'm more familiar with python, so I'm not sure how to do this in clojure.
i would go with something like this:
(def data [[:plate "p1" 0 1] [:plate "p2" 0 2] [:plate "p3" 1 1]])
(some (fn [[_ v x y]] (when (= v "p3") [x y])) data)
;;=> [1 1]
(some (fn [[_ v x y]] (when (= v "p123") [x y])) data)
;;=> nil
(def p '[[plate,"p1",0,1],[plate,"p2",0,2],[plate,"p3",1,1]])
;; be aware, 'p1' you can use in Python, but because in Clojure `'` at beginning
;; of a symbol is parsed as `quote`, you can't use `''` instead of `""` in contrast to Python.
;; create a nested map out of the vec of vecs
(defn vecs-to-map [vecs]
(reduce (fn [m [_ id x y]] (assoc m id {:x x :y y}))
{}
vecs))
(def m (vecs-to-map p))
;;=> {"p1" {:x 0, :y 1}, "p2" {:x 0, :y 2}, "p3" {:x 1, :y 1}}
;; you can access such a nested list via `get-in` and giving the nested map
;; and the keys it should apply on it.
(get-in m ["p3" :x])
;;=> 1
Since the irregularity that one key is a string and the other a keyword is
not so nice, I would make out of them all keywords:
(defn vecs-to-map [vecs]
(reduce (fn [m [_ id x y]] (assoc m (keyword id) {:x x :y y}))
{}
vecs))
(def m (vecs-to-map p))
;; access it by:
(get-in m [:p3 :x])
;;=> 1
Additional Thoughts
We ignored the first element of the vec plate.
Let's say there exist also another vectors like
(def b '[[box "b1" 0 1] [box "b2" 0 2] [box "b3" 1 1]])
And if we want a nested map which contains :plate and :box in the
outer level as keys, we have to change the vecs-to-map function.
(defn vecs-to-map [vecs]
(reduce (fn [m [k id x y]] (assoc m (keyword k)
(assoc (get m (keyword k) {})
(keyword id) {:x x :y y})))
{}
vecs))
Then we can generate the map containing everything by:
(def m (vecs-to-map (concat p b)))
;; or alternatively in two steps:
;; (def m (vecs-to-map p))
;; (def m (merge m (vecs-to-map b)))
m
;; => {:plate {:p1 {:x 0, :y 1}, :p2 {:x 0, :y 2}, :p3 {:x 1, :y 1}}, :box {:b1 {:x 0, :y 1}, :b2 {:x 0, :y 2}, :b3 {:x 1, :y 1}}}
And we access the content by:
;; access through:
(get-in m [:plate :p3 :x])
;; => 1
(get-in m [:box :b2 :y])
;; => 2
You don't really provide much context on what you're trying to do but it feels like you want to filter the vector of tuples to those that have the symbol p3' in the second position and then return just the third and fourth elements of such a match?
If so, the following would work:
dev=> (def plate :plate)
#'dev/plate
dev=> (def data [[plate,'p1',0,1],[plate,'p2',0,2],[plate,'p3',1,1]])
#'dev/data
dev=> (let [[[_ _ x y]] (filter (comp #{'p3'} second) data)]
#_=> [x y])
[1 1]
This doesn't feel very idiomatic, so perhaps you could explain more of the context?
Note: 'p3' is a symbol whose name is p3' so I wonder if you mean "p3" for a string?
The vector of vector format doesn't seem very conducive to the sort of access you want to perform - perhaps changing it to a hash map, whose keys are the plate IDs (if that's what p1, p2, and p3 are?) would be better to work with?
Edit: in response to #leetwinkski's note about the result when there is no match, here's an alternative:
You could use when-first:
dev=> (when-first [[_ _ x y] (filter (comp #{'p123'} second) data)]
#_=> [x y])
nil
dev=> (when-first [[_ _ x y] (filter (comp #{'p3'} second) data)]
#_=> [x y])
[1 1]
Here is how I would do it, based on my favorite template project. Please also note that in Clojure strings always use double-quotes like "p1". Single quotes are totally different!
(ns tst.demo.core
(:use tupelo.core tupelo.test))
(defn vec-has-label
"Returns true iff a vector has the indicated label"
[vec lbl]
(= lbl (nth vec 1)))
(defn vec->x
"Given a vector, return the x value"
[vec]
(nth vec 2))
(defn find-label
[matrix label]
(let [tgt-vecs (filterv #(vec-has-label % label) matrix) ; find all matching vectors
x-vals (mapv vec->x tgt-vecs)] ; extract the x values
x-vals))
The unit tests show the code in action
(dotest
(isnt (vec-has-label '[plate "p1" 0 1] "p0"))
(is (vec-has-label '[plate "p1" 0 1] "p1"))
(is= 9 (vec->x '[plate "p1" 9 1]))
(let [matrix (quote
[[plate "p1" 0 1]
[plate "p2" 0 2]
[plate "p3" 1 1]])]
(is= (find-label matrix "p3")
[1])
))
The unit test show the 2 ways of "quoting" a data structure that contains one or more symbols. This would be unneeded if the redundant plate symbol weren't present.
See also this list of documentation sources.
The result of frequencies is wrong when used for sequencies containing NaNs, for example:
=> (frequencies [Double/NaN Double/NaN])
{NaN 1, NaN 1}
instead of expected {NaN 2}.
Furthermore, the running time deteriorates from expected/average O(n) to worst-case O(n^2), e.g.
=> (def v3 (vec (repeatedly 1e3 #(Double/NaN))))
=> (def r (time (frequencies v3)))
"Elapsed time: 36.081751 msecs"
...
=> (def v3 (vec (repeatedly 1e3 #(Double/NaN))))
=> (def r (time (frequencies v3)))
"Elapsed time: 3358.490101 msecs"
...
i.e. 10 times so many elements need 100 times higher running time.
How can frequencies be calculated with (expected/average) O(n) running time, when NaNs are present in the sequence?
As side note:
=> (frequencies (repeat 1e3 Double/NaN))
{NaN 1000}
yields the expected result, probably because all elements in the sequence are references of the same object.
NaN is pretty weird in many programming languages, partly because the IEEE 754 standard for floating point numbers defines that NaN should not equal anything, not even itself. It is the "not even itself" part that leads to most of the weird behavior you are seeing. More here, if you are curious: https://github.com/jafingerhut/batman
The sample function below may be adaptable to your needs. It uses :nan-kw in the returned map to indicate how many NaNs were found. If you replace :nan-kw with ##NaN, then the returned map has the disadvantage that you cannot find the count with (get frequency-ret-value ##NaN), because of the weirdness of ##NaN.
(defn frequencies-maybe-nans [s]
(let [separate-nans (group-by #(and (double? %) (Double/isNaN %)) s)
num-nans (count (separate-nans true))]
(merge (frequencies (separate-nans false))
(when-not (zero? num-nans)
{:nan-kw num-nans}))))
(def freqs (frequencies-maybe-nans [1 2 ##NaN 5 5]))
freqs
(get freqs 2)
(get freqs :nan-kw)
Some background on NaN values on the JVM: https://www.baeldung.com/java-not-a-number
You can solve this by encoding the NaN values temporarily while computing the frequencies:
(ns tst.demo.core
(:use tupelo.core
tupelo.test))
(defn is-NaN? [x] (.isNaN x))
(defn nan-encode
[arg]
(if (is-NaN? arg)
::nan
arg))
(defn nan-decode
[arg]
(if (= ::nan arg)
Double/NaN
arg))
(defn freq-nan
[coll]
(it-> coll
(mapv nan-encode it)
(frequencies it)
(map-keys it nan-decode)))
(dotest
(let [x [1.0 2.0 2.0 Double/NaN Double/NaN Double/NaN]]
(is= (spyx (freq-nan x)) {1.0 1,
2.0 2,
##NaN 3})))
with result:
-------------------------------
Clojure 1.10.1 Java 13
-------------------------------
Testing tst.demo.core
(freq-nan x) => {1.0 1, 2.0 2, ##NaN 3}
FAIL in (dotest-line-25) (core.clj:27)
expected: (clojure.core/= (spyx (freq-nan x)) {1.0 1, 2.0 2, ##NaN 3})
actual: (not (clojure.core/= {1.0 1, 2.0 2, ##NaN 3} {1.0 1, 2.0 2, ##NaN 3}))
Note that even though it calculates & prints the correct result, the unit test still fails since NaN is never equal to anything, even itself. If you want the unit test to pass, you need to leave in the placeholder ::nan like:
(defn freq-nan
[coll]
(it-> coll
(mapv nan-encode it)
(frequencies it)
))
(dotest
(let [x [1.0 2.0 2.0 Double/NaN Double/NaN Double/NaN]]
(is= (spyx (freq-nan x)) {1.0 1,
2.0 2,
::nan 3})))
I am trying to make 10 PRINT code with Quil. I try to transform this code from the twitter post https://twitter.com/ACharLuk/status/913094845505445890 which is using luna
This is my code for it
(ns tenprint.core
(:require [quil.core :as q]
[quil.middleware :as m]))
(defn setup []
(q/frame-rate 30)
(q/color-mode :hsb)
{:x 0
:y 0
:scale 20
}
)
(defn update-state [state]
(let [x (:x state) y (:y state) s (:scale state)]
{
:x (do (+ x s) ((if (>= x q/width) 0)))
:y (do (if (>= x q/width) (+ y s)) (if (>= x q/height) (+ y s)))
:scale (+ s 0)
}
)
)
(defn draw-state [state]
(q/background 0)
(q/stroke 255)
;(q/line 0 10 10 0)
(let [x (:x state) y (:y state) s (:scale state)]
(if (> (rand) 0.5)
(q/line x y (+ x s) (+ y s))
(q/line x (+ y s) (+ x s) y)
)
)
)
(q/defsketch tenprint
:title "10PRINT"
:size [500 500]
:setup setup
:update update-state
:draw draw-state
:settings #(q/smooth 2)
:features [:keep-on-top]
:middleware [m/fun-mode]
)
And it just appears like this. I was trying to split the update of states, but it says that you must not have duplicated variables to be updated
Thank you.
Your code is in the right direction and you managed to draw the first line. It crashed when update-state was called. To fix the code I did the following things:
Clojure works with pure functions where you cannot "set" values as you seem to wanted to do in update-state (with do only the last expression is returned, not two values). To update-state you need to return a whole new state.
q/height and q/widths are functions that return the height and width, so call them (surround them by parentheses) to get the number out.
When you redraw the background in update-state the older lines are gone, so put (q/background 0) in setup.
Move (q/no-loop) from update-state to the draw-state entry-point of the program.
And stylistically I changed this:
Use associative destructuring in function parameter instead of getting values of keys in let.
Place trailing parentheses on the same line (see Clojure style guide).
Below the working version:
(ns tenprint.core
(:require [quil.core :as q]
[quil.middleware :as m]))
(defn setup []
(q/background 0) ; move setting background to setup, otherwise the state is overwritten
(q/frame-rate 30)
(q/stroke 255)
(q/color-mode :hsb)
{:x 0
:y 0
:scale 20})
(defn update-state [{:keys [x y scale] :as state}] ; destructure
;; height and width are functions you need to `(call)` to get the value
{:x (if (>= x (q/width)) 0 (+ x scale)) ; fix if-statements
:y (if (>= x (q/width)) (+ y scale) y) ; 'do' does something different than you think
:scale scale}) ; no need to add 0
(defn draw-state [{:keys [x y scale] :as state}] ; destructure
(if (>= y (q/height))
(q/no-loop)
(if (> (rand) 0.5)
(q/line x y (+ x scale) (+ y scale))
(q/line x (+ y scale) (+ x scale) y))))
(q/defsketch tenprint
:title "10 PRINT"
:size [500 500]
:setup setup
:draw draw-state
:update update-state
:features [:keep-on-top]
:middleware [m/fun-mode])
I am building a minesweeper where the gameboard is a 2d array.
To generate the board I need to get a 2d array, randomly place some bombs, calculate all neighboring bombs for each field, then pack all together with another value (is-revealed) into a Map that should be the final value of each field.
It seems that to do all of this, I need the help of functions like map, filter, nth or zip, but instead of working on lists, they should work on a 2d array. I already started building those, but it seems like the wrong path to go.
Is there some cool abstraction that helps me use the existing functions on the 2d array? Or are there any functions already existing, that deal with 2d arrays?
edit: The way I was doing it - before thinking to myself, that there should be a better way - is something like this:
(defn mapmap [f xxs]
(for [xs xxs]
(map f xs)))
(defn mapmap-coords [f xxs]
(for [[i xs] (map-indexed list xxs)]
(map-indexed (fn [j x] (f j i)) xs)))
(defn get-value [board x y]
(if (or (< x 0) (< y 0) (< (dec (count board)) y))
false
(let [xs (nth board y)]
(if (< (dec (count xs)) x)
false
(nth xs x)))))
for works for nested sequential data.
user> (def game-state
(let [game '[[_ _ _ _]
[1 1 _ _]
[! 1 _ _]
[1 1 _ _]]]
(for [[i row] (map-indexed list game)
[j cell] (map-indexed list row)
:when (not= '_ cell)]
{:x i :y j :value cell})))
#'user/game-state
user> (pprint game-state)
({:x 1, :y 0, :value 1}
{:x 1, :y 1, :value 1}
{:x 2, :y 0, :value !}
{:x 2, :y 1, :value 1}
{:x 3, :y 0, :value 1}
{:x 3, :y 1, :value 1})
nil
We can use reduce to build up the data structure again (of course any transformations to the state could have been done in between).
user> (let [empty-game (vec (repeat 4 '[_ _ _ _]))
fill-cell (fn [game, {:keys [x y value]}] (assoc-in game [x y] value))
game (reduce fill-cell empty-game game-state)]
(doseq [row game] (apply println row)))
_ _ _ _
1 1 _ _
! 1 _ _
1 1 _ _
nil
If you're willing to drop down into Java types for your implementation, consider using
clojure.core/to-array-2d to create your 2d array and then
clojure.core/aget to index into it.
aget will give you a more natural method for accessing the array, but you'll still need to build further abstractions to get neighbours and perform updates to (i.e., regenerate) this data structure.
I have a vector of entities (maps), I have filtered this vector to those entities with a particular key. Then I apply a function to update some values in those entities, and now have a subset that I'd like to merge with the original superset.
world [{a} {b} {c} {d} {e}]
a [{b} {d} {e}] ; (filter matches? world)
b [{b'} {d'} {e'}] ; (map func a)
new-world [{a} {b'} {c} {d'} {e'}] ; (merge world b)
How can I merge my update b with the original world?
My map structure is:
{:id identity
:attrs {:property1 {:param1 value
:param2 value}
:property2 {}}
There can be a variable number of properties. Properties can have 0 ({}) or more params. The only part of the map that is changing are the values, and only some of them.
I have to peer into each map to identify it, and then merge accordingly? What is an idiomatic way to do this?
Clojure's map function can take multiple sequences, but won't compare my subset b to the whole superset world, only b number of world entities, and stop once b is exhausted.
> (map #(str %1 " " %2) [1 2 3 4 5] [6 7 8])
("1 6" "2 7" "3 8")
Have I chosen the wrong structure for my data in the first place? Would I be better off without a vector and just one map?
{:entid1
{:property1 {:param1 value :param2 value}
:property2 {}}
:entid2
{:property1 {:param1 value :param2 value}
:property2 {:param1 value}
:property3 {:param1 value :param2 value :param3 value}}}
This question looks similar but does not merge my vectors correctly.
Real world implementation
My actual code is part of a game I'm writing to familiarise myself with Clojure (ClojureScript in this instance).
The game state (world) is as follows:
[{:id :player,
:attrs
{:gravity {:weight 10},
:jump {:height 60, :falling false, :ground true},
:renderable {:width 37, :height 35},
:position {:x 60, :y 565},
:walk {:step 4, :facing :right},
:input {},
:solid {:blocked false}}}
{:id wall1,
:attrs
{:solid {},
:position {:x 0, :y 0},
:renderable {:width 20, :height 600}}}
{:id wall2,
:attrs
{:solid {},
:position {:x 780, :y 0},
:renderable {:width 20, :height 600}}}
{:id platform3,
:attrs
{:solid {},
:position {:x 20, :y 430},
:renderable {:width 600, :height 20}}}]
I update the world on each animation frame, then re-render the canvas.
(defn game-loop []
(ui/request-frame game-loop)
(-> world
system/update!
ui/render))
system/update! is:
(defn update! [world]
(let [new-world (->> #world
(phys/move #player/input-cmd))]
(player/clear-cmd)
(reset! world new-world)
#world))
My plan was to have a chain of systems updating the world in the thread last macro. I am in the process of writing phys/move.
This means that systems have to update the world, instead of just returning their effect on the world (vector of changes).
I'm contemplating if it's more manageable to have the system/update! function manage the effects on the world (applying the updates). So systems only return their list of changes. Something like:
(defn update! [world]
(let [updates []
game #world]
(conj updates (phys/move #player/input-cmd game))
(conj updates (camera/track :player game))
; etc.
(reset! world
(map #(update-world updates %) world))
#world))
Repeated (conj updates (func world)) feels clunky though. This is possibly more work than just merging updates (or returning an modified entity) in a system function.
How to elegantly pass state changes between my system functions (phys/move, camera/track), and subsystem functions (walk, jump)?
My stab at applying Joaquin's map only approach to my move system:
(ns game.phys)
(def step 4)
(def height 50)
(defn walk?
"is this a walk command?"
[cmd]
(#{:left :right} cmd))
(defn walks?
"update? equivalent"
[entity]
(contains? (:attrs entity) :position))
(defn walk
[cmd entity]
(if (walks? entity)
(let [x (get-in entity [:attrs :position :x]
op (if (= cmd :left) - +)
update {:attrs {:position {:x (op x step)}
:walk {:facing cmd}}}]
(merge entity update))
entity))
; cmd is a deref'ed atom that holds player input commands
; e.g. :left :right: :jump
(defn move
[cmd world]
(cond
(walk? cmd) (map #(walk input-cmd %) world)
(jump? cmd) (map #(jump height %) world)
:else world))
It is simpler than all that (having a vector of maps is something pretty common, and it may fit your problem properly). Instead of doing a filter and then a map, just do a map:
(defn update? [entity] ...)
(defn update-entity [entity] ...)
(defn update-world [world]
(let [update #(if (matches? %) (update-entity %) %)]
(map update world)))
This pattern of updating something or just leaving it as it is is pretty common, and it is idiomatic to make the functions that update something return the updated thing, or the old thing if it did nothing, so at the end it would be something like:
(defn update-entity?
"Predicate that returns if an entity needs updating"
[entity] ...)
(defn update-entity
"Updates an entity if it is needed.
Otherwise returns the unchanged entity"
[entity]
(if (update-entity? entity)
(assoc entity :something :changed)
entity))
(defn update-world [world]
(map update-entity world))
You can see some examples of this behavior in the game logic of this snake game:
https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs#L54-L66
https://github.com/joakin/cnake/blob/master/src/cnake/game.cljs#L102-L114