
Show HN: Simple JavaScript Tetris - jstimpfle
https://github.com/jstimpfle/tetris-on-a-plane/
======
jstimpfle
EDIT: Better URL [https://github.com/jstimpfle/tetris-on-a-
plane/](https://github.com/jstimpfle/tetris-on-a-plane/)

I had fun building this and experiencing the joyful side of JS (or at least
the browser ecosystem). Boarding a plane I'd had the idea of finishing a
simple tetris before arrival. The game was in a working state after ~2 hours,
even though I had made a few bad decisions. (it was subsequently polished,
investing another few hours).

It was made with a "get things done" mindset, and the experience from dabbling
with purely functional programming in Haskell was very helpful (mostly the
"pure", as in "non-destructive", part).

It's nice that in Javascript we have an environment where we can code a fun
game in <400 lines, without any library dependencies (not even internet
connection needed) or build systems. On the downside, if it had stronger
dynamic types and errors (like Python) that would have saved maybe 25% of my
debugging time, probably without coding overhead.

~~~
zzguy
Had you made Tetris before? Or used an external resource to see any
pseudocode? Reason I'm asking is, I was doing a similar thing with Snake and
it took me a bit longer (probably 4 hours) because I messed up the basic
mechanics in the beginning (I didn't think of how to structure the growing
body as a linked list). I want to gauge how much I suck (at least at games
programming) lol.

~~~
jstimpfle
I once spoke about it with a friend who had to do it in C. However C is a
dangerous trap here, I think it gets you in the wrong mindset.

Data representation is pretty universally one of the most important things
(basically the "design" part to me). Four hours is pretty quick I guess. Snake
might be more difficult (but an array or llist + snake direction + board map
should be straightforward). I'd done chess that week and the representation is
also doable _unless_ thinking about AI or history or... which is when I
quickly go bikeshedding. Multiple different representations for different
tasks (and transforming in between) might be a way to go.

~~~
pgt
I made Snake in 103 lines of ClojureScript for a talk once:
[https://github.com/pate/cljs-snake](https://github.com/pate/cljs-snake) (LOC
excludes whitespace and links to repo). Comes in under 100 LOC if you strip
out the aesthetics.

~~~
jstimpfle
Very nice!

------
g3
And here is a _concise_ JavaScript tetris (playable:
[http://copy.sh/tetris/](http://copy.sh/tetris/)):

    
    
        f=[];p=[1];g=h=2;s=0;t=500;for(i=0;23>i;i++)f[i]=j=-16380;f[23]=-1;onkeydown=e;e(e);function e(b,a){(k=b.which)?k-38?k&-3^37||(g+=a=k^37?-1:1):(z=p,v=p[2],c=p[1],p=[2*v&2|4*c&4,p[3]/2&1|v&2|2*c&4|4*p[0]&8,p[3]/4&1|v/2&2|c&4|2*p[0]&8,v/4&2|c/2&4]):s-j&&setTimeout(e,100+t,h++);m=p[0]<<g;l=p[1]<<g;_=p[2]<<g;o=p[3]<<g;f[h+=32==k]&m|f[1+h]&l|f[2+h]&_|f[3+h]&o?a?g-=a:k^38?(f[h]|=l,f[--h]|=m,f[2+h]|=_,f[3+h]|=o,h?(g=6,x=new Date%7*4,p=[h=0,2908739>>x&15,266758006>>x&15],t*=.97):s+=" Game Over!"):p=z:k^32||e(b);for(y=_=o="";24>++y;o+="\n")for(f[y]+4||(f.splice(y,1),f.unshift(j),s+=++_,o="",y=2),x=14;x;q.textContent=o+s)o+=" X"[(f[y]|p[y-h]<<g)>>x--&1]}

~~~
geuis
Just because you minify and obfuscate this code doesn't somehow make it better
or let you win the "contest".

I can walk through the submitter's code and understand what's happening
clearly. It's fairly well structured and easy enough to read. This is 20x more
valuable than any code that is produced using uncommented edge features for a
perceived 5% gain. (Note that I'm making up these numbers to illustrate a
point.)

~~~
bronson
Wait, where did the OP say it was better or won some contest?

------
wmichelin
What's going on here? [https://github.com/jstimpfle/tetris-on-a-
plane/blob/master/t...](https://github.com/jstimpfle/tetris-on-a-
plane/blob/master/tetris.js#L93)

~~~
proto-n
[http://stackoverflow.com/questions/1642028/what-is-the-
name-...](http://stackoverflow.com/questions/1642028/what-is-the-name-of-the-
operator-in-c)

~~~
Cpoll
In other words, it's a crappy way to write `i-- > 0`

Note that it's not logically equivalent to `for (var i = 5; i > 0; i--)`
because in this case the `i--` operation is applied after the body of the
loop.

Try it in your browser: for (var i = 5; i-- > 0;) { console.log(i); }
//4,3,2,1 for (var i = 5; i > 0; i--) { console.log(i); } //5,4,3,2,1

~~~
jstimpfle
This is why I actually like this syntax (and get fun out of provoking
"shudder" comments).

    
    
        - Can use the same limits as in ascending iteration
        - Can do decrementing in for loop (no extra line)
        - The arrow unambiguously signals that the iteration is correct :-)

~~~
bbcbasic
!!"It's the JS way"

------
TheBiv
Playable version of this code located here
[http://jstimpfle.de/projects/tetris-on-a-
plane/tetris.html](http://jstimpfle.de/projects/tetris-on-a-plane/tetris.html)

------
jibreel
nice, as a web developer i wanted to try my hands on making a game. which
turned out to be much harder than i thought, and also see if i could do any
thing with c lang, never wrote a program more than ~15 lines of code in c, so
i build a tetris game, using SDL lib.

funny thing is i also represented shapes like you did as 0 or 1 on plane, but
then changed to x,y list of blocks.

here it is.
[https://gist.github.com/spaceexperiment/4d6b116ef577a2971259...](https://gist.github.com/spaceexperiment/4d6b116ef577a29712593c41747bd092)

------
mattnewton
Broken on Safari 10, and I can't figure out why. None of the keyboard keys
seem to fire any events.

~~~
dhritzkiv
It seems the code uses `event.key` (which returns a human-readable string,
e.g. "ArrowLeft"). `event.key` is not supported in WebKit.

~~~
jstimpfle
Thanks to you both. I converted to using ev.keyCode. Hope it works everywhere.

------
nthcolumn
Awesome! I made a fiddle
[https://jsfiddle.net/wt309enw/1/](https://jsfiddle.net/wt309enw/1/)

~~~
pryelluw
This is pretty fun to see on a fiddle. :)

------
skanga
Very nice. Agree with danso that keys should be case insensitive. Also - the
UP arrow should rotate in some (any) direction.

------
tluyben2
Nice, I like writing things under constraint; especially without internet and
manuals. Seems to take away a lot of stress and open up creativity, at least
it does for me [0]. I am flying to AUS soon which will have me without
internet for around 21 hours again and I will try another constraint game at
that time.

[0] [http://brainfisheatfishbrain.com/2015/03/writing-a-game-
with...](http://brainfisheatfishbrain.com/2015/03/writing-a-game-without-
sleep-or-internet-at-jfk.html)

------
jnpatel
I like that that this implementation lets you shift right/left for a split
second after you let the piece fall.

Not all Tetris versions I've seen do that. I'm not sure what official
behavior, though.

~~~
0x0
There's quite a few details about the official authentic tetris guidelines
here, looks like it's probably reverse-engineered.
[https://tetris.wiki/Tetris_Guideline](https://tetris.wiki/Tetris_Guideline)

------
acconrad
I think you could optimize quite a bit of this. If you made your shape objects
more robust, even just {x,y,on}, instead of doing all of those nested for
loops, you could start leveraging array methods like filter to only select the
ones where on === 1, then do some sort of matrix transform to swap out that
x,y coord in the 4x4 with the shape you're replacing.

Either way, cool game! Pretty neat you could do that in sub 400 lines of code.

~~~
jstimpfle
The reason why I'm (sort of) proud of this is exactly that I managed to _not_
get hung up with such considerations and just do the obvious things. It's not
a problem to scan through 200 blocks (of which often 50% will be habitated)
once every 100ms or so).

If there is any need for optimization, then it would probably be to avoid DOM
inefficiencies and opting for canvas or another environment.

------
danso
Very neat. I was about to report a bizarre bug -- `a/d` for rotating pieces
worked on my laptop keyboard but not my USB-connected keyboard -- but then I
realized caps-lock was turned-on my connected keyboard. Still probably
wouldn't hurt to make the conditional case-insensitive

------
etaioinshrdlu
My iteration of the same thing

This one generates a wide array of pieces upon start. And has buttons for use
on mobile

[http://kevinusbaragon.us/jtris/jtris.html](http://kevinusbaragon.us/jtris/jtris.html)

------
hauxir
Here's one i made in Haskell and NCurses [https://github.com/hauxir/haskell-
tetris](https://github.com/hauxir/haskell-tetris)

------
smnscu
Similar, in Python, using rudimentary CLI controls (it was a take-home test).
[https://github.com/andreis/bchw](https://github.com/andreis/bchw)

------
sp332
I think the rotations feel wrong. If I get a Z piece, rotating twice should
get me back where I started. Instead it's shifted sideways one space. I have
to shift 4 times to get back.

~~~
jstimpfle
The scheme used here is a 4x4 block (the minimum required to accomodate all
pieces) and rotations by 90 degrees. You can rotate both cw and ccw, this
works for undoing rotation of _all_ pieces.

------
pryelluw
@OP License?

Can I use it as a teaching tool? :)

~~~
jstimpfle
Sure!

~~~
pryelluw
Thanks. Please add a license file to repo of you haven't done so already. :)

------
Scarbutt
no babel/webpack?

~~~
nkg
XD

