15
\$\begingroup\$

In my previous challenge, I drew the first diagram mostly by hand (with the help of vim's visual block mode). But surely there must be a better way...


Given an input of two dimensions, a width and a height, output a hexagonal grid with those dimensions in ASCII art.

Here's the diagram referenced in the intro (with minor edits), which should be your output for the input width=7, height=3:

         _____         _____         _____
        /     \       /     \       /     \
  _____/ -2,-1 \_____/  0,-1 \_____/  2,-1 \_____
 /     \       /     \       /     \       /     \
/ -3,-1 \_____/ -1,-1 \_____/  1,-1 \_____/  3,-1 \
\       /     \       /     \       /     \       /
 \_____/ -2,0  \_____/  0,0  \_____/  2,0  \_____/
 /     \       /     \       /     \       /     \
/ -3,0  \_____/ -1,0  \_____/  1,0  \_____/  3,0  \
\       /     \       /     \       /     \       /
 \_____/ -2,1  \_____/  0,1  \_____/  2,1  \_____/
 /     \       /     \       /     \       /     \
/ -3,1  \_____/ -1,1  \_____/  1,1  \_____/  3,1  \
\       /     \       /     \       /     \       /
 \_____/       \_____/       \_____/       \_____/

Notice several things:

  • The width and height are essentially equivalent to how many hexagons there are for a given y and x coordinate respectively. These will always be odd numbers.

  • Each hexagon is represented by the ASCII art

      _____
     /     \
    /       \
    \       /
     \_____/
    

    but borders are "shared" between neighboring hexagons.

  • The comma in the coordinates is always exactly two characters below the center of the top edge. The x-coordinate is then positioned directly before the comma, and the y-coordinate directly after.

    You may assue that the coordinates will never be too large such that they would overlap the hexagon's borders.

Input may be taken as a whitespace-/comma-separated string, an array of integers, or two function/commandline arguments. Output must be a single string (to STDOUT, as a return value, etc.).

Since this is , the shortest code in bytes will win.

The grid above can be used as a test case. The maximum-sized width=199, height=199 grid is obviously impractical to include here, but the first few rows and columns should look like the following:

         _____         ___
        /     \       /   
  _____/-98,-99\_____/-96,
 /     \       /     \    
/-99,-99\_____/-97,-99\___
\       /     \       /   
 \_____/-98,-98\_____/-96,
 /     \       /     \    
/-99,-98\_____/-97,-98\___
\       /     \       /   
 \_____/-98,-97\_____/-96,
 /     \       /     \    
/-99,-97\_____/-97,-97\___
\       /     \       /   
\$\endgroup\$
1
  • 1
    \$\begingroup\$ Related \$\endgroup\$
    – Alex A.
    Jan 25, 2016 at 22:04

1 Answer 1

2
\$\begingroup\$

Ruby, 221 bytes

->w,h{s=' '
a=(s*9+?_*5)*(w/2)+$/
(2-h*2).upto(h*2+3){|y|c=y<4-h*2 
a+=[b=c ?s:?\\,s+b,s,''][y%4]
(0-w/2).upto(w/2){|x|a+=["/#{h<y/2?s*7:"%3d,%-3d"}\\",s*7,?_*5,"/     \\"][(y+x*2+w)%4]%[x,y/4]}
a+='//  '[c ?3:y%4]+$/}
a}

Ungolfed in test program

f=->w,h{
  s=' '                                #set s to space for golfing reasons
  a=(s*9+?_*5)*(w/2)+$/                #start building the output with a row of just _ and space

  (2-h*2).upto(h*2+3){|y|              #iterate 4 times for each row of hexagons, plus an extra 2 at the end to finish last row
    c=y<4-h*2                          #condition for first two rows
    a+=[b=c ?s:?\\,s+b,s,''][y%4]      #string to be output before main set of hexagons (spaces for top row, \ for certain other rows

    (0-w/2).upto(w/2){|x|              #iterate through hexagons on each row, 4 lines for each with the following printf type string
      a+=["/#{h<y/2?s*7:"%3d,%-3d"}\\",#line 1:contains ends / \ and numbers 
         s*7,                          #line 2 padding spaces
         ?_*5,                         #line 3 padding ___
         "/     \\"][(y+x*2+w)%4]%     #line 0 top of hexagon / \; formula to select string to be printed
           [x,y/4]                     #numbers to be printed (if format for current line does not require them they are ignored)
    }

    a+='//  '[c ?3:y%4]+$/             #ending alternates between / and space; / are suppressed for first two rows
  }
  a
}

puts g[7,3]
puts g[5,5]

Output

As I was finishing debugging, I noticed an ambiguity in the spec. Where w+1 is divisible by 4, the first and last x coordinates are odd, and there is no ambiguity. But where w-1 is divisible by 4 the first and last x coordinates are even. I assumed that the first and last columns should be offset below the next ones. But then I read the previous question and noted in that case it was the odd columns that should be offset below the even ones (note for w-1 divisible by 4 it is not possible to do both.)

That distinction was not made in this question, however. I will leave this up to OP's judgement and rework if necessary, though I'd prefer not to have to.

         _____         _____         _____
        /     \       /     \       /     \
  _____/ -2,-1 \_____/  0,-1 \_____/  2,-1 \_____
 /     \       /     \       /     \       /     \
/ -3,-1 \_____/ -1,-1 \_____/  1,-1 \_____/  3,-1 \
\       /     \       /     \       /     \       /
 \_____/ -2,0  \_____/  0,0  \_____/  2,0  \_____/
 /     \       /     \       /     \       /     \
/ -3,0  \_____/ -1,0  \_____/  1,0  \_____/  3,0  \
\       /     \       /     \       /     \       /
 \_____/ -2,1  \_____/  0,1  \_____/  2,1  \_____/
 /     \       /     \       /     \       /     \
/ -3,1  \_____/ -1,1  \_____/  1,1  \_____/  3,1  \
\       /     \       /     \       /     \       /
 \_____/       \_____/       \_____/       \_____/
         _____         _____
        /     \       /     \
  _____/ -1,-2 \_____/  1,-2 \_____
 /     \       /     \       /     \
/ -2,-2 \_____/  0,-2 \_____/  2,-2 \
\       /     \       /     \       /
 \_____/ -1,-1 \_____/  1,-1 \_____/
 /     \       /     \       /     \
/ -2,-1 \_____/  0,-1 \_____/  2,-1 \
\       /     \       /     \       /
 \_____/ -1,0  \_____/  1,0  \_____/
 /     \       /     \       /     \
/ -2,0  \_____/  0,0  \_____/  2,0  \
\       /     \       /     \       /
 \_____/ -1,1  \_____/  1,1  \_____/
 /     \       /     \       /     \
/ -2,1  \_____/  0,1  \_____/  2,1  \
\       /     \       /     \       /
 \_____/ -1,2  \_____/  1,2  \_____/
 /     \       /     \       /     \
/ -2,2  \_____/  0,2  \_____/  2,2  \
\       /     \       /     \       /
 \_____/       \_____/       \_____/
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.