Дзен - C ++
Этот Кодемон здесь не для того, чтобы есть, но чтобы сражаться. Он знает, что мертвый враг не украдет его яблоки.
Name| Author |Launch with
Zen GholGoth21 Zen.exe
стратегия
Все (за исключением CircleOfLife) спешат на яблоки, но не на дзен, не всегда. Если враг может достать еду до него, он просто ждет в центре (что? Но что вы здесь делаете, CircleOfLife?). Иначе, Дзен идет на яблоко и оборачивается, ожидая, что что-то случится. На самом деле он использует яблоко в качестве приманки.
Я ничего не кодировал против любопытной стратегии CircleOfLife, потому что он может выиграть только с очень большой удачей.
Код
Это полный код проекта C ++. Вырежьте 11 исходных файлов и Makefile и скомпилируйте сmake
$ cat src/* Makefile
/*
* @file Enemy.cpp
* @author GholGoth21
* @date Créé le 1 mars 2015 à 14:10
*/
#include "Enemy.h"
#include <fstream>
Enemy::Enemy()
{
}
Enemy::~Enemy()
{
}
std::ostream &operator<<(std::ostream &os, const Enemy& e)
{
return os<<e.m_pos<<" "<<e.m_date;
}
std::istream &operator>>(std::istream &is, Enemy& e)
{
return is>>e.m_pos>>e.m_date;
}
int Enemy::distTo(int2 const &target, int date) const
{
return m_pos.distTo(target)-(date-m_date);
}
bool Enemy::recentActivity(int2 const &pos, int date, int maxDelay) const
{
return pos.distTo(m_pos)<=date-m_date && date-m_date<=maxDelay;
}
/*
* @file Enemy.h
* @author GholGoth21
* @date Créé le 1 mars 2015 à 14:10
*/
#ifndef ENEMY_H
#define ENEMY_H
#include "int2.h"
class Enemy
{
public:
Enemy();
virtual ~Enemy();
public:
void setPos(int2 const &pos, int date) { m_pos=pos; m_date=date; }
int distTo(int2 const &target, int date) const;
int2 const &pos() const { return m_pos; }
bool recentActivity(int2 const &pos, int date, int maxDelay) const;
friend std::ostream &operator<<(std::ostream &os, const Enemy& e);
friend std::istream &operator>>(std::istream &is, Enemy& e);
private:
int2 m_pos;
int m_date;
};
#endif /* ENEMY_H */
/*
* @file Snake.cpp
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:47
*/
#include "Snake.h"
#include "enums.h"
#include "StrManip.h"
#include "Enemy.h"
#include <vector>
#include <cmath>
Snake::Snake(std::string const &body)
{
std::vector<std::string> posList;
split(body, '/', posList);
for(auto &pos : posList)
m_body.push_back(int2(pos));
}
Snake::~Snake()
{
}
Command Snake::move(int2 food, int date, Enemy const &enemy)
{
Command bestCommand[Command::count];
int myDist=curPos().distTo(food);
int enemyDist=enemy.distTo(food,date);
if(myDist>=enemyDist && enemyDist>2)
{
orderCommand(int2(MAPSIZE/2,MAPSIZE/2), bestCommand);
for(int i=0; i<Command::count; i++)
if(validCommand(bestCommand[i]) && !enemy.recentActivity(nextPos(bestCommand[i]),date,5))
return bestCommand[i];
}
if((myDist==1 && enemyDist>((len()-1)/2)*2+3) || enemyDist<-5)
{
orderCommand(food, bestCommand);
for(int i=0; i<Command::count; i++)
if(validCommand(bestCommand[i]))
return bestCommand[i];
}
int2 embushPoint;
int minDist=-1;
foreach_enum(Direction, d)
{
int2 point(food+d.vector());
int dist=point.quadDistTo(enemy.pos());
if(dist<minDist || minDist<0)
{
minDist=dist;
embushPoint=point;
}
}
if(curPos().distTo(embushPoint)<enemy.distTo(embushPoint,date)-((len()-1)/2)*2)
{
int minimalAction=-1;
int qMinDist = curPos().quadDistTo(embushPoint);
Command minimalCommand;
foreach_enum(Command, c)
{
int2 np=nextPos(c);
int qDist = np.quadDistTo(embushPoint);
if((qDist<minimalAction || minimalAction<0) && qDist>qMinDist && validCommand(c))
{
minimalAction=qDist;
minimalCommand=c;
}
}
return minimalCommand;
}
else
{
orderCommand(embushPoint, food, bestCommand);
for(int i=0; i<Command::count; i++)
if(validCommand(bestCommand[i]) && nextPos(bestCommand[i])!=food)
return bestCommand[i];
}
return Command::forward;
}
bool Snake::validCommand(Command c) const
{
if(!c.isValid())
return false;
int2 np = nextPos(c);
if(!(0<np.x && np.x<MAPSIZE-1 && 0<np.y && np.y<MAPSIZE-1))
return false;
for(unsigned int i=2; i<m_body.size()-1; i++)
if(np==m_body.at(i))
return false;
return true;
}
bool Snake::isStarting() const
{
if(m_body.size()==3)
{
if(m_body.at(0)==int2(3,(MAPSIZE)/2) && m_body.at(1)==int2(2,(MAPSIZE)/2) && m_body.at(2)==int2(1,(MAPSIZE)/2))
return true;
else if(m_body.at(0)==int2(MAPSIZE-4,(MAPSIZE)/2) && m_body.at(1)==int2(MAPSIZE-3,(MAPSIZE)/2) && m_body.at(2)==int2(MAPSIZE-2,(MAPSIZE)/2))
return true;
}
return false;
}
void Snake::orderCommand(int2 target, Command *tab)
{
int weight[Command::count];
foreach_enum(Command, c)
{
int2 np = nextPos(c);
weight[c]=np.quadDistTo(target);
tab[c]=c;
}
for(int i=0; i<Command::count-1; i++)
{
while(i>=0 && weight[tab[i]]>weight[tab[i+1]])
{
varSwitch(tab[i], tab[i+1]);
i--;
}
}
}
void Snake::orderCommand(int2 target1, int2 target2, Command *tab)
{
int weight[Command::count];
foreach_enum(Command, c)
{
int2 np = nextPos(c);
weight[c]=np.quadDistTo(target1)+np.quadDistTo(target2);
tab[c]=c;
}
for(int i=0; i<Command::count-1; i++)
{
while(i>=0 && weight[tab[i]]>weight[tab[i+1]])
{
varSwitch(tab[i], tab[i+1]);
i--;
}
}
}
/*
* @file Snake.h
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:47
*/
#ifndef SNAKE_H
#define SNAKE_H
#include "int2.h"
#include <vector>
#define MAPSIZE 15
class Enemy;
class Snake
{
public:
Snake(std::string const &body);
virtual ~Snake();
public:
Command move(int2 food, int date, Enemy const &enemy);
Direction curDir() const { return (m_body.at(0)-m_body.at(1)).direction(); }
int2 curPos() const { return m_body.at(0); }
int2 nextPos(Command c) const { return curPos()+curDir().applyCommand(c).vector(); }
bool validCommand(Command c) const;
bool isStarting() const;
void orderCommand(int2 target, Command *tab);
void orderCommand(int2 target1, int2 target2, Command *tab);
int len() const { return m_body.size(); }
private:
std::vector<int2> m_body;
};
#endif /* SNAKE_H */
/*
* @file StrManip.cpp
* @author GholGoth21
* @date Créé le 7 février 2015 à 17:26
*/
#include "StrManip.h"
#include <sstream>
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems)
{
std::stringstream ss(s);
std::string item;
while(std::getline(ss, item, delim))
elems.push_back(item);
return elems;
}
int atoi(std::string const &text)
{
std::stringstream ss(text);
int val;
ss >> val;
return val;
}
/*
* @file StrManip.h
* @author GholGoth21
* @date Créé le 7 février 2015 à 17:26
*/
#ifndef STRMANIP_H
#define STRMANIP_H
#include <string>
#include <vector>
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems);
int atoi(std::string const &text);
#endif /* STRMANIP_H */
/*
* @file enums.cpp
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:55
*/
#include "enums.h"
#include "int2.h"
Command Direction::turnTo(Direction newDir) const
{
if(!isValid() || !newDir.isValid())
return Command::count; //Invalid
else if((m_value==Direction::up && newDir==Direction::left) || (m_value==Direction::left && newDir==Direction::down) ||
(m_value==Direction::down && newDir==Direction::right) || (m_value==Direction::right && newDir==Direction::up))
return Command::left;
else if((m_value==Direction::up && newDir==Direction::right) || (m_value==Direction::right && newDir==Direction::down) ||
(m_value==Direction::down && newDir==Direction::left) || (m_value==Direction::left && newDir==Direction::up))
return Command::right;
else if(m_value==newDir)
return Command::forward;
else
return Command::count; // Invalid
}
Direction Direction::applyCommand(Command c) const
{
if(c==Command::forward)
return m_value;
else if(c==Command::left)
{
switch(m_value)
{
case Direction::left:
return Direction::down;
case Direction::up:
return Direction::left;
case Direction::right:
return Direction::up;
case Direction::down:
return Direction::right;
default:
break;
}
}
else if(c==Command::right)
{
switch(m_value)
{
case Direction::left:
return Direction::up;
case Direction::up:
return Direction::right;
case Direction::right:
return Direction::down;
case Direction::down:
return Direction::left;
default:
break;
}
}
return Direction::count; // Invalid
}
int2 Direction::vector() const
{
switch(m_value)
{
case Direction::left:
return int2(-1,0);
case Direction::up:
return int2(0,-1);
case Direction::right:
return int2(1,0);
case Direction::down:
return int2(0,1);
default:
return int2(0,0);
}
}
std::ostream &operator<<(std::ostream &os, const Command& c)
{
switch(c.m_value)
{
case Command::left:
return os<<"L";
case Command::right:
return os<<"R";
default:
return os<<"F";
}
}
/*
* @file enums.h
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:55
*/
#ifndef ENUMS_H
#define ENUMS_H
#include <ostream>
struct int2;
#define DECL_ENUM_STRUCT(_name) \
_name() : m_value(static_cast<Type>(0)) {} \
_name(Type value) : m_value(value) {} \
_name(int value) : m_value(static_cast<Type>(value)) {} \
static Type begin() { return static_cast<Type>(0); } \
static Type end() { return count; } \
_name &operator++() { m_value=static_cast<Type>(static_cast<int>(m_value)+1); return *this; } \
operator int() const { return static_cast<Type>(m_value); } \
Type m_value;
#define foreach_enum(_type,_var) for(_type _var = _type::begin(); _var<_type::end(); ++_var)
struct Command
{
enum Type
{
left,
forward,
right,
count
};
bool isValid() const { return m_value<count; }
friend std::ostream &operator<<(std::ostream &os, const Command& c);
DECL_ENUM_STRUCT(Command)
};
struct Direction
{
enum Type
{
left,
up,
right,
down,
count
};
bool isValid() const { return m_value<count; }
Command turnTo(Direction newDir) const;
Direction applyCommand(Command c) const;
int2 vector() const;
DECL_ENUM_STRUCT(Direction)
};
#endif /* ENUMS_H */
/*
* @file int2.cpp
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:37
*/
#include "int2.h"
#include "enums.h"
#include "StrManip.h"
#include <vector>
#include <cmath>
int2::int2()
{
}
int2::~int2()
{
}
int2::int2(std::string const &text)
{
std::vector<std::string> posList;
split(text, ',', posList);
x=atoi(posList.at(0));
y=atoi(posList.at(1));
}
Direction int2::direction() const
{
if(x==0 && y==0)
return Direction::count; // Invalid
else if(y>=std::abs(x))
return Direction::down;
else if(x>=std::abs(y))
return Direction::right;
else if(x<=-std::abs(y))
return Direction::left;
else
return Direction::up;
}
Direction int2::secondary() const
{
if(x==0 || y==0)
return Direction::count; //Invalid
else if(y<=std::abs(x) && y>=0)
return Direction::down;
else if(x<=std::abs(y) && x>=0)
return Direction::right;
else if(x>=-std::abs(y) && x<=0)
return Direction::left;
else
return Direction::up;
}
int int2::distTo(int2 const &other) const
{
return std::abs(x-other.x)+std::abs(y-other.y);
}
int int2::quadDistTo(int2 const &other) const
{
return sq(x-other.x)+sq(y-other.y);
}
int2 int2::operator+(int2 const &other) const
{
return int2(x+other.x,y+other.y);
}
int2 int2::operator-(int2 const &other) const
{
return int2(x-other.x,y-other.y);
}
std::ostream &operator<<(std::ostream &os, const int2& c)
{
return os<<c.x<<","<<c.y;
}
std::istream &operator>>(std::istream &is, int2& c)
{
std::string text;
is>>text;
c=int2(text);
return is;
}
/*
* @file int2.h
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:37
*/
#ifndef INT2_H
#define INT2_H
#include "enums.h"
#include <string>
struct int2
{
public:
int2();
int2(int p_x, int p_y) : x(p_x), y(p_y) {}
int2(std::string const &text);
virtual ~int2();
public:
Direction direction() const;
Direction secondary() const;
int distTo(int2 const &other) const;
int quadDistTo(int2 const &other) const;
int2 operator+(int2 const &other) const;
int2 operator-(int2 const &other) const;
bool operator==(int2 const &other) const { return x==other.x && y==other.y; }
bool operator!=(int2 const &other) const { return x!=other.x || y!=other.y; }
friend std::ostream &operator<<(std::ostream &os, const int2& c);
friend std::istream &operator>>(std::istream &is, int2& c);
public:
int x;
int y;
};
inline int sq(int val) { return val*val; }
template<typename T>
inline void varSwitch(T &a, T &b) { T tmp=a; a=b; b=tmp; }
#endif /* INT2_H */
/*
* @file main.cpp
* @author GholGoth21
* @date Créé le 28 février 2015 à 17:23
*/
#include "int2.h"
#include "Snake.h"
#include "Enemy.h"
#include <cstdlib>
#include <iostream>
#include <fstream>
using namespace std;
/*
* @brief La fonction principale du programme.
* @param argc Le nombre de paramètres passés en ligne de commandes.
* @param argv La liste des paramètres passés en ligne de commandes.
*/
int main(int argc, char** argv)
{
/* Error handling */
if(argc<3)
{
cerr<<"Error : not enough arguments on the command line."<<endl;
cout<<"F"<<endl;
return 1;
}
/* Init and load */
int2 prevFood;
int date = 0;
Enemy enemy;
ifstream load("PreviousState.txt");
if(load)
{
load>>date;
load>>prevFood;
load>>enemy;
load.close();
}
int2 food(argv[1]);
Snake me(argv[2]);
if(me.isStarting())
{
date=0;
if(me.curPos().x<MAPSIZE/2)
enemy.setPos(int2(MAPSIZE-4,MAPSIZE/2), 0);
else
enemy.setPos(int2(3,MAPSIZE/2), 0);
}
else if(prevFood!=food && me.curPos()!=prevFood)
{
enemy.setPos(prevFood, date);
}
/* Moving */
cout<<me.move(food,date,enemy)<<endl;
/* Saving */
ofstream save("PreviousState.txt");
if(save)
{
save<<++date<<endl;
save<<food<<endl;
save<<enemy<<endl;
save.close();
}
return 0;
}
# Makefile
HEADERS = $(wildcard $(SRCPATH)/*.h)
SOURCES = $(wildcard $(SRCPATH)/*.cpp)
OBJECTS = $(patsubst $(SRCPATH)/%.cpp,$(BUILDPATH)/%.o,$(SOURCES))
M = Makefile
CFLAGS = -Wall -std=c++11
BINPATH = bin
BUILDPATH = build
SRCPATH = src
ifeq ($(OS),Windows_NT)
EXE = Zen.exe
else
EXE = Zen
endif
$(BINPATH)/$(EXE): $(BINPATH) $(BUILDPATH) $(OBJECTS)
g++ -o $@ $(OBJECTS)
$(BUILDPATH)/%.o: $(SRCPATH)/%.cpp $(HEADERS) $M
g++ $(CFLAGS) -o $@ -c $<
$(BINPATH) $(BUILDPATH):
mkdir $@
clean:
rm $(OBJECTS)
Или загрузите zip-файл: Zen.zip
Результаты
| Name | Master | Score |
|--------------|------------|-------|
| Zen | GholGoth21 | 24 |
| SneakySnake | Cipher | 10 |
| ViciousViper | Cipher | 6 |
| CircleOfLife | Manu | 4 |
И несколько типичных сражений (ViciousViper против Zen и SneakySnake против Zen):
Редактировать : я добавляю эту очень интересную битву против CircleOfLife: