Fork me on GitHub

thanks nathan! i’ll take a closer look at this tomorrow, much appreciated! 🙂


that absolutely did what i wanted - i added bounds checking and added my desired reversing behavior when row2 < row or col2 < col, and ended up with this, which i haven’t tested thoroughly but seems to be correct so far:


(defn ^:direct-nav grid-values
  [x1 y1 x2 y2]
  (if (g/cell-is-on-grid x1 y1)
    (let [x2 (bound-between x2 0 (dec GRID-WIDTH))
          y2 (bound-between y2 0 (dec GRID-HEIGHT))]

        (for [x (if (< x1 x2)
                  (range x1 (inc x2))
                  (reverse (range x2 (inc x1))))
              y (if (< y1 y2)
                  (range y1 (inc y2))
                  (reverse (range y2 (inc y1))))]
          (nthpath x y))))



thanks so much for your help, i really appreciate it!


final usage ends up looking like this, replacing my reduce from earlier:

(fn [xdir ydir]
   (let [values-in-direction (select (grid-values (+ x xdir)
                                                  (+ y ydir)
                                                  (+ x (* xdir MAX-RUN-LENGTH))
                                                  (+ y (* ydir MAX-RUN-LENGTH)))
         run-values (take-while (comp not nil?) values-in-direction)]
     [(count run-values) (apply + run-values)]))


seems to be way slower than my previous reduce implementation though, dang - likely some mistake on my end, will profile


ok yeah now my program spends 88% of its time in com.rpl.specter.impl.mk_dynamic_path_maker


the specterized code above is awesome though, i really like it way more than my handrolled reduce from yesterday - it untangles the computation into its component parts (first get a list of up to 5 values in this direction, then drop everything after and including the first nil, then count the values and sum them)


whereas my previous code did all those things at once


so i remain a big fan of specter and also remain appreciative of your help, but am not sure how to proceed performancewise


it’s the weekend, this is a toy project and non-urgent, no rush on a reply 🙂 thanks!


if it’s helpful, a screenshot of the profile data: (percentages shown are different because i’ve filtered for com.rpl.specter, i believe)


@jrheard it would be a lot faster as a first-class navigator


implementation would be similar to ALL, except in two dimensions


it would be easy to also avoid needing to do two nth per element, since you can do every matching value in a row one after another


interesting, thanks for the tip! i’ll read through the docs and investigate that line of attack


hm, can’t tell if this is a foolish question - would the implementation actually look more like srange rather than all? the main difference i see is that srange takes arguments start and end, and my thing will also take arguments (`x1`, y1, x2, y2)


also, i notice that ALL uses doseqres ( ) - should i figure out what doseqres does, or can i safely ignore it?


@jrheard I mean it's going to be similar in function, navigating to many subvalues of a data structure


implementation-wise it will be very different


i ended up with this, it’s 4-5x faster than the previous specter approach but still roughly (no benchmarks collected, going solely on how the app feels to use) 1.5-2x slower than the reduce approach. it’s also kind of hideous but that’s my fault:

  [x1 y1 x2 y2]
  (select* [this structure next-fn]
           (assert (or (= x1 x2)
                       (= y1 y2)))

             (if (cell-is-on-grid x1 y1)
               (let [x2 (bound-between x2 0 (dec GRID-WIDTH))
                     y2 (bound-between y2 0 (dec GRID-HEIGHT))]
                 (if (= x1 x2)
                   (let [column (nth structure x1)]
                     (if (< y1 y2)
                       (subvec column y1 (inc y2))
                       (reverse (subvec column y2 (inc y1)))))

                   (for [x (if (< x1 x2)
                             (range x1 (inc x2))
                             (reverse (range x2 (inc x1))))]
                     (-> structure
                         (nth x)
                         (nth y1)))))

  (transform* [this structure next-fn]
              ; punting on this for now
              (assert false)))