Monday, December 10, 2012

How to deploy node.js applications


I am currently running 5 websites on my free (1 year) Amazon EC2 micro instace. Every one of these urls corresponds to a separate node.js service running on the server:
http://zoggle.zolmeister.com/
http://games.zolmeister.com/
http://avabranch.zolmeister.com/
http://gallery.zolmeister.com/
http://charityvid.org/

Let me preface this by saying that the way I deployed my sites before was the following:
  • ssh myserver@amazonec2
  • screen -ls (to display all the screen instances I had open)
  • screen -r XXXX (guess at which screen was the one running the site I wanted to update)
  • node app.js (launch a server process in the screen, and then Ctrl+a+d to detach from the screen)
This is obviously inefficient and slow, and by the time I got to running 5 websites (and 1 proxy service to direct traffic) I decided I needed a more efficient way of deploying and managing my sites.


Enter upstart, the /sbin/init replacement. Upstart lets you maintain just one config file per site and start and stop it as a service without the need to run everything in a screen. To deploy an app is as simple as copying the myapplication.conf file into /etc/init/ and running "start myapplication". Here is an example of one of my conf files (modified from this site):

 description "CharityVid node server"  
 author   "Zolmeister"  
 stop on shutdown  
 respawn  
 respawn limit 20 5  
 # Max open files are @ 1024 by default. Bit few.  
 limit nofile 32768 32768  
 script  
      echo $$ > /var/run/charityvid.pid  
      export NODE_ENV=production  
      cd /home/pi/websites/charityvid  
      exec /usr/local/bin/up -p 3100 -w app.js 2>&1 >> /var/log/charityvid.log  
 end script  

What this conf file says is that on service start, log the process's pid (in case we need to kill it), set node to production mode, cd into the site directory (this is necessary because of issues with express.js template loading), and finally start the app. Notice that I start the app with the "up" command, and that I am piping 2>&1 (std err to std out) and appending (>>) it to the log file. The "up" command comes from the up node module which does auto-updating and load balancing. The alternative to "up" is node-supervisor which doesn't do load balancing but can be run on any application out of the box (without the modification required by "up").

Ok, so now we have a way to start all of our applications, but how to route all the connections to the right place (remember all our apps are on one server with one IP address). Normally you would use NGINX (pronounced "engine x"), but the stable branch doesn't support websockets (used by http://zoggle.zolmeister.com) so I decided to go with the simple node-http-proxy module. The documentation is a bit lacking, but I was able to get all the sites routed, including websockets support and ssl support (for https://charityvid.org/). Here is what my app.js file looks like for my "gateway" application:

 var http = require('http'),  
      httpProxy = require('http-proxy'),  
      fs = require('fs'),  
   https = require('https'),  
   crypto = require("crypto"),  
   path = require('path');  
 var main1 = httpProxy.createServer({  
  router: {  
   'zoggle.zolmeister.com': 'localhost:3001',  
   'avabranch.zolmeister.com': 'localhost:3005',    
   'charityvid.org': 'localhost:3100'  
  }  
 });  
 main1.listen(8000);  
 var proxy = new httpProxy.HttpProxy({  
  target: {  
   host: 'localhost',  
   port: 8000  
  }  
 });  
 var server = http.createServer(function (req, res) {  
  // Proxy normal HTTP requests  
  proxy.proxyRequest(req, res);  
 });  
 server.on('upgrade', function(req, socket, head) {  
  // Proxy websocket requests too  
  proxy.proxyWebSocketRequest(req, socket, head);  
 });  
 server.listen(80);  
 function getCredentialsContext (cer) {  
  return crypto.createCredentials({  
   key: fs.readFileSync(path.join(__dirname, 'certs', cer + '.key')),  
   cert: fs.readFileSync(path.join(__dirname, 'certs', cer + '.crt'))  
  }).context;  
 }  
 var certs = {  
  "charityvid.org": getCredentialsContext("charityvid")  
 };  
 var options = {  
  https: {  
   SNICallback: function(hostname){  
    return certs[hostname];  
   }  
  },  
  hostnameOnly: true,  
  router: {  
   'charityvid.org': 'localhost:3100'  
  }  
 };  
 // https  
 httpProxy.createServer(options).listen(443);  

After running the routing proxy every site should now be functional and up, but we still have to ssh into the server to start/stop apps and to update them (with supervisor and up you should rarely have to restart the node server). This is where fabric comes in. Fabric lets you automate the ssh process and run commands on the server from your work machine. For example a simple command to send the initial application.conf upstart file would be:
 def installInit():  
      put('avabranch.conf', '/etc/init/avabranch.conf', True)
      sudo('touch /var/log/avabranch.log')  
      sudo('chown admin /var/log/avabranch.log')  

And if you're using git to manage your source (I store mine in a private bitbucket repo), updating your production code is as easy as "fab update:avabranch" with the following fab file declaration:
 def update(app):  
      with cd('/home/admin/websites'):  
           if app=="avabranch":  
                run('cd avabranch && git pull')   

Finally I keep my sites behind the Cloud Flare service, which basically means that they are protected from DDOS attacks, plus get free and efficient localized caching (cloud flare has many data-centers all over the world, which allows them to improve site cache latency times).

Monday, November 19, 2012

Avabranch

Avabranch

Avabranch (source on Github) is my entry for the github gameoff web-game challenge. It's built using Node.js and the Express framework, though most of the code is pure handwritten client-side javascript. I really enjoyed working on avabranch and wanted to take you through what I did to build it.

First of all, since the game uses canvas, we need to figure out how to clear, update, and draw our objects on the canvas. This is where 'requestAnimFrame' comes in. The boilerplate code for this function is this (it adds support for browser-specific implementations because it's not a finalized standard yet):

 window.requestAnimFrame = (function() {  
      return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||  
      function(/* function */callback, /* DOMElement */element) {  
           window.setTimeout(callback, 1000 / 60)  
      }  
 })()  


Before we call this function however, we need to add things that need to be drawn. For me, I add a player, enemy spawner, hud, and powerup spawner to the game object, and then call the update function on the game object.

 function startGame() {  
      keyListeners = []  
      game.play = false  
      game = new Game(canvas)  
      var player = new Player(game, null, null, null, game.speed)  
      var spawner = new BlockSpawner(game, game.speed)  
      var hud = new HUD(game)  
      var power_spawner = new PowerupSpawner(game)  
      game.addObject("spawner", spawner)  
      game.addObject("player", player)  
      game.addObject("power_spawn", power_spawner)  
      game.addObject("hud", hud)  
      game.update()  
 }  

Now, when I call game.update(), it runs this code:
 this.update = function(time) {  
           if (!this.play)  
                return;  
           this.timeDelta = time - this.prevTime  
           this.prevTime = time  
           if (isNaN(this.timeDelta)) {  
                requestAnimFrame(this.update.bind(this))  
                return  
           }  
           this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height)  
           this.physics(this.timeDelta)  
           this.draw()  
           requestAnimFrame(this.update.bind(this))  
      }  

This is where most new developers make a mistake, as they forget the critical 'time' variable that is passed into the function by requestAnimFrame, which is essential for consistent playback across all machines. In order to make sure that a slow machine, unable to run the game at the optimum 60 fps, doesn't end up playing a game that runs half as fast we must keep track of how much time has passed since we last updated the objects on the screen. This is what 'timeDelta' is for, as it keeps track of this time. Now when the Game object calls the 'physics' function on all of its children, it passes in this timeDelta value which is used in the update code for objects that move. For example the 'Line' object uses timeDelta when it updates its position:

 this.points[i].y += .05 * timeDelta * this.ySpeed  

Another thing that is important for gameplay is managing key state and key events. I actually ended up writing my own key event system for this. The basics of how I manage the keyboard are that I store all pressed keys in a JSON object, and on keypress I loop through any listeners that were listening for that keypress and run whatever function they passed in. Here is the code for that (the keys are converted from key number to letter for access in the dictionary):

 var keyListeners = []  
 var keyState = {};  
 var keyMap = {  
      13 : 'enter',  
      37 : 'left',  
      38 : 'up',  
      39 : 'right',  
      40 : 'down',  
      186 : ';'  
 };  
 window.onkeydown = function(e) {  
      try {  
           keyState[keyMap[e.which] || String.fromCharCode(e.which)] = e.which;  
      } catch(e) {  
           console.log('error converting keypress to char code')  
      }  
 }  
 window.onkeyup = function(e) {  
      try {  
           delete keyState[keyMap[e.which] || String.fromCharCode(e.which)];  
      } catch(e) {  
           console.log('error deleting keypress to char code')  
      }  
 }  
 window.onkeypress = function(e) {  
      for (var i = 0; i < keyListeners.length; i++) {  
           var k = keyMap[e.which] || String.fromCharCode(e.which)  
           if (keyListeners[i][0] === k) {  
                e.preventDefault()  
                keyListeners[i][1]();  
           }  
      }  
 }  

The last thing I want to mention is the code that I used to draw the lines. At first my approach was to draw a ton of dots as fast as I could to make it seem linear. This worked but was too CPU intensive, so I decided to try and come up with a better way to do it. I found out that you can draw lines on the canvas easily, and better yet it natively supports rounded caps. The problem was that before when you turned it was smooth, but now the edges were sharp. I tried to solve this by keeping track of the slope of the line, and when the slope changed then I would use the canvas 'quadraticCurveTo' method to round out the corner. This did not work well and so I continued to look for a solution. Turns out that canvas also lets you set the line joint type to round. Yeah, that was quite a journey, but I'm happy I got it working the way I wanted to. Here is the code:

 this.draw = function(ctx) {  
           var tail = this.points[0]  
           var head = this.points[this.points.length-1]  
           if(!tail || !head)  
                return  
           ctx.beginPath();  
           ctx.lineWidth=head.r*2  
           ctx.lineCap='round'  
           ctx.lineJoin='round'  
           ctx.moveTo(tail.x,tail.y);  
           ctx.strokeStyle = tail.color  
           for (var i = 1; i < this.points.length; i++) {  
                var point = this.points[i]  
                ctx.lineTo(point.x,point.y)  
           }  
           ctx.stroke();  
           ctx.closePath()  
      }  

Wednesday, October 24, 2012

Back-light Music LEDs


Cameras don't like taking pictures in the dark.
tl;dr
The LED lamp behind my monitor pulsates with the audio from my computer. Video is at the bottom.
The Code (warning, ugly code ahead)
Setup:
So the way the led lamp works, is that it is hooked up to an arduino which connects over USB to my tower. My computer is running a python script which sends the arduino the value of brightness to set the lamp at, based on the audio output of the music.

PulseAudio -> python -> arduino -> LED lamp

Getting the audio output into python:
This was probably the most silly issue that I had to deal with, because it seemed so simple in terms of what I needed to do, but took a ton of trial and error and lots of failing. Let me save you the trouble. You may have heard of JACK. JACK is a pain, takes a lot of work, and for me it didn't work at all. Save yourself the trouble and stay away from JACK. I use PulseAudio for my sound system as it works  with my USB headphones (they're virtual 7.1 surround sound and have drivers that only work on windows XP). Setting up my headphones is a pain, but worth it because of the fuzz (the part that goes over my ears is fuzzy which makes them extremely comfortable). Ok, enough background, here is the secret:

  • Open Pulse Audio Volume control (pavucontrol).
  • Open Sound Recorder.
  • Start recording, and go to the "Recording" tab of the volume controller
  • Click on the input, and change it to "Monitor of XXX" (where XXX is your audio device)
  • Done! (Just remember to do this for the python script while running it for the first time)
Python and beat detection:
You can check out the code here. Basically it uses the pyaudio library to record audio, write streaming data chunks to a temporary wav file (this could be improved upon), and use some magic to get amplitude data from the wav file. Then it normalizes the amplitude over the 0-255 range of LED brightness for the arduino, smooths the curve slightly, and sends the amplitude over to the arduino at 115200 baud (not sure if this is too much/not enough, but it worked for me - 9600 baud hung because it was too slow).
Beat detection snippet (thanks Mr.Doob and Dean McNamee)
 w = wave.open(WAVE_OUTPUT_FILENAME, 'rb')  
     summ = 0  
     value = 1  
     delta = 1  
     amps = [ ]  
     for i in xrange(0, w.getnframes()):  
       data = struct.unpack('<h', w.readframes(1))  
       summ += (data[0]*data[0]) / 2  
       if (i != 0 and (i % 1470) == 0):  
         value = int(math.sqrt(summ / 1470.0) / 10)  
         amps.append(value - delta)          
         summ = 0  
         tarW=str(amps[0]*1.0/delta/100)    
         sendVal(tarW)#this method normalized the data and sends it to the arduino
         delta = value  

My normalization algorithm for the value consists of storing the last 100 values of data and dividing new data by the max of the last X values (all values before a reset) to get a value between 0 and 1, which I then multiply by 255 to get 0-255. After a period of low values (ie. silence), detected by the store of last 100 values, the minimum and maximum values reset to allow for a new song which may not fit the amplitude of the previous song. I smooth the data by averaging the current point with the previous point.

Arduino LED fading (pwm):
So the arduino UNO that I have has 6 pwm digital I/O pins, which allows me to dim LEDs attached to those pins. After that, just running an analogWrite() on them with a value between 0-255 will dim the LED accordingly. One thing I did have trouble with though was sending the 0-255 number over serial from python, which I fixed by using a buffer and made the python always write out 3 character strings of data and used the atoi() command (ascii to int) to get the values back out.

The lamp:
I hooked up 12 LEDs, 6 pairs of 2 LEDs hooked up in parallel connected to one of six pwm I/O pins. After lots of frustration regarding the illumination of the LEDs (I used a dremel to diffuse the LEDs, and ended up arcing them as shown below), I finally got it to work. I just can't let the arduino fall off because the wires going to it come out easily (design issue, but hey it works).

The result:
(yes I have 5 monitors, song: Bopalong, Kinobe)

Wednesday, September 26, 2012

My Favorite Exploit


XSS (Cross Site Scripting) is my personal favorite security hole. It's everywhere, on almost every site, and it's fun to exploit! I used to spend my evening scouring the top 500 sites on alexa for XSS vulnerabilities just for fun. In addition to that I did most of my testing manually. There are tools built to automate most XSS vulnerability tests, but that's no fun. This hacking spree taught me the foundations of JavaScript and web development in general. By developing intricate tunnel exploit schemes I learned so much about how the web operates at the user level and how bugs enable hackers to get in.

My endeavours got my name here: Google Security Hall Of Fame

Which led me to create this: http://gallery.zolmeister.com/ (click the page)

That page is my XSS gallery. The images are the websites favicons, with size relative to their ranking. I have saved nearly every one of the XSS vulnerabilities I have found by hand, which is now over 200. Most of the sites are ones that were unhelpful or just pissed me off in general and so I took a few minutes to find an XSS vulnerability in them (I almost never report these vulnerabilities). Some however (the big icons) are ones where I started at the top of a list of most popular sites and moved my way down, collecting vulnerabilities along the way. It's pretty scary actually, knowing that even the most high profile sites are vulnerable.

Saturday, September 8, 2012

How not to write a massively multi-player game

Welcome to Page Explorer!

Click here to join! (no longer up)
Click here (again) to join! (yes, bug)
Now hit the CAPS LOCK key (to toggle view state)
After you have joined here are the controls:

  • Ctrl = Jump
  • arrow keys = move
  • Down = Descend a level
  • Ctrl + up = pull up
  • CAPS LOCK = toggle game (visible/hidden)
  • T = chat (just start typing and the text will appear top-left, then enter to submit)
Want to explore somewhere else? Drag this link: Page Explorer to your bookmarks bar, then click on it when your on the site you want to join (may have to click it twice, also chrome blocks it in https pages).

"Wow this is so cool! How can I get the source?" - on github!

Alright, lets break it down!
A few words of warning before I begin, this game is one of my most poorly written and broken games of all. This was a great learning experience in what not to do with a game, and I hope that you will learn something too.

First let me explain how this app works on a general level.
  1. User injects script onto page
  2. script loads all the assets
  3. all assets load
  4. script connects using Socket.io to the master Node.js server
  5. The server puts the user in a room based on the website they're on
  6. users position, name, and animation state are sent to the server
  7. server relays info to all clients in room
  8. GO TO 6
This part actually makes sense, and what makes Page Explorer cool is that you can run it on any page you want. This also happens to be what makes it fail, due to different page layouts of the same site from different users makes them appear to float in mid air and other such bugs which are largely out of my control.

Ok lets start at the beginning of the code (or rather the first part that I wrote and where things wen't horribly wrong). I decided to write a skeletal animation system. Those look like this:
Basically a bunch of nodes connected to each other. This allows me to draw the player once and animate him freely. If you're confused, this video might help: http://www.youtube.com/watch?v=34cBGjCKkgU

The first step in skeletal animation is creating a skeletal map (here is where I messed up). Here is what mine looks like:

The issue here is that everything is absolute positioned instead of being relative to one another. The correct way to do it would have been to use a Polar system (angle, distance) instead of a Cartesian system (x,y).

 var skeleton=[{  
   "name": "root",  
   "rot": 0,  
   "x": 279,  
   "y": 266,  
   "skin": {},  
   "parent": -1,  
   "id": 0,  
   "children": [6, 7, 8]  
 }, {  
   "name": "head",  
   "rot": 0,  
   "x": 282,  
   "y": 150,  
   "skin": {  
     "self": {  
       "name":"head",  
       "x":0,  
       "y":-20  
     },  
     "bone": "neck"  
   },  
   "parent": 6,  
   "id": 1,  
   "children": []  
 },...  

My next step was creating an editor, in order to create everything (ie, draw the bones and connections and add skins etc.). Problem was that I was lazy. I ended up hard-coding the base skeletal system and the animation system involved saving a skeletal state to localstorage when done. There was no "undo" button, and I couldn't edit multiple animations at a time. To get it into my code I copy pasted the giant list of skeletal positions into my source. This is where spending just a bit more time in creating a good editor would have saved me tons of work. (I could post the source for my editor but i'd rather not... it's hideous).

My next mistake was in separating the user (you) from everybody else. I had to duplicate everything (physics, drawing, etc) in my code (that's bad - never duplicate code). This also caused me to keep all of the game code related to the player in one file (main.js - 651 lines) and then duplicate it in another file (socket.js - 173 lines). Yes, main.js should not contain all the code that it does and it was an absolute pain to debug.

My animation sequence seems ok at first, but it is definitely broken. Here is what it looks like:

 function movePlay(){  
   if(playQueue.length<2){  
     playing=false;  
   }  
   else if(sameFrame(playQueue[1],playQueue[0])){  
     playQueue.splice(0,1);  
     updatedQueue();  
   }  
   else{  
     for(var i in playQueue[0]){  
       var curS=playQueue[0][i];  
       var tarS=playQueue[1][i];//have to align within 60 frames  
       var xDistance=curS.x-tarS.x;  
       var yDistance=curS.y-tarS.y;  
       var rotDistance=curS.rot-tarS.rot;  
       var framesLeft=10-currentFrame%10;  
       if(curS.x!=tarS.x)  
         curS.x+=xDistance/framesLeft*-1;  
       if(curS.y!=tarS.y)  
         curS.y+=yDistance/framesLeft*-1;  
       if(curS.rot!=tarS.rot)  
         curS.rot+=rotDistance/framesLeft*-1;  
       if(framesLeft<1){  
         curS.y=tarS.y;  
         curS.x=tarS.x;  
         curS.rot=tarS.rot;  
       }  
     }  
   }  
 }  

The basis for this animation function is that it takes at least 2 frames (states of skeletons) and then motion-tweens them by one step when it's called. The issue (if it wasn't obvious) is that it doesn't support speed-change in tweens. This means that lets say I wanted the player to punch really fast (1 frame fist back, next frame fist forward), it would play really slow because my play-rate (10 steps - var framesLeft=10-currentFrame%10;) is constant. From one frame to the next is always the same amount of time. Instead, it should be set by the editor and be a value in the animation sequence (# steps the animation should take).

Another issue (which I didn't realize till too late) was my abundant use of global variables (maybe my separate var.js file should have given me a hint).

 player.height=500;  
 player.width=500;  
 var playC=player.getContext("2d");  
 var selectedBone;  
 var assetsList=["head", "left arm", "left foot", "left forearm", "left hand",   
 "left leg", "left thigh","neck","right arm","right foot","right forearm",  
 "right hand","right leg","right thigh","spine", "joint","joint2","none",  
 "hat1","hat2","hat3","hat4","hat5","hat6"];  
 var keysPressed=[];  
 var assetCount=0;  
 var assetCallback;  
 var assets={};  
 var playQueue=[];  
 var name=localStorage.name||prompt("name?");  
 localStorage.name=name;  
 var chats=[];  
 var hidden=true;  
 var chatting=false;  
 var currentChat="";  
 var passingThrough=false;  
 var others={};  
 var myHat=Math.floor(Math.random()*6)+1  
 var bgCtx=bgCanvas.getContext("2d");  
 var currentFrame=0;  
 var locked=false;  
 var showBone=false;  
 var jumping=true;  
 var climbing=false;  
 var grav=1;  
 var deltaTime=0;  
 var blocks=[];  
 var lastTimestamp=Date.now();  
 var me={  
   x:0,  
   y:0,  
   width:100,  
   height:100,  
   dir:"right"  
 }  

The solution to this is simple enough. I should have created a Game class which had these values associated with it, as well as separating values that control game state (ie. passingThrough, chatting, hidden etc.) from values controlling player state (jumping, climbing etc.).

Well, I hope that you found something useful in all that I did wrong. Bottom line is Don't Half-Ass Your Code. Do it right from the start (never say "I'll fix it later" or "I'll get back to it eventually" - especially in the beginning).

Cheers!

Tuesday, June 26, 2012

Javascript Golfing



 +

  
What is Javascript Golfing?
Well, Javascript golfing is the process of writing the smallest amount of javascript code to do something awesome. It tests your ability to reduce, reuse, and recycle for the purpose of achieving the tiniest footprint possible. Also, it's fun!
Note: All of these games and more can be found here: Games.Zolmeister.com

First attempt, Snake:
My first attempt at golfing was inspired by MXSnake (back when I didn't even know it was called golfing). Here is my version: tinySnake (686 bytes). Kind of large, not too pretty and nothing really special, except my key events which I think are quite unique.

 onkeydown=function(a){  
 q=a.which-38;  
 q%2?n=0:n=q-1;  
 q%2?e=q:e=0  
 }  

I realized that the key presses should be directly tied to the movement variables of the snake, so I used the keyCode itself to set the movement (I think it could be done even more elegantly, but it's a start).

Second attempt, Pong:
My second attempt at golfing was inspired by an article on hacker-news I read about, where someone made tron in 219 bytes(!). Instead of trying to best them though, I made Pong (451 bytes) instead. (Screen is blank until you hit a key, W and A for p1 movement and UP and DOWN for p2 movement) Sadly I don't have the original non-compressed code, but my technique for compression mimicked the tron game.

Third Attempt, Two Towers:


After feeling good about my pong implementation, I decided I wanted to make something new and original. I settled on a game where the player spawns objects to attack an enemy base. Another constraint I wanted to have was to keep it below 1KB (it's 1008 bytes currently), so that it could be compared to the applications at http://js1k.com (definitely check this out, there are some truly amazing apps people created). This time I did not lose the original non-compressed source:

 //chrome auto-generates accessors for objects with ids  
 <body><canvas id=c width=700></canvas>Buy:  
 <script>  
 C=c.getContext('2d')  
 money=time=level=1//multiple assignments in one statement reduces the use of semicolons  
 upgrade=.99  
 R=Math.random;//assign common functions to variables  
 enemies=[{size:50, x:650, speed:-1/1e99}]//use e for large values (1e3=1000) - saved 1 byte  
 friendlies=[{size:50, x:70, speed:0}]//use unique variable names for easy hand-minification  
 C.fillRect(0,0,c.width,c.height);  
 part1="<button onclick='";  
 part2="</button>"  
 doc=document  
 for(i=3;i<10;i++)  
      doc.write(part1+"buy("+i+")'>$"+i*10+part2);  
 //using ~~ instead of parseInt helps a lot  
 doc.write(" Upgrade: "+part1+"upgradeValue=~~(200/upgrade-200)*10+100;money-upgradeValue<0?i:(upgrade-=.05,money-=upgradeValue);this.innerHTML=upgradeValue'>"+upgrade*100+part2);  
 //keep functions to a minimum (the word function is expensive)  
 //the function below gets removed and the whole thing inserted in an onclick event  
 function buy(n){  
      n=n/upgrade*10  
      money-=n*upgrade;  
      money<0?money+=n:friendlies.push({size:~~(Math.pow(n,2)/250)+5,x:100,speed:60/n});  
 }  
 function animation(){  
      if(R()<.03)//AI code (random is your friend)  
           enemies.push({size:~~(R()*level)+7, x:650, speed:-(level-R())})  
   C.clearRect(0,0,700,300);  
   C.fillText("$"+~~money,9,9)  
   //concat both friendlies and enemies for updating the objects (drawing and moving)  
      g=[].concat(enemies,friendlies)  
      for (i in enemies){  
       for (j in friendlies){  
            //during minification, && and || can usually be replaced by & and | respectively  
        if(friendlies[j].x+friendlies[j].size>=enemies[i].x-enemies[i].size && enemies[i].size>0 && friendlies[j].size>0){  
         --friendlies[j].size<0?friendlies[j].size++:i;  
         enemies[i].size==1?money+=enemies[i].size:i;  
         --enemies[i].size<0?enemies[i].size++:i;  
         enemies[i].x-=enemies[i].speed;  
         friendlies[j].x-=friendlies[j].speed;  
         }  
       }}  
      for (i in g){  
                g[i].x+=g[i].speed  
                //I used negative speed values to differenciate between enemies and friendlies  
                C.fillStyle=g[i].speed<0?'#F10':'#10F';  
                C.save()  
                time+=.01  
                C.translate(g[i].x,150-g[i].size)  
                C.rotate(time*(g[i].speed<0?-1:1))  
                C.font=g[i].size+'pt txt';  
                //thanks http://js1k.com/2010-first/demo/750 for the inspiration to use unicode  
                C.fillText(String.fromCharCode(1161),g[i].size/2,g[i].size/2)  
                C.restore()  
           }  
      //inline if statements are better if doing one action  
      //friendlies[0].size==0?history.go():i;  
      //function are special  
      friendlies[0].size==0&&history.go();  
      //regular ifs are more eficient for more than 1 call  
      if(enemies[0].size==0)friendlies=[friendlies[0]],enemies[0].size=50,level++,money+=500;  
       money+=.25;  
       time+=.1  
 }  
 //put the function inside of quotes in the interval call later to save space  
 setInterval(animation,50)  
 </script>  

Finally, here are some tips for golfing:

Look at other peoples code. They come up with interesting tricks like this one (to remap the canvas calls to have shorter names):
 for($ in C=c.getContext('2d'))C[$[0]+$[6]]=C[$];  
-Source: Bouncing Beholder (This game is crazy-good, worth reading through the source)
Check out this tutorial on stackexchange.
Use a tool like jscrush after you hand-minify your code (and check that closure compiler won't help).
Good Luck!

Saturday, April 14, 2012

Zoggle

Welcome to my guide to Zoggle. Zoggle is not affiliated with Boggle.
Zoggle is available...
On my website Zoggle. (Works on iOS - add to home screen)
On Google+.

How to play:
The objective of the game is to score as many points as possible. Points are scored based on the length of the words.
Length : Points
3,4      = 1
5         = 2
6         = 3
7         = 5
8+       = 11

Words are made by connecting letters Horizontally, Vertically, or Diagonally (illustrated below).


Zoggle is a webapp that takes this game to a whole new level by having all players play at the the same time in the same game in real-time. This creates a whole host of tough problems to solve.

Problem #1, Real-Time Gaming Data In The Browser:
This wasn't actually a problem I had because I already had a solution in mind. The key to solving this problem is to use Node.js (with the Express.js web framework) and Websockets (socket.io), hosted on Amazon EC2.
Problem #2, The Board Solving Algorithm:
The computer generates a random board of letters in a 2-dimensional grid. The next step is to figure out all of the words possible for that given grid. For reference I looked at this page. My solution ended up being slower than the python implementation (200ms vs 80ms), but it was still fast enough to be production worthy.
The basic steps to my algorithm:
1. Reduce the size of the dictionary to only contain words possibly made by the grid. This basically consisted of removing all words that contained a letter not on the board. This took my dictionary from 100k, to ~2k.
2. Flood fill the board grid starting at the the first letter of the dictionary words to see if they can be made. Flood fill works by recursively "filling" adjacent grid cells. All this means is that I make sure that for example the 2nd filled grid cell contains the 2nd letter of the dictionary word, otherwise return.
Flood Fill Graphic:


Here is the code for checking to see if a word can fit on the grid:
function fitWord(x, y, cboard, tarWord, cword) {
  if (x >= boardWidth || x < 0 || y >= boardHeight || y < 0)// out of bounds
    return;
  if (cboard[x][y] == "")// visited space
    return;
  if (tarWord.indexOf(cword) == -1)
    return;
  var board = copyTwoDimentionalArray(cboard);
  var let = board[x][y];
  cword += let;
  if (cword == tarWord) {
    wordFit = true;
    return;
  }
  board[x][y] = "";
  fitWord(x + 1, y + 1, board, tarWord, cword);
  fitWord(x + 1, y - 1, board, tarWord, cword);
  fitWord(x - 1, y + 1, board, tarWord, cword);
  fitWord(x - 1, y - 1, board, tarWord, cword);
  fitWord(x, y + 1, board, tarWord, cword);
  fitWord(x, y - 1, board, tarWord, cword);
  fitWord(x + 1, y, board, tarWord, cword);
  fitWord(x - 1, y, board, tarWord, cword);
  return;
}

Problem #3, Cross-Platform CSS:
Since this is a custom webapp, and did not want to re-code (port) the game to iOS and Android, I had to change CSS to accommodate them. There are ways to do this with CSS only, however I found those ways to be inconsistent and unreliable. Instead I opted to detect via JavaScript.
navigator.userAgent.indexOf("Android") != -1
And then add the required CSS
var mobileCss=document.createElement("link");
  mobileCss.setAttribute("rel","stylesheet");
  mobileCss.setAttribute("href","/stylesheets/mobile.css");
  document.body.appendChild(mobileCss);
So far this has worked reliably for me. I did however achieve separate CSS for portrait mode vs landscape mode via CSS.
@media screen and (orientation:portrait)
@media screen and (orientation:landscape)
Problem #4, Touch detection on Android & iPhone:
Turns out that window.onmousemove doesn't work on mobile devices. Instead I had to use window.ontouchmove and re-write my board highlight detection to use elementFromPoint.
document.addEventListener("touchmove",function(e){
  e.preventDefault();
  var j = document.elementFromPoint(e.touches[0].pageX, e.touches[0].pageY);
    currentWord += j.innerText;
    currentWordUsed.push(j);
    j.parentNode.parentNode.setAttribute("class",
        "tileHighlight");
}, false);

Problem #5, CSS3 on Android:
Android, while it claims to support CSS3 in reality does not. It only supports animation of one property at a time. This can be seen at the end of a Zoggle game, where the game will fade out before it gets moved to the side. This is because it would get all choppy otherwise.
Special Notes:
Socket.io Configuration
io.configure('production', function() {
  io.enable('browser client minification'); // send minified client
  io.enable('browser client etag'); // apply etag caching logic based on version
  io.set('connect timeout',2000);//if connection fails, fall back in 2 seconds
  io.enable('browser client gzip'); // gzip the file
  io.set('log level', 1); // reduce logging
  io.set('transports', [ // enable all transports (optional if you want
              // flashsocket)
  'websocket', 'flashsocket', 'htmlfile', 'xhr-polling', 'jsonp-polling' ]);
});
app.js Caching
var cacheTime = 1000 * 60 * 60 * 1 * 1;// 1 hour
  app.use(express.static(__dirname + '/public', {
    maxAge : cacheTime
  }));

Custom 404
myapp/node_modules/express/node_modules/connect/lib/http.js
It specifies what express is doing with the 404 cases:

res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);
I changed this code to something like this:

res.setHeader('Content-Type', 'text/html');
res.render('errors/404', { title: 'Page not found'});