`
```cpp=
// [YOUR CODE WILL BE PLACED HERE]
#include <cmath>
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
DirectionType _turnDirection = DirectionType::kLeft;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
const float turn_radius = 3 * 180 / 3.1415926 + 30;
float snakeAngle = 0;
float GetCollisionDistance(Position, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, Position, float);
float FrontWallDistance(Position, const Game&, size_t);
float distance_cal(Position, Position);
int getAngle(Position, Position);
};
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;
}
int CustomController::getAngle(Position a, Position b){
float del_x = b.x - a.x;
float del_y = b.y - a.y;
float tan = del_y/del_x;
int angle = 0;
if(del_x >=0 && del_y >= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28);
}else if(del_x < 0 && del_y > 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else if(del_x <= 0 && del_y <= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else{
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 360;
}
return angle;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward)
{
//std::cout << "finalAngle"<<_final_angle << std::endl;
float remaining_angle = abs(_final_angle - snake.Direction());
//std::cout << "remaining"<<remaining_angle << std::endl;
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
}
_currentDirType = DirectionType::kForward;
float distance = GetCollisionDistance(snake.Head(), game, id);
if ((snake.Head().y - 0) < turn_radius*2)
{
if ((snake.Head().x - 0) < turn_radius*2)
{
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kLeft;
}
if (abs(snake.Head().x - game.FieldWidth()) < turn_radius*2)
{
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kRight;
}
}
if (abs(snake.Head().y - game.FieldHeight()) < turn_radius*2)
{
if ((snake.Head().x - 0) < turn_radius*2)
{
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kRight;
}
else if (abs(snake.Head().x - game.FieldWidth()) < turn_radius*2)
{
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kLeft;
}
else
{
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kRight;
}
}
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}
else {
// no collision problem, just go straight forward
std :: vector<Food> foods = game.Foods();
Position foodsPosition;
float max_distance = game.FieldWidth();
for(int i = 0;i < foods.size();i++)
{
if(max_distance > distance_cal(snake.Head(), foods[i].position))
{
max_distance = distance_cal(snake.Head(), foods[i].position);
foodsPosition = foods[i].position;
}
}
_final_angle = getAngle(snake.Head() , foodsPosition);
if(_final_angle < snake.Direction())
_currentDirType = DirectionType::kLeft;
else if (_final_angle > snake.Direction())
_currentDirType = DirectionType::kRight;
else
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
float CustomController::GetCollisionDistance(Position snakePos, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, game, id);
// 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, anotherSnake.Head(), 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, pos, Game::kSnakeRadius);
// if (d_body > 0) {
// if (distance < 0) distance = d_body;
// else {
// distance = std::min(distance, d_body);
// }
// }
//
// }
//
// }
return distance;
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, Position target, float targetRadius) {
// float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
// float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
return 0;
}
float CustomController::FrontWallDistance(Position snakeHead, const Game& game, size_t id) {
auto snake = game.Snakes().at(id);
float a = tan(snake.Direction()/360*2*3.14), b = 0;
b = snakeHead.y - a*snakeHead.x;
float distance = 0;
if(snake.Direction() > 0 && snake.Direction() < 90){
//y = height, x = width
size_t y = game.FieldHeight();
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 90 && snake.Direction() < 180){
//y = height, x = 0
size_t y = game.FieldHeight();
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 180 && snake.Direction() < 270){
//y = 0, x = 0
size_t y = 0;
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 270 && snake.Direction() < 360){
//y = 0, x = width
size_t y = 0;
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else{
if(snake.Direction() == 0){
return game.FieldWidth() - snakeHead.x;
}else if(snake.Direction() == 90){
return game.FieldHeight() - snakeHead.y;
}else if(snake.Direction() == 180){
return snakeHead.x;
}else if(snake.Direction() == 270){
return snakeHead.y;
}
}
return distance;
}
```
```cpp=
#include <cmath>
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
DirectionType _turnDirection = DirectionType::kLeft;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
const float turn_radius = 3 * 180 / 3.1415926 + 30;
float GetCollisionDistance(Position, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, Position, float);
float FrontWallDistance(Position, const Game&, size_t);
float distance_cal(Position, Position);
int getAngle(Position, Position);
};
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;
}
int CustomController::getAngle(Position a, Position b){
float del_x = b.x - a.x;
float del_y = b.y - a.y;
float tan = del_y/del_x;
int angle = 0;
if(del_x >=0 && del_y >= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28);
}else if(del_x < 0 && del_y > 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else if(del_x <= 0 && del_y <= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else{
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 360;
}
return angle;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward)
{
//std::cout << "finalAngle"<<_final_angle << std::endl;
float remaining_angle = abs(_final_angle - snake.Direction());
//std::cout << "remaining"<<remaining_angle << std::endl;
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
}
_currentDirType = DirectionType::kForward;
float distance = GetCollisionDistance(snake.Head(), game, id);
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kLeft;
}else {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kRight;
}
}else {
// no collision problem, just go straight forward
// std :: vector<Food> foods = game.Foods();
// Position foodsPosition;
// float max_distance = game.FieldWidth();
// for(int i = 0;i < foods.size();i++)
// {
// if(max_distance > distance_cal(snake.Head(), foods[i].position))
// {
// max_distance = distance_cal(snake.Head(), foods[i].position);
// foodsPosition = foods[i].position;
// }
// }
// _final_angle = getAngle(snake.Head() , foodsPosition);
// if(_final_angle < snake.Direction())
// _currentDirType = DirectionType::kLeft;
// else if (_final_angle > snake.Direction())
// _currentDirType = DirectionType::kRight;
// else
// _currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
float CustomController::GetCollisionDistance(Position snakePos, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, game, id);
// 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, anotherSnake.Head(), 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, pos, Game::kSnakeRadius);
// if (d_body > 0) {
// if (distance < 0) distance = d_body;
// else {
// distance = std::min(distance, d_body);
// }
// }
//
// }
//
// }
return distance;
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, Position target, float targetRadius) {
// float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
// float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
return 0;
}
float CustomController::FrontWallDistance(Position snakeHead, const Game& game, size_t id) {
auto snake = game.Snakes().at(id);
float a = tan(snake.Direction()/360*2*3.14), b = 0;
b = snakeHead.y - a*snakeHead.x;
float distance = 0;
if(snake.Direction() > 0 && snake.Direction() < 90){
//y = height, x = width
size_t y = game.FieldHeight();
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 90 && snake.Direction() < 180){
//y = height, x = 0
size_t y = game.FieldHeight();
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 180 && snake.Direction() < 270){
//y = 0, x = 0
size_t y = 0;
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake.Direction() > 270 && snake.Direction() < 360){
//y = 0, x = width
size_t y = 0;
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else{
if(snake.Direction() == 0){
return game.FieldWidth() - snakeHead.x;
}else if(snake.Direction() == 90){
return game.FieldHeight() - snakeHead.y;
}else if(snake.Direction() == 180){
return snakeHead.x;
}else if(snake.Direction() == 270){
return snakeHead.y;
}
}
return distance;
}
```
```cpp=
#include <cmath>
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
DirectionType _turnDirection = DirectionType::kLeft;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
const float turn_radius = 3 * 180 / 3.1415926 + 30;
float GetCollisionDistance(Position, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, Position, float);
float FrontWallDistance(Position, const Game&, size_t);
float distance_cal(Position, Position);
float SnakeDirection = 0;
int getAngle(Position, Position);
};
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;
}
int CustomController::getAngle(Position a, Position b){
float del_x = b.x - a.x;
float del_y = b.y - a.y;
float tan = del_y/del_x;
int angle = 0;
if(del_x >=0 && del_y >= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28);
}else if(del_x < 0 && del_y > 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else if(del_x <= 0 && del_y <= 0){
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 180;
}else{
angle = static_cast<int>(atan(tan)* 360 / 6.28) + 360;
}
return angle;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward)
{
//std::cout << "finalAngle"<<_final_angle << std::endl;
float remaining_angle = abs(_final_angle - snake.Direction());
//std::cout << "remaining"<<remaining_angle << std::endl;
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
}
_currentDirType = DirectionType::kForward;
float distance = GetCollisionDistance(snake.Head(), game, id);
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}else {
// no collision problem, just go straight forward
// std :: vector<Food> foods = game.Foods();
// Position foodsPosition;
// float max_distance = game.FieldWidth();
// for(int i = 0;i < foods.size();i++)
// {
// if(max_distance > distance_cal(snake.Head(), foods[i].position))
// {
// max_distance = distance_cal(snake.Head(), foods[i].position);
// foodsPosition = foods[i].position;
// }
// }
// _final_angle = getAngle(snake.Head() , foodsPosition);
// if(_final_angle < snake.Direction())
// _currentDirType = DirectionType::kLeft;
// else if (_final_angle > snake.Direction())
// _currentDirType = DirectionType::kRight;
// else
// _currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
float CustomController::GetCollisionDistance(Position snakePos, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, game, id);
// 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, anotherSnake.Head(), 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, pos, Game::kSnakeRadius);
// if (d_body > 0) {
// if (distance < 0) distance = d_body;
// else {
// distance = std::min(distance, d_body);
// }
// }
//
// }
//
// }
return distance;
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, Position target, float targetRadius) {
// float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
// float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
return 0;
}
float CustomController::FrontWallDistance(Position snakeHead, const Game& game, size_t id) {
auto snake = game.Snakes().at(id);
int snake_dir = static_cast<int>(snake.Direction())%360;
if(snake_dir < 0){
snake_dir += 360;
}
float a = tan(snake_dir/360*2*3.14), b = 0;
b = snakeHead.y - a*snakeHead.x;
float distance = 0;
if(snake_dir > 0 && snake_dir < 90){
//y = height, x = width
size_t y = game.FieldHeight();
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 90 && snake_dir < 180){
//y = height, x = 0
size_t y = game.FieldHeight();
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 180 && snake_dir < 270){
//y = 0, x = 0
size_t y = 0;
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 270 && snake_dir < 360){
//y = 0, x = width
size_t y = 0;
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
return distance_cal(point_a, snakeHead);
}else{
return distance_cal(point_a, snakeHead);
}
}else{
if(snake_dir == 0){
return game.FieldWidth() - snakeHead.x;
}else if(snake_dir == 90){
return game.FieldHeight() - snakeHead.y;
}else if(snake_dir == 180){
return snakeHead.x;
}else if(snake_dir == 270){
return snakeHead.y;
}
}
return distance;
}
```
2023.5.31 14:56
```cpp=
#include <cmath>
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t) override;
private:
DirectionType _turnDirection = DirectionType::kLeft;
DirectionType _currentDirType = DirectionType::kForward;
float _final_angle = 0;
const float turn_radius = 3 * 180 / 3.1415926 + 30;
float GetCollisionDistance(Position, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, Position, float);
float FrontWallDistance(Position, const Game&, size_t);
float distance_cal(Position, Position);
float SnakeDirection = 0;
int wall = 0;
int getAngle(Position, Position);
};
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;
}
int CustomController::getAngle(Position a, Position b){
float del_x = b.x - a.x;
float del_y = b.y - a.y;
float tan = del_y/del_x;
int angle = 0;
if(del_x >=0 && del_y >= 0){
angle = static_cast<int>(atan(tan)* 360 / (3.14159265359*2));
}else if(del_x < 0 && del_y > 0){
angle = static_cast<int>(atan(tan)* 360 / (3.14159265359*2)) + 180;
}else if(del_x <= 0 && del_y <= 0){
angle = static_cast<int>(atan(tan)* 360 / (3.14159265359*2)) + 180;
}else{
angle = static_cast<int>(atan(tan)* 360 / (3.14159265359*2)) + 360;
}
return angle;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// if is turning around
// keep turning
if (_currentDirType != DirectionType::kForward)
{
//std::cout << "finalAngle"<<_final_angle << std::endl;
float remaining_angle = abs(_final_angle - snake.Direction());
//std::cout << "remaining"<<remaining_angle << std::endl;
if (remaining_angle > 0) { //still turning
return _currentDirType;
}
}
_currentDirType = DirectionType::kForward;
float distance = GetCollisionDistance(snake.Head(), game, id);
int snake_dir = static_cast<int>(snake.Direction())%360;
if(snake_dir < 0){
snake_dir += 360;
}
// if 0 < distance < min_distance
if (distance > 0 && distance < turn_radius) {
if(wall == 1){
if(snake.Head().x > game.FieldWidth() - snake.Head().x){
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kRight;
}else{
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kLeft;
}
}else if(wall == 2){
if(snake.Head().y > game.FieldHeight() - snake.Head().y){
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kLeft;
}else{
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kRight;
}
}else if(wall == 3){
if(snake.Head().x < game.FieldWidth() - snake.Head().x){
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kRight;
}else{
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kLeft;
}
}else if(wall == 4){
if(snake.Head().y < game.FieldHeight() - snake.Head().y){
_final_angle = snake.Direction() - 180;
_currentDirType = DirectionType::kLeft;
}else{
_final_angle = snake.Direction() + 180;
_currentDirType = DirectionType::kRight;
}
}
// if(snake_dir > 0 && snake_dir < 90){
// if(wall == 2){
// _final_angle = snake.Direction() + 180 - 2*snake_dir;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() - 2*snake_dir;
// _currentDirType = DirectionType::kLeft;
// }
// }else if(snake_dir > 90 && snake_dir < 180){
// if(wall == 1){
// _final_angle = snake.Direction() + 360 - 2*snake_dir;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() - 2*snake_dir + 180;
// _currentDirType = DirectionType::kLeft;
// }
// }else if(snake_dir > 180 && snake_dir < 270){
// if(wall == 4){
// _final_angle = snake.Direction() - 2*snake_dir + 540;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() + 360 - 2*snake_dir;
// _currentDirType = DirectionType::kLeft;
// }
// }else if(snake_dir > 270 && snake_dir < 360){
// if(wall == 3){
// _final_angle = snake.Direction() + 720 - 2*snake_dir;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() +540 - 2*snake_dir;
// _currentDirType = DirectionType::kLeft;
// }
// }else{
// if(snake_dir == 0){
// if(snake.Head().y > game.FieldHeight() - snake.Head().y){
// _final_angle = snake.Direction() - 180;
// _currentDirType = DirectionType::kLeft;
// }else{
// _final_angle = snake.Direction() + 180;
// _currentDirType = DirectionType::kRight;
// }
// }else if(snake_dir == 90){
// if(snake.Head().x > game.FieldWidth() - snake.Head().x){
// _final_angle = snake.Direction() + 180;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() - 180;
// _currentDirType = DirectionType::kLeft;
// }
// }else if(snake_dir == 180){
// if(snake.Head().y < game.FieldHeight() - snake.Head().y){
// _final_angle = snake.Direction() - 180;
// _currentDirType = DirectionType::kLeft;
// }else{
// _final_angle = snake.Direction() + 180;
// _currentDirType = DirectionType::kRight;
// }
// }else if(snake_dir == 270){
// if(snake.Head().x < game.FieldWidth() - snake.Head().x){
// _final_angle = snake.Direction() + 180;
// _currentDirType = DirectionType::kRight;
// }else{
// _final_angle = snake.Direction() - 180;
// _currentDirType = DirectionType::kLeft;
// }
// }
// }
}else {
// no collision problem, just go straight forward
std :: vector<Food> foods = game.Foods();
Position foodsPosition;
float max_distance = game.FieldWidth();
for(int i = 0;i < foods.size();i++)
{
if(max_distance > distance_cal(snake.Head(), foods[i].position))
{
max_distance = distance_cal(snake.Head(), foods[i].position);
foodsPosition = foods[i].position;
}
}
_final_angle = getAngle(snake.Head() , foodsPosition);
if(_final_angle < snake.Direction())
_currentDirType = DirectionType::kLeft;
else if (_final_angle > snake.Direction())
_currentDirType = DirectionType::kRight;
else
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
float CustomController::GetCollisionDistance(Position snakePos, const Game& game, size_t id) {
// check front collision distance with field
float distance = FrontWallDistance(snakePos, game, id);
// 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, anotherSnake.Head(), 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, pos, Game::kSnakeRadius);
if (d_body > 0) {
if (distance < 0) distance = d_body;
else {
distance = std::min(distance, d_body);
}
}
}
}
return distance;
}
float CustomController::GetFrontCollisionDistance(Position snakePos, float snakeRadius, Position target, float targetRadius) {
// float distanceX = abs(snakePos.x - target.x) - snakeRadius - targetRadius;
// float distanceY = abs(snakePos.y - target.y) - snakeRadius - targetRadius;
return 0;
}
float CustomController::FrontWallDistance(Position snakeHead, const Game& game, size_t id) {
auto snake = game.Snakes().at(id);
int snake_dir = static_cast<int>(snake.Direction())%360;
if(snake_dir < 0){
snake_dir += 360;
}
float a = tan(snake_dir*(3.14159265359/180)), b = snakeHead.y - a*snakeHead.x;
if(snake_dir > 0 && snake_dir < 90){
//y = height, x = width
size_t y = game.FieldHeight();
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
wall = 2;
return distance_cal(point_b, snakeHead);
}else{
wall = 1;
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 90 && snake_dir < 180){
//y = height, x = 0
size_t y = game.FieldHeight();
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
wall = 4;
return distance_cal(point_b, snakeHead);
}else{
wall = 1;
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 180 && snake_dir < 270){
//y = 0, x = 0
size_t y = 0;
size_t x = 0;
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
wall = 4;
return distance_cal(point_b, snakeHead);
}else{
wall = 3;
return distance_cal(point_a, snakeHead);
}
}else if(snake_dir > 270 && snake_dir < 360){
//y = 0, x = width
size_t y = 0;
size_t x = game.FieldWidth();
Position point_a;
Position point_b;
point_a.x = (y - b)/a;
point_a.y = y;
point_b.x = x;
point_b.y = a*x + b;
if(distance_cal(point_a, snakeHead) >= distance_cal(point_b, snakeHead)){
wall = 2;
return distance_cal(point_b, snakeHead);
}else{
wall = 3;
return distance_cal(point_a, snakeHead);
}
}else{
if(snake_dir == 0){
return game.FieldWidth() - snakeHead.x;
}else if(snake_dir == 90){
return game.FieldHeight() - snakeHead.y;
}else if(snake_dir == 180){
return snakeHead.x;
}else if(snake_dir == 270){
return snakeHead.y;
}
}
return 0;
}
```
```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;
DirectionSymbol AngleToSymbol(float);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
};
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// 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 ((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) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
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;
}
// can be converted into 4 directions
int dir = abs(angle / 90);
dir %= 4;
return static_cast<DirectionSymbol>(dir);
}
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::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);
}
```
2023.5.31 9:51
```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;
DirectionSymbol AngleToSymbol(float);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
//game::snakeradius
bool FrontFood(Position, DirectionSymbol, Game);
};
bool CustomController::FrontFood(const Position snakeHead, DirectionSymbol dirSymbol, Game game){
std :: vector<Food> foods = game.Foods();
if (dirSymbol == DirectionSymbol::LEFT) {
for(Food p : foods){
if(p.position.y < snakeHead.y + game.kSnakeRadius/2 && p.position.y > snakeHead.y - game.kSnakeRadius/2){
if(p.position.x < snakeHead.x){
return true;
}
}
}
}
else if (dirSymbol == DirectionSymbol::RIGHT) {
for(Food p : foods){
if(p.position.y < snakeHead.y + game.kSnakeRadius/2 && p.position.y > snakeHead.y - game.kSnakeRadius/2){
if(p.position.x > snakeHead.x){
return true;
}
}
}
}
else if (dirSymbol == DirectionSymbol::UP) {
for(Food p : foods){
if(p.position.x < snakeHead.x + game.kSnakeRadius/2 && p.position.x > snakeHead.x - game.kSnakeRadius/2){
if(p.position.y > snakeHead.y){
return true;
}
}
}
}
else if (dirSymbol == DirectionSymbol::DOWN) {
for(Food p : foods){
if(p.position.x < snakeHead.x + game.kSnakeRadius/2 && p.position.x > snakeHead.x - game.kSnakeRadius/2){
if(p.position.y < snakeHead.y){
return true;
}
}
}
}
return false;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// 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 ((snake.Head().y - 0) < turn_radius*2)
{
if (snake.Direction() == 0)
_turnDirection = DirectionType::kRight;
else
_turnDirection = DirectionType::kLeft;
}
if (abs(snake.Head().y - game.FieldHeight()) < 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) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}else {
// no collision problem, just go straight forward
if(!FrontFood(snake.Head(), _dirSymbol, game)){
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}else{
_currentDirType = DirectionType::kForward;
}
}
return _currentDirType;
}
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;
}
// can be converted into 4 directions
int dir = abs(angle / 90);
dir %= 4;
return static_cast<DirectionSymbol>(dir);
}
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::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);
}
```
```cpp=
if ((snake.Head().y - 0) < turn_radius*2)
{
if (snake.Direction() == 0){
_turnDirection = DirectionType::kRight;
_final_angle = snake.Direction() + 90;
}else{
_turnDirection = DirectionType::kLeft;
_final_angle = snake.Direction() - 90;
}
}
if (abs(snake.Head().y - game.FieldHeight()) < turn_radius*2)
{
if (snake.Direction() == 0){
_turnDirection = DirectionType::kLeft;
_final_angle = snake.Direction() + 90;
}else{
_turnDirection = DirectionType::kRight;
_final_angle = snake.Direction() - 90;
}
}
```
2023.5.31 11:39
```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;
DirectionSymbol AngleToSymbol(float);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
//game::snakeradius
bool FrontFood(Position, DirectionSymbol, Game);
DirectionType turnSide(Position, DirectionSymbol, Game);
};
DirectionType CustomController::turnSide(Position snakeHead, DirectionSymbol dirSymbol, Game game){
if (dirSymbol == DirectionSymbol::LEFT) {
if(snakeHead.y > game.FieldHeight() - snakeHead.y){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}else if (dirSymbol == DirectionSymbol::RIGHT) {
if(snakeHead.y < game.FieldHeight() - snakeHead.y){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}else if (dirSymbol == DirectionSymbol::UP) {
if(snakeHead.x > game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}else if (dirSymbol == DirectionSymbol::DOWN) {
if(snakeHead.x < game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
bool CustomController::FrontFood(const Position snakeHead, DirectionSymbol dirSymbol, Game game){
std :: vector<Food> foods = game.Foods();
if (dirSymbol == DirectionSymbol::LEFT) {
for(Food p : foods){
if(p.position.y <= snakeHead.y + game.kSnakeRadius/2 && p.position.y >= snakeHead.y - game.kSnakeRadius/2){
if(p.position.x < snakeHead.x){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::RIGHT) {
for(Food p : foods){
if(p.position.y <= snakeHead.y + game.kSnakeRadius/2 && p.position.y >= snakeHead.y - game.kSnakeRadius/2){
if(p.position.x > snakeHead.x){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::UP) {
for(Food p : foods){
if(p.position.x <= snakeHead.x + game.kSnakeRadius/2 && p.position.x >= snakeHead.x - game.kSnakeRadius/2){
if(p.position.y > snakeHead.y){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::DOWN) {
for(Food p : foods){
if(p.position.x <= snakeHead.x + game.kSnakeRadius/2 && p.position.x >= snakeHead.x - game.kSnakeRadius/2){
if(p.position.y < snakeHead.y){
return true;
}
}
}
}
return false;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// 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.2) {
// start turning around
_currentDirType = turnSide(snake.Head(), _dirSymbol, game);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 180;
}else{
_final_angle = snake.Direction() - 180;
}
// _currentDirType = _turnDirection;
// if (_currentDirType == DirectionType::kRight) {
// _final_angle = snake.Direction() + 180;
// _turnDirection = DirectionType::kLeft;
// }else {
// _final_angle = snake.Direction() - 180;
// _turnDirection = DirectionType::kRight;
// }
}else {
// no collision problem, just go straight forward
if(!FrontFood(snake.Head(), _dirSymbol, game)){
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}else{
_currentDirType = DirectionType::kForward;
}
}
return _currentDirType;
}
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::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::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);
}
```
2023.6.1 3:43
```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;
DirectionSymbol AngleToSymbol(float);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
//game::snakeradius
bool FrontFood(Position, DirectionSymbol, Game);
DirectionType turnSide(Position, DirectionSymbol, Game);
DirectionType foodAmount(Position, DirectionSymbol, Game);
};
DirectionType CustomController::foodAmount(Position snakeHead, DirectionSymbol dirSymbol, Game game){
std :: vector<int> food_amounts(2);
std :: vector<Food> foods = game.Foods();
for(Food p : foods){
if(p.position.y <= snakeHead.y + game.kSnakeRadius/2 && p.position.y >= snakeHead.y - game.kSnakeRadius/2){
food_amounts[0]++;
}
if(p.position.x <= snakeHead.x + game.kSnakeRadius/2 && p.position.x >= snakeHead.x - game.kSnakeRadius/2){
food_amounts[1]++;
}
if(food_amounts[0] > food_amounts[1]){
if (dirSymbol == DirectionSymbol::LEFT) {
return DirectionType::kForward;
}else if (dirSymbol == DirectionSymbol::RIGHT) {
return DirectionType::kForward;
}else if (dirSymbol == DirectionSymbol::UP) {
if(snakeHead.x > game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}else if (dirSymbol == DirectionSymbol::DOWN) {
if(snakeHead.x < game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}
}else{
if (dirSymbol == DirectionSymbol::LEFT) {
if(snakeHead.y > game.FieldHeight() - snakeHead.y){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}else if (dirSymbol == DirectionSymbol::RIGHT) {
if(snakeHead.y > game.FieldHeight() - snakeHead.y){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}else if (dirSymbol == DirectionSymbol::UP) {
return DirectionType::kForward;
}else if (dirSymbol == DirectionSymbol::DOWN) {
return DirectionType::kForward;
}
}
}
return DirectionType::kForward;
}
DirectionType CustomController::turnSide(Position snakeHead, DirectionSymbol dirSymbol, Game game){
if (dirSymbol == DirectionSymbol::LEFT) {
if(snakeHead.y > game.FieldHeight() - snakeHead.y){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}else if (dirSymbol == DirectionSymbol::RIGHT) {
if(snakeHead.y < game.FieldHeight() - snakeHead.y){
return DirectionType::kRight;
}else{
return DirectionType::kLeft;
}
}else if (dirSymbol == DirectionSymbol::UP) {
if(snakeHead.x > game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}else if (dirSymbol == DirectionSymbol::DOWN) {
if(snakeHead.x < game.FieldWidth() - snakeHead.x){
return DirectionType::kLeft;
}else{
return DirectionType::kRight;
}
}
return DirectionType::kForward;
}
bool CustomController::FrontFood(const Position snakeHead, DirectionSymbol dirSymbol, Game game){
std :: vector<Food> foods = game.Foods();
if (dirSymbol == DirectionSymbol::LEFT) {
for(Food p : foods){
if(p.position.y <= snakeHead.y + game.kSnakeRadius/2 && p.position.y >= snakeHead.y - game.kSnakeRadius/2){
if(p.position.x < snakeHead.x){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::RIGHT) {
for(Food p : foods){
if(p.position.y <= snakeHead.y + game.kSnakeRadius/2 && p.position.y >= snakeHead.y - game.kSnakeRadius/2){
if(p.position.x > snakeHead.x){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::UP) {
for(Food p : foods){
if(p.position.x <= snakeHead.x + game.kSnakeRadius/2 && p.position.x >= snakeHead.x - game.kSnakeRadius/2){
if(p.position.y > snakeHead.y){
return true;
}
}
}
}else if (dirSymbol == DirectionSymbol::DOWN) {
for(Food p : foods){
if(p.position.x <= snakeHead.x + game.kSnakeRadius/2 && p.position.x >= snakeHead.x - game.kSnakeRadius/2){
if(p.position.y < snakeHead.y){
return true;
}
}
}
}
return false;
}
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// 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.2) {
// start turning around
_currentDirType = turnSide(snake.Head(), _dirSymbol, game);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 180;
}else{
_final_angle = snake.Direction() - 180;
}
// _currentDirType = _turnDirection;
// if (_currentDirType == DirectionType::kRight) {
// _final_angle = snake.Direction() + 180;
// _turnDirection = DirectionType::kLeft;
// }else {
// _final_angle = snake.Direction() - 180;
// _turnDirection = DirectionType::kRight;
// }
}else {
// no collision problem, just go straight forward
// if(!FrontFood(snake.Head(), _dirSymbol, game)){
// _currentDirType = turnSide(snake.Head(), _dirSymbol, game);
// if(_currentDirType == DirectionType::kRight){
// _final_angle = snake.Direction() + 90;
// }else{
// _final_angle = snake.Direction() - 90;
// }
// }else{
// _currentDirType = DirectionType::kForward;
// }
_currentDirType = foodAmount(snake.Head(), _dirSymbol, game);
if(_currentDirType == DirectionType::kRight){
_final_angle = snake.Direction() + 90;
}else if(_currentDirType == DirectionType::kLeft){
_final_angle = snake.Direction() - 90;
}
}
return _currentDirType;
}
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::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::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);
}
```
### version 837
```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;
DirectionSymbol AngleToSymbol(float);
float GetCollisionDistance(Position, DirectionSymbol, const Game&, size_t);
float GetFrontCollisionDistance(Position, float, DirectionSymbol, Position, float);
float FrontWallDistance(Position, DirectionSymbol, float, float);
};
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
const auto& snake = game.Snakes().at(id);
// 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 ((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) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
}
return _currentDirType;
}
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;
}
// can be converted into 4 directions
int dir = abs(angle / 90);
dir %= 4;
return static_cast<DirectionSymbol>(dir);
}
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::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);
}
```
### 2023.6.1 VERSION 954
```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);
};
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());
}
float distance = GetCollisionDistance(snake.Head(), _dirSymbol, game, id);
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) {
// start turning around
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 180;
_turnDirection = DirectionType::kLeft;
}
else {
_final_angle = snake.Direction() - 180;
_turnDirection = DirectionType::kRight;
}
}
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;
}
// 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;
}
```
radar version
```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] = {0};
};
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/2 || starting_point.x + j*radar_range < radar_range/2){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range/2 || starting_point.y + i*radar_range < radar_range/2){
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(i == id){
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 + i*radar_range;
if(distance_cal(center, p) < radar_range){
radar[k][r] = 1;
}
}
}
}
}
if(int(game.Snakes().at(id).Direction()/9)%4 == 0){
for(int q = 0;q < 3;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(int(game.Snakes().at(id).Direction()/9)%4 == 1){
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(int(game.Snakes().at(id).Direction()/9)%4 == 2){
//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]);
}
}
}
radar[2][2] = 2, radar[3][2] = 2, radar[4][2] = 2;
//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[1][1] == 1 || radar[1][3] == 1){
dir[0] = false;
}
// if(radar[2][3] == 1 || radar[2][4] == 1){
// dir[0] = false;
// }
// if(radar[3][2] == 1 || radar[3][1] == 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;
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[0]){
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;
// std :: cout << FrontWallDistance(snake.Head(), _dirSymbol, game.FieldWidth(), game.FieldHeight()) << std :: endl;
// std :: cout << GetCollisionDistance(snake.Head(), _dirSymbol, game, id) << std :: endl;
_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;
}
// 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;
}
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;
}
```
```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] = {0};
};
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/2 || starting_point.x + j*radar_range < radar_range/2){
radar[i][j] = 1;
}else if(game.FieldHeight() - starting_point.y - i*radar_range < radar_range/2 || starting_point.y + i*radar_range < radar_range/2){
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(i == id){
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){
radar[k][r] = 1;
}
}
}
}
}
if(int(abs(game.Snakes().at(id).Direction())/90)%4 == 0){
for(int q = 0;q < 3;q++){
//Tranposing the matrix
radar[2][2] = 2, radar[2][1] = 2, radar[2][0] = 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 if(int(abs(game.Snakes().at(id).Direction())/90)%4 == 1){
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(int(abs(game.Snakes().at(id).Direction())/90)%4 == 2){
//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(radar[2][1] == 1 || radar[2][3] == 1){
dir[0] = false;
}
if(radar[3][1] == 1 || radar[3][3] == 1){
dir[0] = false;
}
}
if(dir[0]){
//not in danger
return DirectionType::kForward;
}else{
if(dir[0]){
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 _cur