44
\$\begingroup\$

Your goal is to display ASCII art of a formation in ten-pin bowling where only some of the pins remain. Fewest bytes wins.

The tens pins are in a triangular formation:

O O O O         
 O O O   
  O O       
   O

Pins are labelled from 1 to 10 as:

7 8 9 10    
 4 5 6            
  2 3    
   1

Drawing pins as O and missing pins as ., the formation 1 3 5 6 9 10 is:

. . O O         
 . O O    
  . O       
   O

Input:

A space-separated string that lists a nonempty subset of the numbers 1 though 10 in order.

Output:

Print the corresponding formation or output it as a string with linebreaks.

The formation should be flush with the left of the screen. Any whitespace is fine as long as the visible image is correct. Empty lines before and after are fine too.

Test cases:

>> 1 2 3 4 5 6 7 8 9 10

O O O O    
 O O O    
  O O    
   O

>> 7 10

O . . O    
 . . .   
  . .   
   .

>> 3 5 7 9 10

O . O O    
 . O .    
  . O    
   .

>> 1

. . . .    
 . . .    
  . .    
   O       
\$\endgroup\$
  • \$\begingroup\$ Can you guarantee that there will be at least one pin? It will save characters for me if I can choke on empty input. \$\endgroup\$ – undergroundmonorail Jan 6 '15 at 19:39
  • 1
    \$\begingroup\$ @undergroundmonorail It's already guaranteed: "nonempty subset" \$\endgroup\$ – xnor Jan 6 '15 at 19:40
  • \$\begingroup\$ I totally missed that, thanks :) \$\endgroup\$ – undergroundmonorail Jan 6 '15 at 19:42
  • \$\begingroup\$ [code-bowling]? :P \$\endgroup\$ – mbomb007 Jul 25 '18 at 14:08

30 Answers 30

17
\$\begingroup\$

brainfuck - 617 616 604 bytes

+>>>>,[>++++[<-------->-]<[>>>>],]<<<<[>+<<+<+>>-]<[>+<-]+<+<<[>+>-<<-]>[<+>-]>[,+++++[>+++++<-]>>[<->-]<[>>>>>[>>>>]+[<<<<]<-]>>[<+>-]<<<]>[>>[,<]<<+++++++++<]<<<[-[+>>-<]>[>>[<+<+>>-]<<<<[>+>-<<-]>[<+>-]>[<<[<<<<]>>>>[[<<<<+>>>>-]>>>>]<<<<+>>-]>[>+<-]]<<<[-[+>]+<<<<]>>>>-<<<<<]>>>>>+++++[>----<-]>->[<+>>+<-]<[<<<[<<<<]+[>>>>]<-]>>[<+>-]<[<<<<]>>>++++[<-------->-]>[-[,+++>]+>>>[<<<->>]>]<<<<<[>-]>[>>]>>+[<++++[<++++++++>-]<]>>[+++++++++++++>>>>]<<<<----<+++[<<+<<[<<+<<]+[>>>>]<<<<-]<<<<[-<<<<]>[.,>>]<<<<<[<<<<]<++++++++++<<.<+<<+<<+<<+<<+<[.,>>]<<<<<[<<]>++++++++++<+<<+<<+<..<+<[.,>>]<[<<]<...<<.

This took me the better part of two days. I think it was worth it. There's probably parts that can be golfed more by changing what cell something is stored in or whatever, but right now I'm just happy I got it working.

This program would have to be completely different if the question didn't specify that the input would be sorted. The way this works is by constructing a list of 10 pins around the ones that are input. That's kind of confusing but maybe this will explain it better:

If you input these pins:           [2, 3, 6, 8, 9]
First, the program does this:      [2, 3, 6, 8, 9] + [10]
Then this:                         [2, 3, 6] + [7] + [8, 9, 10]
Then this:                         [2, 3] + [4, 5] + [6, 7, 8, 9, 10]
Finally, this:                     [1] + [2, 3, 4, 5, 6, 7, 8, 9, 10]
To build this:                     [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

While it's doing that, it remembers which of the pins the user put there and which ones it put there. This strategy would be very difficult to use if the input wasn't sorted.

Another thing that the sorting make easier is detection of the number 10. Since brainfuck deals with individual bytes, not "numbers" per se, it could have been a pain in the ass, but the sorted input made it much easier for me to deal with. The reason for that has to do with how I stored data in the program. I take the input one character at time and subtract 32 from the result. If the cell is non-zero after that, I move forward 4 cells. before repeating. This means that I get a non-space byte of input every 4 cells, and I effectively store pins as their number + 16. However, 10 takes two bytes to type, so I had to special case it. If the input wasn't sorted, I'd have to look through the pins, but since it is sorted it will always be the last pin if it appears. I check if the (last byte of input + 1) == (the second last byte of input) and if so, it must be 10. I get rid of the last byte and set the second last one to what my system understands as "10". The characters '1' and '0' don't fit in a single byte, but the number 26 sure does!

Coming up with tricks just to make something work at all is my favourite part of using this language. :)

If you're interested in how this program works in more detail, you can see the program with the comments I used while writing it to make sure I remembered what everything did. Even writing comments in brainfuck is hard, since there's no comment syntax. Instead, every character except those in <[+.,-]> are no-ops. It's easy to introduce bugs by accidentally including . or , in your comments! That's why the grammar is so wonky and semicolons are everywhere.

EDIT: As an example of how easy this is to screw up: I used "non-space" in one of the comments! When I stripped all the non-bf characters from the source, the program I used to do that kept in the -. Luckily it didn't break anything, but now I've removed it to save a byte. :)

EDIT II: It's been a while since I touched this one, haha. In another brainfuck answer on this site, I noticed that I accidentally used a comma in the commented version. Since the input had already been exhausted, it set the current cell to 0 (this is implementation dependant, but in my experience it's the most common behaviour). I fixed the bug, but it got me thinking. The idiomatic way to set a cell to 0 is [-] (roughly while (*p) { *p--; }), which is two bytes longer. Any time all the input has been read, I can use , instead. This saved me 2 bytes in that answer, and 12 in this one!

one flag at the very left; will be important later
+>>>>

all nonspace bytes of input separated by 3 empty cells; pin number `n` stored with value `n` plus 16
,[>++++[<-------->-]<[>>>>],]<<<<

test if last pin is 10
[>+<<+<+>>-]<[>+<-]+<+<<[>+>-<<-]>[<+>-]>

[
    if not: find 10 minus the number it is; put that many placeholder pins (cells with value 1) at the end
    ,+++++[>+++++<-]>>[<->-]<[>>>>>[>>>>]+[<<<<]<-]>>[<+>-]<<<
]>


[
    if so: get rid of '0' byte; convert '1' byte to 26 (10 plus 16)
    >>[,<]<<+++++++++<
]<<<

pointer now sitting on the cell with the second greatest pin that was inputted (ie not a placeholder)

;;;;;;;

[
    check for flag placed at the very beginning of the program; if present: break
    -[+>>-<]>
    [
        find ((pin to our right) minus 1) minus pin to our left
        move all pins left of us 4*(that value) cells and insert placeholder pins
        >>[<+<+>>-]<<<<[>+>-<<-]>[<+>-]>[<<[<<<<]>>>>[[<<<<+>>>>-]>>>>]<<<<+>>-]>[>+<-]
    ]

    find first non placeholder pin to our left
    there has to be one because we haven't hit the flag yet
    <<<[-[+>]+<<<<]>>>>-<<<<<
]>>>>>+

we have now added placeholder pins at the end and in the middle; all that's left is the beginning

subtract 17 from lowest pin and put that many placeholders to the left
++++[>----<-]>->[<+>>+<-]<[<<<[<<<<]+[>>>>]<-]>>[<+>-]

subtract 32 from an empty cell 2 to the left of the lowest pin; will be useful later
<[<<<<]>>>++++[<-------->-]>

placeholder pins have the value 1; real pins have a value somewhere between 17 and 26
normalize it by stepping through and setting every pin with value != 1 to 3 (0's ascii code is 2 higher than period so this will make it easier to print later)
[-[,+++>]+>>>[<<<->>]>]<<<<<[>-]>[>>]>>

start writing 32s across the board; hitting every second cell
that's every pin and the cell 2 to the right of each pin
this is done in such a way that it will only halt if adding 32 to a cell sets it to 0; which is why we subtracted 0 from an empty cell earlier
it will catch us and prevent an infinite loop
+[<++++[<++++++++>-]<]

now write 13 to each pin; this adds up to 46 or 48; which are exactly the ascii values we want
>>[+++++++++++++>>>>]

we happen to have made a 14; turn it into a 10 for a newline
<<<<----

we're so close now; i can taste it
we have a list of 10 pins; each one with the ascii value that needs to be written
we have 32 everywhere because we'll need spaces
we even have a newline

the only problem now is that our list looks like this:
;;;;;;;;;;;;;;;;;;;;;;;;
;;1 2 3 4 5 6 7 8 9 10;;
;;;;;;;;;;;;;;;;;;;;;;;;

and we need to print in this order:
;;;;;;;;;;;;;;;;;;;;;;;;
;;7 8 9 10 4 5 6 2 3 1;;
;;;;;;;;;;;;;;;;;;;;;;;;

it's a pretty simple fix
once we print a pin we obviously don't need to remember it any more
so we simply print the last 4 pins on the list; destroying them on the way
then we print the last 3; which have become the ones we want
then two; then one
<+++[<<+<<[<<+<<]+[>>>>]<<<<-]<<<<[-<<<<]

print pins 7 8 9 10
>[.,>>]

print pins 4 5 6
<<<<<[<<<<]<++++++++++<<.<+<<+<<+<<+<<+<[.,>>]

print pins 3 2
<<<<<[<<]>++++++++++<+<<+<<+<..<+<[.,>>]

print the final pin!! :)
<[<<]<...<<.
\$\endgroup\$
14
\$\begingroup\$

Python 2, 108 bytes

def f(x):
 for i in 4,3,2,1:print" "*(4-i)+" ".join(".O"[i*~-i/2-~z in map(int,x.split())]for z in range(i))

Call with f("3 5 7 9 10").

i is the row number, with 4 being the first row and 1 being the last. z is the nth pin on that row, with 0 meaning it's the first pin in the row and i-1 meaning it's the last pin in the row.

The main hack is i*~-i/2-~z, which converts (i, z) -> pin number. For example, (4, 0) -> 7 as pin 7 is the first pin on row 4 (the first row). The derivation goes like this:

  • We want a function taking i to the first pin on row i, i.e. 4 -> 7, 3 -> 4, 2 -> 2, 1 -> 1. This is satisfied by (i**2-i)/2 + 1, and thus (i**2-i)/2 + 1 + z gives the correct pin number for input (i, z)

  • Then simplify:

(i**2-i)/2 + 1 + z
  = (i*(i-1))/2 + 1 + z
  = i*~-i/2 + 1 + z
  = i*~-i/2-~z

Pyth, 33 bytes

V4~Z-4N+*dNjdm@".O"}+d-11Zrz7U-4N

Try it online.

The program roughly translates to:

z = input()
Z = 0

for N in range(4):
  Z += 4-N
  print(" "*N + " ".join(".O"[d+11-Z in map(int, z.split())] for d in range(4-N)))

(Thanks to isaacg for tips)

\$\endgroup\$
  • \$\begingroup\$ Your Pyth code can be golfed in two ways: V4 is equivalent to FNU4, and rz7 is equivalent to mvkcz\ . \$\endgroup\$ – isaacg Dec 22 '14 at 13:05
  • \$\begingroup\$ Ahaha thanks. I'm still not used to what there is and isn't in Pyth without having to check the docs all the time. \$\endgroup\$ – Sp3000 Dec 22 '14 at 13:08
  • \$\begingroup\$ 107 bytes as a full program. \$\endgroup\$ – FlipTack Dec 19 '18 at 21:31
9
\$\begingroup\$

Pyth, 31

V4+*dNjdm?\O}+7+dZrz7\.rN4~Z-N4

Try it here.

V4 sets up a for loop, with N as the variable over [0,1,2,3].

*dN provides the initial spaces, because d is space.

To find the pin locations, it uses +7+dZ - 7 + d + Z.

d is:

0 1 2 3
 1 2 3
  2 3
   3

while Z is 0 in the first line, -4 in the second, -7 in the third and -9 in the forth. This is becasue Z starts as 0, and ~Z-N4 decrements Z by 4, then 3, then 2.

Then, it checks if the pin location is in the input, using }+7+dZrz7. rz7 is the desired pins in list-of-int form.

Then, it creates an O if it was present, and . otherwise. This is space separated, with jd, and printed implicitly.

\$\endgroup\$
5
\$\begingroup\$

Perl 5: 51 (50 + 1 for -p)

Using r flag for s/// which is one of the recent perl 5 additions.

#!perl -p
$_="7890
 456
  23
   1
"=~s!\d!'. '^a
x/$&\b/!egr
\$\endgroup\$
5
\$\begingroup\$

CJam, 48 41 bytes

Wow, this got horribly long

"6789345 12  0"S*7/N*[l~]:(s"O"erA,s"."er

Test it here.

Explanation

First we generate the layout:

"6789345 12  0"       "Push this string.";
               S*     "Riffle with spaces.";
                 7/   "Split into substrings of length 7.";
                   N* "Join with newlines.";

This yields

6 7 8 9
 3 4 5 
  1 2  
   0

And now we replace the digit characters according to the input:

[l~]                 "Read the input and turn it into an array of integers.";
    :(s              "Decrement each number and turn the array into a string of digits.";
       "O"           "Push this string.";
          er         "Character transliteration, replaces the input digits with O.";
            A,s      "Create the string '0123456789'.";
               "."   "Push this string.";
                  er "Character transliteration, replaces all remaining digits with periods.";
\$\endgroup\$
  • \$\begingroup\$ "789A456S23SS1":~S*7/N*[l~]'OerB,'.er is a bit shorter. \$\endgroup\$ – Dennis Jul 1 '15 at 14:09
  • \$\begingroup\$ @Dennis Thanks. I'm not entirely sure if er was autocasting to array back then. \$\endgroup\$ – Martin Ender Jul 1 '15 at 14:14
  • \$\begingroup\$ Oh, right. That was implemented in 0.6.4, which is younger than this question. "789A456S23SS1":~S*7/N*[l~]"O"erB,"."er works fine in 0.6.2. \$\endgroup\$ – Dennis Jul 1 '15 at 14:16
5
\$\begingroup\$

Python 2, 97 94

This uses the translate function, which allows one to make character-for-character substitutions in a string. Like tr in perl, except much longer to type. I get a list of decimal digits by making a string from 9 to the 99th power.

lambda a:u"7890\n 456\n  23\n   1".translate({ord(n):u'.O'[n+' 'in a+' ']+' 'for n in`9**99`})
\$\endgroup\$
5
\$\begingroup\$

Javascript, 155

First golf, can probably be shorter.

function f(i){q='replace',s='7 8 9 0\n 4 5 6\n  2 3\n   1';alert(s[q](RegExp(i[q]('10','0')[q](/ /g,'|'),'g'),function(a){return a?'O':a})[q](/\d+/g,'.'))}

call with

f('1 2 3 4 5 6 7 8 9 10')
f('1 5 10')
f('')

EDIT

ES6 version, 130

f=i=>{q='replace',s='7 8 9 0\n 4 5 6\n  2 3\n   1';alert(s[q](RegExp(i[q]('10','0')[q](/ /g,'|'),'g'),a=>a?'O':a)[q](/\d+/g,'.'))}

EDIT

ES6 version, 79 fails

f=i=>alert('7890\n 456\n  23\n   1'.replace(/\d/g,a=>i.indexOf(a)<0?'. ':'O '))

ES6 version, 72 77, no alert, just returns

f=i=>'7890\n 456\n  23\n   1'.replace(/\d/g,a=>i.search(a+'\\b')<0?'. ':'O ')
\$\endgroup\$
  • 1
    \$\begingroup\$ The 79 and 72 are broken, both fail for input 10 \$\endgroup\$ – edc65 Jan 9 '15 at 17:39
  • \$\begingroup\$ @edc65 whoops, thanks, fixed. \$\endgroup\$ – red-X Jan 10 '15 at 10:18
  • \$\begingroup\$ Ooh, clever use of word boundary character, I came up with almost the exact same (except using .match). This is the most elegant of them all. \$\endgroup\$ – ninjagecko May 17 '15 at 16:09
4
\$\begingroup\$

Ruby, 91

x=(1..10).map{|i|i.to_s==$*[0]?($*.shift;?0):?.}
4.times{|i|puts (x.pop(4-i)*' ').center 8}

Simply substitutes the command line arguments with .s and 0s and prints them using a loop of 4 cycles.

Readable version

x = (1..10).map do |i|
  if i.to_s == ARGV[0]
    ARGV.shift
    "0"
  else
    "."
  end
end

4.times do |i|
  row = x.pop(4 - i)
  puts row.join(' ').center 8
end
\$\endgroup\$
4
\$\begingroup\$

GNU sed, 75

  • Saved 6 bytes thanks to @Jordan.

Score includes 1 extra for -r option:

s/^/7 8 9 10\
 4 5 6\
  2 3\
   1 /
:
s/([0-9]+)(.*)\1/O\2/
t
s/[0-9]+/./g

Input via STDIN:

$ echo 3 5 7 9 10 | sed -rf ./bowling.sed
O . O O
 . O .
  . O
   .    
$ 

Try it online.

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

CJam, 40 39 bytes

4,Sf*'-A*[q~]{('ot}/3,{)/(\s}%Sf*W%]zN*

I know there is a shorter way, don't have time to figure it out right now.

How it works:

4,Sf*'-A*[q~]{('ot}/3,{)/(\s}%Sf*W%]zN*
4,                                          "Get the array [0,1,2,3]";
  Sf*                                       "Covert each number to that many spaces to";
                                            "get ["", " ", "  ", "   "] array";
     '-A*                                   "String '----------'";
         [q~]                               "Input numbers in an array";
             {    }/                        "For each input number";
              ('ot                          "Put 'o' at the corresponding index";
                    3,                      "Array [0,1,2]";
                      {     }%              "For each of the above number";
                       )                    "Increment the number";
                        /                   "Split the string into pieces of that length";
                         (\s                "Take the first string and join the rest back";
                              Sf*           "Riffle each string in array with space";
                                 W%         "Reverse the array of strings";
                                   ]z       "Zip together the space array and this one";
                                     N*     "Join by new line";

Try it online here

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

APL (35)

⊖4 7⍴'.O'[1+⎕∊⍨⍳10]\⍨17110357⊤⍨28/2

Test:

      ⊖4 7⍴'.O'[1+⎕∊⍨⍳10]\⍨17110357⊤⍨28/2
⎕:
      1 3 5 6 9 10
. . O O
 . O O 
  . O  
   O   

Explanation:

  • 17110357⊤⍨28/2: the 28-bit representation of 17110357:

          4 7⍴17110357⊤⍨28/2
    0 0 0 1 0 0 0
    0 0 1 0 1 0 0
    0 1 0 1 0 1 0
    1 0 1 0 1 0 1
    
  • \⍨: For every 0, give a space, and for every 1, take an item from the string on the left.

  • ⎕∊⍨⍳10: Read a line from the keyboard and evaluate it (), then check for every number from 1 to 10 (⍳10) whether or not it is contained in the input (∊⍨).
  • '.O'[1+...]: Add 1 to every value (giving 1s and 2s instead of 0s and 1s), and then replace every 1 by . and every 2 by O.
  • 4 7⍴: turn the generated string into a 4-by-7 matrix
  • : flip it horizontally
\$\endgroup\$
3
\$\begingroup\$

Powershell: 109

Input is in $i

(7..10),(4..6),(2,3),1|%{$c=0}{$_|%{$o=(" "*$c++)}{$o="$o $(if($i.split() -contains $_){'O'}else{'.'})"};$o}

That was fun. Learned a bunch of stuff about how the pipeline works, too.

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

Haskell: 163 160 bytes

This accepts a line of space separated numbers from stdin.

m=map
y?x|x`elem`y="O "|0<1=". "
f y=putStr.unlines.zipWith(++)(m(`replicate`' ')[0..])$m(concat.m(y?))[[7..10],[4..6],[2,3],[1]]
main=getLine>>=f.m read.words

Ungolfed:

layout :: [[Int]]
layout = [[7,8,9,10]
         ,[ 4,5,6  ]
         ,[  2,3   ]
         ,[   1    ]
         ]

indentBy :: Int -> String
indentBy n = replicate n ' '

indentLines :: [String] -> [String]
indentLines
  = zipWith (++)
            (map indentBy [0..])

bowling :: [Int] -> String
bowling pins
  = unlines
  . indentLines
  $ map (concatMap showPlace)
        layout
  where
    showPlace :: Int -> String
    showPlace index
      | index `elem` pins = "O "
      | otherwise         = ". "

parseInput :: String -> [Int]
parseInput = map read . words

main :: IO ()
main = do
  pins <- fmap parseInput getLine
  putStr (bowling pins)

And a bonus:

C: 250 bytes

This version expects its command line arguments to be the list of numbers.

#define w int
main(w
z,char**a){w
b[10]={1,3,2,6,5,4,10,9,8,7};w
q=9;for(w
k=4;k>0;--k){w
i;for(i=0;i<4-k;++i)printf(" ");for(i=0;i<k;++i,--q){w
g=0;w
c;for(w
p=1;p<z;++p){sscanf(a[p],"%d",&c);g|=b[q]==c;}c=g?'O':'.';printf("%c ",c);}printf("\n");}}
\$\endgroup\$
2
\$\begingroup\$

Perl, 73

$_="7 8 9 10\n 4 5 6\n  2 3\n   1";for$v(<>=~/\d+/g){s/$v/O/g};s/\d+/./g;print

And a goofy bonus approach that didn't pan out, 90 characters:

srand(1488068);$i=<>;print+(($i=~/$_\b/?O:".")." "x rand 5)=~s/  /\n /r for 7..10,4..6,2,3,1
\$\endgroup\$
2
\$\begingroup\$

Mathematica, 109 bytes

Function:

f=(i=0;Reverse@Table[Row@Table[If[MemberQ[ToExpression/@StringSplit@#,++i],O,"."],{n}],{n,4}]~Column~Center&)

Called by:

f@"3 5 7 9 10"

If anonymous functions are allowed, this can be shortened to 105 bytes:

i=0;Reverse@Table[Row@Table[If[MemberQ[ToExpression/@StringSplit@#,++i],O,"."],{n}],{n,4}]~Column~Center&

If the input didn't have to be a space-delimited string, but could be an array of numbers in the form {3,5,7,9,10}, this can be further shortened to 79 bytes:

i=0;Reverse@Table[Row@Table[If[MemberQ[#,++i],O,"."],{n}],{n,4}]~Column~Center&
\$\endgroup\$
2
\$\begingroup\$

Pure bash (no coreutils), 85

Simple pattern replacement:

f="7 8 9 0
 4 5 6
  2 3
   1"
a=${@/10/0}
f="${f//[${a// /}]/O}"
echo "${f//[0-9]/.}"

List is input via the command-line args.

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

Rebol - 117

s: array/initial 10"."b:""foreach n to-block input[s/:n:"0"]for n 4 1 -1[prin b print take/last/part s n append b" "]

Ungolfed:

s: array/initial 10 "."
b: ""
foreach n to-block input [s/:n: "0"]
for n 4 1 -1 [prin b print take/last/part s n append b " "]
\$\endgroup\$
2
\$\begingroup\$

Brainfuck, 179 bytes

++++++++++[-[<<+>>-]+<<]>,[<[-]-[>-<-----]>++[-[>>+<<-]>>]>+++[<<],>,]<[,>>---[>
>]<<+++[<<]]>->>->>>>->>>>>>->[[>>]>,<<+[++[>+++++++++++<-]<+]>>[++.>-.>]>++++++
++++[>>]<<[.[<]<]<]

Formatted:

++++++++++
[
  -[<<+>>-]
  +<<
]
>,
[
  <[-]
  -[>-<-----]
  >++
  [
    -[>>+<<-]
    >>
  ]
  >+++[<<]
  ,>,
]
<
[
  ,>>---[>>]
  <<+++[<<]
]
>->>->>>>->>>>>>->
[
  [>>]
  >,<
  <+
  [
    ++[>+++++++++++<-]
    <+
  ]
  >>[++.>-.>]
  >++++++++++[>>]
  <<[.[<]<]
  <
]

Expects input without a trailing newline.

Try it online.

The tape is initialised with ten nodes, each of which contains a one followed by a zero. The one is the initial value of the pin, and the zero facilitates navigation and acts as a placeholder for the space character. For each number in the input, that pin is incremented by 3; note that ord('O') - ord('.') = 33, and during the printing phase, the pin's value will be multiplied by 11. (This multiplication is also used to generate the space character.) The order of the pins from left to right on the tape is simply 1 up to 10. If the input ends with a 10, a correction is made, since the 10 is initially treated as a 1.

After the input has been processed, a negative one is placed after each row. Then the rows are printed in a loop, with the number of leading spaces determined by the number of rows previously processed.

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

Clojure, 216 chars (ugh)

I'm sure this can be golfed further.

(let[s(map #(dec(read-string %))(.split(slurp *in*)" +"))](println(apply str(replace(apply hash-map(interleave(map #(char(+ 48 %))(range 10))(map #(if(some #{%}s)"O"".")(range 10))))"6 7 8 9\n 3 4 5\n  1 2\n   0"))))

Use like this:

echo -n "2 4 9 8 10 5" | clojure a-file-which-contains-this-program.clj
\$\endgroup\$
1
\$\begingroup\$

AWK: 96 bytes

{gsub(/ /,"");a="6 7 8 9\n 3 4 5\n  1 2\n   0";gsub("["$0"]","O",a);gsub(/[0-9]/,".",a);print a}

Note:

  • The spaces separators on the input value are optional (but it works also with them as required)
  • The numbers don't have to be in order
  • The input is read on STDIN
\$\endgroup\$
1
\$\begingroup\$

C# - 192 bytes

Because C#!

I started out trying to build the output with math, but the simple replace-tokens-in-string method seems best for higher-level languages. Linq dependency is longish but still shorter than keeping a counter and doing range checks.

using System.Linq;class A{static void Main(string[]a){var s=@"7 8 9 0
 4 5 6
  2 3
   1";for(int c=11;c-->1;)s=s.Replace((char)(48+c%10),a.Contains(""+c)?'O':'.');System.Console.Write(s);}}

EDIT: unix line returns (-3 bytes)

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

Scala, 150148

def t(n:Any)=("G H I J D E F   B C     A"/:('A'to'J'))((j,i)=>j.replace(i,(if((n+" ").indexOf((i-64)+" ")>=0)'0'else'.'))).grouped(7).maxBy(println)

Accepts space-delimited set of strings

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

JavaScript ES6, 78 bytes

F=i=>'7890\n 456\n  23\n   1'.replace(/\d/g,e=>'0.'[+!~i.search(e+'\\b')]+' ')

Use the following snippet to test. It uses prompts and alerts and regular function notation for ease of testing.

i=prompt()
alert('7890\n 456\n  23\n   1'.replace(/\d/g,function(e){return'0.'[+!~i.search(e+'\\b')]+' '}))

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

VB/Basic-229

My goal was to beat java^^

Dim f
Sub m()
f = " 1 2 3 4 5 6 7 8 9 10"
a = l(7, 10) + l(4, 6) + l(2, 3) + l(1, 1)
MsgBox a
End Sub
Function l(b, e)
r = Space(3 - (e - b))
For i = b To e
r = r + IIf(InStr(f, Str(i)), "0 ", ". ")
Next
l = r + vbCr
End Function

edit vbCr instead of chr(13)

r = r + Space(3 - (e - b))

shorthand if

use of function instead of sub

sub MAIN() - > sub m()

\$\endgroup\$
  • \$\begingroup\$ Can you please include the code length in bytes in your answer? \$\endgroup\$ – ProgramFOX Jan 2 '15 at 8:55
  • \$\begingroup\$ I will, but i'm still fiddling a bit with the code \$\endgroup\$ – dwana Jan 2 '15 at 9:00
1
\$\begingroup\$

Java - 223 chars

public class Pins {public static void main(String[] args) {String s = "7 8 9 0\n 4 5 6\n  2 3\n   1";for (String arg : args) {s = s.replace(arg.replace("10", "0"), "o");}s = s.replaceAll("\\d", ".");System.out.println(s);}}

I used to like this way of doing it, then I realized I needed a small hack, still kind of like my solution.

public class Pins {
public static void main(String[] args) {
    String s = "7 8 9 0\n 4 5 6\n  2 3\n   1";
    for (String arg : args) {
        s = s.replace(arg.replace("10", "0"), "o");
    }
    s = s.replaceAll("\\d", ".");
    System.out.println(s);
}
}
\$\endgroup\$
1
\$\begingroup\$

K, 57 bytes

Not very competitive yet, but it's a start:

`0:((!4)#\:" "),',/'|0 1 3 6_(". ";"O ")@|/(1+!10)=/:(),.

Usage example:

  `0:((!4)#\:" "),',/'|0 1 3 6_(". ";"O ")@|/(1+!10)=/:(),."3 5 7 9 10"
O . O O 
 . O . 
  . O 
   . 
  `0:((!4)#\:" "),',/'|0 1 3 6_(". ";"O ")@|/(1+!10)=/:(),."1"
. . . . 
 . . . 
  . . 
   O 

I begin by evaluating the input string with .- fortunately, space separated numbers are a valid list literal in K. By prepending an empty list to the result of eval I can ensure it's a list even in the case of a single pin. Then I create a boolean vector representing the positions of pins:

  (1+!10)=/:3 5 7 9 10
(0 0 1 0 0 0 0 0 0 0
 0 0 0 0 1 0 0 0 0 0
 0 0 0 0 0 0 1 0 0 0
 0 0 0 0 0 0 0 0 1 0
 0 0 0 0 0 0 0 0 0 1)
  |/(1+!10)=/:3 5 7 9 10
0 0 1 0 1 0 1 0 1 1

Then I index into a list of strings to get space-padded characters for each pin position.

  (". ";"O ")@0 0 1 0 1 0 1 0 1 1
(". "
 ". "
 "O "
 ". "
 "O "
 ". "
 "O "
 ". "
 "O "
 "O ")

I slice that sequence into rows (_), reverse them (|) and join together each fragment (,/'):

  ,/'|0 1 3 6_(". ";"O ")@0 0 1 0 1 0 1 0 1 1
("O . O O "
 ". O . "
 ". O "
 ". ")

Now it's starting to look like the pattern we want. All that's left is to tack on some leading spaces to each row (((!4)#\:" "),') and print the rows to stdout (0:).

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

Pascal (FPC), 165 bytes

var f:string='. . . .'#10' . . .'#10'  . .'#10'   .';i:byte;z:array[1..10]of byte=(25,18,20,10,12,14,1,3,5,7);begin repeat read(i);f[z[i]]:='O'until eof;write(f)end.

Try it online!

Takes numbers from standard input, prints the formation to standard output.

Pascal (FPC), 175 bytes

function f(q:array of byte):string;var i:byte;z:array[1..10]of byte=(25,18,20,10,12,14,1,3,5,7);begin f:='. . . .'#10' . . .'#10'  . .'#10'   .';for i in q do f[z[i]]:='O'end;

Try it online!

A function which does the same thing, taking an array of pin positions and returning a formatted string.

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

Powershell, 84 bytes

$p='6789
 345
  12
   0'
-split$args|%{$p=$p-replace($_-1),'O '}
$p-replace'\d','. '

Test script:

$f = {

$p='6789
 345
  12
   0'
-split$args|%{$p=$p-replace($_-1),'O '}
$p-replace'\d','. '

}

# one space at the end of each line with pins
@(
,("1 2 3 4 5 6 7 8 9 10",
@"
O O O O 
 O O O 
  O O 
   O 
"@)

,("7 10",
@"
O . . O 
 . . . 
  . . 
   . 
"@)

,("3 5 7 9 10",
@"
O . O O 
 . O . 
  . O 
   . 
"@)

,("1",
@"
. . . . 
 . . . 
  . . 
   O 
"@)
) | % {
    $s, $expected = $_
    $result = &$f $s
    $result-eq$expected
    $result
}

Output:

True
O O O O
 O O O
  O O
   O
True
O . . O
 . . .
  . .
   .
True
O . O O
 . O .
  . O
   .
True
. . . .
 . . .
  . .
   O
\$\endgroup\$
0
\$\begingroup\$

Java - 371 316 294 chars

public class Bowling{public static void main(String[] a){boolean[] o=new boolean[10];int i;for(String s:a){i=Integer.parseInt(s)-1;o[i]=true;}for(int j=9;j>=0;j--){p((o[j]?"0 ":". "));p(j==6?"\n ":"");p(j==3?"\n  ":"");p(j==1?"\n   ":"");}p("\n");}static void p(String l){System.out.print(l);}}

First time doing this, I'm pretty sure it's shitty, but I'm a novice. It also works when the numbers aren't ordered. The numbering is wrong but I don't have time to find out how to fix it...

public class Bowling {
    public static void main(String[] args) {
        boolean[] ordened = new boolean[10];
        int i;
        for (String s : args) {
            i = Integer.parseInt(s) - 1;
            ordened[i] = true;
        }
        for (int j = 9; j >= 0; j--) {
            p((ordened[j] ? "0 " : ". "));
            p(j == 6 ? "\n " : "");
            p(j == 3 ? "\n  " : "");
            p(j == 1 ? "\n   " : "");
        }
        p("\n");
    }
    static void p(String l){
        System.out.print(l);
    }
}

input is given by java B 1 2 3 5 10 for example. Output will then be:

0 . . . 
 . 0 . 
  0 0 
   0 
\$\endgroup\$
  • 1
    \$\begingroup\$ The numbering is wrong. \$\endgroup\$ – Optimizer Dec 29 '14 at 16:27
  • \$\begingroup\$ I'll try to fix it \$\endgroup\$ – Haroen Viaene Dec 29 '14 at 16:28
0
\$\begingroup\$

Japt -Rx, 29 19 18 17 bytes

5ÇÆ".O"gUø°TøÃÔû

Try it


Explanation

                      :Implicit input of integer array U
5Ç                    :Map each Z in the range [0,5)
  Æ                   :  Map the range [0,Z)
          °T          :    Increment T (initially 0)
        Uø            :    Does U contain T? (false=0, true=1)
   ".O"g              :    Get the character in the string ".O" at that index
            Ã         :  End mapping
             ¸        :  Join with spaces
              Ã       :End mapping
               Ô      :Reverse
                û     :Centre pad each element with spaces to the length of the longest
                      :Implicitly join with newlines, trim (not strictly necessary) and output
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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