/ elixirgolf Public

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

# Elixir Christmas Tree Puzzle#3

Open
opened this issue Dec 4, 2015 · 31 comments
Open

# Elixir Christmas Tree Puzzle #3

opened this issue Dec 4, 2015 · 31 comments

### Use your elixir coding skills to create a Christmas tree

Your code should create a triangle of `0` characters that is `9` rows high. At the top of the tree should be a star `*` and at the bottom there should be a trunk `H`. The star and trunk should be aligned, and the start should be directly above the top of the tree. The start and trunk are addional rows, therefore the entire tree is a total of 11 characters high.

http://elixirgolf.com/articles/elixir-christmas-tree-puzzle/

2. Remember to add your Twitter handle (I will link to it if you get a mention)
Many thanks, Ben
When the puzzle is over I'll write them up on http://elixirgolf.com and link back to your Twitter handle

### notexactlyawe commented Dec 4, 2015

 Assuming you have `h` defined beforehand as the number of rows of 0s you want `import String;a=duplicate(" ",h-1);IO.puts"#{a}*";for i<-1..h do IO.puts"#{duplicate(" ",h-i)}#{duplicate("0",i*2-1)}"end;IO.puts"#{a}H"` I believe 136 characters. This goes down to 134 when replacing h with 9 (h-1 then cancels down to 8). twitter: @notexactlyawe

### emson commented Dec 4, 2015

 Great @notexactlyawe you don't need the `h=9` for this puzzle - it's all a fixed size. Also you can remove a few brackets: `import String;a=duplicate " ",8;IO.puts"#{a}*";for i<-1..h do IO.puts"#{duplicate " ",9-i}#{duplicate "0",i*2-1}"end;IO.puts"#{a}H"` So you're at 131 chars!

### notexactlyawe commented Dec 4, 2015

 Cool, thanks :)

### vanstee commented Dec 4, 2015

 Got it down to 101 chars using `List.duplicate/2`. ``````d=&List.duplicate/2;p=&IO.puts d.(32,9-&1)++&2;p.(1,'*');for i<-1..9,do: p.(i,d.(48,2*i-1));p.(1,'H') `````` I think there might be a way to get a little lower with `String.rjust`, but the least I could do with that one was 117. @vanstee on twitter as well. Edit: D'oh not sure why I included the spaces on the right side.

### henrik commented Dec 4, 2015

 My "own" solution, 104 characters (the linebreak is significant and counts as a single character): ```d=&String.duplicate/2;s=d.(" ",8);IO.puts [s,"* ",(for i<-0..8,do: [d.(" ",8-i),d.("0",i*2+1),10]),s,?H]``` `10` is the ASCII code for a newline. If I borrow @vanstee's `List.duplicate` trick (clever!), I can get down to 99 characters: ```d=&List.duplicate/2;s=d.(32,8);IO.puts [s,"* ",(for i<-0..8,do: [d.(32,8-i),d.(?0,i*2+1),10]),s,?H]``` `32` is the ASCII code for a space. `?` (questionmark-space) also works but gives a warning. All these solutions make use of Elixir's wonderful chardata concept, where `IO.puts` accepts nested arrays of strings or codepoints and joins them into a string. `henrik` on Twitter.

### stoft commented Dec 5, 2015

 My feeble attempts started out something like this (before I realized I was printing 17 lines instead of 17 zeroes...): ``` * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 H``` which evolved into this (I think I've got the beginnings of a nice console game though) ``` * 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 H``` and then into the most lopsided tree ever: ``` * 0 00 000 0000 00000 000000 0000000 00000000 000000000 0000000000 00000000000 000000000000 0000000000000 00000000000000 000000000000000 0000000000000000 H``` It was cracking me up quite a bit though. 😂

### stoft commented Dec 5, 2015

 And the hilarity just continues! ``` * 0 000 00000 0000000 000000000 00000000000 0000000000000 000000000000000 H``` ``` * 00 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0```

### stoft commented Dec 5, 2015

 Finally! My humble solution of way too many chars (I have yet to look at the other solutions mind you): `for x <- 0..10, y = (x < 1 && "*" || x > 9 && "H" || "0"), z = 1 < x && x < 10 && String.ljust("0", x - 1, ?0)||"", do: IO.puts(String.rjust(z, 8) <> y <> z)`

### stoft commented Dec 5, 2015

 ...and a solution that's 2 chars shorter than my previous one! (well aware that I can shave whitespace and similar from my previous solution) But this one is so "stupid" I have to post it. :) ```IO.puts " * 0 000 00000 0000000 000000000 00000000000 0000000000000 000000000000000 00000000000000000 H"```

### stoft commented Dec 5, 2015

 My original solution with trimmings (pun intended), 117 chars (which I'm pretty happy with): `for x<-0..10,y=x<1&&"*"||x>9&&"H"||"0",z=1y<>z` edit: @stoftis on twitter

### stoft commented Dec 5, 2015

 And now reading through the comments I realized I probably duplicated @vanstee 's solution he mentioned but never posted. :)

### emson commented Dec 5, 2015

 That's great... although I think the tree needs to be a bit more festive: `d=&List.duplicate/2;s=d.(32,8);IO.puts [s,"* ",(for i<-0..8,do: [d.(32,8-i),d.(Enum.random(~W(> = < ~ ~)),i*2+1),10]),s,?H]`

### stoft commented Dec 5, 2015

 Oh I agree! `d=&List.duplicate/2;s=d.(32,8);IO.puts [s,IO.ANSI.yellow <> "* ",(for i<-0..8,do: [d.(32,8-i),d.(Enum.random([IO.ANSI.green, IO.ANSI.red]) <> Enum.random(~W(> = < ~ ~)),i*2+1),10]),s,?H]` 🎅 🎄 ⛄ 🎁

### emson commented Dec 5, 2015

 Or this one is even better... `d=&List.duplicate/2;s=d.(32,8);IO.puts [s,"* ",(for i<-0..8,do: [d.(32,8-i),(for x<-1..i*2+1,into: [],do: Enum.random ~W(~ x o ~ ~)),10]),s,?H]` Which gives: ``` * ~ox ~o~~~ ~~~~~~o ~~o~~~~~~ ~x~~~x~x~x~ ~x~~x~~oxo~o~ ~~~ox~o~o~~~~ox ~~~ooox~~o~o~~~xx H```

### henrik commented Dec 6, 2015

 Hehe, I've also been meaning to make a festive one. This one assumes your terminal allows ANSI blinking. Did some things to keep it short but I haven't gone full golf on it: `import IO.ANSI;r=reset;b=blink_slow;g=green;y=yellow;d=&List.duplicate/2;s=d.(32,8);t=Stream.cycle([[g,?/],[red,?o],[g,?\\],[y,b,?i,r]]);IO.puts [s,y,b,"*\n",r,(for i<-0..8,do: [d.(32,8-i),Enum.take(t,i*2+1),10]),s,r,?H]` Even without blinking enabled in the terminal, you could probably use `IO.ANSI.clear` and a timer if anyone wants to go further with this :D

### emson commented Dec 6, 2015

 @stoft & @henrik oh man they are great. Brilliant. I have to say I laughed out loud when I saw the flashing lights. Well done

### rubysolo commented Dec 6, 2015

 Best I can do so far is 103 characters: `c=&[:string.centre(&1,17),'\n'];IO.puts c.('*')++(for i<-0..8,do: c.(List.duplicate 48,2*i+1))++c.('H')` Note that it has an extra blank line below the trunk. If that is not acceptable, I could switch `IO.puts` to `IO.write`, then I'm at 104 characters. @rubysolo

### henrik commented Dec 7, 2015

 @rubysolo Oh, neat discovery with `:string.centre`!

### emson commented Dec 7, 2015

 @rubysolo thanks for your solution. Great that you used Erlang. I think it's all to easy to think of elixir as one language, and forget that you have this whole other ecosystem. Well done! PS for this puzzle I haven't implemented @henrik elixir test Gist - therefore I'm happy to ignore the extra blank line.

### fishcakez commented Dec 8, 2015

 `:io.format("~10.1c~s~n~10.1c~n",[?*,(for n<-1..9,do: :io_lib.format("~n~#{9+n}.#{2*n-1}c",'0')),?H])` 89 characters We did this at the Elixir Southampton Meetup

### emson commented Dec 8, 2015

 Excellent thanks a lot. @fishcakez could you add your Twitter handle and I'll link the newsletter to you, if you are ok with it? Thanks a lot. Maybe you could come up to the Edinburgh elixir meet up 😉

### henrik commented Dec 8, 2015

 @fishcakez Very cool solution! I count 100 chars, but you can get it to 96 by trimming some parentheses and spaces: `:io.format"~10.1c~s~n~10.1c~n",[?*,(for n<-1..9,do: :io_lib.format"~n~#{9+n}.#{2*n-1}c",'0'),?H]`

### fishcakez commented Dec 8, 2015

 @henrik ah good spot. Forgot to escape interpolation so our counting method messed up. With that parentheses trick maybe we got a shorter one. @emson, sorry not got twitter. But we messed up counting. Will have too see about going to one if I can bring in some other things.

### fishcakez commented Dec 9, 2015

 `:io.format"~10s~s~n~10s~n",["*",(for n<-1..9,do: :io_lib.format"~n~#{9+n}.#{2*n-1}c",'0'),"H"]` 94 by using ~10s.

### ventsislaf commented Dec 9, 2015

 `p=&(IO.puts :string.centre&1,17);p.('*');for n<-1..9,do: p.(List.duplicate ?0,n*2-1);p.('H')` 92 characters. I did this after the Southampton Elixir Meetup. Thanks for the great time guys and specially @fishcakez for coming all the way there! Twitter handle: `@ventsislaf`

### henrik commented Dec 9, 2015

 @ventsislaf Wow. You can shave another two off for an even 90: `p=&IO.puts :string.centre&1,17;p.('*');for n<-1..9,do: p.(List.duplicate ?0,n*2-1);p.('H')` I intentionally did not try for centering since the example output of the challenge had no right-side spaces, but the visual output is the same – it's fun seeing all kinds of solutions.

### emson commented Dec 9, 2015

 Great solution well done... for a moment I thought you could change the Erlang char `'*'` to `?*` but it appears because it's an Erlang function you can't. Interesting thanks!

### ventsislaf commented Dec 9, 2015

 @henrik nice! I couldn't spot that after all the minimizing. @emson I had the same thought 😆 I have to say that this is probably the most unreadable 90 characters of code I've ever wrote. Great fun, thank you for the quiz!

### fishcakez commented Dec 9, 2015

 @ventsislaf well done!

### henrik commented Dec 9, 2015

 @emson I don't think it's so much about being an Erlang function – `?*` is the same as `42`; `'*'` is the same as `[42]`; `'*'` is thus also the same as `[?*]`. So some Erlang functions require an Erlang string (array of characters), others accept standalone characters/integers. Elixir functions make similar distinctions. The reason I could use `?*` and friends was because I made use of Elixir chardata, which has a kind of equivalent in Erlang iolists/iodata. In some contexts, you're allowed to mix strings with standalone characters and the language makes sense of it all. I've been meaning to blog about this some day – it's a really useful concept.

### rubysolo commented Dec 10, 2015

 Here's a different approach -- it's not anywhere near competitive at 150-ish characters, but it was fun to play with, so I thought I'd share it. 😄 ```m=' *H0' c=fn x,x when x<0->x*-1 _,x when x<0->0 _,_->3 end z=&Enum.at m,c.(&1,&1-abs &2-9) for i<-1..11,do: IO.puts Enum.map 1..17, &z.(rem(i,11)-2,&1)```

to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants