Recreate a 'Snake' game in a console/terminal

Games are fun

this codegolf here was so fun I had to make a version for other classic games similar in complexity. Shortest Way of creating a basic Space Invaders Game in Python

This time, however, try to recreate the classic 'Snake' game, in which you start out as a small shape, constantly moving to collecting pieces to increase your score. When you collect a piece, your 'tail' grows, which follows the path you have made. The objective is to last the longest without crashing into your own tail, or into the walls

Qualifications:

• You, the characters that make up the tail, the walls, and the pieces you collect should all be different characters
• show an HUD with the score. The score increases by 1 point for each piece you collect
• The player loses when they collide with their own tail or the wall
• a piece spawns in a random area immediately after a piece is collected, not to mention at the start of the game
• Speed of the game doesn't matter, as long as it is consistent
• The 'cells' should be 2x1 characters, since the height of block characters is ~twice the width Can be 1x1, because 2x1 is just ugly and I didnt really think of that
• The keys for changing the direction should be awsd, left, up, down, right respectively
• the starting direction should always be up
• You must show the edges of the wall. The score may overlap the wall

Shortest code that meets the above criteria wins. Imaginary Bonus Points for creativity

• The snake isn't supposed to grow when eating? Jan 4 '12 at 0:18
• hm? "When you collect a piece, your 'tail' grows, which follows the path you have made.", so yes, the snake grows. Jan 4 '12 at 2:46
• Without the awsd and the starting direction should always be up requirements, M-x snake would work Apr 22 '14 at 14:12
• @scrblnrd3 M-: (progn(define-key snake-mode-map"a"'snake-move-left)...(setq snake-initial-velocity-x 0 snake-initial-velocity-y 1)(snake)) would do the trick then. Mar 31 '16 at 12:51
• Related: Nibbles Nostalgia Jun 9 '18 at 1:11

JavaScript (553 512 bytes)

c=0;a=b=d=-1;e=[f=[20,7],[20,8]];i=Math.random;~function n(){if(c&&(87==a||83==a
))c=0,d=87==a?-1:1;if(d&&(65==a||68==a))d=0,c=65==a?-1:1;p([j=e[0][0]+c,k=e[0][1
]+d])||!j||39==j||!k||10==k?b+=" | GAME OVER":(e.unshift([j,k]),p(f)?(f=[1+38*i(
)|0,1+9*i()|0],b++):e.pop());for(m=h="";11>h;h++){for(g=0;40>g;g++)l=g+","+h,m+=
!g||39==g||!h||10==h?"X":e[0]==l?"O":p(l)?"*":f==l?"%":" ";m+="\n"}x.innerHTML=m
+b;!b.sup&&setTimeout(n,99)}();onkeydown=function(o){a=o.keyCode};function p(o){
return e.join(p).indexOf(p+o)+1}


I tried to make it output to the real console at first (with console.log and console.clear), but it was flickering too much, so I put it into console-like HTML. It will work with this:

<pre id=x>


Also I implemented it with 2x1 cells first, but it just looked worse than 1x1. That would be a minor change though.

Uses awsd keys on keyboard.

Update:

I was able to cut it down to 512 (exactly 0x200) bytes by improving the tail search and doing some more magic.

You now get 2 points when a piece spawns in your tail (it's a feature). I also fixed the overlapping when the snake bites itself.

• beautiful! and you're right, it does look better as 1x1 than 2x1. the only worry I really had there was up and down being way faster than left and right but it's doable considering the constraints. The flashing in the console I don't mind so much (see my space invaders program, its fairly flickering) but I suppose a plain text web page works too! one qualm though... is there any way to restart without needing to refresh? :( Jan 4 '12 at 5:24
• Doesn't work with awsd Jan 4 '12 at 21:56
• @Blazer That would take more 13 characters :-/ ... and you have the F5 key anyway.
– copy
Jan 5 '12 at 0:23
• @Neal Yeah I used the arrow keys but fixed it now.
– copy
Jan 5 '12 at 0:24
• @copy I suppose I didn't make it a requirement Jan 5 '12 at 0:28

16 bit 8086

526 bytes / 390 bytes

Decode this using a Base64 decoder and call it "snake.com" then execute from Windows command prompt. Tested on WinXP, you may need to use DosBox to get the right video mode. Control keys are 'wasd' and space to exit. Press 'w' to start.

uBMAzRC5AD+2AOipAb1AAbgAoI7Auf//v4sMsAHzqrgAtLksAfOqg8cU/sx19OgsAYs+8gKwAuj4
ALQAzRpCiRYOA4kWEAPouAC0C80hCsB0IbQIzSG+ygKDxgOAPAB0EjgEdfSLRAGzAP/Qo1cBiB7w
A775AnREiz70AiaKHbAA6HUAA7/mAok+9AKA/gB0FscGVwHNAoEudAGu/zPJtj/o2QDofQC0AM0a
OxYOA3X2/wYOA+lZ/8YEAE7+BIA8CnT16F4AaOAB6EQAM9K5LQD38YvCweACBQoA9+WL+OguALlL
iRYQA4vCw772Ar8K9bUEshCstACL2AHDi4f6ArMDtwXR+LEAwNEC/smA4Q8miA0p7/7PdevoIQA6
xHQE/st13ugKAP7NdcroAwB1+8O3BSbGBQEp7/7PdfaBx0EG/srDuBAQM9uAwwLNEID7CnX2w7gD
gQPvQrVA4++BVdVjgQ==


Here's a character mode version that's 390 bytes long:

uAMAzRC4ALiOwLlQADP/uCCf86uzF6u4AA+xTvOruCCfq7LdfCxUPOr6BgBiz5+AqF8Aqu0AM0aQ
m8Bov+z/rhdAoDDBMOzArhnAoDDBsOLPn4Cix58AiaJHQOclgmijUmiR2JPn4CgP4DvoUCdFOLPo
ID0gP6JoA9AHXhJscFA93DoYgCutsA9+K57X/38YkWiAKLwjPSw76CAr8CALkEALSfrAQwq+L6w8
0gd3EBIFcCAGGCAWSAASBXAgB3dwFzeQEgVwIAYP+gAP7/AgACqtAH0AcAAAAA


This character mode one's three bytes longer (but the snake's better):

uAMAzRC4ALiOwLlQADP/uCCf86uzF6u4AA+xTvOruCCfq/7LdfCxUPOr6BsBiz6BAibHBQEKtADN
GkKJFokCiRaLAujHALQLzSEKwHQhtAjNIb5ZAoPGA4A8AHQSOAR19ItEAbMA/9CjUwGIHn8C6XgA
TgD38UID0gP6JoA9AHXhJscFA93DoYsCutsA9+K57X/38YkWiwKLwjPSw76FAr8CALkEALSfrAQw
q+L6w80gd3IBIFoCAGGDAWSBASBaAgB3eAFzegEgWgIAYP+gAP7/AgACqtAH0AcAAAAA

• points for creativity, but i think using dosbox is cheating because the challenge is to make the game work in an ascii console or terminal, not a dosbox. also, shouldn't code golf be source code, not binary? Jan 5 '12 at 23:10
• @Blazer: That is the source code - I typed the machine code in using a hex editor - that's how l337 I am! ;-) The DosBox thing is only needed if your video drivers have trouble with mode 13 graphics (mine card is OK with it). It wouldn't be difficult to do an ascii version (probably smaller too) Jan 6 '12 at 8:50
• The "390-byte" version decodes to only 388 bytes and hangs when run under dosbox. Looks like something may have been lost in transmission. :( Still, the other two versions are extremely cool! Jan 6 '12 at 12:45
• Is there an ungolfed version of the code? (I don't know this language)
– A.L
Apr 20 '14 at 18:46
• @n.1: The program is 8086 machine code, you can load it into a debugger (D86) and view the code as written, albeit without label names. Apr 22 '14 at 8:07

shell/sh, 578 chars

I tried to be POSIX compliant (being as much portable as possible and avoid bashisms, even the random-number-generator does not need /proc). You can e.g. play it in your native terminal or via a SSH-session: run with 'dash -c ./snake' There is also an unuglyfied/readable variant in ~2800 bytes, which can be seen here.

Some notes: shell-scripting is not suited for coding games 8-)

• to be fair, we only used so called 'builtins', which means:
• no external calls of programs like 'clear', 'stty' or 'tput'
• because of that, we redraw the whole screen on every move
• the only used builtins (aka native commands) are:
• echo, eval, while-loop, let, break, read, case, test, set, shift, alias, source
• there is no random number generator (PRNG), so we have to built our own
• getting a keystroke blocks, so we have to spawn another thread
• for getting the event in parent-task we use a tempfile (ugly!)
• the snake itself is a list, which is cheap:
• each element is a (x,y)-tuple
• loosing the tail means: shift the list by 1
• the grid is internally an array, but shell/sh does not know this:
• we "emulated" array(x,y) via an ugly eval-call with global vars
• and finally: we had a lot of fun!
#!/bin/sh
alias J=do T=let E=echo D=done W=while\ let
p(){ eval A$1x$2=${3:-#};} g(){ eval F="\${A$1x$2:- }";}
r(){
E $((1+(99*I)%$1))
}
X=9
Y=8
L="8 8 $X$Y"
I=41
W I-=1
J
p $I 1 p$I 21
p 1 $I p 41$I
D
p 3 3 :
>L
W I+=1
J
E -ne \\033[H
y=22
W y-=1
J
Z=
x=42
W x-=1
J
g $x$y
Z=$Z$F
D
E "$Z" D E$B
. ./L
case $D in a)T X+=1;;d)T X-=1;;s)T Y-=1;;*)T Y+=1;;esac g$X $Y case$F in
\ |:)p $X$Y O
L="$L$X $Y" case$F in
:)W I+=1
J
x=r 39
y=r 19
g $x$y
[ "$F" = \ ]&&{ p$x $y : break } D T B+=1;;*)set$L
p $1$2 \
shift 2
L=$@;;esac;;*).;; esac D& while read -sn1 K J E D=$K>L
D


• Does this actually work? if the snake is going to the right and you press a it stops. Weird. Apr 20 '14 at 14:59
• Yes, because you bite yourself - thats the way it must be IMHO. We discussed that internally and everybody agrees on this. Apr 20 '14 at 15:31
• echo -n is definitely not portable. If the first operand is -n, or if any of the operands contain a backslash ( '\' ) character, the results are implementation-defined. Using echo for anything other than literal text without any switches is not portable. pubs.opengroup.org/onlinepubs/009604599/utilities/echo.html Apr 20 '14 at 18:57
• nyuszika7h: any idea how to circument this? Apr 20 '14 at 20:53
• nyuszika7h: i found a way to remove the main 'echo -n' call - so there is only one call left. it's calling the escape-sequence for 'go to home-position (0,0)' Apr 22 '14 at 14:07

C# .NET Framework 4.7.2 Console (2,4562,4402,4242,4082,0521,9731,747 1,686 bytes)

This was fun, but I really had to think what variables were what, because they are only one letter.

using m=System.Console;using System;using System.Collections.Generic;using System.Threading;class s{static void Main(){m.CursorVisible=0>1;new s()._();}int l;Action<string> w=(x)=>m.Write(x);Action<int,int>n=(x,y)=>m.SetCursorPosition(x,y);(int x,int y)d,c,a;int h,u;List<(int x,int y)>p;void _(){while(1>0){f();h=25;u=25;p=new List<(int x,int y)>();l=0;d=(0,-1);c=(u/2,h/2);e();m.SetWindowSize(u+4,h+4);m.SetBufferSize(u+4,h+4);while(1>0){k();if(t())break;g();r();}f();m.SetWindowSize(u+4,h+6);m.SetBufferSize(u+4,h+6);n(1,h+3);w("        Game over,\n   press any key to retry.");f();m.ReadKey(1>0);m.Clear();}}private bool t(){if(c.x<0||c.y<0||c.x>=u||c.y>=h){r();n(c.x+2,c.y+2);w("X");return 1>0;}for(i=0;i<p.Count;i++){for(int j=0;j<i;j++){if(p[i].x==p[j].x&&p[i].y==p[j].y){r();n(c.x+2,c.y+2);w("X");return 1>0;}}}return 0>1;}private void e(){a=(z.Next(u),z.Next(h));l++;}void f(){while(m.KeyAvailable)m.ReadKey(1>0);}int i;void k(){var b=DateTime.Now;while((DateTime.Now-b).TotalMilliseconds<230)Thread.Sleep(10);if(!m.KeyAvailable)return;var a=m.ReadKey(1>0).Key;switch(a){case ConsoleKey.A:if(d.x==0)d=(-1,0);break;case ConsoleKey.W:if(d.y==0)d=(0,-1);break;case ConsoleKey.S:if(d.y==0)d=(0,1);break;case ConsoleKey.D:if(d.x==0)d=(1,0);break;}f();}void g(){c.x+=d.x;c.y+=d.y;p.Add((c.x,c.y));while(p.Count>l)p.RemoveAt(0);if(c.x==a.x&&c.y==a.y)e();}void r(){n(1,1);w("/");w(new string('-',u));w("\\");n(1,h+2);w("\\");w(new string('-',u));w("/");for(i=0;i<h;i++){n(1,i+2);w("|");n(u+2,i+2);w("|");}for(i=0;i<h;i++){for(int j=0;j<u;j++){n(i+2,j+2);w(" ");}}n(a.x+2,a.y+2);w("@");for(i=0;i<p.Count;i++){n(p[i].x+2,p[i].y+2);w("#");}n(2,0);w("Score:"+l);}Random z=new Random();}


Some screenshots:

<no longer have binaries, you can compile yourself>

• Console.Write("Score:"+l);Console.WriteLine() -> Console.WriteLine("Score:"+l) Jun 16 '19 at 5:43
• Have you tried tuples as in (int X,int Y)d; ...; d=(0,-1)? That might save bytes. I also can't see why are you doing Vector2 d;Vector2 c;Vector2 a; instead of Vector2 d,c,a. I think you can also store the Console.SetCursorPosition function as a Action<...> single-letter variable. You can subtract DateTime with the - operator. You can also declare loop variables globally and simply zero them out when needed, without declaring them. Jun 16 '19 at 6:30
• [suggestions continue] You can use 1>0 or store true in a variable instead of using the keyword. You might be able to use the glorious --> operator in the loops. In the DateTime b = DateTime.Now part, b can be var. You might or might not be able to save some bytes using dynamic (often lets you merge differently-typed declarations). Jun 16 '19 at 6:41
• Pulling m.write(String) into it's own one-letter long function would probably save a ton Jul 8 '19 at 16:11
• There's also a few blocks that use b.width and b.height a lot that could probably be saved to another 1 letter-named local var Jul 8 '19 at 16:20

Applesoft Basic - 478 (462)

This was my first ever code golf, but it was written back in 1989, and it mostly implements the snake game as requested (but without food, the snakes just continuously grow, and it's actually two players, not one) using only two lines of Applesoft Basic.

There were a number of two-line program contests at the time, such as in Dr. Dobbs journal. I spent 6 months figuring out how to fit this into two lines which have a limit of 255 characters (and only one branch)

The program typed in is exactly two lines:

1ONSCRN(X,Y)<>7ANDB<>0ANDSCRN(U,V)<>7GOTO2:HOME:GR:X=10:Y=20:U=30:V=Y:I=201:J=202:K=203:M=205:W=215:A=193:S=211:Z=218:O=1:Q=-1:P=49152:COLOR=7:HLIN0,39AT0:HLIN0,39AT39:VLIN0,39AT0:VLIN0,39AT39:VTAB22: ?"WASZ IJKM  "C:ONB=0GOTO2:CALL-678:RUN
2PLOTX,Y:PLOTU,V:B=PEEK(P):G=B<>ZANDB<>W:H=B<>AANDB<>S:O=G*(O*H+(B=S)-(B=A)):L=H*(L*G+(B=Z)-(B=W)):G=B<>IANDB<>M:H=B<>JANDB<>K:Q=G*(Q*H+(B=K)-(B=J)):R=H*(R*G+(B=M)-(B=I)):X=X+O:Y=Y+L:U=U+Q:V=V+R:FORN=1TO99:NEXT:C=C+1:VTAB22:HTAB12:?C:GOTO1


The listing when formatted looks like this:

1 ONSCRN(X,Y)<>7 AND B<>0 AND SCRN(U,V) <> 7 GOTO 2: HOME : GR :
X=10 : Y=20 : U=30 : V=Y : I=201 : J=202 : K=203 : M=205 : W=215 :
A=193 : S=211 : Z=218 : O=1 : Q=-1 : P=49152 : COLOR=7 : HLIN 0,39
AT 0 : HLIN 0,39 AT 39 : VLIN 0,39 AT 0 : VLIN 0,39 AT 39 : VTAB 22 :
? "WASZ IJKM  "C : ON B=0 GOTO 2 : CALL -678 : RUN
2 PLOT X,Y : PLOT U,V : B=PEEK(P) : G= B<>Z AND B<>W: H=B<>A AND B<>S :
O=G*(O*H+(B=S)-(B=A)) : L=H*(L*G+(B=Z)-(B=W)) : G=B<>I AND B<>M :
H=B<>J AND B<>K : Q=G*(Q*H+(B=K)-(B=J)) : R=H*(R*G+(B=M)-(B=I)) :
X=X+O : Y=Y+L : U=U+Q : V=V+R : FOR N=1 TO 99 : NEXT : C=C+1 :
VTAB 22 : HTAB 12 : ? C : GOTO 1


The game is actually two players and includes "instructions" at the bottom of the page showing the keys as well as a counter so you can see how many steps you survived. It's 478 characters, 16 of those are the instructions and counter output, so 462 if you want to shave those off.

• As described, this sounds more like the Tron light cycles mini game than the snake game. Apr 20 at 3:11
• Yes, the Tron Light Cycles game is essentially 2 player snake. That's true. Apr 22 at 15:04

Ruby 1.9 /Windows only/ (354 337 355 346 bytes)

require'Win32API';G=(W=Win32API).new g="crtdll","_getch",t=[],?I
B=(c=?#*39+h="#
#")+((S=' ')*38+h)*20+c;n=proc{c while B[c=rand(800)]!=S;B[c]=?*;S}
n[h=760];k={97=>-1,100=>1,119=>d=-41,115=>41}
(B[h]=?O;system'cls';$><<B<<$.;sleep 0.1
d=k[G.call]if W.new(g,"_kbhit",[],?I).call>0
t<<h;B[h]=?o;B[h+=d]==?*?B[h]=n[$.+=1]:B[t.shift]=S)while B[h]==S  Plays in a 20x40 board in the windows console. The score is shown under the board. Use WASD to control the snake, any other key to exit (forcefully!). Edit the sleep time at the end of line 5 to control the speed. (Or save 10 characters and make it nearly unplayable by removing the sleep entirely!) Bonus feature: randomly fails to start (when initial piece is generated in snake's location). I needed ~100 chars to work around the lack of a non-blocking getchar. Apparently Ruby 1.9.3 includes a "io/console" library which would have saved roughly half of those. And this solution is Windows specific. There are published solutions to do the same type of thing in *nix systems, but I haven't tested them to compare the character count. Edit: Had to add 18 bytes after I realized that the tail only grows after eating, not after each step. Edit 2: (Possibly) fixed crash issue, saved the 9 bytes by restricting to one food item. • I like the idea of multiple food items at once, however there is a big problem: the tail should move with the player, only growing by one character for every piece of food you collect. Jan 5 '12 at 23:08 • You added the comment while I was working on fixing it... If there is only supposed to be one piece, I can remove the 9.times{}, saving 9 chars. Jan 5 '12 at 23:43 • the only requirement is that there be 1 or more piece of food at a time, so yes you could just make it 1 piece at a time, saving some characters Jan 5 '12 at 23:49 • the game randomly crashed on me at ~140 points, not sure why. but otherwise very nice Jan 6 '12 at 2:32 • Fixed the crash, I think. If it crashes again, please let me know the ruby error message. Jan 28 '12 at 0:47 Python 3 - 644 from curses import * import time from collections import deque from random import randrange as R N,W,S,E=z=119,97,115,100 t=tuple u=0,0 def m(s): a=lambda o,y,x:y.addch(o[0],o[1],x);q=lambda:(R(L-2),R(C-2));L,C=s.getmaxyx();curs_set(0);s.nodelay(1);s.border();s.refresh();r=newwin(L-2,C-2,1,1);n=deque();y,x=[L-2,0];d=N;n.append(u);c=N;p=q();a(p,r,N);a(u,s,48) while 1: if c in z:d=c if d==N:y-=1 if d==S:y+=1 if d==W:x-=1 if d==E:x+=1 l=n.pop() if (y,x) in n:return if (y,x)==p:p=q();a(p,r,N);n.append(l);s.addstr(0,0,str(len(n))) n.appendleft((y,x));a((y,x),r,S);a(l,r,32);r.refresh();time.sleep(.2);c=s.getch() wrapper(m)  Does not quit cleanly. Piece might disappear if it spawns on top of the snake. TI-Basic, 307 bytes This one is very special to me, since I learned to program with a simlar snake game on my TI-83+ (in high school, during boring classes). Also, on these calculators, golfing the programs was a real concern because of the limited space and performance The controls are the direction keys, but they could easily be changed for awsd (although noone would want that since it's an abc layout) codes for the keys would be: A: 41, W: 85, S: 81, D: 51 ClrHome 99→dim(ʟX) ʟX→Y {8,16→dim([A] For(X,1,16 For(Y,1,8 If X=1 or X=16 or Y=1 or Y=16 Then Output(Y,X,": 1→[A](Y,X End:End:End 8→X:7→Y:-1→V Repeat [A](Y,X 1+I(I<99→I Y→ʟY(I X→ʟX(I Output(Y,X,0 1→[A](Y,X If X=N and Y=O or not(N Then Repeat not([A](O,N randInt(2,7→O randInt(2,15→N End Output(0,N,1 Output(1,1,S S+1→S Else 1+J(J<99→J ʟY(J Output(Ans,ʟX(J)," 0→[A](Ans,ʟX(J End getKey→G not(G)U+(G=26)-(G=24→U not(G)V+(G=34)-(G=25→V X+U→X:Y+V→Y End  Bash (too many characters: ca. 1522) t=tput tc="$t cup"
tr="$t rev" ts="$t sgr0"
ox=5
oy=5
((w=$($t cols)-2-2*ox))
((h=$($t lines)-2-2*oy))
trap "$t rmcup stty echo echo 'Thanks for playing snake!' " EXIT$t smcup
$t civis stty -echo clear printf -v hs %$((w+2))s
printf -v v "|%${w}s|"$tc $oy$ox
printf %s ${hs// /_} for((i=1;i<=h+1;++i)); do$tc $((oy+i))$ox
printf %s "$v" done$tc $((oy+h+2))$ox
printf %s ${hs// /¯} dx=0 dy=-1 hx=$((w/2))
hy=$((h-2)) l=2 xa=($hx $hx) ya=($hy $((hy+1)))$tr
for((i=0;i<${#xa[@]};++i)); do$tc $((ya[i]+1+oy))$((xa[i]+1+ox))
printf \
done
$ts print_food() {$tc $((fy+1+oy))$((fx+1+ox))
printf "*"
}
nf() {
rf=1
while((rf))
do
rf=0
((fx=RANDOM%w))
((fy=RANDOM%h))
for ((i=0;i<${#ya[@]};++i)) do if((ya[i]==fy&&xa[i]==fx)) then rf=1 break fi done done print_food } nf ps() { s="SCORE:$l"
$tc$((oy-1)) $((ox+(w-${#s})/2))
printf "$s" } ps while : do read -t 0.2 -s -n1 k if (($?==0))
then
case $k in w|W)((dy==0))&&{ dx=0;dy=-1;};; a|A)((dx==0))&&{ dx=-1;dy=0;};; s|S)((dy==0))&&{ dx=0;dy=1;};; d|D)((dx==0))&&{ dx=1; dy=0;};; q|Q)break;; esac fi ((hx=${xa[0]}+dx))
((hy=${ya[0]}+dy)) if((hx<0||hy<0||hx>w||hy>h)) then go=1 break fi for((i=1;i<${#ya[@]}-1;++i))
do
if((hx==xa[i]&&hy==ya[i]))
then
go=1
break 2
fi
done
$tc$((ya[-1]+1+oy)) $((xa[-1]+1+ox)) printf \$tr
$tc$((hy+1+oy)) $((hx+1+ox)) printf \$ts
if((hx==fx&&hy==fy))
then
((++l))
ps
nf
else
ya=(${ya[@]::${#ya[@]}-1})
xa=(${xa[@]::${#xa[@]}-1})
fi
ya=($hy${ya[@]})
xa=($hx${xa[@]})
done
if((go))
then
\$tc 3 3
echo GAME OVER
fi


Binary - 617 Bytes

Hex:

B80000A36C03A26E03B008A26F03B028A27003A27203A27603A27403B00F
A27103A27303A27503A27703BB0000C6877803204381FBD00775F4BF0000
C6857803FFC685C803C4C685F80AC44783FF5075EBBF0000C685C803B3C6
851704B383C75081FFD00775EDC606C803DAC6061704BFC606F80AC0C606
470BD9E8C601BE0200E8E000A07103A27303A07003A272038A266F0380FC
08740F80FC04741080FC02741180FC017412FF0E7103EB10FF067103EB0A
FF0E7003EB04FF0670038A1E6F03B5008A0E72038A167303E81800E8CF00
E86B00E83500A06E033C00749FE91EFFB44CCD21C3BF7803B050F6E201C8
01C7881DC3BF7803B050F6E201C801C78A1DC38A043C00740346EBF7C3B8
00B88EC0BF7803BE00008A1D80FB08741180FB04740C80FB02740780FB01
7402EB02B3DB26881C4783C60281FEA00F75D9C3BF0000E8BDFFA16C03BF
0D0031D2BB0A00F7F35088D0043088857803584F83F80075E9C3B401CD16
7436B400CD1680FC48741180FC50741380FC4B741580FC4D7417EBE0C606
6F0308EBD9C6066F0304EBD2C6066F0302EBCBC6066F0301EBC4C3B5008A
0E7003B6008A167103E845FF80FB087E0A80FB2A741C80FB2074243C01A2
6E03B301B5008A0E7003B5008A167103E812FFC366FF066C03E8E6FFE863
00EB06E80400E8DBFFC3A07503A27703A07403A27603B5008A0E7403B600
8A167503E8F0FE80FB08741280FB04741380FB02741480FB017415E9C6FE
FF0E7503EB10FF067503EB0AFF0E7403EB04FF067403B320B5008A0E7603
B5008A167703E8A4FEC3B400CD1A89D025FF0FF7E289C289D0B9D00731D2
F7F189D3BF78038A013C2075DFC6012AC3


Create a .com file from the above hex and run it in DOSBox.

For a cleaner graphic, you should run cls before running the .com.

Even though the qualifications says:

Speed of the game doesn't matter, as long as it is consistent

You should use the command cycles 300 if you want the game to be playable