small medium large xlarge

Generic-user-small
11 Jan 2016, 01:31
Diego Villamil (5 posts)

Dear Jamis and Mazers, I have really enjoyed following the book. I am one who falls in the category of non-rubyists and this has been a very enjoyable way to introduce me to that language.

I took the challenge of displaying the maze with these unicode box characters. Yet, I feel like my code can be improved code folding. I wanted to share it for anybody willing to take a look and point me in the right direction.

def to_s
    hrz  =  "\u2500"  # ─
    vrt  =  "\u2502"  # │
    crnr =  "\u2518"  # ┘
    nswe = ["", "\u2576", "\u2574", "\u2500",     #     ╶  ╴   ─
      "\u2577", "\u250C", "\u2510", "\u252C",     # ╷   ┌  ┐   ┬
      "\u2575", "\u2514", "\u2518", "\u2534",     # ╵   └  ┘   ┴
      "\u2502", "\u251C", "\u2524", "\u253C"]     # │   ├  ┤   ┼

    aux_n = Cell.new(-1,-1)
    aux_w = Cell.new(-1,-1)
    aux_d = Cell.new(-1,-1)
    aux_n.link(aux_d)
    aux_w.link(aux_d)

    out = ""
    each_row do |row|
      top = ""
      mid = ""
      btm = ""
      for cell_ in row.each do
        cell_n = cell_.north ? cell_.north : aux_n
        cell_w = cell_.west  ? cell_.west  : aux_w
        cell_d = cell_n.west ? cell_n.west : aux_d

        # Edges referenced from NW corner of cell_
        edge_n = !cell_n.linked?(cell_d)
        edge_s = !cell_w.linked?(cell_)
        edge_w = !cell_w.linked?(cell_d)
        edge_e = !cell_n.linked?(cell_)
        edges = [edge_n, edge_s, edge_w, edge_e]
        key = edges.inject(0){|n, b| 2*n + (b ?1:0)}   
        # The key is the integer corresponding to the binary from `edges`
        # to "open the lock" in nswe and get the right element. 

        top << nswe[key] + hrz*3
        mid << (edge_s ? " " : vrt) + " #{contents_of(cell_)} "

        if cell_.row == @rows-1
          # Edges referenced from SW corner of cell_
          edge_n = edge_s
          edge_s = false
          edge_w = !cell_.west.nil?
          edge_e = true
          edges = [edge_n, edge_s, edge_w, edge_e]
          key = edges.inject(0){|n, b| 2*n + (b ?1:0)}

          btm << nswe[key] + hrz*3
        end
      end

      # Edges referenced from NE corner of cell_
      edge_n = !cell_.north.nil?
      edge_s = true
      edge_w = !cell_n.linked?(cell_)
      edge_e = false
      edges = [edge_n, edge_s, edge_w, edge_e]
      key = edges.inject(0){|n, b| 2*n + (b ?1:0)}

      top << nswe[key] + "\n"
      mid << vrt + "\n"
      out << top + mid + btm
    end

    out << crnr + "\n"
  end

I liked coming up with the vector nswe and (I did get help on) accessing it via a binary representation of the corresponding edges north, south, west, east.

Thank you kindly. Any help will be much appreciated.

Generic-user-small
11 Jan 2016, 05:05
Jamis Buck (30 posts)

Hey Diego, thanks for giving this challenge a try! Using the box characters is trickier than it seems at first glance, but using the “aux” cells as stand-ins for the boundary is a neat trick.

I’ll share just a few suggestions about Ruby:

for cell_ in row.each do

You’re mixing two different iteration styles there. You should either use for cell_ in row, or (best of all) the iterator method, row.each |cell_| do...end. As it is, you’re calling row.each, which iterates over each cell and then returns the collection, and then you’re using for cell_ to iterate over that collection.

cell_n = cell_.north ? cell_.north : aux_n
cell_w = cell_.west  ? cell_.west  : aux_w
cell_d = cell_n.west ? cell_n.west : aux_d

This can be written more idiomatically with the || operator in Ruby, like this:

cell_n = cell_.north || aux_n
cell_w = cell_.west  || aux_w
cell_d = cell_n.west || aux_d

The double-pipe operator returns the first “non-falsey” value (non-nil, non-false), which has the same effect as (but with less duplication than) the ternary operator you used originally.

Thanks for sharing!

Generic-user-small
11 Jan 2016, 20:01
Diego Villamil (5 posts)

Thanks for your hints. It was indeed tricky to use those unicode characters; and it has really brought up a lot of good tricks from Ruby. I also saw another post about not using compact and I wanted to thank you for keeping it simple.

The aux_cell was a derivation on how you had implemented cell = Cell.new(-1,-1) unless cell, which was nice to understand as well.

I did come up with the two iterators for cell_ in row ... end and row.each do |cell_| ... end. I must admit it took me a few times to understand the .each do form, but that’s not the reason why I went back to using the for one. The reason that I went back to it is because after the loop I needed one extra step with the cell_ variable, and thus needed to keep in the workspace. =S

Regards from Mexico City.

You must be logged in to comment