29
\$\begingroup\$

(related/inspired by: Draw a bowling formation)

A fun pastime in the winter months here is to perform snowman bowling, using a large ball (like a basketball) and tiny snowman figures. Let's recreate this in ASCII.

Each snowman consists of the following:

(.,.)
( : )

Here is the alignment of the ten snowman "pins"

(.,.) (.,.) (.,.) (.,.)
( : ) ( : ) ( : ) ( : )
   (.,.) (.,.) (.,.)
   ( : ) ( : ) ( : )
      (.,.) (.,.)
      ( : ) ( : )
         (.,.)
         ( : )

These "pins" are labeled from 1 to 10 as

7 8 9 10
 4 5 6
  2 3
   1

So far, so standard. However, unlike normal bowling, the snowman pins are merely flattened and not totally removed. This is done by someone needing to manually flatten the snow of any pins that were struck. A flattened snowman is represented by _____ (five underscores), with whitespace above. Here is an example with the 1 3 5 6 9 10 pins flattened (meaning only the 2 4 7 8 pins remain):

(.,.) (.,.)
( : ) ( : ) _____ _____
   (.,.)
   ( : ) _____ _____
      (.,.) 
      ( : ) _____

         _____

Input

  • A list of integers from 1 to 10 in any convenient format representing which pins were struck and thus need to be flattened.
  • Each number will only appear at most once, and the numbers can be in any order (sorted, unsorted, sorted descending) -- your choice, whatever makes your code golfier.
  • The input is guaranteed to have at least one integer.

Output

The resulting ASCII art representation of the snowman pins, with the correct pins flattened.

Rules

  • Leading or trailing newlines or whitespace are all optional, so long as the characters themselves line up correctly.
  • Either a full program or a function are acceptable. If a function, you can return the output rather than printing it.
  • If possible, please include a link to an online testing environment so people can try out your code!
  • Standard loopholes are forbidden.
  • This is so all usual golfing rules apply, and the shortest code (in bytes) wins.

Examples

1 3 5 6 9 10

(.,.) (.,.)
( : ) ( : ) _____ _____
   (.,.)
   ( : ) _____ _____
      (.,.) 
      ( : ) _____

         _____

1 2 3

(.,.) (.,.) (.,.) (.,.)
( : ) ( : ) ( : ) ( : )
   (.,.) (.,.) (.,.)
   ( : ) ( : ) ( : )

      _____ _____

         _____

1 2 3 4 5 6 8 9 10

(.,.)
( : ) _____ _____ _____

   _____ _____ _____

      _____ _____

         _____
\$\endgroup\$
5
  • 18
    \$\begingroup\$ Code golf? Not code bowling? \$\endgroup\$
    – Mark
    Dec 22, 2016 at 5:44
  • \$\begingroup\$ Can we take the input numbers indexed from 0? And if possible take the input values without spaces such like 0123456789 instead of 1 2 3 4 5 6 7 8 9 10? \$\endgroup\$ Dec 22, 2016 at 12:08
  • \$\begingroup\$ Perfect :D it allows me to make an easier attempt in ><> \$\endgroup\$ Dec 22, 2016 at 13:56
  • 4
    \$\begingroup\$ I do not approve of flattening snowmen. \$\endgroup\$
    – user18932
    Dec 22, 2016 at 16:16
  • \$\begingroup\$ i identify myself as a snowman and find this flattening. \$\endgroup\$ Dec 23, 2016 at 14:17

10 Answers 10

46
\$\begingroup\$

Snowman 1.0.2, 157 bytes

(()("789:045600230001"4aG::48nSdU][:#:]eq]/nM;AsI[:"_____"wR["     "wR/aC;:"( : )"wR["(.,.)"wR/aC;bI;:"  "wRdUaC;bI\#**\;aMaZ:" "aJ1AfL;aM;aM1AfL"
"aJ1AfL*))

Try it online!

When I saw this challenge, I knew I just had to answer in the perfect language...

This is a subroutine that takes input as an array of numbers and outputs as a string via the current permavar.

Wrapped for "readability" / aesthetics:

(()("789:045600230001"4aG::48nSdU][:#:]eq]/nM;AsI[
:"_____"wR["     "wR/aC;:"( : )"wR["(.,.)"wR/aC;bI
;:"  "wRdUaC;bI\#**\;aMaZ:" "aJ1AfL;aM;aM1AfL"
"aJ1AfL*))

Slightly ungolfed / commented version:

}
1wR`
3wR`aC`
5wR`aC`
6wR`aC`
9wR`aC`
*

((
    )(
    "789:045600230001"  // pin layout data
    4aG                 // split into groups of 4; we need each row twice
    :                   // map over groups of 2 output lines
        :               // map over pins (or whitespace)
            48nS        // subtract ascii '0'
            dU][        // duplicate the pin; we need it in the if{}
            :           // if (pin) {
                #:]eq]/nM;AsI[:"_____"wR["     "wR/aC;:"( : )"wR["(.,.)"wR/aC;bI
            ;:          // } else {
                "  "wRdUaC
            ;bI         // }
            \#**\       // maneuver the permavars around to discard pin
        ;aM
        aZ:" "aJ1AfL;aM
    ;aM
    1AfL                // flatten (simulate a flatmap)
    "
"aJ                     // join on newline
    1AfL                // flatten again into a single string
    *
))

#sP
\$\endgroup\$
2
  • 17
    \$\begingroup\$ Pretty much the only context that this will be known as "the perfect language", :P \$\endgroup\$
    – DJMcMayhem
    Dec 21, 2016 at 18:30
  • 3
    \$\begingroup\$ A snowman killing his own kind... You monster! \$\endgroup\$
    – user60199
    Dec 22, 2016 at 19:45
10
\$\begingroup\$

stacked, noncompeting, 118 bytes

I added deepmap and a few other things after this challenge, along with tons of bugfixes. Try it here!

@a((7 8 9 10)(4 5 6)(2 3)(1)){e:('(.,.)
( : )' ' 
_'5 hrep)a e has#'  'hcat
}deepmap{e i:' 
 'i 3*hrep e,$hcat#/!LF+}map

Ungolfed

{ a :
  ((7 8 9 10) (4 5 6) (2 3) (1))
  { e :
    (
      '(.,.)' LF '( : )' + + 
      ' ' LF '_' + + 5 hrep
    ) @possible
    a e has @ind
    possible ind get @res
    '  ' @padding
    res padding hcat return
  } deepmap
  { e i:
    ' ' LF ' ' + + i 3 * hrep
    e ,
    $hcat insert!
    LF +
  } map
} @:bowl

(1 2 3 4 6 10) bowl out

Output:

(.,.) (.,.) (.,.)       
( : ) ( : ) ( : ) _____ 
         (.,.)       
   _____ ( : ) _____ 

      _____ _____ 

         _____ 
\$\endgroup\$
2
  • \$\begingroup\$ This language looks great. The Fisher-Yates example in the wiki is beautiful. \$\endgroup\$
    – Jordan
    Dec 21, 2016 at 18:58
  • \$\begingroup\$ @Jordan thank you so much! that means a lot to me :) \$\endgroup\$ Dec 21, 2016 at 19:07
7
\$\begingroup\$

05AB1E, 45 44 bytes

TF"(.,.)( : )"„ _5×{«4ä2ä¹N>åè})4L£Rvyø»}».c

Try it online!

Explanation

TF                                           # for N in [0 ... 9] do:
  "(.,.)( : )"                               # push string
              „ _                            # push the string " _"
                 5×                          # repeat it 5 times
                   {                         # sort
                    «                        # concatenate the strings
                     4ä                      # split the string in 4 parts
                       2ä                    # split the list in 2 parts
                         ¹N>åè               # if index+1 is in the input, push the first part
                                             # else push the second part
                              }              # end loop
                               )             # wrap stack in a list
                                4L£          # split list in parts of size 1,2,3,4
                                   R         # reverse list
                                    v        # for each list in list of lists
                                     yø      # transpose the list
                                       »     # join by spaces and newlines
                                        }    # end loop
                                         »   # join by newlines
                                          .c # centralize
\$\endgroup\$
7
\$\begingroup\$

Python 2, 248 243 241 226 224 223 221 210 206 200 177 bytes

-5 with thanks to @Rod

-15 again thanks to Rod

-1 using space calculation again from Rod

Looks longer due to more lines and indents but surprisingly 11 bytes shorter.

I'm sure this will go under 200...

I was right but not without 23 bytes worth of serious hints from @Pietu1998. Many thanks!

i,z=input(),0;m=['']*10;n=m[:]
for x in range(11):m[x-1],n[x-1]=('(.,.)',' '*5,'( : )','_'*5)[x in i::2]
for y in 10,6,3,1:
 for q in m,n:print' '*3*z+' '.join(q[y-4+z:y])
 z+=1

Try it online!

Takes input as a list of integers. Way too big at 248 but it works.

\$\endgroup\$
1
6
\$\begingroup\$

C# 233 221 213 203 bytes

method takes an int array a as the list of fallen pins

string S(int[]a){string o="",x=o,y=o,z=o;for(int i=10;i>0;){var c=a.Contains(i);x=(c?"      ":"(.,.) ")+x;y=(c?"_____ ":"( : ) ")+y;if(i==7|i<5&i--!=3){o+=$"{z}{x}\n{z}{y}\n";x=y="";z+="   ";}}return o;}

wrapped

string S(int[]a){string o="",x=o,y=o,z=o;for(int i=10;i>0;)
{var c=a.Contains(i);x=(c?"      ":"(.,.) ")+x;y=(c?"_____ ":
"( : ) ")+y;if(i==7|i<5&i--!=3){o+=$"{z}{x}\n{z}{y}\n";x=y="";
z+="   ";}}return o;}

expanded

string S(int[] a)
{
    string o = "", x = o, y = o, z= o;
    for (int i = 10; i > 0;)
    {
        var c = a.Contains(i);
        x = (c ? "      " : "(.,.) ") + x;
        y = (c ? "_____ " : "( : ) ") + y;

        if (i==7|i<5&i--!=3)
        {
            o += $"{z}{x}\n{z}{y}\n";
            x = y = "";
            z += "   ";
        }
    }
    return o;
}

knocked off a few bytes by suggestions in comments from Ghost, raznagul and auhmaan.

\$\endgroup\$
7
  • 2
    \$\begingroup\$ Welcome to PPCG! \$\endgroup\$ Dec 21, 2016 at 21:02
  • \$\begingroup\$ nice! You can save a few bytes (5?) if you put the i-- in the for and change new[]{7,4,2,1}.Contains(i--) to i<9&&i%3==1||i==2 \$\endgroup\$
    – Ghost
    Dec 22, 2016 at 2:23
  • \$\begingroup\$ Can improve that by two more (for -7) with i==7||i<5&&i!=3 \$\endgroup\$
    – Ghost
    Dec 22, 2016 at 3:32
  • \$\begingroup\$ @Ghost thanks! knocked it down a bit more by using non-shortcurcuit ors and ands, and still decrementing with the final ref to i i==7|i<5&i--!=3 \$\endgroup\$
    – Erresen
    Dec 22, 2016 at 10:47
  • \$\begingroup\$ You can save some bytes by replacing var o="";var x=... by string o="",x="".... \$\endgroup\$
    – raznagul
    Dec 22, 2016 at 11:19
5
\$\begingroup\$

Batch, 262 bytes

@echo off
for /l %%i in (1,1,10)do set s%%i=( : ) 
for %%i in (%*)do set s%%i=_____ 
set l=call:l 
%l%%s7%%s8%%s9%%s10%
%l%"   %s4%%s5%%s6%
%l%"      %s2%%s3%
%l%"         %s1%
exit/b
:l
set s=%~1
set s=%s:( : )=(.,.)%
echo(%s:_____=     %
echo(%~1

Note: Lines 2, 3 and 4 end in a space, and also outputs a trailing space on each line. These can be removed at a cost of 5 bytes. Works by creating variables s1...s10 as the bottom halves of the snowmen, then flattening the ones given as command-line arguments. The appropriate rows are printed twice, the first time with the bottom halves replaced with the top halves. This saves 18 bytes over using two sets of top and bottom half variables.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ That's a slick answer. \$\endgroup\$ Dec 21, 2016 at 21:40
4
\$\begingroup\$

JavaScript, 154 149 bytes

f=
a=>`6 7 8 9
_3 4 5
__1 2
___0
`[r='replace'](/\d|_/g,m=>++m?~a.indexOf(m)?'_____':'( : )':'   ')[r](/.*\n?/g,m=>m[r](/ : |_/g,s=>s=='_'?' ':'.,.')+m)


I.oninput=()=>O.innerHTML=f(JSON.parse(`[${I.value.match(/\d+/g)}]`))
I.oninput()
<input id=I value="1 3 5 6 9 10"><pre id=O>

\$\endgroup\$
3
\$\begingroup\$

Pyth, 63 bytes

j.ejm+**3k;j;db)_CcR[1 3 6).e:*T]btMQ@m*T]*5d,d\_kc2"(.,.)( : )

A program that takes input of a list of integers and prints the result.

Test suite

[Explanation coming later]

\$\endgroup\$
3
\$\begingroup\$

Pyth, 51 bytes

The code contains some unprintables, so here is an xxd hexdump.

00000000: 6a6d 2e5b 3233 5f6a 3b6d 4063 323f 7d6b  jm.[23_j;m@c2?}k
00000010: 5172 2235 2035 5f22 392e 2220 3b5b 8db2  Qr"5 5_"9." ;[..
00000020: 1778 a822 6472 4673 4d50 4253 2d34 2f64  .x."drFsMPBS-4/d
00000030: 323b 38                                  2;8

Try it online.

Without unprintables, 52 bytes

jm.[23_j;m@c2?}kQr"5 5_"9").,.() : ("drFsMPBS-4/d2;8

Try it online.

\$\endgroup\$
2
\$\begingroup\$

Javascript 178 169 bytes

Essentially a port from my C# answer.

Takes an int array as the list of flattened "pins";

f=a=>{o=x=y=z="";for(i=10;i>0;){c=a.includes(i);x=(c?"      ":"(.,.) ")+x;y=(c?"_____ ":"( : ) ")+y;if(i==7|i<5&i--!=3){o+=z+x+"\n"+z+y+"\n";x=y="";z+= "   ";}}return o}

Wrapped:

f=a=>{o=x=y=z="";for(i=10;i>0;){c=a.includes(i);
x=(c?"      ":"(.,.) ")+x;y=(c?"_____ ":"( : ) ")+y;
if(i==7|i<5&i--!=3){o+=z+x+"\n"+z+y+"\n";x=y="";
z+= "   ";}}return o}

Expanded & Explained:

// function f takes parameter a (an array of ints) 
f = a => {
    
    // four strings:
    // o: output
    // x: top row of snowmen
    // y: bottom row of snowmen
    // z: padding to indent the snowmen
    o = x = y = z = "";

    // loop from 10 to 1 (the pins)
    // remove the "afterthought" decrement - we can do that later
    for (i = 10; i > 0;) {

        // set the boolean c to whether the current pin has been flattened
        c = a.includes(i);

        // prefix x and y with the appropriate "sprite"
        // using a ternary if on c
        x = (c ? "      " : "(.,.) ") + x;
        y = (c ? "_____ " : "( : ) ") + y;

        // determine if we've reached the end of a row (i equals 7, 4, 2 or 1)
        // use non shortcircuit operators to save bytes and ensure we hit the final i, because...
        // we also decrement i here 
        // (we didn't do this in the for loop declaration to save a byte)
        if (i == 7 | i < 5 & i-- != 3) {

            // concatenate our rows x & y,
            // prefixing them with the padding z,
            // postfixing them with a newline
            o += z + x + "\n" + z + y + "\n";
            
            // reset x and y rows
            x = y = "";
 
            // increase our padding for next time
            z += "   ";
        }
    }
   
    // return our final string (no semicolon to save a byte)
    return o
}
\$\endgroup\$

Your Answer

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

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