mirror of
https://github.com/mx42/codingame.git
synced 2026-01-13 21:29:51 +01:00
639 lines
18 KiB
C++
639 lines
18 KiB
C++
// Hypersonic Challenge
|
|
// Xavier Morel - 2016-09-24
|
|
// Ranking 1070/2715 (blehhh)
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <list>
|
|
|
|
using namespace std;
|
|
|
|
#define ITEM_MAX_DISTANCE 10
|
|
#define COMPUTATION_MAX_DISTANCE 50
|
|
|
|
#define TYPE_PLAYER 0
|
|
#define TYPE_BOMB 1
|
|
#define TYPE_ITEM 2
|
|
|
|
#define TILE_EMPTY '.'
|
|
#define TILE_BOX '0'
|
|
#define TILE_BONUS_BOMB '1'
|
|
#define TILE_BONUS_REACH '2'
|
|
#define TILE_WALL 'X'
|
|
#define TILE_BOMB 'B'
|
|
#define TILE_ITEM 'I'
|
|
|
|
int width = 0;
|
|
int height = 0;
|
|
|
|
class Coords {
|
|
public:
|
|
int x;
|
|
int y;
|
|
Coords() : x(-1), y(-1) {}
|
|
Coords(int x, int y) : x(x), y(y) {}
|
|
|
|
Coords above()
|
|
{
|
|
return Coords(x, y - 1);
|
|
}
|
|
|
|
Coords below()
|
|
{
|
|
return Coords(x, y + 1);
|
|
}
|
|
|
|
Coords leftOf()
|
|
{
|
|
return Coords(x - 1, y);
|
|
}
|
|
|
|
Coords rightOf()
|
|
{
|
|
return Coords(x + 1, y);
|
|
}
|
|
|
|
inline void up()
|
|
{
|
|
--y;
|
|
}
|
|
|
|
inline void down()
|
|
{
|
|
++y;
|
|
}
|
|
|
|
inline void left()
|
|
{
|
|
--x;
|
|
}
|
|
|
|
inline void right()
|
|
{
|
|
++x;
|
|
}
|
|
|
|
inline bool isValid()
|
|
{
|
|
return x >= 0 && y >= 0 && x < width && y < height;
|
|
}
|
|
};
|
|
|
|
class Tile {
|
|
public:
|
|
int score;
|
|
char type;
|
|
bool danger;
|
|
bool reachable;
|
|
|
|
Tile() : score(0), danger(false), reachable(false), type(TILE_EMPTY) {}
|
|
|
|
inline bool isBox()
|
|
{
|
|
return (type == TILE_BOX || type == TILE_BONUS_BOMB || type == TILE_BONUS_REACH);
|
|
}
|
|
|
|
inline bool isBlocking()
|
|
{
|
|
return !isFree();
|
|
}
|
|
|
|
inline bool isFree()
|
|
{
|
|
return (type == TILE_EMPTY || type == TILE_ITEM);
|
|
}
|
|
|
|
inline bool isWalkable()
|
|
{
|
|
return isFree() && !isDanger();
|
|
}
|
|
|
|
inline bool isDanger()
|
|
{
|
|
return danger;
|
|
}
|
|
|
|
inline bool isItem()
|
|
{
|
|
return (type == TILE_ITEM);
|
|
}
|
|
|
|
inline bool isReachable()
|
|
{
|
|
return reachable;
|
|
}
|
|
};
|
|
|
|
class Board {
|
|
private:
|
|
vector<vector<Tile>> tiles;
|
|
|
|
public:
|
|
Board() {}
|
|
|
|
void reset()
|
|
{
|
|
// TODO ...
|
|
tiles.clear();
|
|
}
|
|
|
|
void addRow(string row)
|
|
{
|
|
vector<Tile> row_tiles;
|
|
for (int i = 0; i < row.size(); i++) {
|
|
Tile tile;
|
|
tile.type = row.at(i);
|
|
row_tiles.push_back(tile);
|
|
}
|
|
|
|
tiles.push_back(row_tiles);
|
|
}
|
|
|
|
inline Tile get(Coords pos)
|
|
{
|
|
return tiles.at(pos.y).at(pos.x);
|
|
}
|
|
|
|
void setBomb(Coords pos, int reach, int danger)
|
|
{
|
|
tiles.at(pos.y).at(pos.x).type = TILE_BOMB;
|
|
tiles.at(pos.y).at(pos.x).danger = true;
|
|
|
|
for (Coords c = pos.leftOf(); c.isValid(); c.left()) {
|
|
// cerr << "See if I can set danger at " << c.x << " " << c.y << endl;
|
|
if (get(c).isFree()) {
|
|
// cerr << "Set danger at " << c.x << " " << c.y << endl;
|
|
tiles.at(c.y).at(c.x).danger = true;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
for (Coords c = pos.rightOf(); c.isValid(); c.right()) {
|
|
// cerr << "See if I can set danger at " << c.x << " " << c.y << endl;
|
|
if (get(c).isFree()) {
|
|
// cerr << "Set danger at " << c.x << " " << c.y << endl;
|
|
tiles.at(c.y).at(c.x).danger = true;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
for (Coords c = pos.above(); c.isValid(); c.up()) {
|
|
// cerr << "See if I can set danger at " << c.x << " " << c.y << endl;
|
|
if (get(c).isFree()) {
|
|
// cerr << "Set danger at " << c.x << " " << c.y << endl;
|
|
tiles.at(c.y).at(c.x).danger = true;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
for (Coords c = pos.below(); c.isValid(); c.down()) {
|
|
// cerr << "See if I can set danger at " << c.x << " " << c.y << endl;
|
|
if (get(c).isFree()) {
|
|
// cerr << "Set danger at " << c.x << " " << c.y << endl;
|
|
tiles.at(c.y).at(c.x).danger = true;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void setReachable(Coords pos)
|
|
{
|
|
tiles.at(pos.y).at(pos.x).reachable = true;
|
|
}
|
|
|
|
void setItem(Coords pos)
|
|
{
|
|
tiles.at(pos.y).at(pos.x).type = TILE_ITEM;
|
|
}
|
|
|
|
void setScore(Coords pos, int score)
|
|
{
|
|
tiles.at(pos.y).at(pos.x).score = score;
|
|
}
|
|
|
|
inline bool isBox(Coords pos)
|
|
{
|
|
return get(pos).isBox();
|
|
}
|
|
|
|
inline bool isBlocking(Coords pos)
|
|
{
|
|
return get(pos).isBlocking();
|
|
}
|
|
|
|
inline bool isFree(Coords pos)
|
|
{
|
|
return get(pos).isFree();
|
|
}
|
|
|
|
inline bool isItem(Coords pos)
|
|
{
|
|
return get(pos).isItem();
|
|
}
|
|
|
|
inline bool isDanger(Coords pos)
|
|
{
|
|
return get(pos).isDanger();
|
|
}
|
|
|
|
inline bool isReachable(Coords pos)
|
|
{
|
|
return get(pos).isReachable();
|
|
}
|
|
|
|
inline bool isWalkable(Coords pos)
|
|
{
|
|
return get(pos).isWalkable();
|
|
}
|
|
};
|
|
|
|
Board board;
|
|
|
|
typedef struct {
|
|
Coords pos;
|
|
int id;
|
|
int param1;
|
|
int reach;
|
|
} Entity;
|
|
|
|
typedef struct {
|
|
Coords pos;
|
|
int score = 0;
|
|
bool toBomb = false;
|
|
bool getToSafety = false;
|
|
bool fetchItem = false;
|
|
} Destination;
|
|
|
|
bool checkBombLocation(Coords pos, int reach)
|
|
{
|
|
int i;
|
|
cerr << "Checking bomb pos " << pos.x << " " << pos.y << endl;
|
|
Coords c, d;
|
|
for (c = pos.above(), i = 0; i < reach && c.isValid() && board.isFree(c); c.up()) {
|
|
d = c.leftOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
d = c.rightOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
if (c.isValid() && board.isFree(c)) {
|
|
d = c.above();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
for (c = pos.below(), i = 0; i < reach && c.isValid() && board.isFree(c); c.down()) {
|
|
d = c.leftOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
d = c.rightOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
if (c.isValid() && board.isFree(c)) {
|
|
d = c.below();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
for (c = pos.leftOf(), i = 0; i < reach && c.isValid() && board.isFree(c); c.left()) {
|
|
d = c.above();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
d = c.below();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
if (c.isValid() && board.isFree(c)) {
|
|
d = c.leftOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
for (c = pos.rightOf(), i = 0; i < reach && c.isValid() && board.isFree(c); c.right()) {
|
|
d = c.above();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
d = c.below();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
if (c.isValid() && board.isFree(c)) {
|
|
d = c.rightOf();
|
|
if (d.isValid() && board.isWalkable(d)) {
|
|
cerr << "Could flee from " << c.x << " " << c.y << " to " << d.x << " " << d.y << endl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
class Game
|
|
{
|
|
private:
|
|
int myId;
|
|
Entity players[4];
|
|
|
|
Destination currentObjective;
|
|
bool didntmove;
|
|
bool items_present;
|
|
|
|
public:
|
|
string action;
|
|
|
|
Game(int id) : myId(id) {
|
|
currentObjective.score = 0;
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
didntmove = false;
|
|
items_present = false;
|
|
action = "";
|
|
}
|
|
|
|
void addEntity(int entityType, Entity entity)
|
|
{
|
|
switch (entityType) {
|
|
case TYPE_PLAYER:
|
|
if (entity.id == myId) {
|
|
if (players[entity.id].pos.x == entity.pos.x
|
|
&& players[entity.id].pos.y == entity.pos.y
|
|
&& entity.param1 > 0
|
|
) {
|
|
didntmove = true;
|
|
}
|
|
}
|
|
players[entity.id] = entity;
|
|
break;
|
|
case TYPE_BOMB:
|
|
board.setBomb(entity.pos, entity.reach, entity.param1);
|
|
break;
|
|
case TYPE_ITEM:
|
|
board.setItem(entity.pos);
|
|
items_present = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
int getPositionScore(Coords pos)
|
|
{
|
|
int score = 0;
|
|
int reach = players[myId].reach;
|
|
int i;
|
|
Coords c;
|
|
|
|
for (c = pos, i = 0; c.isValid() && i < reach; c.left()) {
|
|
if (board.isBox(c)) {
|
|
score++;
|
|
break;
|
|
}
|
|
if (board.isBlocking(c)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (c = pos, i = 0; c.isValid() && i < reach; c.right()) {
|
|
if (board.isBox(c)) {
|
|
score++;
|
|
break;
|
|
}
|
|
if (board.isBlocking(c)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (c = pos, i = 0; c.isValid() && i < reach; c.up()) {
|
|
if (board.isBox(c)) {
|
|
score++;
|
|
break;
|
|
}
|
|
if (board.isBlocking(c)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (c = pos, i = 0; c.isValid() && i < reach; c.down()) {
|
|
if (board.isBox(c)) {
|
|
score++;
|
|
break;
|
|
}
|
|
if (board.isBlocking(c)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return score;
|
|
}
|
|
|
|
void computeReachableTiles()
|
|
{
|
|
Destination objective = currentObjective;
|
|
|
|
list<Coords> toProcess;
|
|
toProcess.push_back(players[myId].pos);
|
|
|
|
bool shouldFindCover = false;
|
|
if (board.isDanger(players[myId].pos)) {
|
|
shouldFindCover = true;
|
|
}
|
|
|
|
int i = 0;
|
|
|
|
while (toProcess.size() > 0) {
|
|
i++;
|
|
Coords pos = toProcess.front();
|
|
toProcess.pop_front();
|
|
|
|
cerr << "Pos " << pos.x << " " << pos.y << endl;
|
|
board.setReachable(pos);
|
|
int score = getPositionScore(pos);
|
|
cerr << "Score: " << score << endl;
|
|
board.setScore(pos, score);
|
|
|
|
bool dangerous = board.isDanger(pos);
|
|
cerr << "Dangerous: " << (dangerous ? "yes" : "no") << endl;
|
|
|
|
if (!dangerous) {
|
|
if (shouldFindCover) { // && !dangerous) {
|
|
if (!objective.getToSafety) {
|
|
cerr << "Get to any possible cover!" << endl;
|
|
objective.getToSafety = true;
|
|
objective.fetchItem = false;
|
|
objective.toBomb = false;
|
|
objective.pos = pos;
|
|
objective.score = 0;
|
|
}
|
|
}
|
|
|
|
// if (!shouldFindCover || !dangerous) {
|
|
if (board.isItem(pos) && objective.fetchItem == false && i <= ITEM_MAX_DISTANCE) {
|
|
cerr << "Closeby item + (should be) no danger, go for it !" << endl;
|
|
objective.getToSafety = !dangerous;
|
|
objective.fetchItem = true;
|
|
objective.toBomb = false;
|
|
objective.pos = pos;
|
|
objective.score = 4;
|
|
}
|
|
|
|
if (score > objective.score) {
|
|
if (checkBombLocation(pos, players[myId].reach)) {
|
|
cerr << "Better than current objective: go bomb it!" << endl;
|
|
objective.pos = pos;
|
|
objective.score = score;
|
|
objective.toBomb = true;
|
|
objective.fetchItem = false;
|
|
objective.getToSafety = false;
|
|
}
|
|
else {
|
|
cerr << "Nope that's too dangerous!" << endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i > COMPUTATION_MAX_DISTANCE) { // dont go too far...
|
|
cerr << "Already computed " << i << " entries. Stop for now..." << endl;
|
|
break;
|
|
}
|
|
|
|
pos.up();
|
|
if (pos.isValid() && !board.isReachable(pos) && board.isFree(pos)) {
|
|
toProcess.push_back(pos);
|
|
}
|
|
pos.down(); // back to origin
|
|
|
|
pos.down();
|
|
if (pos.isValid() && !board.isReachable(pos) && board.isFree(pos)) {
|
|
toProcess.push_back(pos);
|
|
}
|
|
pos.up(); // back to origin
|
|
|
|
pos.left();
|
|
if (pos.isValid() && !board.isReachable(pos) && board.isFree(pos)) {
|
|
toProcess.push_back(pos);
|
|
}
|
|
pos.right(); // back to origin
|
|
|
|
pos.right();
|
|
if (pos.isValid() && !board.isReachable(pos) && board.isFree(pos)) {
|
|
toProcess.push_back(pos);
|
|
}
|
|
cerr << "#############" << endl;
|
|
}
|
|
|
|
cerr << "Go to " << objective.pos.x << " " << objective.pos.y << endl;
|
|
|
|
currentObjective = objective;
|
|
|
|
// for (int i = 0; i < height; ++i) {
|
|
// for (int j = 0; j < width; ++j) {
|
|
// if (board.isReachable(Coords(j, i))) {
|
|
// cerr << "Reachable: " << j << " " << i << endl;
|
|
// }
|
|
// }
|
|
// }
|
|
|
|
}
|
|
|
|
void computeObjective()
|
|
{
|
|
//if (didntmove) {
|
|
// cerr << "Didnt move: special output" << endl;
|
|
// action = "BOMB 0 0 x_x";
|
|
// return;
|
|
//}
|
|
|
|
action = "MOVE ";
|
|
if (
|
|
currentObjective.pos.x == players[myId].pos.x
|
|
&& currentObjective.pos.y == players[myId].pos.y
|
|
) {
|
|
if (currentObjective.toBomb) {
|
|
action = "BOMB ";
|
|
}
|
|
currentObjective.toBomb = false;
|
|
currentObjective.score = 0;
|
|
currentObjective.getToSafety = false;
|
|
currentObjective.fetchItem = false;
|
|
}
|
|
|
|
action += to_string(currentObjective.pos.x);
|
|
action += " ";
|
|
action += to_string(currentObjective.pos.y);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Auto-generated code below aims at helping you parse
|
|
* the standard input according to the problem statement.
|
|
**/
|
|
int main()
|
|
{
|
|
int myId;
|
|
cin >> width >> height >> myId; cin.ignore();
|
|
|
|
Game game(myId);
|
|
|
|
// game loop
|
|
while (1) {
|
|
board.reset();
|
|
game.reset();
|
|
|
|
for (int i = 0; i < height; i++) {
|
|
string row;
|
|
cin >> row; cin.ignore();
|
|
board.addRow(row);
|
|
}
|
|
|
|
int entities;
|
|
cin >> entities; cin.ignore();
|
|
for (int i = 0; i < entities; i++) {
|
|
Entity entity;
|
|
|
|
int type;
|
|
cin >> type
|
|
>> entity.id
|
|
>> entity.pos.x
|
|
>> entity.pos.y
|
|
>> entity.param1
|
|
>> entity.reach;
|
|
cin.ignore();
|
|
game.addEntity(type, entity);
|
|
}
|
|
|
|
game.computeReachableTiles();
|
|
game.computeObjective();
|
|
|
|
cout << game.action << endl;
|
|
}
|
|
}
|