Arc Forumnew | comments | leaders | submitlogin
Improve this function 2 =)
1 point by bOR_ 5905 days ago | 10 comments
Very simple function this time, but therefore also very easy to write in a classical rather than lispy way.

Given a 2 dimensional array such as made by

  (def makeworld (x)
     (= world (n-of x (n-of x nil))))

  (def showpos (row col) 
      (errsafe ((world row) col))) 
and filled with some numbers, how would you show the immediate surroundings of a number. A classical way would be to use two for loops and a bucket

  (def observe (x y r)
     (let b nil
        (for i (* r -1) r
        (for j (* r -1) r
           (if (showpos (+ x j) (+ y i))
              (= b (cons (showpos (+ x j) (+ y i)) b))
          )))
        b))
What I've been playing with is using each, range and consif, but it still is the same structure. Any alternatives? maybe getting rid of the bucket by using accum?

  (def observe (row col ran)
      (let bucket nil
          (each dr (range (* -1 ran) ran)
              (each dc (range (* -1 ran) ran)
                  (= bucket (consif (showpos (+ row dr) (+ col dc)) bucket))))
      bucket))


1 point by almkglor 5905 days ago | link

Assuming you want to use showpos (which is arguably slower since you have to traverse the list each time):

  (mac w/collect body
    `(accum collect ,@body))

  (def observe (x y r)
    (w/collect:for i (- x r) (+ x r)
      (for j (- y r) (+ y r)
        (awhen (showpos i j)
          (collect it)))))
If you want efficiency and still want to use list structures, you might want to skip 'showpos.

-----

1 point by bOR_ 5905 days ago | link

Good call. Not necessarily want to use showpos.. its main advantage right now is that it nicely returns nil when I try to read any out-of-bound position.

I guess without showpos I could grab the appropriate rows from world and discard the first X and last Y positions.

-----

1 point by bOR_ 5905 days ago | link

There we go. That looks like a solution I was looking for :). and cut nicely takes care of out-of-bounds too.

  (map (fn (_) (cut _ (- row 1) (+ col 2))) (cut world (- row 1) (+ col 2)))

-----

1 point by bOR_ 5905 days ago | link

ugh. just don't mind the nonsensical placing of row and col, it should be row row, col col

-----

1 point by almkglor 5905 days ago | link

  (map [cut _ (- row r) (+ row r)] (cut world (- col r) (+ col r)))

-----

1 point by bOR_ 5905 days ago | link

From here on I adapted the function to the one I really needed (do something if one of the 8 neighbours of posx, posy is X). Because of that requirement it seemed easier to just gather the row - 1 and row + 1 and the row, col - 1 and row, col + 1, and join those in a list. This is what it ended up as:

   (if (find X (flat:map [join (errsafe (world _))] (list (- row 1) (+ row 1) (- col 1) (+ col 1))))
    ; do stuff
    )
Thanks for the help!

-----

1 point by almkglor 5905 days ago | link

  (flat:map [join (errsafe (world _))] (list (- row 1) (+ row 1) (- col 1) (+ col 1)))
This bit doesn't seem correct... world is addressed by row right? Why are you also addressing by column?

-----

1 point by bOR_ 5904 days ago | link

yeah. realized this night (dreaming is a wonderful thing) that I'm now making a mess out of it, rather than just looking at neighbours. bug! ;).

But as far as I'm concerned, I've had enough help already. Should be able to take it from here.

-----

1 point by tokipin 5905 days ago | link

version using accum and aif

  (def observe (row col range)
      (accum append
        (for i (- range) range
        (for j (- range) range
            (aif (showpos (+ row j) (+ col i))
                 (append it))))))
i tried making a showpos using aand like so:

  (def showpos (row col)
      (aand (world row) (it col)))
but it errors on out-of-bounds <_< i was hoping the errsafe was for using nil as a function

-----

1 point by bOR_ 5905 days ago | link

thanks for the (- somevariable)! I was using there (and in other places) still ( -1 somevariable)..

-.variable = (* -1 variable) work just fine in arc.

errsafe was a trick I learned from my previous 'improve this function' post :).

-----