23
\$\begingroup\$

I'm tired, but I can't seem to fall asleep. Help me count sheep.

Given an input N (positive integer), make N sheep jump over an ascii fence, like the sample below. Only one frame should be displayed at once:

o |-|
──|-|──  0

 o|-|
──|-|──  0

   o
  |-|
──|-|──  0

  |-|o
──|-|──  0

  |-| o
──|-|──  0

o |-|
──|-|──  1

 o|-|
──|-|──  1

   o
  |-|
──|-|──  1

Count should be kept at the lower right side of the 'ground'. Trailing and leading whitespace and newlines are allowed. If your language of choice has difficulty clearing the screen for each frame you can add sufficient newlines to clear the screen - please state how many lines you add for this in your answer. The program should terminate when the N'th sheep is on the fifth floortile.

I need to get up early tomorrow, so shortest code in bytes wins. Please submit a function or complete program. Standard loopholes apply.

\$\endgroup\$
  • 6
    \$\begingroup\$ 1. Please, it pains me when people use justifications for short code ("I need to get up early tomorrow") 2. How much whitespace do we put between frames? It looks like 1 newline to be, but you may want to state that clearly. \$\endgroup\$ – Rɪᴋᴇʀ Oct 1 '16 at 14:42
  • 12
    \$\begingroup\$ 1) take aspirin 2) There may be only 1 frame on screen. These frames here are to demonstrate each state individually and should NOT be visible on 1 screen simultaneously. \$\endgroup\$ – steenbergh Oct 1 '16 at 14:44
  • 3
    \$\begingroup\$ Many languages do not have the option to clear display, in such cases what output should they provide? \$\endgroup\$ – Jonathan Allan Oct 1 '16 at 14:50
  • 6
    \$\begingroup\$ "add sufficient newlines to clear the screen". Isn't that dependent on the size of the output window as well as screen resolution? \$\endgroup\$ – Emigna Oct 1 '16 at 15:03
  • 3
    \$\begingroup\$ According to your example, for N=3 the last frame will contain a sheep at the right end and the counter will still say 2. Is that correct? \$\endgroup\$ – Luis Mendo Oct 1 '16 at 15:45

14 Answers 14

15
\$\begingroup\$

MATL, 60 56 53 bytes

:"@qXJx[HKCbO]"7Z"'  |-|  'v'o'@('--|-|--  '  JVhXxXD

The animation with the above code runs very fast. The following version includes a pause to make the animation slower and thus easier to see (not required by the challenge), at the cost of 4 more bytes:

:"@qXJx[HKCbO]"7Z"'  |-|  'v'o'@('--|-|--  '  JVhXxXD.2Y.

Try it at MATL Online! The interpreter is a beta; refresh the page if it doesn't work.

Or see a recording from the offline compiler:

enter image description here

Explanation

:"              % Input N implicitly. Repeat N times
  @q            %   Push iteration index minus 1, that is, from 0 to N-1. This
                %   are the numbers of sheep
  XJx           %   Copy into clipboard J and delete
  [HKCbO]       %   Push array [2 4 7 -2 0]
  "             %   For each value in that array. This loops generates the 5
                %   frames for each number of sheep
    7Z"         %     Push string of 7 spaces
    '  |-|  '   %     Push this string
    v           %     Concatenate vertically. This gives a 2x7 char array
                %     with the upper part of the frame, except the 'o',
                %     which will be now placed in a varying position 
    'o'         %     Push string 'o'
    @           %     Push loop variable, that is, 2, 4, 7, -2 or 0
    (           %     Write 'o' into that position of the 2x7 char array.
                %     The position is interpreated linearly, that is, a single
                %     number is used as index into the 2D array in column-major
                %     order (down, then across). So index 2 is lower-left corner,
                %     index 4 is to the right of that etc. Indexing is
                %     semi-modular (modular for non-positive values). So 0 is
                %     the lower-right corner, and -2 is to the left of that
    '--|-|--  ' %     Push this string
    JV          %     Push current number of sheep converted to string
    h           %     Concatenate horizontally
    Xx          %     Clear screen
    XD          %     Display all stack contents
    .2Y.        %     Pause for 0.2 seconds (optional)
                %   End implicitly
                % End implicitly
\$\endgroup\$
6
\$\begingroup\$

JavaScript (ES6), 120 124 bytes

f=(n,m=`   2
43|-|10
──|-|── `,s=0)=>n?alert(m.replace(s%5,'o').replace(/\d/g,' ')+' '+(n-1),(++s%5?f(n,m,s):f(n-1,m,0))):''

The last frame computed is showing first. Thanks to this the jump number is n-1
In alert, charaters have different width so it looks like it's broken.

f=(n,m=`   2
43|-|10
──|-|── `,s=0)=>n?alert(m.replace(s%5,'o').replace(/\d/g,' ')+' '+(n-1),(++s%5?f(n,m,s):f(n-1,m,0))):''
;

f(2);//You'll get 10 alert popup


Previous answer:

120 bytes, the jump number is wrong because it starts at 1 instead of 0

f=(n,m=`   2
43|-|10
──|-|── `,s=0)=>n?alert(m.replace(s%5,'o').replace(/\d/g,' ')+' '+n,(++s%5?f(n,m,s):f(n-1,m,0))):''
\$\endgroup\$
  • \$\begingroup\$ @LuisMendo I updated the counter to start at 0. For the bars it's thanks to the font used by alert. I have the same result than chrome with edge, and it's worse with firefox. \$\endgroup\$ – Hedi Oct 1 '16 at 16:22
6
\$\begingroup\$

JavaScript (ES6), 144 142 bytes

Clears the output and waits 300ms between each frame:

n=>(F=j=>((c=console).clear(),c.log(`   2
01|-|34
──|-|── `.replace(/\d/g,i=>(j-i)%5?' ':'o')+(j/5|0)),++j<n*5&&setTimeout(`F(${j})`,300)))(0)

You can test it here (make sure to open the console).

\$\endgroup\$
  • \$\begingroup\$ This doesn't seem to increment the counter (from 4 to 5) after the last sheep has jumped the fence... \$\endgroup\$ – ʰᵈˑ Oct 3 '16 at 15:18
  • \$\begingroup\$ @ʰᵈˑ - I think this is the expected behavior. (See Luis Mendo's question in the challenge comments.) \$\endgroup\$ – Arnauld Oct 3 '16 at 15:25
  • \$\begingroup\$ Ah yes, I didn't read that - link to comment for anyone else \$\endgroup\$ – ʰᵈˑ Oct 3 '16 at 15:28
4
\$\begingroup\$

Ruby, 83 bytes

->n{(n*5).times{|i|$><<"   c
  |-|  
ab|-|de  #{i/5}
".tr('abcde',' '*(i%5)+'o ')}}

Prints to stdout. Output separated by newlines. Reducing screen height to 3 makes only one image visible at a time.

\$\endgroup\$
4
\$\begingroup\$

C#, 234 Bytes

using C=System.Console;class P{static void Main(string[]a){for(int n=0;n-1+""!=a[0];++n){foreach(int p in new[]{5,6,3,10,11}){C.Clear();C.Write("    \n  |-|  \n──|-|── ".Remove(p,1).Insert(p,"o")+n);for(var w=3e7;w>0;--w);}}}}
\$\endgroup\$
  • \$\begingroup\$ At a first glance, there's some whitespaces laying around at string[] args and at for (int. Int32.Parse could be int.Parse. \$\endgroup\$ – Yytsi Oct 1 '16 at 17:11
  • 1
    \$\begingroup\$ You can change the name of the class from Program to just P or something \$\endgroup\$ – Matias Cicero Oct 2 '16 at 3:17
  • 1
    \$\begingroup\$ string could be var. The integer in the for loop could be initialized at the same time you parse args[0] to an integer. \$\endgroup\$ – Yytsi Oct 2 '16 at 11:37
  • \$\begingroup\$ I see you edit the byte count each time it is lowered. However, I recommend keeping around old byte counts (crossed with a line), to keep track of the progress :) \$\endgroup\$ – Yytsi Oct 2 '16 at 11:41
  • \$\begingroup\$ You only need to have a function so compile to an Action<string[]> and you can remove the brackets around the outer for loop so I believe I get 200 bytes: using C=System.Console;a=>{for(int n=0;n-1+""!=a[0];++n)foreach(int p in new[]{5,6,3,10,11}){C.Clear();C.Write(" \n |-| \n──|-|── ".Remove(p,1).Insert(p,"o")+n);for(var w=3e7;w>0;--w);}}; \$\endgroup\$ – TheLethalCoder Oct 5 '16 at 11:55
3
\$\begingroup\$

PHP+JavaScript, 168 bytes

<?extract($_GET);$s="     ";$s[$f=++$f%5]=o;echo strtr("<pre>   C
AB|─|DE
──|─|── $c",EABCD,$s),($c+=!$f)<$n?"<script>location.href='s.php?n=$n&c=$c&f=$f'</script>":"";

Save to file s.php, call in browser with s.php?n=<n>.

Calls itself with new parameters for every frame, no delay.


I could save 5 more with index.php; but I don´t want to go that far.

\$\endgroup\$
  • \$\begingroup\$ I've tried running this on PHP 5 and 7, but all Chrome gives me is C AB|─|DE ──|─|── $c",EABCD,$s),($c+=!$f)<$n?". \$\endgroup\$ – steenbergh Oct 1 '16 at 18:06
  • \$\begingroup\$ @steenbergh You have short_open_tag disabled. Enable it (default) or add php+space after <?. \$\endgroup\$ – Titus Oct 2 '16 at 6:30
  • \$\begingroup\$ Yup, that's it. Got it running now. \$\endgroup\$ – steenbergh Oct 2 '16 at 6:37
3
\$\begingroup\$

Tcl, 168 bytes

Version using 10-row-high screen. (Replace the 7 below with your screen height in columns minus four.)

set s {0 1 2 3 4 }
for {set n 0} {$n<$argv} {incr n} {foreach x $s {
puts [string repe \n 6][string map [split $s {}] [string map "$x o" {   2
01|-|34
--|-|--  }]]$n}}

That runs really fast, so you can add a pause on line two:

Tcl, 177 bytes

set s {0 1 2 3 4 }
for {set n 0} {$n<$argv} {incr n} {foreach x $s {after 250
puts [string repe \n 6][string map [split $s {}] [string map "$x o" {   2
01|-|34
--|-|--  }]]$n}}

It works by reusing the string at the top for two different things:

  • as a list for the inner loop (to display each version of the sheep+fence)
  • as a mapping of digit→space to remove digits from the sheep+fence image template

The template itself is the string image to display. First we map (string replace) the sheep's current position digit (inner loop) to an 'o'. Then we map the remaining digits to spaces. Then we print the resulting string.

(The string itself starts after the last { on the third line and ends with the leftmost } on the last line.)

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

QBasic, 110 bytes

INPUT n
FOR i=0TO 5*n-1
CLS
?
?"  |-|"
?"--|-|-- ";i\5
x=i MOD 5
LOCATE(x=2)+2,1+x-(x>1)+x\3
?"o"
SLEEP 1
NEXT

Loops over 5*n ticks. At each tick, clears the screen, prints the stile and sheep count, and then uses LOCATE to print the o at the appropriate spot. With x being the position code between 0 and 4:

  • Row: (x=2)+2
    • If x=2 is true, -1+2 = 1
    • If x=2 is false, 0+2 = 2
  • Column: 1+x-(x>1)+x\3
    • If x is 0 or 1, x>1 is false and x\3 is 0: 1+x-0+0 = 1 or 2
    • If x is 2, x>1 is true and x\3 is 0: 1+x-(-1)+0 = 4
    • If x is 3 or 4, x>1 is true and x\3 is 1: 1+x-(-1)+1 = 6 or 7

Finally, SLEEP for 1 second and loop. If you don't mind hitting enter at every frame, I can shave two bytes by removing the argument to SLEEP.

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

PHP, 132 131 bytes

Edits after comments (thanks!):

<?php for(;$i<$argv[1]*5;sleep(1),system(clear),$c="    
  |-|  
──|-|──  ".floor($i/5),$c[[5,6,3,10,11][$i++%5]]=o)echo$c;

Which is ungolfed:

<?php

ini_set('error_reporting', '0');        # golfing precondition

for(; $i<$argv[1]*5;                    # repeat N times
  sleep(1),                             # sleep after iteration
  system(clear),                        # clear screen (linux only)
  $c = "    
  |-|  
──|-|──  " . floor($i / 5),             # define template
  $c[[5, 6, 3, 10, 11][$i++ % 5]] = o)  # replace with sheep (and finish "for" statement)
  echo $c;                              # output result

Original post

<?php $i=0;for(;;){system("clear");$c="  \n  |-|  \n──|-|──  ";$c[[3,4,1,8,9][$i%5]]='o';echo"  $c".floor($i++/5);sleep(1);}

Tested on ubuntu (don't know, if system("clear") works on windows)

Ungolfed:

<?php
$i = 0;
for(;;) {
  system("clear");
  $content = "  \n  |-|  \n──|-|──  ";
  $content[[3,4,1,8,9][$i%5]] = 'o';
  echo "  $content " . floor($i++/5);
  sleep(1);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Idk either about Windows, but I´m sure that clear needs no quotes. \$\endgroup\$ – Titus Oct 2 '16 at 13:07
  • 1
    \$\begingroup\$ Thinking about Windows ... it was cls in DOS. \$\endgroup\$ – Titus Oct 2 '16 at 13:58
  • 1
    \$\begingroup\$ Remove the $i=0;, warnings are typically not displayed in code golf (-5 bytes). For the same reason, you don't need quotes around clear and o (-4 bytes). Replace the \ns by real newlines (-2 bytes). Since you only have expressions, not any statements, you can put everything but the last one in your for loop, allowing you to remove the brackets (for(;;system(clear),$c=…)sleep(1);) (-2 bytes). And finally, you forget to add the condition $i<$argv[0] (+ 11 bytes). \$\endgroup\$ – Blackhole Oct 2 '16 at 14:41
  • \$\begingroup\$ Thank you! I did not get an echo into the loop. But the reposted solution is doing it. \$\endgroup\$ – user470370 Oct 3 '16 at 5:57
3
\$\begingroup\$

node.js + sleep, 169 bytes

c='   2\n01|-|34\n──|-|──  '
for(i=0;i<process.argv[2]*5;require('sleep').sleep(1))console.log('\033[2J'+c.replace(i%5,'o').replace(/\d/g,' ')+Math.floor(i++/5))

Original solution

node.js, 146 142 185 bytes

Tested with ubuntu terminal only (and now with n sheeps):

i=0
c='   2\n01|-|34\n──|-|──  '
setInterval(function(){console.log('\033[2J'+c.replace(i%5,'o').replace(/\d/g,' ')+Math.floor(i++/5))
if(process.argv[2]*5==i)process.exit()},9)

Well, that's a frame every 9 ms. A more sleep-soothing version (frame every 1s):

i=0;setInterval(function(){console.log('\033[2J'+'   2\n01|-|34\n──|-|──  '.replace(i%5,'o').replace(/\d/g,' ')+Math.floor(i++/5))},1000)

And ungolfed:

var i = 0;
setInterval(function(){
  console.log('\033[2J' + '   2\n01|-|34\n──|-|──  '.replace(i%5, 'o').replace(/\d/g, ' ') + Math.floor(i++/5));
}, 1000)
\$\endgroup\$
  • \$\begingroup\$ In my first solution, I forgot the parameter for N sheeps \$\endgroup\$ – user470370 Oct 3 '16 at 6:52
2
\$\begingroup\$

05AB1E, 66 60 59 bytes

FNU5Fð4×N<i¨'oJ},N<iðë'o}ðNÉis}"|-|  "JN1›iR},…──|Â'-sððXJ,

Uses CP-1252 encoding.

Explanantion

Iteration refers to the inner iteration (0 -> 4) of the sheeps journey.

Main loops

F      # For N in range [0 .. input)
 NU    # Save N in variable X
 5F    # For N in range [0 .. 5)

Generate top row

ð4×         # push 4 spaces
N<i    }    # if we're on the 2nd iteration
   ¨'oJ     # replace the last space with an "o"
,           # print row

Generate middle row

N<iðë'o}     # push a space if we're on the 2nd iteration, else push "o"
ð            # push a space
NÉis}        # if we're on an odd numbered iteration, swap the stacks top 2 chars
"|-|  "      # push this string
J            # join the stack to one string
N1›iR}       # if we're on the any of the last 3 iterations, reverse the string
,            # print row

Generate bottom row

…──|  # push the string "──|"
     # push a reversed copy
'-s   # push "-" between the 2 strings on the stack
ðð    # push 2 spaces
X     # push the N we saved in the main loop (current sheep number)
J,    # join and print row
\$\endgroup\$
1
\$\begingroup\$

Jelly, 55 54 53 bytes

ị30214D¤“o    ”ṙ“   “
““|-|““
__|-|__  ”ż
×5Ḷµ:5ż@Ç€Y

TryItOnline

Prints frames separated by line feeds.

How?

ị30214D¤“o    ”ṙ“   “
““|-|““
__|-|__  ”ż           - Link 1, build a frame without counts: frameNumber
       ¤              - nilad and link(s) as a nilad:
 30214                -     literal 30214 (a nilad)
      D               -     to decimal: [3,0,2,1,4]
ị                     - index into (1-based and modular, so frames go 4,3,0,2,1,4,...)
        “o    ”       - string "o    "
               ṙ      - rotated to the left by that number
                “   “ - the rest, except the last character, is:
““|-|““               -     an array of strings ["   ","\n","","|-|","","\n__|-|__  "]
__|-|__  ”            -     i.e. split where a sheep might go

          ż           - zip the sheep (the rotated "o    ") into that

×5Ḷµ:5ż@Ç€Y - Main link: nSheep
×5          - multiply by 5 -> nFrames
  Ḷ         - lowered range: [0,1,2,...nFrames-1]
   µ        - monadic chain separation
    :5      - integer division by 5 (vectorises): [5 zeros, 5 ones, ..., 5 (nSheep-1)s]
      ż@    - zip with reversed arguments
        ǀ  - call last link (1) as a monad for each (zip sheep numbers with frames)
          Y - join with line feeds (TODO: replace with future animate frames atom :p)
\$\endgroup\$
1
\$\begingroup\$

Python 2, 171 159 144 bytes, 163 151 136 characters

Solution using a recursive function. Call as f(int)

EDIT

-12 after rereading the comments and seeing that the count does not have to increment when the sheep reaches the end of the field

-15 by iterating through the index list directly and losing a variable

def f(a,x=0):
 if a>0:
  for c in 5,6,3,10,11:
   b=list('    \n  |-|  \n──|-|──  ');b[c]='o';print"\n"*50+"".join(b)+(`x`)
  f(a-1,x+1)

Notes

Assumes UTF-8 encoding

Using - instead of ─ (as in @Luis MATL answer) would bring the byte count down by 8 to match the character count and would lose the UTF-8 dependency

50 newlines added - output is at the bottom on the console (cheaper than importing and using os.system("clear") and works on Windows and Linux)

Version with 1 second time delay between outputs (170 bytes, 162 characters)

import time
def f(a,x=0):
 if a>0:
  for c in 5,6,3,10,11:
   b=list('    \n  |-|  \n──|-|──  ');b[c]='o';print"\n"*50+"".join(b)+(`x`);time.sleep(1)
  f(a-1,x+1)
\$\endgroup\$
1
\$\begingroup\$

Bash + standard Linux utilities (339 bytes)

e(){ echo "$@";}
n(){ e -n "$@";}
r(){ [ $? -eq 0 ]&&s=o||s=" ";[ $1 ]&&n " $s "||n "$s";}
f(){ k=$(($1%5));n "  ";[ $k -eq 2 ];r .;e "  ";for i in 0 1;do [ $k -eq $i ];r;done;n "|-|";for i in 3 4;do [ $k -eq $i ];r;done;e;n "──|-|──";}
for l in `seq 1 $1`;do for z in `seq 0 4`;do clear;f $z;e "  $((l-1))";sleep 1;done;done
\$\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.