Our classic snake has developed an inbalance of growth hormones. To make matters worse, his tail is frozen in place! Given directional input as specified in Figure 1, write a program to determine where he will grow.


Figure 1. Directional input.

Program specifications

  • Read the input character by character on STDIN.
  • After reading a character, output the snake to STDOUT. Please include a blank line in between each time you print a snake.
  • The snake consists of <>v^ and a head. The head of the snake may be any round character of your choosing, such as o, 0, O, or .
  • Any combination of wasd is valid for input.
  • Your program should not assume the input is within a certain length.
  • The snake can pile on top of itself, overwriting <>v^. See examples for snake growing mechanics.
  • Trailing whitespace is okay, but your snake must look correct.


This is . Your score is the number of characters in your program. Lowest score wins!

Example snakes:

Input: ddddssaassdddddww


  v<<  ☺
  v    ^

Input: dddsssaaawww


^  v
^  v

Input: dddsssdddddasddddwww


   v       ☺
   v       ^
   >>>>v<  ^

Input: dddwwdddssssaaaaaaaaawww


☺     ^  v
^  >>>^  v
^        v

Input: ddddssssaawwddddd


  ^ v

Input: dddddssaawwwwddddd


   ^ v




v<<<<  v<<<<  v<<<<  >>>>v
v      v   ^  v   ^  ^   v
v      v   ^  v   ^  v<<<<
v      v   ^  v   ^  v
v      v   ^  v   ^  v
                     v  v<<<<
                     v  v   ^
                     v  v
       >>>>v  >>>>v  v  v
       ^   v  ^   v  v  v<<
       ^   v  ^   v  v  v
       ^   v  ^   v  v  v
  • 8
    \$\begingroup\$ Very nice. But... WTH is a "code gofl"? \$\endgroup\$ – John Dvorak Aug 30 '14 at 14:14
  • 2
    \$\begingroup\$ I'd get rid of the bonus as it is way too easy to create your own snake and input string. \$\endgroup\$ – Beta Decay Aug 30 '14 at 14:14
  • 1
    \$\begingroup\$ @JanDvorak rotfl my bad. \$\endgroup\$ – hmatt1 Aug 30 '14 at 14:16
  • 1
    \$\begingroup\$ @BetaDecay the plane scales. In the code golf example it started at the top left of the c, but since the d is taller it moves down. \$\endgroup\$ – hmatt1 Aug 30 '14 at 14:55
  • 2
    \$\begingroup\$ @chilemagic Thanks! If both are acceptable you should probably clarify this in the question. \$\endgroup\$ – Ingo Bürk Aug 30 '14 at 23:36

11 Answers 11


Ruby, 207 characters

b=[];x=y=0;gets.chars{|c|b[y]||=[];b[y][x]={?\n=>->{?0},?w=>->{y>0?y-=1:b=[[]]+b;?^},?a=>->{x>0?x-=1:b.map!{|r|[' ']+r};b[y][1]=?<},?s=>->{y+=1;?v},?d=>->{x+=1;?>}}[c][]};puts b.map{|r|r.map{|c|c||' '}.join}


b=[]  #board
x=y=0 #position
  b[y] ||= []
  b[y][x] = {
    "\n" => lambda{0},
    "w"  => lambda{if y>0 then y-=1 else b=[[]]+b; "^"},
    "a"  => lambda{if x>0 then x-=1 else b.map!{|r|[' ']+r}; b[y][1]="<"},
    "s"  => lambda{y+=1; "v"},
    "d"  => lambda{x+=1; ">"}
puts b.map{|r|r.map{|c|c||' '}.join}

(the lambda for a writes back because the row the assignment above writes to is no longer on the board)


ECMAScript 6 Javascript (399 401 431)

Has to be run in a browser supporting ECMAScript 6 due to the arrow functions.

Here are fiddles which have been altered to run in any (common) browser by not using arrow functions. They also print to a textarea instead:

Golfed Version

while((i=y.pop())!=null){i-=w;j=x.pop()-q;t=(o[i]||Array(e+1-q).join(" ")).split("");t.splice(j,1,v.pop()||"@");o[i]=t.join("")}alert(o.join("\n"))

Animated GIF:

One of the OP's examples:

enter image description here

The example from Stretch Maniac:

enter image description here


Here is a (slightly) ungolfed version from sometime before I started really golfing it down:

var input = prompt(),
    values = [],
    c = 0,
    x = [0],
    y = [0],
    s = 'unshift';
while (c < input.length) {
    var mapped = 'wasd'.indexOf(input[c++]);
    x[s](x[0]+[0, -1, 0, 1][mapped]);
    y[s](y[0]+[-1, 0, 1, 0][mapped]);

var minX = x.slice().sort(function (a,b){return a-b})[0];
var maxX = x.slice().sort(function (a,b){return b-a})[0];
var minY = y.slice().sort(function (a,b){return a-b})[0];

var output = [];
while((i=y.pop())!=null) {
    t=(output[i]||Array(maxX+1-minX).join(" ")).split("");

  • \$\begingroup\$ The gifs are very cool. Are they made automatically, by a script you've written? \$\endgroup\$ – AndoDaan Aug 31 '14 at 20:25
  • 1
    \$\begingroup\$ Thanks! With the power of Google I just looked up how to make a gift from a screen recording in Ubuntu. It just uses a screen recorder and convert. Pretty easy :) \$\endgroup\$ – Ingo Bürk Aug 31 '14 at 20:29
  • 3
    \$\begingroup\$ (gif, not gift) \$\endgroup\$ – Ingo Bürk Aug 31 '14 at 20:52

sed, 71


Golfscript, 165 126

' '*"\33[":e{e'D'}:-{[e'C'+'<'--]]}:a{[-+'>']]}:d{[e'B'+'^'-e'A']]}:w{[e'A'+'v'-e'B']]}:s{][\[}:+7{;}*''\~[e'H'e'J']\'@'e'20H'

Same approach as my previous answer, but correctly positioning the cursor before and afterwards. I'm pretty proud of the approach to cursor positioning -- basically, it first runs the snake in reverse, without printing out characters.

  • 1
    \$\begingroup\$ Can you add an example call? echo "dddddssaawwwwddddd" | sed -e 's/w/\^\x1B[D\x1B[A/g' -e 's/a/<\x1B[2D/g' -e 's/s/v\x1B[S\x1B[D/g' -e 's/d/>/g' -e 's/$/@/' doesn't give the correct output for me. \$\endgroup\$ – Ingo Bürk Aug 31 '14 at 9:53
  • \$\begingroup\$ Your prompt after executing is probably overwriting part of the snake. Paste the snake directly into stdin instead of piping, or add a few \ns after the @ so your prompt goes elsewhere. \$\endgroup\$ – Sneftel Aug 31 '14 at 9:57
  • 1
    \$\begingroup\$ This might fail if the snake goes up or left of the board. \$\endgroup\$ – tomsmeding Aug 31 '14 at 12:31
  • \$\begingroup\$ @tomsmeding Yeah, I might expand it to deal with that. Language aside, though, I really think ANSI control sequences are the way to go for shorter code. \$\endgroup\$ – Sneftel Aug 31 '14 at 21:47

Java - 646

Might as well be the first one!

I bet you all can beat this.

un(sort of)golfed

import java.util.*;
public class Snake{
    public static void main(String[]a) {
        int x,y,minX,minY,maxX,maxY;
        List<Integer>xs,ys=new ArrayList<Integer>();
        xs=new ArrayList<Integer>();
        List<Character>p=new ArrayList<Character>();
        for(int b=0;b<a[0].length();b++){
            int newX=x,newY=y;
        char[][]c=new char[maxY-minY+1][maxX-minX+1];
        for(int i=0;i<xs.size();i++)c[ys.get(i)-minY][xs.get(i)-minX]=p.get(i);
        for(char[]k:c){for(char l:k){System.out.print(l);}System.out.println();}

Smaller -

import java.util.*;class S{public static void main(String[]a){int x,y,o,z,s,u;x=y=o=s=z=u=0;List<Integer>j,t=new ArrayList<Integer>();j=new ArrayList<Integer>();List<Character>p=new ArrayList<Character>();for(int b=0;b<a[0].length();b++){int e=x,r=y;switch(a[0].charAt(b)){case'a':e--;p.add('<');break;case's':r++;p.add('v');break;case'd':e++;p.add('>');break;case'w':r--;p.add('^');break;}j.add(x);t.add(y);x=e;y=r;if(x<o)o=x;if(x>s)s=x;if(y<z)z=y;if(y>u)u=y;}char[][]c=new char[u-z+1][s-o+1];for(int i=0;i<j.size();i++)c[t.get(i)-z][j.get(i)-o]=p.get(i);c[y-z][x-o]='@';for(char[]k:c){for(char l:k){System.out.print(l);}System.out.println();}}}

input - dddsssdddwwwwaaaaaaaassssssssssddddddddddddddddd

v >>>v  ^         
v    v  ^         
v    v  ^         
v    >>>^         

input - dddsssdddddasddddwww

   v       @
   v       ^
   >>>>v<  ^

my personal favorite - dwdwdwddaasassdddddwdwdwddsdswawaasassdddddddwdwdwddsdswawaasassddddwwwwwwwssssssdsdddwwwwddaassddaassddddsssdddwdwdwddaasasassddddwwwwssssssssasasaaawdwwdwddwwdddddddwdwdwddsdswawaasassddddddddddwwdwwwwaasssassdsdddddddwdwdwwwwasasssssssssssdwwwwwwwddd

                    v   v<<                                    
   v<<   v<<     v<<v   v                                      
  v<    v< ^<   v< ^v   v<<                        v<<     v<  
 >v    >v   ^  >v   >v  v                          v ^    v<^  
>^>>>>>^>>>>>>>^>>>>^>>>>>>>v    v<v               v ^    v ^  
                            v   v< v       v<<    v< ^    v ^  
                            v  v<  v      v< ^<   v >^    v>^  
                            >>>v   v     >v   ^   >v^     v>>>@
                                  ^v                      v^   
                                >>^v                      v^   
                               >^  v                      v^   
                               ^  v<                      v^   
                              >^ v<                       v^   
                              ^<<<                        >^  

C# 607

namespace System{using B=Text.StringBuilder;class P{static void Main(){var f=new Collections.Generic.List<B>(){new B("O")};int w=1,r=0,c=0;for(Action R=()=>f[r].Append(' ',w-f[r].Length+1);1>0;){var key=Console.ReadKey(1>0).KeyChar;if(key=='w'){f[r][c]='^';if(--r<0)f.Insert(r=0,new B());R();f[r][c]='O';}if(key=='a'){f[r][c]='<';if(--c<0){foreach(var s in f)s.Insert(c=0,' ');w++;}R();f[r][c]='O';}if(key=='s'){f[r][c]='v';if(++r>f.Count-1)f.Add(new B());R();f[r][c]='O';}if(key=='d'){f[r][c]='>';if(++c>w++)foreach(var s in f)s.Append(' ');R();f[r][c]='O';}Console.WriteLine(string.Join("\n",f)+"\n");}}}}

"Ungolfed" with whitespace (this will not be kept in sync with the golfed version):

namespace System
    using B = Text.StringBuilder;
    class P
        static void Main()
            var f = new Collections.Generic.List<B>() { new B("O") };
            int w = 1, r = 0, c = 0;
            Action R = () => f[r].Append(' ', w - f[r].Length + 1);
            while (true)
                char key = Console.ReadKey(1>0).KeyChar;
                if (key == 'w')
                    f[r][c] = '^';
                    if (--r < 0) { f.Insert(0, new B()); r = 0; }
                    f[r][c] = 'O';
                if (key == 'a')
                    f[r][c] = '<';
                    if (--c < 0)
                        foreach (var s in f)
                            s.Insert(0, ' ');
                        c = 0;
                    f[r][c] = 'O';
                if (key == 's')
                    f[r][c] = 'v';
                    if (++r > f.Count - 1) f.Add(new B());
                    f[r][c] = 'O';
                if (key == 'd')
                    f[r][c] = '>';
                    if (++c > w++)
                        foreach (var s in f)
                            s.Append(' ');
                    f[r][c] = 'O';

                Console.WriteLine(string.Join("\n", f) + "\n");

Python 3: 259 Bytes

while 1:
 d='wasd'.index(input());b[(x,y)]='^<v>'[d];x+=p[d];y-=p[~d];b[(x,y)]='☺';l,m=([k[i]for k in b]for i in(0,1))
 for j in r(min(m),max(m)+1):print(''.join(b[(i,j)]if(i,j)in b else' 'for i in r(min(l),max(l)+1)))

I decided to store the snake in a dict, with coordinates for the keys. Then find and iterate over the output range, substituting blank spaces.

x = y = 0
board = {}
while 1:
    d = 'wasd'.index(input())
    board[(x, y)] = '^<v>'[d] # body
    x += (0, -1, 0, 1)[d]
    y -= list(reversed((0, -1, 0, 1)))[d]
    board[(x,y)] = '☺' # head

    xs, ys= ([coord[dim] for coord in board] for dim in(0, 1))
    for j in range(min(ys), max(ys)+1):
        print(''.join(board[(i,j)] if (i,j) in board else ' '
                      for i in range(min(xs), max(xs)+1)))

PS. My first Golf :) Let me know if my answer is inappropriate

  • \$\begingroup\$ Using O instead of saves you 2 bytes. is a red herring. \$\endgroup\$ – Erik the Outgolfer Jul 31 '16 at 18:20
  • \$\begingroup\$ @EʀɪᴋᴛʜᴇGᴏʟғᴇʀ wasn't actually counted as 3 bytes. \$\endgroup\$ – Martin Ender Jul 31 '16 at 18:30
  • \$\begingroup\$ @MartinEnder It must be, the default encoding is UTF-8. I had a feeling it wasn't counted. I have a feeling it was accidental and must be immediately fixed by Gilly. \$\endgroup\$ – Erik the Outgolfer Jul 31 '16 at 18:39
  • \$\begingroup\$ @EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Well technically, the answerer is free to use any encoding supported by their interpreter (and I'm pretty sure some ASCII-compatible code page contains that character) but that's beside the point. I'm saying the byte count is already the same as that of using O, so I wouldn't worry about it. It's clear from the code that it would still work for any other character but using lets you conveniently run the test cases from the challenge without changes. \$\endgroup\$ – Martin Ender Jul 31 '16 at 18:43
  • \$\begingroup\$ @MartinEnder Python uses UTF-8, proved by its ability to support unicode strings. To enable this functionality, the first or second line must be #coding=utf-8. Note that #coding=utf-16 does not work. Hence must be counted as 3. \$\endgroup\$ – Erik the Outgolfer Jul 31 '16 at 18:45

Python 2.7 - 274 bytes

for c in raw_input():b='wasd'.index(c);m[(x,y)]='^<v>'[b];x+=d[b];y-=d[~b];m[(x,y)]='@';l,n=([k[h] for k in m] for h in (0, 1))
for j in range(min(n),max(n)+1):print(''.join(m[(i,j)] if (i,j) in m else ' 'for i in range(min(l),max(l)+1)))

Ungolfed version

x,y,matrix,delta = 0,0,{},(0, -1, 0, 1)    
for c in raw_input('Command: '):
    d = 'wasd'.index(c)
    matrix[(x, y)] = '^<v>'[d]
    x += delta[d]
    y -= list(reversed(delta))[d]
    matrix[(x, y)] = '@'    
xs, ys = ([xy[i] for xy in matrix] for i in (0, 1))
for j in range(min(ys), max(ys)+1):
    print(''.join(matrix[(i, j)] if (i, j) in matrix else ' '
                  for i in range(min(xs), max(xs)+1)))
  • 2
    \$\begingroup\$ Welcome to Programming Puzzles & Code Golf! According to the rules outlined in our help center, all solutions to challenges should be a serious contender for the winning criteria in use. For example, an entry to a code golf contest needs to be golfed. \$\endgroup\$ – Dennis Mar 19 '16 at 17:09
  • 1
    \$\begingroup\$ I'm added the byte count for you, but there's quite a lot of unnecessary spaces in there which you might want to remove. \$\endgroup\$ – Martin Ender Mar 19 '16 at 18:38
  • \$\begingroup\$ Thanks guys, I made the necessary changes to my first entry. Any extra advice will be greatly appreciated. \$\endgroup\$ – Adriaan Erasmus Mar 20 '16 at 7:20
  • \$\begingroup\$ I really golfed it. \$\endgroup\$ – Erik the Outgolfer Jul 31 '16 at 19:04
  • \$\begingroup\$ @EʀɪᴋᴛʜᴇGᴏʟғᴇʀ That just prints SyntaxError: invalid syntax. \$\endgroup\$ – Dennis Jul 31 '16 at 19:34

05AB1E, 35 34 30 28 bytes


Uses 0 as head of the snake.

-4 bytes thanks to @Grimy.

Try it online (no test suite for all test cases at once, because there is no way to reset the Canvas, so outputs would overlap..).


.•₃º•          # Push compressed string "adsw"
     "<>v^"    # Push string "<>v^"
           ©   # Save it in variable `r` (without popping)
            ‡  # Transliterate the (implicit) input-string,
               # replacing all "adsw" with "<>v^" respectively
               #  i.e. "ddddssaassdddddww" → ">>>>vv<<vv>>>>>^^"
0ª             # Convert the string to a list of characters, and append a 0 (for the head)
               #  → [">",">",">",">","v","v","<","<","v","v",">",">",">",">",">","^","^","0"]
  Ð            # Triplicate this list of characters
   U           # Pop and store one of the three lists in variable `X`
   Ā           # Trutify each character ("0" remains 0; everything else becomes 1)
    >          # And then increase each integer by 1
               #  → [2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1]
  s            # Swap the two lists on the stack
      ®Xk      # Get the index of each character of variable `X` in variable `r` ("<>v^")
               #  i.e. [">",">",">",">","v","v","<","<","v","v",">",">",">",">",">","^","^","0"]
               #   → [1,1,1,1,2,2,0,0,2,2,1,1,1,1,1,3,3,-1]
   ŽO^   è     # And use those to index into the compressed number 6240
               #  → [2,2,2,2,4,4,6,6,4,4,2,2,2,2,2,0,0,0]
Λ              # Use the Canvas builtin with these three lists

See this 05AB1E tip of mine (sections How to compress strings not part of the dictionary? and How to compress large integers?) to understand why .•₃º• is "adsw" and ŽO^ is 6240.

As for a brief explanation of the Canvas builtin Λ and its three arguments:

First argument: length(s): the sizes of the lines we want to draw. Since we have to keep in mind overlapping, we use size 2 for every character, and an additional 1 for the head of the snake.
Second argument: string(s): the characters we want to display. Which are the characters in this case, appended with the head-character of the snake.
Third argument: direction(s): the directions these character-lines of the given length should be drawn in. In general we have the directions [0,7] which map to these directions:

7   0   1
  ↖ ↑ ↗
6 ← X → 2
  ↙ ↓ ↘
5   4   3

Which is why we have the integer 6240 for the directions \$[←,→,↓,↑]\$ respectively.

See this 05AB1E tip of mine for a more detailed explanation about the Canvas builtin Λ.

  • 1
    \$\begingroup\$ I might have missed something, but I don't think γ is needed at all. This seem to work just fine. \$\endgroup\$ – Grimmy Jun 4 '19 at 10:37
  • \$\begingroup\$ @Grimy Thanks, it indeed does; nice alternative approach with the list of 2s and 1 for the head! And I've been able to save 2 more bytes based off your program. \$\endgroup\$ – Kevin Cruijssen Jun 4 '19 at 12:02
  • \$\begingroup\$ Thanks! I am currently at 23, though that's a significantly different approach, so I might make it its own answer if that's fine by you. \$\endgroup\$ – Grimmy Jun 4 '19 at 12:22
  • \$\begingroup\$ @Grimy That indeed is quite a different approach than mine, so feel free to post it. I was indeed kinda expecting some unicode conversion and modulo might make this shorter than the transliterate, but I'm quite honestly pretty bad with those kind of magic integer/string conversions. :) \$\endgroup\$ – Kevin Cruijssen Jun 4 '19 at 12:24

Perl - 394

Not the shortest, but it beats Javascript, C# and Java at least.

use List::Util qw(min max);sub c{()=$_[0]=~/$_[1]/g}%l=(a,['<',-1,0],d,['>',1,0],w,['^',0,-1],s=>['v',0,1]);($s,$x,$y,$w,$h)=($ARGV[0],0,0,max(c($s,a),c($s,d)),max(c($s,w),c($s,'s')));@s=split'',$s;map$x=min($x,$i+=$l{$_}[1]),@s;$i=0;map$y=min($y,$i+=$l{$_}[2]),@s;$x=abs $x;$y=abs $y;map{$m[$y][$x]=$l{$_}[0];$x+=$l{$_}[1];$y+=$l{$_}[2]}@s;$m[$y][$x]='o';map{map{print$_||' '}@$_;print"\n"}@m 

Some tricks:

  • Warnings and strict not turned on to allow barewords and not declaring variables before using them
  • Thin commas instead of fat commas to save a few characters
  • Not setting initial values for variables when not necessary
  • Leaving out semi-colons when possible
  • Defining arrays and hashes not as references to avoid having to use ->
  • Allowing width, height to be larger than necessary to avoid having to calculate them accurately (which would take extra code)

Things that hurt:

  • No built-in way to count number of characters in a string (might have been longer anyway)
  • No built-in min/max functions, thus need to waste 27 characters to import library that does it (less than defining our own)

C - 273 bytes - with Interactive Input!

#define F for(i=w*w

The field is printed each time a character is entered and grows if the snake's head nears the edge. I don't know how portable it is--someone on the Internet said getch() doesn't work on non-Windows platforms. Hard to say whether ASCII 1 will look like a smiley face either.

The golfed version is quite annoying as there is no way to gracefully exit the program. Control-C doesn't work for me. On the other hand, the ungolfed version terminates if a character other than 'w', 'a', 's', or 'd' is entered.

So-called "ungolfed":

#define SMILEYFACE 1
int main()
    int o;
    int w = 1;
    int *g = 0, *g2;
    int c, n;
    int x = 0;
    for( putch(SMILEYFACE);c = getch(); ) {
            return 1;
        if(!(x%w) | !(~-~x%w) | !(x/w)  | !(x/w-~-w) ) {
            int wnew = w + 4;
            int off = 2;
            g2 = calloc(wnew*wnew,sizeof(int));
            for(n = w*w; --n; )
                g2[ n%w+off + (n/w+off)*wnew ] = g[n];
            g = g2;
            x = (x/w+off)*wnew + x%w + off;
            w = wnew;
        int i = -~c%7;
        g[x] = "<^X>v"[i];
        int dx = 1-g[x]%3 + w * (!!i-i/2);
        x += dx;
        g[x] = SMILEYFACE;
        for(o = w*w; o; )

    return 0;

05AB1E, 23 bytes


Try it online!


                      # implicit input (eg: "wasd")
Ç                     # codepoints (eg: [119, 97, 115, 100])
 7%                   # modulo 7 (eg: [0, 6, 3, 2])
   DÉ+                # plus itself modulo 2 (eg: [0, 6, 4, 2])
# This is the list of directions that will be passed to 05AB1E's canvas function, Λ.
# 0 means up, 6 left, 4 right, 2 down.

 "^>>v"º              # "^>>v", horizontally mirrored (namely "^>>vv<<^")
D       sè            # index into this with a copy of the list of directions
          0ª          # append "0"
# This is the list of strings that will be drawn.

D                     # duplicate the list of strings
 Ā                    # truthify (maps letters to 1, 0 stays 0)
  >                   # increment each
# This is the list of lengths to draw.

r                     # reverse the stack because Λ takes arguments in the opposite order
 Λ                    # draw!


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.