Tag Archives: MySQL

Update: Trigger game

In recent weeks I’ve been working a lot on the Trigger game (Live page.) These update have included an overhaul of the style, addition of new pages, rewriting of the “Spy mode”, adding new particles, tweaking the graphics, and many more changes behind the scenes. The code was significantly refactored to make it easier to extend and understand, as now this has becomes a collaborative project. The game has been tested on a few schools and shown to be a good success with children (and adults) and it seems to have a bright future. I also added sounds, music, and a simple music player.

Screenshots

Updated event display
Updated event display
Showing the various modes (some in development) with a garish colour scheme.
Showing the various modes (some in development) with a garish colour scheme.
Updated Spy mode, analysing the data.
Updated Spy mode, analysing the data.

Work in progress: Trigger game

Like the Science Shift Simulator, this is a game that emerged as a subset of the aDetector project. The player has to save events that match the criteria given, just like a trigger does in real life. The results are then combined across all the players in a given team to determine the final score. The scores can be combined across experiments to make a “discovery”. This is still in development, which will continue over the net week and months.

Links

Live page
Spy page
GitHub repository

Overview

This is another cooperative multiplayer game aimed at showing the public (especially high school pupils) how particle physics research actually takes place. Any number of players can take part and they are split into “Team ATLAS” and “Team CMS”. The score of each team is determined by the performance of the players on each “shift” they take at the trigger, and the final scores are combined for the discovery of the Higgs boson. There is also a “spy” mode where people can see the events as they are submitted.

Challenges

Challenge: This project needs an attractive, fast, and realistic detector model.
Solution: Having already developed a decent detector model for the aDetector project, I simply used a two dimensional version for this project. I then split the detector finely in \(\eta\) and \(\phi\) to make interactions between the particles and detector easier. The aesthetics went through a few iterations before settling on the final design. However further optimisations and aesthetic changes are anticipated as development continues. (Resolved, to be revisited.)
Challenge: This game puts a bit of a strain on my server.
Solution: My web space uses a shared server, so sometimes many HTTP requests from the same client looks like a Denial Of Service (DOS) attack, resulting in a throttling of the requests. There are two main strategies to overcome this. The first option is to bundle up several requests into one request, reducing the total number of requests, and the load on the server. This solution has not been implemented yet. The second option is to change the server settings. I do not have access to these, but as development continues I intend to move to a different server that can handle so many very small requests. (To be revisited.)
Challenge: This game needs cross platform and cross device support.
Solution: This game was initially intended to be played with an iPad, but I did not have an iPad for testing. On the day of the release of the game I had to tweak the settings so the response times were slower with respect to mouse events to make it easier to play on a tablet device. These settings are trivially changed to allow multiple device support. (Resolved.)
Challenge: The game should be repsonsive to the inputs of the user.
Solution: Initially the game did not confirm success when a user clicked on the screen and this lead to confusion. As a result I had to add a big green “tick” for success and a big red “cross” for failure to inform the user of the status of the event. (Resolved.)
Challenge: The game needed an animated histogram for the final result.
Solution: I’ve made histogras before, including histograms that update themselves on the aDetector project, but until now I had not animated a histogram. This was a bit tricky as I had to call events which were using the this keyword, so the histogram object had to be stored as a global variable because, although I’d like to, I couldn’t use this to refer to the histgoram. Javascript can be frustating like that. (Resolved.)

Screenshots

I don’t normally put lots of screenshots up, but I’m quite proud of the asethetics here, so here are the three main screens of the main game:

The front page of the game.
The front page of the game.
The transition page of the game.
The transition page of the game.
The game in progress.
The game in progress.

The design went through a few iterations before settling on the current choice:

Design 1
Design 1
Design 2
Design 2
Design 3
Design 3

Work in progress: Science Shift Simulator

The Science Shift Simulator game is something that emerged from development of the aDetector project and LHC Driver projects. The mechanic is loosely based on the cooperative game Space Team. This is still in development, so the current page doesn’t actually work at the time of writing, and development will continue over the net week and months.

Links

Live page
GitHub repository

Overview

This is a cooperative multiplayer game aimed at showing the public (especially high school pupils) how particle physics research actually takes place, with an emphasis on cooperation. The game proceeds by bringing up several issues that need to be solved. The “Shift Leader” has information about how to solve the problems, but no control over the various subsystems. Instead they have a team of “Shifters” whose job is to solve the problems. This then becomes a problem of communication, cooperation, and optimisation between the various players.

For this project each player has control of a browser, which communicates with a central server. The Shift Leader’s client sends problems to the server, which are then collected by the Shifters’ clients. As a result the main difficulty in developing this game is synchronisation, especially when there are network problems!

Eventually this project will be reskinnable to allow other developers to add their own content. This will also be moved into a collaborative space, as this will have several developers in the future.

Challenges

Challenge: The big problem is synchronisation.
Solution: This is not the first project I’ve developed that required the client and server to communicate via AJAX requests, but it is the first that had more than one client sending information to the server. In fact it was this project that persuaded me to install MySQL locally and hook it up to Apache to get a local LAMP stack running on the my laptop. I got a prototype version working for demonstration purposes, but had to cut some corners. Development stopped in the middle of a significant rewriting of code, which is still to be completed. (To be revisited.)
Challenge: This game contains many mini games.
Solution: This is the first game I made that has mini games in it, and this required a different strategy for development. Making a generic mini game module in Javascript is not easy, and there will be some further significant changes as I rewrite this code again. (Resolved, to be revisited.)

Screenshot

Here’s the page as it currently looks. It needs a bit of a facelift!

Screenshot of the Shift Leader's page
Screenshot of the Shift Leader’s page

Tetris

This was my first serious Javascript project which was written some time in 2009. I chose to write a Tetris clone because it was a well defined project that would teach me how to use Javascript. In addition to Tetris I also made Tritris and Pentris to see how well balanced the three games are compared to each other. It turns out that Tetris is about right, with Tritris being too easy and Pentris being too hard.

Links

Live page
GitHub repository

Overview

The user plays the game with the arrow keys, and the game gets slowly faster as their score increases. There is a MySQL and PHP backend to save scores on the server. As much as possible, the three games have been harmonised so that they use the same page, the same Javascript library, and the same PHP page for interaction with the server. This is outlined in a previous post where I discussed how the code was refactored. This is one of my favourite projects, as it’s one of the few “complete” projects that touches on almost all of Javascript, with some HTML, CSS, PHP, MySQL, httpxml, and cookies also thrown in there. This project taught me so much about Javascript and was an excellent start with the language.

Challenges

Challenge: This project required learning how to use Javascript.
Solution: What a challenge! Having worked previously with C++, I found that Javascript was rather easy to learn, and quickly came across its peculiarities and limitations. (Resolved)
Challenge: The project required detailed manipulation of the DOM.
Solution: It was with this project that I learned how to use the DOM, which helped me to better understand the heirarchical structure of XML in general. I also wanted the HTML to be semantically pure, so while I used the DOM to store some information about the state of the game, I also ensured that it was semantically consistent. (Resolved)
Challenge: This game required careful control of Javascript events and synchronisation.
Solution: This was probably the most difficult and instructive part of the project. I had to learn how to register event handlers in a manner which worked across browsers. I still use the same style of event handling today that I developed when I wrote this project. It took a while to get used to the issues of synchronisation using the window.setTimeout method, which I still use frequently today. (Resolved)
Challenge: I had to store some data on the server.
Solution: I had had plenty of experience with PHP and MySQL before this project, including sanitising input to the database, so the PHP side of this challenge was easy to implement. However making the httpxml requests was not so easy and took some practice. After a few iterations I got a working model, although this is something I should improve further, as httpxml requests tend to be rather messy. (Resolved)
Challenge: One of the users wanted a feature that required cookies.
Solution: One user spent so long playing the game that he wanted to be able to “block” himself. As a result I had to implement a feature hat sets a cookie that prevents the user from playing. This was the first time I had set and read cookies using Javascript, and not something I have had much use for since. (Resolved)
Challenge: The game has a soundtrack.
Solution: Having used so many feature of Javascript, I wanted to add some music. This is far from trivial in the world of Javascript, and not so easy in the days befre embedded YouTube videos. Although support is a little shaky, the music was added and an interface included. (Resolved)
Challenge: The game had to have cross browser support.
Solution: This game was initially developed using Firefox, but one of the users wanted it to work with Chrome. This was the first time I met the frustration of cross browser event handling, which has been something of a pain ever since, but it was not too hard to overcome. (Resolved)

Screenshot

Screenshot of the Tetris game
Screenshot of the Tetris game

Code update: Tetris

The first major Javascript project I took on was a clone of Tetris. Every time I look back at it I’m actually surprised an impressed at how many features it has. For a first project it has DOM manipulation, httpxml requests, timeout functions, cookies, audio, and a MySQL backend. After making the Tetris clone I then tried to make Pentris, which is the same game but with five blocks per piece. In going from Tetris to Pentris I made some interesting optimisations.

The Tetris clone
The Tetris clone

For example, here is the function tryRotate:

function tryRotate(){
  switch(color){
    case "red":
    switch(orientation){
      case 0:
      case 2:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] - 2 ; rotatedR[3] = R[3] + 1 ;
      break ;
      case 1:
      case 3:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 2 ; rotatedR[3] = R[3] - 1 ;
      break ;
    }
    break ;
    
    case "green":
    switch(orientation){
      case 0:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 1 ;
        rotatedC[1] = C[1] + 1 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] + 0 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] - 1 ; rotatedR[3] = R[3] + 1 ;
      break ;
      case 1:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 1 ;
        rotatedC[1] = C[1] + 1 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] + 0 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] - 1 ; rotatedR[3] = R[3] - 1 ;
      break ;
      case 2:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] - 1 ;
        rotatedC[1] = C[1] - 1 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] + 0 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 1 ; rotatedR[3] = R[3] - 1 ;
      break ;
      case 3:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] - 1 ;
        rotatedC[1] = C[1] - 1 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] + 0 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 1 ; rotatedR[3] = R[3] + 1 ;
      break ;
    }
    break ;
    
    case "blue":
    switch(orientation){
      case 0:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] + 2 ;
        rotatedC[3] = C[3] - 2 ; rotatedR[3] = R[3] + 1 ;
      break ;
      case 1:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] - 1 ;
        rotatedC[3] = C[3] + 0 ; rotatedR[3] = R[3] - 2 ;
      break ;
      case 2:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] - 1 ;
        rotatedC[3] = C[3] + 2 ; rotatedR[3] = R[3] + 0 ;
      break ;
      case 3:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] - 2 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 0 ; rotatedR[3] = R[3] + 1 ;
      break ;
    }
    break ;
    
    case "cyan":
    switch(orientation){
      case 0:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 2 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 0 ; rotatedR[3] = R[3] - 1 ;
      break ;
      case 1:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] - 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] + 1 ;
        rotatedC[3] = C[3] + 2 ; rotatedR[3] = R[3] + 0 ;
      break ;
      case 2:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] - 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] + 1 ;
        rotatedC[3] = C[3] + 0 ; rotatedR[3] = R[3] + 2 ;
      break ;
      case 3:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] - 2 ;
        rotatedC[3] = C[3] - 2 ; rotatedR[3] = R[3] - 1 ;
      break ;
    }
    break ;
    
    case "magenta":
    switch(orientation){
      case 0:
      case 2:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 1 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 2 ; rotatedR[3] = R[3] + 1 ;
      break ;
      case 1:
      case 3:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] - 1 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] - 2 ; rotatedR[3] = R[3] - 1 ;
      break ;
    }
    break ;
    
    case "yellow":
    switch(orientation){
      case 0:
      case 1:
      case 2:
      case 3:
        rotatedC[0] = C[0] + 0 ; rotatedR[0] = R[0] + 0 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] + 0 ; rotatedR[2] = R[2] + 0 ;
        rotatedC[3] = C[3] + 0 ; rotatedR[3] = R[3] + 0 ;
      break ;
    }
    break ;
    
    case "white":
    switch(orientation){
      case 0:
      case 2:
        rotatedC[0] = C[0] + 1 ; rotatedR[0] = R[0] - 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] - 1 ; rotatedR[2] = R[2] + 1 ;
        rotatedC[3] = C[3] - 2 ; rotatedR[3] = R[3] + 2 ;
      break ;
      case 1:
      case 3:
        rotatedC[0] = C[0] - 1 ; rotatedR[0] = R[0] + 1 ;
        rotatedC[1] = C[1] + 0 ; rotatedR[1] = R[1] + 0 ;
        rotatedC[2] = C[2] + 1 ; rotatedR[2] = R[2] - 1 ;
        rotatedC[3] = C[3] + 2 ; rotatedR[3] = R[3] - 2 ;
      break ;
    }
  break ;
  }
  for(var i=0 ; i<4 ; i++){
    if(rotatedR[i]>nRows) return false ;
    if(rotatedR[i]<1)     return false ;
    if(rotatedC[i]>nCols) return false ;
    if(rotatedC[i]<1)     return false ;
    var skip = 0 ;
    for(var j=0 ; j<4 ; j++){ if(rotatedR[i]==R[j] && rotatedC[i]==C[j]) skip = 1 ; }
    if(skip==0){
      var className = getClass(rotatedR[i],rotatedC[i]) ;
      if(className!="empty") return false ;
    }
  }
  for(var i=0 ; i<4 ; i++){
    set(R[i],C[i], "empty") ;
    R[i] = rotatedR[i] ;
    C[i] = rotatedC[i] ;
  }
  for(var i=0 ; i<4 ; i++){
    set(R[i],C[i], color) ;
  }
  orientation++ ;
  if(orientation==4) orientation = 0 ;
}

Compare that to the streamlined version I had for Pentris:

function tryRotate(){
  rotatePiece() ;
  for(var i=0 ; i<n ; i++){
    if(rotatedR[i]>nRows) return false ;
    if(rotatedR[i]<1)     return false ;
    if(rotatedC[i]>nCols) return false ;
    if(rotatedC[i]<1)     return false ;
    var skip = 0 ;
    for(var j=0 ; j<n ; j++){ if(rotatedR[i]==R[j] && rotatedC[i]==C[j]) skip = 1 ; }
    if(skip==0){
      var className = getClass(rotatedR[i],rotatedC[i]) ;
      if(className!="empty") return false ;
    }
  }
  for(var i=0 ; i<n ; i++){
    set(R[i],C[i], "empty") ;
    R[i] = rotatedR[i] ;
    C[i] = rotatedC[i] ;
  }
  for(var i=0 ; i<n ; i++){ set(R[i],C[i], color) ;}
}
function rotatePiece(){
  for(var i=0 ; i<n ; i++){
    rotatedR[i] =  (Y) + C[i] - (X) ;
    rotatedC[i] =  (X) - R[i] + (Y) ;
  }
}

The optimisation here is quite impressive, and very much needed when you consider that the move from Tetris to Pentris means moving from five pieces of four blocks each, to eighteeen pieces of five blocks each, with the space needed for ratotions scaling from sixteen to twenty five.

In the first function the different scenarios are all checked explicitly, whereas in the second function the temporary piece is rotated and then collisions checked, before updating the main piece. The amount of code when from 82 to 27 lines, and in doing so became safer and more easily extendible.

In a similar vein, here's the updatePreview function, first in Tetris:

function updatePreview(){
  for(var i=1 ; i<3 ; i++){ for(var j=1 ; j<5 ; j++){ setPreview(i, j, "empty") ; } }
  switch(nextPiece){
    case 1:
      setPreview(1, 2, "red") ;
      setPreview(1, 3, "red") ;
      setPreview(2, 3, "red") ;
      setPreview(2, 4, "red") ;
      break ;
    case 2:
      setPreview(1, 3, "green") ;
      setPreview(2, 2, "green") ;
      setPreview(2, 3, "green") ;
      setPreview(2, 4, "green") ;
      break ;
    case 3:
      setPreview(1, 1, "blue") ;
      setPreview(1, 2, "blue") ;
      setPreview(1, 3, "blue") ;
      setPreview(2, 3, "blue") ;
      break ;
    case 4:
      setPreview(1, 3, "cyan") ;
      setPreview(1, 2, "cyan") ;
      setPreview(1, 1, "cyan") ;
      setPreview(2, 1, "cyan") ;
      break ;
    case 5:
      setPreview(1, 3, "magenta") ;
      setPreview(1, 2, "magenta") ;
      setPreview(2, 2, "magenta") ;
      setPreview(2, 1, "magenta") ;
      break ;
    case 6:
      setPreview(1, 2, "yellow") ;
      setPreview(1, 3, "yellow") ;
      setPreview(2, 3, "yellow") ;
      setPreview(2, 2, "yellow") ;
      break ;
    case 7:
      setPreview(2, 1, "white") ;
      setPreview(2, 2, "white") ;
      setPreview(2, 3, "white") ;
      setPreview(2, 4, "white") ;
      break ;
  }
}

Second in Pentris:

function updatePreview(){
  for(var i=1 ; i<4 ; i++){ for(var j=1 ; j<6 ; j++){ setPreview(i, j, "empty") ; } }
  var x = new Array(n) ;
  var y = new Array(n) ;
  var piece = getPiece(nextPiece) ;
  var counter = 0 ;
  for(var i=0 ; i<n ; i++){
    for(var j=0 ; j<n ; j++){
      if(piece[i][j]==1){
        x[counter] = i   ;
        y[counter] = j+1 ;
        counter++ ;
      }
    }
  }
  for(var i=0 ; i<n ; i++){setPreview(x[i],y[i],colors[nextPiece-1]);}
}

Such an economy of code! One of my favourite parts of code is refactoring existing blocks of code into something more elegant and effiienct. The original code, as a first attempt, and a first adventure in serious Javascript was necessarily messy and in need of a good clean, so it's no surprise that so many improvements could be had.

I've been putting off resolving these differences for a very long time, partly because the games work as they are and there's no need to fix something that's not broken, and partly because I wanted to keep some legacy code around to remind myself of how it all started. I've archived the original code and now I'm bringing the Tetris, Pentris, and Tritris into line with each other to make all three games share a single code base.

Guess the song

This project is a fun game where the user had to guess the song by guessing the lyrics, hangman style, with whole words instead of letters.

Links

Live page
GitHub repository

Overview

The script loads a song randomly and displays blank spaces for the lyrics on the screen. The user then enters guesses and the script checks for matches, keeping track of which words have already been suggested by the user. The score depends on the total number of guesses, the time, and whether the user chooses the hard or easy mode.

Challenges

Challenge: The lyrics must be hidden from the user.
Solution: Initally the lyrics were “whited out”, but some users simply highlighted the lyrics to cheat. To prevent this the lyrics were replaced with underlined monospaced blank characters. (Resolved)
Challenge: The users should be able to collect achievements, to encourage subsequent visits.
Solution: I don’t usually pester my users to come back a second time, but with this game it seemed natural to do so. User’s gain achievements for various actiosn which are then stored via AJAX to the MySQL backend, building on previous knowledge of these methods. The achievements are then highlighted by changing the CSS of HTML elements. The user id is store in a cookie, and can be recovered by copying and pasting a uri. (Resolved)
Challenge: The users interface should be as intuitive as possible.
Solution: As usual the user interface is a significant stumbling block, and what is obvious to the designer si not obvious to the user. After some iterating with friends the user interface was adapted based on their feedback, and now the game starts with the correct element on focus so that the user can start guessing immediately. (Resolved)

Screenshot

Guessing "Gangster's Paradise" by Cololio
Guessing “Gangster’s Paradise” by Cololio

Mandelbrot explorer

This project estimates the Mandelbrot set using the HTML5 canvas. It’s one of my longest running projects that has been implemented in PHP, SVG, HTML5 canvas, HTML tables, and even in ROOT.

Links

Live page
GitHub repository

Overview

This projects presents a wide range of different challenges. The aim is to create a fractal browser that pushes the operating environment to the limit in terms of performance, while still being user friendly and responsive. In its current iteration the user clicks on the region of the fractal they wish to explore and the project zooms in to that region. The user can change the way the fractal is coloured by changing the palette its properties. They can also move from the Mandelbrot set to the corresponding Julia set. There is also the option to explore the cubic Mandelbrot set. Past iterations have included even more fractals, including Newton iterations and generalised Julia sets. However these have been removed in this iteration as they should be refactored into a separate fractal class rather than inserted by hand.

Challenges

Challenge: The algorithm must be responsive and make reasonable use of memory.
Solution: The iterations used in the algorithm can be expensive when the image approaches several hundred thousand pixels. Currently the algorithm uses a pixel object to manage the colour at a given point, and for arbitrarily large images a single pixel object is used in order to reduce the cost of creating and storing large numbers of these objects. The current iteration uses Javascript in the user’s browser, and most modern browsers deal with excessive memory usage sensibly, killing particularly bad cases. It is not desirable to cap a user’s capabulities when it comes to image size, so instead the algorithm forces the browser to fail relatively safely and without major inconvenience. Previously this project ran on PHP on a shared server, so memory use had to be monitored and was formally enforced on the server, making failure modes potentially dangerous. Once the canvas became available I switched to using it very quickly. Even so, running PHP locally overnight to generate very large images is still a sensible use of resounces. There are probably other areas where savings could be made. (Resolved, to be revisited)
Challenge: The algorithm must make reasonable use of CPU.
Solution: In many cases the fractals take several tens of thousands of iterations per pixel for several thousand pixels, leading to large CPU usage. In the context of Javascript this can cause serious performance issues for the user, affecting their whole computing experience and not just that associated with the browser session. To mitigate this the iterations are interrupted every \(100 ms\) and forced to wait for \(10 ms\) before continuing. In addition when several small canvases are populated they are pushed into a queue which is processed serially with interruptions. This reduces the impact on the user’s CPU significantly leading to much smoother performance and better response to user input. Even so, this should be revisited to make further savings and be more responsive to the user’s inputs. (Resolved, to be revisited)
Challenge: The user interface must be intuitive.
Solution: In some senses it will never be possible ot make the user interface entirely transparent, given the technical nature of the fractal’s inner workings. In spite of this the way the user navigates is relativelt straightforward, but more improvments can and should be made. (Resolved, to be revisited)
Challenge: The palettes should be easy to edit.
Solution: The asethetic properties of the fractals often depend on the choice of palette. The palette scales can be manipulated, using slders on the log scale. This solution borrows from another project being developed in parallel, and leads to an easier interpretation of the scaling and distorting of the palette scale. This method should be tested in a “focus group” style environment. The user should be able to create and store a palette from scratch with their own choice of colours stops. (Resolved, to be revisited)
Challenge: The user should be able to store fractals.
Solution: The user can currently choose to save a fractal to the server, storing the \((x,y)\) coordinates, zoom, and other factors. This uses AJAX requests with a PHP and MySQL backend, which has become fairly standard in my projects by now. This comes with the usual MySQL injection overheads and PHP safety issues. In the future, as the number of fractals in the gallery increases, the gallery should be orgainsed in some manner to reduce bandwidth and CPU usage. (Resolved, to be revisited)
Challenge: The project should support arbitrary fractals for future expansion.
Solution: At the moment the fractal algorithms are hard coded into the project. This needs to be more object oriented in the future so that other developers can contribute their own fractals. (Partially resolved, to be revisited)

Sample output

Mandelbrot explorer output
Mandelbrot explorer output

My MySQL is installed!

Last week I was involved in a rather delicate project that required AJAX requests with a MySQL backend. The problem I faced was that I would be on the Eurostar for two hours without any internet connection, and needed to develop the project in that time. With minutes to spare I managed to complete a MySQL isntallation and get PHP to successfully talk to it, meaning that I now have a functioning server installed on my laptop and it can do everything my webspace can do!

PHP and MySQL, playing nicely together
PHP and MySQL, playing nicely together

This came shortly before a scare related to the Yosemite upgrade. Overnight I allowed my laptop to upgrade, and the following morning, a couple of hours before I was due to present my latest project, I found that apache was down, PHP was down, my Sites folder was not accessible, and MySQL stopped working again. After a slighlty panicked 30 minutes I managed to have everything under control and all was as it should be. It’s stressful having all the pieces fall into place, and then fall apart again within a matter of hours. In spite of that, my laptop based web server is more versatile than it was before and this has come at just the right time. I may need to migrate my webspace to a new server soon, and being able to test on my laptop will help ease that process considerably.

That weird part of YouTube

One of the most fruitful memes on the internet is “That wierd part of YouTube”. I saw an opportunity to createa a service to find the weirdest videos on YouTube, and I made this webpage.

Links

Live page
GitHub repository

Overview

This page uses the YouTube Javascript API to load pairs of YouTube videos. The user then votes on which one they think is “weirder”, and two new videos are loaded for comparison. The backend is handled using PHP with a MySQL database to store and retrieve the video ids. The user can submit their own videos with client side validation of the URI and server side sanitisation to prevent MySQL injection attacks. The statistics associated with each video are also displayed, showing how many times each “won” or “lost” a comparison.

This project was never actually released outside my webspace, despite my original intentions. This is because YouTube is very clear about its branding policies- a third party cannot use the word “YouTube” without explicit permission, and the meme requires the name “YouTube” to be used. As a result this was only ever shown to my friends and never received much traffic. I may revisit this later and release to the general public with a different name.

Challenges

Challenge: As usual, this uses the YouTube Javascript API and all the difficulties that come with that.
Solution: The YouTube Javascript API is second nature now. This wasn’t difficult at all! (Resolved)
Challenge: The user should be able to recommend videos.
Solution: The interface to add suggestions had to be simple to use, so I made the form as clean as possible. The input had to sanitised as well. The URI is matched to a regular expression client side before submission, and sanitised server side to prevent injection. The server side sanitising is very easy given that it must consist of exactly 11 characters in the set [A-Za-z0-9_\-]. (Resolved)
Challenge: This page needed a catchy motif.
Solution: I wanted an image of YouTube videos falling from the sky, as if the videos has been rejected and thrown onto a pile. I had to emulate the YouTube logo using vector graphics with the canvas, then randomly generate an collection of them that wrapped around in the horizontal direction for the wallpaper. It was fun to make, and I may make a wallpaper generator based on this concept. (Resolved)

Screenshots

Some YouTube weirdness
Some YouTube weirdness
The automatically generated wallpaper
The automatically generated wallpaper

2010 UK General Election analysis

This project displays the results of the 2010 UK General Electrion, and it was to be the first of many that investigate different data sets. One of my planned meta projects is to make the acquisition, storage, and analysis of public domain data simpler and easier. This was an experimental project, and created in a hurry.

Links

Live page
GitHub repository

Overview

The source of data was identified (BBC News website) and custom functions written to extract the HTML sources via HTTP requests. The HTML sources were there parsed to determine the relevant information and written to file. These files were then used to create PHP files to create and populate MySQL tables. The remaining pages then allow the user to browse the data, sorting by various fields, with links back to the original sources.

This project should be revisited in the future to clean up the code and make the styles match those of the rest of the wider website. This should be done in time for the next election!

Challenges

Challenge: Data must be taken from a public domain resource.
Solution: This project’s first challenge was at the heart of the concept, which is how to obtain large amounts of publically available data in as few HTTP requests as possible, and in an ethical manner (ie avoiding overloading the servers which provide the data). The HTTP requests were automated and the data dumped to file for further processing. (Resolved)
Challenge: The data for each constituency varies in its content and structure.
Solution: The data contains various parties and candidates which vary from constituency to constituency. As a result the data processing must be able to add an arbitrary list of candidates and parties per constituency. This turned out to be trivial, using the database schema, but did add another layer of complexity to the project. (Resolved)
The 2010 UK General Election analysis.
The 2010 UK General Election analysis.