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.
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.
decide
functionThe 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.
preprocess
functionThe 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.
console.log()
to get a grasp on what the bot is doingdecide
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.