views:

1841

answers:

14
+31  Q: 

Code Golf: Beehive

The challenge

The shortest code by character count that will generate a beehive from user input.

A beehive is defined a a grid of hexagons in a size inputted by the user as two positive numbers greater than zero (no need to validate input). The first number (W) represents the width of the beehive - or - how many hexagons are on each row. The second number (H) represents the height of the beehive - or - how many hexagons are on each column.

A Single hexagon is made from three ASCII characters: _, / and \, and three lines:

 __
/  \
\__/

Hexagons complete each other: the first column of the beehive will be 'low', and the second will be high - alternating and repeating in the same pattern forming W hexagons. This will be repeated H times to form a total of WxH hexagons.

Test cases:

Input:
 1 1
Output:
  __
 /  \
 \__/


Input:
 4 2
Output:
     __    __
  __/  \__/  \
 /  \__/  \__/
 \__/  \__/  \
 /  \__/  \__/
 \__/  \__/


Input:
 2 5
Output:
     __ 
  __/  \
 /  \__/
 \__/  \
 /  \__/
 \__/  \
 /  \__/
 \__/  \
 /  \__/
 \__/  \
 /  \__/
 \__/


Input:
 11 3
Output:
     __    __    __    __    __
  __/  \__/  \__/  \__/  \__/  \__
 /  \__/  \__/  \__/  \__/  \__/  \
 \__/  \__/  \__/  \__/  \__/  \__/
 /  \__/  \__/  \__/  \__/  \__/  \
 \__/  \__/  \__/  \__/  \__/  \__/
 /  \__/  \__/  \__/  \__/  \__/  \
 \__/  \__/  \__/  \__/  \__/  \__/


Code count includes input/output (i.e full program).

+1  A: 

F#, 303 chars

let[|x;y|]=System.Console.ReadLine().Split([|' '|])
let p=printf
let L s o e=p"%s"s;(for i in 1..int x do p"%s"(if i%2=1 then o else e));p"\n"
if int x>1 then L" ""  "" __ ";L" ""__""/  \\"
else L" ""__"""
for i in 1..int y-1 do(L"/""  \\""__/";L"\\""__/""  \\")
L"/""  \\""__/"
L"""\\__/""  "

EDIT

Now that there are finally some other answers posted, I don't mind sharing a less-obfuscated version:

let [|sx;sy|] = System.Console.ReadLine().Split([|' '|])
let x,y = int sx, int sy

let Line n start odd even =
    printf "%s" start
    for i in 1..n do
        printf "%s" (if i%2=1 then odd else even)
    printfn ""

// header
if x > 1 then
    Line x " "   "  "   " __ "
    Line x " "   "__"   "/  \\"
else    
    Line x " "   "__"   "    "

// body
for i in 1..y-1 do
    Line x "/"    "  \\"   "__/"
    Line x "\\"   "__/"    "  \\"

// footer
Line x "/"   "  \\"    "__/"
Line x ""    "\\__/"   "  "
Brian
I was wondering, are those double quotes really necessary in F#? If so, why?
LiraNuna
It's three different string literals passed as arguments, so "" is the end of one argument and the beginning of the next.
Brian
+10  A: 

Python 2.6 - 144 characters including newlines

I can save about 20 more characters if the inputs are allowed to be comma separated.

C,R=map(int,raw_input().split())
print C/2*"    __"+"\n "+("__/  \\"*99)[:3*C-C%2]
r=0
exec'r+=3;print ("\__/  "*99)[r:r+3*C+1-r/6/R*~C%2];'*2*R

The version that takes input from the command line is 4 more bytes:

import sys
C,R=map(int,sys.argv[1:])
print C/2*"    __"+"\n "+("__/  \\"*99)[:3*C-C%2]
r=0
exec'r+=3;print ("\__/  "*99)[r:r+3*C+1-r/6/R*~C%2];'*2*R
recursive
Put the character count in the header part and it'll be better noticed.
strager
Thanks, I've done it.
recursive
Python doesn't automatically parse the command line arguments as a list?
Mark Canlas
i assumed input was on stdin, not command line arguments.
recursive
Show us your command line argument solution, too.
mobrule
There you go. command line.
recursive
command line looks broken. `sys.argv[0]` is the program name
gnibbler
Oh yeah. Thanks. +2 bytes.
recursive
I've fixed command line parsing. -2+4 bytes.
J.F. Sebastian
Thanks. Obviously, I didn't test it. :)
recursive
Using exec in code golf is no fun :/
truppo
Not fun for who? If you don't like it, you can leave it to me.
recursive
+2  A: 

C89 - 261 necessary chars

All white spaces can be removed. My solution uses rotation of the board...

x,y,W,h,B[999],*a,*b,*c,*d;
main(w){
  for(scanf("%d%d",&h,&w);y<h;y++,*b++ = *c++ = 63)
    for(x=0,
        W=w*2+2-(h==1),
        a=B+y*W*3+y%2,
        b=a+W,
        c=b+W,
        d=c+W;x++<w;)

      *a++ = 60,
      *a++ = *d++ = 15,
      *b++ = *c++ = 63,
      *b++ = *c++ = 0,
      *d++ = 60;

  for(x=W;--x>=0;puts(""))
    for(y=0;y<h*3+1;putchar(B[x+y++*W]+32));
}
natrium42
+6  A: 

Perl, 160 characters

$w=shift;for$h(-1..2*shift){push@a,join'',(('\__','/  ')x($w+$h))[$h..$w+$h]}
$a[0]=~y#\\/# #;$a[1]=~s/./ /;s/_*$//for@a;$a[$w%2||$#a]=~s/. *$//;print$_,$/for@a

No cleverness involved at all: just fill the array with characters, then weed out the ones that look ugly.

strager's masterpiece is only 137 characters when ported to Perl, but all credit should go to him.

$w=shift;$\=$/;for$y(1..($h=2+2*shift)){print map+(split//,'_ \__/  ')
[$y-1?$y-2|$_?($_+$y%2*3)%6+2:1:$_%6<4],0..$w*3-!($w&1?$y-2:$y-$h)}
ephemient
Masterpiece? I'm flattered. =]
strager
Amazingly, @mobrule's native Perl masterpiece is even shorter than strager's.
Chris Lutz
@Lutz, That's because my "masterpiece" was designed to be used in C where string manipulation is much more difficult.
strager
+11  A: 

C89 (136 characters)

x;y;w;main(h){for(h=scanf("%d%d",&w,&h)*h+2;y++
<h;++x)putchar(x>w*3-(y==(w&1?2:h))?x=-1,10:
"/  \\__"[--y?y-1|x?(x+y*3)%6:1:x%6<4?1:5]);}
strager
Do you need '{' and '}' for 'for' loops?
rekli
Would totally be cooler if you reversed the string literal and the index. Also, you technically need to `#include <stdio.h>` or something in order to get a proper definition for the `scanf()` function.
Chris Lutz
@Lutz, I've been told I don't need to. Reversing the literal and index won't work unless I add parentheses. @rekli, I can't believe I missed that (and I'm not one to miss such things!). Thanks.
strager
Where did you hear that? I thought varargs functions had to be declared for full standards compliance (of course, we're already breaking rules with a one-arg `main()` so it's probably not worth it).
Chris Lutz
@stranger :) Your welcome. I'm still trying to solve how it works. This is not human-readable and understandable for me.
rekli
@rekli, Once enough answers have been posted I'll post how mine works. I encourage independent development of ideas.
strager
Chris: why would it matter in any tiny way if a code-golf C program was standard conforming? There are thousands and thousands of non-C99-conforming lines in Linux, because that's how the author wants it. There are no ANSI police.
DigitalRoss
@DigitalRoss, I could write a "C compiler" which accepts any input and produces a binary printing the beehive given parameters from stdin, and call the code I write non-standard C. Conformity to *some* standard is required for a reasonable, acceptable solution.
strager
Chris Lutz is right about `scanf` needing a prototype - it's because it's a varargs function.
caf
Hate to be even more pedantic, but I think the lack of a sequence point between `scanf` and `*h` invokes UB, and fixing it costs 2 characters. :(
ephemient
@DigitalRoss - It matters because he said his code was C89, which implies conformance to the C89 standard. :P
Chris Lutz
Besides, declaring `scanf(char*,...)` only takes 16 characters. It's still smaller than the Ruby solution, and vastly smaller than the other solution.
Chris Lutz
@ephemient, It's not UB as far as I know because the function is evaluated before `h` is (thus `h`'s value is changed before the `h` in my code is evaluated into a value). @Lutz, I'll look into if I *need* to declare `scanf`. I may use `atoi` if that's less chars, but I really wouldn't like including that. I can defeat the current Python solution by removing `main(){}` and features/problems of statically-typed languages like C...
strager
@strager: multiplication commutes so `h*scanf()` == `scanf()*h`, right? I don't think C guarantees that `h` is loaded after the function call.
ephemient
I think the `%2` may be unnecessary.
mobrule
@mobrule, Very good catch! Thanks!
strager
+4  A: 

Ruby, 164

$ ruby -a -p bh.rb

strager's masterpiece in Ruby...

w,h = $F; w=w.to_i
(1..(h = h.to_i * 2 + 2)).each { |y|        
  (0...(w * 3 + (y != ((w & 1) != 0 ? 2 : h) ? 1:0))).each { |x|
    $> << ('_ \__/  ' [
      y - 1 != 0 ?
        (y - 2 | x) != 0 ?
          (x + y % 2 * 3) % 6 + 2 : 1 : (x % 6 < 4) ? 1:0]).chr
  }
  $> << $/
}

aka

w,h=$F;w=w.to_i
(1..(h=h.to_i*2+2)).each{|y|(0...(w*3+(y!=((w&1)!=0?2:h)?1:0))).each{|x|$><<('_ \__/  '[y-1!=0?(y-2|x)!=0?(x+y%2*3)%6+2:1:(x%6<4)?1:0]).chr}
$><<$/}
DigitalRoss
+6  A: 

J, 143 characters

4(1!:2)~(10{a.)&,"1({.4 :0{:)".(1!:1)3
|:(18,(}:,32-+:@{:)3 3 8 1 1 10$~3*x){(,' '&(0})"1,' '&(0 1})"1)(,}."1)(}."1,}:"1)(3++:y)$"1'/\',:' _'
)

Using J feels very awkward when dealing with variable-length strings and the sort of console-oriented user interaction that is assumed in other languages. Still, I guess this is not too bad...

Stealing ideas once more (J is much easier to work with once you find a way of looking at the problem in an array-structured way), here's mobrule's masterpiece ported in 124 (ick, it's longer than the original):

4(1!:2)~({.4 :0{:)".(1!:1)3
(x}~' '_1}(x=.-1-+:2|x){])((10{a.),(' ',,99#'__/  \',:'    __'){~(i.>:3*x)+])"0]595 0,3 6$~+:y
)
ephemient
Where did all the smilies went to?!
LiraNuna
@Liran, I see a few: `:0` `{:)` `>:3` `x}~` `(}:` `|:(`
strager
Don't forget: `(}.` `@{:)` `:2)`
Instantsoup
+22  A: 

Perl, 99 characters

@P=map{$/.substr$".'__/  \\'x99,$_,$W||=1+3*pop}0,(3,6)x pop;
chop$P[0-$W%2];print"    __"x($W/6),@P

Last edit: Saved one character replacing -($W%2) with 0-$W%2 (thanks A. Rex)

Explanation:

For width W and height H, the output is 2+2 * H lines long and 3 * W+1 characters wide, with a lot of repetition in the middle of the output.

For convenience, we let $W be 3 * W + 1, the width of the output in characters.

The top line consists of the pattern " __", repeated W/2 == $W/6 times.

The even numbered lines consist of the repeating pattern "\__/ ", truncated to $W characters. The second line of output is a special case, where the first character of the second line should be a space instead of a \.

The odd numbered lines consist of the repeating pattern "/ \__", truncated to $W characters.

We construct a string: " " . "__/ \" x 99. Note that the beginning of this string is the desired output for the second line. This line starting at position 3 is the desired output for the odd lines, and starting at position 6 for the even numbered lines.

The LIST argument to the map call begins with 0 and is followed by H repetitions of (3,6). The map call creates a list of the substrings that begin at the appropriate positions and are $W = 3 * W + 1 characters long.

There is one more adjustment to make before printing the results. If W is odd, then there is an extra character on the second line ($P[0]) that needs to be chopped off. If W is even, then there is an extra character on the bottom line ($P[-1]) to chop.

mobrule
I knew Python wouldn't be beating Perl for long.
Chris Lutz
Do you need the parenthesis around the arguments to `map()` or did I just shorten your code by 2 characters?
Chris Lutz
Apparently you do not need them. The parentheses in substr() are unnecessary too -- down to 113.
mobrule
You might change the first line to `$_=<>;($W,$H)=split;` - it's not any shorter, but it plays nicer with whitespace (entering `2 3` will still be valid).
Chris Lutz
Also, you can change `$"=$/;print"@P"` to `$,=$/;print@P` and shave the two quotation marks.
Chris Lutz
$, ! Thank you. I kept trying $\ for some reason.
mobrule
No problem. I tried `$\\` first too. I wonder how long it'll be before you hit two digits?
Chris Lutz
"I was operating on the assumption that input could come from command line arguments." It doesn't matter where input is coming from, I grant flexibility as long as your input is *just* two numbers and output is the same as test cases.
LiraNuna
You can save 2 more characters by replacing `0` by `$,=$/` and removing the assignment `$,=$/;`. The characters saved are `0` and `;`.
A. Rex
Nice, A. Rex !!
mobrule
Finally, 102 characters with a rewrite that also fixes the 99 limitation: `$h=pop;$x=1+($W=1+3*pop)%2*2*$h;print substr$"."__/ \\"x$W." __"x$W,$_,$W-!$x--for-6*$W,0,(3,6)x$h`
A. Rex
@A.Rex - Did you check it? It doesn't work.
LiraNuna
@LiraNuna: There are a couple issues. One is with Stack Overflow, in that the string constants had their spaces compressed (they're the same as in the post above). The other is that I didn't realize I was running Perl with the -l switch, which probably should count as characters. But with these two changes, yes, I've checked and it does work. =)
A. Rex
I thought it didn't work too. But putting back the spaces and changing it to `print$/.substr...` go it to work for me.
mobrule
The forgotten `-l` switch is a shame, because that would count for 3 characters in Perl golf competitions, or maybe 2 characters if you don't care about trailing newlines with @mobrule's `print$/.substr`. In any case, here's 101 characters, which works assuming a `-l` switch and corrected string constants: `@h=(3,6)x pop;$x=1+($W=1+3*pop)%2*@h;print substr$"."__/ \\"x$W." __"x$W,$_,$W-!$x--for-6*$W,0,@h`
A. Rex
@mobrule: By the way, I never told you that your code is awesome. Anyway, to get your code into two-digit range, change `-($W%2)` to `0-$W%2`. Binary `-` binds looser than `%` which binds looser than unary `-`.
A. Rex
I've almost lost hope in my solution. =S
strager
Grats on winning!
strager
+2  A: 
markt
Don't feel bad, C#-ers. You still dominate the entire rest of Stack Overflow.
Chris Lutz
@Lutz, Interesting how the syntax hilighter for SO doesn't understand `@""` syntax.
strager
lol at 'Don't feel bad.' Not trying to dominate either ... just thought it was a fun exercise ;).
markt
+4  A: 

C#, 216 characters

class B{static void Main(string[]a){int b=0,i=0,w=int.Parse(a[0])+1,z=2*w*(int.Parse(a[1])+1);for(;i<z;b=(i%w+i/w)%2)System.Console.Write("\\/ "[i>w&(w%2>0?i<z-1:i!=2*w-1)?b>0?0:1:2]+(++i%w<1?"\n":b>0?"__":"  "));}}

Less obfuscated:

class B{
    static void Main(string[]a){
       int b=0,
           i=0,
           w=int.Parse(a[0])+1,
           z=2*w*(int.Parse(a[1])+1);

       for(;i<z;b=(i%w+i/w)%2)
           System.Console.Write(
             "\\/ "[i>w&(w%2>0?i<z-1:i!=2*w-1)?b>0?0:1:2]
             +
             (++i%w<1?"\n":b>0?"__":"  ")
           );
    }
}

I used the following method:

input: 4 2
cols:  0 00 1 11 2 22 3 33 4 44  
row 0:" |  | |__| |  | |__| |"
    1:" |__|/|  |\|__|/|  |\|"
    2:"/|  |\|__|/|  |\|__|/|"
    3:"\|__|/|  |\|__|/|  |\|"
    4:"/|  |\|__|/|  |\|__|/|"
    5:"\|__|/|  |\|__|/|  | |"
  1. Iterate from zero to (W+1)(H2+1). The *2 is because each comb is 2 lines tall, and +1 to account for the first line and end of lines.
  2. Render two "pieces" of a hexagon per iteration:
  3. Decide between " ", "\", and "/" for the first part
  4. Decide between "__", "  ", and "\n" for the second part

The pattern is evident if you look at a large enough honeycomb. Half the logic is there only to address exceptions in the first row, the end of the second row, and the last cell.

Jeff Meatball Yang
You can save some chars if you replace `Int32.Parse` with `int.Parse`.
Scoregraphic
I made your suggested changes, and was able to pull out the "using System;" also! Down to 216 from 226.
Jeff Meatball Yang
+1  A: 

Groovy, #375 chars

Same logic & code that @markt implemented in c#, but have changed few places for Groovy :)

public class FunCode {
        public static void main(a) {
         int i,j,w=Integer.parseInt(a[0]),h=Integer.parseInt(a[1]);
            String n="\n",e="",o=e,l="__",s=" ",r=s+s,b="\\",f="/";
            def t=[r+r,l,b+l+f,r,l,f+r+b,e,f,b,s];
            for(i=0;i<w;)o+=t[i++%2];
            for(i=0;i<2*h;i++){
                o+=n+(i%2==0?i!=0?b:s:e);
                for(j=0;j<w;)
                    o+=t[((j+++i)%2)+4];
                o+=i!=0?t[((w+i)%2)+6]:e;
            }
            o+=n;
            for(i=0;i<w;)o+=t[i++%2+2]; println(o);
        }
    }
TuxGeek
+1  A: 

Lua, 227 characters

w,h,s=io.read("*n"),io.read("*n")*2+2," " for i=1,h do b=(i%2>0 and "/  \\__" or "\\__/  "):rep(w/2+1):sub(1,w*3+1) print(i==1 and b:gsub("[/\\]",s) or i==2 and b:gsub("^\\",s):gsub("/$",s) or i==h and b:gsub("\\$",s) or b) end

208 characters, when width and height are read from command line.

s,w,h=" ",... h=h*2+2 for i=1,h do b=(i%2>0 and "/  \\__" or "\\__/  "):rep(w/2+1):sub(1,w*3+1) print(i==1 and b:gsub("[/\\]",s) or i==2 and b:gsub("^\\",s):gsub("/$",s) or i==h and b:gsub("\\$",s) or b) end
gwell
+3  A: 

NewLisp: 257 chars

I'm sure this is not an optimal solution:

(silent(define(i v)(println)(set v(int(read-line))))(i'w)(i'h)(set't(+(* 3 w)1))(set'l " __/ \\__/ ")(define(p s e(b 0))(println(slice(append(dup" "b)(dup(s 6 l)w))0 e)))(p 0 t)(p 4(- t(% w 2))1)(dotimes(n(- h 1))(p 6 t)(p 9 t))(p 6 t)(p 9(- t(%(+ w 1)2))))

Less obfuscated:

(silent
  (define (i v)
          (println)
          (set v (int (read-line))))
  (i 'w)
  (i 'h)
  (set 't (+ (* 3 w) 1))
  (set 'l "    __/  \\__/  ")
  (define (p s e (b 0))
          (println (slice (append (dup " " b) (dup (s 6 l) w)) 0 e)))
  (p 0 t)
  (p 4 (- t (% w 2)) 1)
  (dotimes (n (- h 1))
    (p 6 t)
    (p 9 t))
  (p 6 t)
  (p 9 (- t(% (+ w 1)2))))

I'm sure I could write the loop differently and save two lines and a few characters, for instance, but it's late...

Galghamon
+3  A: 

Golfscript, 88 characters

Based on the mobrule's solution. It was a lot of work to get it smaller than that one! Newlines are just for clarity.

~:r;:c 3*):W 6/"    __"*n
[][0]r[3 6]*+{[" ""__/  \\"99*+>W<]+.},;
c 2%-1 1if:r%)[-1<]+r%
n*

Explanation:

~:r;,:c              # read input into rows, columns
3 *):W               # store c*3+1 into W
6 /"    __"*n        # write out "    __" W/6 times, plus newline
[]                   # initialize output array
[0]r[3 6]*+          # create array [0] + [3,6] repeated r times
{                    # for every entry in the input array...
[" ""__/  \\"99*+    #   create the magic string
>W<                  #   truncate it between [n:W], where n is the cur entry
]+                   #   store this line in the output array
.},;                 # repeat for every entry in array
                     # now to handle the extra cases:
c 2%-1 1if:r%        # reverse the array if c is odd, do nothing if it's even
)[-1<]               # take the last entry in the array, cut off the last char
+r%                  # put it back on the array, and un-reverse it
n*                   # now join the array with newlines


Here is my original entry at 118 characters:

Late entry, but it's 2nd smallest! (I'm just using these to learn Golfscript). Newlines are for clarity.

~:r;:c 2%:o;c 2/:b"    __"*n:e
{e" ""\\"if"__/  \\"b*o{"__"e{"":e}"/"if}{"":e}if n
"/""  \\__/"b*o"  \\"""if n}r*
"\\__/  "b o+*
Claudiu
most of the code is dealing with odd numbers =(. maybe ill try porting mobrules solution, but i dnno if you can truncate strings in golfscript..
Claudiu