Race Condition 2023

Introduction

Race Condition is a coding game where you compete against other players in the seemingly simple task of driving around a racing circuit as fast as possible. Players who have completed the fastest lap times on the track get their names on the Leaderboard.

In Race Condition, you write JavaScript code in the browser and you can see the results immediately as your car drives on the track in the same browser window.

The Race Condition coding environmentImmediate feedback on errorsPause, playback, powerful debugging options

Getting started

Your job is to write a JavaScript program that steers the car. The program consists essentially of two functions:

/** * The brain of your bot. Makes decisions based on the incoming "frame" of pixels. **/ function decide(frame) { // implementation omitted for now } /** * Pixel frame preprocessor. Simplifies the job of `decide`. **/ function preprocess(frame) { // implementation omitted for now }

When the car moves on the track, a virtual camera on the car sends a picture, or a "frame", to your program. The frame consists of individual pixels, each of which in turn consists of numeric RGB values in the range between 0 and 255. For instance, a single pixel in the frame can look like this:

{ r: 255, g: 255, b: 0 }

Can you tell, which color this pixel is?

This pixel frame is first passed to the preprocess function which simplifies the frame by replacing all the different shades of colors by either a pure black, red, green or blue pixel. (Later you may want to write your own preprocess function to suit your algorithm better)

You can always see both the original camera frame and the preprocessed / simplified frame beside your code when you're playing. For instance, the camera and the preprocessed frame could look like this:

After preprocessing, the frame is passed to the decide function.

The decide function

The decide function is essentially the "brain" of your program. It receives an incoming frame that has already been preprocessed and is responsible of returning a command to steer the car. For instance, this function always drives forward slowly and doesn't turn:

function decide(frame) { return { throttle: 0.1, steering: 0 }; }

The frame is an array of rows, each of which is an array of RGB pixels. For example, you can "look at" the center pixel of the bottom row like this:

function decide(frame) { // Choose the center row const height = frame.length; const bottomRow = frame[height - 1]; // Choose a pixel at the center of this row const width = bottomRow.length; const pixel = bottomRow[width / 2]; console.log(pixel); return { throttle: 0.1, steering: 0 }; }

As a result, your car will still be bumping to the walls, but if you open the Developer Console in your browser, you'll start to see some RGB values in the console. Notice that the console.log call in the code is there merely for you to be able to get some insights into what's happening in your code, it has no effect as to where the car goes.

Now, based on the pixel value, you may try to implement your first bot that doesn't just crash to the walls all the time. Try replacing the last two lines with this:

if (sameColor(pixel, RED)) { // Red side of track -> turn right return { throttle: 0.05, steering: -1 }; } else if (sameColor(pixel, GREEN)) { // Green side of track -> turn left return { throttle: 0.05, steering: 1 }; } return { throttle: 0.1, steering: 0 };

Now your car should actually be doing something remotely intelligent.

Your job is to make it FAST.

The preprocess function

The preprocess function is where you can simplify the incoming pixel frame to a more suitable format for your decide function. You could, of course, do all the work in the decide function, but doing preprocessing separately allows you to visually inspect the preprocessed frame. We've found that this makes it easier to reason about what' going on.

The default implementation of preprocess simplifies the frame by replacing all the different shades of colors by either a pure black, red, green or blue pixel.

Your implementation can take another approach at simplification, and it can also output a frame with smaller dimensions if you like. For instance, you may clip out the top half of the frame.

Developer tips

  • Use the Developer Console of your browser and console.log() to get a grasp on what the bot is doing
  • Use the Pause button to stop the program, take your time to analyse what's going on. You can use the slider to inspect the incoming frame, processed frame and the bot decision for any point in time
  • In your decide function, you may include additional information in the result object. If, for instance, you had a variable called numberOfBlackPixels in your function, you could return { throttle: 1, steering: 1, numberOfBlackPixels }. This way, when your car crashes to the wall, you can more closely inspect the inner workings of your algorithm before the crash.