turn dir

mail@pastecode.io avatar
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