Snake instructions
Introduction
Snake is a game in which you write a bot that controls a snake. The goal of the game is to get your Snake as big as possible by eating food while avoiding a collision with another snake, which results in deauth.
Your snake bot is competing with the bots from other participants in one big realtime arena. The game continously runs throughout the whole egoi week.
This game is inspired by slither.io .
Game mechanics
The game is split up into small steps. In each step your Snake can use the Api to learn about nearby food and snakes. It then has to decide in which directions it wants to move. This happens simultaneously for all snakes. After all snakes have decided on their next step, the game server moves all the snakes forward in their new direction. If the head of a snake collides with another snake, it is dead and numerous food items are placed where it was, proportionally to it’s mass.
A snake consists of several circle-shaped segments. The number of segments is increasing with the mass of the snake. All segments of a snake have the same radius, which is also increasing as the mass increases.
Every food item an the field has an associated mass. Eating a food segment results in an increase of the snake’s mass by the amout of the food item. Food items can spawn and decay at random in every step. Food items also appear if a snake dies. Additionally, every snake looses a small percentage of it’s mass every step, leaving a trail of food items behind itself.
In addition to the direction that a snake chooses every step, a snake can also decide whether it wants to boost. Boosting results in twice the speed for a snake. However in exchange for boosting the snake looses a far greater percentage of it’s mass per step.
There is a limited amount of time per step that a snake can take to compute it’s step. After that, the snake simply moves in the same direction as in the previous step. The bot’s step function continues to run and once it returns in a subsequent turn, the direction is then used as new direction. If the execution of a step function takes too many turns, your snake is killed and restarted.
Api
This section contains a small overview about how the api works. The next section Bot Template contains the code of an example bot that can be used as a starting point. If you struggle to understand this api description, it’s recommended to look at the example bot. A more detailed, systematical description of the Api can be found below at Api Documentation.
Your bot is a C++ program that needs to implement two functions: init and step.
init is run exactly once when your bot is started. Your can select your snake’s colors by using the addColor function or make some initial computations.
In every step your step function is called once. This is where your program can make queries about the environment using getSegmentCount, getSegments,getFoodCount,getFood or other functions. In the end you need to set angle to the direction in which the snake should move next and boost needs to be set to true if the snake should boost this turn.
Both the init and step functions take one argument: The api object which is used to run all previously mentioned the functions and set the angle and boost status.
Your functions return a bool which should be true if your bot run correctly. If something went wrong and you want your snake to be killed and restarted, return false.
Querying the environment
The two most useful pairs of functions are the getSegmentCount+getSegments and getFoodCount+getFood functions.
The XYCount functions return an integer which represents how many food items / segments are visible to your snake. The getSegments and getFood functions each return an array of segment / food objects.
segment objects have the following properties
| Property | Type | Description |
|---|---|---|
| x | float |
x coordinate |
| y | float |
y coordinate |
| r | float |
radius of segment |
| bot_id | long long |
id of the snake |
| idx | int |
this segment is the idx-th segment of the snake |
| dir | float |
direction your snake needs to take to go directly to the segment |
| dist | float |
distance between segment and your snake’s head |
| is_self | bool |
whether this segment belongs to your snake |
The dir,dist and is_self properties are there for your convenience. You could also compute them yourself.
food objects have the following properties
| Property | Type | Description |
|---|---|---|
| x | float |
x coordinate |
| y | float |
y coordinate |
| val | float |
how much mass the food item contains |
| dir | float |
direction your snake needs to take to go directly to the food item |
| dist | float |
distance between food item and your snake’s head |
The dir and dist properties are there for your convenience. You could also compute them yourself.
There are more functions available. Check them out at Api Documentation.
Selecting your snake’s move
To select the your snake’s angle, use the angle variable of the api.
For example:
api->angle = 0.1;Note that the angle has to be given in radians. It is specified relative to the snakes current angle.
You can tell your snake to boost by setting api->boost to true.
Logging output for debugging
The log function is useful to help you debugging your snake.
example:
api->log("some text to log");Note that the log function only takes a c-style string i.e. a char*.
It’s recommended to use c++ strings. To do that you first need to include them. Write this at the begin of your program:
#include<string>
using namespace std;You can convert int,float or bool to string by using to_string. To use it with api->log you need to convert it to a c-style string with c_str().
Example:
string example = "Here comes some number: " + to_string(20) + " and a boolean: " + to_string(false) + " .";
api->log(string_example.c_str());There is a rather small limit on how frequently and how much text you can log.
Bot Template
This is a template for a very simple bot. It moves in a circle as it always moves in the same direction.
// You can use the entire C/C++ standard library, just add the relevant
// #includes. We recommend math.h ;-)
// Limits
// your 64 MB Ram including overhead from c and the snake api
#include "usercode.h"
bool init(Api *api)
{
// remove the default color
api->clearColors();
// These 4 colors are repeated as many times as needed to color all segments.
api->addColor(40, 255, 0);
api->addColor(20, 128, 0);
api->addColor(10, 64, 0);
api->addColor(20, 128, 0);
// note: you can add at most 200 colors
return true;
}
bool step(Api *api)
{
// let's start by moving in a large circle. Please note that all angles are
// represented in radians, where -π to +π is a full circle.
api->angle = 0.001;
//[bool] api->boost - set this variable to run twice as fast, if you do so your snake drops mass fast
// check for other snakes
for(size_t i = 0; i < api->getSegmentCount(); i++) {
const auto &seg = api->getSegments()[i];
//[float] seg.x -- x coordinate
//[float] seg.y -- y coordinate
//[float] seg.r -- radius of segment
//[float] seg.dir -- direction your snake needs to take to go directly to the segment
//[float] seg.dist -- distance to your snakes head
//[int] seg.bot_id -- id of the bot
//[long long] seg.idx -- the
//[bool] seg.is_self -- does this segment belong to me
if(!seg.is_self && seg.dist < 20) {
api->log("Oh no, I'm going to die!");
break;
}
}
for(size_t i = 0; i < api->getFoodCount(); i++) {
const auto &food = api->getFood()[i];
//[float] food.x -- x coordinate
//[float] food.y -- y coordinate
//[float] food.val -- how much mass the food gives to your snake
//[float] food.dir -- direction your snake needs to take to go directly to the food
//[float] food.dist -- distance to your snakes head
}
// Signal that everything is ok. Return false here if anything goes wrong but
// you want to shut down cleanly.
return true;
}The same template as above without all the comments:
#include "usercode.h"
bool init(Api *api)
{
api->clearColors();
api->addColor(40, 255, 0);
api->addColor(20, 128, 0);
api->addColor(10, 64, 0);
api->addColor(20, 128, 0);
return true;
}
bool step(Api *api)
{
api->angle = 0.001;
for(size_t i = 0; i < api->getSegmentCount(); i++) {
const auto &seg = api->getSegments()[i];
if(!seg.is_self && seg.dist < 20) {
api->log("Oh no, I'm going to die!");
break;
}
}
for(size_t i = 0; i < api->getFoodCount(); i++) {
const auto &food = api->getFood()[i];
}
return true;
}Rules
- Any attempts at attacking the sandbox or the snake servers can lead to disqualification
- A user can only create one account per server and only the server where they belong to.
- If you don’t use your real name for signing up, you have to send me a message on Discord with your real name. This is needed to prevent the abuse of several accounts by only one person.
Game mechanics in detail
- Snakes only see nearby food items and segments. The sight radius depends on the snake’s mass.
- A snake may collide with it’s own segments without dying.
- If a snake collides with another snake and is >= 1000x bigger than the other snake, it doesn’t die. This prevents freshly spawned snakes from killing big snakes in surprise.
Api Documentation
Segments
api->getSegmentCount() // {long long} returns number of visible segmentsapi->getSegments() // {IpcSegmentInfo[]} returns an array of all visible segments. The segments are sorted by distance to your snake's headstruct IpcSegmentInfo {
float x; // x coordinate
float y; // y coordinate
float r; // radius of segment
int idx; // id of the snake
long long bot_id; // this segment is the `idx`-th segment of the snake
float dir; // direction your snake needs to take to go directly to the segment
float dist; // distance between segment and your snake's head
bool is_self; // whether this segment belongs to your snake
}Food
api->getFoodCount() // {long long} returns number of visible food itemsapi->getFood() // {IpcFoodInfo[]} returns an array of all visible food items. The items are sorted by distance to your snake's headstruct IpcFoodInfo {
float x; // x coordinate
float y; // y coordinate
float val; // how much mass the food item contains
float dir; // direction your snake needs to take to go directly to the food item
float dist; // distance between the food item and your snake's head
}Angle
api->angle // {float} direction in which the snake moves. Changed by your program.Boost
api->boost // {bool} whether the snake boosts in this step. Changed by your program.Log
api->log(const char *msg) // {void} sends a log messageColors
api->clearColors() // {void} resets your snake's colorsapi->addColor(uint8_t r, uint8_t g, uint8_t b) // {void} Add a color to your snake's color listclearColors and addColor can only be used in the init function. The colors of your snake are repeated as many times as needed. You may add at most 200 colors.
Bots
api->getBotsCount() // {long long} returns number of bots in the gameapi->getBots() // {IpcBotInfo[]} returns an array of descriptions of all botsstruct IpcBotInfo {
long long bot_id; // ID of the bot
char bot_name[64] // the first 64 characters of the bot's name
}Server Config
api->getServerConfig() // {IpcServerConfig} returns the server's configurationstruct IpcServerConfig {
int snake_boost_steps; // number of steps a snake moves when boosting
float snake_turn_radius_factor; // Multiplied with your segment radius to determine the inner turn radius
float snake_pull_factor; // Pull-together factor (determines how fast segments move to the center of a loop)
float snake_conversion_factor; // how much of a snake's mass is converted to food when it dies
float snake_segment_distance_factor; // segment distance = (mass * factor)^exponent
float snake_segment_distance_exponent; // segment distance = (mass * factor)^exponent
float snake_consume_range; // consume range multiplier (multiplied with segment radius)
float snake_boost_loss_factor; // Multiplied with the snakes mass to determine how much mass is lost per step while boosting
float snake_survival_loss_factor; // This part of your mass is dropped every step (to limit snake growth)
float snake_self_kill_mass_theshold; // Mass below which a snake dies through starvation
float food_decay_step; // Food decays by this value each step
float log_credits_per_frame; // How many log messages you can send per step
float log_initial_credits; // How many log messages you can send right after startup
float log_max_credits; // You can send at most this many messages in a row
}IpcServerConfig contains the constants that are used for simulating the snake game. The physics is on all games the same, only the size of the field may vary. There is no need to look at these constants. They are only listed here for completeness.
Self Info
api->getSelfInfo() // {IpcSelfInfo*} returns the information about your snakestruct IpcSelfInfo {
float segment_radius; // Radius of your snake's segments
float mass; // Your snake's current mass
float sight_radius; // Radius around your snake's head in which you can see food and segments
float consume_radius; // Radius around your snake's head in which food is consumed.
uint32_t start_frame; // Step number when your snake was spawned
uint32_t current_frame; // Current step number
float speed; // Distance per step
float max_step_angle; // Maximum direction change in this step
float consumed_natural_food; // Amount of naturally spawned food your snake consumed
float consumed_food_hunted_by_self; // Amount of food you consumed and that was created from snakes you killed
float consumed_food_hunted_by_others; // Amount of food you consumed and that was created from snakes others killed (carrion)
}C++ Basics
Use the C++ Reference to find the specification of the C++ Standart Library.
Snake Game of