Code Golf: Beehive
Asked Answered
C

14

31

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).

Chablis answered 8/10, 2009 at 19:50 Comment(15)
Stefan: Perhaps, but the way the question was posed, the homeworky smell was masked by a spicy barbecue sauce, so it actually doesn't taste that bad. ;)Counterblow
This is no homework, I have a job.Chablis
LiraNuna, I believe you, but I am just not smart enough to answer.Allethrin
I'm waiting for the first 250 line C# answer - those are always funny in a "golf" questionRugose
Can you add a couple quick bits to spec: input format (two positive integers on one line separated by a single space char), output is printed to screen?Meghannmegiddo
How do you represent the output? Do you have to draw the beehives using the / _ \ characters or can it be any character, like the letter X.Allethrin
LiraNuna is the monarch of golf questions. Look for a new one every Thursday!Caespitose
I swear I did this once in AppleSoft basic, so I could print out "hex paper" on my Dad's 12 pin dot matrix printer. If only I still had the code...Stauffer
@LiraNuna, I know how a hexagon is drawn. What I meant was do we literally have to draw a hexagon?Allethrin
@Brian: You have to input two numbers. It can be done via command line arguments or stdin, you are free to choose, as with previous questions. @Xaisoft: Would you like me to define how a hexagon is drawn? I thought that's what the '1 1' test case is for.Chablis
Is it just me or are the comments being displayed out of order.Allethrin
@strager, I don't think I can (or should) police that, so yes.Chablis
Wait, so are we allowed to have a comma between the numbers on input?Osteoplastic
where's the <20 character J solution?Bromley
@Jason: well i got an 88 character golfscript one..Chrystalchryste
G
21

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.

Gaona answered 8/10, 2009 at 19:50 Comment(14)
I knew Python wouldn't be beating Perl for long.Stereochrome
Do you need the parenthesis around the arguments to map() or did I just shorten your code by 2 characters?Stereochrome
Apparently you do not need them. The parentheses in substr() are unnecessary too -- down to 113.Gaona
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).Stereochrome
Also, you can change $"=$/;print"@P" to $,=$/;print@P and shave the two quotation marks.Stereochrome
No problem. I tried `$\` first too. I wonder how long it'll be before you hit two digits?Stereochrome
"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.Chablis
You can save 2 more characters by replacing 0 by $,=$/ and removing the assignment $,=$/;. The characters saved are 0 and ;.Semiliquid
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$hSemiliquid
@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. =)Semiliquid
I thought it didn't work too. But putting back the spaces and changing it to print$/.substr... go it to work for me.Gaona
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,@hSemiliquid
@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 -.Semiliquid
I've almost lost hope in my solution. =SInaugural
I
10

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]);}
Inaugural answered 8/10, 2009 at 19:50 Comment(15)
Do you need '{' and '}' for 'for' loops?Ablaut
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.Stereochrome
@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.Inaugural
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).Stereochrome
@stranger :) Your welcome. I'm still trying to solve how it works. This is not human-readable and understandable for me.Ablaut
@rekli, Once enough answers have been posted I'll post how mine works. I encourage independent development of ideas.Inaugural
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.Blowtube
@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.Inaugural
Chris Lutz is right about scanf needing a prototype - it's because it's a varargs function.Manse
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. :(Nebo
@Blowtube - It matters because he said his code was C89, which implies conformance to the C89 standard. :PStereochrome
Besides, declaring scanf(char*,...) only takes 16 characters. It's still smaller than the Ruby solution, and vastly smaller than the other solution.Stereochrome
@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...Inaugural
@strager: multiplication commutes so h*scanf() == scanf()*h, right? I don't think C guarantees that h is loaded after the function call.Nebo
I think the %2 may be unnecessary.Gaona
O
10

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
Osteoplastic answered 8/10, 2009 at 19:50 Comment(3)
Put the character count in the header part and it'll be better noticed.Inaugural
Python doesn't automatically parse the command line arguments as a list?Kaikaia
Not fun for who? If you don't like it, you can leave it to me.Osteoplastic
N
6

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
)
Nebo answered 8/10, 2009 at 19:50 Comment(1)
Where did all the smilies went to?!Chablis
N
6

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)}
Nebo answered 8/10, 2009 at 19:50 Comment(3)
Masterpiece? I'm flattered. =]Inaugural
Amazingly, @mobrule's native Perl masterpiece is even shorter than strager's.Stereochrome
@Lutz, That's because my "masterpiece" was designed to be used in C where string manipulation is much more difficult.Inaugural
P
5

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)*(H*2+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.

Preschool answered 8/10, 2009 at 19:50 Comment(2)
You can save some chars if you replace Int32.Parse with int.Parse.Inappreciable
I made your suggested changes, and was able to pull out the "using System;" also! Down to 216 from 226.Preschool
G
4

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...

Gelsemium answered 8/10, 2009 at 19:50 Comment(0)
B
4

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}
$><<$/}
Blowtube answered 8/10, 2009 at 19:50 Comment(0)
C
3

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+*
Chrystalchryste answered 8/10, 2009 at 19:50 Comment(1)
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..Chrystalchryste
S
2

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));
}
Sudbury answered 8/10, 2009 at 19:50 Comment(0)
C
1

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
Charming answered 8/10, 2009 at 19:50 Comment(0)
A
1

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);
        }
    }
Abert answered 8/10, 2009 at 19:50 Comment(0)
A
1

C# 377 chars

Didn't want to disappoint anyone waiting for the "funny" C# answer. Unfortunately, it's not 250 lines though...;)


using System;
class P{
    static void Main(string[] a){
        int i,j,w=Int32.Parse(a[0]),h=Int32.Parse(a[1]);
        string n="\n",e="",o=e,l="__",s=" ",r=s+s,b=@"\",f="/";
        string[] 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];
        Console.Write(o);
    }
}
Aggy answered 8/10, 2009 at 19:50 Comment(3)
Don't feel bad, C#-ers. You still dominate the entire rest of Stack Overflow.Stereochrome
@Lutz, Interesting how the syntax hilighter for SO doesn't understand @"" syntax.Inaugural
lol at 'Don't feel bad.' Not trying to dominate either ... just thought it was a fun exercise ;).Aggy
M
1

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 ""    "\\__/"   "  "
Meghannmegiddo answered 8/10, 2009 at 19:50 Comment(2)
I was wondering, are those double quotes really necessary in F#? If so, why?Chablis
It's three different string literals passed as arguments, so "" is the end of one argument and the beginning of the next.Meghannmegiddo

© 2022 - 2024 — McMap. All rights reserved.