turn dir
unknown
c_cpp
2 years ago
12 kB
0
Indexable
Never
#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