Skip to content

Instantly share code, notes, and snippets.

@raptium
Created May 22, 2010 21:50
Show Gist options
  • Save raptium/410393 to your computer and use it in GitHub Desktop.
Save raptium/410393 to your computer and use it in GitHub Desktop.
#include "Tank.h"
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <climits>
#include <cmath>
namespace net {
namespace raptium {
// Operator Overloading for sturct Points
bool operator== (Point a, Point b) {
return (a.col == b.col && a.row == b.row);
}
Point operator-(Point a, Point b) {
Point p;
p.row = a.row - b.row;
p.col = a.col - b.col;
return p;
}
Point operator+(Point a, Point b) {
Point p;
p.row = a.row + b.row;
p.col = a.col + b.col;
return p;
}
Point operator*(Point a, int b) {
Point p;
p.row = a.row * b;
p.col = a.col * b;
return p;
}
class Tank {
protected:
int **_costs;
short _id;
DataForAI _data;
Point offset[4];
void nextStep(Point start);
void init();
public:
Point position;
Tank();
Tank(DataForAI data);
~Tank();
void update(DataForAI data);
void print();
static OrderType nextDirection(Point start, Point end);
bool detectCollision(Point next);
CellType detectCellType(Point p);
Point findNextPoint(Point end);
Point destination;
Point next;
int cost;
virtual Point findTarget();
virtual Point findDestination();
virtual Order makeOrder();
};
class TankPioneer : Tank {
public:
Point findTarget();
//Order makeOrder();
};
class TankSniper : Tank {
public:
Order makeOrder();
};
class StupidAI {
void solveCollision();
public:
StupidAI();
~StupidAI();
InitiateInfo getInitInfo();
Order makeOrder(DataForAI data);
Tank *tanks[5];
static bool isValidPoint(Point p);
};
}
}
using namespace net::raptium;
static StupidAI *AI;
Tank::Tank() {
init();
}
Tank::Tank(DataForAI data) {
init();
update(data);
}
void Tank::init() {
// init offset array
offset[0].col = 0;
offset[0].row = -1;
offset[1].col = 0;
offset[1].row = +1;
offset[2].col = -1;
offset[2].row = 0;
offset[3].col = +1;
offset[3].row = 0;
this->_costs = NULL;
}
void Tank::update(DataForAI data) {
_data = data;
_id = data.myID % 5;
if(_costs == NULL) {
_costs = new int *[MAP_HEIGHT + 2];
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
_costs[i] = new int[MAP_WIDTH + 2];
}
}
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
for(int j = 0;j < MAP_WIDTH + 2;j++) {
switch(data.map[i][j].type) {
case STONE:
_costs[i][j] = -1;
break;
default:
_costs[i][j] = INT_MAX;
}
}
}
Point tank_pos;
tank_pos.col = data.tank[data.myID].col;
tank_pos.row = data.tank[data.myID].row;
position = tank_pos;
_costs[tank_pos.row][tank_pos.col] = 0;
nextStep(tank_pos);
}
Tank::~Tank() {
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
delete this->_costs[i];
}
delete this->_costs;
}
void Tank::nextStep(Point start) {
Point next;
int cost;
for(int i = 0;i < 4;i++) {
next.col = start.col + offset[i].col;
next.row = start.row + offset[i].row;
if(!StupidAI::isValidPoint(next))
continue;
if(_costs[next.row][next.col] >= 0) {
cost = _costs[start.row][start.col] + 1;
switch(_data.map[next.row][next.col].type) {
case BREAKBRICK:
cost += 1;
break;
case BRICK:
cost += 2;
break;
}
if(cost < _costs[next.row][next.col]) {
_costs[next.row][next.col] = cost;
nextStep(next);
}
}
}
}
Point Tank::findNextPoint(Point end) {
Point next;
for(int i = 0;i < 4;i++) {
next.col = end.col + offset[i].col;
next.row = end.row + offset[i].row;
if(!StupidAI::isValidPoint(next))
continue;
if(_costs[next.row][next.col] == 0)
return end;
if(_costs[next.row][next.col] > 0 && _costs[next.row][next.col] < _costs[end.row][end.col])
return findNextPoint(next);
}
return end;
}
void Tank::print() {
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
for(int j = 0;j < MAP_WIDTH + 2;j++) {
printf("%3d", _costs[i][j]);
}
printf("\n");
}
}
OrderType Tank::nextDirection(Point start, Point end) {
int dx = end.row - start.row;
int dy = end.col - start.col;
if(dx == -1)
return GOUP;
if(dx == 1)
return GODOWN;
if(dy == -1)
return GOLEFT;
if(dy == 1)
return GORIGHT;
return STOP;
}
Point Tank::findDestination() {
Point p;
Point sourceP;
Point minP;
int found;
int minCost;
int count;
minCost = INT_MAX;
minP.col = 0;
minP.row = 0;
cost = INT_MAX;
for(int i = 0;i < 13;i++) {
count = 0;
sourceP = _data.source[i];
if (sourceP.row <=0)
continue;
// already own
SourceType sType = _data.map[sourceP.row][sourceP.col].isHereSource;
if(sType == BlueSource && _data.myFlag == BLUE)
continue;
if(sType == RedSource && _data.myFlag == RED)
continue;
// check if teammate's destination
for(int j = 0;j < 5;j++) {
if(sourceP == AI->tanks[j]->destination && j != _id) {
if(AI->tanks[j]->cost < _costs[sourceP.row][sourceP.col])
count++;
}
}
if(count > 0 && !(destination == sourceP))
continue;
if(_costs[sourceP.row][sourceP.col] < minCost) {
minCost = _costs[sourceP.row][sourceP.col];
minP = sourceP;
cost = minCost;
}
}
return minP;
}
bool Tank::detectCollision(Point next){
int tank_id = _data.map[next.row][next.col].whoIsHere;
if ( tank_id != -1){
if ( _data.tank[tank_id].flag == _data.myFlag){
if(AI->tanks[tank_id % 5]->next == position)
return true;
}
}
return false;
};
CellType Tank:: detectCellType(Point p) {
return _data.map[p.row][p.col].type;
}
Point Tank::findTarget(){
short range = _data.tank[_data.myID].range;
Point p;
for (int dx = -range;dx <= range;dx++){
for(int dy = -range;dy <= range;dy++) {
if(abs(dx) + abs(dy) > range)
continue;
p.row = position.row + dx;
p.col = position.col + dy;
//printf("(%d, %d) =>Fire (%d, %d).\n", position.row, position.col, p.row, p.col);
if(!StupidAI::isValidPoint(p))
continue;
if (_data.map[p.row][p.col].whoIsHere != -1){
short tank_id = _data.map[p.row][p.col].whoIsHere;
if (_data.tank[tank_id].flag != _data.myFlag)
return p;
}
if (this->detectCellType(p) == BREAKBRICK || this->detectCellType(p) == BRICK) {
for(int i = 0;i < 5;i++) {
if(p == AI->tanks[i]->next) {
return p;
}
}
}
}
}
p.row = 0;
p.col = 0;
return p;
}
Order Tank::makeOrder() {
Order order;
Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;
Point target = this->findTarget();
if (target.row){
order.type = FIRE;
order.row = target.row;
order.col = target.col;
return order;
}
Point dest = this->findDestination();
Point next;
if(dest.col) {
next = this->findNextPoint(dest);
order.type = Tank::nextDirection(position, next);
destination = dest;
next = next;
} else {
order.type = STOP;
destination = tmpPoint;
next = tmpPoint;
}
return order;
}
bool StupidAI::isValidPoint(Point p) {
if(p.col <= 0 || p.col >= MAP_WIDTH + 1)
return false;
if(p.row <= 0 || p.row >= MAP_HEIGHT + 1)
return false;
return true;
}
StupidAI::StupidAI() {
tanks[0] = (Tank *)new TankPioneer();
tanks[1] = (Tank *)new Tank();
tanks[2] = (Tank *)new TankSniper();
tanks[3] = (Tank *)new TankSniper();
tanks[4] = (Tank *)new Tank();
}
StupidAI::~StupidAI() {
for(int i = 0;i < 5;i++) {
delete tanks[i];
}
}
InitiateInfo StupidAI::getInitInfo() {
InitiateInfo Info;
Info.tank[0] = Pioneer;
Info.tank[1] = Striker;
Info.tank[2] = Sniper;
Info.tank[3] = Sniper;
Info.tank[4] = Striker;
strcpy(Info.aiName, "Stupid AI");
return Info;
}
Order StupidAI::makeOrder(DataForAI data) {
int id = data.myID % 5;
tanks[id]->update(data);
Tank *tank = tanks[id];
Order order = tank->makeOrder();
// solve collision
Point next = tank->next;
if(StupidAI::isValidPoint(next)){
if (tank->detectCollision(next)){
short dx = next.row - tank->position.row;
short dy = next.col - tank->position.col;
next.row = tank->position.row + dy;
next.col = tank->position.col + dx;
if (tank->detectCellType(next) == STONE){
next.row = tank->position.row - dy;
next.col = tank->position.col - dx;
}
}
tank->next = next;
order.type = Tank::nextDirection(tank->position, next);
}
return order;
}
Point TankPioneer::findTarget(){
short range = 1;
Point p;
for (int dx = -1;dx <= 1;dx++){
for (int dy = -1;dy <= 1;dy++){
p.row = position.row + dx;
p.col = position.col + dy;
if(abs(dx) + abs(dy) > 1)
continue;
//printf("Fire (%d, %d).\n", p.row, p.col);
if(!StupidAI::isValidPoint(p))
continue;
if (_data.map[p.row][p.col].whoIsHere != -1){
short tank_id = _data.map[p.row][p.col].whoIsHere;
if (_data.tank[tank_id].flag != _data.myFlag) {
if(_data.tank[tank_id].life >= _data.tank[_data.myID].life) {
return p;
}
}
}
if (this->detectCellType(p) == BREAKBRICK || this->detectCellType(p) == BRICK) {
for(int i = 0;i < 5;i++) {
if(p == AI->tanks[i]->next) {
return p;
}
}
}
}
}
p.row = 0;
p.col = 0;
return p;
}
/*
Order TankPioneer::makeOrder() {
Order order;
Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;
// Pioneer never shots tanks
Point dest = this->findDestination();
Point next;
if(dest.col) {
next = this->findNextPoint(dest);
order.type = Tank::nextDirection(position, next);
destination = dest;
next = next;
} else {
order.type = STOP;
destination = tmpPoint;
next = tmpPoint;
}
if (this->detectCellType(next) == BRICK || this->detectCellType(next) == BREAKBRICK) {
order.type = FIRE;
order.col = next.col;
order.row = next.row;
next = position;
}
return order;
}
*/
Order TankSniper::makeOrder() {
Order order;
Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;
// Sniper shots tanks
Point target = this->findTarget();
if (target.row){
order.type = FIRE;
order.row = target.row;
order.col = target.col;
return order;
}
Point dest = this->findDestination();
Point next;
if(dest.col) {
next = this->findNextPoint(dest);
order.type = Tank::nextDirection(position, next);
destination = dest;
next = next;
} else {
order.type = STOP;
destination = tmpPoint;
next = tmpPoint;
}
if (this->detectCellType(next) == BRICK || this->detectCellType(next) == BREAKBRICK) {
order.type = FIRE;
order.col = next.col;
order.row = next.row;
next = position;
}
return order;
}
extern "C" InitiateInfo chooseType()
{
AI = new StupidAI();
return AI->getInitInfo();
}
extern "C" Order makeOrder(DataForAI data)
{
return AI->makeOrder(data);
}
@raptium
Copy link
Author

raptium commented May 23, 2010

include "Tank.h"

include <string.h>

include

include

include

include

namespace net {
namespace raptium {

    // Operator Overloading for sturct Points
    bool operator== (Point a, Point b) {
        return (a.col == b.col && a.row == b.row);
    }

    Point operator-(Point a, Point b) {
        Point p;
        p.row = a.row - b.row;
        p.col = a.col - b.col;
        return p;
    }

    Point operator+(Point a, Point b) {
        Point p;
        p.row = a.row + b.row;
        p.col = a.col + b.col;
        return p;
    }

    Point operator*(Point a, int b) {
        Point p;
        p.row = a.row * b;
        p.col = a.col * b;
        return p;
    }

    class Tank {

    protected:
        int **_costs;
        short _id;
        DataForAI _data;
        Point offset[4];
        void nextStep(Point start);
        void init();

    public:
        Point position;
        Tank();
        Tank(DataForAI data);
        ~Tank();
        void update(DataForAI data);
        void print();

        static OrderType nextDirection(Point start, Point end);

        bool detectCollision(Point next);
        CellType detectCellType(Point p);
        Point findNextPoint(Point end);

        Point destination;
        Point next;
        int cost;

        virtual Point findTarget();
        virtual Point findDestination();
        virtual Order makeOrder();
    };


    class TankPioneer : Tank {

    public:
        Point findTarget();
        //Order makeOrder();
    };


    class TankSniper : Tank {

    public:
        Order makeOrder();
    };

    class StupidAI {

        void solveCollision();
    public:
        StupidAI();
        ~StupidAI();
        InitiateInfo getInitInfo();
        Order makeOrder(DataForAI data);
        Tank *tanks[5];

        static bool isValidPoint(Point p);
    };



}

}

using namespace net::raptium;

static StupidAI *AI;

Tank::Tank() {
init();
}

Tank::Tank(DataForAI data) {
init();
update(data);
}

void Tank::init() {

// init offset array
offset[0].col = 0;
offset[0].row = -1;
offset[1].col = 0;
offset[1].row = +1;
offset[2].col = -1;
offset[2].row = 0;
offset[3].col = +1;
offset[3].row = 0;

this->_costs = NULL;

}

void Tank::update(DataForAI data) {
_data = data;
_id = data.myID % 5;

if(_costs == NULL) {
_costs = new int *[MAP_HEIGHT + 2];
    for(int i = 0;i < MAP_HEIGHT + 2;i++) {
        _costs[i] = new int[MAP_WIDTH + 2];
    }
}

for(int i = 0;i < MAP_HEIGHT + 2;i++) {
    for(int j = 0;j < MAP_WIDTH + 2;j++) {
        switch(data.map[i][j].type) {
        case STONE:
            _costs[i][j] = -1;
            break;
        default:
            _costs[i][j] = INT_MAX;
        }
    }
}

Point tank_pos;
tank_pos.col = data.tank[data.myID].col;
tank_pos.row = data.tank[data.myID].row;
position = tank_pos;

_costs[tank_pos.row][tank_pos.col] = 0;

nextStep(tank_pos);

}

Tank::~Tank() {
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
delete this->_costs[i];
}
delete this->_costs;
}

void Tank::nextStep(Point start) {
Point next;
int cost;

for(int i = 0;i < 4;i++) {
    next.col = start.col + offset[i].col;
    next.row = start.row + offset[i].row;
    if(!StupidAI::isValidPoint(next))
        continue;

    if(_costs[next.row][next.col] >= 0) {
        cost = _costs[start.row][start.col] + 1;

        switch(_data.map[next.row][next.col].type) {
        case BREAKBRICK:
            cost += 1;
            break;
        case BRICK:
            cost += 2;
            break;
        }

        if(cost < _costs[next.row][next.col]) {
            _costs[next.row][next.col] = cost;
            nextStep(next);
        }
    }
}

}

Point Tank::findNextPoint(Point end) {
Point next;

for(int i = 0;i < 4;i++) {
    next.col = end.col + offset[i].col;
    next.row = end.row + offset[i].row;
    if(!StupidAI::isValidPoint(next))
        continue;

    if(_costs[next.row][next.col] == 0)
        return end;

    if(_costs[next.row][next.col] > 0 && _costs[next.row][next.col] < _costs[end.row][end.col])
        return findNextPoint(next);
}
return end;

}

void Tank::print() {
for(int i = 0;i < MAP_HEIGHT + 2;i++) {
for(int j = 0;j < MAP_WIDTH + 2;j++) {
printf("%3d", _costs[i][j]);
}
printf("\n");
}
}

OrderType Tank::nextDirection(Point start, Point end) {
int dx = end.row - start.row;
int dy = end.col - start.col;
if(dx == -1)
return GOUP;
if(dx == 1)
return GODOWN;
if(dy == -1)
return GOLEFT;
if(dy == 1)
return GORIGHT;
return STOP;
}

Point Tank::findDestination() {
Point p;
Point sourceP;
Point minP;
int found;
int minCost;
int count;

minCost = INT_MAX;
minP.col = 0;
minP.row = 0;
cost = INT_MAX;

for(int i = 0;i < 13;i++) {
    count = 0;

    sourceP = _data.source[i];
    if (sourceP.row <=0)
        continue;

    // already own
    SourceType sType = _data.map[sourceP.row][sourceP.col].isHereSource;
    if(sType == BlueSource && _data.myFlag == BLUE)
        continue;
    if(sType == RedSource && _data.myFlag == RED)
        continue;

    // check if teammate's destination
    for(int j = 0;j < 5;j++) {
        if(sourceP == AI->tanks[j]->destination && j != _id) {
            if(AI->tanks[j]->cost < _costs[sourceP.row][sourceP.col])
                count++;
        }
    }
    if(count > 0 && !(destination == sourceP))
        continue;

    if(_costs[sourceP.row][sourceP.col] < minCost) {
        minCost = _costs[sourceP.row][sourceP.col];
        minP = sourceP;
        cost = minCost;
    }
}

return minP;

}

bool Tank::detectCollision(Point next){
int tank_id = _data.map[next.row][next.col].whoIsHere;
if ( tank_id != -1){
if ( _data.tank[tank_id].flag == _data.myFlag){
if(AI->tanks[tank_id % 5]->next == position)
return true;
}
}
return false;
};

CellType Tank:: detectCellType(Point p) {
return _data.map[p.row][p.col].type;
}

Point Tank::findTarget(){
short range = _data.tank[_data.myID].range;
Point p;
for (int dx = -range;dx <= range;dx++){
for(int dy = -range;dy <= range;dy++) {

        if(abs(dx) + abs(dy) > range)
            continue;

        p.row = position.row + dx;
        p.col = position.col + dy;
        //printf("(%d, %d) =>Fire (%d, %d).\n", position.row, position.col, p.row, p.col);

        if(!StupidAI::isValidPoint(p))
            continue;

        if (_data.map[p.row][p.col].whoIsHere != -1){
            short tank_id = _data.map[p.row][p.col].whoIsHere;
            if (_data.tank[tank_id].flag != _data.myFlag)
                return p;
        }

        if (this->detectCellType(p) == BREAKBRICK || this->detectCellType(p) == BRICK) {
            for(int i = 0;i < 5;i++) {
                if(p == AI->tanks[i]->next) {
                    return p;
                }
            }

        }
    }
}
p.row = 0;
p.col = 0;
return p;

}

Order Tank::makeOrder() {
Order order;

Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;

Point target = this->findTarget();
if (target.row){
    order.type = FIRE;
    order.row = target.row;
    order.col = target.col;
    return order;
}
Point dest = this->findDestination();
Point next;

if(dest.col) {
    next = this->findNextPoint(dest);
    order.type = Tank::nextDirection(position, next);
    destination = dest;
    next = next;

} else {
    order.type = STOP;
    destination = tmpPoint;
    next = tmpPoint;
}

return order;

}

bool StupidAI::isValidPoint(Point p) {
if(p.col <= 0 || p.col >= MAP_WIDTH + 1)
return false;
if(p.row <= 0 || p.row >= MAP_HEIGHT + 1)
return false;
return true;
}

StupidAI::StupidAI() {
tanks[0] = (Tank *)new TankPioneer();
tanks[1] = (Tank *)new Tank();
tanks[2] = (Tank *)new TankSniper();
tanks[3] = (Tank *)new TankSniper();
tanks[4] = (Tank *)new Tank();
}

StupidAI::~StupidAI() {
for(int i = 0;i < 5;i++) {
delete tanks[i];
}
}

InitiateInfo StupidAI::getInitInfo() {
InitiateInfo Info;
Info.tank[0] = Pioneer;
Info.tank[1] = Striker;
Info.tank[2] = Sniper;
Info.tank[3] = Sniper;
Info.tank[4] = Striker;
strcpy(Info.aiName, "Stupid AI");
return Info;
}

Order StupidAI::makeOrder(DataForAI data) {

int id = data.myID % 5;
tanks[id]->update(data);
Tank *tank = tanks[id];
Order order = tank->makeOrder();

// solve collision
Point next = tank->next;
if(StupidAI::isValidPoint(next)){
    if (tank->detectCollision(next)){
        short dx = next.row - tank->position.row;
        short dy = next.col - tank->position.col;
        next.row = tank->position.row + dy;
        next.col = tank->position.col + dx;
        if (tank->detectCellType(next) == STONE){
            next.row = tank->position.row - dy;
            next.col = tank->position.col - dx;
        }
    }
    tank->next = next;
    order.type = Tank::nextDirection(tank->position, next);
}

return order;

}

Point TankPioneer::findTarget(){
short range = 1;
Point p;

for (int dx = -1;dx <= 1;dx++){
    for (int dy = -1;dy <= 1;dy++){
        p.row = position.row + dx;
        p.col = position.col + dy;
        if(abs(dx) + abs(dy) > 1)
            continue;
        //printf("Fire (%d, %d).\n", p.row, p.col);

        if(!StupidAI::isValidPoint(p))
            continue;

        if (_data.map[p.row][p.col].whoIsHere != -1){
            short tank_id = _data.map[p.row][p.col].whoIsHere;
            if (_data.tank[tank_id].flag != _data.myFlag) {
                if(_data.tank[tank_id].life >= _data.tank[_data.myID].life) {
                    return p;
                }
            }
        }

        if (this->detectCellType(p) == BREAKBRICK || this->detectCellType(p) == BRICK) {
            for(int i = 0;i < 5;i++) {
                if(p == AI->tanks[i]->next) {
                    return p;
                }
            }

        }
    }
}
p.row = 0;
p.col = 0;
return p;

}

/*
Order TankPioneer::makeOrder() {
Order order;

Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;

// Pioneer never shots tanks

Point dest = this->findDestination();
Point next;

if(dest.col) {
    next = this->findNextPoint(dest);
    order.type = Tank::nextDirection(position, next);
    destination = dest;
    next = next;
} else {
    order.type = STOP;
    destination = tmpPoint;
    next = tmpPoint;
}

if (this->detectCellType(next) == BRICK || this->detectCellType(next) == BREAKBRICK) {
    order.type = FIRE;
    order.col = next.col;
    order.row = next.row;
    next = position;
}
return order;

}
*/

Order TankSniper::makeOrder() {
Order order;

Point tmpPoint;
tmpPoint.col = 0;
tmpPoint.row = 0;

// Sniper shots tanks
Point target = this->findTarget();
if (target.row){
    order.type = FIRE;
    order.row = target.row;
    order.col = target.col;
    return order;
}

Point dest = this->findDestination();
Point next;

if(dest.col) {
    next = this->findNextPoint(dest);
    order.type = Tank::nextDirection(position, next);
    destination = dest;
    next = next;
} else {
    order.type = STOP;
    destination = tmpPoint;
    next = tmpPoint;
}

if (this->detectCellType(next) == BRICK || this->detectCellType(next) == BREAKBRICK) {
    order.type = FIRE;
    order.col = next.col;
    order.row = next.row;
    next = position;
}
return order;

}

extern "C" InitiateInfo chooseType()
{
AI = new StupidAI();
return AI->getInitInfo();
}

extern "C" Order makeOrder(DataForAI data)
{
return AI->makeOrder(data);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment