31
\$\begingroup\$

My parents-in-law have a fishpond in their yard, filled with koi. It didn't really cross my mind until I noticed the following extract from my code.

',') & '_'

... I had fish-faces looking back at me from my screen...

Which has given me a great idea...

My quest for you, my dear golfers is to create a one-line ASCII aquarium, with the following rules:

  • The size of the aquarium from side of the tank to the other side of the tank should be no smaller than 60 characters and no bigger than 80 characters. Sides of the tank need to be indicated using the pipe/bar (|) character.
  • Fish must be able to "swim" left to right between the sides of the tank. As they will be turning, a front view is required for the transition from one direction to the other.
  • The fish must look like the following:

    • }}< }} ',') Fish swimming right
    • (',' {{ >{{ Fish swimming left
    • }}('_'){{ Fish facing the front
  • When a fish turns to change direction (30% chance), it must start from one direction, face the front, then face the other direction... Make sure there is ample room for the fish to turn, i.e. requires six spaces before the edge of the tank minimum...

  • Unless a fish is blowing a bubble or changing direction, it will continue in the direction it is facing, if it gets within six spaces of the side of the tank, it will change direction.
  • The fish (facing left or right) can on occasion (10% chance) stop to blow bubbles in succession (.oO*), so the fish is required to have a space available next to them in order for the bubble to exist, so a fish can only swim as close to the sides, save one space. The bubble must disappear before the fish can move on...

A series of example lines of the fish's behavior, with - characters indicating the spaces, as the code display feature on here is a little strict... I will expect these dashes to be replaced with spaces when you code this...

Each line here could be considered a frame in time-lapse.

|-}}< }} ',')----------|
|--}}< }} ',')---------|
|---}}< }} ',')--------|
|----}}< }} ',')-------|
|-----}}< }} ',')------|
|-----}}< }} ',').-----|
|-----}}< }} ',')o-----|
|-----}}< }} ',')O-----|
|-----}}< }} ',')*-----|
|---------}}('_'){{----|
|-----------(',' {{ >{{|
|----------(',' {{ >{{-|
|---------(',' {{ >{{--|
|--------.(',' {{ >{{--|
|--------o(',' {{ >{{--|
|--------O(',' {{ >{{--|
|--------*(',' {{ >{{--|
|--------(',' {{ >{{---|
|-------(',' {{ >{{----|
|------(',' {{ >{{-----|

etc. The above example is, as I said, small, but you get the general idea...

Shortest code wins...

I am expecting the output on the same line (if possible), if not, displaying frame after frame in succession is fine... Whether you go one line or multiple lines is up to you. If you are doing multiple lines, they must be separated by a newline.

Also a timer is imposed between frames, 2000ms . This is mandatory.

Let's see what you've got!

\$\endgroup\$
  • \$\begingroup\$ If the fish gets too close to the edge of the aquarium, is it required to turn, or it may phase out of the screen? Must it be possible that the fish blows bubbles in this situation? Also, must it be possible (or is it forbidden, or is allowed but not required) for the fish to blow bubbles twice in succession? \$\endgroup\$ – John Dvorak Jan 16 '14 at 6:04
  • 1
    \$\begingroup\$ Wait, no, don't do changes like this! I've already started coding! Would you mind rolling back? \$\endgroup\$ – John Dvorak Jan 16 '14 at 6:29
  • 5
    \$\begingroup\$ Please use the sandbox the next time. \$\endgroup\$ – John Dvorak Jan 16 '14 at 6:32
  • 1
    \$\begingroup\$ It's not explicitly stated, but I guess there must be exactly one fish in the aquarium? \$\endgroup\$ – John Dvorak Jan 16 '14 at 7:08
  • 1
    \$\begingroup\$ Is it required that the fish may bubble twice in succession, or are we allowed to let it happen? It makes a three-character difference for me. \$\endgroup\$ – John Dvorak Jan 16 '14 at 7:42
11
\$\begingroup\$

Python 3 (278)

Previously: 334, 332, 325, 302, 300, 299, 291, 286, 284, 281

import random,time
r=random.random
F="}}('_'){{%s","}}< }} ',')%s","%s(',' {{ >{{"
p,d=9,1
c=b=0
while 1:
 if c:p-=c+c*3*(2*d+c==1);d=c-c*d*d;c-=d
 elif b%5:b+=1
 elif.3>r()or{p*d}<{-5,53}:c=-d
 elif.1>r():b=1
 else:p+=d
 print('|%-70s|'%(' '*p+F[d])%' .oO*'[b%5]);time.sleep(2)

Golfing in Python is always difficult due to the indentation requirements of statements, but despite that, this went incredibly well!

Big thanks to Volatility and DSM for helping me golf this so much further.

Clean version

from random import random as r
from time import sleep as s
F = { 1: "}}< }} ',')%s", 0: "}}('_'){{%s", -1: "%s(',' {{ >{{" }

# p: position (from left)
# d: direction (-1: left, +1: right)
# c: changing direction (0: not changing, +1: to right, -1: to left)
# b: bubble (0)
p, d, c, b = 9, 1, 0, 0

while 1:
    if c:
        p -= c*[1,4][2*d+c==1]
        if d:
            d = 0
        else:
            d, c = c, 0
    elif b % 5:
        b += 1
    else:
        # change direction
        if r() < .3 or p * d in (-5,53):
            c = -d
        # start bubbling
        elif r() < .1:
            b = 1
        # move forward
        else:
            p += d

    # print fish and sleep
    print('|{:<70}|'.format(' '*p+(F[d]%' .oO*'[b%5])))
    s(2)
\$\endgroup\$
7
\$\begingroup\$

Ruby, 291 289

l="(',' {{ >{{";m="    }}('_'){{    ";r="}}< }} ',')";w=?\s;s=w*6;q="|#{r+s*9}|"
f=->*s{(puts q;sleep 2)if q.sub! *s}
loop{rand>0.1||(f[") ",")."]||f[" (",".("];f[?.,?o];f[?o,?O];f[?O,?*];f[?*,w])
q[7]==?(||q[-8]==?)||rand<0.3?f[s+l,m]&&f[m,r+s]||f[r+s,m]&&f[m,s+l]:f[w+l,l+w]||f[r+w,w+r]}

The fish is eleven characters long, making the aquarium 6*9+11+2 = 67 characters wide, which fits neatly in the required tolerance.

The f lambda function does all the heavy lifting: it accepts a substitution as a pair of arguments, then attempts to apply the substitution on the aquarium. If it succeeds, it paints one frame of the animation. It then reports the success value as 2 (the delay taken) or nil (delay not executed).

Fish will not blow bubbles twice in succession. (Fix: ...while rand>0.1 - 4 characers)

Fish may blow bubbles even before a forced turn. (Fix: rearrange the branching structure)

There is a frame where the bubble is completely gone (including the *) but the fish has not moved into the resulting void. This follows the letter, but not the example. (Fix: replace f[?*,w] with q[?*]=w - free)

Does not clear the console. Fix: add `clear` (Unix) or system 'cls' (Windows console) before puts q to fix (Ref.) or use print instead of puts and prepend \r to the aquarium (suggested by @manatwork).

Readable version:

# l - left fish; m - middle fish + space; r - right fish
# w - single space character; s - six spaces; q - the aquarium
l="(',' {{ >{{"; m="    }}('_'){{    "; r="}}< }} ',')";
w=" "; s=w*6; q="|#{r+s*9}|"
f = ->k,v do
  if q.sub! k,v
    puts q
    sleep 2
    return 2
  else
    return nil
  end
end

loop do
  if rand < 0.1
    f[") ",")."] || f[" (",".("]
    f[?.,?o]; f[?o,?O]; f[?O,?*]; f[?*,' ']
  end
  if q[7] == "(" || q[-8] == ")" || rand < 0.3
    (f[s+l,m] && f[m,r+s]) || (f[r+s,m] && f[m,s+l])
  else
    f[w+l,l+w] || f[r+w,w+r]
  end
end
\$\endgroup\$
  • \$\begingroup\$ I would add \r to the beginning of q: q="\r|#{r+s*9}|". Then use $><<q instead of puts q. Is 1 character longer, but looks better without using external commands. \$\endgroup\$ – manatwork Jan 16 '14 at 10:29
  • \$\begingroup\$ \r clears the screen? It doesn't in my case. Or, why don't you like puts? \$\endgroup\$ – John Dvorak Jan 16 '14 at 10:35
  • 1
    \$\begingroup\$ No, \r is carriage return. By using $><<q for output the cursor will stay in the same line (puts forces a \n after the output) so starting the next output with \r will jump back to the beginning of the current line and start to output from there. Thus overwrites the aquarium line's previous “image”. \$\endgroup\$ – manatwork Jan 16 '14 at 10:40
  • \$\begingroup\$ @manatwork unfortunately, this completely messes up the jRuby interactive window, which ignores the \r. \$\endgroup\$ – John Dvorak Jan 16 '14 at 10:58
  • \$\begingroup\$ Oh. Sorry to hear that. And thank you for the information. Sadly this is the first fact I learn about jRuby. :( \$\endgroup\$ – manatwork Jan 16 '14 at 11:07
3
\$\begingroup\$

R, 451 characters

A first attempt:

f=function(j,p){cat("\r|",rep("-",j),p,rep("-",50-j),"|",sep="");Sys.sleep(2)};d=F;j=5;P=c("--}}(\'_\'){{--","-}}< }} \',\')-","-(\',\' {{ >{{-");B=c("-",".","o","O","*","-");g=Vectorize(gsub,v="replacement");b=list(g("-$",B,P[2]),g("^-",B,P[3]));repeat{if(j<5 & d){d=!d;j=j+1;f(j,P[1])};if(j>44 & !d){d=!d;f(j,P[1]);j=j-1};if(runif(1)<.1){for(i in b[[d+1]])f(j,i)}else{f(j,P[d+2])};if(runif(1)<.3){d=!d;f(j,P[1]);f(j,P[d+2])};if(d){j=j-1}else{j=j+1}}

Indented:

f=function(j,p){ #Printing function (depends of buffer and kind of fish)
    cat("\r|",rep("-",j),p,rep("-",50-j),"|",sep="")
    Sys.sleep(2)
}
d=F   #Direction: if FALSE left to right, if TRUE right to left.
j=5   #Buffer from left side of tank
P=c("--}}(\'_\'){{--","-}}< }} \',\')-","-(\',\' {{ >{{-") #The fish
B=c("-",".","o","O","*","-") #The bubble sequence
g=Vectorize(gsub,v="replacement")
b=list(g("-$",B,P[2]),g("^-",B,P[3])) #Fish+bubble
repeat{
    if(j<5 & d){ #What happens if too close from left side
        d=!d
        j=j+1
        f(j,P[1])
        }
    if(j>44 & !d){ #What happens if too close from right side
        d=!d
        f(j,P[1])
        j=j-1}
    if(runif(1)<.1){ #If bubble sequence initiated
        for(i in b[[d+1]])f(j,i)
        }else{f(j,P[d+2])} #Otherwise
    if(runif(1)<.3){ #If fish decide to turn
        d=!d
        f(j,P[1])
        f(j,P[d+2])
    }
    if(d){j=j-1}else{j=j+1} #Increment or decrement j depending on direction
}

It prints the aquarium as stdout on a single line (then 2s break and carriage return before the aquarium at t+1 is printed).

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

Perl, 281

@f=("s O(',' {{ >{{","s}}('_'){{s","}}< }} ',')O s");$d=1;@o=split//," *Oo. ";{$_="|".$"x$x.$f[$d+1].$"x(44-$x).'|
';s/O/$o[$b]/;s/s/    /g;print;if($b||$t){$b--if$b;if($t){$d+=$t;$t=0if$d}}else{$x+=$d;$t=($x<1)-($x>43);if(!$t){$b=5if.9<rand;if(.7<rand){$t=-$d;$b=0}}}sleep 2;redo}

or more clearly

@f = ( "s O(',' {{ >{{", "s}}('_'){{s", "}}< }} ',')O s" );
$d = 1;
@o = split //, " *Oo. ";
{
    $_ = "|" . $" x $x . $f[ $d + 1 ] . $" x ( 44 - $x ) . '|
';
    s/O/$o[$b]/;
    s/s/    /g;
    print;
    if ( $b || $t ) {
        $b-- if $b;
        if ($t) { $d += $t; $t = 0 if $d }
    }
    else {
        $x += $d;
        $t = ( $x < 1 ) - ( $x > 43 );
        if ( !$t ) {
            $b = 5 if .9 < rand;
            if ( .7 < rand ) { $t = -$d; $b = 0 }
        }
    }
    sleep 2;
    redo
}

Fish turning correctly. Bubbles blowing.

285 - if you like the real aquarium feel and not the scrolling version:

$|=@f=("s O(',' {{ >{{","s}}('_'){{s","}}< }} ',')O s");$d=1;@o=split//," *Oo. ";{$_="\r|".$"x$x.$f[$d+1].$"x(44-$x).'|';s/O/$o[$b]/;s/s/    /g;print;if($b||$t){$b--if$b;if($t){$d+=$t;$t=0if$d}}else{$x+=$d;$t=($x<1)-($x>43);if(!$t){$b=5if.9<rand;if(.7<rand){$t=-$d;$b=0}}}sleep 2;redo}
\$\endgroup\$
  • \$\begingroup\$ Where do you do turning? I can't see you setting $d=0 in the "required turning" case. \$\endgroup\$ – John Dvorak Jan 16 '14 at 21:19
  • 1
    \$\begingroup\$ sleep2 (without space) is not working for me; also when you are turning, you don’t keep the fish face aligned. And the bubbles seem to never appear. \$\endgroup\$ – poke Jan 16 '14 at 21:25
  • \$\begingroup\$ "Also a timer is imposed between frames, 2000ms . This is mandatory." - this doesn't happen at all for me. Also, bubbles don't appear, the fish just sits in place. Also, the head should stay in place while the fish is turning, not the body center (at least that's what the example shows) \$\endgroup\$ – John Dvorak Jan 16 '14 at 21:28
  • \$\begingroup\$ Drat! Golfed too Hard. Need an extra space with sleep! Fish was bubbling nicely too! hang on... \$\endgroup\$ – KevinColyer Jan 16 '14 at 21:38
  • \$\begingroup\$ Oops - forgot the head in the middle when turning at the edges - need some rework... \$\endgroup\$ – KevinColyer Jan 16 '14 at 21:50
2
\$\begingroup\$

C, 400 394 373 characters

#define p printf
#define a(x) l[5]=r[11]=x;d();
char *l="      (',' {{ >{{",*f="    }}('_'){{    ",*r="}}< }} ',')      ",*c,s=7,i,*T;d(){p("|");for(i=0;i<s;i++)p(" ");p(c);for(i=0;i<70-s;i++)p(" ");puts("|");sleep(2);}b(){a(46)a(111)a(79)a(42)a(32)}t(){T=c;c=f;d();c=T==r?l:r;d();}m(){c==l?s--:s++;d();s>69||s<1?t():0;}main(){c=r;for(d();;)i=rand()%10,i?i>6?t():m():b();} 

With whitespace:

#define p printf
#define a(x) l[5]=r[11]=x;d();
char *l="      (',' {{ >{{",
     *f="    }}('_'){{    ",
     *r="}}< }} ',')      ",
     *c, 
     s=7,
     i,  
    *T; 
d(){
  p("|");
  for(i=0;i<s;i++)
    p(" ");
  p(c);
  for(i=0;i<70-s;i++)
    p(" ");
  puts("|");
  sleep(2);
}
b(){
  a(46)
  a(111)
  a(79)
  a(42)
  a(32)
}
t(){
  T=c;
  c=f;
  d();
  c=T==r?l:r;
  d();
}
m(){
  c==l?s--:s++;
  d();
  s>69||s<1?t():0;
}
main(){
  c=r;
  for(d();;)
    i=rand()%10,
    i?i>6?t():m():b();
}
\$\endgroup\$
  • 1
    \$\begingroup\$ Can i==l?(c=r):(c=l) be shortened to c=i==l?r:l? \$\endgroup\$ – John Dvorak Jan 16 '14 at 18:43
  • \$\begingroup\$ Looks like it can be. Thanks! \$\endgroup\$ – Josh Jan 16 '14 at 18:45
  • \$\begingroup\$ You can save a few characters by #define p printf( \$\endgroup\$ – ace Jan 16 '14 at 22:06
  • \$\begingroup\$ @Ace gcc doesn't like it when I do that. \$\endgroup\$ – Josh Jan 16 '14 at 22:11
  • \$\begingroup\$ it works for me. oi41.tinypic.com/15fqbvb.jpg \$\endgroup\$ – ace Jan 16 '14 at 22:19

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.