### version WhereCanGo
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int circirling_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistanceForNoSnake(DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType WhereCanGo(Position, DirectionSymbol, const Game&, size_t);
};
DirectionType CustomController::WhereCanGo(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id)
{
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
for (const Position& pos : anotherSnake.Body()) {
if (dirSymbol == DirectionSymbol::UP) {
if (abs(snakePos.x - pos.x) < turn_radius * 2 && pos.x > snakePos.x && abs(snakePos.y - pos.y) < turn_radius * 2 ) {
return DirectionType::kLeft;
}
else if (abs(snakePos.x - pos.x) < turn_radius * 2 && pos.x < snakePos.x && abs(snakePos.y - pos.y) < turn_radius * 2 ) {
return DirectionType::kRight;
}
}
if (dirSymbol == DirectionSymbol::DOWN) {
if (abs(snakePos.x - pos.x) < turn_radius * 2 && pos.x > snakePos.x && abs(snakePos.y - pos.y) < turn_radius * 2 ) {
return DirectionType::kRight;
}
else if (abs(snakePos.x - pos.x) < turn_radius * 2 && pos.x < snakePos.x && abs(snakePos.y - pos.y) < turn_radius * 2 ) {
return DirectionType::kLeft;
}
}
if (dirSymbol == DirectionSymbol::LEFT) {
if (abs(snakePos.y - game.FieldHeight()) < turn_radius * 2)
{
return DirectionType::kRight;
}
if (abs(snakePos.x - pos.x) < turn_radius * 2 && abs(snakePos.y - pos.y) < turn_radius * 2 && snakePos.y > pos.y)
{
return DirectionType::kLeft;
}
else if(abs(snakePos.x - pos.x) < turn_radius * 2 && abs(snakePos.y - pos.y) < turn_radius * 2 && snakePos.y < pos.y)
{
return DirectionType::kRight;
}
}
if (dirSymbol == DirectionSymbol::RIGHT) {
if (abs(snakePos.x - pos.x) < turn_radius * 2 && abs(snakePos.y - pos.y) < turn_radius * 2 && pos.y > snakePos.y) {
return DirectionType::kLeft;
}
else if(abs(snakePos.x - pos.x) < turn_radius * 2 && abs(snakePos.y - pos.y) < turn_radius * 2 && snakePos.y < pos.y)
{
return DirectionType::kRight;
}
}
}
}
//std::cout << "test" << std::endl;
if (snakePos.y - 0 < turn_radius * 2)
{
if (_dirSymbol == DirectionSymbol::RIGHT)
return DirectionType::kRight;
else if (_dirSymbol == DirectionSymbol::LEFT)
return DirectionType::kLeft;
}
else if (abs(snakePos.y - game.FieldHeight()) < turn_radius * 2)
{
if (_dirSymbol == DirectionSymbol::RIGHT)
return DirectionType::kLeft;
else if (_dirSymbol == DirectionSymbol::LEFT)
return DirectionType::kRight;
}
return _turnDirection;
}
int CustomController::howManySnake(const Game& game) {
int amount = 0;
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
if (howManySnake(game) == 1) // for test_A
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistanceForNoSnake(_dirSymbol, game, id);
if (distance > 0 && distance * 1.2 < turn_radius + circirling_times * 39.25) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
circirling_times++;
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else // other condition
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(snake.Head(), _dirSymbol, game, id);
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius * 1.5) {
// if(_turnDirection == DirectionType::kRight)
// std::cout <<"right" <<std::endl;
// else if (_turnDirection == DirectionType::kLeft)
// std::cout <<"left" <<std::endl;
// else
// std::cout <<"forward" <<std::endl;
// start turning around
// if(_turnDirection == WhereCanGo(snake.Head(), _dirSymbol, game, id))
// {
// if(_turnDirection == DirectionType::kRight)
// _turnDirection = DirectionType::kLeft;
// else if(_turnDirection == DirectionType::kLeft)
// _turnDirection = DirectionType::kRight;
// }
// else
_turnDirection = WhereCanGo(snake.Head(), _dirSymbol, game, id);
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 90;
//_turnDirection = DirectionType::kLeft;
}
else if (_currentDirType == DirectionType::kLeft) {
_final_angle = snake.Direction() - 90;
//_turnDirection = DirectionType::kRight;
}
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistanceForNoSnake(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
angle = int(angle) % 360;
if(angle < 0)
angle += 360;
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
// can be converted into 4 directions
int dir = abs(angle / 90);
dir %= 4;
return static_cast<DirectionSymbol>(dir);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
```
# here version what the fuck
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t);
float distance_cal(Position, Position);
int radar[5][5];
};
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
std :: map<size_t, Snake> snakes = game.Snakes();
for(int i = 0;i < snakes.size();i++){
std :: list<Position> body = snakes[i].Body();
if(snakeHead.x == snakes[i].Head().x && snakeHead.y == snakes[i].Head().y ){
continue;
}
for(Position p : body){
for(int k = 0; k < 5;k++){
for(int r = 0; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < radar_range - game.kSnakeRadius){
radar[k][r] = 1;
}
}
}
}
}
//
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
int n = 5;
for(int i=0;i<n/2;i++){
for(int j=i;j<n-i-1;j++)
{
// Swapping elements after each iteration in Anticlockwise direction
int temp=radar[i][j];
radar[i][j]=radar[j][n-i-1];
radar[j][n-i-1]=radar[n-i-1][n-j-1];
radar[n-i-1][n-j-1]=radar[n-j-1][i];
radar[n-j-1][i]=temp;
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
for(int q = 0; q < 2;q++){
//Tranposing the matrix
for(int i=0; i<5; i++){
for(int j=i+1; j<5; j++)
std :: swap(radar[i][j], radar[j][i]);
}
//Reversing each row of the matrix
for(int i=0; i<5; i++){
for(int j=0; j<5/2; j++){
std :: swap(radar[i][j], radar[i][5-j-1]);
}
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
for(int i=0; i<5; i++){
for(int j=i+1; j<5; j++)
std :: swap(radar[i][j], radar[j][i]);
}
//Reversing each row of the matrix
for(int i=0; i<5; i++){
for(int j=0; j<5/2; j++){
std :: swap(radar[i][j], radar[i][5-j-1]);
}
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
}
// for(int i = 0;i < 5;i++){
// for(int j = 0;j < 5;j++){
// std :: cout << radar[i][j] << " ";
// }
// std :: cout << std :: endl;
// }
// std :: cout << std :: endl;
//forward left right
bool dir[3] = {true, true, true};
if(radar[1][0] == 1 || radar[1][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[2]){
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else{
return DirectionType::kForward;
}
}
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
Radar(snake.Head(), _dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
//
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
_currentDirType = DirectionType::kForward;
_currentDirType = Radar(snake.Head(), _dirSymbol, game, id);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
ans = sqrt(ans);
return ans;
}
```
# another fuck
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t);
float distance_cal(Position, Position);
int radar[5][5];
};
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
std :: map<size_t, Snake> snakes = game.Snakes();
for(int i = 0;i < snakes.size();i++){
std :: list<Position> body = snakes[i].Body();
if(snakeHead.x == snakes[i].Head().x && snakeHead.y == snakes[i].Head().y ){
continue;
}
for(Position p : body){
for(int k = 0; k < 5;k++){
for(int r = 0; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < radar_range - game.kSnakeRadius){
radar[k][r] = 1;
}
}
}
}
}
//
bool dir[3] = {true, true, true};
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
if(radar[0][3] == 1 || radar[1][3] == 1){
dir[1] = false;
}
if(radar[3][3] == 1 || radar[4][3] == 1){
dir[2] = false;
}
if(radar[2][4] == 1 || radar[2][3] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][4] == 1 || radar[3][4] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
if(radar[3][3] == 1 || radar[3][4] == 1){
dir[1] = false;
}
if(radar[3][0] == 1 || radar[3][1] == 1){
dir[2] = false;
}
if(radar[3][2] == 1 || radar[4][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[4][1] == 1 || radar[4][3] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
if(radar[3][1] == 1 || radar[4][1] == 1){
dir[1] = false;
}
if(radar[0][1] == 1 || radar[1][1] == 1){
dir[2] = false;
}
if(radar[2][0] == 1 || radar[2][1] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][0] == 1 || radar[3][0] == 1){
dir[0] = false;
}
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
if(radar[1][0] == 1 || radar[1][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
}
// for(int i = 0;i < 5;i++){
// for(int j = 0;j < 5;j++){
// std :: cout << radar[i][j] << " ";
// }
// std :: cout << std :: endl;
// }
// std :: cout << std :: endl;
//forward left right
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[2]){
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else{
return DirectionType::kForward;
}
}
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
Radar(snake.Head(), _dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
//
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
_currentDirType = DirectionType::kForward;
_currentDirType = Radar(snake.Head(), _dirSymbol, game, id);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
ans = sqrt(ans);
return ans;
}
```
# version might be a little fucking quicker
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t);
float distance_cal(Position, Position);
DirectionType safeDirection(const Snake& snake, const Game&);
int radar[5][5];
};
DirectionType CustomController::safeDirection(const Snake& snake, const Game& game){
const auto& head = snake.Head();
const auto& directions = {DirectionSymbol::RIGHT, DirectionSymbol::LEFT};
const auto& dir = {DirectionType::kRight, DirectionType::kLeft};
std :: vector<float> distances;
for(const auto& direction : directions){
distances.push_back(GetCollisionDistance(head, direction, game, snake.Id()));
}
if(distances[0] >= distances[1]){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
std :: map<size_t, Snake> snakes = game.Snakes();
for(int i = 0;i < snakes.size();i++){
std :: list<Position> body = snakes[i].Body();
if(snakeHead.x == snakes[i].Head().x && snakeHead.y == snakes[i].Head().y ){
continue;
}
for(Position p : body){
if(_dirSymbol == DirectionSymbol::RIGHT){
for(int k = 0; k < 5;k++){
for(int r = 2; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
for(int k = 2; k < 5;k++){
for(int r = 2; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
for(int k = 0; k < 5;k++){
for(int r = 2; r < 3;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}else{
for(int k = 0; k < 3;k++){
for(int r = 0; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, p) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}
}
//
bool dir[3] = {true, true, true};
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
if(radar[0][3] == 1 || radar[1][3] == 1){
dir[1] = false;
}
if(radar[3][3] == 1 || radar[4][3] == 1){
dir[2] = false;
}
if(radar[2][4] == 1 || radar[2][3] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][4] == 1 || radar[3][4] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
if(radar[3][3] == 1 || radar[3][4] == 1){
dir[1] = false;
}
if(radar[3][0] == 1 || radar[3][1] == 1){
dir[2] = false;
}
if(radar[3][2] == 1 || radar[4][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[4][1] == 1 || radar[4][3] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
if(radar[3][1] == 1 || radar[4][1] == 1){
dir[1] = false;
}
if(radar[0][1] == 1 || radar[1][1] == 1){
dir[2] = false;
}
if(radar[2][0] == 1 || radar[2][1] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][0] == 1 || radar[3][0] == 1){
dir[0] = false;
}
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
if(radar[1][0] == 1 || radar[1][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
}
// for(int i = 0;i < 5;i++){
// for(int j = 0;j < 5;j++){
// std :: cout << radar[i][j] << " ";
// }
// std :: cout << std :: endl;
// }
// std :: cout << std :: endl;
//forward left right
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[2] && dir[1]){
// return safeDirection(game.Snakes().at(id), game);
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else if(dir[2]){
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
Radar(snake.Head(), _dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
//
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
_currentDirType = DirectionType::kForward;
_currentDirType = Radar(snake.Head(), _dirSymbol, game, id);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
// ans = sqrt(ans);
return ans;
}
```
# last dance
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t, Snake);
float distance_cal(Position, Position);
DirectionType safeDirection(const Snake& snake, const Game&);
int radar[5][5];
};
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id, Snake snake){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
GetCollisionDistance(snakeHead, _dirSymbol, game, id);
GetCollisionDistance(snakeHead, AngleToSymbol(snake.Direction()+90), game, id);
GetCollisionDistance(snakeHead, AngleToSymbol(snake.Direction()-90), game, id);
bool dir[3] = {true, true, true};
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
if(radar[0][3] == 1 || radar[1][3] == 1 || radar[1][2] == 1){
dir[1] = false;
}
if(radar[3][3] == 1 || radar[4][3] == 1 || radar[3][2] == 1){
dir[2] = false;
}
if(radar[2][4] == 1 || radar[2][3] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][4] == 1 || radar[3][4] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
if(radar[3][3] == 1 || radar[3][4] == 1 || radar[2][3]){
dir[1] = false;
}
if(radar[3][0] == 1 || radar[3][1] == 1 || radar[2][1]){
dir[2] = false;
}
if(radar[3][2] == 1 || radar[4][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[4][1] == 1 || radar[4][3] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
if(radar[3][1] == 1 || radar[4][1] == 1 || radar[3][2] == 1){
dir[1] = false;
}
if(radar[0][1] == 1 || radar[1][1] == 1 || radar[1][2] == 1){
dir[2] = false;
}
if(radar[2][0] == 1 || radar[2][1] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][0] == 1 || radar[3][0] == 1){
dir[0] = false;
}
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
if(radar[1][0] == 1 || radar[1][1] == 1 || radar[2][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1 || radar[2][3] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
}
//forward left right
// for(int i = 0;i < 5;i++){
// for(int j = 0;j < 5;j++){
// std :: cout << radar[i][j] << " ";
// }
// std :: cout << std :: endl;
// }
// std :: cout << std :: endl;
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[2] && dir[1]){
// return safeDirection(game.Snakes().at(id), game);
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else if(dir[2]){
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
_currentDirType = DirectionType::kForward;
_currentDirType = Radar(snake.Head(), _dirSymbol, game, id, snake);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
Snake neareat;
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
if(distance == d_body){
neareat = anotherSnake;
}
}
}
}
}
float radar_range = turn_radius;
Position starting_point;
starting_point.x = snakePos.x - 2*radar_range;
starting_point.y = snakePos.y - 2*radar_range;
if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction())){
for(Position pos : neareat.Body()){
for(int k = 0; k < 4;k++){
for(int r = 0; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}else if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction() + 90)){
for(Position pos : neareat.Body()){
for(int k = 0; k < 5;k++){
for(int r = 0; r < 4;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}else if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction() - 90)){
for(Position pos : neareat.Body()){
for(int k = 0; k < 5;k++){
for(int r = 2; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
// ans = sqrt(ans);
return ans;
}
```
# go farest place
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t);
float distance_cal(Position, Position);
DirectionType safeDirection(const Snake& snake, const Game&);
int radar[5][5];
};
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
//
bool dir[3] = {true, true, true};
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
if(radar[0][3] == 1 || radar[1][3] == 1){
dir[1] = false;
}
if(radar[3][3] == 1 || radar[4][3] == 1){
dir[2] = false;
}
if(radar[2][4] == 1 || radar[2][3] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][4] == 1 || radar[3][4] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
if(radar[3][3] == 1 || radar[3][4] == 1){
dir[1] = false;
}
if(radar[3][0] == 1 || radar[3][1] == 1){
dir[2] = false;
}
if(radar[3][2] == 1 || radar[4][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[4][1] == 1 || radar[4][3] == 1){
dir[0] = false;
}
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
if(radar[3][1] == 1 || radar[4][1] == 1){
dir[1] = false;
}
if(radar[0][1] == 1 || radar[1][1] == 1){
dir[2] = false;
}
if(radar[2][0] == 1 || radar[2][1] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][0] == 1 || radar[3][0] == 1){
dir[0] = false;
}
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
if(radar[1][0] == 1 || radar[1][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
}
//forward left right
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[2] && dir[1]){
// return safeDirection(game.Snakes().at(id), game);
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else if(dir[2]){
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
// Radar(snake.Head(), _dirSymbol, game, id, );
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(snake.Head(), _dirSymbol, game, id);
float distance_right = GetCollisionDistance(snake.Head(), DirectionSymbol(AngleToSymbol(snake.Direction()+90)), game, id);
float distance_left = GetCollisionDistance(snake.Head(), DirectionSymbol(AngleToSymbol(snake.Direction()-90)), game, id);
float max = distance;
max = std :: max(max, distance_right);
max = std :: max(max, distance_left);
if ((snake.Head().y - 0) < turn_radius*2)
{
if (snake.Direction() == 0)
_turnDirection = DirectionType::kRight;
else
_turnDirection = DirectionType::kLeft;
}
if (abs(snake.Head().y - 2500) < turn_radius*2)
{
if (snake.Direction() == 0)
_turnDirection = DirectionType::kLeft;
else
_turnDirection = DirectionType::kRight;
}
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius*1.2) {
if(max == distance_left){
_currentDirType = DirectionType::kLeft;
_final_angle = snake.Direction() - 90;
}else if(max == distance_right){
_currentDirType = DirectionType::kRight;
_final_angle = snake.Direction() + 90;
}
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
// ans = sqrt(ans);
return ans;
}
```
# Demo this shit
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
DirectionType Radar(Position, DirectionSymbol, Game, size_t, Snake);
float distance_cal(Position, Position);
DirectionType safeDirection(const Snake& snake, const Game&);
void clearPath(Position, Position);
Position lastturnPosition = {2500, 1250};
int radar[5][5];
int path[501][501] = {0};
};
void CustomController::clearPath(Position a, Position b){
Position start = {a.x/50, a.y/50};
Position end = {b.x/50, b.y/50};
if(start.x == end.x){
for(int i = start.y; i <= end.y;i++){
path[i][int(start.x)] = 1;
}
}else if(start.y == end.y){
for(int i = start.x; i <= end.x;i++){
path[int(start.y)][i] = 1;
}
}else{
// std :: cout << "what ?? " << std :: endl;
}
}
DirectionType CustomController::Radar(Position snakeHead, DirectionSymbol _dirSymbol, Game game, size_t id, Snake snake){
float radar_range = turn_radius;
for(int i = 0;i < 5;i++)
for(int j = 0;j < 5;j++)
radar[i][j] = 0;
Position starting_point;
starting_point.x = snakeHead.x - 2*radar_range;
starting_point.y = snakeHead.y - 2*radar_range;
for(int i = 0; i < 5;i++){
for(int j = 0; j < 5;j++){
if(game.FieldWidth() - starting_point.x - j*radar_range < radar_range || starting_point.x + j*radar_range < radar_range){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range || starting_point.y + i*radar_range < radar_range){
radar[i][j] = 1;
}
}
}
float distance = GetCollisionDistance(snakeHead, _dirSymbol, game, id);
float distance_right = GetCollisionDistance(snakeHead, AngleToSymbol(snake.Direction()+90), game, id);
float distance_left = GetCollisionDistance(snakeHead, AngleToSymbol(snake.Direction()-90), game, id);
float max = std :: max(distance, distance_right);
max = std :: max(distance_left, max);
bool dir[3] = {true, true, true};
bool visited[3] = {false, false, false};
int a = snakeHead.x/50, b = snakeHead.y/50;
if(_dirSymbol == DirectionSymbol::RIGHT){
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 2;
if(radar[0][3] == 1 || radar[1][3] == 1 || radar[1][2] == 1){
dir[1] = false;
}
if(radar[3][3] == 1 || radar[4][3] == 1 || radar[3][2] == 1){
dir[2] = false;
}
if(radar[2][4] == 1 || radar[2][3] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][4] == 1 || radar[3][4] == 1){
dir[0] = false;
}
}
if(path[a+1][b-1] == 1){
visited[1] = true;
}
if(path[a+1][b+1] == 1){
visited[2] = true;
}
if(path[a+1][b] == 1){
visited[0] = true;
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
radar[0][2] = 2, radar[1][2] = 2, radar[2][2] = 2;
if(radar[3][3] == 1 || radar[3][4] == 1 || radar[2][3]){
dir[1] = false;
}
if(radar[3][0] == 1 || radar[3][1] == 1 || radar[2][1]){
dir[2] = false;
}
if(radar[3][2] == 1 || radar[4][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[4][1] == 1 || radar[4][3] == 1){
dir[0] = false;
}
}
if(path[a+1][b+1] == 1){
visited[1] = true;
}
if(path[a-1][b+1] == 1){
visited[2] = true;
}
if(path[a][b+1] == 1){
visited[0] = true;
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
radar[2][2] = 2, radar[2][3] = 2, radar[2][4] = 2;
if(radar[3][1] == 1 || radar[4][1] == 1 || radar[3][2] == 1){
dir[1] = false;
}
if(radar[0][1] == 1 || radar[1][1] == 1 || radar[1][2] == 1){
dir[2] = false;
}
if(radar[2][0] == 1 || radar[2][1] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[1][0] == 1 || radar[3][0] == 1){
dir[0] = false;
}
}
if(path[a-1][b+1] == 1){
visited[1] = true;
}
if(path[a-1][b-1] == 1){
visited[2] = true;
}
if(path[a-1][b] == 1){
visited[0] = true;
}
}else{
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
if(radar[1][0] == 1 || radar[1][1] == 1 || radar[2][1] == 1){
dir[1] = false;
}
if(radar[1][3] == 1 || radar[1][4] == 1 || radar[2][3] == 1){
dir[2] = false;
}
if(radar[0][2] == 1 || radar[1][2] == 1){
dir[0] = false;
}
//define dead-end
if(dir[0]){
if(radar[0][1] == 1 || radar[0][3] == 1){
dir[0] = false;
}
}
if(path[a-1][b-1] == 1){
visited[1] = true;
}
if(path[a+1][b-1] == 1){
visited[2] = true;
}
if(path[a][b-1] == 1){
visited[0] = true;
}
}
int cnt = 0;
for(int i = 0; i< 3;i++)
if(visited[i] == false)
cnt++;
if(cnt > 0)
for(int i = 0;i < 3;i++)
dir[i] = (dir[i] && !visited[i]);
if(dir[0]){
return DirectionType::kForward;
}else{
if(dir[1] && dir[2]){
if(distance_left > distance_right){
return DirectionType::kLeft;
}
return DirectionType::kRight;
}else if(dir[1]){
return DirectionType::kLeft;
}else if(dir[2]){
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
lastturnPosition = snake.Head();
}
_currentDirType = DirectionType::kForward;
_currentDirType = Radar(snake.Head(), _dirSymbol, game, id, snake);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
clearPath(lastturnPosition, snake.Head());
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
clearPath(lastturnPosition, snake.Head());
}
return _currentDirType;
}
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
// check front collision distance with other snakes
Snake neareat;
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius, dirSymbol, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
if(distance == d_body){
neareat = anotherSnake;
}
}
}
}
}
float radar_range = turn_radius;
// if(distance > radar_range*5/2){
// return distance;
// }
Position starting_point;
starting_point.x = snakePos.x - 2*radar_range;
starting_point.y = snakePos.y - 2*radar_range;
if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction())){
for(Position pos : neareat.Body()){
for(int k = 0; k < 3;k++){
for(int r = 0; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}else if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction() + 90)){
for(Position pos : neareat.Body()){
for(int k = 0; k < 5;k++){
for(int r = 0; r < 3;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}else if(dirSymbol == AngleToSymbol(game.Snakes().at(id).Direction() - 90)){
for(Position pos : neareat.Body()){
for(int k = 0; k < 5;k++){
for(int r = 2; r < 5;r++){
Position center;
center.x = starting_point.x + r*radar_range;
center.y = starting_point.y + k*radar_range;
if(distance_cal(center, pos) < pow((radar_range - game.kSnakeRadius),2)){
radar[k][r] = 1;
}
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
angle = int(angle) % 360;
if(angle < 0){
angle += 360;
}
// can be converted into 4 directions
return static_cast<DirectionSymbol>(angle/90);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT || dirSymbol == DirectionSymbol::RIGHT) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP || dirSymbol == DirectionSymbol::DOWN) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
float CustomController::distance_cal(Position a, Position b){
float ans = pow((a.x - b.x),2) + pow((a.y - b.y), 2);
// ans = sqrt(ans);
return ans;
}
```
# divide world into small piece of shit
### fucking collision
```cpp=
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT && snakePos.x - target.x > 0) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}else if(dirSymbol == DirectionSymbol::RIGHT && snakePos.x - target.x < 0){
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP && snakePos.y - target.y > 0) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}else if(dirSymbol == DirectionSymbol::DOWN && snakePos.y - target.y < 0){
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
```
# new shit alarm
```cpp=
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection = DirectionType::kRight;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
DirectionSymbol _dirSymbol = AngleToSymbol(_final_angle);
const float turn_radius = 3 * 180 / 3.1415926 + 30;
int A_times = 1;
DirectionSymbol AngleToSymbol(float);
int howManySnake(const Game& game);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetCollisionDistance(DirectionSymbol, const Game&, size_t);//for A
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
void clearPath(Position, Position);
void clearPath(Position);
void markDown(Game, size_t);
Position last_turn = {2500, 1250};
int path[501][501] = {0};
};
void CustomController::clearPath(Position a){
path[int(round(a.x/50))][int(round(a.y/50))] = 1;
return;
}
void CustomController::clearPath(Position a, Position b){
Position start = {round(a.x/50), round(a.y/50)};
Position end = {round(b.x/50), round(b.y/50)};
if(start.x == end.x){
for(int i = start.y; i <= end.y;i++){
path[i][int(start.x)] = 1;
}
}else if(start.y == end.y){
for(int i = start.x; i <= end.x;i++){
path[int(start.y)][i] = 1;
}
}
}
int CustomController::howManySnake(const Game& game){
int amount = 0;
for(auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it){
amount++;
}
return amount;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
int amount = howManySnake(game);
if(amount == 1)
{
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
// finished turning
_dirSymbol = AngleToSymbol(snake.Direction());
}
float distance = GetCollisionDistance(_dirSymbol, game, id);
if (distance > 0 && distance*1.2 < turn_radius + A_times*39.2) {
// start turning around
_currentDirType = _turnDirection;
_final_angle = snake.Direction() + 90;
A_times++;
}else{
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
else
{
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward) {
float remaining_angle = abs(_final_angle - snake.Direction());
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
last_turn = snake.Head();
_dirSymbol = AngleToSymbol(snake.Direction());
_currentDirType = DirectionType::kForward;
}
float distance= GetCollisionDistance(snake.Head() , _dirSymbol, game, id);
float distance_right;
float distance_left;
float predict = turn_radius;
Position rightTurn = { predict , 0 };
Position downTurn = { 0 , predict };
Position leftTurn = { -predict , 0 };
Position upTurn = { 0 , -predict };
if (_dirSymbol == DirectionSymbol::RIGHT) {
distance_right = GetCollisionDistance(snake.Head() +rightTurn , DirectionSymbol::DOWN , game, id);
distance_left = GetCollisionDistance(snake.Head() +rightTurn , DirectionSymbol::UP , game, id);
}
if (_dirSymbol == DirectionSymbol::DOWN) {
distance_right = GetCollisionDistance(snake.Head() +downTurn, DirectionSymbol::LEFT, game, id);
distance_left = GetCollisionDistance(snake.Head() +downTurn, DirectionSymbol::RIGHT, game, id);
}
if (_dirSymbol == DirectionSymbol::LEFT) {
distance_right = GetCollisionDistance(snake.Head() +leftTurn, DirectionSymbol::UP, game, id);
distance_left = GetCollisionDistance(snake.Head() +leftTurn, DirectionSymbol::DOWN, game, id);
}
if (_dirSymbol == DirectionSymbol::UP) {
distance_right = GetCollisionDistance(snake.Head() +upTurn, DirectionSymbol::RIGHT, game, id);
distance_left = GetCollisionDistance(snake.Head() +upTurn, DirectionSymbol::LEFT, game, id);
}
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius* 1.8 ) {
float max = distance;
max = std :: max(max, distance_right);
max = std :: max(max, distance_left);
if(max == distance_left ){
_currentDirType = DirectionType::kLeft;
_final_angle = snake.Direction() - 90;
clearPath(snake.Head(), last_turn);
}else if(max == distance_right ){
_currentDirType = DirectionType::kRight;
_final_angle = snake.Direction() + 90;
clearPath(snake.Head(), last_turn);
}else{
_currentDirType = DirectionType::kForward;
}
}
else {
bool visited[3] = {false, false, false};
int a = snake.Head().x/50, b = snake.Head().y/50;
if(_dirSymbol == DirectionSymbol::RIGHT){
if(path[a+3][b-3] == 1){
visited[1] = true;
}if(path[a+3][b+3] == 1){
visited[2] = true;
}if(path[a+3][b] == 1){
visited[0] = true;
}
}else if(_dirSymbol == DirectionSymbol::DOWN){
if(path[a+3][b+3] == 1){
visited[1] = true;
}if(path[a-3][b+3] == 1){
visited[2] = true;
}if(path[a][b+3] == 1){
visited[0] = true;
}
}else if(_dirSymbol == DirectionSymbol::LEFT){
//Tranposing the matrix
if(path[a-3][b+3] == 1){
visited[1] = true;
}if(path[a-3][b-3] == 1){
visited[2] = true;
}if(path[a-3][b] == 1){
visited[0] = true;
}
}else{
if(path[a-3][b-3] == 1){
visited[1] = true;
}if(path[a+3][b-3] == 1){
visited[2] = true;
}if(path[a][b-3] == 1){
visited[0] = true;
}
}
if(!visited[0]){
return DirectionType::kForward;
}else if(!visited[1]){
_final_angle = snake.Direction() - 90;
clearPath(snake.Head(), last_turn);
_currentDirType = DirectionType::kLeft;
return DirectionType::kLeft;
}else if(!visited[2]){
_final_angle = snake.Direction() + 90;
clearPath(snake.Head(), last_turn);
_currentDirType = DirectionType::kRight;
return DirectionType::kRight;
}
}
}
return DirectionType::kForward;
}
float CustomController::GetCollisionDistance(DirectionSymbol dirSymbol, const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
float distance = FrontWallDistance(snake.Head(), dirSymbol, game.FieldWidth(), game.FieldHeight());
return distance;
}
float CustomController::GetCollisionDistance(Position snakePos, DirectionSymbol dirSymbol, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, dirSymbol, game.FieldWidth(), game.FieldHeight());
//std::cout << "wall_distance" << distance << std::endl;
// check front collision distance with other snakes
for (auto it = game.Snakes().begin(); it != game.Snakes().end(); ++it) {
const size_t anotherID = it->first;
const Snake& anotherSnake = it->second;
if (anotherID == id) continue;
float d = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius*2, dirSymbol, anotherSnake.Head(), Game::kSnakeRadius*2);//Game::kSnakeRadius*2
if (d > 0) {
if (distance < 0) distance = d;
else {
distance = std::min(distance, d);
}
}
for (const Position& pos : anotherSnake.Body()) {
float d_body = GetFrontCollisionDistance(snakePos, Game::kSnakeRadius*2, dirSymbol, pos, Game::kSnakeRadius*2);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
// if angle is not a multiple of 90
angle = int(angle) % 360;
if(angle < 0)
angle += 360;
if (int(angle) % 90 != 0) {
return DirectionSymbol::NONE;
}
// can be converted into 4 directions
int dir = abs(angle / 90);
dir %= 4;
return static_cast<DirectionSymbol>(dir);
}
float CustomController::FrontWallDistance(Position snakeHead, DirectionSymbol dirSymbol, float rightWall, float downWall) {
Position frontFieldCollisionPos{ 0, 0 };
if (dirSymbol == DirectionSymbol::LEFT) {
frontFieldCollisionPos.x = 0;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
frontFieldCollisionPos.x = rightWall;
frontFieldCollisionPos.y = snakeHead.y;
}
else if (dirSymbol == DirectionSymbol::UP) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = 0;
}
else if (dirSymbol == DirectionSymbol::DOWN) {
frontFieldCollisionPos.x = snakeHead.x;
frontFieldCollisionPos.y = downWall;
}
return GetFrontCollisionDistance(snakeHead, Game::kSnakeRadius, dirSymbol, frontFieldCollisionPos, 0);
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, DirectionSymbol dirSymbol, Position target, float targetRadius) {
float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
// if direction is Left/Right
if (dirSymbol == DirectionSymbol::LEFT && snakePos.x - target.x > 0) {
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}else if(dirSymbol == DirectionSymbol::RIGHT && snakePos.x - target.x < 0){
if (distanceY > 0) { // if will not hit target y, return -1
return -1;
}
return distanceX;
}
// if direction is Up/Down
if (dirSymbol == DirectionSymbol::UP && snakePos.y - target.y > 0) {
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}else if(dirSymbol == DirectionSymbol::DOWN && snakePos.y - target.y < 0){
if (distanceX > 0) { // if will not hit target x, return -1
return -1;
}
return distanceY;
}
return -1;
}
```