turn dir
unknown
c_cpp
4 years ago
12 kB
8
Indexable
#ifndef DSAP_CUSTOM_CONTROLLER_H
#define DSAP_CUSTOM_CONTROLLER_H
#include "ISnakeController.h"
#include "DirectionType.h"
#include "Snake.h"
////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <vector>
#include <algorithm>
#include <time.h>
#include <random>
class CustomController : public ISnakeController {
public:
DirectionType NextDirection(const Game&, size_t);
DirectionType DecideTurnDirection(const Game&, size_t);
const Position& SnakeHead(const Game& game, const size_t id){return game.Snakes().find(id)->second.Head();};
const std::list<Position> SnakeBodyList(const Game& game, const size_t id){return game.Snakes().find(id)->second.Body();};
const Position& MyHead(const Game& game){return game.Center();};
const Snake Me(const Game& game){return game.Snakes().find(1)->second;};
private:
enum class DirectionSymbol {
RIGHT, DOWN, LEFT, UP, NONE
};
DirectionType _turnDirection;
DirectionType _currentDirType;
float _final_angle = 0;
DirectionSymbol _dirSymbol;
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);
};
bool first = 1;
bool left = true;
DirectionType CustomController::NextDirection(const Game& game, size_t id) {
// Print angle, direction type, and symbol
int H = game.FieldHeight();
int W = game.FieldWidth();
const auto& snake = game.Snakes().at(id);
Position pos = snake.Head();
// 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());
}
std::cout << snake.Direction() << ", " << _final_angle << std::endl;
float distance = GetCollisionDistance(snake.Head(), _dirSymbol, game, id);
// if 0 < distance < min_distance
// std::cout << "Radius: " << turn_radius << std::endl;
if (distance > 0 && distance < turn_radius) {
// start turning around
// TODO: How to turn
_turnDirection = DecideTurnDirection(game, id);
// _turnDirection = DirectionType::kRight;
_currentDirType = _turnDirection;
if (_currentDirType == DirectionType::kRight) {
_final_angle = snake.Direction() + 90;
}
else {
_final_angle = snake.Direction() - 90;
}
}
else {
// no collision problem, just go straight forward
_currentDirType = DirectionType::kForward;
// TODO: if loop
if(snake.Direction() == ){ // if already loop
turn_radius += 300;
// if(snake.Head().x > W - turn_radius && _dirSymbol == DirectionSymbol::DOWN){ // if will collide with right edge
// _turnDirection = DirectionType::kRight;
// _currentDirType = _turnDirection;
// _final_angle = snake.Direction() + 90;
// }
// else if(snake.Head().x > W - turn_radius && _dirSymbol == DirectionSymbol::UP){
// _turnDirection = DirectionType::kLeft;
// _currentDirType = _turnDirection;
// _final_angle = snake.Direction() - 90;
// }
// else if(snake.Head().x < turn_radius && _dirSymbol == DirectionSymbol::DOWN){
// _turnDirection = DirectionType::kLeft;
// _currentDirType = _turnDirection;
// _final_angle = snake.Direction() - 90;
//
// }
// else if(snake.Head().x < turn_radius && _dirSymbol == DirectionSymbol::UP){
// _turnDirection = DirectionType::kRight;
// _currentDirType = _turnDirection;
// _final_angle = snake.Direction() + 90;
//
// }
}
}
return _currentDirType;
//////////////////////////
/////////////////////////////
// int radius = game.kSnakeRadius;
// int H = game.FieldHeight();
// int W = game.FieldWidth();
//
// float wall_dist = FrontWallDistance(pos, _dirSymbol, W, H);
//
// if (wall_dist < WALL_DIST){
// std::cout << "in la " << std::endl;
//
//
// srand(777);
// if(rand()%2 == 0){
// std::cout << "3)" << std::endl;
// _currentDirType = DirectionType::kLeft;
// return DirectionType::kLeft;
// }
// else{
// std::cout << "4)" << std::endl;
// _currentDirType = DirectionType::kRight;
// return DirectionType::kRight;
// }
//
//
//
// }
// else if((pos.y < WALL_DIST && _dirSymbol == DirectionSymbol::UP) || ((pos.y > (H-WALL_DIST)) && _dirSymbol == DirectionSymbol::DOWN) || (pos.x < WALL_DIST && _dirSymbol == DirectionSymbol::LEFT) || ((pos.x > (W-WALL_DIST)) && _dirSymbol == DirectionSymbol::RIGHT) ){}
////////////////////////////////////////////////
} // end of NextDirection
DirectionType CustomController::DecideTurnDirection(const Game& game, size_t id){
if(_dirSymbol == DirectionSymbol::UP){
std::cout << "UP" << std::endl;
}
else if(_dirSymbol == DirectionSymbol::DOWN){
std::cout << "DOWN" << std::endl;
}
else if(_dirSymbol == DirectionSymbol::LEFT){
std::cout << "LEFT" << std::endl;
}
else if(_dirSymbol == DirectionSymbol::RIGHT){
std::cout << "RIGHT" << std::endl;
}
else if(_dirSymbol == DirectionSymbol::NONE){
std::cout << "NONE" << std::endl;
}
float WALL_DIST = 450; // must be greater than 50
const auto& snake = game.Snakes().at(id);
int H = game.FieldHeight();
int W = game.FieldWidth();
Position pos = snake.Head();
std::cout << "(x,y): " << pos.x << ", " << pos.y << std::endl;
std::cout << "(H,W): " << H << ", " << W << std::endl;
std::cout << "WALL DIST" << WALL_DIST << std::endl;
// collide with corner
// if((pos.x < WALL_DIST && pos.y < WALL_DIST && _dirSymbol == DirectionSymbol::UP) ||
// (pos.x < WALL_DIST && pos.y > (H-WALL_DIST) && _dirSymbol == DirectionSymbol::LEFT) ||
// ((pos.x > (W-WALL_DIST)) && pos.y < WALL_DIST && _dirSymbol == DirectionSymbol::RIGHT) ||
// (((pos.x > (W-WALL_DIST)) && pos.y > (H-WALL_DIST) && _dirSymbol == DirectionSymbol::DOWN)))
// { // dir: UP, collide left wall
// std::cout << "1!!!!!" << std::endl;
// return DirectionType::kRight;
// }
// else if((pos.x < WALL_DIST && pos.y < WALL_DIST && _dirSymbol == DirectionSymbol::LEFT) ||
// (pos.x < WALL_DIST && pos.y > (H-WALL_DIST) && _dirSymbol == DirectionSymbol::DOWN) ||
// ((pos.x > (W-WALL_DIST)) && pos.y < WALL_DIST && _dirSymbol == DirectionSymbol::UP) ||
// (((pos.x > (W-WALL_DIST)) && pos.y > (H-WALL_DIST) && _dirSymbol == DirectionSymbol::RIGHT)))
// { // dir: UP, collide left wall
// std::cout << "2!!!!!" << std::endl;
// return DirectionType::kLeft;
// }
//
// // collide with edge
// else{
// if(left == true){
// std::cout << "3!!!!!" << std::endl;
// left = false;
// return DirectionType::kLeft;
// }
// else{
// std::cout << "4!!!!!" << std::endl;
// left = true;
// return DirectionType::kRight;
// }
//
//
// }
}
CustomController::DirectionSymbol CustomController::AngleToSymbol(float angle) {
while(angle < 0){
angle += 360;
}
// 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::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 * 2, dirSymbol, 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, dirSymbol, 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, 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);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // DSAP_CUSTOM_CONTROLLER_H
Editor is loading...