John Conway's Game of Life in Processing



Checkout the live demo on my Home Page!

I was sitting in a lecture the other day when the lecturers screen saver appeared on the projector. It immediately drew all of our attention as it was a live simulation of John Conway’s Game of Life. I had read and watched videos about this topic before and it is quite an interesting simulation. It acts as a model for population evolves over time and given the right inputs (or not!) it can produce some fascinating results for such a simple concept. I first heard about it from the same place I hear most of the interesting facts about the world, from Mr Michael Stevens aka Vsauce. If you haven’t heard of Vsauce you should definitely check out his YouTube channel. He makes extremely interesting videos on a huge variety of topics ranging from science and math to philosophy and psychology and his content is pretty widely accepted as some of the best on YouTube in that space.

Here is a quick snippet from the video where he mentions it (~90 seconds and it should start from the right point!)



So just to reiterate what Michael said (or for those who didn’t feel like watching), the simulation contains a grid of cells which are either alive (lit up) or dead (dark) at any point in time. The interesting part comes from the rules which are applied to this grid of cells which govern how the cells survive, are killed and are reborn. The most common ruleset is the following:

  1. Any live cell with fewer than two live neighbours dies, as if caused by underpopulation.
  2. Any live cell with more than three live neighbours dies, as if by overpopulation.
  3. Any live cell with two or three live neighbours lives on to the next generation.
  4. Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.

With those four simple rules, some really interesting patterns and phenomena occur such as oscilators and spaceships which can traverse the grid! This article is just to show a simple implementation of The Game of Life in Processing that I wrote on a hungover lazy Sunday afternoon and won’t be exploring any of the outcomes in any great detail, but you can find a bunch more info from people who know a whole lot more about it than I do right here!

The Processing Code

The first thing I did was decide on the data structure I would use to represent the grid. The name pretty much gives the game away as a grid is basically a synonym for a matrix or 2D array. Next I declared some constans and global variables which would be useful later on. The only one of note here for now is SQUARE_SIZE which will be the number of pixels each cell will be, the rest are self-explanatory or will be explained later (you decide!).

1
2
3
4
5
6
7
8
9
final int SQUARE_SIZE = 10;
final float GRID_SEED_THRESHOLD = 0.8;
final boolean DRAW_UI_INFO = false;
int numRows, numCols;
Cell[][] grid;
boolean settingUp = true;
int generation = 0;
int numberAlive = 0;

Next the good old void setup(). Here we define the size of our canvas, do some initialization and figure out the number of rows and columns of cells we can have. I was lazy and purposely set my SQUARE_SIZE = 10 as I knew the size of my canvas would be a multiple of 10 meaning I wouldn’t have any remainder pixels.

1
2
3
4
5
6
7
void setup() {
size(900, 600);
numRows = width/SQUARE_SIZE;
numCols = height/SQUARE_SIZE;
grid = initGrid();
generateRandomGrid();
}

The initGrid() function just creates instances of a Cell class (which will be created later) and slots them into a 2D array to act as our grid.

1
2
3
4
5
6
7
8
9
10
Cell[][] initGrid() {
Cell[][] grid = new Cell[numRows][numCols];
for (int i=0; i<numRows; i++ ) {
for (int j=0; j<numCols; j++) {
grid[i][j] = new Cell();
}
}
return grid;
}

The other function here is generateRandomGrid(). This just iterates over our global grid and randomly populates some cells with living cells. This is handy for just creating a random grid to run in order to observe the simulation.

1
2
3
4
5
6
7
8
9
10
11
12
void generateRandomGrid() {
for (int i=0; i<numRows; i++) {
for (int j=0; j<numCols; j++) {
float r = random(1);
if (r > GRID_SEED_THRESHOLD) {
grid[i][j].alive = true;
} else {
grid[i][j].alive = false;
}
}
}
}

Next up is the other good old - void draw(). This is split in two by an if statement which tests the settingUp boolean we defined earlier. In setup mode, you can bring cells to life by left clicking and kill off cells by right clicking by making calls on the Cell objects themselves (these will be shown later). This requires a method to convert the mouse click coordinates into row and column indices into the grid and this is done using the getIndex(mouseX, mouseY) function. Finally in setup mode, we check for some key strokes 's' and 'g' and respond to them by starting the simulation and regenerating a new random board respectively.

The other half (in running mode), simply applys Conway’s rules to the current board by calling applyRules() and checks if the 'r' key has been preset, which initiates a reset of the board through reset().

Finally for both settingUp and !settingUp (simulating), we make a call to drawGrid() which simply draws grid full of living cells.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void draw() {
if (settingUp) {
frameRate(30);
int[] coords = getIndex(mouseX, mouseY);
int i = coords[0];
int j = coords[1];
if (mousePressed) {
if (mouseButton == LEFT) {
grid[i][j].create();
} else {
grid[i][j].kill();
}
}
if (keyPressed) {
if (key == 's') {
settingUp = false;
} else if (key =='g') {
generateRandomGrid();
}
}
} else {
frameRate(15);
applyRules();
if (keyPressed && key == 'r') {
reset();
}
}
drawGrid();
}

You may have have noticed the calls to frameRate(30) and frameRate(15). These (obviously) adjust the frame rate and are are used to slow the simulation down a bit so that we can better see whats going on with how the cells are interacting.

The bodies of the methods mentioned above are given below.

getIndex(mouseX, mouseY)

This returns valid indices into the grid. This actually caused some problems as clicking and dragging the mouse off the canvas actually caused processing to pass me coordinates that were out of range of the canvas (ie coordinates < 0 or coordinates > canvas height etc). A simple bit of logic can be used to combat this however. Taking x as an example coordinate we can:

  1. int largerThanZero = max(x, 0) - This ensures that x is non-negative
  2. min(largerThanZero, width-1) - This ensures that x is not larger than the size of the canvas.

Now that we have cleaned x and y coordinates, we can use integer division to get the nearest cell in our grid and return those as the indices.

1
2
3
4
5
6
int[] getIndex(int x, int y) {
int[] cleanedCoords = {min(max(x, 0), width-1), min(max(y, 0), height-1) - 1};
cleanedCoords[0] = cleanedCoords[0] / SQUARE_SIZE;
cleanedCoords[1] = cleanedCoords[1] / SQUARE_SIZE;
return cleanedCoords;
}

applyRules()

This is where the interesting logic of the simulation comes in. The rules were given above but here is a quick refresher in some weird pseudo-peseudoish-code:

  1. (<2 neighbours) = DIE
  2. (>3 neighbours) = DIE.
  3. (2 <= neighbours <= 3) && currentlyAlive = LIVE
  4. (neighbours == 3) && currentlyDead = REBIRTH

A key concept here is that rules apply to all of the cells in the grid for a given generation simultaenously. That is, you can’t update the board as you iterate over it checking the cells of the current generation. We need a snapshot of the board in its current state to compare each cell against. Or more simply, we create a new board on each generation, fill that board based on the previous generation rather than updating the old board.

This function then is rather simple. We create our new grid using initGrid() and iterate over the board. For each cell, we check how many neighbours it has using the (yet to be defined) getNumberOfNeigbours(rowIndex, columnIndex) function, apply Conway’s rules to that cell and figure out if it should be alive or dead in the next grid and update our new grid accordingly! Again we use some Cell instance methods kill(), create()(bring back to life) and age() that cell. Ageing has no effect on the simulation but is just used to set the colour of the cell in order to get a visual representation of how long a given cell has been around for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void applyRules() {
// Create our NEW grid for the next generation
Cell[][] nextGrid = initGrid();
// This is just used to show the user how many cells are currently living
numberAlive = 0;
for (int i=0; i<numRows; i++) {
for (int j=0; j<numCols; j++) {
int numNeighbours = getNumberOfNeighbours(i, j);
if (numNeighbours < 2 || numNeighbours > 3) {
nextGrid[i][j].kill();
} else {
// Two or three neighbours
if (!grid[i][j].alive && numNeighbours == 3) {
nextGrid[i][j].create();
numberAlive ++;
} else {
// Alive with two or 3 neighbours
Cell oldCell = grid[i][j];
oldCell.age();
nextGrid[i][j] = oldCell;
}
}
}
}
grid = nextGrid;
}

And of course the getNumberOfNeighbours(row, column) function will return the number of neighbours the cell at that position has. For the general case each cell has 8 possible neighbours - 3 above it, 2 on either side of it and 3 below it. However (literal) edge cases exist for cells that are on the border.

To handle these we can define the max and min allowed values for the row an column, and iterate from rowMin to rowMax and inside that iterate from colMin to colMax. In the general case where r and c are the cell in questions row and column:

  • rowMin = r-1
  • rowMax = r+1
  • colMin = c-1
  • colMax = c+1

However we apply the same trick of maximizing any potentially negative rows/cols with 0 and minimizing any rows/cols that can be greater than the grid dimensions with the numRows and numCols respectively.

Finally we can iterate over the 9 adjacent cells, and perform one last check that we aren’t at the row and column that corresponds to ourselves (as we don’t want to count ourselves!).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int getNumberOfNeighbours(int r, int c) {
int numberOfNeighbours = 0;
int rowMin = max(r-1, 0);
int rowMax = min(r+1, numRows-1);
int colMin = max(c-1, 0);
int colMax = min(c+1, numCols-1);
for (int row = rowMin; row <= rowMax; row++) {
for (int col = colMin; col <= colMax; col++) {
if (row != r || col != c) {
if (grid[row][col].alive) {
numberOfNeighbours ++;
}
}
}
}
return numberOfNeighbours;
}

drawGrid()

Finally after all that work it’s time to draw something to the screen. This part is easy, just iterate over the grid and call cell.drawCell(row, column) on each cell in the grid and they will handle drawing themsevles. The only other things in this method are clearing the prevously drawn cells by redrawing a black backgroun with background(0) and (conditionally) drawing an overlay containing some info about the simulation (how many are currently alive / generation number etc).

1
2
3
4
5
6
7
8
9
10
11
12
void drawGrid() {
background(0);
for (int i=0; i<numRows; i++) {
for (int j=0; j<numCols; j++) {
grid[i][j].drawCell(i,j);
}
}
if(DRAW_UI_INFO) {
drawUI();
}
}

reset()

The last function we need is one to reset the board and it is pretty self explanatory - it puts us back in setup mode, recreates a fresh grid and reinitializes the generation and number of alive cells to 0. In Java, we can rest assured that garbage collection will handle freeing up our now out of scope old grid.

1
2
3
4
5
6
void reset() {
settingUp = true;
grid = initGrid();
generation = 0;
numberAlive = 0;
}

The Cell Class

Almost there, just a super basic class to represent our Cells. The only interesting thing about this Cell class is the concept of “colour-aging”. As discussed, I thought it would be nice to have some visual feedback on how long a certain cell had been around for. So the cells start out with a blue value of 255 (fully blue) and a red value of 0 (no red). On each tick a cell survives, we remove COLOUR_STEP from it’s blue value and add COLOUR_STEP to it’s red value. This allows the colour of the cells to change over time based on how many generations they have been alive for.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
boolean alive;
int red;
int blue;
// This controls how fast the cells "colour-age"
final static int COLOUR_STEP = 2;
Cell() {
alive = false;
red = 0;
blue = 255;
}
// Draws the cell with the appropriate "colour-age" at the appropriate position
void drawCell(int row, int col) {
if (alive) {
int x = row*SQUARE_SIZE;
int y = col*SQUARE_SIZE;
fill(red, 0, blue);
rect(x, y, SQUARE_SIZE, SQUARE_SIZE);
}
}
// Kill off the cell and set its "colour-age" back to fully blue
void kill() {
this.alive = false;
this.red = 0;
this.blue = 255;
}
// Bring the cell back to life
void create() {
this.alive = true;
}
// Age the cell from blue to red for each tick they survive.
void age() {
if (blue > 20) {
this.blue -= COLOUR_STEP;
}
if (red < 255) {
this.red += COLOUR_STEP;
}
}
}

Give it a go!

That’s it! Now we have our own Conway’s Game of Life. I’m sure this is nothing new and that there is a tonne of them already written in Processing, but I just decided to write my own for fun! Only after I built it in Processing did I realise I could use processing.js to run it in a browser!

Feel free to play around with the simulator on my homepage.
Thanks for reading!

WebSocket Chat Room

Websocket Chat Room
So I was just about to board my flight to Amsterdam when we were informed that the flight was to be delayed by three hours (guess what airline I was flying with..). I started thinking of things to do to kill the time, but had decided not to bring my laptop with me. Fortunately however I have my router port forwarded so I have ssh access to my Raspberry Pi (which I leave on 24/7 since it uses a whole 1.2 Watts) from anywhere I have an internet connection. So I pulled out my phone and fired up JuiceSSH and started thinking what I could do..

What Are WebSockets?

I had done some socket programming before (mainly writing a simple HTTP/HTTPS Proxy Server in Java - GitHub Repo) but I had heard the buzz word WebSockets being thrown around a lot lately so I decided to check it out. I had a rough idea of what to expect but a quick google gave me a nice succint description:

“WebSockets represent a long awaited evolution in client/server web technology. They allow a long-held single TCP socket connection to be established between the client and server which allows for bi-directional, full duplex, messages to be instantly distributed with little overhead resulting in a very low latency connection.” - from pusher.com

The first things that come to mind when reading that description are real-time applications such as video games and chat. Since I only had two hours (and was developing over SSH on my phone), I decided on the latter. Another quick google search provided a great blog post on setting up a simple chat server with WebSockets.

Getting the Required Tools

The first thing to do was to obtain a WebSocket library for node. There are a bunch of WebSocket implementations and im sure most are great, but the I went for was websocket-node. The first thing to do was to make a directory to hold my project. As I knew there would be server side and client side code, I made two seperate directories - public for client side code and server for server side code.

A quick note here - as we need to serve up the client side code (through a browser in my case), we need some extra functionality to do this for us. As I am a web developer I already had the LAMP stack set up on my machines at home (this is a great article on how to set this up if you haven’t already). The LAMP stack is an extremely common and easy way to serve up static websites and is most likely what was used if you have ever paid for web hosting. Another great option if you would like to stick with Node is Express. I probably would have went with this had I not already had a way to serve web pages set up.

I set up a new virtual host for my WebSocket chat server (see here) and proceeded to create the directories to hold my chat server.

1
2
# Note you may need sudo here depending on how you have set up your permissions
$ mkdir /var/www/websockets/public /var/www/websockets/server -p

The -p flag for mkdir is a handy one which will create any directories that do not exist along the way, saving you from typing multiple mkdir commands.

Next I created a package.json file in my server directory (as this will be written in node, but the client side code will not).

1
2
$ cd /var/www/websockets/server
$ npm init

Follow along in the initialization process to create your package.json file (although what you actually type has little importance). Finally install websocket-node using the following:

1
2
# Again, either use sudo, or chown the websockets directory
$ npm install websocket --save

Creating the WebSocket Chat Server

Server Side Code

Finally it was time to write some code. I decided to work on the server side code first. The first step is to set up a standard Node HTTP server.

1
2
var http = require('http');
var server = http.createServer(function (request, response) {});

Next we need to specify a free port on which the server can listen. I picked 3000 as I had already portforwarded that port to my Raspberry Pi on my router. Portforwarding allows your router to forward incoming packets at the specified port, to a specified machine on your local network. It looks something like this:

http://<Router’s IP>:3000 —> Router —> Server on Raspberry Pi Listening on port 3000

Since I had port forwarded port 3000 to point to my Raspberry Pi, the router then forwards those packets onto my Raspberry Pi allowing my server to be connected to from outside of my local network.

So telling our HTTP server to listen on port 3000:

1
2
3
server.listen(3000, function () {
console.log('Server is listening on port 3000');
});

Next we can create a WebSocket Server and connect it up to our HTTP server by passing the HTTP server to the constructor. This WebSocket is what gives us our long held client-server connection, as opposed to standard HTTP which requires a fresh HTTP request everytime we wish to update.

1
2
var WebSocketServer = require('websocket').server;
wsServer = new WebSocketServer({ httpServer: server });

Next we need some way of keeping track of our clients and the messages that have been sent. As I was just doing this for fun I didn’t implement anything fancy for storing the messages (no not even file IO - but I was doing this from my phone after all…). I ended up just storing the messages in an array which obviously isn’t a good idea, but it works in the short term.

So we need three variables, one to use as clients IDs, a Map to hold our clients which can be indexed by the ID and an array of sent messages.

1
2
3
var id = 0;
var clients = new Map();
var messages = [];

Next we define the callback to executed when a client attempts to connect to the server. Upon receiving a request, we have the option to accept or reject the client. All are welcome on my chat server so I just accepted any incoming connections. I assign the new client the next ID and increment the ID so it’s ready for the next client, add the client to our clients Map and log out a small message to the terminal so we can see when clients have joined. Finally we will send all the old messages to the newly connected client. Note that the sendUTF method obviously only works with strings, but since were using JSON, a simple JSON.stringify() takes care of that and the data can be recovered using JSON.parse() on the other side.

1
2
3
4
5
6
7
8
9
10
11
12
wsServer.on('request', function (request) {
// Envoked when client connects, send them all previous messages
var connection = request.accept('echo-protocol', request.origin);
connection.id = id++;
clients.set(id, connection);
console.log((new Date()) + ' Connection accepted [' + connection.id + ']');
// Send old messages to client
connection.sendUTF(JSON.stringify(messages));
// More code to go here soon..
});

Finally we need to define a couple more callbacks for when a client sends a message (or rather, when the server receives a message) and when the client disconnects. WebSockets make this really simple with the on('message', callback) and on('close', callback) respectively. Upon (the server) receiving a message, we want to save the message and broadcast that message to all connected clients. Ideally, we wouldn’t send this back to client who sent it and just update the sender’s client side messages, but as this was just a quick implementation, I went with the simpler route of just having the message broadcast to and picked up by all clients (including the sender).

Finally when a client disconnects, we free up the resources they were using and remove them from our clients Map so that we don’t try to send any more messages to that connection. This is why we used a Map, so that the client with the appropriate ID can be deleted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
wsServer.on('request', function (request) {
// ....Previous code
// Envoked when a message is sent
connection.on('message', function (message) {
var msgString = message.utf8Data;
messages.push(msgString);
sendToAllClients(msgString);
});
// Envoked when client disconnects
connection.on('close', function (reasonCode, description) {
clients.delete(connection.id);
console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
});
});

The last thing to do on the server side code is to define our sendToAllClients(message) function. Since we have a Map containing all of our clients and a function sendUTF(message) to send a message to a client, this is really simple.

1
2
3
4
5
6
// Note this is outside of the on request received function body
function sendToAllClients(message) {
clients.forEach(function(client) {
client.sendUTF(message);
});
}

Client Side Code

Now that the server is all set up its time to create the web page for the chat room. I wrote this using basic HTML, CSS, Bootstrap and jQuery. First head back to the root of our project, cd into our public folder and make two files - index.html and script.js.

1
2
cd /var/www/websockets/public
touch index.html script.js

I started out with the markup to create the interface. It consists of two <form>s (one for signing up for the chat room and one for sending messages) and a <ul> to which we will programatically add <li>s as we receive messages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<div class="container-fluid">
<h1 class="text-center">The Worlds Worst Chat Room </h1>
<hr>
<h2>Join The Chat Room</h2>
<form id="join">
<input required placeholder="Enter your name" id="name" name="name" />
<input required placeholder="Avatar URL" id="avatar" name="avatar" />
<button class="btn btn-primary" type="submit" name="join_button" id="join_button">Join</button>
</form>
<h1>Chat</h1>
<div id="chat-div">
<ul id="chatlog"></ul>
</div>
<form id="send">
<textarea rows="4" cols="50" required disabled name="message" id="message" placeholder="Send a message"></textarea>
<button class="btn btn-danger disabled" type="submit" id="send-button">Send!</button>
</form>
</div>

Finally I added some styling, grabbed CDNs for Bootstrap and jQuery and included our script.js file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"/>
<script src="script.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
#chat-div {
border: solid black 1px;
height:350px;
overflow:auto;
-webkit-box-shadow: 5px 5px 34px -10px rgba(0,0,0,0.75);
-moz-box-shadow: 5px 5px 34px -10px rgba(0,0,0,0.75);
box-shadow: 5px 5px 34px -10px rgba(0,0,0,0.75);
}
#chatlog {
list-style-type:none;
}
hr {
margin-top: 5px;
margin-bottom: 5px;
}
h4 {
display: inline
}
#avatar-pic {
width: 50px;
border-radius: 50%;
border: solid rgba(0,0,0,0.6) 1px;
margin: 5px;
}
#date-string {
text-align: right;
float:right;
}
#message-li {
padding:5px 0px 5px 0px
}
</style>

The last thing we have to do is to connect up our client side code to our server and set up some logic in jQuery to handle the client joining the chat room and sending messages. Once the client submits the join form, we will save their inputted credentials and connect to the server. This is really easy with WebSockets, simply create a new WebSocket instance that points to our server.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Ensure document is defined (page is fully loaded)
$(document).ready(function () {
var ws;
var name, avatar;
// Allow the client to join the server
$("#join").submit(function( event ) {
event.preventDefault();
// Save credentials
name = $("#name").val();
avatar = $("#avatar").val();
// Connnect to Server
ws = new WebSocket('ws://<server>:<port>', 'echo-protocol');
// More code to go here..
});
});

We need to define a couple of callbacks in order to get the functionality we want. onopen allows us to define a callback function that will be executed when we successfully connect to the server. I wanted to announce when a new client joined the chatroom, so in the body of the onopen callback I created a new message object and sent that off to the server. I also enabled the <textarea> field which is used for inputing the user’s message and the submit <button> which is used for sending the message. Until this point they were both disabled as I didn’t want users attempting to send messages prior to connecting to the server.

We also need an event listener to handle receiving messages from the server. Once messages are received from the server, we want to create <li>s to hold the new messages. For clarity we will define this function later, so the callback just needs to call this function for each new message that is received (or array of messages in the case of the server sending the array of past messages when the client connects).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$("#join").submit(function( event ) {
// ...Previous code
// Send "client" joined chatroom messgae
ws.onopen = function() {
var message = {
name: name,
avatar: avatar,
message: "joined the chatroom.",
date: new Date()
}
ws.send(JSON.stringify(message));
// Allow client to send messages
$("#message").prop('disabled', false);
$("#send-button").removeClass("disabled btn-danger").addClass("btn-success");
};
// Add Listener for receiving messages
ws.addEventListener("message", function (e) {
var msg = JSON.parse(e.data);
// Server sends an array of passed messages to client upon joining
if(Array.isArray(msg)) {
msg.forEach(function (message) {
addMessage(JSON.parse(message));
});
} else {
addMessage(msg);
}
// Scroll to bottom of chat div to keep up with current messages
$('#chat-div').scrollTop($('#chat-div')[0].scrollHeight);
});
});

Next we need a listener for sending messages to the server. This callback simply creates a message obejct, sends it on to the server and and clears the message <textarea> in preperation for the next message.

Finally we define the addMessage(message) function. We make use of jQuery’s append(markup) method in order to append a list item to the unordered list which holds our messages. Theres some extra bits and pieces in the markup to display the sender’s name, avatar and the timestamp.

// Add listener for sending messages
$("#send").submit(function( event ) {
    event.preventDefault();

    // Package up the message object
    var message = {
        name: name,
        avatar: avatar,
        message: $("#message").val(),
        date: new Date()
    }

    // Clear the message input field once the message has been sent 
    $("#message").val('');

    // Send the message object (serialized as a string)
    ws.send(JSON.stringify(message));
});  

// Some markup for the messages
function addMessage(message) {
    $("#chatlog").append('<li id="message-li">'
        + '<div><img id="avatar-pic" src="'
        + "  " + message.avatar + '">' 
        + "<h4>" + message.name + "</h4>"
        + '<p id="date-string">' + new Date(message.date).toLocaleTimeString() + "</p></div>" 
        + message.message 
        + "<hr>"   
        + "</li>"
    );
}

Conclusion

And with that we’re all set. Run the server code with node server/index.js from the root of our project directory and browse to your IP address (or localhost if you’re developing locally) and give it a go!

The full source code is available here on GitHub. Thanks for reading.

Octagonal Patio Table

The Finished Table
So back at the start of summer just as I was finishing my exams, I was snooping around my house looking for something that was old / damaged that I knew would be annoying my Mum. After about a month straight of studying (and writing way more ARM Assembly than one should ever have to) I really wanted to build something. Also at this point I had spent all my money on tools and hadn’t yet built anything with them (hence me looking for a project that my mum would fund be interested in), so was feeling a bit dumb at this stage.

I finally looked out the back and realised our patio table was pretty destroyed after sitting out in Irish weather for about 8 years.

Gross Old Patio Table

So I decided that this would be a fun big project and one that would be quite useful for the summer. My family suggested refinishing it which I quickly rejected due to all that sanding (and besides the wood was starting to rot anyway) and decided to build a new one.

Steve Ramsey’s Octagonal Patio Table

Luckily for me tonnes of people have posted videos about every topic conceivable on YouTube, so I started there. I came accross a Steve Ramsey video (who by the way is a great You Tuber who makes woodworking accessible for everyone) and decided to go for his cool octagonal patio table design.

The first thing I did was figure out how to make an octagon which is pretty easy:

360 degrees / 8 sides = 45 degrees / 2 cuts join together = 22.5 degrees

This means that each segment of the octagon needs a 22.5 degree mitre on both ends, so that when two adjacent segments are joined together the resulting angle is 45 degrees. Im really bad at visualizing things (as was confirmed in every aptitude test I’ve ever taken - probably why Im a computer engineer..) so I had to make a little mini test octagon, but I also didnt want to cut 8 pieces to make a test octagon so I cut two pieces. I could then place the two down and trace them with chalk, move one piece to act as the next segment, trace the newly added piece and repeat. This traced me out a nice octagon so I was happy that my angles / mitre setup was correct.

I went ahead and cut 8 pieces (at 90 degreees) to the long dimension. Once I knew these were all the same, I could set up my mitre gauge to make a 22.5 degree cut and cut each piece such that the long side wouldn’t be shortened at all, resulting in 8 pieces with the same long side length and same angle - so 8 identical pieces. I laid the 8 pieces out and I had a pretty nice fitting octagon!

The Octagon and " Chalk Test for Idiots™ "

I cut a rabbet on the insde of all 8 pieces to accept the 4x1 pieces that would make up the actual table top, glued and pocket screwed all the 8 pieces together and had a solid octagon!

I then got to work cutting and fitting the 4x1s to span the width of the octagon and make up the table top. Most of these cuts were simple 90 or 45 degree cuts but four of them (one on each of the ends of two of the pieces) were a little messier as part of the cut had to be 90 degrees and the other part 45 degrees. This wasn’t too bad though, I just cut them square at their full length and then snook up (reallllyy slowly) on the 45 degree cut until the piece slotted in. This makes more sense with a picture.

Partial 45 degree cut

The Legs

I followed Steve Ramsey’s plans again here and attached the legs together using two cross pieces joined using half laps. I pocket screwed the bottom cross braces into the legs from underneath so they were out of sight. However for the top cross brace, I cut a rabbet onto each of the four ends of the cross so that the octagon could sit on top of the rabbet. This meant the top was now connected to the upper cross piece and I finally connected this assembly to each of the four legs with screws through the front of the legs and capped them with dowels so they wouldn’t be noticable (which you just see at the top of the leg in the following image).

The (almost) Assembled Table

And yes I ran out of 4x1 at this point so had to wait till the next day to put in the final pieces.
One thing that irritates me about this table is the last pieces of the table top being really skinny - you can see the slot for the last piece of the top on the left in the previous picture.

The Finished Table

All that was left to do was to apply a finish. I really liked the ‘whiteness’ (or lack of yellowness) of unfinished pine and have had projects in past look awful due to how yellow the pine went after varnishing. Luckily I found this Ronseal Outdoor Varnish that apparently “doesn’t yellow like traditional varnish” and after applying 4 coats was happy it with how little it yellowed. To be honest it could have used a few more coats but I was so sick of varnishing that I decided I’d rather build a new patio table next year than do any more varnishing.

The Finished Table

The Underside