Browse Source

Merge pull request #652 from xiangmy21/dev

添加选手代码
dev
xiangmy21 GitHub 2 years ago
parent
commit
274065ed49
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
100 changed files with 831388 additions and 0 deletions
  1. +3656
    -0
      players/-/player1.cpp
  2. +3656
    -0
      players/-/player2.cpp
  3. +3656
    -0
      players/-/player3.cpp
  4. +3656
    -0
      players/-/player4.cpp
  5. +3656
    -0
      players/-/player5.cpp
  6. +222761
    -0
      players/ChatGPA/player1.cpp
  7. +1575
    -0
      players/ChatGPA/player2.cpp
  8. +222762
    -0
      players/ChatGPA/player3.cpp
  9. +222762
    -0
      players/ChatGPA/player4.cpp
  10. +995
    -0
      players/ChatGPA/player5.cpp
  11. +3757
    -0
      players/LQ说什么都队/player1.cpp
  12. +3757
    -0
      players/LQ说什么都队/player2.cpp
  13. +3757
    -0
      players/LQ说什么都队/player3.cpp
  14. +3757
    -0
      players/LQ说什么都队/player4.cpp
  15. +3757
    -0
      players/LQ说什么都队/player5.cpp
  16. +1255
    -0
      players/Mukava Poikaa/player1.cpp
  17. +1255
    -0
      players/Mukava Poikaa/player2.cpp
  18. +1255
    -0
      players/Mukava Poikaa/player3.cpp
  19. +1255
    -0
      players/Mukava Poikaa/player4.cpp
  20. +1255
    -0
      players/Mukava Poikaa/player5.cpp
  21. +2902
    -0
      players/N-A/player1.cpp
  22. +2902
    -0
      players/N-A/player2.cpp
  23. +2902
    -0
      players/N-A/player3.cpp
  24. +2902
    -0
      players/N-A/player4.cpp
  25. +2902
    -0
      players/N-A/player5.cpp
  26. +2477
    -0
      players/PKT48TeamTS/player1.cpp
  27. +2477
    -0
      players/PKT48TeamTS/player2.cpp
  28. +2477
    -0
      players/PKT48TeamTS/player3.cpp
  29. +2477
    -0
      players/PKT48TeamTS/player4.cpp
  30. +2477
    -0
      players/PKT48TeamTS/player5.cpp
  31. +1014
    -0
      players/closeAI/player1.cpp
  32. +1014
    -0
      players/closeAI/player2.cpp
  33. +1014
    -0
      players/closeAI/player3.cpp
  34. +1014
    -0
      players/closeAI/player4.cpp
  35. +382
    -0
      players/closeAI/player5.cpp
  36. +735
    -0
      players/pqfobj/player1.py
  37. +735
    -0
      players/pqfobj/player2.py
  38. +735
    -0
      players/pqfobj/player3.py
  39. +735
    -0
      players/pqfobj/player4.py
  40. +734
    -0
      players/pqfobj/player5.py
  41. +977
    -0
      players/一会吃萤火虫/player1.cpp
  42. +977
    -0
      players/一会吃萤火虫/player2.cpp
  43. +977
    -0
      players/一会吃萤火虫/player3.cpp
  44. +977
    -0
      players/一会吃萤火虫/player4.cpp
  45. +977
    -0
      players/一会吃萤火虫/player5.cpp
  46. +772
    -0
      players/京ICP备2022019669号-1 2022 EESAST/player1.cpp
  47. +772
    -0
      players/京ICP备2022019669号-1 2022 EESAST/player2.cpp
  48. +772
    -0
      players/京ICP备2022019669号-1 2022 EESAST/player3.cpp
  49. +772
    -0
      players/京ICP备2022019669号-1 2022 EESAST/player4.cpp
  50. +871
    -0
      players/京ICP备2022019669号-1 2022 EESAST/player5.cpp
  51. +1212
    -0
      players/代码一行都不队/player1.py
  52. +1212
    -0
      players/代码一行都不队/player2.py
  53. +1212
    -0
      players/代码一行都不队/player3.py
  54. +1212
    -0
      players/代码一行都不队/player4.py
  55. +1212
    -0
      players/代码一行都不队/player5.py
  56. +1226
    -0
      players/你说什么都队/player1.cpp
  57. +1226
    -0
      players/你说什么都队/player2.cpp
  58. +1226
    -0
      players/你说什么都队/player3.cpp
  59. +1226
    -0
      players/你说什么都队/player4.cpp
  60. +1226
    -0
      players/你说什么都队/player5.cpp
  61. +1587
    -0
      players/你说得队/player1.py
  62. +1587
    -0
      players/你说得队/player2.py
  63. +1587
    -0
      players/你说得队/player3.py
  64. +1556
    -0
      players/你说得队/player4.py
  65. +1016
    -0
      players/你说得队/player5.py
  66. +1596
    -0
      players/劝退吧,少女/player1.cpp
  67. +1596
    -0
      players/劝退吧,少女/player2.cpp
  68. +1596
    -0
      players/劝退吧,少女/player3.cpp
  69. +1596
    -0
      players/劝退吧,少女/player4.cpp
  70. +2041
    -0
      players/劝退吧,少女/player5.cpp
  71. +4043
    -0
      players/努力少女戏尔危/player1.cpp
  72. +4043
    -0
      players/努力少女戏尔危/player2.cpp
  73. +4043
    -0
      players/努力少女戏尔危/player3.cpp
  74. +4043
    -0
      players/努力少女戏尔危/player4.cpp
  75. +4043
    -0
      players/努力少女戏尔危/player5.cpp
  76. +310
    -0
      players/卷动量守恒/player1.cpp
  77. +310
    -0
      players/卷动量守恒/player2.cpp
  78. +297
    -0
      players/卷动量守恒/player3.cpp
  79. +314
    -0
      players/卷动量守恒/player4.cpp
  80. +342
    -0
      players/卷动量守恒/player5.cpp
  81. +1622
    -0
      players/叛逃者联盟/player1.cpp
  82. +1622
    -0
      players/叛逃者联盟/player2.cpp
  83. +1622
    -0
      players/叛逃者联盟/player3.cpp
  84. +1622
    -0
      players/叛逃者联盟/player4.cpp
  85. +1622
    -0
      players/叛逃者联盟/player5.cpp
  86. +425
    -0
      players/土木清华没有水/player1.cpp
  87. +425
    -0
      players/土木清华没有水/player2.cpp
  88. +425
    -0
      players/土木清华没有水/player3.cpp
  89. +425
    -0
      players/土木清华没有水/player4.cpp
  90. +168
    -0
      players/土木清华没有水/player5.cpp
  91. +899
    -0
      players/大括号换行委员会/player1.cpp
  92. +899
    -0
      players/大括号换行委员会/player2.cpp
  93. +899
    -0
      players/大括号换行委员会/player3.cpp
  94. +899
    -0
      players/大括号换行委员会/player4.cpp
  95. +930
    -0
      players/大括号换行委员会/player5.cpp
  96. +1830
    -0
      players/孤客若风/player1.cpp
  97. +1830
    -0
      players/孤客若风/player2.cpp
  98. +1830
    -0
      players/孤客若风/player3.cpp
  99. +1830
    -0
      players/孤客若风/player4.cpp
  100. +1782
    -0
      players/孤客若风/player5.cpp

+ 3656
- 0
players/-/player1.cpp
File diff suppressed because it is too large
View File


+ 3656
- 0
players/-/player2.cpp
File diff suppressed because it is too large
View File


+ 3656
- 0
players/-/player3.cpp
File diff suppressed because it is too large
View File


+ 3656
- 0
players/-/player4.cpp
File diff suppressed because it is too large
View File


+ 3656
- 0
players/-/player5.cpp
File diff suppressed because it is too large
View File


+ 222761
- 0
players/ChatGPA/player1.cpp
File diff suppressed because it is too large
View File


+ 1575
- 0
players/ChatGPA/player2.cpp
File diff suppressed because it is too large
View File


+ 222762
- 0
players/ChatGPA/player3.cpp
File diff suppressed because it is too large
View File


+ 222762
- 0
players/ChatGPA/player4.cpp
File diff suppressed because it is too large
View File


+ 995
- 0
players/ChatGPA/player5.cpp View File

@@ -0,0 +1,995 @@
#include <array>
#include <cmath>
#include <queue>
#include <sstream>
#include <stack>
#include <thread>
#include <utility>
#include <vector>
#include "AI.h"
#include "constants.h"
#define PI 3.14159265358979323846

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
struct CellPos {
int x, y;
};
struct GridPos {
int x, y;
};

class Action;
class BFS;
class Communication;
class Escape;
class GameState;

class Action {
public:
enum class Direction {
null, up, down, left, right,
up_left, up_right, down_left, down_right
}; //移动方式
static const std::vector <Direction> allMove; //所有的移动方式
static int isAtCellFalseCnt;
static int classNo; //要去的教室位置
static CellPos lastNextPos;
static CellPos lastDesPos;
static Direction lastMove;
static CellPos PredictPos;

static bool isValidMove(CellPos judgePos, Direction comeDir, GameState state, IStudentAPI& api);
static bool isValidMove(CellPos judgePos, Direction comeDir, GameState state, ITrickerAPI& api);
static double getAngle(GridPos grid1, GridPos grid2); //计算两点间方位角
static void Move(CellPos des, IStudentAPI& api);
static void Move(CellPos des, ITrickerAPI& api);
static void Move(Direction directon, IStudentAPI& api);
static void Move(Direction direction, ITrickerAPI& api);
static CellPos directionToPos(CellPos nowPos, Direction direction); //根据当前坐标和移动方式计算出下一个坐标
static Direction posToDirection(CellPos nowPos, CellPos nextPos); //目标点的坐标转化为移动方式
};
class BFS {
public:
static bool vis[Constants::rows][Constants::cols];
static CellPos now;
static CellPos nxt;
static CellPos pre[Constants::rows][Constants::cols];

static std::pair<CellPos, int> bfs(CellPos start, CellPos destination, ITrickerAPI& api);
static std::pair<std::pair<CellPos, CellPos>, int> bfs(CellPos start, THUAI6::PlaceType destination, ITrickerAPI& api); //return pair<next_point,destination>
};
class Communication {
public:
static void receiveMessage(IStudentAPI& api, int64_t myID);
static void sendClassroomPos(IStudentAPI& api, int64_t myID, CellPos classroomPos);
static void sendTrickerPos(IStudentAPI& api, int64_t myID);
/*
通信协议:AA BB CC DD
(AA, BB)为学完的教室的坐标
(CC, DD)为看到的捣蛋鬼的坐标
若AA, BB均为-1,则忽略教室坐标,只读捣蛋鬼坐标
若CC, DD均为-1,则忽略捣蛋鬼坐标,只读教室坐标
*/
};
class Escape {
public:
//static std::pair<CellPos, Action::Direction> minimax(CellPos start, THUAI6::PlaceType destination); //规避算法
};
class GameState {
public:
static int readCnt;
static int clsFinishCnt;
THUAI6::PlaceType gameMap[Constants::rows][Constants::cols]; //存图信息
std::vector <CellPos> ClassRoom;
std::vector <CellPos> Gate;
std::vector <CellPos> HiddenGate;
std::vector <CellPos> Window;
std::vector <CellPos> Door3;
std::vector <CellPos> Door5;
std::vector <CellPos> Door6;
std::vector <CellPos> Chest;
std::vector <std::pair<GridPos,int>> ValidMoveBuffer;
CellPos studentPos[4]; //四个学生的坐标
GridPos studentGrid[4];
CellPos trickerPos; //捣蛋鬼的坐标

bool isAtCell(GridPos myPos, GridPos cellPos) const; //判断人物是否完全在格点内
bool isAtPosition(CellPos myPos, CellPos pos) const;
bool isAtPos(CellPos myPos, CellPos pos) const; //判断character坐标与pos坐标是否在一个九宫格内
bool isAttackable(GridPos trickerPos, GridPos studentPos) const; //判断是否可以攻击
bool isClassroomFinished(CellPos classroomPos, IStudentAPI& studentapi) const; //判断教室是否学完了
bool isDoor(CellPos pos) const;
bool isGateFinished(CellPos gatePos, IStudentAPI& api) const; //判断大门是否开了
bool isTrickerVisible() const; //判断tricker是否可见
bool isType(CellPos pos, THUAI6::PlaceType type) const;
bool canReach(CellPos pos, ITrickerAPI& api) const;
bool readyToGraduate() const; //判断当前局面是否可毕业
double gridDistance(GridPos grid1, GridPos grid2) const; //计算两点间以grid计的距离
void deleteStudiedClassroom(CellPos classroomPos); //把学完的教室删除,变成墙
void getMap(IStudentAPI& api); //获取地图格点信息
void getMap(ITrickerAPI& api); //获取地图格点信息
std::pair<std::pair<bool, std::pair<CellPos, GridPos>>, std::pair<double, double>> getClosestStudent(GridPos trickerPos, ITrickerAPI& api); //找到视野中最近的学生
//CellPos isGrassAround(CellPos, IStudentAPI& api) const;
};

const std::vector <Action::Direction> Action::allMove = {
Direction::up,
Direction::down,
Direction::left,
Direction::right,
Direction::up_left,
Direction::up_right,
Direction::down_left,
Direction::down_right
};
int Action::isAtCellFalseCnt = 0;
int Action::classNo = 0;
CellPos Action::lastNextPos = { -1,-1 };
Action::Direction Action::lastMove = Direction::null;
CellPos Action::lastDesPos = { -1,-1 };
bool BFS::vis[Constants::rows][Constants::cols] = { false };
CellPos BFS::now = { -1,-1 };
CellPos BFS::nxt = { -1,-1 };
CellPos BFS::pre[Constants::rows][Constants::cols] = { {-1,-1} };

int GameState::readCnt = 0;
int GameState::clsFinishCnt = 0;
GameState gameState;

bool Action::isValidMove(CellPos judgePos, Direction comeDir, GameState state, IStudentAPI& api)
{
auto students = api.GetStudents();

for (auto it = students.begin(); it != students.end(); it++)
{

state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y + 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y - 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
}
auto trickers = api.GetTrickers();
for (auto it = trickers.begin(); it != trickers.end(); it++)
{
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y + 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y - 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
}
switch (comeDir)
{
case Action::Direction::up_left: {
if (state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Grass)return false;
if (state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Grass)return false;
break;
}
case Action::Direction::up_right: {
if (state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Grass)return false;
if (state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Grass)return false;
break;
}
case Action::Direction::down_right: {
if (state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Grass)return false;
if (state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Grass)return false;
break;
}
case Action::Direction::down_left: {
if (state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Grass)return false;
if (state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Land && state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Grass)return false;
break;
}
default:break;
}
return state.gameMap[judgePos.x][judgePos.y] == THUAI6::PlaceType::Land
|| state.gameMap[judgePos.x][judgePos.y] == THUAI6::PlaceType::Grass
|| state.gameMap[judgePos.x][judgePos.y] == THUAI6::PlaceType::Window
|| (state.isDoor(judgePos) && api.IsDoorOpen(judgePos.x, judgePos.y));
}
bool Action::isValidMove(CellPos judgePos, Direction comeDir, GameState state, ITrickerAPI& api)
{
for (int i=0; i<gameState.ValidMoveBuffer.size(); i++) {
auto it = &gameState.ValidMoveBuffer[i].first;
if (api.HaveView(it->x, it->y)|| (api.GetFrameCount()- gameState.ValidMoveBuffer[i].second)>=100) {
gameState.ValidMoveBuffer.erase(gameState.ValidMoveBuffer.begin()+i);
i--;
}
else {
state.gameMap[api.GridToCell(it->x)][api.GridToCell(it->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x + 390)][api.GridToCell(it->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x - 390)][api.GridToCell(it->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x)][api.GridToCell(it->y + 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x)][api.GridToCell(it->y - 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x + 280)][api.GridToCell(it->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x + 280)][api.GridToCell(it->y - 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x - 280)][api.GridToCell(it->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell(it->x - 280)][api.GridToCell(it->y - 280)] = THUAI6::PlaceType::Wall;
}
}
auto students = api.GetStudents();
for (auto it = students.begin(); it != students.end(); it++)
{
if ((*it)->determination>0)
continue;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 390)][api.GridToCell((*it)->y)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y + 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x)][api.GridToCell((*it)->y - 390)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x + 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y + 280)] = THUAI6::PlaceType::Wall;
state.gameMap[api.GridToCell((*it)->x - 280)][api.GridToCell((*it)->y - 280)] = THUAI6::PlaceType::Wall;
gameState.ValidMoveBuffer.push_back({ { (*it)->x ,(*it)->y },api.GetFrameCount()});
}
switch (comeDir)
{
case Action::Direction::up_left: {

if (state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Land )return false;
if (state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Land )return false;
break;
}
case Action::Direction::up_right: {

if (state.gameMap[judgePos.x + 1][judgePos.y] != THUAI6::PlaceType::Land )return false;
if (state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Land )return false;
break;
}
case Action::Direction::down_right: {

if (state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Land )return false;
if (state.gameMap[judgePos.x][judgePos.y - 1] != THUAI6::PlaceType::Land )return false;
break;
}
case Action::Direction::down_left: {

if (state.gameMap[judgePos.x - 1][judgePos.y] != THUAI6::PlaceType::Land )return false;
if (state.gameMap[judgePos.x][judgePos.y + 1] != THUAI6::PlaceType::Land )return false;
break;
}
default:break;
}
return state.canReach(judgePos, api);
}
double Action::getAngle(GridPos grid1, GridPos grid2)
{
return atan2(grid2.y - grid1.y, grid2.x - grid1.x);
}
void Action::Move(CellPos destination, IStudentAPI& api)
{
int desX = api.CellToGrid(destination.x);
int desY = api.CellToGrid(destination.y);
auto self = api.GetSelfInfo();
api.Move(50, getAngle({ self->x,self->y }, { desX,desY }));
}
void Action::Move(CellPos destination, ITrickerAPI& api)
{
int desX = api.CellToGrid(destination.x);
int desY = api.CellToGrid(destination.y);
auto self = api.GetSelfInfo();
api.Move(50, getAngle({ self->x,self->y }, { desX,desY }));
}

void Action::Move(Direction direction, IStudentAPI& api)
{
auto self = api.GetSelfInfo();
int x = api.GridToCell(self->x);
int y = api.GridToCell(self->y);
Move(Action::directionToPos({ x, y }, direction), api);
}
void Action::Move(Direction direction, ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
int x = api.GridToCell(self->x);
int y = api.GridToCell(self->y);
Move(Action::directionToPos({ x, y }, direction), api);
}
CellPos Action::directionToPos(CellPos nowPos, Direction direction)
{
switch (direction)
{
case Action::Direction::up:
return { nowPos.x - 1, nowPos.y };
case Action::Direction::down:
return { nowPos.x + 1, nowPos.y };
case Action::Direction::left:
return { nowPos.x, nowPos.y - 1 };
case Action::Direction::right:
return { nowPos.x, nowPos.y + 1 };
case Action::Direction::up_left:
return { nowPos.x - 1, nowPos.y - 1 };
case Action::Direction::up_right:
return { nowPos.x - 1, nowPos.y + 1 };
case Action::Direction::down_left:
return { nowPos.x + 1, nowPos.y - 1 };
case Action::Direction::down_right:
return { nowPos.x + 1, nowPos.y + 1 };
}
return { -1,-1 };
}
Action::Direction Action::posToDirection(CellPos nowPos, CellPos nextPos)
{
if (nextPos.x == nowPos.x + 1 && nextPos.y == nowPos.y)
return Action::Direction::down;
if (nextPos.x == nowPos.x - 1 && nextPos.y == nowPos.y)
return Action::Direction::up;
if (nextPos.x == nowPos.x && nextPos.y == nowPos.y + 1)
return Action::Direction::right;
if (nextPos.x == nowPos.x && nextPos.y == nowPos.y - 1)
return Action::Direction::left;
if (nextPos.x == nowPos.x + 1 && nextPos.y == nowPos.y + 1)
return Action::Direction::down_right;
if (nextPos.x == nowPos.x - 1 && nextPos.y == nowPos.y + 1)
return Action::Direction::up_right;
if (nextPos.x == nowPos.x + 1 && nextPos.y == nowPos.y - 1)
return Action::Direction::down_left;
if (nextPos.x == nowPos.x - 1 && nextPos.y == nowPos.y - 1)
return Action::Direction::up_left;
return Action::Direction::null;
}

std::pair<CellPos, int> BFS::bfs(CellPos start, CellPos destination, ITrickerAPI& api)
{
int length = 0;
std::queue<CellPos> posQ;

memset(vis, false, sizeof(vis));
vis[start.x][start.y] = true;
posQ.push(start);
while (!posQ.empty())
{
now = posQ.front();
posQ.pop();
for (auto move = Action::allMove.begin(); move != Action::allMove.end(); move++)
{
nxt = Action::directionToPos(now, *move);
if (nxt.x == destination.x && nxt.y == destination.y && !gameState.canReach(nxt, api))
{
pre[nxt.x][nxt.y] = now;
now = nxt;
break;
}
if (!Action::isValidMove(nxt, *move, gameState, api) || vis[nxt.x][nxt.y])
continue;
if (nxt.x == destination.x && nxt.y == destination.y)
{
pre[nxt.x][nxt.y] = now;
now = nxt;
break;
}
vis[nxt.x][nxt.y] = true;
posQ.push(nxt);
pre[nxt.x][nxt.y] = now;
}
if (now.x == nxt.x && now.y == nxt.y)
{
while (pre[now.x][now.y].x != start.x || pre[now.x][now.y].y != start.y)
{
now = pre[now.x][now.y];
length++;
}
return { now, length + 1 };
}
}
return { {-1,-1},-1 };
}
std::pair<std::pair<CellPos, CellPos>,int> BFS::bfs(CellPos start, THUAI6::PlaceType destination, ITrickerAPI& api)
{
int length = 0;
std::queue<CellPos> posQ;
if (gameState.gameMap[start.x][start.y] == destination) {
return { {start,start},0 };
}
memset(vis, false, sizeof(vis));
vis[start.x][start.y] = true;
posQ.push(start);
while (!posQ.empty())
{
now = posQ.front();
posQ.pop();
for (auto move = Action::allMove.begin(); move != Action::allMove.end(); move++)
{
nxt = Action::directionToPos(now, *move);
if (gameState.gameMap[nxt.x][nxt.y] == destination && !gameState.canReach(nxt, api))
{
pre[nxt.x][nxt.y] = now;
now = nxt;
break;
}
if (!Action::isValidMove(nxt, *move, gameState, api) || vis[nxt.x][nxt.y])
continue;
if (gameState.gameMap[nxt.x][nxt.y] == destination)
{
pre[nxt.x][nxt.y] = now;
now = nxt;
break;
}
vis[nxt.x][nxt.y] = true;
posQ.push(nxt);
pre[nxt.x][nxt.y] = now;
}
if (now.x == nxt.x && now.y == nxt.y)
{
while (pre[now.x][now.y].x != start.x || pre[now.x][now.y].y != start.y) {
length++;
now = pre[now.x][now.y];
}
return { { now,nxt },length };
}
}
return { { {-1,-1},{-1,-1} },1000 };
}

void Communication::sendClassroomPos(IStudentAPI& api, int64_t myID, CellPos classroomPos) {
auto message = fmt::format("{} {} {} {}", classroomPos.x, classroomPos.y, -1, -1);
for (int id = 0; id <= 3; id++)
if (id != myID)
api.SendTextMessage(id, message);
}
void Communication::sendTrickerPos(IStudentAPI& api, int64_t myID) {
auto trickers = api.GetTrickers();
if (trickers.empty())
return;
CellPos trickerPos = { api.GridToCell(trickers[0]->x), api.GridToCell(trickers[0]->y) };
auto message = fmt::format("{} {} {} {}", -1, -1, trickerPos.x, trickerPos.y);
for (int i = 0; i <= 3; i++)
if (i != myID)
api.SendTextMessage(i, message);
}
void Communication::receiveMessage(IStudentAPI& api, int64_t myID) {
CellPos classroomPos, trickerPos;
std::pair<int64_t, std::string> message;
std::stringstream ss;
gameState.trickerPos = { -1, -1 };
auto trickers = api.GetTrickers();
if (!trickers.empty())
gameState.trickerPos = { api.GridToCell(trickers[0]->x), api.GridToCell(trickers[0]->y) };
while (api.HaveMessage()) {
ss.clear();
message = api.GetMessage();
ss.str(message.second);
ss >> classroomPos.x >> classroomPos.y >> trickerPos.x >> trickerPos.y;
if (classroomPos.x != -1 && classroomPos.y != -1)
gameState.deleteStudiedClassroom(classroomPos);
if (trickerPos.x != -1 && trickerPos.y != -1)
gameState.trickerPos = trickerPos;
}
}

inline bool GameState::isAtCell(GridPos myPos, GridPos cellPos) const {
return abs(myPos.x - cellPos.x) < 100 && abs(myPos.y - cellPos.y) < 100;
}
inline bool GameState::isAtPosition(CellPos character, CellPos pos) const {
return (abs(character.x - pos.x) <= 1 && abs(character.y - pos.y) <= 1);
}
inline bool GameState::isAtPos(CellPos character, CellPos pos) const {
return (abs(character.x - pos.x) <= 1 && abs(character.y - pos.y) == 0) || (abs(character.y - pos.y) <= 1 && abs(character.x - pos.x) == 0);
}
inline bool GameState::isAttackable(GridPos trickerPos, GridPos studentPos) const {
return gridDistance(trickerPos, studentPos) <= 1500;
}
inline bool GameState::isClassroomFinished(CellPos classroomPos, IStudentAPI& api) const {
return api.GetClassroomProgress(classroomPos.x, classroomPos.y) >= Constants::maxClassroomProgress;
}
inline bool GameState::isDoor(CellPos pos) const {
return gameMap[pos.x][pos.y] == THUAI6::PlaceType::Door3
|| gameMap[pos.x][pos.y] == THUAI6::PlaceType::Door5
|| gameMap[pos.x][pos.y] == THUAI6::PlaceType::Door6;
}
inline bool GameState::isGateFinished(CellPos gatePos, IStudentAPI& api) const {
return api.GetGateProgress(gatePos.x, gatePos.y) >= Constants::maxGateProgress;
}
inline bool GameState::isTrickerVisible() const {
return trickerPos.x == -1 && trickerPos.y == -1;
}
inline bool GameState::isType(CellPos pos, THUAI6::PlaceType type) const {
return gameMap[pos.x][pos.y] == type;
}
inline bool GameState::canReach(CellPos pos, ITrickerAPI& api) const {
return gameMap[pos.x][pos.y] == THUAI6::PlaceType::Window
|| gameMap[pos.x][pos.y] == THUAI6::PlaceType::Grass
|| gameMap[pos.x][pos.y] == THUAI6::PlaceType::Land
|| (isDoor(pos) && api.IsDoorOpen(pos.x, pos.y));
}
inline bool GameState::readyToGraduate() const {
return clsFinishCnt >= Constants::numOfRequiredClassroomForGate;
}
double GameState::gridDistance(GridPos grid1, GridPos grid2) const {
return sqrt(pow((grid1.x - grid2.x), 2) + pow((grid1.y - grid2.y), 2));
}
void GameState::deleteStudiedClassroom(CellPos classroomPos) {
for (auto it = gameState.ClassRoom.begin(); it != gameState.ClassRoom.end(); it++)
if (it->x == classroomPos.x && it->y == classroomPos.y)
{
ClassRoom.erase(it);
gameState.gameMap[classroomPos.x][classroomPos.y] = THUAI6::PlaceType::Wall;
clsFinishCnt++;
break;
}
}
void GameState::getMap(IStudentAPI& api) {
for (int i = 0; i < Constants::rows; i++) {
for (int j = 0; j < Constants::cols; j++) {
gameMap[i][j] = (api.GetFullMap()[i][j]);
if (gameMap[i][j] == THUAI6::PlaceType::ClassRoom) ClassRoom.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Gate) Gate.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::HiddenGate) HiddenGate.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Window) Window.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Chest) Chest.push_back({ i, j });
}
}
}
void GameState::getMap(ITrickerAPI& api) {
for (int i = 0; i < Constants::rows; i++) {
for (int j = 0; j < Constants::cols; j++) {
gameMap[i][j] = (api.GetFullMap()[i][j]);
if (gameMap[i][j] == THUAI6::PlaceType::ClassRoom) ClassRoom.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Gate) Gate.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::HiddenGate) HiddenGate.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Window) Window.push_back({ i, j });
if (gameMap[i][j] == THUAI6::PlaceType::Chest) Chest.push_back({ i, j });
}
}
}
std::pair<std::pair<bool, std::pair<CellPos,GridPos>>, std::pair<double, double>> GameState::getClosestStudent(GridPos trickerPos, ITrickerAPI& api)
{
auto students = api.GetStudents();
double minDistance = 1e5;
CellPos studentPos = { -1,-1 };
GridPos studentGrid = { -1,-1 };
bool updated[4] = { false };
bool inSight = false;
double angle[5] = { -1,-1,-1,-1,-1 };
int picked = 4;
for (auto it = students.begin(); it != students.end(); it++)
{
if ((*it)->determination<=0) {
gameState.studentPos[(*it)->playerID].x = -1;
gameState.studentPos[(*it)->playerID].y = -1;
gameState.studentGrid[(*it)->playerID].x = -1;
gameState.studentGrid[(*it)->playerID].y = -1;
continue;
}
angle[(*it)->playerID] = (*it)->facingDirection;
gameState.studentPos[(*it)->playerID].x = api.GridToCell((*it)->x);
gameState.studentPos[(*it)->playerID].y = api.GridToCell((*it)->y);
gameState.studentGrid[(*it)->playerID].x = (*it)->x;
gameState.studentGrid[(*it)->playerID].y = (*it)->y;
updated[(*it)->playerID] = true;
}
for (int i = 0; i < 4; i++) {
if (minDistance > gridDistance(trickerPos, { api.CellToGrid(gameState.studentPos[i].x),api.CellToGrid(gameState.studentPos[i].y) }) && gameState.studentPos[i].x >= 0)
{
minDistance = gridDistance(trickerPos, { api.CellToGrid(gameState.studentPos[i].x),api.CellToGrid(gameState.studentPos[i].y) });
studentPos = gameState.studentPos[i];
studentGrid = gameState.studentGrid[i];
inSight = updated[i];
picked = i;
}
}
return { {inSight,{studentPos,studentGrid}},{minDistance,angle[picked]} };
}

void AI::play(IStudentAPI& api) {}
int AttackCount = 0;
int needNew = 0;
bool del=false;
GridPos lastGrid = { -1,-1 };
int stuck = 0;
int classcount = 0;
int pointing = -1;
//bool attackToGrass = false;
std::vector <CellPos> traversal;
std::vector <CellPos> gates;
void AI::play(ITrickerAPI& api)
{
if (gameState.readCnt < 1)
{
gameState.getMap(api);
gameState.readCnt++;
for (int i = 0; i < 4; i++) {
//studentPos赋初值,代表视野没有,也没记住
gameState.studentPos[i] = { -1,-1 };
gameState.studentGrid[i] = { -1,-1 };
}
if (gameState.gameMap[5][9] == THUAI6::PlaceType::Grass) {
traversal.push_back({ 6,24 });
traversal.push_back({ 8,31 });//class
traversal.push_back({ 10,38 });//class
traversal.push_back({ 12,46 });
traversal.push_back({ 19,41 });//class
//traversal.push_back({ 18,46 });
//traversal.push_back({ 23,40 });
traversal.push_back({ 21,27 });
traversal.push_back({ 28,26 });//class
traversal.push_back({ 33,40 });//class
//traversal.push_back({ 39,38 });
traversal.push_back({ 44,32 });//class
traversal.push_back({ 40,12 });//class
//traversal.push_back({ 46,9 });
//traversal.push_back({ 36,7 });
traversal.push_back({ 30,7 });//class
traversal.push_back({ 22,18 });//class
traversal.push_back({ 18,5 });//class
traversal.push_back({ 8,16 });
traversal.push_back({ 7,21 });
gates.push_back({ 46,45 });
gates.push_back({ 5,6 });
}
else if (gameState.gameMap[5][9] == THUAI6::PlaceType::Wall) {
traversal.push_back({ 16,20 });
traversal.push_back({ 16,16 });//class
traversal.push_back({ 20,16 });
traversal.push_back({ 29,16 });
traversal.push_back({ 33,16 });//class
traversal.push_back({ 33,20 });
traversal.push_back({ 33,29 });
traversal.push_back({ 33,33 });//class
traversal.push_back({ 29,33 });
traversal.push_back({ 20,33 });
traversal.push_back({ 16,33 });//class
traversal.push_back({ 16,29 });
traversal.push_back({ 6,13 });//class
traversal.push_back({ 6,36 });//class
traversal.push_back({ 13,43 });//class
traversal.push_back({ 34,45 });
traversal.push_back({ 43,36 });//class
traversal.push_back({ 43,13 });//class
traversal.push_back({ 36,6 });//class
traversal.push_back({ 15,4 });
gates.push_back({ 47,6 });
gates.push_back({ 2,43 });
}
else {
traversal = gameState.ClassRoom;
}
api.Print("Map read");

}

if (traversal.size())
Action::classNo = Action::classNo % traversal.size();
else
Action::classNo = -1;

auto self = api.GetSelfInfo();
GridPos myGrid = { self->x,self->y };

CellPos myCell = { api.GridToCell(self->x), api.GridToCell(self->y) };
api.Print(fmt::format("mypos {} {}", myCell.x, myCell.y));
if (self->playerState == THUAI6::PlayerState::Swinging || self->playerState == THUAI6::PlayerState::Attacking || self->playerState == THUAI6::PlayerState::Stunned) {
gameState.getClosestStudent(myGrid, api);
api.Print("not idle");
return;
}
if (gameState.isAtCell(myGrid, { api.CellToGrid(myCell.x),api.CellToGrid(myCell.y) }) || Action::isAtCellFalseCnt > 15)
//if (gameState.isAtCell(myGrid, { api.CellToGrid(myCell.x),api.CellToGrid(myCell.y) }))
{
//在格点上或者连续10次进不到格点
bool notAtCell = Action::isAtCellFalseCnt > 15;
Action::isAtCellFalseCnt = 0;
api.Print(fmt::format("notAtCell {}", notAtCell));
if (!notAtCell) {
if (abs(myGrid.x - lastGrid.x) <= 5 && abs(myGrid.y - lastGrid.y) <= 5) {
stuck++;
api.Print(fmt::format("stuck {}", stuck));
}
else {
stuck = 0;
api.Print("stuck zero");
}
if (stuck >= 5) {
if (pointing <= 1) {

auto angle = Action::getAngle({ api.CellToGrid(Action::directionToPos(myCell, Action::lastMove).x), api.CellToGrid(Action::directionToPos(myCell, Action::lastMove).y) }, { api.CellToGrid(myCell.x), api.CellToGrid(myCell.y) });
angle = angle + pointing * PI / 4;
api.Attack(angle);
pointing++;
}
else {
pointing = -1;
stuck = 0;
}
api.Print(fmt::format("{} {} set to wall", Action::lastNextPos.x, Action::lastNextPos.y));
stuck = 0;
gameState.gameMap[Action::lastNextPos.x][Action::lastNextPos.y] = THUAI6::PlaceType::Wall;
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == Action::lastNextPos.x && gameState.studentPos[i].y == Action::lastNextPos.y) {
gameState.studentPos[i].x = -1;
gameState.studentPos[i].y = -1;
gameState.studentGrid[i].x = -1;
gameState.studentGrid[i].y = -1;
}
}
}
lastGrid = myGrid;
}
else{
if (gameState.gameMap[Action::lastNextPos.x][Action::lastNextPos.y] == THUAI6::PlaceType::Grass && AttackCount < 5) {

GridPos target = { api.CellToGrid(Action::lastNextPos.x),api.CellToGrid(Action::lastNextPos.y) };
api.Attack(Action::getAngle(myGrid, target));
api.Print(fmt::format("attacknum {}", AttackCount));
api.Print(fmt::format("attackto {} {}", Action::lastNextPos.x, Action::lastNextPos.y));
AttackCount++;
}
else {
AttackCount = 0;
del = true;
//Action::lastNextPos = Action::directionToPos(Action::lastNextPos, Action::lastMove);
api.Print(fmt::format("delete {} {}", Action::lastNextPos.x, Action::lastNextPos.y));
gameState.gameMap[Action::lastNextPos.x][Action::lastNextPos.y] = THUAI6::PlaceType::Wall;
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == Action::lastNextPos.x && gameState.studentPos[i].y == Action::lastNextPos.y) {
gameState.studentPos[i].x = -1;
gameState.studentPos[i].y = -1;
gameState.studentGrid[i].x = -1;
gameState.studentGrid[i].y = -1;
}
}
}

Action::lastNextPos = Action::directionToPos(Action::lastNextPos, Action::lastMove);
return;
}

auto closestStudent = gameState.getClosestStudent(myGrid, api);
bool inSight = closestStudent.first.first;
auto stuCellPos = closestStudent.first.second.first;
GridPos stuGridPos = closestStudent.first.second.second;
auto distance = closestStudent.second.first;
api.Print(fmt::format("insight {} stupos {} {} distance {}", inSight, stuCellPos.x, stuCellPos.y, distance));
if (distance < Constants::basicTrickerViewRange)//如果视野里有学生,且未沉迷,则判断攻击条件,不满足则追击学生
{
Action::lastDesPos = { stuCellPos.x,stuCellPos.y };
bool isClose;
if (inSight) {
isClose = gameState.isAtPos(myCell, stuCellPos);
api.UseSkill(0);
//if ((!api.GetSelfInfo()->buff.empty())&&api.GetSelfInfo()->buff[0]==THUAI6::TrickerBuffType::Invisible)
//api.Print("invisible");
api.UseSkill(1);
if (api.GetSelfInfo()->bulletType == THUAI6::BulletType::FlyingKnife) {
//api.Print("knife");
api.Attack(Action::getAngle(myGrid, stuGridPos));
}

}
else {

isClose = gameState.isAtCell(myGrid, {api.CellToGrid(stuCellPos.x),api.CellToGrid(stuCellPos.y)}) || (gameState.isAtPosition(myCell, stuCellPos) && notAtCell);
}
api.Print(fmt::format("isclose {}", isClose));
if (isClose) {

if (inSight) {
api.Attack(Action::getAngle(myGrid, stuGridPos));

}
/*
else if (notAtCell && AttackCount < 3) {
api.Attack(Action::getAngle(myGrid, stuGridPos));
AttackCount++;
}

else if (del) {
//AttackCount = 0;
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == stuCellPos.x && gameState.studentPos[i].y == stuCellPos.y) {
gameState.studentPos[i].x = -1;
gameState.studentPos[i].y = -1;
}
}
del = false;
}*/
else {

if (gameState.gameMap[myCell.x][myCell.y] != THUAI6::PlaceType::Grass) {
int newx, newy;
/*
if (gameState.gameMap[stuCellPos.x][stuCellPos.y] == THUAI6::PlaceType::Grass) {
newx = stuCellPos.x;
newy = stuCellPos.y;
}
for (int i = -1; i <= 1; i = i + 2) {
if (gameState.gameMap[stuCellPos.x + i][stuCellPos.y] == THUAI6::PlaceType::Grass) {
newx = stuCellPos.x + i;
newy = stuCellPos.y;
}
}
for (int j = -1; j <= 1; j = j + 2) {
if (gameState.gameMap[stuCellPos.x][stuCellPos.y + j] == THUAI6::PlaceType::Grass) {
newx = stuCellPos.x;
newy = stuCellPos.y + j;
}
}
*/
api.Print("bfsing");
auto result = BFS::bfs(myCell, THUAI6::PlaceType::Grass, api);
api.Print(fmt::format("newdist {}", result.second));
if (result.second < 5&&result.second>=0) {
newx = result.first.second.x;
newy = result.first.second.y;
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == stuCellPos.x && gameState.studentPos[i].y == stuCellPos.y) {
gameState.studentPos[i].x = newx;
gameState.studentPos[i].y = newy;
gameState.studentGrid[i].x = api.CellToGrid(newx);
gameState.studentGrid[i].y = api.CellToGrid(newy);
}
}
api.Print(fmt::format("newxy {} {}", newx, newy));
}


//needNew=3;
//return;
}
else {
api.Print("not bfsing");
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == stuCellPos.x && gameState.studentPos[i].y == stuCellPos.y) {
gameState.studentPos[i].x = -1;
gameState.studentPos[i].y = -1;
gameState.studentGrid[i].x = -1;
gameState.studentGrid[i].y = -1;
}
}
}




}
}
else
{
api.Print(fmt::format("my pos {} {}", myCell.x, myCell.y));
api.Print(fmt::format("stu pos {} {}", stuCellPos.x, stuCellPos.y));
auto result = BFS::bfs(myCell, stuCellPos, api);
auto nextPos = result.first;
api.Print(fmt::format("next {} {}", nextPos.x, nextPos.y));
if (nextPos.x == -1) {
for (int i = 0; i < 4; i++) {
if (gameState.studentPos[i].x == stuCellPos.x && gameState.studentPos[i].y == stuCellPos.y) {
gameState.studentPos[i].x = -1;
gameState.studentPos[i].y = -1;
}
}
return;
}
if (gameState.isType(nextPos, THUAI6::PlaceType::Window))
api.SkipWindow();
Action::Move(nextPos, api);
Action::lastNextPos = nextPos;
Action::lastMove = Action::posToDirection(nextPos, myCell);
}
}
else//视野里没有学生,就遍历教室并前往
{
if (classcount >= 7) {
auto classroomCellPos = gates[0];
GridPos classroomGridPos = { api.CellToGrid(classroomCellPos.x),api.CellToGrid(classroomCellPos.y) };
api.Print(fmt::format("class pos {} {}", classroomCellPos.x, classroomCellPos.y));
auto result = BFS::bfs(myCell, classroomCellPos, api);
auto nextPos = result.first;
api.Print(fmt::format("next pos {} {}", nextPos.x, nextPos.y));
if (nextPos.x == -1) {
return;
}

if (!gameState.isAtPosition(myCell, classroomCellPos))
{
if (gameState.isType(nextPos, THUAI6::PlaceType::Window))
api.SkipWindow();
Action::Move(nextPos, api);
Action::lastNextPos = nextPos;
Action::lastMove = Action::posToDirection(nextPos, myCell);
}
return;
}
auto classroomCellPos = traversal[Action::classNo];
GridPos classroomGridPos = { api.CellToGrid(classroomCellPos.x),api.CellToGrid(classroomCellPos.y) };
if (gameState.gameMap[classroomCellPos.x][classroomCellPos.y] == THUAI6::PlaceType::ClassRoom) {
if (api.GetClassroomProgress(classroomCellPos.x, classroomCellPos.y) >= Constants::maxClassroomProgress) {
traversal.erase(traversal.begin() + Action::classNo);
classcount++;
}
//else if (api.GetClassroomProgress(classroomCellPos.x, classroomCellPos.y) == 0 && api.HaveView(classroomCellPos.x, classroomCellPos.y))
else if (api.GetClassroomProgress(classroomCellPos.x, classroomCellPos.y) == 0 && api.HaveView(classroomGridPos.x, classroomGridPos.y))
Action::classNo++;
else
{
api.Print(fmt::format("class pos {} {}", classroomCellPos.x, classroomCellPos.y));
auto result = BFS::bfs(myCell, classroomCellPos, api);
auto nextPos = result.first;
api.Print(fmt::format("next pos {} {}", nextPos.x, nextPos.y));
if (nextPos.x == -1) {
Action::classNo++;
return;
}
if (!gameState.isAtPosition(myCell, classroomCellPos))
{
if (gameState.isType(nextPos, THUAI6::PlaceType::Window))
api.SkipWindow();
Action::Move(nextPos, api);
Action::lastNextPos = nextPos;
Action::lastMove = Action::posToDirection(nextPos, myCell);
}
else
{
//if (api.GetClassroomProgress(classroomCellPos.x, classroomCellPos.y) > 0)
//api.Attack(Action::getAngle(myGrid, classroomGridPos));
//else
Action::classNo++;
}
}
}
else if (gameState.gameMap[classroomCellPos.x][classroomCellPos.y] == THUAI6::PlaceType::Grass) {
api.Print(fmt::format("grass pos {} {}", classroomCellPos.x, classroomCellPos.y));
auto result = BFS::bfs(myCell, classroomCellPos, api);
auto nextPos = result.first;
api.Print(fmt::format("next pos {} {}", nextPos.x, nextPos.y));
if (nextPos.x == -1) {
Action::classNo++;
return;
}
if (!gameState.isAtCell(myGrid, classroomGridPos))
{
if (gameState.isType(nextPos, THUAI6::PlaceType::Window))
api.SkipWindow();
Action::Move(nextPos, api);
Action::lastNextPos = nextPos;
Action::lastMove = Action::posToDirection(nextPos, myCell);
}
else
{
Action::classNo++;
}
}
else {
Action::classNo++;
}

}
//if (needNew > 0) {
//needNew--;
//}
}
else
{
auto self = api.GetSelfInfo();
GridPos myGrid = { self->x,self->y };
CellPos myCell = { api.GridToCell(self->x), api.GridToCell(self->y) };
gameState.getClosestStudent(myGrid, api);
Action::Move(Action::lastNextPos, api);
Action::isAtCellFalseCnt++;
}
}

+ 3757
- 0
players/LQ说什么都队/player1.cpp
File diff suppressed because it is too large
View File


+ 3757
- 0
players/LQ说什么都队/player2.cpp
File diff suppressed because it is too large
View File


+ 3757
- 0
players/LQ说什么都队/player3.cpp
File diff suppressed because it is too large
View File


+ 3757
- 0
players/LQ说什么都队/player4.cpp
File diff suppressed because it is too large
View File


+ 3757
- 0
players/LQ说什么都队/player5.cpp
File diff suppressed because it is too large
View File


+ 1255
- 0
players/Mukava Poikaa/player1.cpp
File diff suppressed because it is too large
View File


+ 1255
- 0
players/Mukava Poikaa/player2.cpp
File diff suppressed because it is too large
View File


+ 1255
- 0
players/Mukava Poikaa/player3.cpp
File diff suppressed because it is too large
View File


+ 1255
- 0
players/Mukava Poikaa/player4.cpp
File diff suppressed because it is too large
View File


+ 1255
- 0
players/Mukava Poikaa/player5.cpp
File diff suppressed because it is too large
View File


+ 2902
- 0
players/N-A/player1.cpp
File diff suppressed because it is too large
View File


+ 2902
- 0
players/N-A/player2.cpp
File diff suppressed because it is too large
View File


+ 2902
- 0
players/N-A/player3.cpp
File diff suppressed because it is too large
View File


+ 2902
- 0
players/N-A/player4.cpp
File diff suppressed because it is too large
View File


+ 2902
- 0
players/N-A/player5.cpp
File diff suppressed because it is too large
View File


+ 2477
- 0
players/PKT48TeamTS/player1.cpp
File diff suppressed because it is too large
View File


+ 2477
- 0
players/PKT48TeamTS/player2.cpp
File diff suppressed because it is too large
View File


+ 2477
- 0
players/PKT48TeamTS/player3.cpp
File diff suppressed because it is too large
View File


+ 2477
- 0
players/PKT48TeamTS/player4.cpp
File diff suppressed because it is too large
View File


+ 2477
- 0
players/PKT48TeamTS/player5.cpp
File diff suppressed because it is too large
View File


+ 1014
- 0
players/closeAI/player1.cpp
File diff suppressed because it is too large
View File


+ 1014
- 0
players/closeAI/player2.cpp
File diff suppressed because it is too large
View File


+ 1014
- 0
players/closeAI/player3.cpp
File diff suppressed because it is too large
View File


+ 1014
- 0
players/closeAI/player4.cpp
File diff suppressed because it is too large
View File


+ 382
- 0
players/closeAI/player5.cpp View File

@@ -0,0 +1,382 @@
#include <vector>
#include <thread>
#include <array>
#include<math.h>
#include "AI.h"
#include "constants.h"
int flag1 = 0, flag2 = 0, flag3 = 0;
long long c = 0;
int ii = -1, jj = 0, iii = -1;
int count = 0;
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Athlete,
THUAI6::StudentType::Athlete,
THUAI6::StudentType::Athlete,
THUAI6::StudentType::Athlete };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::ANoisyPerson;
// 可以在AI.cpp内部声明变量与函数


long long UpLeft(int dx, int dy, int x, int y, ITrickerAPI& api) //会输出一串形如101000111的数字(数字应有dx+dy-1位,若不足,则在高位自动补足0)//
{ //从右往左每个数字代表一步,0代表向上一步,1代表向左一步//
int a = 0, flag = 0;
if (dx == 0)
{
for (int i = 1; i < dy; i++)
{
if (api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - i) == THUAI6::PlaceType::Wall|| api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - i) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 1;
}
if (flag == 1) return 2;
else return a;
}
flag = 0;
if (dy == 0)
{
for (int i = 0; i < dx; i++)
{
if (api.GetPlaceType(api.GridToCell(x) - i, api.GridToCell(y)) == THUAI6::PlaceType::Wall|| api.GetPlaceType(api.GridToCell(x) - i, api.GridToCell(y)) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 0;
}
if (flag == 1) return 2;
else return a;
}
if (UpLeft(dx, dy - 1, x, y - 1000, api) != 2 && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - 1) != THUAI6::PlaceType::Wall&& api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - 1) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx, dy-1, x , y-1000, api) + 1;
}
if (UpLeft(dx - 1, dy, x - 1000, y, api) != 2 && api.GetPlaceType(api.GridToCell(x)-1, api.GridToCell(y)) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x)-1, api.GridToCell(y)) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx - 1, dy, x - 1000, y, api);
}
else return 2;
}

long long UpRight(int dx, int dy, int x, int y, ITrickerAPI& api) //会输出一串形如101000111的数字(数字应有dx+dy-1位,若不足,则在高位自动补足0)//
{ //从右往左每个数字代表一步,0代表向上一步,1代表向右一步//
int a = 0, flag = 0;
if (dx == 0)
{
for (int i = 1; i < dy; i++)
{
if (api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + i) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + i) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 1;
}
if (flag == 1) return 2;
else return a;
}
flag = 0;
if (dy == 0)
{
for (int i = 0; i < dx; i++)
{
if (api.GetPlaceType(api.GridToCell(x) - i, api.GridToCell(y)) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x) - i, api.GridToCell(y)) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 0;
}
if (flag == 1) return 2;
else return a;
}
if (UpLeft(dx, dy - 1, x, y + 1000, api) != 2 && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + 1) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + 1) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx, dy - 1, x, y + 1000, api) + 1;
}
if (UpLeft(dx - 1, dy, x - 1000, y, api) != 2 && api.GetPlaceType(api.GridToCell(x) - 1, api.GridToCell(y)) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x) - 1, api.GridToCell(y)) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx - 1, dy, x - 1000, y, api);
}
else return 2;
}

long long DownLeft(int dx, int dy, int x, int y, ITrickerAPI& api) //会输出一串形如101000111的数字(数字应有dx+dy-1位,若不足,则在高位自动补足0)//
{ //从右往左每个数字代表一步,0代表向下一步,1代表向左一步//
int a = 0, flag = 0;
if (dx == 0)
{
for (int i = 1; i < dy; i++)
{
if (api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - i) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - i) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 1;
}
if (flag == 1) return 2;
else return a;
}
flag = 0;
if (dy == 0)
{
for (int i = 0; i < dx; i++)
{
if (api.GetPlaceType(api.GridToCell(x) + i, api.GridToCell(y)) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x) + i, api.GridToCell(y)) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 0;
}
if (flag == 1) return 2;
else return a;
}
if (UpLeft(dx, dy - 1, x, y - 1000, api) != 2 && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - 1) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) - 1) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx, dy - 1, x, y - 1000, api) + 1;
}
if (UpLeft(dx - 1, dy, x + 1000, y, api) != 2 && api.GetPlaceType(api.GridToCell(x) + 1, api.GridToCell(y)) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x) + 1, api.GridToCell(y)) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx - 1, dy, x + 1000, y, api);
}
else return 2;
}

long long DownRight(int dx, int dy, int x, int y, ITrickerAPI& api) //会输出一串形如101000111的数字(数字应有dx+dy-1位,若不足,则在高位自动补足0)//
{ //从右往左每个数字代表一步,0代表向下一步,1代表向右一步//
int a = 0, flag = 0;
if (dx == 0)
{
for (int i = 1; i < dy; i++)
{
if (api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + i) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + i) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 1;
}
if (flag == 1) return 2;
else return a;
}
flag = 0;
if (dy == 0)
{
for (int i = 0; i < dx; i++)
{
if (api.GetPlaceType(api.GridToCell(x) + i, api.GridToCell(y)) == THUAI6::PlaceType::Wall || api.GetPlaceType(api.GridToCell(x) + i, api.GridToCell(y)) == THUAI6::PlaceType::Window)
{
flag = 1; break;
}
else a = a * 10 + 0;
}
if (flag == 1) return 2;
else return a;
}
if (UpLeft(dx, dy - 1, x, y + 1000, api) != 2 && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + 1) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x), api.GridToCell(y) + 1) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx, dy - 1, x, y + 1000, api) + 1;
}
if (UpLeft(dx - 1, dy, x + 1000, y, api) != 2 && api.GetPlaceType(api.GridToCell(x) + 1, api.GridToCell(y)) != THUAI6::PlaceType::Wall && api.GetPlaceType(api.GridToCell(x) + 1, api.GridToCell(y)) != THUAI6::PlaceType::Window)
{
return 10 * UpLeft(dx - 1, dy, x + 1000, y, api);
}
else return 2;
}
void DownRight(long long c, ITrickerAPI& api)
{
if (c % 10 == 0)
{
api.MoveDown(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (c % 10 == 1)
{
api.MoveRight(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
return;
}
void DownLeft(long long c, ITrickerAPI& api)
{
if (c % 10 == 0)
{
api.MoveDown(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (c % 10 == 1)
{
api.MoveLeft(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
return;
}
void UpRight(long long c, ITrickerAPI& api)
{
if (c % 10 == 0)
{
api.MoveUp(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (c % 10 == 1)
{
api.MoveRight(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
return;
}
void UpLeft(long long c, ITrickerAPI& api)
{
if (c % 10 == 0)
{
api.MoveUp(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
if (c % 10 == 1)
{
api.MoveLeft(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(300));
}
return;
}


void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 2)
{
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
double dx, dy, aa=0;
int ddx, ddy;
auto self = api.GetSelfInfo();
auto st = api.GetStudents();
if (!st.empty())
{
api.UseSkill(0);
std::this_thread::sleep_for(std::chrono::milliseconds(810));
if (flag1 == 0)
{
dx = st[0]->x - self->x;
dy = st[0]->y - self->y;
ddx = abs(api.GridToCell(dx));
ddy = abs(api.GridToCell(dy));
if (dx >= 0&&dy >= 0) { c = DownRight(ddx, ddy, self->x, self->y, api); jj = 1; }
if (dx >= 0&&dy < 0) { c = DownLeft(ddx, ddy, self->x, self->y, api); jj = 2; }
if (dx < 0&&dy >= 0) { c = UpRight(ddx, ddy, self->x, self->y, api); jj = 3; }
if (dx < 0&&dy < 0) { c = UpLeft(ddx, ddy, self->x, self->y, api); jj = 4; }
ii = ddx + ddy - 1;
flag1 = 1;
}
if (ii > 0 && c != 2 && jj == 1)
{
DownRight(c, api);
c = c / 10;
ii--;
}
if (ii > 0 && c != 2 && jj == 2)
{
DownLeft(c, api);
c = c / 10;
ii--;
}
if (ii > 0 && c != 2 && jj == 3)
{

UpRight(c, api);
c = c / 10;
ii--;
}
if (ii > 0 && c != 2 && jj == 4)
{
UpLeft(c, api);
c = c / 10;
ii--;
}
if (ii == 0)
{
auto self = api.GetSelfInfo();
auto st = api.GetStudents();
if (!st.empty())
{
if (api.GridToCell(st[0]->x) == api.GridToCell(self->x) && st[0]->y > self->y) aa = 1.5707963;
if (api.GridToCell(st[0]->x) == api.GridToCell(self->x) && st[0]->y < self->y) aa = 4.7123889;
if (api.GridToCell(st[0]->y) == api.GridToCell(self->y) && st[0]->x > self->x) aa = 0;
if (api.GridToCell(st[0]->y) == api.GridToCell(self->y) && st[0]->x < self->x) aa = 3.1415926;
api.Attack(aa);
}
}
}
if(st.empty())
{
if (count==0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
api.MoveUp(2 * 259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(540));
}
if (count < 13)
{
api.MoveLeft(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(270));
count++;
}
if (count == 13)
{
api.MoveDown(2 * 259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(530));
count++;
}
}
if (count == 14)
{
auto self = api.GetSelfInfo();
c = DownRight(9, 5, self->x, self->y, api);
iii = 13; count++; ii = -1;
}
if (count == 15)
{
if (iii > 0 && c != 2)
{
DownRight(c, api);
c = c / 10;
iii--;
}
if (iii == 1)
{
api.MoveDown(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(280));
count++; flag1 = 0;
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
if (st.empty() && api.GridToCell(self->x) == 23 && api.GridToCell(self->y) == 12 && count == 16)
{
count++;
std::this_thread::sleep_for(std::chrono::milliseconds(5000));
api.MoveRight(259.6053998 * 2);
std::this_thread::sleep_for(std::chrono::milliseconds(550));
api.MoveDown(259.6053998 * 13);
std::this_thread::sleep_for(std::chrono::milliseconds(3500));
ii = -1;
}
if (count < 26 && count >= 17)
{
api.MoveRight(259.6053998);
std::this_thread::sleep_for(std::chrono::milliseconds(280));
count++;
}
if (count == 26)
{
ii = 0;
}
}

+ 735
- 0
players/pqfobj/player1.py View File

@@ -0,0 +1,735 @@
import PyAPI.structures as THUAI6
from PyAPI.Interface import *
from typing import Union, Final, cast, List
from PyAPI.constants import *
import queue

import time

# add
import numpy as np
import math
import copy
from collections import deque


class Setting:
# 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
@staticmethod
def asynchronous() -> bool:
return True

# 选手需要依次将player0到player4的职业都定义
@staticmethod
def studentType() -> List[THUAI6.StudentType]:
return [THUAI6.StudentType.Athlete, THUAI6.StudentType.Teacher, THUAI6.StudentType.StraightAStudent, THUAI6.StudentType.Sunshine]

@staticmethod
def trickerType() -> THUAI6.TrickerType:
return THUAI6.TrickerType.ANoisyPerson


# 辅助函数
numOfGridPerCell: Final[int] = 1000


class AssistFunction:

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2

@staticmethod
def GridToCell(grid: int) -> int:
return grid // numOfGridPerCell

# additional function_tricker

pi = 3.1415926535

class cel:
x:int
y:int
gridx:int
gridy:int
def __init__(self,x1:int, y1:int,type = 0):#type==0采用0-50赋值
if type ==0:
self.x = x1
self.y = y1
self.gridx = AssistFunction.CellToGrid(x1)
self.gridy = AssistFunction.CellToGrid(y1)
else:
self.x = AssistFunction.GridToCell(x1)
self.y = AssistFunction.GridToCell(y1)
self.gridx = AssistFunction.CellToGrid(self.x)
self.gridy = AssistFunction.CellToGrid(self.y)

class precise_cel:
x:int
y:int
def __init__(self,x1:int, y1:int):
self.x = x1
self.y = y1

def gridtocell(x:int,y:int) -> cel:#返回坐标对应的cell
return cel(AssistFunction.GridToCell(x),AssistFunction.GridToCell(y))

def distocell(x:int,y:int,dis:float,angle:float) -> List[cel]:#返回以一个点为中心长度为dis的cell
allcell=[]
for i in range(0,2*pi,angle):
x1 = x+dis*math.cos(i)
y1 = y+dis*math.sin(i)
if x1>0 and x1<50000 and y1 >0 and y1<50000:
the = gridtocell(x1,y1)
if len(allcell) == 0:
allcell.append(the)
elif allcell[-1].x != the.x or allcell[-1].y != the.y:
allcell.append(the)
return allcell
# Land = 1
# Wall = 2
# Grass = 3
# ClassRoom = 4
# Gate = 5
# HiddenGate = 6
# Window = 7
# Door3 = 8
# Door5 = 9
# Door6 = 10
# Chest = 11

def findpa(now:cel,dest:cel,map:List[List[THUAI6.PlaceType]]) -> cel:
return cel(1,1)

def dist(x1:int,y1:int,x2:int,y2:int) ->float:
return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def toangle(nowx:int,nowy:int,tox:int,toy:int) ->float:
if toy >= nowy:
return math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))
else:
return -math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))

def toangle_cel(now:cel,dest:cel) ->float:
if dest.y >= now.y:
return math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))
else:
return -math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))

def findway_DFS(grid, start:cel, end:cel) -> List[cel]:
row, col = 50,50
visited = set()
path =[]
class anan:
angle:float
to:int#0,1,2,3,下右上左
def __init__(self,angel:float,to:int) -> None:
self.angle = angel
self.to = to
pass

def azhe(jjj:anan)->float:
return jjj.angle

def help(now:cel,path:List[cel])->List[cel]:
if now == end:
return path
if now in visited:
oo = []
return oo
visited.add(now)
angle = toangle_cel(now,end)
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
chae = [anan(abs(angle),0),anan(abs(angle-pi/2),1),anan(abs(angle-pi),2),anan(abs(angle-pi*1.5),3)]
chae.sort(key = azhe)
for i in chae:
dx,dy = directions[i.to]
new_x, new_y = now.x + dx, now.y + dy
new =cel(new_x, new_y)
if (grid[new_x][new_y]).value in [1,3,7,8,9,10]:
path.append(new)
visited.remove(now)
return help(path[-1], path)
return help(start,path = path)


# additional function_tricker

# additional function_student

pi=3.1415926535
class Cel:
x:int
y:int
def __init__(self,x1:int,y1:int):
self.x=x1
self.y=y1

#计算距离
def distance(target:Cel,api:IStudentAPI,ai)->float:
selfinfo=api.GetSelfInfo()
return math.sqrt((target.x-selfinfo.x)**2+(target.y-selfinfo.y)**2)

movetime=50
#为避免没到格子中心卡墙角,用cel规划路径,用grid精确地走
def Goto(target:Cel,api:IStudentAPI,ai)->None:
selfinfo=api.GetSelfInfo()
#当前格子坐标
#if self.nowpath==None:
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)
nowpath=ai.BFSpath(selfinfo,cur,target,api)#规划路径
#print('self.nowpath')
#for k in nowpath:
# print(k.x,k.y)
while len(nowpath)!=0:#能否这样判断不空
first=nowpath[0]
x1=1000*first.x+500
y1=1000*first.y+500
#print('curgrid',selfx,selfy)
#print('first ',x1,y1)
if cur.x==first.x and cur.y==first.y:
a=nowpath.pop(0)
else:
#print('not the same')
#print('first',x1,y1)
#print('cur',cur.x,cur.y)
if x1==selfx and y1<selfy:api.MoveLeft(movetime)
elif x1==selfx and y1>selfy:api.MoveRight(movetime)
elif x1<selfx and y1==selfy:api.MoveUp(movetime)
elif x1>selfx and y1==selfy:api.MoveDown(movetime)
elif x1<selfx and y1<selfy:api.Move(movetime,-pi*3/4)
elif x1<selfx and y1>selfy:api.Move(movetime,pi*3/4)
elif x1>selfx and y1<selfy:api.Move(movetime,-pi/4)
elif x1>selfx and y1>selfy:api.Move(movetime,pi/4)
#api.PrintSelfInfo()
selfinfo1=api.GetSelfInfo()
selfx1=selfinfo1.x
selfy1=selfinfo1.y
#print('aftermove',selfx1,selfy1)
#cur1=gridtocell(selfinfo1.x,selfinfo1.y)
#print('info',cur1.x,cur1.y)
if(selfx==selfx1 and selfy==selfy1):
#print('not moved')
api.MoveRight(movetime)
# api.MoveRight(movetime)
selfinfo=api.GetSelfInfo()
#print('State ',selfinfo.playerState.name)
#api.PrintSelfInfo()
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)

# additional function_student

class AI(IAI):
map = None


# tricker
allgates_tr=[]
allwindows_tr = []
alldoor3_tr = []
alldoor5_tr = []
alldoor6_tr = []
allclassrooms_tr = []
allboxes_tr = []
allhiddengates_tr = []

studentposition_previous_frame=None#precise_cel
studentposition_this_frame=None#precise_cel
my_previous_frame=None#precise_cel
my_this_frame=None#precise_cel

now_path=None#List[cel]
move_along_path=None#bool


def closest_chest(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allboxes_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxChestProgress:
dis = k
the = i
return the
def closest_classroom(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allclassrooms_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxClassroomProgress:
dis = k
the = i
return the

def wall_exist_precise(self,now:precise_cel,dest:precise_cel)->bool:
k = (dest.y-now.y)/(dest.x-now.x)
# y = k(x-now.x)+now.y
long = dest.x-now.x
for i in range(0,long,801):
y1= k*i+now.y
ok = cel(now.x+i,y1)
if self.map[ok.x][ok.y].value in [2,4,5,6,11]:
return True
return False

def near_chest(self,now:cel,api)->bool:
eight = [cel(now.x,now.y+1),cel(now.x,now.y-1),cel(now.x+1,now.y),cel(now.x-1,now.y),cel(now.x+1,now.y+1),cel(now.x-1,now.y-1),cel(now.x+1,now.y-1),cel(now.x-1,now.y+1)]
for i in eight:
jindu = api.GetChestProgress(i.x,i.y)
if self.map[i.x][i.y].name == 'Chest' and jindu < Constants.maxChestProgress:
return True
return False
# student

allgates=[]
allwindows = []
alldoors3 = []
alldoors5 = []
alldoors6 = []
allclassrooms = []
allboxes = []
allhiddengates = []

last_cel:Cel
cur_cel:Cel
#movetime=10#移动时间是多少?
#nowpath:deque[Cel]#存BFS得出的路径直到路径走�??
#move_along_path=0#直到走完路径,避免每帧调用一�??

def Todestin(self,api:IStudentAPI):
return

def Iscanreach(self,point:Cel,target:Cel)->bool:#判断两个点能否直接到
if(target.x<0 or target.x>50
or target.y<0 or target.y>50
or self.map[target.x][target.y].name=='Wall'
or (target.x==point.x and target.y==point.y)):#或超出地图、墙壁、与初始点重�??
return False
else:#上下左右�??
if(abs(point.x-target.x)+abs(point.y-target.y)==1):
return True
else:#斜对角线是门的话先不�??
name1=self.map[target.x][target.y].name
if(name1=='Door3' or name1=='Door5' or name1=='Door6'):
return False
else:
name2=self.map[target.x][point.y].name
name3=self.map[point.x][target.y].name
if name2=='Wall' or name3=='Wall':
return False
else:
return True
#对角线的两侧有墙壁的话也不行�??45度的时候走不过�??
#隐藏门和大校门?
def getSurroundCell(self,info:THUAI6.Student,point:Cel)->deque[Cel]:#找到该点周围8个点中能到的
surroundCell=[]#存能到的
curprop=info.prop
global next
for xi in range(point.x-1,point.x+2):
for yj in range(point.y-1,point.y+2):
other=Cel(xi,yj)
if(self.Iscanreach(point,other)):
sname=self.map[other.x][other.y].name
if(sname=='Door3'):#是门的话,判断有无对应钥匙?
if 1 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door5'):
if 2 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door6'):
if 3 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Window'):#是窗的话爬出�??
next=Cel(2*other.x-point.x,2*other.y-point.y)
else:
next=other
surroundCell.append(next)
return surroundCell
#判断坐标是否在list里,searched用到,也是数字相同但不同对象
def InList(self,point:Cel,llist:List)->bool:
for k in llist:
if point.x==k.x and point.y==k.y:
return True
return False
#坐标是否在字典的key里,每一次初始化类的对象,尽管数字相同但还是不同对象,可以重�??=?还可以?(后面简化一�??
def InDic(self,point:Cel,DDix:dict)->bool:
for k in DDix.keys():
if point.x==k.x and point.y==k.y:
return True
return False

#广度搜索找路径,如果
#路径不存在的情况�??
def BFSpath(self,info:THUAI6.Student,point:Cel,target:Cel,api:IStudentAPI)->List[Cel]:
#self_info=api.GetSelfInfo(self)
searched=[]#已经搜过的点
q=deque()
q.append(point)#初始点加�??
#定义搜索过的点的父节�??
parents=dict()
path=[target]

while q:
cur_=q.popleft()
#如果点没有被搜过
if not self.InList(cur_,searched):
#api.Print('not serached'+'cur_ '+str(cur_.x)+' '+str(cur_.y))
if(cur_.x !=target.x or cur_.y!=target.y):
#print('!=here')
sur=self.getSurroundCell(info,cur_)
for k in sur:
if not self.InList(k,searched):
q.append(k)
if not self.InDic(k,parents):
parents[k]=cur_
searched.append(cur_)
else:
#print('cur_=target')
key=Cel(target.x,target.y)
while key.x!=point.x or key.y!=point.y:
for k in parents:
if k.x==key.x and k.y==key.y:
father=parents[k]
path.append(father)
key=father
#往回找到路径后,将列表反转
path.reverse()
break
return path

#�?7间教室学�?
def Study(self,api:IStudentAPI)->None:
leng=len(self.allclassrooms)
ifdone=np.zeros((leng,1),dtype=bool)
class_count=0#已经学的教室的间�?
#找到距离self最近的教室并前往,途中捡道�?
while class_count<7:
my_filter=filter(lambda x:ifdone[self.allclassrooms.index(x)]==0,self.allclassrooms)#已经学过的教室就不要去了
result=list(my_filter)
dis_to_class=[]
for k in result:
dis=distance(k,api,self)
dis_to_class.append(dis)
num=dis_to_class.index(min(dis_to_class))#result中距离最近的教室的编�?
which_class=result[num]
x1=which_class.x
y1=which_class.y
#print('nearest ',x1,y1)
#在classroom列表中找回这个点的位置,并在ifdone中修改标�?
index_of_class=next((i for i,xx in enumerate(self.allclassrooms) if xx.x==x1 and xx.y==y1),None)
ifdone[index_of_class]=1

Goto(which_class,api,self)
api.StartLearning()#开始学�?

class_count=class_count+1



# function

def __init__(self, pID: int):
self.__playerID = pID

def StudentPlay(self, api: IStudentAPI) -> None:
return
# 鍏叡鎿嶄綔
if self.map==None:
self.map=api.GetFullMap()
xi=0
yj=0
for i in self.map:
yj=0
for j in i:
if j.name=='ClassRoom':
self.allclassrooms.append(Cel(xi,yj))
if j.name=='Gate':
self.allgates.append(Cel(xi,yj))
if j.name=='HiddenGate':
self.allhiddengates.append(Cel(xi,yj))
if j.name=='Window':#��һ���������ĺ�������
self.allwindows.append(Cel(xi,yj))
if j.name=='Door3':
self.alldoors3.append(Cel(xi,yj))
if j.name=='Door5':
self.alldoors5.append(Cel(xi,yj))
if j.name=='Door6':
self.alldoors6.append(Cel(xi,yj))
if j.name=='Chest':
self.allboxes.append(Cel(xi,yj))
yj=yj+1
xi=xi+1
print(self.map)


if self.__playerID == 0:
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
#api.StartLearning()
#api.PrintSelfInfo()
#print('end')
#self.Study(api)
elif self.__playerID == 1:
# 鐜╁�??1鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 2:
# 鐜╁�??2鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 3:
# 鐜╁�??3鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
# 鍙互鍐欐垚if self.__playerID<2涔嬬被鐨勫啓娉�
# 鍏叡鎿嶄綔
return

def TrickerPlay(self, api: ITrickerAPI) -> None:
#api.EndAllAction()

if self.map is None:
self.map = api.GetFullMap()
yj = 0
xi = 0
for i in self.map:
yj = 0
for j in i:
if j.name == 'ClassRoom':
self.allclassrooms_tr.append(cel(xi,yj))
elif j.name == 'Gate':
self.allgates_tr.append(cel(xi,yj))
elif j.name == 'HiddenGate':
self.allhiddengates_tr.append(cel(xi,yj))
elif j.name == 'Window':
self.allwindows_tr.append(cel(xi,yj))
elif j.name == 'Door3':
self.alldoor3_tr.append(cel(xi,yj))
elif j.name == 'Door5':
self.alldoor5_tr.append(cel(xi,yj))
elif j.name == 'Door6':
self.alldoor6_tr.append(cel(xi,yj))
elif j.name == 'Chest':
self.allboxes_tr.append(cel(xi,yj))
yj = yj + 1
xi = xi + 1

if self.my_previous_frame is None:
self.my_previous_frame = precise_cel(0,0)
selfInfo = api.GetSelfInfo()
self.my_this_frame = precise_cel(selfInfo.x,selfInfo.y)


if selfInfo.trickerType.name == 'ANoisyPerson':
student_see = api.GetStudents()
now = cel(selfInfo.x,selfInfo.y,1)
dest= cel(0,0)
this_dest:cel
if self.near_chest(now,api):
api.StartOpenChest()
if selfInfo.playerState.name == 'Idle':
if len(student_see) == 0:
self.move_along_path = True
dest = cel(0,0)
if selfInfo.trickDesire == 0:
#找教室
dest = self.closest_classroom(now.x,now.y)
else:
dis = float(ANoisyPerson.alertnessRadius)/selfInfo.trickDesire
a=1
else:
self.move_along_path = False
closestudent:THUAI6.Student
closestudent = None
cloest = 1000000000000
attacklong = Constants.basicAttackShortRange
for i in student_see:
dis = dist(i.x,i.y,selfInfo.x,selfInfo.y)
if dis < cloest :
cloest = dis
if i.playerState.name != 'Addicted':
closestudent = i
if closestudent is not None:
dest = cel(closestudent.x,closestudent.y,1)
else:
dest = self.closest_chest(now.x,now.y,api)
#self.move_along_path = True
if closestudent is not None:
if closestudent.studentType.name == 'Athlete':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Teacher':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'StraightAStudent':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Sunshine':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
# if self.now_path is None and self.move_along_path == True:
# self.now_path = findway_DFS(self.map,now,dest)
# if self.move_along_path == True:
# dest = self.now_path[1]
this_dest = dest
angle = toangle(selfInfo.x,selfInfo.y,this_dest.gridx,this_dest.gridy)
if self.my_previous_frame.x == self.my_this_frame.x and self.my_previous_frame.y == self.my_this_frame.y:
if selfInfo.playerState.name == 'Idle':
api.MoveUp(10)
return
self.my_previous_frame = precise_cel(selfInfo.x,selfInfo.y)
if selfInfo.playerState.name == 'Idle':
api.Move(60,angle)
# hide in grass
# attack
# trick around
# find chest
# find classroom
elif selfInfo.trickerType.name == 'Idol':
a=1
elif selfInfo.trickerType.name == 'Assassin':
a=1

return

# playerID=4, GUID=678, x=21500, y=25500
# speed=3960, view range=15600, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, 0.0, -1.0]
# state=Idle, bullet=CommonAttackOfTricker, prop=NullPropType, NullPropType, NullPropType,
# type=Assassin, trick desire=2.4405367634838275, class volume=0.0
# buff=

# playerID=2, GUID=694, x=12500, y=26500
# speed=2880, view range=9000, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, -1.0, -1.0]
# state=Idle, bullet=NullBulletType, prop=NullPropType, NullPropType, NullPropType,
# type=StraightAStudent, determination=3300000, addiction=0, danger alert=0.0
# learning speed=135, encourage speed=100, encourage progress=0, rouse progress=0
# buff=

+ 735
- 0
players/pqfobj/player2.py View File

@@ -0,0 +1,735 @@
import PyAPI.structures as THUAI6
from PyAPI.Interface import *
from typing import Union, Final, cast, List
from PyAPI.constants import *
import queue

import time

# add
import numpy as np
import math
import copy
from collections import deque


class Setting:
# 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
@staticmethod
def asynchronous() -> bool:
return True

# 选手需要依次将player0到player4的职业都定义
@staticmethod
def studentType() -> List[THUAI6.StudentType]:
return [THUAI6.StudentType.Athlete, THUAI6.StudentType.Teacher, THUAI6.StudentType.StraightAStudent, THUAI6.StudentType.Sunshine]

@staticmethod
def trickerType() -> THUAI6.TrickerType:
return THUAI6.TrickerType.ANoisyPerson


# 辅助函数
numOfGridPerCell: Final[int] = 1000


class AssistFunction:

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2

@staticmethod
def GridToCell(grid: int) -> int:
return grid // numOfGridPerCell

# additional function_tricker

pi = 3.1415926535

class cel:
x:int
y:int
gridx:int
gridy:int
def __init__(self,x1:int, y1:int,type = 0):#type==0采用0-50赋值
if type ==0:
self.x = x1
self.y = y1
self.gridx = AssistFunction.CellToGrid(x1)
self.gridy = AssistFunction.CellToGrid(y1)
else:
self.x = AssistFunction.GridToCell(x1)
self.y = AssistFunction.GridToCell(y1)
self.gridx = AssistFunction.CellToGrid(self.x)
self.gridy = AssistFunction.CellToGrid(self.y)

class precise_cel:
x:int
y:int
def __init__(self,x1:int, y1:int):
self.x = x1
self.y = y1

def gridtocell(x:int,y:int) -> cel:#返回坐标对应的cell
return cel(AssistFunction.GridToCell(x),AssistFunction.GridToCell(y))

def distocell(x:int,y:int,dis:float,angle:float) -> List[cel]:#返回以一个点为中心长度为dis的cell
allcell=[]
for i in range(0,2*pi,angle):
x1 = x+dis*math.cos(i)
y1 = y+dis*math.sin(i)
if x1>0 and x1<50000 and y1 >0 and y1<50000:
the = gridtocell(x1,y1)
if len(allcell) == 0:
allcell.append(the)
elif allcell[-1].x != the.x or allcell[-1].y != the.y:
allcell.append(the)
return allcell
# Land = 1
# Wall = 2
# Grass = 3
# ClassRoom = 4
# Gate = 5
# HiddenGate = 6
# Window = 7
# Door3 = 8
# Door5 = 9
# Door6 = 10
# Chest = 11

def findpa(now:cel,dest:cel,map:List[List[THUAI6.PlaceType]]) -> cel:
return cel(1,1)

def dist(x1:int,y1:int,x2:int,y2:int) ->float:
return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def toangle(nowx:int,nowy:int,tox:int,toy:int) ->float:
if toy >= nowy:
return math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))
else:
return -math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))

def toangle_cel(now:cel,dest:cel) ->float:
if dest.y >= now.y:
return math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))
else:
return -math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))

def findway_DFS(grid, start:cel, end:cel) -> List[cel]:
row, col = 50,50
visited = set()
path =[]
class anan:
angle:float
to:int#0,1,2,3,下右上左
def __init__(self,angel:float,to:int) -> None:
self.angle = angel
self.to = to
pass

def azhe(jjj:anan)->float:
return jjj.angle

def help(now:cel,path:List[cel])->List[cel]:
if now == end:
return path
if now in visited:
oo = []
return oo
visited.add(now)
angle = toangle_cel(now,end)
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
chae = [anan(abs(angle),0),anan(abs(angle-pi/2),1),anan(abs(angle-pi),2),anan(abs(angle-pi*1.5),3)]
chae.sort(key = azhe)
for i in chae:
dx,dy = directions[i.to]
new_x, new_y = now.x + dx, now.y + dy
new =cel(new_x, new_y)
if (grid[new_x][new_y]).value in [1,3,7,8,9,10]:
path.append(new)
visited.remove(now)
return help(path[-1], path)
return help(start,path = path)


# additional function_tricker

# additional function_student

pi=3.1415926535
class Cel:
x:int
y:int
def __init__(self,x1:int,y1:int):
self.x=x1
self.y=y1

#计算距离
def distance(target:Cel,api:IStudentAPI,ai)->float:
selfinfo=api.GetSelfInfo()
return math.sqrt((target.x-selfinfo.x)**2+(target.y-selfinfo.y)**2)

movetime=50
#为避免没到格子中心卡墙角,用cel规划路径,用grid精确地走
def Goto(target:Cel,api:IStudentAPI,ai)->None:
selfinfo=api.GetSelfInfo()
#当前格子坐标
#if self.nowpath==None:
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)
nowpath=ai.BFSpath(selfinfo,cur,target,api)#规划路径
#print('self.nowpath')
#for k in nowpath:
# print(k.x,k.y)
while len(nowpath)!=0:#能否这样判断不空
first=nowpath[0]
x1=1000*first.x+500
y1=1000*first.y+500
#print('curgrid',selfx,selfy)
#print('first ',x1,y1)
if cur.x==first.x and cur.y==first.y:
a=nowpath.pop(0)
else:
#print('not the same')
#print('first',x1,y1)
#print('cur',cur.x,cur.y)
if x1==selfx and y1<selfy:api.MoveLeft(movetime)
elif x1==selfx and y1>selfy:api.MoveRight(movetime)
elif x1<selfx and y1==selfy:api.MoveUp(movetime)
elif x1>selfx and y1==selfy:api.MoveDown(movetime)
elif x1<selfx and y1<selfy:api.Move(movetime,-pi*3/4)
elif x1<selfx and y1>selfy:api.Move(movetime,pi*3/4)
elif x1>selfx and y1<selfy:api.Move(movetime,-pi/4)
elif x1>selfx and y1>selfy:api.Move(movetime,pi/4)
#api.PrintSelfInfo()
selfinfo1=api.GetSelfInfo()
selfx1=selfinfo1.x
selfy1=selfinfo1.y
#print('aftermove',selfx1,selfy1)
#cur1=gridtocell(selfinfo1.x,selfinfo1.y)
#print('info',cur1.x,cur1.y)
if(selfx==selfx1 and selfy==selfy1):
#print('not moved')
api.MoveRight(movetime)
# api.MoveRight(movetime)
selfinfo=api.GetSelfInfo()
#print('State ',selfinfo.playerState.name)
#api.PrintSelfInfo()
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)

# additional function_student

class AI(IAI):
map = None


# tricker
allgates_tr=[]
allwindows_tr = []
alldoor3_tr = []
alldoor5_tr = []
alldoor6_tr = []
allclassrooms_tr = []
allboxes_tr = []
allhiddengates_tr = []

studentposition_previous_frame=None#precise_cel
studentposition_this_frame=None#precise_cel
my_previous_frame=None#precise_cel
my_this_frame=None#precise_cel

now_path=None#List[cel]
move_along_path=None#bool


def closest_chest(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allboxes_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxChestProgress:
dis = k
the = i
return the
def closest_classroom(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allclassrooms_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxClassroomProgress:
dis = k
the = i
return the

def wall_exist_precise(self,now:precise_cel,dest:precise_cel)->bool:
k = (dest.y-now.y)/(dest.x-now.x)
# y = k(x-now.x)+now.y
long = dest.x-now.x
for i in range(0,long,801):
y1= k*i+now.y
ok = cel(now.x+i,y1)
if self.map[ok.x][ok.y].value in [2,4,5,6,11]:
return True
return False

def near_chest(self,now:cel,api)->bool:
eight = [cel(now.x,now.y+1),cel(now.x,now.y-1),cel(now.x+1,now.y),cel(now.x-1,now.y),cel(now.x+1,now.y+1),cel(now.x-1,now.y-1),cel(now.x+1,now.y-1),cel(now.x-1,now.y+1)]
for i in eight:
jindu = api.GetChestProgress(i.x,i.y)
if self.map[i.x][i.y].name == 'Chest' and jindu < Constants.maxChestProgress:
return True
return False
# student

allgates=[]
allwindows = []
alldoors3 = []
alldoors5 = []
alldoors6 = []
allclassrooms = []
allboxes = []
allhiddengates = []

last_cel:Cel
cur_cel:Cel
#movetime=10#移动时间是多少?
#nowpath:deque[Cel]#存BFS得出的路径直到路径走�??
#move_along_path=0#直到走完路径,避免每帧调用一�??

def Todestin(self,api:IStudentAPI):
return

def Iscanreach(self,point:Cel,target:Cel)->bool:#判断两个点能否直接到
if(target.x<0 or target.x>50
or target.y<0 or target.y>50
or self.map[target.x][target.y].name=='Wall'
or (target.x==point.x and target.y==point.y)):#或超出地图、墙壁、与初始点重�??
return False
else:#上下左右�??
if(abs(point.x-target.x)+abs(point.y-target.y)==1):
return True
else:#斜对角线是门的话先不�??
name1=self.map[target.x][target.y].name
if(name1=='Door3' or name1=='Door5' or name1=='Door6'):
return False
else:
name2=self.map[target.x][point.y].name
name3=self.map[point.x][target.y].name
if name2=='Wall' or name3=='Wall':
return False
else:
return True
#对角线的两侧有墙壁的话也不行�??45度的时候走不过�??
#隐藏门和大校门?
def getSurroundCell(self,info:THUAI6.Student,point:Cel)->deque[Cel]:#找到该点周围8个点中能到的
surroundCell=[]#存能到的
curprop=info.prop
global next
for xi in range(point.x-1,point.x+2):
for yj in range(point.y-1,point.y+2):
other=Cel(xi,yj)
if(self.Iscanreach(point,other)):
sname=self.map[other.x][other.y].name
if(sname=='Door3'):#是门的话,判断有无对应钥匙?
if 1 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door5'):
if 2 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door6'):
if 3 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Window'):#是窗的话爬出�??
next=Cel(2*other.x-point.x,2*other.y-point.y)
else:
next=other
surroundCell.append(next)
return surroundCell
#判断坐标是否在list里,searched用到,也是数字相同但不同对象
def InList(self,point:Cel,llist:List)->bool:
for k in llist:
if point.x==k.x and point.y==k.y:
return True
return False
#坐标是否在字典的key里,每一次初始化类的对象,尽管数字相同但还是不同对象,可以重�??=?还可以?(后面简化一�??
def InDic(self,point:Cel,DDix:dict)->bool:
for k in DDix.keys():
if point.x==k.x and point.y==k.y:
return True
return False

#广度搜索找路径,如果
#路径不存在的情况�??
def BFSpath(self,info:THUAI6.Student,point:Cel,target:Cel,api:IStudentAPI)->List[Cel]:
#self_info=api.GetSelfInfo(self)
searched=[]#已经搜过的点
q=deque()
q.append(point)#初始点加�??
#定义搜索过的点的父节�??
parents=dict()
path=[target]

while q:
cur_=q.popleft()
#如果点没有被搜过
if not self.InList(cur_,searched):
#api.Print('not serached'+'cur_ '+str(cur_.x)+' '+str(cur_.y))
if(cur_.x !=target.x or cur_.y!=target.y):
#print('!=here')
sur=self.getSurroundCell(info,cur_)
for k in sur:
if not self.InList(k,searched):
q.append(k)
if not self.InDic(k,parents):
parents[k]=cur_
searched.append(cur_)
else:
#print('cur_=target')
key=Cel(target.x,target.y)
while key.x!=point.x or key.y!=point.y:
for k in parents:
if k.x==key.x and k.y==key.y:
father=parents[k]
path.append(father)
key=father
#往回找到路径后,将列表反转
path.reverse()
break
return path

#�?7间教室学�?
def Study(self,api:IStudentAPI)->None:
leng=len(self.allclassrooms)
ifdone=np.zeros((leng,1),dtype=bool)
class_count=0#已经学的教室的间�?
#找到距离self最近的教室并前往,途中捡道�?
while class_count<7:
my_filter=filter(lambda x:ifdone[self.allclassrooms.index(x)]==0,self.allclassrooms)#已经学过的教室就不要去了
result=list(my_filter)
dis_to_class=[]
for k in result:
dis=distance(k,api,self)
dis_to_class.append(dis)
num=dis_to_class.index(min(dis_to_class))#result中距离最近的教室的编�?
which_class=result[num]
x1=which_class.x
y1=which_class.y
#print('nearest ',x1,y1)
#在classroom列表中找回这个点的位置,并在ifdone中修改标�?
index_of_class=next((i for i,xx in enumerate(self.allclassrooms) if xx.x==x1 and xx.y==y1),None)
ifdone[index_of_class]=1

Goto(which_class,api,self)
api.StartLearning()#开始学�?

class_count=class_count+1



# function

def __init__(self, pID: int):
self.__playerID = pID

def StudentPlay(self, api: IStudentAPI) -> None:
return
# 鍏叡鎿嶄綔
if self.map==None:
self.map=api.GetFullMap()
xi=0
yj=0
for i in self.map:
yj=0
for j in i:
if j.name=='ClassRoom':
self.allclassrooms.append(Cel(xi,yj))
if j.name=='Gate':
self.allgates.append(Cel(xi,yj))
if j.name=='HiddenGate':
self.allhiddengates.append(Cel(xi,yj))
if j.name=='Window':#��һ���������ĺ�������
self.allwindows.append(Cel(xi,yj))
if j.name=='Door3':
self.alldoors3.append(Cel(xi,yj))
if j.name=='Door5':
self.alldoors5.append(Cel(xi,yj))
if j.name=='Door6':
self.alldoors6.append(Cel(xi,yj))
if j.name=='Chest':
self.allboxes.append(Cel(xi,yj))
yj=yj+1
xi=xi+1
print(self.map)


if self.__playerID == 0:
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
#api.StartLearning()
#api.PrintSelfInfo()
#print('end')
#self.Study(api)
elif self.__playerID == 1:
# 鐜╁�??1鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 2:
# 鐜╁�??2鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 3:
# 鐜╁�??3鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
# 鍙互鍐欐垚if self.__playerID<2涔嬬被鐨勫啓娉�
# 鍏叡鎿嶄綔
return

def TrickerPlay(self, api: ITrickerAPI) -> None:
#api.EndAllAction()

if self.map is None:
self.map = api.GetFullMap()
yj = 0
xi = 0
for i in self.map:
yj = 0
for j in i:
if j.name == 'ClassRoom':
self.allclassrooms_tr.append(cel(xi,yj))
elif j.name == 'Gate':
self.allgates_tr.append(cel(xi,yj))
elif j.name == 'HiddenGate':
self.allhiddengates_tr.append(cel(xi,yj))
elif j.name == 'Window':
self.allwindows_tr.append(cel(xi,yj))
elif j.name == 'Door3':
self.alldoor3_tr.append(cel(xi,yj))
elif j.name == 'Door5':
self.alldoor5_tr.append(cel(xi,yj))
elif j.name == 'Door6':
self.alldoor6_tr.append(cel(xi,yj))
elif j.name == 'Chest':
self.allboxes_tr.append(cel(xi,yj))
yj = yj + 1
xi = xi + 1

if self.my_previous_frame is None:
self.my_previous_frame = precise_cel(0,0)
selfInfo = api.GetSelfInfo()
self.my_this_frame = precise_cel(selfInfo.x,selfInfo.y)


if selfInfo.trickerType.name == 'ANoisyPerson':
student_see = api.GetStudents()
now = cel(selfInfo.x,selfInfo.y,1)
dest= cel(0,0)
this_dest:cel
if self.near_chest(now,api):
api.StartOpenChest()
if selfInfo.playerState.name == 'Idle':
if len(student_see) == 0:
self.move_along_path = True
dest = cel(0,0)
if selfInfo.trickDesire == 0:
#找教室
dest = self.closest_classroom(now.x,now.y)
else:
dis = float(ANoisyPerson.alertnessRadius)/selfInfo.trickDesire
a=1
else:
self.move_along_path = False
closestudent:THUAI6.Student
closestudent = None
cloest = 1000000000000
attacklong = Constants.basicAttackShortRange
for i in student_see:
dis = dist(i.x,i.y,selfInfo.x,selfInfo.y)
if dis < cloest :
cloest = dis
if i.playerState.name != 'Addicted':
closestudent = i
if closestudent is not None:
dest = cel(closestudent.x,closestudent.y,1)
else:
dest = self.closest_chest(now.x,now.y,api)
#self.move_along_path = True
if closestudent is not None:
if closestudent.studentType.name == 'Athlete':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Teacher':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'StraightAStudent':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Sunshine':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
# if self.now_path is None and self.move_along_path == True:
# self.now_path = findway_DFS(self.map,now,dest)
# if self.move_along_path == True:
# dest = self.now_path[1]
this_dest = dest
angle = toangle(selfInfo.x,selfInfo.y,this_dest.gridx,this_dest.gridy)
if self.my_previous_frame.x == self.my_this_frame.x and self.my_previous_frame.y == self.my_this_frame.y:
if selfInfo.playerState.name == 'Idle':
api.MoveUp(10)
return
self.my_previous_frame = precise_cel(selfInfo.x,selfInfo.y)
if selfInfo.playerState.name == 'Idle':
api.Move(60,angle)
# hide in grass
# attack
# trick around
# find chest
# find classroom
elif selfInfo.trickerType.name == 'Idol':
a=1
elif selfInfo.trickerType.name == 'Assassin':
a=1

return

# playerID=4, GUID=678, x=21500, y=25500
# speed=3960, view range=15600, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, 0.0, -1.0]
# state=Idle, bullet=CommonAttackOfTricker, prop=NullPropType, NullPropType, NullPropType,
# type=Assassin, trick desire=2.4405367634838275, class volume=0.0
# buff=

# playerID=2, GUID=694, x=12500, y=26500
# speed=2880, view range=9000, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, -1.0, -1.0]
# state=Idle, bullet=NullBulletType, prop=NullPropType, NullPropType, NullPropType,
# type=StraightAStudent, determination=3300000, addiction=0, danger alert=0.0
# learning speed=135, encourage speed=100, encourage progress=0, rouse progress=0
# buff=

+ 735
- 0
players/pqfobj/player3.py View File

@@ -0,0 +1,735 @@
import PyAPI.structures as THUAI6
from PyAPI.Interface import *
from typing import Union, Final, cast, List
from PyAPI.constants import *
import queue

import time

# add
import numpy as np
import math
import copy
from collections import deque


class Setting:
# 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
@staticmethod
def asynchronous() -> bool:
return True

# 选手需要依次将player0到player4的职业都定义
@staticmethod
def studentType() -> List[THUAI6.StudentType]:
return [THUAI6.StudentType.Athlete, THUAI6.StudentType.Teacher, THUAI6.StudentType.StraightAStudent, THUAI6.StudentType.Sunshine]

@staticmethod
def trickerType() -> THUAI6.TrickerType:
return THUAI6.TrickerType.ANoisyPerson


# 辅助函数
numOfGridPerCell: Final[int] = 1000


class AssistFunction:

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2

@staticmethod
def GridToCell(grid: int) -> int:
return grid // numOfGridPerCell

# additional function_tricker

pi = 3.1415926535

class cel:
x:int
y:int
gridx:int
gridy:int
def __init__(self,x1:int, y1:int,type = 0):#type==0采用0-50赋值
if type ==0:
self.x = x1
self.y = y1
self.gridx = AssistFunction.CellToGrid(x1)
self.gridy = AssistFunction.CellToGrid(y1)
else:
self.x = AssistFunction.GridToCell(x1)
self.y = AssistFunction.GridToCell(y1)
self.gridx = AssistFunction.CellToGrid(self.x)
self.gridy = AssistFunction.CellToGrid(self.y)

class precise_cel:
x:int
y:int
def __init__(self,x1:int, y1:int):
self.x = x1
self.y = y1

def gridtocell(x:int,y:int) -> cel:#返回坐标对应的cell
return cel(AssistFunction.GridToCell(x),AssistFunction.GridToCell(y))

def distocell(x:int,y:int,dis:float,angle:float) -> List[cel]:#返回以一个点为中心长度为dis的cell
allcell=[]
for i in range(0,2*pi,angle):
x1 = x+dis*math.cos(i)
y1 = y+dis*math.sin(i)
if x1>0 and x1<50000 and y1 >0 and y1<50000:
the = gridtocell(x1,y1)
if len(allcell) == 0:
allcell.append(the)
elif allcell[-1].x != the.x or allcell[-1].y != the.y:
allcell.append(the)
return allcell
# Land = 1
# Wall = 2
# Grass = 3
# ClassRoom = 4
# Gate = 5
# HiddenGate = 6
# Window = 7
# Door3 = 8
# Door5 = 9
# Door6 = 10
# Chest = 11

def findpa(now:cel,dest:cel,map:List[List[THUAI6.PlaceType]]) -> cel:
return cel(1,1)

def dist(x1:int,y1:int,x2:int,y2:int) ->float:
return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def toangle(nowx:int,nowy:int,tox:int,toy:int) ->float:
if toy >= nowy:
return math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))
else:
return -math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))

def toangle_cel(now:cel,dest:cel) ->float:
if dest.y >= now.y:
return math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))
else:
return -math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))

def findway_DFS(grid, start:cel, end:cel) -> List[cel]:
row, col = 50,50
visited = set()
path =[]
class anan:
angle:float
to:int#0,1,2,3,下右上左
def __init__(self,angel:float,to:int) -> None:
self.angle = angel
self.to = to
pass

def azhe(jjj:anan)->float:
return jjj.angle

def help(now:cel,path:List[cel])->List[cel]:
if now == end:
return path
if now in visited:
oo = []
return oo
visited.add(now)
angle = toangle_cel(now,end)
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
chae = [anan(abs(angle),0),anan(abs(angle-pi/2),1),anan(abs(angle-pi),2),anan(abs(angle-pi*1.5),3)]
chae.sort(key = azhe)
for i in chae:
dx,dy = directions[i.to]
new_x, new_y = now.x + dx, now.y + dy
new =cel(new_x, new_y)
if (grid[new_x][new_y]).value in [1,3,7,8,9,10]:
path.append(new)
visited.remove(now)
return help(path[-1], path)
return help(start,path = path)


# additional function_tricker

# additional function_student

pi=3.1415926535
class Cel:
x:int
y:int
def __init__(self,x1:int,y1:int):
self.x=x1
self.y=y1

#计算距离
def distance(target:Cel,api:IStudentAPI,ai)->float:
selfinfo=api.GetSelfInfo()
return math.sqrt((target.x-selfinfo.x)**2+(target.y-selfinfo.y)**2)

movetime=50
#为避免没到格子中心卡墙角,用cel规划路径,用grid精确地走
def Goto(target:Cel,api:IStudentAPI,ai)->None:
selfinfo=api.GetSelfInfo()
#当前格子坐标
#if self.nowpath==None:
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)
nowpath=ai.BFSpath(selfinfo,cur,target,api)#规划路径
#print('self.nowpath')
#for k in nowpath:
# print(k.x,k.y)
while len(nowpath)!=0:#能否这样判断不空
first=nowpath[0]
x1=1000*first.x+500
y1=1000*first.y+500
#print('curgrid',selfx,selfy)
#print('first ',x1,y1)
if cur.x==first.x and cur.y==first.y:
a=nowpath.pop(0)
else:
#print('not the same')
#print('first',x1,y1)
#print('cur',cur.x,cur.y)
if x1==selfx and y1<selfy:api.MoveLeft(movetime)
elif x1==selfx and y1>selfy:api.MoveRight(movetime)
elif x1<selfx and y1==selfy:api.MoveUp(movetime)
elif x1>selfx and y1==selfy:api.MoveDown(movetime)
elif x1<selfx and y1<selfy:api.Move(movetime,-pi*3/4)
elif x1<selfx and y1>selfy:api.Move(movetime,pi*3/4)
elif x1>selfx and y1<selfy:api.Move(movetime,-pi/4)
elif x1>selfx and y1>selfy:api.Move(movetime,pi/4)
#api.PrintSelfInfo()
selfinfo1=api.GetSelfInfo()
selfx1=selfinfo1.x
selfy1=selfinfo1.y
#print('aftermove',selfx1,selfy1)
#cur1=gridtocell(selfinfo1.x,selfinfo1.y)
#print('info',cur1.x,cur1.y)
if(selfx==selfx1 and selfy==selfy1):
#print('not moved')
api.MoveRight(movetime)
# api.MoveRight(movetime)
selfinfo=api.GetSelfInfo()
#print('State ',selfinfo.playerState.name)
#api.PrintSelfInfo()
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)

# additional function_student

class AI(IAI):
map = None


# tricker
allgates_tr=[]
allwindows_tr = []
alldoor3_tr = []
alldoor5_tr = []
alldoor6_tr = []
allclassrooms_tr = []
allboxes_tr = []
allhiddengates_tr = []

studentposition_previous_frame=None#precise_cel
studentposition_this_frame=None#precise_cel
my_previous_frame=None#precise_cel
my_this_frame=None#precise_cel

now_path=None#List[cel]
move_along_path=None#bool


def closest_chest(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allboxes_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxChestProgress:
dis = k
the = i
return the
def closest_classroom(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allclassrooms_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxClassroomProgress:
dis = k
the = i
return the

def wall_exist_precise(self,now:precise_cel,dest:precise_cel)->bool:
k = (dest.y-now.y)/(dest.x-now.x)
# y = k(x-now.x)+now.y
long = dest.x-now.x
for i in range(0,long,801):
y1= k*i+now.y
ok = cel(now.x+i,y1)
if self.map[ok.x][ok.y].value in [2,4,5,6,11]:
return True
return False

def near_chest(self,now:cel,api)->bool:
eight = [cel(now.x,now.y+1),cel(now.x,now.y-1),cel(now.x+1,now.y),cel(now.x-1,now.y),cel(now.x+1,now.y+1),cel(now.x-1,now.y-1),cel(now.x+1,now.y-1),cel(now.x-1,now.y+1)]
for i in eight:
jindu = api.GetChestProgress(i.x,i.y)
if self.map[i.x][i.y].name == 'Chest' and jindu < Constants.maxChestProgress:
return True
return False
# student

allgates=[]
allwindows = []
alldoors3 = []
alldoors5 = []
alldoors6 = []
allclassrooms = []
allboxes = []
allhiddengates = []

last_cel:Cel
cur_cel:Cel
#movetime=10#移动时间是多少?
#nowpath:deque[Cel]#存BFS得出的路径直到路径走�??
#move_along_path=0#直到走完路径,避免每帧调用一�??

def Todestin(self,api:IStudentAPI):
return

def Iscanreach(self,point:Cel,target:Cel)->bool:#判断两个点能否直接到
if(target.x<0 or target.x>50
or target.y<0 or target.y>50
or self.map[target.x][target.y].name=='Wall'
or (target.x==point.x and target.y==point.y)):#或超出地图、墙壁、与初始点重�??
return False
else:#上下左右�??
if(abs(point.x-target.x)+abs(point.y-target.y)==1):
return True
else:#斜对角线是门的话先不�??
name1=self.map[target.x][target.y].name
if(name1=='Door3' or name1=='Door5' or name1=='Door6'):
return False
else:
name2=self.map[target.x][point.y].name
name3=self.map[point.x][target.y].name
if name2=='Wall' or name3=='Wall':
return False
else:
return True
#对角线的两侧有墙壁的话也不行�??45度的时候走不过�??
#隐藏门和大校门?
def getSurroundCell(self,info:THUAI6.Student,point:Cel)->deque[Cel]:#找到该点周围8个点中能到的
surroundCell=[]#存能到的
curprop=info.prop
global next
for xi in range(point.x-1,point.x+2):
for yj in range(point.y-1,point.y+2):
other=Cel(xi,yj)
if(self.Iscanreach(point,other)):
sname=self.map[other.x][other.y].name
if(sname=='Door3'):#是门的话,判断有无对应钥匙?
if 1 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door5'):
if 2 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door6'):
if 3 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Window'):#是窗的话爬出�??
next=Cel(2*other.x-point.x,2*other.y-point.y)
else:
next=other
surroundCell.append(next)
return surroundCell
#判断坐标是否在list里,searched用到,也是数字相同但不同对象
def InList(self,point:Cel,llist:List)->bool:
for k in llist:
if point.x==k.x and point.y==k.y:
return True
return False
#坐标是否在字典的key里,每一次初始化类的对象,尽管数字相同但还是不同对象,可以重�??=?还可以?(后面简化一�??
def InDic(self,point:Cel,DDix:dict)->bool:
for k in DDix.keys():
if point.x==k.x and point.y==k.y:
return True
return False

#广度搜索找路径,如果
#路径不存在的情况�??
def BFSpath(self,info:THUAI6.Student,point:Cel,target:Cel,api:IStudentAPI)->List[Cel]:
#self_info=api.GetSelfInfo(self)
searched=[]#已经搜过的点
q=deque()
q.append(point)#初始点加�??
#定义搜索过的点的父节�??
parents=dict()
path=[target]

while q:
cur_=q.popleft()
#如果点没有被搜过
if not self.InList(cur_,searched):
#api.Print('not serached'+'cur_ '+str(cur_.x)+' '+str(cur_.y))
if(cur_.x !=target.x or cur_.y!=target.y):
#print('!=here')
sur=self.getSurroundCell(info,cur_)
for k in sur:
if not self.InList(k,searched):
q.append(k)
if not self.InDic(k,parents):
parents[k]=cur_
searched.append(cur_)
else:
#print('cur_=target')
key=Cel(target.x,target.y)
while key.x!=point.x or key.y!=point.y:
for k in parents:
if k.x==key.x and k.y==key.y:
father=parents[k]
path.append(father)
key=father
#往回找到路径后,将列表反转
path.reverse()
break
return path

#�?7间教室学�?
def Study(self,api:IStudentAPI)->None:
leng=len(self.allclassrooms)
ifdone=np.zeros((leng,1),dtype=bool)
class_count=0#已经学的教室的间�?
#找到距离self最近的教室并前往,途中捡道�?
while class_count<7:
my_filter=filter(lambda x:ifdone[self.allclassrooms.index(x)]==0,self.allclassrooms)#已经学过的教室就不要去了
result=list(my_filter)
dis_to_class=[]
for k in result:
dis=distance(k,api,self)
dis_to_class.append(dis)
num=dis_to_class.index(min(dis_to_class))#result中距离最近的教室的编�?
which_class=result[num]
x1=which_class.x
y1=which_class.y
#print('nearest ',x1,y1)
#在classroom列表中找回这个点的位置,并在ifdone中修改标�?
index_of_class=next((i for i,xx in enumerate(self.allclassrooms) if xx.x==x1 and xx.y==y1),None)
ifdone[index_of_class]=1

Goto(which_class,api,self)
api.StartLearning()#开始学�?

class_count=class_count+1



# function

def __init__(self, pID: int):
self.__playerID = pID

def StudentPlay(self, api: IStudentAPI) -> None:
return
# 鍏叡鎿嶄綔
if self.map==None:
self.map=api.GetFullMap()
xi=0
yj=0
for i in self.map:
yj=0
for j in i:
if j.name=='ClassRoom':
self.allclassrooms.append(Cel(xi,yj))
if j.name=='Gate':
self.allgates.append(Cel(xi,yj))
if j.name=='HiddenGate':
self.allhiddengates.append(Cel(xi,yj))
if j.name=='Window':#��һ���������ĺ�������
self.allwindows.append(Cel(xi,yj))
if j.name=='Door3':
self.alldoors3.append(Cel(xi,yj))
if j.name=='Door5':
self.alldoors5.append(Cel(xi,yj))
if j.name=='Door6':
self.alldoors6.append(Cel(xi,yj))
if j.name=='Chest':
self.allboxes.append(Cel(xi,yj))
yj=yj+1
xi=xi+1
print(self.map)


if self.__playerID == 0:
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
#api.StartLearning()
#api.PrintSelfInfo()
#print('end')
#self.Study(api)
elif self.__playerID == 1:
# 鐜╁�??1鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 2:
# 鐜╁�??2鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 3:
# 鐜╁�??3鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
# 鍙互鍐欐垚if self.__playerID<2涔嬬被鐨勫啓娉�
# 鍏叡鎿嶄綔
return

def TrickerPlay(self, api: ITrickerAPI) -> None:
#api.EndAllAction()

if self.map is None:
self.map = api.GetFullMap()
yj = 0
xi = 0
for i in self.map:
yj = 0
for j in i:
if j.name == 'ClassRoom':
self.allclassrooms_tr.append(cel(xi,yj))
elif j.name == 'Gate':
self.allgates_tr.append(cel(xi,yj))
elif j.name == 'HiddenGate':
self.allhiddengates_tr.append(cel(xi,yj))
elif j.name == 'Window':
self.allwindows_tr.append(cel(xi,yj))
elif j.name == 'Door3':
self.alldoor3_tr.append(cel(xi,yj))
elif j.name == 'Door5':
self.alldoor5_tr.append(cel(xi,yj))
elif j.name == 'Door6':
self.alldoor6_tr.append(cel(xi,yj))
elif j.name == 'Chest':
self.allboxes_tr.append(cel(xi,yj))
yj = yj + 1
xi = xi + 1

if self.my_previous_frame is None:
self.my_previous_frame = precise_cel(0,0)
selfInfo = api.GetSelfInfo()
self.my_this_frame = precise_cel(selfInfo.x,selfInfo.y)


if selfInfo.trickerType.name == 'ANoisyPerson':
student_see = api.GetStudents()
now = cel(selfInfo.x,selfInfo.y,1)
dest= cel(0,0)
this_dest:cel
if self.near_chest(now,api):
api.StartOpenChest()
if selfInfo.playerState.name == 'Idle':
if len(student_see) == 0:
self.move_along_path = True
dest = cel(0,0)
if selfInfo.trickDesire == 0:
#找教室
dest = self.closest_classroom(now.x,now.y)
else:
dis = float(ANoisyPerson.alertnessRadius)/selfInfo.trickDesire
a=1
else:
self.move_along_path = False
closestudent:THUAI6.Student
closestudent = None
cloest = 1000000000000
attacklong = Constants.basicAttackShortRange
for i in student_see:
dis = dist(i.x,i.y,selfInfo.x,selfInfo.y)
if dis < cloest :
cloest = dis
if i.playerState.name != 'Addicted':
closestudent = i
if closestudent is not None:
dest = cel(closestudent.x,closestudent.y,1)
else:
dest = self.closest_chest(now.x,now.y,api)
#self.move_along_path = True
if closestudent is not None:
if closestudent.studentType.name == 'Athlete':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Teacher':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'StraightAStudent':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Sunshine':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
# if self.now_path is None and self.move_along_path == True:
# self.now_path = findway_DFS(self.map,now,dest)
# if self.move_along_path == True:
# dest = self.now_path[1]
this_dest = dest
angle = toangle(selfInfo.x,selfInfo.y,this_dest.gridx,this_dest.gridy)
if self.my_previous_frame.x == self.my_this_frame.x and self.my_previous_frame.y == self.my_this_frame.y:
if selfInfo.playerState.name == 'Idle':
api.MoveUp(10)
return
self.my_previous_frame = precise_cel(selfInfo.x,selfInfo.y)
if selfInfo.playerState.name == 'Idle':
api.Move(60,angle)
# hide in grass
# attack
# trick around
# find chest
# find classroom
elif selfInfo.trickerType.name == 'Idol':
a=1
elif selfInfo.trickerType.name == 'Assassin':
a=1

return

# playerID=4, GUID=678, x=21500, y=25500
# speed=3960, view range=15600, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, 0.0, -1.0]
# state=Idle, bullet=CommonAttackOfTricker, prop=NullPropType, NullPropType, NullPropType,
# type=Assassin, trick desire=2.4405367634838275, class volume=0.0
# buff=

# playerID=2, GUID=694, x=12500, y=26500
# speed=2880, view range=9000, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, -1.0, -1.0]
# state=Idle, bullet=NullBulletType, prop=NullPropType, NullPropType, NullPropType,
# type=StraightAStudent, determination=3300000, addiction=0, danger alert=0.0
# learning speed=135, encourage speed=100, encourage progress=0, rouse progress=0
# buff=

+ 735
- 0
players/pqfobj/player4.py View File

@@ -0,0 +1,735 @@
import PyAPI.structures as THUAI6
from PyAPI.Interface import *
from typing import Union, Final, cast, List
from PyAPI.constants import *
import queue

import time

# add
import numpy as np
import math
import copy
from collections import deque


class Setting:
# 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
@staticmethod
def asynchronous() -> bool:
return True

# 选手需要依次将player0到player4的职业都定义
@staticmethod
def studentType() -> List[THUAI6.StudentType]:
return [THUAI6.StudentType.Athlete, THUAI6.StudentType.Teacher, THUAI6.StudentType.StraightAStudent, THUAI6.StudentType.Sunshine]

@staticmethod
def trickerType() -> THUAI6.TrickerType:
return THUAI6.TrickerType.ANoisyPerson


# 辅助函数
numOfGridPerCell: Final[int] = 1000


class AssistFunction:

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2

@staticmethod
def GridToCell(grid: int) -> int:
return grid // numOfGridPerCell

# additional function_tricker

pi = 3.1415926535

class cel:
x:int
y:int
gridx:int
gridy:int
def __init__(self,x1:int, y1:int,type = 0):#type==0采用0-50赋值
if type ==0:
self.x = x1
self.y = y1
self.gridx = AssistFunction.CellToGrid(x1)
self.gridy = AssistFunction.CellToGrid(y1)
else:
self.x = AssistFunction.GridToCell(x1)
self.y = AssistFunction.GridToCell(y1)
self.gridx = AssistFunction.CellToGrid(self.x)
self.gridy = AssistFunction.CellToGrid(self.y)

class precise_cel:
x:int
y:int
def __init__(self,x1:int, y1:int):
self.x = x1
self.y = y1

def gridtocell(x:int,y:int) -> cel:#返回坐标对应的cell
return cel(AssistFunction.GridToCell(x),AssistFunction.GridToCell(y))

def distocell(x:int,y:int,dis:float,angle:float) -> List[cel]:#返回以一个点为中心长度为dis的cell
allcell=[]
for i in range(0,2*pi,angle):
x1 = x+dis*math.cos(i)
y1 = y+dis*math.sin(i)
if x1>0 and x1<50000 and y1 >0 and y1<50000:
the = gridtocell(x1,y1)
if len(allcell) == 0:
allcell.append(the)
elif allcell[-1].x != the.x or allcell[-1].y != the.y:
allcell.append(the)
return allcell
# Land = 1
# Wall = 2
# Grass = 3
# ClassRoom = 4
# Gate = 5
# HiddenGate = 6
# Window = 7
# Door3 = 8
# Door5 = 9
# Door6 = 10
# Chest = 11

def findpa(now:cel,dest:cel,map:List[List[THUAI6.PlaceType]]) -> cel:
return cel(1,1)

def dist(x1:int,y1:int,x2:int,y2:int) ->float:
return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def toangle(nowx:int,nowy:int,tox:int,toy:int) ->float:
if toy >= nowy:
return math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))
else:
return -math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))

def toangle_cel(now:cel,dest:cel) ->float:
if dest.y >= now.y:
return math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))
else:
return -math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))

def findway_DFS(grid, start:cel, end:cel) -> List[cel]:
row, col = 50,50
visited = set()
path =[]
class anan:
angle:float
to:int#0,1,2,3,下右上左
def __init__(self,angel:float,to:int) -> None:
self.angle = angel
self.to = to
pass

def azhe(jjj:anan)->float:
return jjj.angle

def help(now:cel,path:List[cel])->List[cel]:
if now == end:
return path
if now in visited:
oo = []
return oo
visited.add(now)
angle = toangle_cel(now,end)
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
chae = [anan(abs(angle),0),anan(abs(angle-pi/2),1),anan(abs(angle-pi),2),anan(abs(angle-pi*1.5),3)]
chae.sort(key = azhe)
for i in chae:
dx,dy = directions[i.to]
new_x, new_y = now.x + dx, now.y + dy
new =cel(new_x, new_y)
if (grid[new_x][new_y]).value in [1,3,7,8,9,10]:
path.append(new)
visited.remove(now)
return help(path[-1], path)
return help(start,path = path)


# additional function_tricker

# additional function_student

pi=3.1415926535
class Cel:
x:int
y:int
def __init__(self,x1:int,y1:int):
self.x=x1
self.y=y1

#计算距离
def distance(target:Cel,api:IStudentAPI,ai)->float:
selfinfo=api.GetSelfInfo()
return math.sqrt((target.x-selfinfo.x)**2+(target.y-selfinfo.y)**2)

movetime=50
#为避免没到格子中心卡墙角,用cel规划路径,用grid精确地走
def Goto(target:Cel,api:IStudentAPI,ai)->None:
selfinfo=api.GetSelfInfo()
#当前格子坐标
#if self.nowpath==None:
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)
nowpath=ai.BFSpath(selfinfo,cur,target,api)#规划路径
#print('self.nowpath')
#for k in nowpath:
# print(k.x,k.y)
while len(nowpath)!=0:#能否这样判断不空
first=nowpath[0]
x1=1000*first.x+500
y1=1000*first.y+500
#print('curgrid',selfx,selfy)
#print('first ',x1,y1)
if cur.x==first.x and cur.y==first.y:
a=nowpath.pop(0)
else:
#print('not the same')
#print('first',x1,y1)
#print('cur',cur.x,cur.y)
if x1==selfx and y1<selfy:api.MoveLeft(movetime)
elif x1==selfx and y1>selfy:api.MoveRight(movetime)
elif x1<selfx and y1==selfy:api.MoveUp(movetime)
elif x1>selfx and y1==selfy:api.MoveDown(movetime)
elif x1<selfx and y1<selfy:api.Move(movetime,-pi*3/4)
elif x1<selfx and y1>selfy:api.Move(movetime,pi*3/4)
elif x1>selfx and y1<selfy:api.Move(movetime,-pi/4)
elif x1>selfx and y1>selfy:api.Move(movetime,pi/4)
#api.PrintSelfInfo()
selfinfo1=api.GetSelfInfo()
selfx1=selfinfo1.x
selfy1=selfinfo1.y
#print('aftermove',selfx1,selfy1)
#cur1=gridtocell(selfinfo1.x,selfinfo1.y)
#print('info',cur1.x,cur1.y)
if(selfx==selfx1 and selfy==selfy1):
#print('not moved')
api.MoveRight(movetime)
# api.MoveRight(movetime)
selfinfo=api.GetSelfInfo()
#print('State ',selfinfo.playerState.name)
#api.PrintSelfInfo()
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)

# additional function_student

class AI(IAI):
map = None


# tricker
allgates_tr=[]
allwindows_tr = []
alldoor3_tr = []
alldoor5_tr = []
alldoor6_tr = []
allclassrooms_tr = []
allboxes_tr = []
allhiddengates_tr = []

studentposition_previous_frame=None#precise_cel
studentposition_this_frame=None#precise_cel
my_previous_frame=None#precise_cel
my_this_frame=None#precise_cel

now_path=None#List[cel]
move_along_path=None#bool


def closest_chest(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allboxes_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxChestProgress:
dis = k
the = i
return the
def closest_classroom(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allclassrooms_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxClassroomProgress:
dis = k
the = i
return the

def wall_exist_precise(self,now:precise_cel,dest:precise_cel)->bool:
k = (dest.y-now.y)/(dest.x-now.x)
# y = k(x-now.x)+now.y
long = dest.x-now.x
for i in range(0,long,801):
y1= k*i+now.y
ok = cel(now.x+i,y1)
if self.map[ok.x][ok.y].value in [2,4,5,6,11]:
return True
return False

def near_chest(self,now:cel,api)->bool:
eight = [cel(now.x,now.y+1),cel(now.x,now.y-1),cel(now.x+1,now.y),cel(now.x-1,now.y),cel(now.x+1,now.y+1),cel(now.x-1,now.y-1),cel(now.x+1,now.y-1),cel(now.x-1,now.y+1)]
for i in eight:
jindu = api.GetChestProgress(i.x,i.y)
if self.map[i.x][i.y].name == 'Chest' and jindu < Constants.maxChestProgress:
return True
return False
# student

allgates=[]
allwindows = []
alldoors3 = []
alldoors5 = []
alldoors6 = []
allclassrooms = []
allboxes = []
allhiddengates = []

last_cel:Cel
cur_cel:Cel
#movetime=10#移动时间是多少?
#nowpath:deque[Cel]#存BFS得出的路径直到路径走�??
#move_along_path=0#直到走完路径,避免每帧调用一�??

def Todestin(self,api:IStudentAPI):
return

def Iscanreach(self,point:Cel,target:Cel)->bool:#判断两个点能否直接到
if(target.x<0 or target.x>50
or target.y<0 or target.y>50
or self.map[target.x][target.y].name=='Wall'
or (target.x==point.x and target.y==point.y)):#或超出地图、墙壁、与初始点重�??
return False
else:#上下左右�??
if(abs(point.x-target.x)+abs(point.y-target.y)==1):
return True
else:#斜对角线是门的话先不�??
name1=self.map[target.x][target.y].name
if(name1=='Door3' or name1=='Door5' or name1=='Door6'):
return False
else:
name2=self.map[target.x][point.y].name
name3=self.map[point.x][target.y].name
if name2=='Wall' or name3=='Wall':
return False
else:
return True
#对角线的两侧有墙壁的话也不行�??45度的时候走不过�??
#隐藏门和大校门?
def getSurroundCell(self,info:THUAI6.Student,point:Cel)->deque[Cel]:#找到该点周围8个点中能到的
surroundCell=[]#存能到的
curprop=info.prop
global next
for xi in range(point.x-1,point.x+2):
for yj in range(point.y-1,point.y+2):
other=Cel(xi,yj)
if(self.Iscanreach(point,other)):
sname=self.map[other.x][other.y].name
if(sname=='Door3'):#是门的话,判断有无对应钥匙?
if 1 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door5'):
if 2 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door6'):
if 3 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Window'):#是窗的话爬出�??
next=Cel(2*other.x-point.x,2*other.y-point.y)
else:
next=other
surroundCell.append(next)
return surroundCell
#判断坐标是否在list里,searched用到,也是数字相同但不同对象
def InList(self,point:Cel,llist:List)->bool:
for k in llist:
if point.x==k.x and point.y==k.y:
return True
return False
#坐标是否在字典的key里,每一次初始化类的对象,尽管数字相同但还是不同对象,可以重�??=?还可以?(后面简化一�??
def InDic(self,point:Cel,DDix:dict)->bool:
for k in DDix.keys():
if point.x==k.x and point.y==k.y:
return True
return False

#广度搜索找路径,如果
#路径不存在的情况�??
def BFSpath(self,info:THUAI6.Student,point:Cel,target:Cel,api:IStudentAPI)->List[Cel]:
#self_info=api.GetSelfInfo(self)
searched=[]#已经搜过的点
q=deque()
q.append(point)#初始点加�??
#定义搜索过的点的父节�??
parents=dict()
path=[target]

while q:
cur_=q.popleft()
#如果点没有被搜过
if not self.InList(cur_,searched):
#api.Print('not serached'+'cur_ '+str(cur_.x)+' '+str(cur_.y))
if(cur_.x !=target.x or cur_.y!=target.y):
#print('!=here')
sur=self.getSurroundCell(info,cur_)
for k in sur:
if not self.InList(k,searched):
q.append(k)
if not self.InDic(k,parents):
parents[k]=cur_
searched.append(cur_)
else:
#print('cur_=target')
key=Cel(target.x,target.y)
while key.x!=point.x or key.y!=point.y:
for k in parents:
if k.x==key.x and k.y==key.y:
father=parents[k]
path.append(father)
key=father
#往回找到路径后,将列表反转
path.reverse()
break
return path

#�?7间教室学�?
def Study(self,api:IStudentAPI)->None:
leng=len(self.allclassrooms)
ifdone=np.zeros((leng,1),dtype=bool)
class_count=0#已经学的教室的间�?
#找到距离self最近的教室并前往,途中捡道�?
while class_count<7:
my_filter=filter(lambda x:ifdone[self.allclassrooms.index(x)]==0,self.allclassrooms)#已经学过的教室就不要去了
result=list(my_filter)
dis_to_class=[]
for k in result:
dis=distance(k,api,self)
dis_to_class.append(dis)
num=dis_to_class.index(min(dis_to_class))#result中距离最近的教室的编�?
which_class=result[num]
x1=which_class.x
y1=which_class.y
#print('nearest ',x1,y1)
#在classroom列表中找回这个点的位置,并在ifdone中修改标�?
index_of_class=next((i for i,xx in enumerate(self.allclassrooms) if xx.x==x1 and xx.y==y1),None)
ifdone[index_of_class]=1

Goto(which_class,api,self)
api.StartLearning()#开始学�?

class_count=class_count+1



# function

def __init__(self, pID: int):
self.__playerID = pID

def StudentPlay(self, api: IStudentAPI) -> None:
return
# 鍏叡鎿嶄綔
if self.map==None:
self.map=api.GetFullMap()
xi=0
yj=0
for i in self.map:
yj=0
for j in i:
if j.name=='ClassRoom':
self.allclassrooms.append(Cel(xi,yj))
if j.name=='Gate':
self.allgates.append(Cel(xi,yj))
if j.name=='HiddenGate':
self.allhiddengates.append(Cel(xi,yj))
if j.name=='Window':#��һ���������ĺ�������
self.allwindows.append(Cel(xi,yj))
if j.name=='Door3':
self.alldoors3.append(Cel(xi,yj))
if j.name=='Door5':
self.alldoors5.append(Cel(xi,yj))
if j.name=='Door6':
self.alldoors6.append(Cel(xi,yj))
if j.name=='Chest':
self.allboxes.append(Cel(xi,yj))
yj=yj+1
xi=xi+1
print(self.map)


if self.__playerID == 0:
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
#api.StartLearning()
#api.PrintSelfInfo()
#print('end')
#self.Study(api)
elif self.__playerID == 1:
# 鐜╁�??1鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 2:
# 鐜╁�??2鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 3:
# 鐜╁�??3鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
# 鍙互鍐欐垚if self.__playerID<2涔嬬被鐨勫啓娉�
# 鍏叡鎿嶄綔
return

def TrickerPlay(self, api: ITrickerAPI) -> None:
#api.EndAllAction()

if self.map is None:
self.map = api.GetFullMap()
yj = 0
xi = 0
for i in self.map:
yj = 0
for j in i:
if j.name == 'ClassRoom':
self.allclassrooms_tr.append(cel(xi,yj))
elif j.name == 'Gate':
self.allgates_tr.append(cel(xi,yj))
elif j.name == 'HiddenGate':
self.allhiddengates_tr.append(cel(xi,yj))
elif j.name == 'Window':
self.allwindows_tr.append(cel(xi,yj))
elif j.name == 'Door3':
self.alldoor3_tr.append(cel(xi,yj))
elif j.name == 'Door5':
self.alldoor5_tr.append(cel(xi,yj))
elif j.name == 'Door6':
self.alldoor6_tr.append(cel(xi,yj))
elif j.name == 'Chest':
self.allboxes_tr.append(cel(xi,yj))
yj = yj + 1
xi = xi + 1

if self.my_previous_frame is None:
self.my_previous_frame = precise_cel(0,0)
selfInfo = api.GetSelfInfo()
self.my_this_frame = precise_cel(selfInfo.x,selfInfo.y)


if selfInfo.trickerType.name == 'ANoisyPerson':
student_see = api.GetStudents()
now = cel(selfInfo.x,selfInfo.y,1)
dest= cel(0,0)
this_dest:cel
if self.near_chest(now,api):
api.StartOpenChest()
if selfInfo.playerState.name == 'Idle':
if len(student_see) == 0:
self.move_along_path = True
dest = cel(0,0)
if selfInfo.trickDesire == 0:
#找教室
dest = self.closest_classroom(now.x,now.y)
else:
dis = float(ANoisyPerson.alertnessRadius)/selfInfo.trickDesire
a=1
else:
self.move_along_path = False
closestudent:THUAI6.Student
closestudent = None
cloest = 1000000000000
attacklong = Constants.basicAttackShortRange
for i in student_see:
dis = dist(i.x,i.y,selfInfo.x,selfInfo.y)
if dis < cloest :
cloest = dis
if i.playerState.name != 'Addicted':
closestudent = i
if closestudent is not None:
dest = cel(closestudent.x,closestudent.y,1)
else:
dest = self.closest_chest(now.x,now.y,api)
#self.move_along_path = True
if closestudent is not None:
if closestudent.studentType.name == 'Athlete':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Teacher':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'StraightAStudent':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Sunshine':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
# if self.now_path is None and self.move_along_path == True:
# self.now_path = findway_DFS(self.map,now,dest)
# if self.move_along_path == True:
# dest = self.now_path[1]
this_dest = dest
angle = toangle(selfInfo.x,selfInfo.y,this_dest.gridx,this_dest.gridy)
if self.my_previous_frame.x == self.my_this_frame.x and self.my_previous_frame.y == self.my_this_frame.y:
if selfInfo.playerState.name == 'Idle':
api.MoveUp(10)
return
self.my_previous_frame = precise_cel(selfInfo.x,selfInfo.y)
if selfInfo.playerState.name == 'Idle':
api.Move(60,angle)
# hide in grass
# attack
# trick around
# find chest
# find classroom
elif selfInfo.trickerType.name == 'Idol':
a=1
elif selfInfo.trickerType.name == 'Assassin':
a=1

return

# playerID=4, GUID=678, x=21500, y=25500
# speed=3960, view range=15600, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, 0.0, -1.0]
# state=Idle, bullet=CommonAttackOfTricker, prop=NullPropType, NullPropType, NullPropType,
# type=Assassin, trick desire=2.4405367634838275, class volume=0.0
# buff=

# playerID=2, GUID=694, x=12500, y=26500
# speed=2880, view range=9000, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, -1.0, -1.0]
# state=Idle, bullet=NullBulletType, prop=NullPropType, NullPropType, NullPropType,
# type=StraightAStudent, determination=3300000, addiction=0, danger alert=0.0
# learning speed=135, encourage speed=100, encourage progress=0, rouse progress=0
# buff=

+ 734
- 0
players/pqfobj/player5.py View File

@@ -0,0 +1,734 @@
import PyAPI.structures as THUAI6
from PyAPI.Interface import *
from typing import Union, Final, cast, List
from PyAPI.constants import *
import queue

import time

# add
import numpy as np
import math
import copy
from collections import deque


class Setting:
# 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
@staticmethod
def asynchronous() -> bool:
return True

# 选手需要依次将player0到player4的职业都定义
@staticmethod
def studentType() -> List[THUAI6.StudentType]:
return [THUAI6.StudentType.Athlete, THUAI6.StudentType.Teacher, THUAI6.StudentType.StraightAStudent, THUAI6.StudentType.Sunshine]

@staticmethod
def trickerType() -> THUAI6.TrickerType:
return THUAI6.TrickerType.ANoisyPerson


# 辅助函数
numOfGridPerCell: Final[int] = 1000


class AssistFunction:

@staticmethod
def CellToGrid(cell: int) -> int:
return cell * numOfGridPerCell + numOfGridPerCell // 2

@staticmethod
def GridToCell(grid: int) -> int:
return grid // numOfGridPerCell

# additional function_tricker

pi = 3.1415926535

class cel:
x:int
y:int
gridx:int
gridy:int
def __init__(self,x1:int, y1:int,type = 0):#type==0采用0-50赋值
if type ==0:
self.x = x1
self.y = y1
self.gridx = AssistFunction.CellToGrid(x1)
self.gridy = AssistFunction.CellToGrid(y1)
else:
self.x = AssistFunction.GridToCell(x1)
self.y = AssistFunction.GridToCell(y1)
self.gridx = AssistFunction.CellToGrid(self.x)
self.gridy = AssistFunction.CellToGrid(self.y)

class precise_cel:
x:int
y:int
def __init__(self,x1:int, y1:int):
self.x = x1
self.y = y1

def gridtocell(x:int,y:int) -> cel:#返回坐标对应的cell
return cel(AssistFunction.GridToCell(x),AssistFunction.GridToCell(y))

def distocell(x:int,y:int,dis:float,angle:float) -> List[cel]:#返回以一个点为中心长度为dis的cell
allcell=[]
for i in range(0,2*pi,angle):
x1 = x+dis*math.cos(i)
y1 = y+dis*math.sin(i)
if x1>0 and x1<50000 and y1 >0 and y1<50000:
the = gridtocell(x1,y1)
if len(allcell) == 0:
allcell.append(the)
elif allcell[-1].x != the.x or allcell[-1].y != the.y:
allcell.append(the)
return allcell
# Land = 1
# Wall = 2
# Grass = 3
# ClassRoom = 4
# Gate = 5
# HiddenGate = 6
# Window = 7
# Door3 = 8
# Door5 = 9
# Door6 = 10
# Chest = 11

def findpa(now:cel,dest:cel,map:List[List[THUAI6.PlaceType]]) -> cel:
return cel(1,1)

def dist(x1:int,y1:int,x2:int,y2:int) ->float:
return math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2))

def toangle(nowx:int,nowy:int,tox:int,toy:int) ->float:
if toy >= nowy:
return math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))
else:
return -math.acos((tox-nowx)/dist(nowx,nowy,tox,toy))

def toangle_cel(now:cel,dest:cel) ->float:
if dest.y >= now.y:
return math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))
else:
return -math.acos((dest.x-now.x)/dist(now.x,now.y,dest.x,dest.y))

def findway_DFS(grid, start:cel, end:cel) -> List[cel]:
row, col = 50,50
visited = set()
path =[]
class anan:
angle:float
to:int#0,1,2,3,下右上左
def __init__(self,angel:float,to:int) -> None:
self.angle = angel
self.to = to
pass

def azhe(jjj:anan)->float:
return jjj.angle

def help(now:cel,path:List[cel])->List[cel]:
if now == end:
return path
if now in visited:
oo = []
return oo
visited.add(now)
angle = toangle_cel(now,end)
directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
chae = [anan(abs(angle),0),anan(abs(angle-pi/2),1),anan(abs(angle-pi),2),anan(abs(angle-pi*1.5),3)]
chae.sort(key = azhe)
for i in chae:
dx,dy = directions[i.to]
new_x, new_y = now.x + dx, now.y + dy
new =cel(new_x, new_y)
if (grid[new_x][new_y]).value in [1,3,7,8,9,10]:
path.append(new)
visited.remove(now)
return help(path[-1], path)
return help(start,path = path)


# additional function_tricker

# additional function_student

pi=3.1415926535
class Cel:
x:int
y:int
def __init__(self,x1:int,y1:int):
self.x=x1
self.y=y1

#计算距离
def distance(target:Cel,api:IStudentAPI,ai)->float:
selfinfo=api.GetSelfInfo()
return math.sqrt((target.x-selfinfo.x)**2+(target.y-selfinfo.y)**2)

movetime=50
#为避免没到格子中心卡墙角,用cel规划路径,用grid精确地走
def Goto(target:Cel,api:IStudentAPI,ai)->None:
selfinfo=api.GetSelfInfo()
#当前格子坐标
#if self.nowpath==None:
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)
nowpath=ai.BFSpath(selfinfo,cur,target,api)#规划路径
#print('self.nowpath')
#for k in nowpath:
# print(k.x,k.y)
while len(nowpath)!=0:#能否这样判断不空
first=nowpath[0]
x1=1000*first.x+500
y1=1000*first.y+500
#print('curgrid',selfx,selfy)
#print('first ',x1,y1)
if cur.x==first.x and cur.y==first.y:
a=nowpath.pop(0)
else:
#print('not the same')
#print('first',x1,y1)
#print('cur',cur.x,cur.y)
if x1==selfx and y1<selfy:api.MoveLeft(movetime)
elif x1==selfx and y1>selfy:api.MoveRight(movetime)
elif x1<selfx and y1==selfy:api.MoveUp(movetime)
elif x1>selfx and y1==selfy:api.MoveDown(movetime)
elif x1<selfx and y1<selfy:api.Move(movetime,-pi*3/4)
elif x1<selfx and y1>selfy:api.Move(movetime,pi*3/4)
elif x1>selfx and y1<selfy:api.Move(movetime,-pi/4)
elif x1>selfx and y1>selfy:api.Move(movetime,pi/4)
#api.PrintSelfInfo()
selfinfo1=api.GetSelfInfo()
selfx1=selfinfo1.x
selfy1=selfinfo1.y
#print('aftermove',selfx1,selfy1)
#cur1=gridtocell(selfinfo1.x,selfinfo1.y)
#print('info',cur1.x,cur1.y)
if(selfx==selfx1 and selfy==selfy1):
#print('not moved')
api.MoveRight(movetime)
# api.MoveRight(movetime)
selfinfo=api.GetSelfInfo()
#print('State ',selfinfo.playerState.name)
#api.PrintSelfInfo()
selfx=selfinfo.x
selfy=selfinfo.y
cur=gridtocell(selfx,selfy)

# additional function_student

class AI(IAI):
map = None


# tricker
allgates_tr=[]
allwindows_tr = []
alldoor3_tr = []
alldoor5_tr = []
alldoor6_tr = []
allclassrooms_tr = []
allboxes_tr = []
allhiddengates_tr = []

studentposition_previous_frame=None#precise_cel
studentposition_this_frame=None#precise_cel
my_previous_frame=None#precise_cel
my_this_frame=None#precise_cel

now_path=None#List[cel]
move_along_path=None#bool


def closest_chest(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allboxes_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxChestProgress:
dis = k
the = i
return the
def closest_classroom(self,x:int,y:int,api:ITrickerAPI) ->cel:
now = cel(x,y)
dis = 1000000000000
the:cel
for i in self.allclassrooms_tr:
k = dist(now.x,now.y,i.x,i.y)
jindu = api.GetChestProgress(i.x,i.y)
if k<dis and jindu < Constants.maxClassroomProgress:
dis = k
the = i
return the

def wall_exist_precise(self,now:precise_cel,dest:precise_cel)->bool:
k = (dest.y-now.y)/(dest.x-now.x)
# y = k(x-now.x)+now.y
long = dest.x-now.x
for i in range(0,long,801):
y1= k*i+now.y
ok = cel(now.x+i,y1)
if self.map[ok.x][ok.y].value in [2,4,5,6,11]:
return True
return False

def near_chest(self,now:cel,api)->bool:
eight = [cel(now.x,now.y+1),cel(now.x,now.y-1),cel(now.x+1,now.y),cel(now.x-1,now.y),cel(now.x+1,now.y+1),cel(now.x-1,now.y-1),cel(now.x+1,now.y-1),cel(now.x-1,now.y+1)]
for i in eight:
jindu = api.GetChestProgress(i.x,i.y)
if self.map[i.x][i.y].name == 'Chest' and jindu < Constants.maxChestProgress:
return True
return False
# student

allgates=[]
allwindows = []
alldoors3 = []
alldoors5 = []
alldoors6 = []
allclassrooms = []
allboxes = []
allhiddengates = []

last_cel:Cel
cur_cel:Cel
#movetime=10#移动时间是多少?
#nowpath:deque[Cel]#存BFS得出的路径直到路径走�??
#move_along_path=0#直到走完路径,避免每帧调用一�??

def Todestin(self,api:IStudentAPI):
return

def Iscanreach(self,point:Cel,target:Cel)->bool:#判断两个点能否直接到
if(target.x<0 or target.x>50
or target.y<0 or target.y>50
or self.map[target.x][target.y].name=='Wall'
or (target.x==point.x and target.y==point.y)):#或超出地图、墙壁、与初始点重�??
return False
else:#上下左右�??
if(abs(point.x-target.x)+abs(point.y-target.y)==1):
return True
else:#斜对角线是门的话先不�??
name1=self.map[target.x][target.y].name
if(name1=='Door3' or name1=='Door5' or name1=='Door6'):
return False
else:
name2=self.map[target.x][point.y].name
name3=self.map[point.x][target.y].name
if name2=='Wall' or name3=='Wall':
return False
else:
return True
#对角线的两侧有墙壁的话也不行�??45度的时候走不过�??
#隐藏门和大校门?
def getSurroundCell(self,info:THUAI6.Student,point:Cel)->deque[Cel]:#找到该点周围8个点中能到的
surroundCell=[]#存能到的
curprop=info.prop
global next
for xi in range(point.x-1,point.x+2):
for yj in range(point.y-1,point.y+2):
other=Cel(xi,yj)
if(self.Iscanreach(point,other)):
sname=self.map[other.x][other.y].name
if(sname=='Door3'):#是门的话,判断有无对应钥匙?
if 1 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door5'):
if 2 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Door6'):
if 3 in curprop:
next=Cel(2*other.x-point.x,2*other.y-point.y)
elif(sname=='Window'):#是窗的话爬出�??
next=Cel(2*other.x-point.x,2*other.y-point.y)
else:
next=other
surroundCell.append(next)
return surroundCell
#判断坐标是否在list里,searched用到,也是数字相同但不同对象
def InList(self,point:Cel,llist:List)->bool:
for k in llist:
if point.x==k.x and point.y==k.y:
return True
return False
#坐标是否在字典的key里,每一次初始化类的对象,尽管数字相同但还是不同对象,可以重�??=?还可以?(后面简化一�??
def InDic(self,point:Cel,DDix:dict)->bool:
for k in DDix.keys():
if point.x==k.x and point.y==k.y:
return True
return False

#广度搜索找路径,如果
#路径不存在的情况�??
def BFSpath(self,info:THUAI6.Student,point:Cel,target:Cel,api:IStudentAPI)->List[Cel]:
#self_info=api.GetSelfInfo(self)
searched=[]#已经搜过的点
q=deque()
q.append(point)#初始点加�??
#定义搜索过的点的父节�??
parents=dict()
path=[target]

while q:
cur_=q.popleft()
#如果点没有被搜过
if not self.InList(cur_,searched):
#api.Print('not serached'+'cur_ '+str(cur_.x)+' '+str(cur_.y))
if(cur_.x !=target.x or cur_.y!=target.y):
#print('!=here')
sur=self.getSurroundCell(info,cur_)
for k in sur:
if not self.InList(k,searched):
q.append(k)
if not self.InDic(k,parents):
parents[k]=cur_
searched.append(cur_)
else:
#print('cur_=target')
key=Cel(target.x,target.y)
while key.x!=point.x or key.y!=point.y:
for k in parents:
if k.x==key.x and k.y==key.y:
father=parents[k]
path.append(father)
key=father
#往回找到路径后,将列表反转
path.reverse()
break
return path

#�?7间教室学�?
def Study(self,api:IStudentAPI)->None:
leng=len(self.allclassrooms)
ifdone=np.zeros((leng,1),dtype=bool)
class_count=0#已经学的教室的间�?
#找到距离self最近的教室并前往,途中捡道�?
while class_count<7:
my_filter=filter(lambda x:ifdone[self.allclassrooms.index(x)]==0,self.allclassrooms)#已经学过的教室就不要去了
result=list(my_filter)
dis_to_class=[]
for k in result:
dis=distance(k,api,self)
dis_to_class.append(dis)
num=dis_to_class.index(min(dis_to_class))#result中距离最近的教室的编�?
which_class=result[num]
x1=which_class.x
y1=which_class.y
#print('nearest ',x1,y1)
#在classroom列表中找回这个点的位置,并在ifdone中修改标�?
index_of_class=next((i for i,xx in enumerate(self.allclassrooms) if xx.x==x1 and xx.y==y1),None)
ifdone[index_of_class]=1

Goto(which_class,api,self)
api.StartLearning()#开始学�?

class_count=class_count+1



# function

def __init__(self, pID: int):
self.__playerID = pID

def StudentPlay(self, api: IStudentAPI) -> None:
# 鍏叡鎿嶄綔
if self.map==None:
self.map=api.GetFullMap()
xi=0
yj=0
for i in self.map:
yj=0
for j in i:
if j.name=='ClassRoom':
self.allclassrooms.append(Cel(xi,yj))
if j.name=='Gate':
self.allgates.append(Cel(xi,yj))
if j.name=='HiddenGate':
self.allhiddengates.append(Cel(xi,yj))
if j.name=='Window':#��һ���������ĺ�������
self.allwindows.append(Cel(xi,yj))
if j.name=='Door3':
self.alldoors3.append(Cel(xi,yj))
if j.name=='Door5':
self.alldoors5.append(Cel(xi,yj))
if j.name=='Door6':
self.alldoors6.append(Cel(xi,yj))
if j.name=='Chest':
self.allboxes.append(Cel(xi,yj))
yj=yj+1
xi=xi+1
print(self.map)


if self.__playerID == 0:
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
#api.StartLearning()
#api.PrintSelfInfo()
#print('end')
#self.Study(api)
elif self.__playerID == 1:
# 鐜╁�??1鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 2:
# 鐜╁�??2鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
elif self.__playerID == 3:
# 鐜╁�??3鎵ц鎿嶄�??
selfinfo=api.GetSelfInfo()#获取自身信息
Props=api.GetProps()#获取场上所有可见道�?
students=api.GetStudents()#获取其他所有学生的信息
api.PrintSelfInfo()
box1=self.allboxes[0]
Goto(box1,api,self)
return
# 鍙互鍐欐垚if self.__playerID<2涔嬬被鐨勫啓娉�
# 鍏叡鎿嶄綔
return

def TrickerPlay(self, api: ITrickerAPI) -> None:
#api.EndAllAction()

if self.map is None:
self.map = api.GetFullMap()
yj = 0
xi = 0
for i in self.map:
yj = 0
for j in i:
if j.name == 'ClassRoom':
self.allclassrooms_tr.append(cel(xi,yj))
elif j.name == 'Gate':
self.allgates_tr.append(cel(xi,yj))
elif j.name == 'HiddenGate':
self.allhiddengates_tr.append(cel(xi,yj))
elif j.name == 'Window':
self.allwindows_tr.append(cel(xi,yj))
elif j.name == 'Door3':
self.alldoor3_tr.append(cel(xi,yj))
elif j.name == 'Door5':
self.alldoor5_tr.append(cel(xi,yj))
elif j.name == 'Door6':
self.alldoor6_tr.append(cel(xi,yj))
elif j.name == 'Chest':
self.allboxes_tr.append(cel(xi,yj))
yj = yj + 1
xi = xi + 1

if self.my_previous_frame is None:
self.my_previous_frame = precise_cel(0,0)
selfInfo = api.GetSelfInfo()
self.my_this_frame = precise_cel(selfInfo.x,selfInfo.y)


if selfInfo.trickerType.name == 'ANoisyPerson':
student_see = api.GetStudents()
now = cel(selfInfo.x,selfInfo.y,1)
dest= cel(0,0)
this_dest:cel
if self.near_chest(now,api):
api.StartOpenChest()
if selfInfo.playerState.name == 'Idle':
if len(student_see) == 0:
self.move_along_path = True
dest = cel(0,0)
if selfInfo.trickDesire == 0:
#找教室
dest = self.closest_classroom(now.x,now.y)
else:
dis = float(ANoisyPerson.alertnessRadius)/selfInfo.trickDesire
a=1
else:
self.move_along_path = False
closestudent:THUAI6.Student
closestudent = None
cloest = 1000000000000
attacklong = Constants.basicAttackShortRange
for i in student_see:
dis = dist(i.x,i.y,selfInfo.x,selfInfo.y)
if dis < cloest :
cloest = dis
if i.playerState.name != 'Addicted':
closestudent = i
if closestudent is not None:
dest = cel(closestudent.x,closestudent.y,1)
else:
dest = self.closest_chest(now.x,now.y,api)
#self.move_along_path = True
if closestudent is not None:
if closestudent.studentType.name == 'Athlete':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Teacher':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'StraightAStudent':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
elif closestudent.studentType.name == 'Sunshine':
if cloest > StraightAStudent.viewRange:
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
#api.Attack()
else:
a=1#if selfInfo.playerState =
else:
if cloest <= attacklong:
#if selfInfo.timeUntilSkillAvailable[1] == 0:
#api.UseSkill(1)
if closestudent.playerState.name != 'Addicted':
attckangle = toangle(now.gridx,now.gridy,dest.gridx,dest.gridy)
api.Attack(attckangle)
if selfInfo.timeUntilSkillAvailable[0] == 0:
api.UseSkill(0)
else:
a=1#if selfInfo.playerState =
# if self.now_path is None and self.move_along_path == True:
# self.now_path = findway_DFS(self.map,now,dest)
# if self.move_along_path == True:
# dest = self.now_path[1]
this_dest = dest
angle = toangle(selfInfo.x,selfInfo.y,this_dest.gridx,this_dest.gridy)
if self.my_previous_frame.x == self.my_this_frame.x and self.my_previous_frame.y == self.my_this_frame.y:
if selfInfo.playerState.name == 'Idle':
api.MoveUp(10)
return
self.my_previous_frame = precise_cel(selfInfo.x,selfInfo.y)
if selfInfo.playerState.name == 'Idle':
api.Move(60,angle)
# hide in grass
# attack
# trick around
# find chest
# find classroom
elif selfInfo.trickerType.name == 'Idol':
a=1
elif selfInfo.trickerType.name == 'Assassin':
a=1

return

# playerID=4, GUID=678, x=21500, y=25500
# speed=3960, view range=15600, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, 0.0, -1.0]
# state=Idle, bullet=CommonAttackOfTricker, prop=NullPropType, NullPropType, NullPropType,
# type=Assassin, trick desire=2.4405367634838275, class volume=0.0
# buff=

# playerID=2, GUID=694, x=12500, y=26500
# speed=2880, view range=9000, place=Land, radius=400
# score=0, facing direction=0.0, skill time=[0.0, -1.0, -1.0]
# state=Idle, bullet=NullBulletType, prop=NullPropType, NullPropType, NullPropType,
# type=StraightAStudent, determination=3300000, addiction=0, danger alert=0.0
# learning speed=135, encourage speed=100, encourage progress=0, rouse progress=0
# buff=

+ 977
- 0
players/一会吃萤火虫/player1.cpp View File

@@ -0,0 +1,977 @@
#include <vector>
#include <list>
#include <math.h>
#include <string>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

constexpr int deltaTimems = 50;
constexpr int LastTrickerNum = 10;
#define deltaTime 0.05
#define pi 3.1415926

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
};
extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Klee;

/*
* 全局常量:
*
* 全局变量:
*
* Debug相关
* 寻路相关
* 游戏相关
*
* 学生变量:
* 通信相关
* 状态相关
* 游戏相关
*
* StraightAStudent变量:
* 冥想相关
* Athlete变量:
*
* Teacher变量:
*
* Sunshine变量:
*
*
* 捣蛋鬼变量:
*
*
* Assas变量:
*
* 工具类
* A*类
*
*/
struct Node {
int x, y;
int F, G, H;
Node* parent;
Node(int _x, int _y):x(_x), y(_y), F(0), G(0), H(0), parent(NULL) {}
}*node[50][50];
const std::list<Node*> emptylist;
const int EscapeDist = 16000;
std::list<Node*> PathToGo, PathGone;
bool isFirstFrame = true;
int PlayerId;
int Gridx, Gridy;
int Cellx, Celly;
std::vector<std::vector<THUAI6::PlaceType>> Map;
int map[50][50];//0为无阻碍,1为半阻碍,2为完全阻碍, 3为临时避障
struct ClassRoomInfo {
int x, y;
bool finished;
int occupied;//为4说明无学生占用,为0-3说明相应编号学生正在占用
}Classroom[100];
int ClassroomCount, ClassroomFinished;
struct ChestInfo {
int x, y;
bool opened;
int occupied;
}Chest[80];
int ChestCount;
struct GateInfo {
int x, y;
bool opening;
bool open;
}Gate[20];
int GateCount;
struct HiddenGateInfo {
int x, y;
bool refreshed;
bool open;
}HiddenGate[30];
int HiddenGateCount;
struct GrassInfo {
int x, y, occupied;
}Grass[200];
int GrassCount;
double faceDir = 0;
bool map1 = false, map2 = false;
std::pair<int, int> LastTarget;

std::pair<int, std::string> msgrcv;
std::string msg;//信息结构:'准备前往*号教室''1/0完成了作业''*号教室作业已完成''需要被营救'"捣蛋鬼x坐标""捣蛋鬼y坐标"
std::shared_ptr<const THUAI6::Student> studentinfo;
THUAI6::Tricker Trickers,LastTrickers[LastTrickerNum];
bool TrickerisInSight;
bool CanGetTrickerInfo;
enum class StudentState {
MovingForClassroom, Learning, MovingForGrass, MovingToAttck, MovingForProp, MovingToRescue, MovingToGraduate, WaitToGraduate
}studentstate;
int CurrentClassroomToGo;
int CurrentGateToGo;
int CurrentStudentToRescue;
int CurrentGrassToGo;
bool ShouldChangeClassroomToGo;
float Courage = 1.0;
int TrickerStuckTime;
bool rousing = false;
int framecount;

int MeditationProgress;

double ChargeTimeLeft;

std::shared_ptr<const THUAI6::Tricker> trickerinfo;
THUAI6::Student Students[4];
bool StudentisInSight[4];
enum class TrickerState {
MovingToPatrol, MovingToPursue, MovingToSearch, MovingForProp
}trickerstate;
struct _PatrolNode {
int x, y;
};
std::vector<_PatrolNode> PatrolNode;
int CurrentPatrolNodeToGo;
int CurrentStudentToPursue;
int StuckTime;
int WaitTrickerTime;
bool bgmuseful;


class Tools {
public:
double max(double a, double b) {
return a > b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
double Dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int ToInt(std::string s) {
int x = 0;
for(int i = 0;i < 5;i++, x *= 10)
x += s[i] - '0';
return x / 10;
}
std::string ToString(int x) {
std::string s = "*****";
for(int i = 0;i < 5;i++, x /= 10)
s[4 - i] = x % 10 + '0';
return s;
}
double StuDistValSet(double Dist) {
if(Dist < 7500)
return Dist;
return (Dist - 7500) * 2 + 7500;
}
double TriDistValSet(double Dist) {
int dist1 = 8500, dist2 = 10500;
if(Dist < dist1)
return Dist * 6;
if(Dist >= dist1 && Dist <= dist2)
return (Dist - dist1) * 3 + dist1 * 6;
return (Dist - dist2) + dist1 * 4 + (dist2 - dist1) * 2;
}
}T;
class A_Star {
public:
void init() {
openlist.clear();
closelist.clear();
}
std::list<Node*> GetPath(std::vector<int> st, std::vector<int> ed, bool Reach) {
if(st == ed) {
std::list<Node*> simplelist;
simplelist.push_back(new Node(st[0], st[1]));
return simplelist;
}
openlist.push_back(new Node(st[0], st[1]));
while(!openlist.empty()) {
Node* CurrentUpdateNode = GetLeastF();
closelist.push_back(CurrentUpdateNode);
UpdateFValue(CurrentUpdateNode, ed);
Node* CurPathNode;
if(!Reach) {
CurPathNode = GetDestSurroundNode(ed);
if(CurPathNode) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
} else {
CurPathNode = isInList(openlist, ed[0], ed[1]);
if(CurPathNode != NULL) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
}
openlist.remove(CurrentUpdateNode);
}
return emptylist;
}
private:
void UpdateFValue(Node* CurNode, std::vector<int> ed) {
std::list<std::vector<int>> UpdateList = GetSurroundNode(CurNode);
for(auto Curnum = UpdateList.begin();Curnum != UpdateList.end();Curnum++) {
int i = (*Curnum)[0], j = (*Curnum)[1];
if(isInList(openlist, i, j) == NULL) {
Node* UpdateNode = new Node(i, j);
UpdateNode->parent = CurNode;
if(map[i][j] == 1) {
if(PlayerId <= 3 && studentType[PlayerId] == THUAI6::StudentType::StraightAStudent) {
if(MeditationProgress + CurNode->G / 28.8 * 40000 > 300000)
UpdateNode->G = CurNode->G + 1;
else
UpdateNode->G = CurNode->G + 100;
} else
UpdateNode->G = CurNode->G + 1 * (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
} else
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->H = (abs(ed[0] - i) + abs(ed[1] - j)) * 10;
UpdateNode->F = UpdateNode->G + UpdateNode->H;
openlist.push_back(UpdateNode);
} else {
Node* UpdateNode = isInList(openlist, i, j);
int newG = (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
if(CurNode->G + newG <= UpdateNode->G) {
UpdateNode->parent = CurNode;
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->F = UpdateNode->G + UpdateNode->H;
}
}
}
}
std::list<std::vector<int>> GetSurroundNode(Node* CurNode) {
std::list<std::vector<int>> SurroundNodeList;
bool up = false, down = false, left = false, right = false;
if(CurNode->x > 0 && map[CurNode->x - 1][CurNode->y] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y}), up = true;
if(CurNode->x < 49 && map[CurNode->x + 1][CurNode->y] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y}), down = true;
if(CurNode->y > 0 && map[CurNode->x][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y - 1}), left = true;
if(CurNode->y < 49 && map[CurNode->x][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y + 1}), right = true;
if(up && left && map[CurNode->x - 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y - 1});
if(up && right && map[CurNode->x - 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y + 1});
if(down && left && map[CurNode->x + 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y - 1});
if(down && right && map[CurNode->x + 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y + 1});
return SurroundNodeList;
}
Node* isInList(std::list<Node*>& List, int x, int y) {
for(auto i = List.begin();i != List.end();i++)
if((*i)->x == x && (*i)->y == y)
return (*i);
return NULL;
}
Node* GetDestSurroundNode(std::vector<int> ed) {
Node* retNode;
retNode = isInList(openlist, ed[0] - 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0] + 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] - 1);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] + 1);
if(retNode) return retNode;
return NULL;
}
Node* GetLeastF() {
if(!openlist.empty()) {
Node* resPoint = openlist.front();
for(auto i = openlist.begin();i != openlist.end();i++)
if(resPoint->F > (*i)->F)
resPoint = *i;
return resPoint;
}
return NULL;
}
private:
std::list<Node*> openlist;
std::list<Node*> closelist;
}AStar;
int SearchBestClassroom(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < ClassroomCount;i++) {
if(!Classroom[i].finished && Classroom[i].occupied == 4) {
double val = T.Dist(api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
}
return nearestId;
}
int SearchBestGate(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GateCount;i++) {
double val = T.Dist(api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int StudentSearchBestGrass(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
/*api.Print(fmt::format("Grid{},{}", Gridx, Gridy));
api.Print(fmt::format("Tri{},{}", Trickers.x, Trickers.y));*/
for(int i = 0;i < GrassCount;i++) {
double val = T.StuDistValSet(T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy));
/*api.Print(fmt::format("Grass{},{}:val{}", Grass[i].x, Grass[i].y, val));
api.Print(fmt::format("Dist(stu,Grass)={}", T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy)));
api.Print(fmt::format("Dist(tri,Grass)={}", T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y))));*/
if(val < valmin && !Grass[i].occupied) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int TrickerSearchPossibleGrass(IAPI& api, int DistMax) {
double distmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GrassCount;i++) {
double dist = T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy);
if(dist < distmin) {
distmin = dist;
nearestId = i;
}
}
return nearestId;
}
void FindPathTo(std::pair<int, int> Target, bool CanReach, bool ForceToFind = false) {
if((PathToGo.empty() || (!PathToGo.empty() && LastTarget != Target)) || ForceToFind) {
LastTarget = Target;
AStar.init();
PathToGo = AStar.GetPath({Cellx,Celly}, {Target.first,Target.second}, CanReach);
}
}
inline void StudentStart(IAPI& api) {
studentstate = StudentState::MovingForClassroom;
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
inline void TrickerStart(IAPI& api) {
CurrentPatrolNodeToGo = 0;
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
CurrentStudentToPursue = -1;
}
inline void Start(IAPI& api) {
isFirstFrame = false;
Map = api.GetFullMap();
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(Map[i][j] == THUAI6::PlaceType::Window)
map[i][j] = 1;
if(Map[i][j] == THUAI6::PlaceType::Wall || Map[i][j] == THUAI6::PlaceType::Gate
|| Map[i][j] == THUAI6::PlaceType::Chest || Map[i][j] == THUAI6::PlaceType::ClassRoom
|| Map[i][j] == THUAI6::PlaceType::HiddenGate)
map[i][j] = 2;
if(Map[i][j] == THUAI6::PlaceType::ClassRoom)
Classroom[ClassroomCount].x = i, Classroom[ClassroomCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Chest)
Chest[ChestCount].x = i, Chest[ChestCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Gate)
Gate[GateCount].x = i, Gate[GateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::HiddenGate)
HiddenGate[HiddenGateCount].x = i, HiddenGate[HiddenGateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Grass) {
Grass[GrassCount].x = i;
Grass[GrassCount++].y = j;
//api.Print(fmt::format("Grass[{}]:{},{}", GrassCount - 1, Grass[GrassCount - 1].x, Grass[GrassCount - 1].y));
}
}
if(Gate[0].y > 25) {
PatrolNode = {{18,18},{31,31},{42,31},{42,18},{31,7},{31,18},{18,31},{18,42},{7,31},{7,18}};
map2 = true;
} else {
PatrolNode = {{23,13},{18,7},{8,9},{8,33},{14,36},{23,29},{31,35},{42,41},{40,24}};
map1 = true;
}
if(PlayerId <= 3) {
StudentStart(api);
} else
TrickerStart(api);
}
void UpdateStudentInfo(IStudentAPI& api) {
msg = "*0*0";
if(studentinfo->x == Gridx && studentinfo->y == Gridy && studentinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
switch(studentType[PlayerId]) {
case THUAI6::StudentType::StraightAStudent:
if((int)studentinfo->playerState >= 1 && (int)studentinfo->playerState <= 10 && (int)studentinfo->playerState != 2)
MeditationProgress += 40 * deltaTimems;
else
MeditationProgress = 0;
break;
}
Gridx = studentinfo->x;
Gridy = studentinfo->y;
Cellx = api.GridToCell(studentinfo->x);
Celly = api.GridToCell(studentinfo->y);
for(int i = 0;i < 4;i++)
Students[i] = *(api.GetStudents()[i]);
auto TrickersInSight = api.GetTrickers();
TrickerisInSight = false;
CanGetTrickerInfo = false;
for(int i= LastTrickerNum - 1;i >= 1;i--)
LastTrickers[i] = LastTrickers[i-1];
LastTrickers[0] = Trickers;
if(!TrickersInSight.empty()) {
//api.Print("TrickerisInSight!");
TrickerisInSight = true;
CanGetTrickerInfo = true;
Trickers = *TrickersInSight[0];
} else {
//api.Print("TrickerisnotInSight!");
//if(Trickers.x != -1)
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(Trickers.x != -1 && api.HaveView(api.GridToCell(Trickers.x), api.GridToCell(Trickers.y))) {
Trickers.x = -1;
//api.Print("TrickerisnotInSightremove!");
}
}
//api.Print(fmt::format("TrickerStuckTime {}", TrickerStuckTime));
}
void UpdateTrickerInfo(ITrickerAPI& api) {
if(trickerinfo->x == Gridx && trickerinfo->y == Gridy && trickerinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
Gridx = trickerinfo->x;
Gridy = trickerinfo->y;
Cellx = api.GridToCell(trickerinfo->x);
Celly = api.GridToCell(trickerinfo->y);
auto StudentsInSight = api.GetStudents();
for(int i = 0;i < 4;i++)
StudentisInSight[i] = false;
for(int i = 0;i < StudentsInSight.size();i++) {
StudentisInSight[StudentsInSight[i]->playerID] = true;
Students[StudentsInSight[i]->playerID] = *StudentsInSight[i];
}
}
void UpdateMapInfo(IAPI& api) {
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(map[i][j] == 3)
map[i][j] = 0;
if(map[i][j] % 5 == 3)
map[i][j] -= 5;
}
}
void MoveAlongPath(IAPI& api) {
if(!PathToGo.empty() && ((!PathGone.empty() && PathToGo.front() != PathGone.front()) || PathGone.empty())) {
bool Reach = false;
if(PathToGo.size() == 1) {
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y)) < 100) {
Reach = true;
}
} else {
auto it = PathToGo.begin();it++;
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y))
+ T.Dist(Gridx, Gridy, api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) <
T.Dist(api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y),
api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) * 1.15) {
Reach = true;
}
}
if(Reach) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
if(!PathToGo.empty()) {
if(Map[PathToGo.front()->x][PathToGo.front()->y] == THUAI6::PlaceType::Window) {
if(api.SkipWindow().get()) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
} else {
faceDir = atan2(api.CellToGrid(PathToGo.front()->y) - Gridy, api.CellToGrid(PathToGo.front()->x) - Gridx);
api.Move(500, faceDir);
}
} else {
if(PlayerId <= 3) {
switch(studentstate) {
case StudentState::MovingForClassroom:
if(studentType[PlayerId] == THUAI6::StudentType::StraightAStudent && studentinfo->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
studentstate = StudentState::Learning;
break;
case StudentState::MovingForGrass:
break;
case StudentState::MovingToGraduate:
api.StartOpenGate();
studentstate = StudentState::WaitToGraduate;
break;
case StudentState::WaitToGraduate:
break;
}
} else {
int GrassId;
switch(trickerstate) {
case TrickerState::MovingToPatrol:
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].determination <= 0) {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
} else {
trickerstate = TrickerState::MovingToSearch;
GrassId = TrickerSearchPossibleGrass(api, 2000);
if(GrassId != -1) {
FindPathTo({Grass[GrassId].x,Grass[GrassId].y}, true);
}
}
break;
case TrickerState::MovingToSearch:
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
break;
}
}
}
}
}
bool OnlyTeacherLeft(ITrickerAPI& api) {
if(framecount > 6000)
return true;
for(int i = 0;i < 4;i++) {
if(Students[i].studentType != THUAI6::StudentType::Teacher && Students[i].determination > 0)
return false;
}
return true;
}
int FindStudentInSight(ITrickerAPI& api) {
auto StudentsInSight = api.GetStudents();
for(auto i = 0;i < StudentsInSight.size();i++) {
if(OnlyTeacherLeft(api)) {
if(Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
} else {
if(Students[StudentsInSight[i]->playerID].studentType != THUAI6::StudentType::Teacher && Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
}
}
return -1;
}
void ReadMessage(IStudentAPI& api) {
for(int i = 0;i < 10;i++)
Classroom[i].occupied = 4;
if(map1)
Classroom[5].occupied = 5;
ShouldChangeClassroomToGo = false;
while(api.HaveMessage()) {
msgrcv = api.GetMessage();
Classroom[msgrcv.second[0] - '0'].occupied = msgrcv.first;
if(msgrcv.second[0] - '0' == CurrentClassroomToGo) ShouldChangeClassroomToGo = true;
if(msgrcv.second[1] == '1') Classroom[msgrcv.second[2] - '0'].finished = true, ClassroomFinished++;
if(msgrcv.second[3] == '1' && studentstate != StudentState::MovingToRescue) {
int dist = 1000000, id = 0;
for(int i = 0;i < 4;i++) {
//api.Print(fmt::format("stu[{}].x = {} stu[{}].y = {}", i, Students[i].x, i, Students[i].y));
if(msgrcv.first != i) {
if(dist > T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y)) {
dist = T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y);
id = i;
}
}
}
//api.Print(fmt::format("id{},dist{}", id, dist));
if(id == PlayerId) {
studentstate = StudentState::MovingToRescue;
CurrentStudentToRescue = msgrcv.first;
}
}
if(msgrcv.second[4] != '*' && !TrickerisInSight) {
Trickers.x = T.ToInt(msgrcv.second.substr(4, 5));
Trickers.y = T.ToInt(msgrcv.second.substr(9, 5));
CanGetTrickerInfo = true;
}
}
if(ShouldChangeClassroomToGo) {
CurrentClassroomToGo = SearchBestClassroom(api);
if(studentstate == StudentState::MovingForClassroom)
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
}
void SendMessage(IStudentAPI& api) {
if(studentstate == StudentState::MovingForClassroom || studentstate == StudentState::Learning)
msg[0] = CurrentClassroomToGo + '0';
if(studentinfo->playerState == THUAI6::PlayerState::Addicted &&
!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))
msg[3] = '1';
if(TrickerisInSight)
msg = msg + T.ToString(Trickers.x) + T.ToString(Trickers.y);
else
msg = msg + "**********";
for(int i = 0;i < 4;i++)
if(PlayerId != i)
api.SendTextMessage(i, msg);
}
bool CheckTrickerStuck(){
int avex = 0,avey = 0;
for(int i = 0;i < LastTrickerNum;i++){
avex += LastTrickers[i].x;
avey += LastTrickers[i].y;
}
avex /= LastTrickerNum;
avey /= LastTrickerNum;
return (T.Dist(avex,avey,Trickers.x,Trickers.y) < 350);
}
void AI::play(IStudentAPI& api) {
studentinfo = api.GetSelfInfo();
//api.Print(fmt::format("studentinfo->dangerAlert {}", studentinfo->dangerAlert));
UpdateMapInfo(api);
UpdateStudentInfo(api);
if(studentstate != StudentState::Learning && !rousing) {
api.EndAllAction();
//api.Print("endallaction");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
}
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
ReadMessage(api);
if(CheckTrickerStuck() && CanGetTrickerInfo) {
TrickerStuckTime += 50;
} else
TrickerStuckTime = 0;
if(studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && abs(T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) - 15000 / studentinfo->dangerAlert) > 100)
Trickers.x = -1;
if(!CanGetTrickerInfo)
Trickers.x = -1;
//api.Print(fmt::format("Trickers{},{}", Trickers.x, Trickers.y));
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(StuckTime >= 200) {
if(PathToGo.size() >= 2) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
StuckTime = 0;
}
if(studentstate != StudentState::MovingForGrass) {
if((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage))) {
rousing = false;
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
Grass[CurrentGrassToGo].occupied = true;
studentstate = StudentState::MovingForGrass;
//api.Print(fmt::format("grassfind{},{}", Grass[TargetGrass].x, Grass[TargetGrass].y));
}
auto bullets = api.GetBullets();
bool FlyingKnifeInSight = false;
for(auto i = 0;i < bullets.size();i++)
if(bullets[i]->bulletType == THUAI6::BulletType::FlyingKnife){
FlyingKnifeInSight = true;
//api.Print(fmt::format("FlyingKnifeInSight!!!"));
}
if(FlyingKnifeInSight){
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
Grass[CurrentGrassToGo].occupied = true;
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
studentstate = StudentState::MovingForGrass;
}
}
if(ClassroomFinished >= 7 && studentstate != StudentState::WaitToGraduate && studentstate != StudentState::MovingToGraduate && studentstate != StudentState::MovingForGrass) {
studentstate = StudentState::MovingToGraduate;
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
}
//api.Print(fmt::format("Courage{}", Courage));
//api.Print(fmt::format("EscapeDist / Courage{}", EscapeDist / Courage));
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01 && studentinfo->determination < 3200000) {
api.UseSkill(1);
}
switch(studentstate) {
case StudentState::MovingForClassroom:
//api.Print(fmt::format("state:MovingForClassroom"));
//api.Print(fmt::format("classroom{}:{},{}", CurrentClassroomToGo, Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y));
//CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y}, false);
break;
case StudentState::Learning:
//api.Print(fmt::format("state:Learning"));
//api.Print(fmt::format("classroom[{}] process = {}", CurrentClassroomToGo, api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y)));

if(api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y) == 10000000) {
//api.Print("ClassroomFinished");
studentstate = StudentState::MovingForClassroom;
Classroom[CurrentClassroomToGo].finished = true;
ClassroomFinished++;
msg[1] = '1';
msg[2] = (char)(CurrentClassroomToGo + '0');
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
} else
api.StartLearning();
break;
case StudentState::MovingForGrass:
Courage += 0.002;
//api.Print(fmt::format("state:MovingForGrass"));
if(!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))) {
WaitTrickerTime += 50;
if(Trickers.trickerType == THUAI6::TrickerType::ANoisyPerson){
if(WaitTrickerTime >= 10000) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}else{
if(WaitTrickerTime >= 2500) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}
} else {
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[2] < 0.01) {
api.UseSkill(2);
}
if(PathToGo.empty()) {
//api.Print("gototricker");
if(Map[Cellx - 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx - 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx - 1, Celly}, true);
if(Map[Cellx + 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx + 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx + 1, Celly}, true);
if(Map[Cellx][Celly - 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly - 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly - 1}, true);
if(Map[Cellx][Celly + 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly + 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly + 1}, true);
}
/*int TargetGrass;
TargetGrass = StudentSearchBestGrass(api);
FindPathTo({Grass[TargetGrass].x, Grass[TargetGrass].y}, true);*/
}
break;
case StudentState::MovingToRescue:
//api.Print(fmt::format("state:MovingToRescue"));
//api.Print(fmt::format("rescuestudent{}:{},{}", CurrentStudentToRescue, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
rousing = false;
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToRescue].x),api.GridToCell(Students[CurrentStudentToRescue].y)}, false);
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y) < 1200) {
api.StartRouseMate(CurrentStudentToRescue);
PathToGo.clear();
rousing = true;
//api.Print("rousing!");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
//api.Print("rouseover!");
rousing = false;
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01) {
api.UseSkill(1);
}
}
}
break;
case StudentState::MovingToGraduate:
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
break;
case StudentState::WaitToGraduate:
api.StartOpenGate();
if(api.GetGateProgress(Gate[CurrentGateToGo].x, Gate[CurrentGateToGo].y) == 18000) {
api.Graduate();
}
break;
default:
break;
}
if(TrickerStuckTime >= 200) {
Courage += 0.003;
}else{
if(CanGetTrickerInfo)
Courage = 1;
}
if(Courage > 1)
Courage -= 0.0015;
if(Courage > 2.3)
Courage = 2.3;
if(Courage < 1)
Courage = 1;
//api.Print(fmt::format("Courage = {}", Courage));
//api.Print(fmt::format("CriticalDist = {}", EscapeDist / Courage));
//api.Print(fmt::format("BGM = {}", studentinfo->dangerAlert));
//api.Print(fmt::format("BGM Dist = {}", 15000 / studentinfo->dangerAlert));
//for(auto i = PathToGo.begin();i != PathToGo.end();i++)
// api.Print(fmt::format("{} {}", (*i)->x, (*i)->y));
MoveAlongPath(api);
SendMessage(api);
}
void AI::play(ITrickerAPI& api) {
framecount++;
if(trickerType == THUAI6::TrickerType::ANoisyPerson) {
api.UseSkill(0);
goto end;
}
api.EndAllAction();
trickerinfo = api.GetSelfInfo();
UpdateMapInfo(api);
UpdateTrickerInfo(api);
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
int StudentsInSightId;
if(StuckTime >= 200) {
if(StuckTime >= 1000) {
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
} else {
if(trickerstate == TrickerState::MovingToSearch || trickerstate == TrickerState::MovingToPursue) {
if(api.Attack(faceDir).get())
Students[CurrentStudentToPursue].determination -= 1500000;
if(Students[CurrentStudentToPursue].determination <= 0) {
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
}
} else {
if(!PathToGo.empty()) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
}
}
}
switch(trickerstate) {
case TrickerState::MovingToPatrol:
StudentsInSightId = FindStudentInSight(api);
if(StudentsInSightId != -1) {
trickerstate = TrickerState::MovingToPursue;
CurrentStudentToPursue = StudentsInSightId;
} else {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
}
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].playerState == THUAI6::PlayerState::Addicted) {
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToPursue].x), api.GridToCell(Students[CurrentStudentToPursue].y)}, false);
if(StudentisInSight[CurrentStudentToPursue]) {
if(trickerinfo->timeUntilSkillAvailable[1] == 0) {
if(trickerType == THUAI6::TrickerType::Klee && T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.UseSkill(0);
}
if(api.HaveView(Students[CurrentStudentToPursue].y + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01))
if(trickerType == THUAI6::TrickerType::Assassin)
api.UseSkill(1);
}
switch(trickerinfo->bulletType) {
case THUAI6::BulletType::CommonAttackOfTricker:
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1500000;
}
break;
case THUAI6::BulletType::FlyingKnife:
api.Attack(atan2(
Students[CurrentStudentToPursue].y - Gridy + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x - Gridx + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
case THUAI6::BulletType::BombBomb:
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
}
}
break;
case TrickerState::MovingToSearch:
break;
}
MoveAlongPath(api);
end:;
}

+ 977
- 0
players/一会吃萤火虫/player2.cpp View File

@@ -0,0 +1,977 @@
#include <vector>
#include <list>
#include <math.h>
#include <string>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

constexpr int deltaTimems = 50;
constexpr int LastTrickerNum = 10;
#define deltaTime 0.05
#define pi 3.1415926

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
};
extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Klee;

/*
* 全局常量:
*
* 全局变量:
*
* Debug相关
* 寻路相关
* 游戏相关
*
* 学生变量:
* 通信相关
* 状态相关
* 游戏相关
*
* StraightAStudent变量:
* 冥想相关
* Athlete变量:
*
* Teacher变量:
*
* Sunshine变量:
*
*
* 捣蛋鬼变量:
*
*
* Assas变量:
*
* 工具类
* A*类
*
*/
struct Node {
int x, y;
int F, G, H;
Node* parent;
Node(int _x, int _y):x(_x), y(_y), F(0), G(0), H(0), parent(NULL) {}
}*node[50][50];
const std::list<Node*> emptylist;
const int EscapeDist = 16000;
std::list<Node*> PathToGo, PathGone;
bool isFirstFrame = true;
int PlayerId;
int Gridx, Gridy;
int Cellx, Celly;
std::vector<std::vector<THUAI6::PlaceType>> Map;
int map[50][50];//0为无阻碍,1为半阻碍,2为完全阻碍, 3为临时避障
struct ClassRoomInfo {
int x, y;
bool finished;
int occupied;//为4说明无学生占用,为0-3说明相应编号学生正在占用
}Classroom[100];
int ClassroomCount, ClassroomFinished;
struct ChestInfo {
int x, y;
bool opened;
int occupied;
}Chest[80];
int ChestCount;
struct GateInfo {
int x, y;
bool opening;
bool open;
}Gate[20];
int GateCount;
struct HiddenGateInfo {
int x, y;
bool refreshed;
bool open;
}HiddenGate[30];
int HiddenGateCount;
struct GrassInfo {
int x, y, occupied;
}Grass[200];
int GrassCount;
double faceDir = 0;
bool map1 = false, map2 = false;
std::pair<int, int> LastTarget;

std::pair<int, std::string> msgrcv;
std::string msg;//信息结构:'准备前往*号教室''1/0完成了作业''*号教室作业已完成''需要被营救'"捣蛋鬼x坐标""捣蛋鬼y坐标"
std::shared_ptr<const THUAI6::Student> studentinfo;
THUAI6::Tricker Trickers,LastTrickers[LastTrickerNum];
bool TrickerisInSight;
bool CanGetTrickerInfo;
enum class StudentState {
MovingForClassroom, Learning, MovingForGrass, MovingToAttck, MovingForProp, MovingToRescue, MovingToGraduate, WaitToGraduate
}studentstate;
int CurrentClassroomToGo;
int CurrentGateToGo;
int CurrentStudentToRescue;
int CurrentGrassToGo;
bool ShouldChangeClassroomToGo;
float Courage = 1.0;
int TrickerStuckTime;
bool rousing = false;
int framecount;

int MeditationProgress;

double ChargeTimeLeft;

std::shared_ptr<const THUAI6::Tricker> trickerinfo;
THUAI6::Student Students[4];
bool StudentisInSight[4];
enum class TrickerState {
MovingToPatrol, MovingToPursue, MovingToSearch, MovingForProp
}trickerstate;
struct _PatrolNode {
int x, y;
};
std::vector<_PatrolNode> PatrolNode;
int CurrentPatrolNodeToGo;
int CurrentStudentToPursue;
int StuckTime;
int WaitTrickerTime;
bool bgmuseful;


class Tools {
public:
double max(double a, double b) {
return a > b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
double Dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int ToInt(std::string s) {
int x = 0;
for(int i = 0;i < 5;i++, x *= 10)
x += s[i] - '0';
return x / 10;
}
std::string ToString(int x) {
std::string s = "*****";
for(int i = 0;i < 5;i++, x /= 10)
s[4 - i] = x % 10 + '0';
return s;
}
double StuDistValSet(double Dist) {
if(Dist < 7500)
return Dist;
return (Dist - 7500) * 2 + 7500;
}
double TriDistValSet(double Dist) {
int dist1 = 8500, dist2 = 10500;
if(Dist < dist1)
return Dist * 6;
if(Dist >= dist1 && Dist <= dist2)
return (Dist - dist1) * 3 + dist1 * 6;
return (Dist - dist2) + dist1 * 4 + (dist2 - dist1) * 2;
}
}T;
class A_Star {
public:
void init() {
openlist.clear();
closelist.clear();
}
std::list<Node*> GetPath(std::vector<int> st, std::vector<int> ed, bool Reach) {
if(st == ed) {
std::list<Node*> simplelist;
simplelist.push_back(new Node(st[0], st[1]));
return simplelist;
}
openlist.push_back(new Node(st[0], st[1]));
while(!openlist.empty()) {
Node* CurrentUpdateNode = GetLeastF();
closelist.push_back(CurrentUpdateNode);
UpdateFValue(CurrentUpdateNode, ed);
Node* CurPathNode;
if(!Reach) {
CurPathNode = GetDestSurroundNode(ed);
if(CurPathNode) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
} else {
CurPathNode = isInList(openlist, ed[0], ed[1]);
if(CurPathNode != NULL) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
}
openlist.remove(CurrentUpdateNode);
}
return emptylist;
}
private:
void UpdateFValue(Node* CurNode, std::vector<int> ed) {
std::list<std::vector<int>> UpdateList = GetSurroundNode(CurNode);
for(auto Curnum = UpdateList.begin();Curnum != UpdateList.end();Curnum++) {
int i = (*Curnum)[0], j = (*Curnum)[1];
if(isInList(openlist, i, j) == NULL) {
Node* UpdateNode = new Node(i, j);
UpdateNode->parent = CurNode;
if(map[i][j] == 1) {
if(PlayerId <= 3 && studentType[PlayerId] == THUAI6::StudentType::StraightAStudent) {
if(MeditationProgress + CurNode->G / 28.8 * 40000 > 300000)
UpdateNode->G = CurNode->G + 1;
else
UpdateNode->G = CurNode->G + 100;
} else
UpdateNode->G = CurNode->G + 1 * (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
} else
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->H = (abs(ed[0] - i) + abs(ed[1] - j)) * 10;
UpdateNode->F = UpdateNode->G + UpdateNode->H;
openlist.push_back(UpdateNode);
} else {
Node* UpdateNode = isInList(openlist, i, j);
int newG = (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
if(CurNode->G + newG <= UpdateNode->G) {
UpdateNode->parent = CurNode;
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->F = UpdateNode->G + UpdateNode->H;
}
}
}
}
std::list<std::vector<int>> GetSurroundNode(Node* CurNode) {
std::list<std::vector<int>> SurroundNodeList;
bool up = false, down = false, left = false, right = false;
if(CurNode->x > 0 && map[CurNode->x - 1][CurNode->y] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y}), up = true;
if(CurNode->x < 49 && map[CurNode->x + 1][CurNode->y] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y}), down = true;
if(CurNode->y > 0 && map[CurNode->x][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y - 1}), left = true;
if(CurNode->y < 49 && map[CurNode->x][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y + 1}), right = true;
if(up && left && map[CurNode->x - 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y - 1});
if(up && right && map[CurNode->x - 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y + 1});
if(down && left && map[CurNode->x + 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y - 1});
if(down && right && map[CurNode->x + 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y + 1});
return SurroundNodeList;
}
Node* isInList(std::list<Node*>& List, int x, int y) {
for(auto i = List.begin();i != List.end();i++)
if((*i)->x == x && (*i)->y == y)
return (*i);
return NULL;
}
Node* GetDestSurroundNode(std::vector<int> ed) {
Node* retNode;
retNode = isInList(openlist, ed[0] - 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0] + 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] - 1);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] + 1);
if(retNode) return retNode;
return NULL;
}
Node* GetLeastF() {
if(!openlist.empty()) {
Node* resPoint = openlist.front();
for(auto i = openlist.begin();i != openlist.end();i++)
if(resPoint->F > (*i)->F)
resPoint = *i;
return resPoint;
}
return NULL;
}
private:
std::list<Node*> openlist;
std::list<Node*> closelist;
}AStar;
int SearchBestClassroom(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < ClassroomCount;i++) {
if(!Classroom[i].finished && Classroom[i].occupied == 4) {
double val = T.Dist(api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
}
return nearestId;
}
int SearchBestGate(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GateCount;i++) {
double val = T.Dist(api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int StudentSearchBestGrass(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
/*api.Print(fmt::format("Grid{},{}", Gridx, Gridy));
api.Print(fmt::format("Tri{},{}", Trickers.x, Trickers.y));*/
for(int i = 0;i < GrassCount;i++) {
double val = T.StuDistValSet(T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy));
/*api.Print(fmt::format("Grass{},{}:val{}", Grass[i].x, Grass[i].y, val));
api.Print(fmt::format("Dist(stu,Grass)={}", T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy)));
api.Print(fmt::format("Dist(tri,Grass)={}", T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y))));*/
if(val < valmin && !Grass[i].occupied) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int TrickerSearchPossibleGrass(IAPI& api, int DistMax) {
double distmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GrassCount;i++) {
double dist = T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy);
if(dist < distmin) {
distmin = dist;
nearestId = i;
}
}
return nearestId;
}
void FindPathTo(std::pair<int, int> Target, bool CanReach, bool ForceToFind = false) {
if((PathToGo.empty() || (!PathToGo.empty() && LastTarget != Target)) || ForceToFind) {
LastTarget = Target;
AStar.init();
PathToGo = AStar.GetPath({Cellx,Celly}, {Target.first,Target.second}, CanReach);
}
}
inline void StudentStart(IAPI& api) {
studentstate = StudentState::MovingForClassroom;
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
inline void TrickerStart(IAPI& api) {
CurrentPatrolNodeToGo = 0;
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
CurrentStudentToPursue = -1;
}
inline void Start(IAPI& api) {
isFirstFrame = false;
Map = api.GetFullMap();
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(Map[i][j] == THUAI6::PlaceType::Window)
map[i][j] = 1;
if(Map[i][j] == THUAI6::PlaceType::Wall || Map[i][j] == THUAI6::PlaceType::Gate
|| Map[i][j] == THUAI6::PlaceType::Chest || Map[i][j] == THUAI6::PlaceType::ClassRoom
|| Map[i][j] == THUAI6::PlaceType::HiddenGate)
map[i][j] = 2;
if(Map[i][j] == THUAI6::PlaceType::ClassRoom)
Classroom[ClassroomCount].x = i, Classroom[ClassroomCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Chest)
Chest[ChestCount].x = i, Chest[ChestCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Gate)
Gate[GateCount].x = i, Gate[GateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::HiddenGate)
HiddenGate[HiddenGateCount].x = i, HiddenGate[HiddenGateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Grass) {
Grass[GrassCount].x = i;
Grass[GrassCount++].y = j;
//api.Print(fmt::format("Grass[{}]:{},{}", GrassCount - 1, Grass[GrassCount - 1].x, Grass[GrassCount - 1].y));
}
}
if(Gate[0].y > 25) {
PatrolNode = {{18,18},{31,31},{42,31},{42,18},{31,7},{31,18},{18,31},{18,42},{7,31},{7,18}};
map2 = true;
} else {
PatrolNode = {{23,13},{18,7},{8,9},{8,33},{14,36},{23,29},{31,35},{42,41},{40,24}};
map1 = true;
}
if(PlayerId <= 3) {
StudentStart(api);
} else
TrickerStart(api);
}
void UpdateStudentInfo(IStudentAPI& api) {
msg = "*0*0";
if(studentinfo->x == Gridx && studentinfo->y == Gridy && studentinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
switch(studentType[PlayerId]) {
case THUAI6::StudentType::StraightAStudent:
if((int)studentinfo->playerState >= 1 && (int)studentinfo->playerState <= 10 && (int)studentinfo->playerState != 2)
MeditationProgress += 40 * deltaTimems;
else
MeditationProgress = 0;
break;
}
Gridx = studentinfo->x;
Gridy = studentinfo->y;
Cellx = api.GridToCell(studentinfo->x);
Celly = api.GridToCell(studentinfo->y);
for(int i = 0;i < 4;i++)
Students[i] = *(api.GetStudents()[i]);
auto TrickersInSight = api.GetTrickers();
TrickerisInSight = false;
CanGetTrickerInfo = false;
for(int i= LastTrickerNum - 1;i >= 1;i--)
LastTrickers[i] = LastTrickers[i-1];
LastTrickers[0] = Trickers;
if(!TrickersInSight.empty()) {
//api.Print("TrickerisInSight!");
TrickerisInSight = true;
CanGetTrickerInfo = true;
Trickers = *TrickersInSight[0];
} else {
//api.Print("TrickerisnotInSight!");
//if(Trickers.x != -1)
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(Trickers.x != -1 && api.HaveView(api.GridToCell(Trickers.x), api.GridToCell(Trickers.y))) {
Trickers.x = -1;
//api.Print("TrickerisnotInSightremove!");
}
}
//api.Print(fmt::format("TrickerStuckTime {}", TrickerStuckTime));
}
void UpdateTrickerInfo(ITrickerAPI& api) {
if(trickerinfo->x == Gridx && trickerinfo->y == Gridy && trickerinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
Gridx = trickerinfo->x;
Gridy = trickerinfo->y;
Cellx = api.GridToCell(trickerinfo->x);
Celly = api.GridToCell(trickerinfo->y);
auto StudentsInSight = api.GetStudents();
for(int i = 0;i < 4;i++)
StudentisInSight[i] = false;
for(int i = 0;i < StudentsInSight.size();i++) {
StudentisInSight[StudentsInSight[i]->playerID] = true;
Students[StudentsInSight[i]->playerID] = *StudentsInSight[i];
}
}
void UpdateMapInfo(IAPI& api) {
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(map[i][j] == 3)
map[i][j] = 0;
if(map[i][j] % 5 == 3)
map[i][j] -= 5;
}
}
void MoveAlongPath(IAPI& api) {
if(!PathToGo.empty() && ((!PathGone.empty() && PathToGo.front() != PathGone.front()) || PathGone.empty())) {
bool Reach = false;
if(PathToGo.size() == 1) {
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y)) < 100) {
Reach = true;
}
} else {
auto it = PathToGo.begin();it++;
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y))
+ T.Dist(Gridx, Gridy, api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) <
T.Dist(api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y),
api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) * 1.15) {
Reach = true;
}
}
if(Reach) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
if(!PathToGo.empty()) {
if(Map[PathToGo.front()->x][PathToGo.front()->y] == THUAI6::PlaceType::Window) {
if(api.SkipWindow().get()) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
} else {
faceDir = atan2(api.CellToGrid(PathToGo.front()->y) - Gridy, api.CellToGrid(PathToGo.front()->x) - Gridx);
api.Move(500, faceDir);
}
} else {
if(PlayerId <= 3) {
switch(studentstate) {
case StudentState::MovingForClassroom:
if(studentType[PlayerId] == THUAI6::StudentType::StraightAStudent && studentinfo->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
studentstate = StudentState::Learning;
break;
case StudentState::MovingForGrass:
break;
case StudentState::MovingToGraduate:
api.StartOpenGate();
studentstate = StudentState::WaitToGraduate;
break;
case StudentState::WaitToGraduate:
break;
}
} else {
int GrassId;
switch(trickerstate) {
case TrickerState::MovingToPatrol:
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].determination <= 0) {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
} else {
trickerstate = TrickerState::MovingToSearch;
GrassId = TrickerSearchPossibleGrass(api, 2000);
if(GrassId != -1) {
FindPathTo({Grass[GrassId].x,Grass[GrassId].y}, true);
}
}
break;
case TrickerState::MovingToSearch:
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
break;
}
}
}
}
}
bool OnlyTeacherLeft(ITrickerAPI& api) {
if(framecount > 6000)
return true;
for(int i = 0;i < 4;i++) {
if(Students[i].studentType != THUAI6::StudentType::Teacher && Students[i].determination > 0)
return false;
}
return true;
}
int FindStudentInSight(ITrickerAPI& api) {
auto StudentsInSight = api.GetStudents();
for(auto i = 0;i < StudentsInSight.size();i++) {
if(OnlyTeacherLeft(api)) {
if(Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
} else {
if(Students[StudentsInSight[i]->playerID].studentType != THUAI6::StudentType::Teacher && Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
}
}
return -1;
}
void ReadMessage(IStudentAPI& api) {
for(int i = 0;i < 10;i++)
Classroom[i].occupied = 4;
if(map1)
Classroom[5].occupied = 5;
ShouldChangeClassroomToGo = false;
while(api.HaveMessage()) {
msgrcv = api.GetMessage();
Classroom[msgrcv.second[0] - '0'].occupied = msgrcv.first;
if(msgrcv.second[0] - '0' == CurrentClassroomToGo) ShouldChangeClassroomToGo = true;
if(msgrcv.second[1] == '1') Classroom[msgrcv.second[2] - '0'].finished = true, ClassroomFinished++;
if(msgrcv.second[3] == '1' && studentstate != StudentState::MovingToRescue) {
int dist = 1000000, id = 0;
for(int i = 0;i < 4;i++) {
//api.Print(fmt::format("stu[{}].x = {} stu[{}].y = {}", i, Students[i].x, i, Students[i].y));
if(msgrcv.first != i) {
if(dist > T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y)) {
dist = T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y);
id = i;
}
}
}
//api.Print(fmt::format("id{},dist{}", id, dist));
if(id == PlayerId) {
studentstate = StudentState::MovingToRescue;
CurrentStudentToRescue = msgrcv.first;
}
}
if(msgrcv.second[4] != '*' && !TrickerisInSight) {
Trickers.x = T.ToInt(msgrcv.second.substr(4, 5));
Trickers.y = T.ToInt(msgrcv.second.substr(9, 5));
CanGetTrickerInfo = true;
}
}
if(ShouldChangeClassroomToGo) {
CurrentClassroomToGo = SearchBestClassroom(api);
if(studentstate == StudentState::MovingForClassroom)
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
}
void SendMessage(IStudentAPI& api) {
if(studentstate == StudentState::MovingForClassroom || studentstate == StudentState::Learning)
msg[0] = CurrentClassroomToGo + '0';
if(studentinfo->playerState == THUAI6::PlayerState::Addicted &&
!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))
msg[3] = '1';
if(TrickerisInSight)
msg = msg + T.ToString(Trickers.x) + T.ToString(Trickers.y);
else
msg = msg + "**********";
for(int i = 0;i < 4;i++)
if(PlayerId != i)
api.SendTextMessage(i, msg);
}
bool CheckTrickerStuck(){
int avex = 0,avey = 0;
for(int i = 0;i < LastTrickerNum;i++){
avex += LastTrickers[i].x;
avey += LastTrickers[i].y;
}
avex /= LastTrickerNum;
avey /= LastTrickerNum;
return (T.Dist(avex,avey,Trickers.x,Trickers.y) < 350);
}
void AI::play(IStudentAPI& api) {
studentinfo = api.GetSelfInfo();
//api.Print(fmt::format("studentinfo->dangerAlert {}", studentinfo->dangerAlert));
UpdateMapInfo(api);
UpdateStudentInfo(api);
if(studentstate != StudentState::Learning && !rousing) {
api.EndAllAction();
//api.Print("endallaction");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
}
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
ReadMessage(api);
if(CheckTrickerStuck() && CanGetTrickerInfo) {
TrickerStuckTime += 50;
} else
TrickerStuckTime = 0;
if(studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && abs(T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) - 15000 / studentinfo->dangerAlert) > 100)
Trickers.x = -1;
if(!CanGetTrickerInfo)
Trickers.x = -1;
//api.Print(fmt::format("Trickers{},{}", Trickers.x, Trickers.y));
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(StuckTime >= 200) {
if(PathToGo.size() >= 2) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
StuckTime = 0;
}
if(studentstate != StudentState::MovingForGrass) {
if((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage))) {
rousing = false;
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
Grass[CurrentGrassToGo].occupied = true;
studentstate = StudentState::MovingForGrass;
//api.Print(fmt::format("grassfind{},{}", Grass[TargetGrass].x, Grass[TargetGrass].y));
}
auto bullets = api.GetBullets();
bool FlyingKnifeInSight = false;
for(auto i = 0;i < bullets.size();i++)
if(bullets[i]->bulletType == THUAI6::BulletType::FlyingKnife){
FlyingKnifeInSight = true;
//api.Print(fmt::format("FlyingKnifeInSight!!!"));
}
if(FlyingKnifeInSight){
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
Grass[CurrentGrassToGo].occupied = true;
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
studentstate = StudentState::MovingForGrass;
}
}
if(ClassroomFinished >= 7 && studentstate != StudentState::WaitToGraduate && studentstate != StudentState::MovingToGraduate && studentstate != StudentState::MovingForGrass) {
studentstate = StudentState::MovingToGraduate;
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
}
//api.Print(fmt::format("Courage{}", Courage));
//api.Print(fmt::format("EscapeDist / Courage{}", EscapeDist / Courage));
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01 && studentinfo->determination < 3200000) {
api.UseSkill(1);
}
switch(studentstate) {
case StudentState::MovingForClassroom:
//api.Print(fmt::format("state:MovingForClassroom"));
//api.Print(fmt::format("classroom{}:{},{}", CurrentClassroomToGo, Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y));
//CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y}, false);
break;
case StudentState::Learning:
//api.Print(fmt::format("state:Learning"));
//api.Print(fmt::format("classroom[{}] process = {}", CurrentClassroomToGo, api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y)));

if(api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y) == 10000000) {
//api.Print("ClassroomFinished");
studentstate = StudentState::MovingForClassroom;
Classroom[CurrentClassroomToGo].finished = true;
ClassroomFinished++;
msg[1] = '1';
msg[2] = (char)(CurrentClassroomToGo + '0');
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
} else
api.StartLearning();
break;
case StudentState::MovingForGrass:
Courage += 0.002;
//api.Print(fmt::format("state:MovingForGrass"));
if(!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))) {
WaitTrickerTime += 50;
if(Trickers.trickerType == THUAI6::TrickerType::ANoisyPerson){
if(WaitTrickerTime >= 10000) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}else{
if(WaitTrickerTime >= 2500) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}
} else {
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[2] < 0.01) {
api.UseSkill(2);
}
if(PathToGo.empty()) {
//api.Print("gototricker");
if(Map[Cellx - 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx - 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx - 1, Celly}, true);
if(Map[Cellx + 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx + 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx + 1, Celly}, true);
if(Map[Cellx][Celly - 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly - 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly - 1}, true);
if(Map[Cellx][Celly + 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly + 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly + 1}, true);
}
/*int TargetGrass;
TargetGrass = StudentSearchBestGrass(api);
FindPathTo({Grass[TargetGrass].x, Grass[TargetGrass].y}, true);*/
}
break;
case StudentState::MovingToRescue:
//api.Print(fmt::format("state:MovingToRescue"));
//api.Print(fmt::format("rescuestudent{}:{},{}", CurrentStudentToRescue, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
rousing = false;
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToRescue].x),api.GridToCell(Students[CurrentStudentToRescue].y)}, false);
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y) < 1200) {
api.StartRouseMate(CurrentStudentToRescue);
PathToGo.clear();
rousing = true;
//api.Print("rousing!");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
//api.Print("rouseover!");
rousing = false;
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01) {
api.UseSkill(1);
}
}
}
break;
case StudentState::MovingToGraduate:
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
break;
case StudentState::WaitToGraduate:
api.StartOpenGate();
if(api.GetGateProgress(Gate[CurrentGateToGo].x, Gate[CurrentGateToGo].y) == 18000) {
api.Graduate();
}
break;
default:
break;
}
if(TrickerStuckTime >= 200) {
Courage += 0.003;
}else{
if(CanGetTrickerInfo)
Courage = 1;
}
if(Courage > 1)
Courage -= 0.0015;
if(Courage > 2.3)
Courage = 2.3;
if(Courage < 1)
Courage = 1;
//api.Print(fmt::format("Courage = {}", Courage));
//api.Print(fmt::format("CriticalDist = {}", EscapeDist / Courage));
//api.Print(fmt::format("BGM = {}", studentinfo->dangerAlert));
//api.Print(fmt::format("BGM Dist = {}", 15000 / studentinfo->dangerAlert));
//for(auto i = PathToGo.begin();i != PathToGo.end();i++)
// api.Print(fmt::format("{} {}", (*i)->x, (*i)->y));
MoveAlongPath(api);
SendMessage(api);
}
void AI::play(ITrickerAPI& api) {
framecount++;
if(trickerType == THUAI6::TrickerType::ANoisyPerson) {
api.UseSkill(0);
goto end;
}
api.EndAllAction();
trickerinfo = api.GetSelfInfo();
UpdateMapInfo(api);
UpdateTrickerInfo(api);
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
int StudentsInSightId;
if(StuckTime >= 200) {
if(StuckTime >= 1000) {
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
} else {
if(trickerstate == TrickerState::MovingToSearch || trickerstate == TrickerState::MovingToPursue) {
if(api.Attack(faceDir).get())
Students[CurrentStudentToPursue].determination -= 1500000;
if(Students[CurrentStudentToPursue].determination <= 0) {
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
}
} else {
if(!PathToGo.empty()) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
}
}
}
switch(trickerstate) {
case TrickerState::MovingToPatrol:
StudentsInSightId = FindStudentInSight(api);
if(StudentsInSightId != -1) {
trickerstate = TrickerState::MovingToPursue;
CurrentStudentToPursue = StudentsInSightId;
} else {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
}
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].playerState == THUAI6::PlayerState::Addicted) {
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToPursue].x), api.GridToCell(Students[CurrentStudentToPursue].y)}, false);
if(StudentisInSight[CurrentStudentToPursue]) {
if(trickerinfo->timeUntilSkillAvailable[1] == 0) {
if(trickerType == THUAI6::TrickerType::Klee && T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.UseSkill(0);
}
if(api.HaveView(Students[CurrentStudentToPursue].y + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01))
if(trickerType == THUAI6::TrickerType::Assassin)
api.UseSkill(1);
}
switch(trickerinfo->bulletType) {
case THUAI6::BulletType::CommonAttackOfTricker:
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1500000;
}
break;
case THUAI6::BulletType::FlyingKnife:
api.Attack(atan2(
Students[CurrentStudentToPursue].y - Gridy + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x - Gridx + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
case THUAI6::BulletType::BombBomb:
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
}
}
break;
case TrickerState::MovingToSearch:
break;
}
MoveAlongPath(api);
end:;
}

+ 977
- 0
players/一会吃萤火虫/player3.cpp View File

@@ -0,0 +1,977 @@
#include <vector>
#include <list>
#include <math.h>
#include <string>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

constexpr int deltaTimems = 50;
constexpr int LastTrickerNum = 10;
#define deltaTime 0.05
#define pi 3.1415926

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
};
extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Klee;

/*
* 全局常量:
*
* 全局变量:
*
* Debug相关
* 寻路相关
* 游戏相关
*
* 学生变量:
* 通信相关
* 状态相关
* 游戏相关
*
* StraightAStudent变量:
* 冥想相关
* Athlete变量:
*
* Teacher变量:
*
* Sunshine变量:
*
*
* 捣蛋鬼变量:
*
*
* Assas变量:
*
* 工具类
* A*类
*
*/
struct Node {
int x, y;
int F, G, H;
Node* parent;
Node(int _x, int _y):x(_x), y(_y), F(0), G(0), H(0), parent(NULL) {}
}*node[50][50];
const std::list<Node*> emptylist;
const int EscapeDist = 16000;
std::list<Node*> PathToGo, PathGone;
bool isFirstFrame = true;
int PlayerId;
int Gridx, Gridy;
int Cellx, Celly;
std::vector<std::vector<THUAI6::PlaceType>> Map;
int map[50][50];//0为无阻碍,1为半阻碍,2为完全阻碍, 3为临时避障
struct ClassRoomInfo {
int x, y;
bool finished;
int occupied;//为4说明无学生占用,为0-3说明相应编号学生正在占用
}Classroom[100];
int ClassroomCount, ClassroomFinished;
struct ChestInfo {
int x, y;
bool opened;
int occupied;
}Chest[80];
int ChestCount;
struct GateInfo {
int x, y;
bool opening;
bool open;
}Gate[20];
int GateCount;
struct HiddenGateInfo {
int x, y;
bool refreshed;
bool open;
}HiddenGate[30];
int HiddenGateCount;
struct GrassInfo {
int x, y, occupied;
}Grass[200];
int GrassCount;
double faceDir = 0;
bool map1 = false, map2 = false;
std::pair<int, int> LastTarget;

std::pair<int, std::string> msgrcv;
std::string msg;//信息结构:'准备前往*号教室''1/0完成了作业''*号教室作业已完成''需要被营救'"捣蛋鬼x坐标""捣蛋鬼y坐标"
std::shared_ptr<const THUAI6::Student> studentinfo;
THUAI6::Tricker Trickers,LastTrickers[LastTrickerNum];
bool TrickerisInSight;
bool CanGetTrickerInfo;
enum class StudentState {
MovingForClassroom, Learning, MovingForGrass, MovingToAttck, MovingForProp, MovingToRescue, MovingToGraduate, WaitToGraduate
}studentstate;
int CurrentClassroomToGo;
int CurrentGateToGo;
int CurrentStudentToRescue;
int CurrentGrassToGo;
bool ShouldChangeClassroomToGo;
float Courage = 1.0;
int TrickerStuckTime;
bool rousing = false;
int framecount;

int MeditationProgress;

double ChargeTimeLeft;

std::shared_ptr<const THUAI6::Tricker> trickerinfo;
THUAI6::Student Students[4];
bool StudentisInSight[4];
enum class TrickerState {
MovingToPatrol, MovingToPursue, MovingToSearch, MovingForProp
}trickerstate;
struct _PatrolNode {
int x, y;
};
std::vector<_PatrolNode> PatrolNode;
int CurrentPatrolNodeToGo;
int CurrentStudentToPursue;
int StuckTime;
int WaitTrickerTime;
bool bgmuseful;


class Tools {
public:
double max(double a, double b) {
return a > b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
double Dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int ToInt(std::string s) {
int x = 0;
for(int i = 0;i < 5;i++, x *= 10)
x += s[i] - '0';
return x / 10;
}
std::string ToString(int x) {
std::string s = "*****";
for(int i = 0;i < 5;i++, x /= 10)
s[4 - i] = x % 10 + '0';
return s;
}
double StuDistValSet(double Dist) {
if(Dist < 7500)
return Dist;
return (Dist - 7500) * 2 + 7500;
}
double TriDistValSet(double Dist) {
int dist1 = 8500, dist2 = 10500;
if(Dist < dist1)
return Dist * 6;
if(Dist >= dist1 && Dist <= dist2)
return (Dist - dist1) * 3 + dist1 * 6;
return (Dist - dist2) + dist1 * 4 + (dist2 - dist1) * 2;
}
}T;
class A_Star {
public:
void init() {
openlist.clear();
closelist.clear();
}
std::list<Node*> GetPath(std::vector<int> st, std::vector<int> ed, bool Reach) {
if(st == ed) {
std::list<Node*> simplelist;
simplelist.push_back(new Node(st[0], st[1]));
return simplelist;
}
openlist.push_back(new Node(st[0], st[1]));
while(!openlist.empty()) {
Node* CurrentUpdateNode = GetLeastF();
closelist.push_back(CurrentUpdateNode);
UpdateFValue(CurrentUpdateNode, ed);
Node* CurPathNode;
if(!Reach) {
CurPathNode = GetDestSurroundNode(ed);
if(CurPathNode) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
} else {
CurPathNode = isInList(openlist, ed[0], ed[1]);
if(CurPathNode != NULL) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
}
openlist.remove(CurrentUpdateNode);
}
return emptylist;
}
private:
void UpdateFValue(Node* CurNode, std::vector<int> ed) {
std::list<std::vector<int>> UpdateList = GetSurroundNode(CurNode);
for(auto Curnum = UpdateList.begin();Curnum != UpdateList.end();Curnum++) {
int i = (*Curnum)[0], j = (*Curnum)[1];
if(isInList(openlist, i, j) == NULL) {
Node* UpdateNode = new Node(i, j);
UpdateNode->parent = CurNode;
if(map[i][j] == 1) {
if(PlayerId <= 3 && studentType[PlayerId] == THUAI6::StudentType::StraightAStudent) {
if(MeditationProgress + CurNode->G / 28.8 * 40000 > 300000)
UpdateNode->G = CurNode->G + 1;
else
UpdateNode->G = CurNode->G + 100;
} else
UpdateNode->G = CurNode->G + 1 * (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
} else
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->H = (abs(ed[0] - i) + abs(ed[1] - j)) * 10;
UpdateNode->F = UpdateNode->G + UpdateNode->H;
openlist.push_back(UpdateNode);
} else {
Node* UpdateNode = isInList(openlist, i, j);
int newG = (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
if(CurNode->G + newG <= UpdateNode->G) {
UpdateNode->parent = CurNode;
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->F = UpdateNode->G + UpdateNode->H;
}
}
}
}
std::list<std::vector<int>> GetSurroundNode(Node* CurNode) {
std::list<std::vector<int>> SurroundNodeList;
bool up = false, down = false, left = false, right = false;
if(CurNode->x > 0 && map[CurNode->x - 1][CurNode->y] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y}), up = true;
if(CurNode->x < 49 && map[CurNode->x + 1][CurNode->y] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y}), down = true;
if(CurNode->y > 0 && map[CurNode->x][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y - 1}), left = true;
if(CurNode->y < 49 && map[CurNode->x][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y + 1}), right = true;
if(up && left && map[CurNode->x - 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y - 1});
if(up && right && map[CurNode->x - 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y + 1});
if(down && left && map[CurNode->x + 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y - 1});
if(down && right && map[CurNode->x + 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y + 1});
return SurroundNodeList;
}
Node* isInList(std::list<Node*>& List, int x, int y) {
for(auto i = List.begin();i != List.end();i++)
if((*i)->x == x && (*i)->y == y)
return (*i);
return NULL;
}
Node* GetDestSurroundNode(std::vector<int> ed) {
Node* retNode;
retNode = isInList(openlist, ed[0] - 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0] + 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] - 1);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] + 1);
if(retNode) return retNode;
return NULL;
}
Node* GetLeastF() {
if(!openlist.empty()) {
Node* resPoint = openlist.front();
for(auto i = openlist.begin();i != openlist.end();i++)
if(resPoint->F > (*i)->F)
resPoint = *i;
return resPoint;
}
return NULL;
}
private:
std::list<Node*> openlist;
std::list<Node*> closelist;
}AStar;
int SearchBestClassroom(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < ClassroomCount;i++) {
if(!Classroom[i].finished && Classroom[i].occupied == 4) {
double val = T.Dist(api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
}
return nearestId;
}
int SearchBestGate(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GateCount;i++) {
double val = T.Dist(api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int StudentSearchBestGrass(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
/*api.Print(fmt::format("Grid{},{}", Gridx, Gridy));
api.Print(fmt::format("Tri{},{}", Trickers.x, Trickers.y));*/
for(int i = 0;i < GrassCount;i++) {
double val = T.StuDistValSet(T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy));
/*api.Print(fmt::format("Grass{},{}:val{}", Grass[i].x, Grass[i].y, val));
api.Print(fmt::format("Dist(stu,Grass)={}", T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy)));
api.Print(fmt::format("Dist(tri,Grass)={}", T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y))));*/
if(val < valmin && !Grass[i].occupied) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int TrickerSearchPossibleGrass(IAPI& api, int DistMax) {
double distmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GrassCount;i++) {
double dist = T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy);
if(dist < distmin) {
distmin = dist;
nearestId = i;
}
}
return nearestId;
}
void FindPathTo(std::pair<int, int> Target, bool CanReach, bool ForceToFind = false) {
if((PathToGo.empty() || (!PathToGo.empty() && LastTarget != Target)) || ForceToFind) {
LastTarget = Target;
AStar.init();
PathToGo = AStar.GetPath({Cellx,Celly}, {Target.first,Target.second}, CanReach);
}
}
inline void StudentStart(IAPI& api) {
studentstate = StudentState::MovingForClassroom;
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
inline void TrickerStart(IAPI& api) {
CurrentPatrolNodeToGo = 0;
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
CurrentStudentToPursue = -1;
}
inline void Start(IAPI& api) {
isFirstFrame = false;
Map = api.GetFullMap();
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(Map[i][j] == THUAI6::PlaceType::Window)
map[i][j] = 1;
if(Map[i][j] == THUAI6::PlaceType::Wall || Map[i][j] == THUAI6::PlaceType::Gate
|| Map[i][j] == THUAI6::PlaceType::Chest || Map[i][j] == THUAI6::PlaceType::ClassRoom
|| Map[i][j] == THUAI6::PlaceType::HiddenGate)
map[i][j] = 2;
if(Map[i][j] == THUAI6::PlaceType::ClassRoom)
Classroom[ClassroomCount].x = i, Classroom[ClassroomCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Chest)
Chest[ChestCount].x = i, Chest[ChestCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Gate)
Gate[GateCount].x = i, Gate[GateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::HiddenGate)
HiddenGate[HiddenGateCount].x = i, HiddenGate[HiddenGateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Grass) {
Grass[GrassCount].x = i;
Grass[GrassCount++].y = j;
//api.Print(fmt::format("Grass[{}]:{},{}", GrassCount - 1, Grass[GrassCount - 1].x, Grass[GrassCount - 1].y));
}
}
if(Gate[0].y > 25) {
PatrolNode = {{18,18},{31,31},{42,31},{42,18},{31,7},{31,18},{18,31},{18,42},{7,31},{7,18}};
map2 = true;
} else {
PatrolNode = {{23,13},{18,7},{8,9},{8,33},{14,36},{23,29},{31,35},{42,41},{40,24}};
map1 = true;
}
if(PlayerId <= 3) {
StudentStart(api);
} else
TrickerStart(api);
}
void UpdateStudentInfo(IStudentAPI& api) {
msg = "*0*0";
if(studentinfo->x == Gridx && studentinfo->y == Gridy && studentinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
switch(studentType[PlayerId]) {
case THUAI6::StudentType::StraightAStudent:
if((int)studentinfo->playerState >= 1 && (int)studentinfo->playerState <= 10 && (int)studentinfo->playerState != 2)
MeditationProgress += 40 * deltaTimems;
else
MeditationProgress = 0;
break;
}
Gridx = studentinfo->x;
Gridy = studentinfo->y;
Cellx = api.GridToCell(studentinfo->x);
Celly = api.GridToCell(studentinfo->y);
for(int i = 0;i < 4;i++)
Students[i] = *(api.GetStudents()[i]);
auto TrickersInSight = api.GetTrickers();
TrickerisInSight = false;
CanGetTrickerInfo = false;
for(int i= LastTrickerNum - 1;i >= 1;i--)
LastTrickers[i] = LastTrickers[i-1];
LastTrickers[0] = Trickers;
if(!TrickersInSight.empty()) {
//api.Print("TrickerisInSight!");
TrickerisInSight = true;
CanGetTrickerInfo = true;
Trickers = *TrickersInSight[0];
} else {
//api.Print("TrickerisnotInSight!");
//if(Trickers.x != -1)
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(Trickers.x != -1 && api.HaveView(api.GridToCell(Trickers.x), api.GridToCell(Trickers.y))) {
Trickers.x = -1;
//api.Print("TrickerisnotInSightremove!");
}
}
//api.Print(fmt::format("TrickerStuckTime {}", TrickerStuckTime));
}
void UpdateTrickerInfo(ITrickerAPI& api) {
if(trickerinfo->x == Gridx && trickerinfo->y == Gridy && trickerinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
Gridx = trickerinfo->x;
Gridy = trickerinfo->y;
Cellx = api.GridToCell(trickerinfo->x);
Celly = api.GridToCell(trickerinfo->y);
auto StudentsInSight = api.GetStudents();
for(int i = 0;i < 4;i++)
StudentisInSight[i] = false;
for(int i = 0;i < StudentsInSight.size();i++) {
StudentisInSight[StudentsInSight[i]->playerID] = true;
Students[StudentsInSight[i]->playerID] = *StudentsInSight[i];
}
}
void UpdateMapInfo(IAPI& api) {
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(map[i][j] == 3)
map[i][j] = 0;
if(map[i][j] % 5 == 3)
map[i][j] -= 5;
}
}
void MoveAlongPath(IAPI& api) {
if(!PathToGo.empty() && ((!PathGone.empty() && PathToGo.front() != PathGone.front()) || PathGone.empty())) {
bool Reach = false;
if(PathToGo.size() == 1) {
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y)) < 100) {
Reach = true;
}
} else {
auto it = PathToGo.begin();it++;
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y))
+ T.Dist(Gridx, Gridy, api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) <
T.Dist(api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y),
api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) * 1.15) {
Reach = true;
}
}
if(Reach) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
if(!PathToGo.empty()) {
if(Map[PathToGo.front()->x][PathToGo.front()->y] == THUAI6::PlaceType::Window) {
if(api.SkipWindow().get()) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
} else {
faceDir = atan2(api.CellToGrid(PathToGo.front()->y) - Gridy, api.CellToGrid(PathToGo.front()->x) - Gridx);
api.Move(500, faceDir);
}
} else {
if(PlayerId <= 3) {
switch(studentstate) {
case StudentState::MovingForClassroom:
if(studentType[PlayerId] == THUAI6::StudentType::StraightAStudent && studentinfo->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
studentstate = StudentState::Learning;
break;
case StudentState::MovingForGrass:
break;
case StudentState::MovingToGraduate:
api.StartOpenGate();
studentstate = StudentState::WaitToGraduate;
break;
case StudentState::WaitToGraduate:
break;
}
} else {
int GrassId;
switch(trickerstate) {
case TrickerState::MovingToPatrol:
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].determination <= 0) {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
} else {
trickerstate = TrickerState::MovingToSearch;
GrassId = TrickerSearchPossibleGrass(api, 2000);
if(GrassId != -1) {
FindPathTo({Grass[GrassId].x,Grass[GrassId].y}, true);
}
}
break;
case TrickerState::MovingToSearch:
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
break;
}
}
}
}
}
bool OnlyTeacherLeft(ITrickerAPI& api) {
if(framecount > 6000)
return true;
for(int i = 0;i < 4;i++) {
if(Students[i].studentType != THUAI6::StudentType::Teacher && Students[i].determination > 0)
return false;
}
return true;
}
int FindStudentInSight(ITrickerAPI& api) {
auto StudentsInSight = api.GetStudents();
for(auto i = 0;i < StudentsInSight.size();i++) {
if(OnlyTeacherLeft(api)) {
if(Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
} else {
if(Students[StudentsInSight[i]->playerID].studentType != THUAI6::StudentType::Teacher && Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
}
}
return -1;
}
void ReadMessage(IStudentAPI& api) {
for(int i = 0;i < 10;i++)
Classroom[i].occupied = 4;
if(map1)
Classroom[5].occupied = 5;
ShouldChangeClassroomToGo = false;
while(api.HaveMessage()) {
msgrcv = api.GetMessage();
Classroom[msgrcv.second[0] - '0'].occupied = msgrcv.first;
if(msgrcv.second[0] - '0' == CurrentClassroomToGo) ShouldChangeClassroomToGo = true;
if(msgrcv.second[1] == '1') Classroom[msgrcv.second[2] - '0'].finished = true, ClassroomFinished++;
if(msgrcv.second[3] == '1' && studentstate != StudentState::MovingToRescue) {
int dist = 1000000, id = 0;
for(int i = 0;i < 4;i++) {
//api.Print(fmt::format("stu[{}].x = {} stu[{}].y = {}", i, Students[i].x, i, Students[i].y));
if(msgrcv.first != i) {
if(dist > T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y)) {
dist = T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y);
id = i;
}
}
}
//api.Print(fmt::format("id{},dist{}", id, dist));
if(id == PlayerId) {
studentstate = StudentState::MovingToRescue;
CurrentStudentToRescue = msgrcv.first;
}
}
if(msgrcv.second[4] != '*' && !TrickerisInSight) {
Trickers.x = T.ToInt(msgrcv.second.substr(4, 5));
Trickers.y = T.ToInt(msgrcv.second.substr(9, 5));
CanGetTrickerInfo = true;
}
}
if(ShouldChangeClassroomToGo) {
CurrentClassroomToGo = SearchBestClassroom(api);
if(studentstate == StudentState::MovingForClassroom)
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
}
void SendMessage(IStudentAPI& api) {
if(studentstate == StudentState::MovingForClassroom || studentstate == StudentState::Learning)
msg[0] = CurrentClassroomToGo + '0';
if(studentinfo->playerState == THUAI6::PlayerState::Addicted &&
!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))
msg[3] = '1';
if(TrickerisInSight)
msg = msg + T.ToString(Trickers.x) + T.ToString(Trickers.y);
else
msg = msg + "**********";
for(int i = 0;i < 4;i++)
if(PlayerId != i)
api.SendTextMessage(i, msg);
}
bool CheckTrickerStuck(){
int avex = 0,avey = 0;
for(int i = 0;i < LastTrickerNum;i++){
avex += LastTrickers[i].x;
avey += LastTrickers[i].y;
}
avex /= LastTrickerNum;
avey /= LastTrickerNum;
return (T.Dist(avex,avey,Trickers.x,Trickers.y) < 350);
}
void AI::play(IStudentAPI& api) {
studentinfo = api.GetSelfInfo();
//api.Print(fmt::format("studentinfo->dangerAlert {}", studentinfo->dangerAlert));
UpdateMapInfo(api);
UpdateStudentInfo(api);
if(studentstate != StudentState::Learning && !rousing) {
api.EndAllAction();
//api.Print("endallaction");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
}
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
ReadMessage(api);
if(CheckTrickerStuck() && CanGetTrickerInfo) {
TrickerStuckTime += 50;
} else
TrickerStuckTime = 0;
if(studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && abs(T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) - 15000 / studentinfo->dangerAlert) > 100)
Trickers.x = -1;
if(!CanGetTrickerInfo)
Trickers.x = -1;
//api.Print(fmt::format("Trickers{},{}", Trickers.x, Trickers.y));
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(StuckTime >= 200) {
if(PathToGo.size() >= 2) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
StuckTime = 0;
}
if(studentstate != StudentState::MovingForGrass) {
if((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage))) {
rousing = false;
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
Grass[CurrentGrassToGo].occupied = true;
studentstate = StudentState::MovingForGrass;
//api.Print(fmt::format("grassfind{},{}", Grass[TargetGrass].x, Grass[TargetGrass].y));
}
auto bullets = api.GetBullets();
bool FlyingKnifeInSight = false;
for(auto i = 0;i < bullets.size();i++)
if(bullets[i]->bulletType == THUAI6::BulletType::FlyingKnife){
FlyingKnifeInSight = true;
//api.Print(fmt::format("FlyingKnifeInSight!!!"));
}
if(FlyingKnifeInSight){
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
Grass[CurrentGrassToGo].occupied = true;
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
studentstate = StudentState::MovingForGrass;
}
}
if(ClassroomFinished >= 7 && studentstate != StudentState::WaitToGraduate && studentstate != StudentState::MovingToGraduate && studentstate != StudentState::MovingForGrass) {
studentstate = StudentState::MovingToGraduate;
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
}
//api.Print(fmt::format("Courage{}", Courage));
//api.Print(fmt::format("EscapeDist / Courage{}", EscapeDist / Courage));
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01 && studentinfo->determination < 3200000) {
api.UseSkill(1);
}
switch(studentstate) {
case StudentState::MovingForClassroom:
//api.Print(fmt::format("state:MovingForClassroom"));
//api.Print(fmt::format("classroom{}:{},{}", CurrentClassroomToGo, Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y));
//CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y}, false);
break;
case StudentState::Learning:
//api.Print(fmt::format("state:Learning"));
//api.Print(fmt::format("classroom[{}] process = {}", CurrentClassroomToGo, api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y)));

if(api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y) == 10000000) {
//api.Print("ClassroomFinished");
studentstate = StudentState::MovingForClassroom;
Classroom[CurrentClassroomToGo].finished = true;
ClassroomFinished++;
msg[1] = '1';
msg[2] = (char)(CurrentClassroomToGo + '0');
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
} else
api.StartLearning();
break;
case StudentState::MovingForGrass:
Courage += 0.002;
//api.Print(fmt::format("state:MovingForGrass"));
if(!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))) {
WaitTrickerTime += 50;
if(Trickers.trickerType == THUAI6::TrickerType::ANoisyPerson){
if(WaitTrickerTime >= 10000) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}else{
if(WaitTrickerTime >= 2500) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}
} else {
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[2] < 0.01) {
api.UseSkill(2);
}
if(PathToGo.empty()) {
//api.Print("gototricker");
if(Map[Cellx - 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx - 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx - 1, Celly}, true);
if(Map[Cellx + 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx + 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx + 1, Celly}, true);
if(Map[Cellx][Celly - 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly - 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly - 1}, true);
if(Map[Cellx][Celly + 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly + 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly + 1}, true);
}
/*int TargetGrass;
TargetGrass = StudentSearchBestGrass(api);
FindPathTo({Grass[TargetGrass].x, Grass[TargetGrass].y}, true);*/
}
break;
case StudentState::MovingToRescue:
//api.Print(fmt::format("state:MovingToRescue"));
//api.Print(fmt::format("rescuestudent{}:{},{}", CurrentStudentToRescue, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
rousing = false;
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToRescue].x),api.GridToCell(Students[CurrentStudentToRescue].y)}, false);
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y) < 1200) {
api.StartRouseMate(CurrentStudentToRescue);
PathToGo.clear();
rousing = true;
//api.Print("rousing!");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
//api.Print("rouseover!");
rousing = false;
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01) {
api.UseSkill(1);
}
}
}
break;
case StudentState::MovingToGraduate:
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
break;
case StudentState::WaitToGraduate:
api.StartOpenGate();
if(api.GetGateProgress(Gate[CurrentGateToGo].x, Gate[CurrentGateToGo].y) == 18000) {
api.Graduate();
}
break;
default:
break;
}
if(TrickerStuckTime >= 200) {
Courage += 0.003;
}else{
if(CanGetTrickerInfo)
Courage = 1;
}
if(Courage > 1)
Courage -= 0.0015;
if(Courage > 2.3)
Courage = 2.3;
if(Courage < 1)
Courage = 1;
//api.Print(fmt::format("Courage = {}", Courage));
//api.Print(fmt::format("CriticalDist = {}", EscapeDist / Courage));
//api.Print(fmt::format("BGM = {}", studentinfo->dangerAlert));
//api.Print(fmt::format("BGM Dist = {}", 15000 / studentinfo->dangerAlert));
//for(auto i = PathToGo.begin();i != PathToGo.end();i++)
// api.Print(fmt::format("{} {}", (*i)->x, (*i)->y));
MoveAlongPath(api);
SendMessage(api);
}
void AI::play(ITrickerAPI& api) {
framecount++;
if(trickerType == THUAI6::TrickerType::ANoisyPerson) {
api.UseSkill(0);
goto end;
}
api.EndAllAction();
trickerinfo = api.GetSelfInfo();
UpdateMapInfo(api);
UpdateTrickerInfo(api);
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
int StudentsInSightId;
if(StuckTime >= 200) {
if(StuckTime >= 1000) {
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
} else {
if(trickerstate == TrickerState::MovingToSearch || trickerstate == TrickerState::MovingToPursue) {
if(api.Attack(faceDir).get())
Students[CurrentStudentToPursue].determination -= 1500000;
if(Students[CurrentStudentToPursue].determination <= 0) {
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
}
} else {
if(!PathToGo.empty()) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
}
}
}
switch(trickerstate) {
case TrickerState::MovingToPatrol:
StudentsInSightId = FindStudentInSight(api);
if(StudentsInSightId != -1) {
trickerstate = TrickerState::MovingToPursue;
CurrentStudentToPursue = StudentsInSightId;
} else {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
}
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].playerState == THUAI6::PlayerState::Addicted) {
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToPursue].x), api.GridToCell(Students[CurrentStudentToPursue].y)}, false);
if(StudentisInSight[CurrentStudentToPursue]) {
if(trickerinfo->timeUntilSkillAvailable[1] == 0) {
if(trickerType == THUAI6::TrickerType::Klee && T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.UseSkill(0);
}
if(api.HaveView(Students[CurrentStudentToPursue].y + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01))
if(trickerType == THUAI6::TrickerType::Assassin)
api.UseSkill(1);
}
switch(trickerinfo->bulletType) {
case THUAI6::BulletType::CommonAttackOfTricker:
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1500000;
}
break;
case THUAI6::BulletType::FlyingKnife:
api.Attack(atan2(
Students[CurrentStudentToPursue].y - Gridy + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x - Gridx + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
case THUAI6::BulletType::BombBomb:
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
}
}
break;
case TrickerState::MovingToSearch:
break;
}
MoveAlongPath(api);
end:;
}

+ 977
- 0
players/一会吃萤火虫/player4.cpp View File

@@ -0,0 +1,977 @@
#include <vector>
#include <list>
#include <math.h>
#include <string>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

constexpr int deltaTimems = 50;
constexpr int LastTrickerNum = 10;
#define deltaTime 0.05
#define pi 3.1415926

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
};
extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Klee;

/*
* 全局常量:
*
* 全局变量:
*
* Debug相关
* 寻路相关
* 游戏相关
*
* 学生变量:
* 通信相关
* 状态相关
* 游戏相关
*
* StraightAStudent变量:
* 冥想相关
* Athlete变量:
*
* Teacher变量:
*
* Sunshine变量:
*
*
* 捣蛋鬼变量:
*
*
* Assas变量:
*
* 工具类
* A*类
*
*/
struct Node {
int x, y;
int F, G, H;
Node* parent;
Node(int _x, int _y):x(_x), y(_y), F(0), G(0), H(0), parent(NULL) {}
}*node[50][50];
const std::list<Node*> emptylist;
const int EscapeDist = 16000;
std::list<Node*> PathToGo, PathGone;
bool isFirstFrame = true;
int PlayerId;
int Gridx, Gridy;
int Cellx, Celly;
std::vector<std::vector<THUAI6::PlaceType>> Map;
int map[50][50];//0为无阻碍,1为半阻碍,2为完全阻碍, 3为临时避障
struct ClassRoomInfo {
int x, y;
bool finished;
int occupied;//为4说明无学生占用,为0-3说明相应编号学生正在占用
}Classroom[100];
int ClassroomCount, ClassroomFinished;
struct ChestInfo {
int x, y;
bool opened;
int occupied;
}Chest[80];
int ChestCount;
struct GateInfo {
int x, y;
bool opening;
bool open;
}Gate[20];
int GateCount;
struct HiddenGateInfo {
int x, y;
bool refreshed;
bool open;
}HiddenGate[30];
int HiddenGateCount;
struct GrassInfo {
int x, y, occupied;
}Grass[200];
int GrassCount;
double faceDir = 0;
bool map1 = false, map2 = false;
std::pair<int, int> LastTarget;

std::pair<int, std::string> msgrcv;
std::string msg;//信息结构:'准备前往*号教室''1/0完成了作业''*号教室作业已完成''需要被营救'"捣蛋鬼x坐标""捣蛋鬼y坐标"
std::shared_ptr<const THUAI6::Student> studentinfo;
THUAI6::Tricker Trickers,LastTrickers[LastTrickerNum];
bool TrickerisInSight;
bool CanGetTrickerInfo;
enum class StudentState {
MovingForClassroom, Learning, MovingForGrass, MovingToAttck, MovingForProp, MovingToRescue, MovingToGraduate, WaitToGraduate
}studentstate;
int CurrentClassroomToGo;
int CurrentGateToGo;
int CurrentStudentToRescue;
int CurrentGrassToGo;
bool ShouldChangeClassroomToGo;
float Courage = 1.0;
int TrickerStuckTime;
bool rousing = false;
int framecount;

int MeditationProgress;

double ChargeTimeLeft;

std::shared_ptr<const THUAI6::Tricker> trickerinfo;
THUAI6::Student Students[4];
bool StudentisInSight[4];
enum class TrickerState {
MovingToPatrol, MovingToPursue, MovingToSearch, MovingForProp
}trickerstate;
struct _PatrolNode {
int x, y;
};
std::vector<_PatrolNode> PatrolNode;
int CurrentPatrolNodeToGo;
int CurrentStudentToPursue;
int StuckTime;
int WaitTrickerTime;
bool bgmuseful;


class Tools {
public:
double max(double a, double b) {
return a > b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
double Dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int ToInt(std::string s) {
int x = 0;
for(int i = 0;i < 5;i++, x *= 10)
x += s[i] - '0';
return x / 10;
}
std::string ToString(int x) {
std::string s = "*****";
for(int i = 0;i < 5;i++, x /= 10)
s[4 - i] = x % 10 + '0';
return s;
}
double StuDistValSet(double Dist) {
if(Dist < 7500)
return Dist;
return (Dist - 7500) * 2 + 7500;
}
double TriDistValSet(double Dist) {
int dist1 = 8500, dist2 = 10500;
if(Dist < dist1)
return Dist * 6;
if(Dist >= dist1 && Dist <= dist2)
return (Dist - dist1) * 3 + dist1 * 6;
return (Dist - dist2) + dist1 * 4 + (dist2 - dist1) * 2;
}
}T;
class A_Star {
public:
void init() {
openlist.clear();
closelist.clear();
}
std::list<Node*> GetPath(std::vector<int> st, std::vector<int> ed, bool Reach) {
if(st == ed) {
std::list<Node*> simplelist;
simplelist.push_back(new Node(st[0], st[1]));
return simplelist;
}
openlist.push_back(new Node(st[0], st[1]));
while(!openlist.empty()) {
Node* CurrentUpdateNode = GetLeastF();
closelist.push_back(CurrentUpdateNode);
UpdateFValue(CurrentUpdateNode, ed);
Node* CurPathNode;
if(!Reach) {
CurPathNode = GetDestSurroundNode(ed);
if(CurPathNode) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
} else {
CurPathNode = isInList(openlist, ed[0], ed[1]);
if(CurPathNode != NULL) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
}
openlist.remove(CurrentUpdateNode);
}
return emptylist;
}
private:
void UpdateFValue(Node* CurNode, std::vector<int> ed) {
std::list<std::vector<int>> UpdateList = GetSurroundNode(CurNode);
for(auto Curnum = UpdateList.begin();Curnum != UpdateList.end();Curnum++) {
int i = (*Curnum)[0], j = (*Curnum)[1];
if(isInList(openlist, i, j) == NULL) {
Node* UpdateNode = new Node(i, j);
UpdateNode->parent = CurNode;
if(map[i][j] == 1) {
if(PlayerId <= 3 && studentType[PlayerId] == THUAI6::StudentType::StraightAStudent) {
if(MeditationProgress + CurNode->G / 28.8 * 40000 > 300000)
UpdateNode->G = CurNode->G + 1;
else
UpdateNode->G = CurNode->G + 100;
} else
UpdateNode->G = CurNode->G + 1 * (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
} else
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->H = (abs(ed[0] - i) + abs(ed[1] - j)) * 10;
UpdateNode->F = UpdateNode->G + UpdateNode->H;
openlist.push_back(UpdateNode);
} else {
Node* UpdateNode = isInList(openlist, i, j);
int newG = (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
if(CurNode->G + newG <= UpdateNode->G) {
UpdateNode->parent = CurNode;
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->F = UpdateNode->G + UpdateNode->H;
}
}
}
}
std::list<std::vector<int>> GetSurroundNode(Node* CurNode) {
std::list<std::vector<int>> SurroundNodeList;
bool up = false, down = false, left = false, right = false;
if(CurNode->x > 0 && map[CurNode->x - 1][CurNode->y] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y}), up = true;
if(CurNode->x < 49 && map[CurNode->x + 1][CurNode->y] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y}), down = true;
if(CurNode->y > 0 && map[CurNode->x][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y - 1}), left = true;
if(CurNode->y < 49 && map[CurNode->x][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y + 1}), right = true;
if(up && left && map[CurNode->x - 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y - 1});
if(up && right && map[CurNode->x - 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y + 1});
if(down && left && map[CurNode->x + 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y - 1});
if(down && right && map[CurNode->x + 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y + 1});
return SurroundNodeList;
}
Node* isInList(std::list<Node*>& List, int x, int y) {
for(auto i = List.begin();i != List.end();i++)
if((*i)->x == x && (*i)->y == y)
return (*i);
return NULL;
}
Node* GetDestSurroundNode(std::vector<int> ed) {
Node* retNode;
retNode = isInList(openlist, ed[0] - 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0] + 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] - 1);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] + 1);
if(retNode) return retNode;
return NULL;
}
Node* GetLeastF() {
if(!openlist.empty()) {
Node* resPoint = openlist.front();
for(auto i = openlist.begin();i != openlist.end();i++)
if(resPoint->F > (*i)->F)
resPoint = *i;
return resPoint;
}
return NULL;
}
private:
std::list<Node*> openlist;
std::list<Node*> closelist;
}AStar;
int SearchBestClassroom(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < ClassroomCount;i++) {
if(!Classroom[i].finished && Classroom[i].occupied == 4) {
double val = T.Dist(api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
}
return nearestId;
}
int SearchBestGate(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GateCount;i++) {
double val = T.Dist(api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int StudentSearchBestGrass(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
/*api.Print(fmt::format("Grid{},{}", Gridx, Gridy));
api.Print(fmt::format("Tri{},{}", Trickers.x, Trickers.y));*/
for(int i = 0;i < GrassCount;i++) {
double val = T.StuDistValSet(T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy));
/*api.Print(fmt::format("Grass{},{}:val{}", Grass[i].x, Grass[i].y, val));
api.Print(fmt::format("Dist(stu,Grass)={}", T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy)));
api.Print(fmt::format("Dist(tri,Grass)={}", T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y))));*/
if(val < valmin && !Grass[i].occupied) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int TrickerSearchPossibleGrass(IAPI& api, int DistMax) {
double distmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GrassCount;i++) {
double dist = T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy);
if(dist < distmin) {
distmin = dist;
nearestId = i;
}
}
return nearestId;
}
void FindPathTo(std::pair<int, int> Target, bool CanReach, bool ForceToFind = false) {
if((PathToGo.empty() || (!PathToGo.empty() && LastTarget != Target)) || ForceToFind) {
LastTarget = Target;
AStar.init();
PathToGo = AStar.GetPath({Cellx,Celly}, {Target.first,Target.second}, CanReach);
}
}
inline void StudentStart(IAPI& api) {
studentstate = StudentState::MovingForClassroom;
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
inline void TrickerStart(IAPI& api) {
CurrentPatrolNodeToGo = 0;
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
CurrentStudentToPursue = -1;
}
inline void Start(IAPI& api) {
isFirstFrame = false;
Map = api.GetFullMap();
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(Map[i][j] == THUAI6::PlaceType::Window)
map[i][j] = 1;
if(Map[i][j] == THUAI6::PlaceType::Wall || Map[i][j] == THUAI6::PlaceType::Gate
|| Map[i][j] == THUAI6::PlaceType::Chest || Map[i][j] == THUAI6::PlaceType::ClassRoom
|| Map[i][j] == THUAI6::PlaceType::HiddenGate)
map[i][j] = 2;
if(Map[i][j] == THUAI6::PlaceType::ClassRoom)
Classroom[ClassroomCount].x = i, Classroom[ClassroomCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Chest)
Chest[ChestCount].x = i, Chest[ChestCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Gate)
Gate[GateCount].x = i, Gate[GateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::HiddenGate)
HiddenGate[HiddenGateCount].x = i, HiddenGate[HiddenGateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Grass) {
Grass[GrassCount].x = i;
Grass[GrassCount++].y = j;
//api.Print(fmt::format("Grass[{}]:{},{}", GrassCount - 1, Grass[GrassCount - 1].x, Grass[GrassCount - 1].y));
}
}
if(Gate[0].y > 25) {
PatrolNode = {{18,18},{31,31},{42,31},{42,18},{31,7},{31,18},{18,31},{18,42},{7,31},{7,18}};
map2 = true;
} else {
PatrolNode = {{23,13},{18,7},{8,9},{8,33},{14,36},{23,29},{31,35},{42,41},{40,24}};
map1 = true;
}
if(PlayerId <= 3) {
StudentStart(api);
} else
TrickerStart(api);
}
void UpdateStudentInfo(IStudentAPI& api) {
msg = "*0*0";
if(studentinfo->x == Gridx && studentinfo->y == Gridy && studentinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
switch(studentType[PlayerId]) {
case THUAI6::StudentType::StraightAStudent:
if((int)studentinfo->playerState >= 1 && (int)studentinfo->playerState <= 10 && (int)studentinfo->playerState != 2)
MeditationProgress += 40 * deltaTimems;
else
MeditationProgress = 0;
break;
}
Gridx = studentinfo->x;
Gridy = studentinfo->y;
Cellx = api.GridToCell(studentinfo->x);
Celly = api.GridToCell(studentinfo->y);
for(int i = 0;i < 4;i++)
Students[i] = *(api.GetStudents()[i]);
auto TrickersInSight = api.GetTrickers();
TrickerisInSight = false;
CanGetTrickerInfo = false;
for(int i= LastTrickerNum - 1;i >= 1;i--)
LastTrickers[i] = LastTrickers[i-1];
LastTrickers[0] = Trickers;
if(!TrickersInSight.empty()) {
//api.Print("TrickerisInSight!");
TrickerisInSight = true;
CanGetTrickerInfo = true;
Trickers = *TrickersInSight[0];
} else {
//api.Print("TrickerisnotInSight!");
//if(Trickers.x != -1)
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(Trickers.x != -1 && api.HaveView(api.GridToCell(Trickers.x), api.GridToCell(Trickers.y))) {
Trickers.x = -1;
//api.Print("TrickerisnotInSightremove!");
}
}
//api.Print(fmt::format("TrickerStuckTime {}", TrickerStuckTime));
}
void UpdateTrickerInfo(ITrickerAPI& api) {
if(trickerinfo->x == Gridx && trickerinfo->y == Gridy && trickerinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
Gridx = trickerinfo->x;
Gridy = trickerinfo->y;
Cellx = api.GridToCell(trickerinfo->x);
Celly = api.GridToCell(trickerinfo->y);
auto StudentsInSight = api.GetStudents();
for(int i = 0;i < 4;i++)
StudentisInSight[i] = false;
for(int i = 0;i < StudentsInSight.size();i++) {
StudentisInSight[StudentsInSight[i]->playerID] = true;
Students[StudentsInSight[i]->playerID] = *StudentsInSight[i];
}
}
void UpdateMapInfo(IAPI& api) {
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(map[i][j] == 3)
map[i][j] = 0;
if(map[i][j] % 5 == 3)
map[i][j] -= 5;
}
}
void MoveAlongPath(IAPI& api) {
if(!PathToGo.empty() && ((!PathGone.empty() && PathToGo.front() != PathGone.front()) || PathGone.empty())) {
bool Reach = false;
if(PathToGo.size() == 1) {
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y)) < 100) {
Reach = true;
}
} else {
auto it = PathToGo.begin();it++;
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y))
+ T.Dist(Gridx, Gridy, api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) <
T.Dist(api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y),
api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) * 1.15) {
Reach = true;
}
}
if(Reach) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
if(!PathToGo.empty()) {
if(Map[PathToGo.front()->x][PathToGo.front()->y] == THUAI6::PlaceType::Window) {
if(api.SkipWindow().get()) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
} else {
faceDir = atan2(api.CellToGrid(PathToGo.front()->y) - Gridy, api.CellToGrid(PathToGo.front()->x) - Gridx);
api.Move(500, faceDir);
}
} else {
if(PlayerId <= 3) {
switch(studentstate) {
case StudentState::MovingForClassroom:
if(studentType[PlayerId] == THUAI6::StudentType::StraightAStudent && studentinfo->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
studentstate = StudentState::Learning;
break;
case StudentState::MovingForGrass:
break;
case StudentState::MovingToGraduate:
api.StartOpenGate();
studentstate = StudentState::WaitToGraduate;
break;
case StudentState::WaitToGraduate:
break;
}
} else {
int GrassId;
switch(trickerstate) {
case TrickerState::MovingToPatrol:
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].determination <= 0) {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
} else {
trickerstate = TrickerState::MovingToSearch;
GrassId = TrickerSearchPossibleGrass(api, 2000);
if(GrassId != -1) {
FindPathTo({Grass[GrassId].x,Grass[GrassId].y}, true);
}
}
break;
case TrickerState::MovingToSearch:
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
break;
}
}
}
}
}
bool OnlyTeacherLeft(ITrickerAPI& api) {
if(framecount > 6000)
return true;
for(int i = 0;i < 4;i++) {
if(Students[i].studentType != THUAI6::StudentType::Teacher && Students[i].determination > 0)
return false;
}
return true;
}
int FindStudentInSight(ITrickerAPI& api) {
auto StudentsInSight = api.GetStudents();
for(auto i = 0;i < StudentsInSight.size();i++) {
if(OnlyTeacherLeft(api)) {
if(Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
} else {
if(Students[StudentsInSight[i]->playerID].studentType != THUAI6::StudentType::Teacher && Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
}
}
return -1;
}
void ReadMessage(IStudentAPI& api) {
for(int i = 0;i < 10;i++)
Classroom[i].occupied = 4;
if(map1)
Classroom[5].occupied = 5;
ShouldChangeClassroomToGo = false;
while(api.HaveMessage()) {
msgrcv = api.GetMessage();
Classroom[msgrcv.second[0] - '0'].occupied = msgrcv.first;
if(msgrcv.second[0] - '0' == CurrentClassroomToGo) ShouldChangeClassroomToGo = true;
if(msgrcv.second[1] == '1') Classroom[msgrcv.second[2] - '0'].finished = true, ClassroomFinished++;
if(msgrcv.second[3] == '1' && studentstate != StudentState::MovingToRescue) {
int dist = 1000000, id = 0;
for(int i = 0;i < 4;i++) {
//api.Print(fmt::format("stu[{}].x = {} stu[{}].y = {}", i, Students[i].x, i, Students[i].y));
if(msgrcv.first != i) {
if(dist > T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y)) {
dist = T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y);
id = i;
}
}
}
//api.Print(fmt::format("id{},dist{}", id, dist));
if(id == PlayerId) {
studentstate = StudentState::MovingToRescue;
CurrentStudentToRescue = msgrcv.first;
}
}
if(msgrcv.second[4] != '*' && !TrickerisInSight) {
Trickers.x = T.ToInt(msgrcv.second.substr(4, 5));
Trickers.y = T.ToInt(msgrcv.second.substr(9, 5));
CanGetTrickerInfo = true;
}
}
if(ShouldChangeClassroomToGo) {
CurrentClassroomToGo = SearchBestClassroom(api);
if(studentstate == StudentState::MovingForClassroom)
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
}
void SendMessage(IStudentAPI& api) {
if(studentstate == StudentState::MovingForClassroom || studentstate == StudentState::Learning)
msg[0] = CurrentClassroomToGo + '0';
if(studentinfo->playerState == THUAI6::PlayerState::Addicted &&
!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))
msg[3] = '1';
if(TrickerisInSight)
msg = msg + T.ToString(Trickers.x) + T.ToString(Trickers.y);
else
msg = msg + "**********";
for(int i = 0;i < 4;i++)
if(PlayerId != i)
api.SendTextMessage(i, msg);
}
bool CheckTrickerStuck(){
int avex = 0,avey = 0;
for(int i = 0;i < LastTrickerNum;i++){
avex += LastTrickers[i].x;
avey += LastTrickers[i].y;
}
avex /= LastTrickerNum;
avey /= LastTrickerNum;
return (T.Dist(avex,avey,Trickers.x,Trickers.y) < 350);
}
void AI::play(IStudentAPI& api) {
studentinfo = api.GetSelfInfo();
//api.Print(fmt::format("studentinfo->dangerAlert {}", studentinfo->dangerAlert));
UpdateMapInfo(api);
UpdateStudentInfo(api);
if(studentstate != StudentState::Learning && !rousing) {
api.EndAllAction();
//api.Print("endallaction");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
}
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
ReadMessage(api);
if(CheckTrickerStuck() && CanGetTrickerInfo) {
TrickerStuckTime += 50;
} else
TrickerStuckTime = 0;
if(studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && abs(T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) - 15000 / studentinfo->dangerAlert) > 100)
Trickers.x = -1;
if(!CanGetTrickerInfo)
Trickers.x = -1;
//api.Print(fmt::format("Trickers{},{}", Trickers.x, Trickers.y));
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(StuckTime >= 200) {
if(PathToGo.size() >= 2) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
StuckTime = 0;
}
if(studentstate != StudentState::MovingForGrass) {
if((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage))) {
rousing = false;
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
Grass[CurrentGrassToGo].occupied = true;
studentstate = StudentState::MovingForGrass;
//api.Print(fmt::format("grassfind{},{}", Grass[TargetGrass].x, Grass[TargetGrass].y));
}
auto bullets = api.GetBullets();
bool FlyingKnifeInSight = false;
for(auto i = 0;i < bullets.size();i++)
if(bullets[i]->bulletType == THUAI6::BulletType::FlyingKnife){
FlyingKnifeInSight = true;
//api.Print(fmt::format("FlyingKnifeInSight!!!"));
}
if(FlyingKnifeInSight){
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
Grass[CurrentGrassToGo].occupied = true;
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
studentstate = StudentState::MovingForGrass;
}
}
if(ClassroomFinished >= 7 && studentstate != StudentState::WaitToGraduate && studentstate != StudentState::MovingToGraduate && studentstate != StudentState::MovingForGrass) {
studentstate = StudentState::MovingToGraduate;
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
}
//api.Print(fmt::format("Courage{}", Courage));
//api.Print(fmt::format("EscapeDist / Courage{}", EscapeDist / Courage));
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01 && studentinfo->determination < 3200000) {
api.UseSkill(1);
}
switch(studentstate) {
case StudentState::MovingForClassroom:
//api.Print(fmt::format("state:MovingForClassroom"));
//api.Print(fmt::format("classroom{}:{},{}", CurrentClassroomToGo, Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y));
//CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y}, false);
break;
case StudentState::Learning:
//api.Print(fmt::format("state:Learning"));
//api.Print(fmt::format("classroom[{}] process = {}", CurrentClassroomToGo, api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y)));

if(api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y) == 10000000) {
//api.Print("ClassroomFinished");
studentstate = StudentState::MovingForClassroom;
Classroom[CurrentClassroomToGo].finished = true;
ClassroomFinished++;
msg[1] = '1';
msg[2] = (char)(CurrentClassroomToGo + '0');
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
} else
api.StartLearning();
break;
case StudentState::MovingForGrass:
Courage += 0.002;
//api.Print(fmt::format("state:MovingForGrass"));
if(!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))) {
WaitTrickerTime += 50;
if(Trickers.trickerType == THUAI6::TrickerType::ANoisyPerson){
if(WaitTrickerTime >= 10000) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}else{
if(WaitTrickerTime >= 2500) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}
} else {
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[2] < 0.01) {
api.UseSkill(2);
}
if(PathToGo.empty()) {
//api.Print("gototricker");
if(Map[Cellx - 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx - 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx - 1, Celly}, true);
if(Map[Cellx + 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx + 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx + 1, Celly}, true);
if(Map[Cellx][Celly - 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly - 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly - 1}, true);
if(Map[Cellx][Celly + 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly + 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly + 1}, true);
}
/*int TargetGrass;
TargetGrass = StudentSearchBestGrass(api);
FindPathTo({Grass[TargetGrass].x, Grass[TargetGrass].y}, true);*/
}
break;
case StudentState::MovingToRescue:
//api.Print(fmt::format("state:MovingToRescue"));
//api.Print(fmt::format("rescuestudent{}:{},{}", CurrentStudentToRescue, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
rousing = false;
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToRescue].x),api.GridToCell(Students[CurrentStudentToRescue].y)}, false);
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y) < 1200) {
api.StartRouseMate(CurrentStudentToRescue);
PathToGo.clear();
rousing = true;
//api.Print("rousing!");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
//api.Print("rouseover!");
rousing = false;
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01) {
api.UseSkill(1);
}
}
}
break;
case StudentState::MovingToGraduate:
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
break;
case StudentState::WaitToGraduate:
api.StartOpenGate();
if(api.GetGateProgress(Gate[CurrentGateToGo].x, Gate[CurrentGateToGo].y) == 18000) {
api.Graduate();
}
break;
default:
break;
}
if(TrickerStuckTime >= 200) {
Courage += 0.003;
}else{
if(CanGetTrickerInfo)
Courage = 1;
}
if(Courage > 1)
Courage -= 0.0015;
if(Courage > 2.3)
Courage = 2.3;
if(Courage < 1)
Courage = 1;
//api.Print(fmt::format("Courage = {}", Courage));
//api.Print(fmt::format("CriticalDist = {}", EscapeDist / Courage));
//api.Print(fmt::format("BGM = {}", studentinfo->dangerAlert));
//api.Print(fmt::format("BGM Dist = {}", 15000 / studentinfo->dangerAlert));
//for(auto i = PathToGo.begin();i != PathToGo.end();i++)
// api.Print(fmt::format("{} {}", (*i)->x, (*i)->y));
MoveAlongPath(api);
SendMessage(api);
}
void AI::play(ITrickerAPI& api) {
framecount++;
if(trickerType == THUAI6::TrickerType::ANoisyPerson) {
api.UseSkill(0);
goto end;
}
api.EndAllAction();
trickerinfo = api.GetSelfInfo();
UpdateMapInfo(api);
UpdateTrickerInfo(api);
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
int StudentsInSightId;
if(StuckTime >= 200) {
if(StuckTime >= 1000) {
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
} else {
if(trickerstate == TrickerState::MovingToSearch || trickerstate == TrickerState::MovingToPursue) {
if(api.Attack(faceDir).get())
Students[CurrentStudentToPursue].determination -= 1500000;
if(Students[CurrentStudentToPursue].determination <= 0) {
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
}
} else {
if(!PathToGo.empty()) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
}
}
}
switch(trickerstate) {
case TrickerState::MovingToPatrol:
StudentsInSightId = FindStudentInSight(api);
if(StudentsInSightId != -1) {
trickerstate = TrickerState::MovingToPursue;
CurrentStudentToPursue = StudentsInSightId;
} else {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
}
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].playerState == THUAI6::PlayerState::Addicted) {
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToPursue].x), api.GridToCell(Students[CurrentStudentToPursue].y)}, false);
if(StudentisInSight[CurrentStudentToPursue]) {
if(trickerinfo->timeUntilSkillAvailable[1] == 0) {
if(trickerType == THUAI6::TrickerType::Klee && T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.UseSkill(0);
}
if(api.HaveView(Students[CurrentStudentToPursue].y + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01))
if(trickerType == THUAI6::TrickerType::Assassin)
api.UseSkill(1);
}
switch(trickerinfo->bulletType) {
case THUAI6::BulletType::CommonAttackOfTricker:
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1500000;
}
break;
case THUAI6::BulletType::FlyingKnife:
api.Attack(atan2(
Students[CurrentStudentToPursue].y - Gridy + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x - Gridx + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
case THUAI6::BulletType::BombBomb:
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
}
}
break;
case TrickerState::MovingToSearch:
break;
}
MoveAlongPath(api);
end:;
}

+ 977
- 0
players/一会吃萤火虫/player5.cpp View File

@@ -0,0 +1,977 @@
#include <vector>
#include <list>
#include <math.h>
#include <string>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

constexpr int deltaTimems = 50;
constexpr int LastTrickerNum = 10;
#define deltaTime 0.05
#define pi 3.1415926

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
};
extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Klee;

/*
* 全局常量:
*
* 全局变量:
*
* Debug相关
* 寻路相关
* 游戏相关
*
* 学生变量:
* 通信相关
* 状态相关
* 游戏相关
*
* StraightAStudent变量:
* 冥想相关
* Athlete变量:
*
* Teacher变量:
*
* Sunshine变量:
*
*
* 捣蛋鬼变量:
*
*
* Assas变量:
*
* 工具类
* A*类
*
*/
struct Node {
int x, y;
int F, G, H;
Node* parent;
Node(int _x, int _y):x(_x), y(_y), F(0), G(0), H(0), parent(NULL) {}
}*node[50][50];
const std::list<Node*> emptylist;
const int EscapeDist = 16000;
std::list<Node*> PathToGo, PathGone;
bool isFirstFrame = true;
int PlayerId;
int Gridx, Gridy;
int Cellx, Celly;
std::vector<std::vector<THUAI6::PlaceType>> Map;
int map[50][50];//0为无阻碍,1为半阻碍,2为完全阻碍, 3为临时避障
struct ClassRoomInfo {
int x, y;
bool finished;
int occupied;//为4说明无学生占用,为0-3说明相应编号学生正在占用
}Classroom[100];
int ClassroomCount, ClassroomFinished;
struct ChestInfo {
int x, y;
bool opened;
int occupied;
}Chest[80];
int ChestCount;
struct GateInfo {
int x, y;
bool opening;
bool open;
}Gate[20];
int GateCount;
struct HiddenGateInfo {
int x, y;
bool refreshed;
bool open;
}HiddenGate[30];
int HiddenGateCount;
struct GrassInfo {
int x, y, occupied;
}Grass[200];
int GrassCount;
double faceDir = 0;
bool map1 = false, map2 = false;
std::pair<int, int> LastTarget;

std::pair<int, std::string> msgrcv;
std::string msg;//信息结构:'准备前往*号教室''1/0完成了作业''*号教室作业已完成''需要被营救'"捣蛋鬼x坐标""捣蛋鬼y坐标"
std::shared_ptr<const THUAI6::Student> studentinfo;
THUAI6::Tricker Trickers,LastTrickers[LastTrickerNum];
bool TrickerisInSight;
bool CanGetTrickerInfo;
enum class StudentState {
MovingForClassroom, Learning, MovingForGrass, MovingToAttck, MovingForProp, MovingToRescue, MovingToGraduate, WaitToGraduate
}studentstate;
int CurrentClassroomToGo;
int CurrentGateToGo;
int CurrentStudentToRescue;
int CurrentGrassToGo;
bool ShouldChangeClassroomToGo;
float Courage = 1.0;
int TrickerStuckTime;
bool rousing = false;
int framecount;

int MeditationProgress;

double ChargeTimeLeft;

std::shared_ptr<const THUAI6::Tricker> trickerinfo;
THUAI6::Student Students[4];
bool StudentisInSight[4];
enum class TrickerState {
MovingToPatrol, MovingToPursue, MovingToSearch, MovingForProp
}trickerstate;
struct _PatrolNode {
int x, y;
};
std::vector<_PatrolNode> PatrolNode;
int CurrentPatrolNodeToGo;
int CurrentStudentToPursue;
int StuckTime;
int WaitTrickerTime;
bool bgmuseful;


class Tools {
public:
double max(double a, double b) {
return a > b ? a : b;
}
double min(double a, double b) {
return a < b ? a : b;
}
double Dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
int ToInt(std::string s) {
int x = 0;
for(int i = 0;i < 5;i++, x *= 10)
x += s[i] - '0';
return x / 10;
}
std::string ToString(int x) {
std::string s = "*****";
for(int i = 0;i < 5;i++, x /= 10)
s[4 - i] = x % 10 + '0';
return s;
}
double StuDistValSet(double Dist) {
if(Dist < 7500)
return Dist;
return (Dist - 7500) * 2 + 7500;
}
double TriDistValSet(double Dist) {
int dist1 = 8500, dist2 = 10500;
if(Dist < dist1)
return Dist * 6;
if(Dist >= dist1 && Dist <= dist2)
return (Dist - dist1) * 3 + dist1 * 6;
return (Dist - dist2) + dist1 * 4 + (dist2 - dist1) * 2;
}
}T;
class A_Star {
public:
void init() {
openlist.clear();
closelist.clear();
}
std::list<Node*> GetPath(std::vector<int> st, std::vector<int> ed, bool Reach) {
if(st == ed) {
std::list<Node*> simplelist;
simplelist.push_back(new Node(st[0], st[1]));
return simplelist;
}
openlist.push_back(new Node(st[0], st[1]));
while(!openlist.empty()) {
Node* CurrentUpdateNode = GetLeastF();
closelist.push_back(CurrentUpdateNode);
UpdateFValue(CurrentUpdateNode, ed);
Node* CurPathNode;
if(!Reach) {
CurPathNode = GetDestSurroundNode(ed);
if(CurPathNode) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
} else {
CurPathNode = isInList(openlist, ed[0], ed[1]);
if(CurPathNode != NULL) {
std::list<Node*> path;
while(CurPathNode != NULL) {
path.push_front(CurPathNode);
CurPathNode = CurPathNode->parent;
}
return path;
}
}
openlist.remove(CurrentUpdateNode);
}
return emptylist;
}
private:
void UpdateFValue(Node* CurNode, std::vector<int> ed) {
std::list<std::vector<int>> UpdateList = GetSurroundNode(CurNode);
for(auto Curnum = UpdateList.begin();Curnum != UpdateList.end();Curnum++) {
int i = (*Curnum)[0], j = (*Curnum)[1];
if(isInList(openlist, i, j) == NULL) {
Node* UpdateNode = new Node(i, j);
UpdateNode->parent = CurNode;
if(map[i][j] == 1) {
if(PlayerId <= 3 && studentType[PlayerId] == THUAI6::StudentType::StraightAStudent) {
if(MeditationProgress + CurNode->G / 28.8 * 40000 > 300000)
UpdateNode->G = CurNode->G + 1;
else
UpdateNode->G = CurNode->G + 100;
} else
UpdateNode->G = CurNode->G + 1 * (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
} else
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->H = (abs(ed[0] - i) + abs(ed[1] - j)) * 10;
UpdateNode->F = UpdateNode->G + UpdateNode->H;
openlist.push_back(UpdateNode);
} else {
Node* UpdateNode = isInList(openlist, i, j);
int newG = (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
if(CurNode->G + newG <= UpdateNode->G) {
UpdateNode->parent = CurNode;
UpdateNode->G = CurNode->G + (int)sqrt(100 * ((i - CurNode->x) * (i - CurNode->x) + (j - CurNode->y) * (j - CurNode->y)));
UpdateNode->F = UpdateNode->G + UpdateNode->H;
}
}
}
}
std::list<std::vector<int>> GetSurroundNode(Node* CurNode) {
std::list<std::vector<int>> SurroundNodeList;
bool up = false, down = false, left = false, right = false;
if(CurNode->x > 0 && map[CurNode->x - 1][CurNode->y] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y}), up = true;
if(CurNode->x < 49 && map[CurNode->x + 1][CurNode->y] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y}), down = true;
if(CurNode->y > 0 && map[CurNode->x][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y - 1}), left = true;
if(CurNode->y < 49 && map[CurNode->x][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x,CurNode->y + 1}), right = true;
if(up && left && map[CurNode->x - 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y - 1});
if(up && right && map[CurNode->x - 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x - 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x - 1,CurNode->y + 1});
if(down && left && map[CurNode->x + 1][CurNode->y - 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y - 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y - 1});
if(down && right && map[CurNode->x + 1][CurNode->y + 1] < 2 && isInList(closelist, CurNode->x + 1, CurNode->y + 1) == NULL)
SurroundNodeList.push_back({CurNode->x + 1,CurNode->y + 1});
return SurroundNodeList;
}
Node* isInList(std::list<Node*>& List, int x, int y) {
for(auto i = List.begin();i != List.end();i++)
if((*i)->x == x && (*i)->y == y)
return (*i);
return NULL;
}
Node* GetDestSurroundNode(std::vector<int> ed) {
Node* retNode;
retNode = isInList(openlist, ed[0] - 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0] + 1, ed[1]);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] - 1);
if(retNode) return retNode;
retNode = isInList(openlist, ed[0], ed[1] + 1);
if(retNode) return retNode;
return NULL;
}
Node* GetLeastF() {
if(!openlist.empty()) {
Node* resPoint = openlist.front();
for(auto i = openlist.begin();i != openlist.end();i++)
if(resPoint->F > (*i)->F)
resPoint = *i;
return resPoint;
}
return NULL;
}
private:
std::list<Node*> openlist;
std::list<Node*> closelist;
}AStar;
int SearchBestClassroom(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < ClassroomCount;i++) {
if(!Classroom[i].finished && Classroom[i].occupied == 4) {
double val = T.Dist(api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Classroom[i].x), api.CellToGrid(Classroom[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
}
return nearestId;
}
int SearchBestGate(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GateCount;i++) {
double val = T.Dist(api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y), Gridx, Gridy)
- 0.5 * T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Gate[i].x), api.CellToGrid(Gate[i].y));
if(val < valmin) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int StudentSearchBestGrass(IAPI& api) {
double valmin = 10000000;
int nearestId = -1;
/*api.Print(fmt::format("Grid{},{}", Gridx, Gridy));
api.Print(fmt::format("Tri{},{}", Trickers.x, Trickers.y));*/
for(int i = 0;i < GrassCount;i++) {
double val = T.StuDistValSet(T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy));
/*api.Print(fmt::format("Grass{},{}:val{}", Grass[i].x, Grass[i].y, val));
api.Print(fmt::format("Dist(stu,Grass)={}", T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy)));
api.Print(fmt::format("Dist(tri,Grass)={}", T.Dist(Trickers.x, Trickers.y, api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y))));*/
if(val < valmin && !Grass[i].occupied) {
valmin = val;
nearestId = i;
}
}
return nearestId;
}
int TrickerSearchPossibleGrass(IAPI& api, int DistMax) {
double distmin = 10000000;
int nearestId = -1;
for(int i = 0;i < GrassCount;i++) {
double dist = T.Dist(api.CellToGrid(Grass[i].x), api.CellToGrid(Grass[i].y), Gridx, Gridy);
if(dist < distmin) {
distmin = dist;
nearestId = i;
}
}
return nearestId;
}
void FindPathTo(std::pair<int, int> Target, bool CanReach, bool ForceToFind = false) {
if((PathToGo.empty() || (!PathToGo.empty() && LastTarget != Target)) || ForceToFind) {
LastTarget = Target;
AStar.init();
PathToGo = AStar.GetPath({Cellx,Celly}, {Target.first,Target.second}, CanReach);
}
}
inline void StudentStart(IAPI& api) {
studentstate = StudentState::MovingForClassroom;
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
inline void TrickerStart(IAPI& api) {
CurrentPatrolNodeToGo = 0;
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
CurrentStudentToPursue = -1;
}
inline void Start(IAPI& api) {
isFirstFrame = false;
Map = api.GetFullMap();
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(Map[i][j] == THUAI6::PlaceType::Window)
map[i][j] = 1;
if(Map[i][j] == THUAI6::PlaceType::Wall || Map[i][j] == THUAI6::PlaceType::Gate
|| Map[i][j] == THUAI6::PlaceType::Chest || Map[i][j] == THUAI6::PlaceType::ClassRoom
|| Map[i][j] == THUAI6::PlaceType::HiddenGate)
map[i][j] = 2;
if(Map[i][j] == THUAI6::PlaceType::ClassRoom)
Classroom[ClassroomCount].x = i, Classroom[ClassroomCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Chest)
Chest[ChestCount].x = i, Chest[ChestCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Gate)
Gate[GateCount].x = i, Gate[GateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::HiddenGate)
HiddenGate[HiddenGateCount].x = i, HiddenGate[HiddenGateCount++].y = j;
if(Map[i][j] == THUAI6::PlaceType::Grass) {
Grass[GrassCount].x = i;
Grass[GrassCount++].y = j;
//api.Print(fmt::format("Grass[{}]:{},{}", GrassCount - 1, Grass[GrassCount - 1].x, Grass[GrassCount - 1].y));
}
}
if(Gate[0].y > 25) {
PatrolNode = {{18,18},{31,31},{42,31},{42,18},{31,7},{31,18},{18,31},{18,42},{7,31},{7,18}};
map2 = true;
} else {
PatrolNode = {{23,13},{18,7},{8,9},{8,33},{14,36},{23,29},{31,35},{42,41},{40,24}};
map1 = true;
}
if(PlayerId <= 3) {
StudentStart(api);
} else
TrickerStart(api);
}
void UpdateStudentInfo(IStudentAPI& api) {
msg = "*0*0";
if(studentinfo->x == Gridx && studentinfo->y == Gridy && studentinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
switch(studentType[PlayerId]) {
case THUAI6::StudentType::StraightAStudent:
if((int)studentinfo->playerState >= 1 && (int)studentinfo->playerState <= 10 && (int)studentinfo->playerState != 2)
MeditationProgress += 40 * deltaTimems;
else
MeditationProgress = 0;
break;
}
Gridx = studentinfo->x;
Gridy = studentinfo->y;
Cellx = api.GridToCell(studentinfo->x);
Celly = api.GridToCell(studentinfo->y);
for(int i = 0;i < 4;i++)
Students[i] = *(api.GetStudents()[i]);
auto TrickersInSight = api.GetTrickers();
TrickerisInSight = false;
CanGetTrickerInfo = false;
for(int i= LastTrickerNum - 1;i >= 1;i--)
LastTrickers[i] = LastTrickers[i-1];
LastTrickers[0] = Trickers;
if(!TrickersInSight.empty()) {
//api.Print("TrickerisInSight!");
TrickerisInSight = true;
CanGetTrickerInfo = true;
Trickers = *TrickersInSight[0];
} else {
//api.Print("TrickerisnotInSight!");
//if(Trickers.x != -1)
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(Trickers.x != -1 && api.HaveView(api.GridToCell(Trickers.x), api.GridToCell(Trickers.y))) {
Trickers.x = -1;
//api.Print("TrickerisnotInSightremove!");
}
}
//api.Print(fmt::format("TrickerStuckTime {}", TrickerStuckTime));
}
void UpdateTrickerInfo(ITrickerAPI& api) {
if(trickerinfo->x == Gridx && trickerinfo->y == Gridy && trickerinfo->playerState == THUAI6::PlayerState::Idle)
StuckTime += 50;
else
StuckTime = 0;
Gridx = trickerinfo->x;
Gridy = trickerinfo->y;
Cellx = api.GridToCell(trickerinfo->x);
Celly = api.GridToCell(trickerinfo->y);
auto StudentsInSight = api.GetStudents();
for(int i = 0;i < 4;i++)
StudentisInSight[i] = false;
for(int i = 0;i < StudentsInSight.size();i++) {
StudentisInSight[StudentsInSight[i]->playerID] = true;
Students[StudentsInSight[i]->playerID] = *StudentsInSight[i];
}
}
void UpdateMapInfo(IAPI& api) {
for(int i = 0;i < 50;i++)
for(int j = 0;j < 50;j++) {
if(map[i][j] == 3)
map[i][j] = 0;
if(map[i][j] % 5 == 3)
map[i][j] -= 5;
}
}
void MoveAlongPath(IAPI& api) {
if(!PathToGo.empty() && ((!PathGone.empty() && PathToGo.front() != PathGone.front()) || PathGone.empty())) {
bool Reach = false;
if(PathToGo.size() == 1) {
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y)) < 100) {
Reach = true;
}
} else {
auto it = PathToGo.begin();it++;
if(T.Dist(Gridx, Gridy, api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y))
+ T.Dist(Gridx, Gridy, api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) <
T.Dist(api.CellToGrid(PathToGo.front()->x), api.CellToGrid(PathToGo.front()->y),
api.CellToGrid((*it)->x), api.CellToGrid((*it)->y)) * 1.15) {
Reach = true;
}
}
if(Reach) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
if(!PathToGo.empty()) {
if(Map[PathToGo.front()->x][PathToGo.front()->y] == THUAI6::PlaceType::Window) {
if(api.SkipWindow().get()) {
PathGone.push_front(PathToGo.front());
PathToGo.pop_front();
}
} else {
faceDir = atan2(api.CellToGrid(PathToGo.front()->y) - Gridy, api.CellToGrid(PathToGo.front()->x) - Gridx);
api.Move(500, faceDir);
}
} else {
if(PlayerId <= 3) {
switch(studentstate) {
case StudentState::MovingForClassroom:
if(studentType[PlayerId] == THUAI6::StudentType::StraightAStudent && studentinfo->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
studentstate = StudentState::Learning;
break;
case StudentState::MovingForGrass:
break;
case StudentState::MovingToGraduate:
api.StartOpenGate();
studentstate = StudentState::WaitToGraduate;
break;
case StudentState::WaitToGraduate:
break;
}
} else {
int GrassId;
switch(trickerstate) {
case TrickerState::MovingToPatrol:
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].determination <= 0) {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
} else {
trickerstate = TrickerState::MovingToSearch;
GrassId = TrickerSearchPossibleGrass(api, 2000);
if(GrassId != -1) {
FindPathTo({Grass[GrassId].x,Grass[GrassId].y}, true);
}
}
break;
case TrickerState::MovingToSearch:
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
trickerstate = TrickerState::MovingToPatrol;
break;
}
}
}
}
}
bool OnlyTeacherLeft(ITrickerAPI& api) {
if(framecount > 6000)
return true;
for(int i = 0;i < 4;i++) {
if(Students[i].studentType != THUAI6::StudentType::Teacher && Students[i].determination > 0)
return false;
}
return true;
}
int FindStudentInSight(ITrickerAPI& api) {
auto StudentsInSight = api.GetStudents();
for(auto i = 0;i < StudentsInSight.size();i++) {
if(OnlyTeacherLeft(api)) {
if(Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
} else {
if(Students[StudentsInSight[i]->playerID].studentType != THUAI6::StudentType::Teacher && Students[StudentsInSight[i]->playerID].determination > 0)
return StudentsInSight[i]->playerID;
}
}
return -1;
}
void ReadMessage(IStudentAPI& api) {
for(int i = 0;i < 10;i++)
Classroom[i].occupied = 4;
if(map1)
Classroom[5].occupied = 5;
ShouldChangeClassroomToGo = false;
while(api.HaveMessage()) {
msgrcv = api.GetMessage();
Classroom[msgrcv.second[0] - '0'].occupied = msgrcv.first;
if(msgrcv.second[0] - '0' == CurrentClassroomToGo) ShouldChangeClassroomToGo = true;
if(msgrcv.second[1] == '1') Classroom[msgrcv.second[2] - '0'].finished = true, ClassroomFinished++;
if(msgrcv.second[3] == '1' && studentstate != StudentState::MovingToRescue) {
int dist = 1000000, id = 0;
for(int i = 0;i < 4;i++) {
//api.Print(fmt::format("stu[{}].x = {} stu[{}].y = {}", i, Students[i].x, i, Students[i].y));
if(msgrcv.first != i) {
if(dist > T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y)) {
dist = T.Dist(Students[i].x, Students[i].y, Students[msgrcv.first].x, Students[msgrcv.first].y);
id = i;
}
}
}
//api.Print(fmt::format("id{},dist{}", id, dist));
if(id == PlayerId) {
studentstate = StudentState::MovingToRescue;
CurrentStudentToRescue = msgrcv.first;
}
}
if(msgrcv.second[4] != '*' && !TrickerisInSight) {
Trickers.x = T.ToInt(msgrcv.second.substr(4, 5));
Trickers.y = T.ToInt(msgrcv.second.substr(9, 5));
CanGetTrickerInfo = true;
}
}
if(ShouldChangeClassroomToGo) {
CurrentClassroomToGo = SearchBestClassroom(api);
if(studentstate == StudentState::MovingForClassroom)
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
}
}
void SendMessage(IStudentAPI& api) {
if(studentstate == StudentState::MovingForClassroom || studentstate == StudentState::Learning)
msg[0] = CurrentClassroomToGo + '0';
if(studentinfo->playerState == THUAI6::PlayerState::Addicted &&
!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))
msg[3] = '1';
if(TrickerisInSight)
msg = msg + T.ToString(Trickers.x) + T.ToString(Trickers.y);
else
msg = msg + "**********";
for(int i = 0;i < 4;i++)
if(PlayerId != i)
api.SendTextMessage(i, msg);
}
bool CheckTrickerStuck(){
int avex = 0,avey = 0;
for(int i = 0;i < LastTrickerNum;i++){
avex += LastTrickers[i].x;
avey += LastTrickers[i].y;
}
avex /= LastTrickerNum;
avey /= LastTrickerNum;
return (T.Dist(avex,avey,Trickers.x,Trickers.y) < 350);
}
void AI::play(IStudentAPI& api) {
studentinfo = api.GetSelfInfo();
//api.Print(fmt::format("studentinfo->dangerAlert {}", studentinfo->dangerAlert));
UpdateMapInfo(api);
UpdateStudentInfo(api);
if(studentstate != StudentState::Learning && !rousing) {
api.EndAllAction();
//api.Print("endallaction");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
}
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
ReadMessage(api);
if(CheckTrickerStuck() && CanGetTrickerInfo) {
TrickerStuckTime += 50;
} else
TrickerStuckTime = 0;
if(studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && abs(T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) - 15000 / studentinfo->dangerAlert) > 100)
Trickers.x = -1;
if(!CanGetTrickerInfo)
Trickers.x = -1;
//api.Print(fmt::format("Trickers{},{}", Trickers.x, Trickers.y));
//api.Print(fmt::format("tricker{},{}", Trickers.x, Trickers.y));
if(StuckTime >= 200) {
if(PathToGo.size() >= 2) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
StuckTime = 0;
}
if(studentstate != StudentState::MovingForGrass) {
if((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage))) {
rousing = false;
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
Grass[CurrentGrassToGo].occupied = true;
studentstate = StudentState::MovingForGrass;
//api.Print(fmt::format("grassfind{},{}", Grass[TargetGrass].x, Grass[TargetGrass].y));
}
auto bullets = api.GetBullets();
bool FlyingKnifeInSight = false;
for(auto i = 0;i < bullets.size();i++)
if(bullets[i]->bulletType == THUAI6::BulletType::FlyingKnife){
FlyingKnifeInSight = true;
//api.Print(fmt::format("FlyingKnifeInSight!!!"));
}
if(FlyingKnifeInSight){
CurrentGrassToGo = -1;
if(map1) {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 0) CurrentGrassToGo = 15;
if(CurrentClassroomToGo == 1) CurrentGrassToGo = 30;
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 37;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 65;
if(CurrentClassroomToGo == 7) CurrentGrassToGo = 90;
}
} else {
if(studentstate == StudentState::Learning) {
if(CurrentClassroomToGo == 3) CurrentGrassToGo = 19;
if(CurrentClassroomToGo == 4) CurrentGrassToGo = 45;
if(CurrentClassroomToGo == 5) CurrentGrassToGo = 78;
if(CurrentClassroomToGo == 6) CurrentGrassToGo = 104;
}
}
if(CurrentGrassToGo == -1)
CurrentGrassToGo = StudentSearchBestGrass(api);
Grass[CurrentGrassToGo].occupied = true;
FindPathTo({Grass[CurrentGrassToGo].x, Grass[CurrentGrassToGo].y}, true);
studentstate = StudentState::MovingForGrass;
}
}
if(ClassroomFinished >= 7 && studentstate != StudentState::WaitToGraduate && studentstate != StudentState::MovingToGraduate && studentstate != StudentState::MovingForGrass) {
studentstate = StudentState::MovingToGraduate;
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
}
//api.Print(fmt::format("Courage{}", Courage));
//api.Print(fmt::format("EscapeDist / Courage{}", EscapeDist / Courage));
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01 && studentinfo->determination < 3200000) {
api.UseSkill(1);
}
switch(studentstate) {
case StudentState::MovingForClassroom:
//api.Print(fmt::format("state:MovingForClassroom"));
//api.Print(fmt::format("classroom{}:{},{}", CurrentClassroomToGo, Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y));
//CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y}, false);
break;
case StudentState::Learning:
//api.Print(fmt::format("state:Learning"));
//api.Print(fmt::format("classroom[{}] process = {}", CurrentClassroomToGo, api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y)));

if(api.GetClassroomProgress(Classroom[CurrentClassroomToGo].x, Classroom[CurrentClassroomToGo].y) == 10000000) {
//api.Print("ClassroomFinished");
studentstate = StudentState::MovingForClassroom;
Classroom[CurrentClassroomToGo].finished = true;
ClassroomFinished++;
msg[1] = '1';
msg[2] = (char)(CurrentClassroomToGo + '0');
CurrentClassroomToGo = SearchBestClassroom(api);
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
} else
api.StartLearning();
break;
case StudentState::MovingForGrass:
Courage += 0.002;
//api.Print(fmt::format("state:MovingForGrass"));
if(!((studentinfo->dangerAlert < 1000 && studentinfo->dangerAlert > 0.01 && 15000 / studentinfo->dangerAlert < EscapeDist / Courage)
|| (Trickers.x != -1 && (T.Dist(Gridx, Gridy, Trickers.x, Trickers.y) < EscapeDist / Courage)))) {
WaitTrickerTime += 50;
if(Trickers.trickerType == THUAI6::TrickerType::ANoisyPerson){
if(WaitTrickerTime >= 10000) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}else{
if(WaitTrickerTime >= 2500) {
Grass[CurrentGrassToGo].occupied = false;
if(ClassroomFinished >= 7)
studentstate = StudentState::MovingToGraduate;
else
studentstate = StudentState::MovingForClassroom;
WaitTrickerTime = 0;
}
}
} else {
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[2] < 0.01) {
api.UseSkill(2);
}
if(PathToGo.empty()) {
//api.Print("gototricker");
if(Map[Cellx - 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx - 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx - 1, Celly}, true);
if(Map[Cellx + 1][Celly] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx + 1), api.CellToGrid(Celly), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx + 1, Celly}, true);
if(Map[Cellx][Celly - 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly - 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly - 1}, true);
if(Map[Cellx][Celly + 1] == THUAI6::PlaceType::Grass
&& T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly + 1), Trickers.x, Trickers.y) < T.Dist(api.CellToGrid(Cellx), api.CellToGrid(Celly), Trickers.x, Trickers.y))
FindPathTo({Cellx, Celly + 1}, true);
}
/*int TargetGrass;
TargetGrass = StudentSearchBestGrass(api);
FindPathTo({Grass[TargetGrass].x, Grass[TargetGrass].y}, true);*/
}
break;
case StudentState::MovingToRescue:
//api.Print(fmt::format("state:MovingToRescue"));
//api.Print(fmt::format("rescuestudent{}:{},{}", CurrentStudentToRescue, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
rousing = false;
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToRescue].x),api.GridToCell(Students[CurrentStudentToRescue].y)}, false);
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToRescue].x, Students[CurrentStudentToRescue].y) < 1200) {
api.StartRouseMate(CurrentStudentToRescue);
PathToGo.clear();
rousing = true;
//api.Print("rousing!");
//api.Print(fmt::format("state {}", (int)studentinfo->playerState));
if(Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Addicted && Students[CurrentStudentToRescue].playerState != THUAI6::PlayerState::Roused) {
studentstate = StudentState::MovingForClassroom;
FindPathTo({Classroom[CurrentClassroomToGo].x,Classroom[CurrentClassroomToGo].y}, false);
//api.Print("rouseover!");
rousing = false;
if(studentType[PlayerId] == THUAI6::StudentType::Sunshine && studentinfo->timeUntilSkillAvailable[1] < 0.01) {
api.UseSkill(1);
}
}
}
break;
case StudentState::MovingToGraduate:
CurrentGateToGo = SearchBestGate(api);
FindPathTo({Gate[CurrentGateToGo].x,Gate[CurrentGateToGo].y}, false);
break;
case StudentState::WaitToGraduate:
api.StartOpenGate();
if(api.GetGateProgress(Gate[CurrentGateToGo].x, Gate[CurrentGateToGo].y) == 18000) {
api.Graduate();
}
break;
default:
break;
}
if(TrickerStuckTime >= 200) {
Courage += 0.003;
}else{
if(CanGetTrickerInfo)
Courage = 1;
}
if(Courage > 1)
Courage -= 0.0015;
if(Courage > 2.3)
Courage = 2.3;
if(Courage < 1)
Courage = 1;
//api.Print(fmt::format("Courage = {}", Courage));
//api.Print(fmt::format("CriticalDist = {}", EscapeDist / Courage));
//api.Print(fmt::format("BGM = {}", studentinfo->dangerAlert));
//api.Print(fmt::format("BGM Dist = {}", 15000 / studentinfo->dangerAlert));
//for(auto i = PathToGo.begin();i != PathToGo.end();i++)
// api.Print(fmt::format("{} {}", (*i)->x, (*i)->y));
MoveAlongPath(api);
SendMessage(api);
}
void AI::play(ITrickerAPI& api) {
framecount++;
if(trickerType == THUAI6::TrickerType::ANoisyPerson) {
api.UseSkill(0);
goto end;
}
api.EndAllAction();
trickerinfo = api.GetSelfInfo();
UpdateMapInfo(api);
UpdateTrickerInfo(api);
if(isFirstFrame) {
PlayerId = this->playerID;
Start(api);
}
int StudentsInSightId;
if(StuckTime >= 200) {
if(StuckTime >= 1000) {
CurrentPatrolNodeToGo = (CurrentPatrolNodeToGo + 1) % PatrolNode.size();
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
} else {
if(trickerstate == TrickerState::MovingToSearch || trickerstate == TrickerState::MovingToPursue) {
if(api.Attack(faceDir).get())
Students[CurrentStudentToPursue].determination -= 1500000;
if(Students[CurrentStudentToPursue].determination <= 0) {
trickerstate = TrickerState::MovingToPatrol;
CurrentStudentToPursue = -1;
}
} else {
if(!PathToGo.empty()) {
map[PathToGo.front()->x][PathToGo.front()->y] = 203;
FindPathTo({PathToGo.back()->x, PathToGo.back()->y}, true, true);
}
}
}
}
switch(trickerstate) {
case TrickerState::MovingToPatrol:
StudentsInSightId = FindStudentInSight(api);
if(StudentsInSightId != -1) {
trickerstate = TrickerState::MovingToPursue;
CurrentStudentToPursue = StudentsInSightId;
} else {
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
}
break;
case TrickerState::MovingToPursue:
if(Students[CurrentStudentToPursue].playerState == THUAI6::PlayerState::Addicted) {
trickerstate = TrickerState::MovingToPatrol;
FindPathTo({PatrolNode[CurrentPatrolNodeToGo].x,PatrolNode[CurrentPatrolNodeToGo].y}, true);
break;
}
FindPathTo({api.GridToCell(Students[CurrentStudentToPursue].x), api.GridToCell(Students[CurrentStudentToPursue].y)}, false);
if(StudentisInSight[CurrentStudentToPursue]) {
if(trickerinfo->timeUntilSkillAvailable[1] == 0) {
if(trickerType == THUAI6::TrickerType::Klee && T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.UseSkill(0);
}
if(api.HaveView(Students[CurrentStudentToPursue].y + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01))
if(trickerType == THUAI6::TrickerType::Assassin)
api.UseSkill(1);
}
switch(trickerinfo->bulletType) {
case THUAI6::BulletType::CommonAttackOfTricker:
if(T.Dist(Gridx, Gridy, Students[CurrentStudentToPursue].x, Students[CurrentStudentToPursue].y) <= 2000) {
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1500000;
}
break;
case THUAI6::BulletType::FlyingKnife:
api.Attack(atan2(
Students[CurrentStudentToPursue].y - Gridy + sin(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01,
Students[CurrentStudentToPursue].x - Gridx + cos(Students[CurrentStudentToPursue].facingDirection) * Students[CurrentStudentToPursue].speed * 0.01));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
case THUAI6::BulletType::BombBomb:
api.Attack(atan2(Students[CurrentStudentToPursue].y - Gridy, Students[CurrentStudentToPursue].x - Gridx));
Students[CurrentStudentToPursue].determination -= 1200000;
break;
}
}
break;
case TrickerState::MovingToSearch:
break;
}
MoveAlongPath(api);
end:;
}

+ 772
- 0
players/京ICP备2022019669号-1 2022 EESAST/player1.cpp View File

@@ -0,0 +1,772 @@
//四学霸策略

#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"
#include "API.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType =
{
THUAI6::StudentType::StraightAStudent ,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数

//全局变量
int32_t HomeworkLocations[10][2]{ {8,31},{18,5},{10,38},{19,41},{22,18},{28,26},{30,7},{33,40},{40,12},{44,32}};
int32_t GrassLocations[13][2]{ {8,2},{8,16},{5,25},{4,29},{10,46},{18,46},{20,36},{15,29},{20,1},{30,25},{40,24},{39,35},{46,8} };

bool IfResetDestination = true;

std::vector<bool> Condition1 = { false, true, false, true, false, false, false, false, true ,true ,true, false };//门都可以,草地,land可以



namespace MoveFunc
{
int32_t Distance(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return int32_t(sqrt((gridX0 - gridX1) * (gridX0 - gridX1) + (gridY0 - gridY1) * (gridY0 - gridY1)));
}

//角度为0指向1
double Angle(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return atan2(gridY1 - gridY0, gridX1 - gridX0);
}

namespace FindWay
{

int IfAchievable(THUAI6::PlaceType ThisPlace, std::vector<bool> Condition)
{
//是否可以通过的条件可以进一步完善
if ((ThisPlace == THUAI6::PlaceType::NullPlaceType && Condition[0])
|| (ThisPlace == THUAI6::PlaceType::Land && Condition[1])
|| (ThisPlace == THUAI6::PlaceType::Wall && Condition[2])
|| (ThisPlace == THUAI6::PlaceType::Grass && Condition[3])
|| (ThisPlace == THUAI6::PlaceType::ClassRoom && Condition[4])
|| (ThisPlace == THUAI6::PlaceType::Gate && Condition[5])
|| (ThisPlace == THUAI6::PlaceType::HiddenGate && Condition[6])
|| (ThisPlace == THUAI6::PlaceType::Window && Condition[7])
|| (ThisPlace == THUAI6::PlaceType::Door3 && Condition[8])
|| (ThisPlace == THUAI6::PlaceType::Door5 && Condition[9])
|| (ThisPlace == THUAI6::PlaceType::Door6 && Condition[10])
|| (ThisPlace == THUAI6::PlaceType::Chest && Condition[11]))
return 0;
else
return 1;//1不可达
}

const int kCost1 = 10; //直移一格消耗
const int kCost2 = 14; //斜移一格消耗

struct Point
{
int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列
int F, G, H; //F=G+H
Point* parent; //parent的坐标,这里没有用指针,从而简化代码
Point(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL) //变量初始化
{
}
};

class Astar
{
public:
void InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& api);
std::list<Point*> GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<bool> ThisCondition;
Astar(IStudentAPI& _api) :
maze({ {} }), api(_api), openList({}), closeList({}) {}

private:
Point* findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<Point*> getSurroundPoints(const Point* point, bool isIgnoreCorner) const;
bool isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断
Point* isInList(const std::list<Point*>& list, const Point* point) const; //判断开启/关闭列表中是否包含某点
Point* getLeastFpoint(); //从开启列表中返回F值最小的节点
//计算FGH值
int calcG(Point* temp_start, Point* point);
int calcH(Point* point, Point* end);
int calcF(Point* point);
private:
std::vector<std::vector<THUAI6::PlaceType>> maze;
std::list<Point*> openList; //开启列表
std::list<Point*> closeList; //关闭列表
IStudentAPI& api;
};




void Astar::InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& _api)
{
maze = _maze;
ThisCondition = Condition;
api = _api;
}

int Astar::calcG(Point* temp_start, Point* point)
{
int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空
return parentG + extraG;
}

int Astar::calcH(Point* point, Point* end)
{
//用简单的欧几里得距离计算H,这个H的计算是关键,还有很多算法,没深入研究^_^
return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calcF(Point* point)
{
return point->G + point->H;
}

Point* Astar::getLeastFpoint()
{
if (!openList.empty())
{
auto resPoint = openList.front();
for (auto& point : openList)
if (point->F < resPoint->F)
resPoint = point;
return resPoint;
}
return NULL;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
openList.push_back(new Point(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离
while (!openList.empty())
{
auto curPoint = getLeastFpoint(); //找到F值最小的点
openList.remove(curPoint); //从开启列表中删除
closeList.push_back(curPoint); //放到关闭列表
//1,找到当前周围八个格中可以通过的格子
auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
for (auto& target : surroundPoints)
{
//2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H
if (!isInList(openList, target))
{
target->parent = curPoint;

target->G = calcG(curPoint, target);
target->H = calcH(target, &endPoint);
target->F = calcF(target);

openList.push_back(target);
}
//3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
else
{
int tempG = calcG(curPoint, target);
if (tempG < target->G)
{
target->parent = curPoint;

target->G = tempG;
target->F = calcF(target);
}
}
Point* resPoint = isInList(openList, &endPoint);
if (resPoint)
return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝
}
}

return NULL;
}

std::list<Point*> Astar::GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
Point* result = findPath(startPoint, endPoint, isIgnoreCorner);
std::list<Point*> path;
//返回路径,如果没找到路径,返回空链表
while (result)
{
path.push_front(result);
result = result->parent;
}

// 清空临时开闭列表,防止重复执行GetPath导致结果异常
openList.clear();
closeList.clear();

return path;
}

Point* Astar::isInList(const std::list<Point*>& list, const Point* point) const
{
//判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标
for (auto p : list)
if (p->x == point->x && p->y == point->y)
return p;
return NULL;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
if ((target->x==api.GridToCell(api.GetSelfInfo()->x)&& target->y == api.GridToCell(api.GetSelfInfo()->y))
||target->x<0 || target->x>maze.size() - 1
|| target->y<0 || target->y>maze[0].size() - 1
|| IfAchievable(maze[target->x][target->y], ThisCondition) == 1
|| target->x == point->x && target->y == point->y
|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
return false;
else
{
if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以
return true;
else
{
//斜对角要判断是否绊住
if (IfAchievable(maze[point->x][target->y], ThisCondition) == 0 && IfAchievable(maze[target->x][point->y], ThisCondition) == 0)
return true;
else
return isIgnoreCorner;
}
}
}

std::vector<Point*> Astar::getSurroundPoints(const Point* point, bool isIgnoreCorner) const
{
std::vector<Point*> surroundPoints;

for (int x = point->x - 1; x <= point->x + 1; x++)
for (int y = point->y - 1; y <= point->y + 1; y++)
if (isCanreach(point, new Point(x, y), isIgnoreCorner))
surroundPoints.push_back(new Point(x, y));

return surroundPoints;
}


bool InPath(const int& row, const int& col, const std::list<Point*>& path) {
for (const auto& p : path) {
if (row == p->x && col == p->y) {
return true;
}
}
return false;
}

std::vector<std::vector<int32_t>> findPath(const std::vector<std::vector<THUAI6::PlaceType>>& map, int32_t cellX0, int32_t cellY0, int32_t cellX1, int32_t cellY1, std::vector<bool> Condition, IStudentAPI& api)
{
Astar astar(api);
astar.InitAstar(map, Condition,api);
Point start(cellX0, cellY0);
Point end(cellX1, cellY1);
std::list<Point*> path = astar.GetPath(start, end, false);
std::vector<std::vector<int>> result{};
for (auto P : path)
{
std::vector<int> Loc{ P->x,P->y };
result.push_back(Loc);
}
return result;
}

}

namespace GoToSomePlace
{
std::vector<bool> MoveToNextBlock(IStudentAPI& api, int32_t cellX, int32_t cellY)
{
auto self = api.GetSelfInfo();
if (Distance(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)) < 50)//可以调整
return { false,true };
auto p = api.Move(50, Angle(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
if (!p.get())
return { false,false };
return { true,true };
}//可以修改移动时间
//不检查是否可达,谨慎使用

class GoToAPlace
{
protected:
bool Going = false;//是否正在走
int32_t DestinationX = -1;//cell
int32_t DestinationY = -1;
std::vector<std::vector<int32_t>> Way{ {} };//没吃到
int32_t StepNumber = 0;
int32_t ThisStep = 0;
IStudentAPI& api;
std::vector<bool> ThisCondition;
int32_t LastGridX=-1;
int32_t LastGridY=-1;

public:
GoToAPlace(IStudentAPI& _api) :
Going(false), DestinationX(-1), DestinationY(-1), LastGridX(-1), LastGridY(-1), api(_api), StepNumber(0), ThisStep(0), Way({}), ThisCondition{ {} } {}

GoToAPlace& operator =(GoToAPlace P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way={ {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api=P.api;
ThisCondition=P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
return (*this);
}

bool SetDestination(int32_t cellX, int32_t cellY, std::vector<bool> Condition)
{
if (api.GridToCell(api.GetSelfInfo()->x) == cellX && api.GridToCell(api.GetSelfInfo()->y) == cellY)
Way = { {} };
else
Way = FindWay::findPath(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), cellX, cellY, Condition, api);
if (Way.empty())
{
Unset();
return false;
}
Going = true;
DestinationX = cellX;
DestinationY = cellY;
StepNumber = Way.size();//size-1是最大可访问下表
ThisStep = 0;//从0到size-1
ThisCondition = Condition;
LastGridX = -1;
LastGridY = -1;
return true;
}

void Unset()
{
Going = false;
DestinationX = -1;
DestinationY = -1;
Way = { {} };
StepNumber = 0;
ThisStep = 0;
LastGridX = -1;
LastGridY = -1;
}

void Update()
{
if (!Going)
return;
if (ThisStep >= Way.size() - 1)
{
Unset();
return;
}
return;
}

bool MoveAStep()
{
Update();
if (!Going||Way.empty())
{
Unset();
return false;
}
else
{
if ((LastGridX != -1 && Distance(LastGridX, LastGridY, api.GetSelfInfo()->x, api.GetSelfInfo()->y) < 20)
|| abs(Way[ThisStep + 1][0] - api.GridToCell(api.GetSelfInfo()->x)) + abs(Way[ThisStep + 1][1] - api.GridToCell(api.GetSelfInfo()->y)) > 5)
{
SetDestination(DestinationX, DestinationY, Condition1);
return false;
}
auto p = MoveToNextBlock(api, Way[ThisStep + 1][0], Way[ThisStep + 1][1]);
if (!p[0])
ThisStep++;
LastGridX = api.GetSelfInfo()->x;
LastGridY = api.GetSelfInfo()->y;
Update();
return true;
}
}

bool IfDone()
{
Update();
return !Going;
}
};
}

}

namespace Homework
{
struct Homework
{

int32_t x = -1;
int32_t y = -1;//cell
int32_t Progress = 0;
bool IfBeingDone = false;//待实现
Homework() :x(-1), y(-1), Progress(0), IfBeingDone(false) {}
};

enum class Direction
{
Left = 0,
Right = 1,
Up = 2,
Down = 3,
LeftUp = 4,
LeftDown = 5,
RightUp = 6,
RightDown = 7
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework);

class GoToNearestHomework :public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
Homework ThisHomework;
public:
GoToNearestHomework(IStudentAPI& _api) :
GoToAPlace(_api), ThisHomework() {}

GoToNearestHomework& operator=(GoToNearestHomework P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
ThisHomework = Homework();
return (*this);
}

Homework FindTheNearestHomework()//考虑实现对于多人走向同一份作业的规避,目前未实现
{
Homework NearestHomework;
int32_t DistanceOfTheNearestHomework = -1;
int32_t NumberOfTheNearestHomework = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 10; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), HomeworkLocations[i][0], HomeworkLocations[i][1], { false,true,false,true,true,false,false,false,true,true,true,false }, api).size();
if (i == 0)
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
else if (D < DistanceOfTheNearestHomework && api.GetClassroomProgress(HomeworkLocations[i][0], HomeworkLocations[i][1]) < 10000000)//待实现无人正在写
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
}
if (NumberOfTheNearestHomework != -1)
{
NearestHomework.x = HomeworkLocations[NumberOfTheNearestHomework][0];
NearestHomework.y = HomeworkLocations[NumberOfTheNearestHomework][1];
NearestHomework.Progress = api.GetClassroomProgress(NearestHomework.x, NearestHomework.y);
}
return NearestHomework;
}

std::vector<bool> MoveAStepToNearestHomework(Direction ThisDirection)//第一个位置返回是否有最近作业,第二个位置返回是否成功
{
if (ThisHomework.x == -1)
return { false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
auto a = MoveAStep();
return { true, a };
}

void UnsetHomework()
{
ThisHomework = Homework();
}

std::vector<bool> FindAndDo(Direction ThisDirection = Direction::Right)//是否找到,是否赶到,是否完成
{
if (api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
{
UnsetHomework();
Unset();
}
if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
if (ThisHomework.x == -1)
return { false,false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
}
/*if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
SetDestination(ThisHomework.x, ThisHomework.y + 1);
}*/
//MoveAStep();
if (!IfDone())
{
MoveAStep();
return { true,false,false };
}
else
{
Unset();
auto a = DoHomework(api, ThisHomework);
return{ true,true,!a };
}
}
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework)
{
auto self = api.GetSelfInfo();
if (abs(api.GridToCell(self->x) - ThisHomework.x) > 1 || abs(api.GridToCell(self->y) - ThisHomework.y) > 1 || api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
return false;
auto State = api.StartLearning();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
return true;
}
}


namespace Grass
{
class MoveToGrass : public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
bool Escaping = false;
public:
MoveToGrass(IStudentAPI& _api) :
GoToAPlace(_api), Escaping(false) {}

MoveToGrass& operator=(MoveToGrass P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
Escaping = false;
return (*this);
}

std::vector<int32_t> FindTheNearestGrass()
{
int32_t DistanceOfTheNearestGrass = -1;
int32_t NumberOfTheNearestGrass = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 13; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), GrassLocations[i][0], GrassLocations[i][1], Condition1, api).size();
if (i == 0)
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
else if (D < DistanceOfTheNearestGrass)//待实现无人正在写
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
}
return { GrassLocations[NumberOfTheNearestGrass][0],GrassLocations[NumberOfTheNearestGrass][1] };
}

void FindAndGo()
{
if (!Escaping)
{
auto p = FindTheNearestGrass();
SetDestination(p[0], p[1], Condition1);
Escaping = true;
}
else
if (!IfDone())
{
MoveAStep();
return;
}
else
{
return;
}
}

void StopEscape()
{
Escaping = false;
}
};
}


void AI::play(IStudentAPI& api)
{
// 公共操作
static std::vector<std::vector<int>> a{ {24,6},{15,6},{15,17},{24,17} };

if (this->playerID == 0)//三教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家0执行操作
}
else if (this->playerID == 1)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
//玩家1执行操作
}
else if (this->playerID == 2)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家2执行操作
}
else if (this->playerID == 3)//六教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 772
- 0
players/京ICP备2022019669号-1 2022 EESAST/player2.cpp View File

@@ -0,0 +1,772 @@
//四学霸策略

#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"
#include "API.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType =
{
THUAI6::StudentType::StraightAStudent ,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数

//全局变量
int32_t HomeworkLocations[10][2]{ {8,31},{18,5},{10,38},{19,41},{22,18},{28,26},{30,7},{33,40},{40,12},{44,32}};
int32_t GrassLocations[13][2]{ {8,2},{8,16},{5,25},{4,29},{10,46},{18,46},{20,36},{15,29},{20,1},{30,25},{40,24},{39,35},{46,8} };

bool IfResetDestination = true;

std::vector<bool> Condition1 = { false, true, false, true, false, false, false, false, true ,true ,true, false };//门都可以,草地,land可以



namespace MoveFunc
{
int32_t Distance(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return int32_t(sqrt((gridX0 - gridX1) * (gridX0 - gridX1) + (gridY0 - gridY1) * (gridY0 - gridY1)));
}

//角度为0指向1
double Angle(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return atan2(gridY1 - gridY0, gridX1 - gridX0);
}

namespace FindWay
{

int IfAchievable(THUAI6::PlaceType ThisPlace, std::vector<bool> Condition)
{
//是否可以通过的条件可以进一步完善
if ((ThisPlace == THUAI6::PlaceType::NullPlaceType && Condition[0])
|| (ThisPlace == THUAI6::PlaceType::Land && Condition[1])
|| (ThisPlace == THUAI6::PlaceType::Wall && Condition[2])
|| (ThisPlace == THUAI6::PlaceType::Grass && Condition[3])
|| (ThisPlace == THUAI6::PlaceType::ClassRoom && Condition[4])
|| (ThisPlace == THUAI6::PlaceType::Gate && Condition[5])
|| (ThisPlace == THUAI6::PlaceType::HiddenGate && Condition[6])
|| (ThisPlace == THUAI6::PlaceType::Window && Condition[7])
|| (ThisPlace == THUAI6::PlaceType::Door3 && Condition[8])
|| (ThisPlace == THUAI6::PlaceType::Door5 && Condition[9])
|| (ThisPlace == THUAI6::PlaceType::Door6 && Condition[10])
|| (ThisPlace == THUAI6::PlaceType::Chest && Condition[11]))
return 0;
else
return 1;//1不可达
}

const int kCost1 = 10; //直移一格消耗
const int kCost2 = 14; //斜移一格消耗

struct Point
{
int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列
int F, G, H; //F=G+H
Point* parent; //parent的坐标,这里没有用指针,从而简化代码
Point(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL) //变量初始化
{
}
};

class Astar
{
public:
void InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& api);
std::list<Point*> GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<bool> ThisCondition;
Astar(IStudentAPI& _api) :
maze({ {} }), api(_api), openList({}), closeList({}) {}

private:
Point* findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<Point*> getSurroundPoints(const Point* point, bool isIgnoreCorner) const;
bool isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断
Point* isInList(const std::list<Point*>& list, const Point* point) const; //判断开启/关闭列表中是否包含某点
Point* getLeastFpoint(); //从开启列表中返回F值最小的节点
//计算FGH值
int calcG(Point* temp_start, Point* point);
int calcH(Point* point, Point* end);
int calcF(Point* point);
private:
std::vector<std::vector<THUAI6::PlaceType>> maze;
std::list<Point*> openList; //开启列表
std::list<Point*> closeList; //关闭列表
IStudentAPI& api;
};




void Astar::InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& _api)
{
maze = _maze;
ThisCondition = Condition;
api = _api;
}

int Astar::calcG(Point* temp_start, Point* point)
{
int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空
return parentG + extraG;
}

int Astar::calcH(Point* point, Point* end)
{
//用简单的欧几里得距离计算H,这个H的计算是关键,还有很多算法,没深入研究^_^
return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calcF(Point* point)
{
return point->G + point->H;
}

Point* Astar::getLeastFpoint()
{
if (!openList.empty())
{
auto resPoint = openList.front();
for (auto& point : openList)
if (point->F < resPoint->F)
resPoint = point;
return resPoint;
}
return NULL;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
openList.push_back(new Point(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离
while (!openList.empty())
{
auto curPoint = getLeastFpoint(); //找到F值最小的点
openList.remove(curPoint); //从开启列表中删除
closeList.push_back(curPoint); //放到关闭列表
//1,找到当前周围八个格中可以通过的格子
auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
for (auto& target : surroundPoints)
{
//2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H
if (!isInList(openList, target))
{
target->parent = curPoint;

target->G = calcG(curPoint, target);
target->H = calcH(target, &endPoint);
target->F = calcF(target);

openList.push_back(target);
}
//3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
else
{
int tempG = calcG(curPoint, target);
if (tempG < target->G)
{
target->parent = curPoint;

target->G = tempG;
target->F = calcF(target);
}
}
Point* resPoint = isInList(openList, &endPoint);
if (resPoint)
return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝
}
}

return NULL;
}

std::list<Point*> Astar::GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
Point* result = findPath(startPoint, endPoint, isIgnoreCorner);
std::list<Point*> path;
//返回路径,如果没找到路径,返回空链表
while (result)
{
path.push_front(result);
result = result->parent;
}

// 清空临时开闭列表,防止重复执行GetPath导致结果异常
openList.clear();
closeList.clear();

return path;
}

Point* Astar::isInList(const std::list<Point*>& list, const Point* point) const
{
//判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标
for (auto p : list)
if (p->x == point->x && p->y == point->y)
return p;
return NULL;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
if ((target->x==api.GridToCell(api.GetSelfInfo()->x)&& target->y == api.GridToCell(api.GetSelfInfo()->y))
||target->x<0 || target->x>maze.size() - 1
|| target->y<0 || target->y>maze[0].size() - 1
|| IfAchievable(maze[target->x][target->y], ThisCondition) == 1
|| target->x == point->x && target->y == point->y
|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
return false;
else
{
if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以
return true;
else
{
//斜对角要判断是否绊住
if (IfAchievable(maze[point->x][target->y], ThisCondition) == 0 && IfAchievable(maze[target->x][point->y], ThisCondition) == 0)
return true;
else
return isIgnoreCorner;
}
}
}

std::vector<Point*> Astar::getSurroundPoints(const Point* point, bool isIgnoreCorner) const
{
std::vector<Point*> surroundPoints;

for (int x = point->x - 1; x <= point->x + 1; x++)
for (int y = point->y - 1; y <= point->y + 1; y++)
if (isCanreach(point, new Point(x, y), isIgnoreCorner))
surroundPoints.push_back(new Point(x, y));

return surroundPoints;
}


bool InPath(const int& row, const int& col, const std::list<Point*>& path) {
for (const auto& p : path) {
if (row == p->x && col == p->y) {
return true;
}
}
return false;
}

std::vector<std::vector<int32_t>> findPath(const std::vector<std::vector<THUAI6::PlaceType>>& map, int32_t cellX0, int32_t cellY0, int32_t cellX1, int32_t cellY1, std::vector<bool> Condition, IStudentAPI& api)
{
Astar astar(api);
astar.InitAstar(map, Condition,api);
Point start(cellX0, cellY0);
Point end(cellX1, cellY1);
std::list<Point*> path = astar.GetPath(start, end, false);
std::vector<std::vector<int>> result{};
for (auto P : path)
{
std::vector<int> Loc{ P->x,P->y };
result.push_back(Loc);
}
return result;
}

}

namespace GoToSomePlace
{
std::vector<bool> MoveToNextBlock(IStudentAPI& api, int32_t cellX, int32_t cellY)
{
auto self = api.GetSelfInfo();
if (Distance(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)) < 50)//可以调整
return { false,true };
auto p = api.Move(50, Angle(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
if (!p.get())
return { false,false };
return { true,true };
}//可以修改移动时间
//不检查是否可达,谨慎使用

class GoToAPlace
{
protected:
bool Going = false;//是否正在走
int32_t DestinationX = -1;//cell
int32_t DestinationY = -1;
std::vector<std::vector<int32_t>> Way{ {} };//没吃到
int32_t StepNumber = 0;
int32_t ThisStep = 0;
IStudentAPI& api;
std::vector<bool> ThisCondition;
int32_t LastGridX=-1;
int32_t LastGridY=-1;

public:
GoToAPlace(IStudentAPI& _api) :
Going(false), DestinationX(-1), DestinationY(-1), LastGridX(-1), LastGridY(-1), api(_api), StepNumber(0), ThisStep(0), Way({}), ThisCondition{ {} } {}

GoToAPlace& operator =(GoToAPlace P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way={ {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api=P.api;
ThisCondition=P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
return (*this);
}

bool SetDestination(int32_t cellX, int32_t cellY, std::vector<bool> Condition)
{
if (api.GridToCell(api.GetSelfInfo()->x) == cellX && api.GridToCell(api.GetSelfInfo()->y) == cellY)
Way = { {} };
else
Way = FindWay::findPath(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), cellX, cellY, Condition, api);
if (Way.empty())
{
Unset();
return false;
}
Going = true;
DestinationX = cellX;
DestinationY = cellY;
StepNumber = Way.size();//size-1是最大可访问下表
ThisStep = 0;//从0到size-1
ThisCondition = Condition;
LastGridX = -1;
LastGridY = -1;
return true;
}

void Unset()
{
Going = false;
DestinationX = -1;
DestinationY = -1;
Way = { {} };
StepNumber = 0;
ThisStep = 0;
LastGridX = -1;
LastGridY = -1;
}

void Update()
{
if (!Going)
return;
if (ThisStep >= Way.size() - 1)
{
Unset();
return;
}
return;
}

bool MoveAStep()
{
Update();
if (!Going||Way.empty())
{
Unset();
return false;
}
else
{
if ((LastGridX != -1 && Distance(LastGridX, LastGridY, api.GetSelfInfo()->x, api.GetSelfInfo()->y) < 20)
|| abs(Way[ThisStep + 1][0] - api.GridToCell(api.GetSelfInfo()->x)) + abs(Way[ThisStep + 1][1] - api.GridToCell(api.GetSelfInfo()->y)) > 5)
{
SetDestination(DestinationX, DestinationY, Condition1);
return false;
}
auto p = MoveToNextBlock(api, Way[ThisStep + 1][0], Way[ThisStep + 1][1]);
if (!p[0])
ThisStep++;
LastGridX = api.GetSelfInfo()->x;
LastGridY = api.GetSelfInfo()->y;
Update();
return true;
}
}

bool IfDone()
{
Update();
return !Going;
}
};
}

}

namespace Homework
{
struct Homework
{

int32_t x = -1;
int32_t y = -1;//cell
int32_t Progress = 0;
bool IfBeingDone = false;//待实现
Homework() :x(-1), y(-1), Progress(0), IfBeingDone(false) {}
};

enum class Direction
{
Left = 0,
Right = 1,
Up = 2,
Down = 3,
LeftUp = 4,
LeftDown = 5,
RightUp = 6,
RightDown = 7
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework);

class GoToNearestHomework :public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
Homework ThisHomework;
public:
GoToNearestHomework(IStudentAPI& _api) :
GoToAPlace(_api), ThisHomework() {}

GoToNearestHomework& operator=(GoToNearestHomework P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
ThisHomework = Homework();
return (*this);
}

Homework FindTheNearestHomework()//考虑实现对于多人走向同一份作业的规避,目前未实现
{
Homework NearestHomework;
int32_t DistanceOfTheNearestHomework = -1;
int32_t NumberOfTheNearestHomework = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 10; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), HomeworkLocations[i][0], HomeworkLocations[i][1], { false,true,false,true,true,false,false,false,true,true,true,false }, api).size();
if (i == 0)
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
else if (D < DistanceOfTheNearestHomework && api.GetClassroomProgress(HomeworkLocations[i][0], HomeworkLocations[i][1]) < 10000000)//待实现无人正在写
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
}
if (NumberOfTheNearestHomework != -1)
{
NearestHomework.x = HomeworkLocations[NumberOfTheNearestHomework][0];
NearestHomework.y = HomeworkLocations[NumberOfTheNearestHomework][1];
NearestHomework.Progress = api.GetClassroomProgress(NearestHomework.x, NearestHomework.y);
}
return NearestHomework;
}

std::vector<bool> MoveAStepToNearestHomework(Direction ThisDirection)//第一个位置返回是否有最近作业,第二个位置返回是否成功
{
if (ThisHomework.x == -1)
return { false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
auto a = MoveAStep();
return { true, a };
}

void UnsetHomework()
{
ThisHomework = Homework();
}

std::vector<bool> FindAndDo(Direction ThisDirection = Direction::Right)//是否找到,是否赶到,是否完成
{
if (api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
{
UnsetHomework();
Unset();
}
if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
if (ThisHomework.x == -1)
return { false,false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
}
/*if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
SetDestination(ThisHomework.x, ThisHomework.y + 1);
}*/
//MoveAStep();
if (!IfDone())
{
MoveAStep();
return { true,false,false };
}
else
{
Unset();
auto a = DoHomework(api, ThisHomework);
return{ true,true,!a };
}
}
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework)
{
auto self = api.GetSelfInfo();
if (abs(api.GridToCell(self->x) - ThisHomework.x) > 1 || abs(api.GridToCell(self->y) - ThisHomework.y) > 1 || api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
return false;
auto State = api.StartLearning();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
return true;
}
}


namespace Grass
{
class MoveToGrass : public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
bool Escaping = false;
public:
MoveToGrass(IStudentAPI& _api) :
GoToAPlace(_api), Escaping(false) {}

MoveToGrass& operator=(MoveToGrass P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
Escaping = false;
return (*this);
}

std::vector<int32_t> FindTheNearestGrass()
{
int32_t DistanceOfTheNearestGrass = -1;
int32_t NumberOfTheNearestGrass = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 13; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), GrassLocations[i][0], GrassLocations[i][1], Condition1, api).size();
if (i == 0)
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
else if (D < DistanceOfTheNearestGrass)//待实现无人正在写
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
}
return { GrassLocations[NumberOfTheNearestGrass][0],GrassLocations[NumberOfTheNearestGrass][1] };
}

void FindAndGo()
{
if (!Escaping)
{
auto p = FindTheNearestGrass();
SetDestination(p[0], p[1], Condition1);
Escaping = true;
}
else
if (!IfDone())
{
MoveAStep();
return;
}
else
{
return;
}
}

void StopEscape()
{
Escaping = false;
}
};
}


void AI::play(IStudentAPI& api)
{
// 公共操作
static std::vector<std::vector<int>> a{ {24,6},{15,6},{15,17},{24,17} };

if (this->playerID == 0)//三教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家0执行操作
}
else if (this->playerID == 1)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
//玩家1执行操作
}
else if (this->playerID == 2)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家2执行操作
}
else if (this->playerID == 3)//六教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 772
- 0
players/京ICP备2022019669号-1 2022 EESAST/player3.cpp View File

@@ -0,0 +1,772 @@
//四学霸策略

#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"
#include "API.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType =
{
THUAI6::StudentType::StraightAStudent ,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数

//全局变量
int32_t HomeworkLocations[10][2]{ {8,31},{18,5},{10,38},{19,41},{22,18},{28,26},{30,7},{33,40},{40,12},{44,32}};
int32_t GrassLocations[13][2]{ {8,2},{8,16},{5,25},{4,29},{10,46},{18,46},{20,36},{15,29},{20,1},{30,25},{40,24},{39,35},{46,8} };

bool IfResetDestination = true;

std::vector<bool> Condition1 = { false, true, false, true, false, false, false, false, true ,true ,true, false };//门都可以,草地,land可以



namespace MoveFunc
{
int32_t Distance(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return int32_t(sqrt((gridX0 - gridX1) * (gridX0 - gridX1) + (gridY0 - gridY1) * (gridY0 - gridY1)));
}

//角度为0指向1
double Angle(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return atan2(gridY1 - gridY0, gridX1 - gridX0);
}

namespace FindWay
{

int IfAchievable(THUAI6::PlaceType ThisPlace, std::vector<bool> Condition)
{
//是否可以通过的条件可以进一步完善
if ((ThisPlace == THUAI6::PlaceType::NullPlaceType && Condition[0])
|| (ThisPlace == THUAI6::PlaceType::Land && Condition[1])
|| (ThisPlace == THUAI6::PlaceType::Wall && Condition[2])
|| (ThisPlace == THUAI6::PlaceType::Grass && Condition[3])
|| (ThisPlace == THUAI6::PlaceType::ClassRoom && Condition[4])
|| (ThisPlace == THUAI6::PlaceType::Gate && Condition[5])
|| (ThisPlace == THUAI6::PlaceType::HiddenGate && Condition[6])
|| (ThisPlace == THUAI6::PlaceType::Window && Condition[7])
|| (ThisPlace == THUAI6::PlaceType::Door3 && Condition[8])
|| (ThisPlace == THUAI6::PlaceType::Door5 && Condition[9])
|| (ThisPlace == THUAI6::PlaceType::Door6 && Condition[10])
|| (ThisPlace == THUAI6::PlaceType::Chest && Condition[11]))
return 0;
else
return 1;//1不可达
}

const int kCost1 = 10; //直移一格消耗
const int kCost2 = 14; //斜移一格消耗

struct Point
{
int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列
int F, G, H; //F=G+H
Point* parent; //parent的坐标,这里没有用指针,从而简化代码
Point(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL) //变量初始化
{
}
};

class Astar
{
public:
void InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& api);
std::list<Point*> GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<bool> ThisCondition;
Astar(IStudentAPI& _api) :
maze({ {} }), api(_api), openList({}), closeList({}) {}

private:
Point* findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<Point*> getSurroundPoints(const Point* point, bool isIgnoreCorner) const;
bool isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断
Point* isInList(const std::list<Point*>& list, const Point* point) const; //判断开启/关闭列表中是否包含某点
Point* getLeastFpoint(); //从开启列表中返回F值最小的节点
//计算FGH值
int calcG(Point* temp_start, Point* point);
int calcH(Point* point, Point* end);
int calcF(Point* point);
private:
std::vector<std::vector<THUAI6::PlaceType>> maze;
std::list<Point*> openList; //开启列表
std::list<Point*> closeList; //关闭列表
IStudentAPI& api;
};




void Astar::InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& _api)
{
maze = _maze;
ThisCondition = Condition;
api = _api;
}

int Astar::calcG(Point* temp_start, Point* point)
{
int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空
return parentG + extraG;
}

int Astar::calcH(Point* point, Point* end)
{
//用简单的欧几里得距离计算H,这个H的计算是关键,还有很多算法,没深入研究^_^
return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calcF(Point* point)
{
return point->G + point->H;
}

Point* Astar::getLeastFpoint()
{
if (!openList.empty())
{
auto resPoint = openList.front();
for (auto& point : openList)
if (point->F < resPoint->F)
resPoint = point;
return resPoint;
}
return NULL;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
openList.push_back(new Point(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离
while (!openList.empty())
{
auto curPoint = getLeastFpoint(); //找到F值最小的点
openList.remove(curPoint); //从开启列表中删除
closeList.push_back(curPoint); //放到关闭列表
//1,找到当前周围八个格中可以通过的格子
auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
for (auto& target : surroundPoints)
{
//2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H
if (!isInList(openList, target))
{
target->parent = curPoint;

target->G = calcG(curPoint, target);
target->H = calcH(target, &endPoint);
target->F = calcF(target);

openList.push_back(target);
}
//3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
else
{
int tempG = calcG(curPoint, target);
if (tempG < target->G)
{
target->parent = curPoint;

target->G = tempG;
target->F = calcF(target);
}
}
Point* resPoint = isInList(openList, &endPoint);
if (resPoint)
return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝
}
}

return NULL;
}

std::list<Point*> Astar::GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
Point* result = findPath(startPoint, endPoint, isIgnoreCorner);
std::list<Point*> path;
//返回路径,如果没找到路径,返回空链表
while (result)
{
path.push_front(result);
result = result->parent;
}

// 清空临时开闭列表,防止重复执行GetPath导致结果异常
openList.clear();
closeList.clear();

return path;
}

Point* Astar::isInList(const std::list<Point*>& list, const Point* point) const
{
//判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标
for (auto p : list)
if (p->x == point->x && p->y == point->y)
return p;
return NULL;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
if ((target->x==api.GridToCell(api.GetSelfInfo()->x)&& target->y == api.GridToCell(api.GetSelfInfo()->y))
||target->x<0 || target->x>maze.size() - 1
|| target->y<0 || target->y>maze[0].size() - 1
|| IfAchievable(maze[target->x][target->y], ThisCondition) == 1
|| target->x == point->x && target->y == point->y
|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
return false;
else
{
if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以
return true;
else
{
//斜对角要判断是否绊住
if (IfAchievable(maze[point->x][target->y], ThisCondition) == 0 && IfAchievable(maze[target->x][point->y], ThisCondition) == 0)
return true;
else
return isIgnoreCorner;
}
}
}

std::vector<Point*> Astar::getSurroundPoints(const Point* point, bool isIgnoreCorner) const
{
std::vector<Point*> surroundPoints;

for (int x = point->x - 1; x <= point->x + 1; x++)
for (int y = point->y - 1; y <= point->y + 1; y++)
if (isCanreach(point, new Point(x, y), isIgnoreCorner))
surroundPoints.push_back(new Point(x, y));

return surroundPoints;
}


bool InPath(const int& row, const int& col, const std::list<Point*>& path) {
for (const auto& p : path) {
if (row == p->x && col == p->y) {
return true;
}
}
return false;
}

std::vector<std::vector<int32_t>> findPath(const std::vector<std::vector<THUAI6::PlaceType>>& map, int32_t cellX0, int32_t cellY0, int32_t cellX1, int32_t cellY1, std::vector<bool> Condition, IStudentAPI& api)
{
Astar astar(api);
astar.InitAstar(map, Condition,api);
Point start(cellX0, cellY0);
Point end(cellX1, cellY1);
std::list<Point*> path = astar.GetPath(start, end, false);
std::vector<std::vector<int>> result{};
for (auto P : path)
{
std::vector<int> Loc{ P->x,P->y };
result.push_back(Loc);
}
return result;
}

}

namespace GoToSomePlace
{
std::vector<bool> MoveToNextBlock(IStudentAPI& api, int32_t cellX, int32_t cellY)
{
auto self = api.GetSelfInfo();
if (Distance(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)) < 50)//可以调整
return { false,true };
auto p = api.Move(50, Angle(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
if (!p.get())
return { false,false };
return { true,true };
}//可以修改移动时间
//不检查是否可达,谨慎使用

class GoToAPlace
{
protected:
bool Going = false;//是否正在走
int32_t DestinationX = -1;//cell
int32_t DestinationY = -1;
std::vector<std::vector<int32_t>> Way{ {} };//没吃到
int32_t StepNumber = 0;
int32_t ThisStep = 0;
IStudentAPI& api;
std::vector<bool> ThisCondition;
int32_t LastGridX=-1;
int32_t LastGridY=-1;

public:
GoToAPlace(IStudentAPI& _api) :
Going(false), DestinationX(-1), DestinationY(-1), LastGridX(-1), LastGridY(-1), api(_api), StepNumber(0), ThisStep(0), Way({}), ThisCondition{ {} } {}

GoToAPlace& operator =(GoToAPlace P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way={ {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api=P.api;
ThisCondition=P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
return (*this);
}

bool SetDestination(int32_t cellX, int32_t cellY, std::vector<bool> Condition)
{
if (api.GridToCell(api.GetSelfInfo()->x) == cellX && api.GridToCell(api.GetSelfInfo()->y) == cellY)
Way = { {} };
else
Way = FindWay::findPath(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), cellX, cellY, Condition, api);
if (Way.empty())
{
Unset();
return false;
}
Going = true;
DestinationX = cellX;
DestinationY = cellY;
StepNumber = Way.size();//size-1是最大可访问下表
ThisStep = 0;//从0到size-1
ThisCondition = Condition;
LastGridX = -1;
LastGridY = -1;
return true;
}

void Unset()
{
Going = false;
DestinationX = -1;
DestinationY = -1;
Way = { {} };
StepNumber = 0;
ThisStep = 0;
LastGridX = -1;
LastGridY = -1;
}

void Update()
{
if (!Going)
return;
if (ThisStep >= Way.size() - 1)
{
Unset();
return;
}
return;
}

bool MoveAStep()
{
Update();
if (!Going||Way.empty())
{
Unset();
return false;
}
else
{
if ((LastGridX != -1 && Distance(LastGridX, LastGridY, api.GetSelfInfo()->x, api.GetSelfInfo()->y) < 20)
|| abs(Way[ThisStep + 1][0] - api.GridToCell(api.GetSelfInfo()->x)) + abs(Way[ThisStep + 1][1] - api.GridToCell(api.GetSelfInfo()->y)) > 5)
{
SetDestination(DestinationX, DestinationY, Condition1);
return false;
}
auto p = MoveToNextBlock(api, Way[ThisStep + 1][0], Way[ThisStep + 1][1]);
if (!p[0])
ThisStep++;
LastGridX = api.GetSelfInfo()->x;
LastGridY = api.GetSelfInfo()->y;
Update();
return true;
}
}

bool IfDone()
{
Update();
return !Going;
}
};
}

}

namespace Homework
{
struct Homework
{

int32_t x = -1;
int32_t y = -1;//cell
int32_t Progress = 0;
bool IfBeingDone = false;//待实现
Homework() :x(-1), y(-1), Progress(0), IfBeingDone(false) {}
};

enum class Direction
{
Left = 0,
Right = 1,
Up = 2,
Down = 3,
LeftUp = 4,
LeftDown = 5,
RightUp = 6,
RightDown = 7
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework);

class GoToNearestHomework :public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
Homework ThisHomework;
public:
GoToNearestHomework(IStudentAPI& _api) :
GoToAPlace(_api), ThisHomework() {}

GoToNearestHomework& operator=(GoToNearestHomework P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
ThisHomework = Homework();
return (*this);
}

Homework FindTheNearestHomework()//考虑实现对于多人走向同一份作业的规避,目前未实现
{
Homework NearestHomework;
int32_t DistanceOfTheNearestHomework = -1;
int32_t NumberOfTheNearestHomework = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 10; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), HomeworkLocations[i][0], HomeworkLocations[i][1], { false,true,false,true,true,false,false,false,true,true,true,false }, api).size();
if (i == 0)
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
else if (D < DistanceOfTheNearestHomework && api.GetClassroomProgress(HomeworkLocations[i][0], HomeworkLocations[i][1]) < 10000000)//待实现无人正在写
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
}
if (NumberOfTheNearestHomework != -1)
{
NearestHomework.x = HomeworkLocations[NumberOfTheNearestHomework][0];
NearestHomework.y = HomeworkLocations[NumberOfTheNearestHomework][1];
NearestHomework.Progress = api.GetClassroomProgress(NearestHomework.x, NearestHomework.y);
}
return NearestHomework;
}

std::vector<bool> MoveAStepToNearestHomework(Direction ThisDirection)//第一个位置返回是否有最近作业,第二个位置返回是否成功
{
if (ThisHomework.x == -1)
return { false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
auto a = MoveAStep();
return { true, a };
}

void UnsetHomework()
{
ThisHomework = Homework();
}

std::vector<bool> FindAndDo(Direction ThisDirection = Direction::Right)//是否找到,是否赶到,是否完成
{
if (api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
{
UnsetHomework();
Unset();
}
if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
if (ThisHomework.x == -1)
return { false,false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
}
/*if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
SetDestination(ThisHomework.x, ThisHomework.y + 1);
}*/
//MoveAStep();
if (!IfDone())
{
MoveAStep();
return { true,false,false };
}
else
{
Unset();
auto a = DoHomework(api, ThisHomework);
return{ true,true,!a };
}
}
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework)
{
auto self = api.GetSelfInfo();
if (abs(api.GridToCell(self->x) - ThisHomework.x) > 1 || abs(api.GridToCell(self->y) - ThisHomework.y) > 1 || api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
return false;
auto State = api.StartLearning();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
return true;
}
}


namespace Grass
{
class MoveToGrass : public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
bool Escaping = false;
public:
MoveToGrass(IStudentAPI& _api) :
GoToAPlace(_api), Escaping(false) {}

MoveToGrass& operator=(MoveToGrass P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
Escaping = false;
return (*this);
}

std::vector<int32_t> FindTheNearestGrass()
{
int32_t DistanceOfTheNearestGrass = -1;
int32_t NumberOfTheNearestGrass = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 13; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), GrassLocations[i][0], GrassLocations[i][1], Condition1, api).size();
if (i == 0)
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
else if (D < DistanceOfTheNearestGrass)//待实现无人正在写
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
}
return { GrassLocations[NumberOfTheNearestGrass][0],GrassLocations[NumberOfTheNearestGrass][1] };
}

void FindAndGo()
{
if (!Escaping)
{
auto p = FindTheNearestGrass();
SetDestination(p[0], p[1], Condition1);
Escaping = true;
}
else
if (!IfDone())
{
MoveAStep();
return;
}
else
{
return;
}
}

void StopEscape()
{
Escaping = false;
}
};
}


void AI::play(IStudentAPI& api)
{
// 公共操作
static std::vector<std::vector<int>> a{ {24,6},{15,6},{15,17},{24,17} };

if (this->playerID == 0)//三教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家0执行操作
}
else if (this->playerID == 1)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
//玩家1执行操作
}
else if (this->playerID == 2)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家2执行操作
}
else if (this->playerID == 3)//六教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 772
- 0
players/京ICP备2022019669号-1 2022 EESAST/player4.cpp View File

@@ -0,0 +1,772 @@
//四学霸策略

#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"
#include "API.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType =
{
THUAI6::StudentType::StraightAStudent ,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数

//全局变量
int32_t HomeworkLocations[10][2]{ {8,31},{18,5},{10,38},{19,41},{22,18},{28,26},{30,7},{33,40},{40,12},{44,32}};
int32_t GrassLocations[13][2]{ {8,2},{8,16},{5,25},{4,29},{10,46},{18,46},{20,36},{15,29},{20,1},{30,25},{40,24},{39,35},{46,8} };

bool IfResetDestination = true;

std::vector<bool> Condition1 = { false, true, false, true, false, false, false, false, true ,true ,true, false };//门都可以,草地,land可以



namespace MoveFunc
{
int32_t Distance(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return int32_t(sqrt((gridX0 - gridX1) * (gridX0 - gridX1) + (gridY0 - gridY1) * (gridY0 - gridY1)));
}

//角度为0指向1
double Angle(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return atan2(gridY1 - gridY0, gridX1 - gridX0);
}

namespace FindWay
{

int IfAchievable(THUAI6::PlaceType ThisPlace, std::vector<bool> Condition)
{
//是否可以通过的条件可以进一步完善
if ((ThisPlace == THUAI6::PlaceType::NullPlaceType && Condition[0])
|| (ThisPlace == THUAI6::PlaceType::Land && Condition[1])
|| (ThisPlace == THUAI6::PlaceType::Wall && Condition[2])
|| (ThisPlace == THUAI6::PlaceType::Grass && Condition[3])
|| (ThisPlace == THUAI6::PlaceType::ClassRoom && Condition[4])
|| (ThisPlace == THUAI6::PlaceType::Gate && Condition[5])
|| (ThisPlace == THUAI6::PlaceType::HiddenGate && Condition[6])
|| (ThisPlace == THUAI6::PlaceType::Window && Condition[7])
|| (ThisPlace == THUAI6::PlaceType::Door3 && Condition[8])
|| (ThisPlace == THUAI6::PlaceType::Door5 && Condition[9])
|| (ThisPlace == THUAI6::PlaceType::Door6 && Condition[10])
|| (ThisPlace == THUAI6::PlaceType::Chest && Condition[11]))
return 0;
else
return 1;//1不可达
}

const int kCost1 = 10; //直移一格消耗
const int kCost2 = 14; //斜移一格消耗

struct Point
{
int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列
int F, G, H; //F=G+H
Point* parent; //parent的坐标,这里没有用指针,从而简化代码
Point(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL) //变量初始化
{
}
};

class Astar
{
public:
void InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& api);
std::list<Point*> GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<bool> ThisCondition;
Astar(IStudentAPI& _api) :
maze({ {} }), api(_api), openList({}), closeList({}) {}

private:
Point* findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<Point*> getSurroundPoints(const Point* point, bool isIgnoreCorner) const;
bool isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断
Point* isInList(const std::list<Point*>& list, const Point* point) const; //判断开启/关闭列表中是否包含某点
Point* getLeastFpoint(); //从开启列表中返回F值最小的节点
//计算FGH值
int calcG(Point* temp_start, Point* point);
int calcH(Point* point, Point* end);
int calcF(Point* point);
private:
std::vector<std::vector<THUAI6::PlaceType>> maze;
std::list<Point*> openList; //开启列表
std::list<Point*> closeList; //关闭列表
IStudentAPI& api;
};




void Astar::InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, IStudentAPI& _api)
{
maze = _maze;
ThisCondition = Condition;
api = _api;
}

int Astar::calcG(Point* temp_start, Point* point)
{
int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空
return parentG + extraG;
}

int Astar::calcH(Point* point, Point* end)
{
//用简单的欧几里得距离计算H,这个H的计算是关键,还有很多算法,没深入研究^_^
return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calcF(Point* point)
{
return point->G + point->H;
}

Point* Astar::getLeastFpoint()
{
if (!openList.empty())
{
auto resPoint = openList.front();
for (auto& point : openList)
if (point->F < resPoint->F)
resPoint = point;
return resPoint;
}
return NULL;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
openList.push_back(new Point(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离
while (!openList.empty())
{
auto curPoint = getLeastFpoint(); //找到F值最小的点
openList.remove(curPoint); //从开启列表中删除
closeList.push_back(curPoint); //放到关闭列表
//1,找到当前周围八个格中可以通过的格子
auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
for (auto& target : surroundPoints)
{
//2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H
if (!isInList(openList, target))
{
target->parent = curPoint;

target->G = calcG(curPoint, target);
target->H = calcH(target, &endPoint);
target->F = calcF(target);

openList.push_back(target);
}
//3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
else
{
int tempG = calcG(curPoint, target);
if (tempG < target->G)
{
target->parent = curPoint;

target->G = tempG;
target->F = calcF(target);
}
}
Point* resPoint = isInList(openList, &endPoint);
if (resPoint)
return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝
}
}

return NULL;
}

std::list<Point*> Astar::GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
Point* result = findPath(startPoint, endPoint, isIgnoreCorner);
std::list<Point*> path;
//返回路径,如果没找到路径,返回空链表
while (result)
{
path.push_front(result);
result = result->parent;
}

// 清空临时开闭列表,防止重复执行GetPath导致结果异常
openList.clear();
closeList.clear();

return path;
}

Point* Astar::isInList(const std::list<Point*>& list, const Point* point) const
{
//判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标
for (auto p : list)
if (p->x == point->x && p->y == point->y)
return p;
return NULL;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
if ((target->x==api.GridToCell(api.GetSelfInfo()->x)&& target->y == api.GridToCell(api.GetSelfInfo()->y))
||target->x<0 || target->x>maze.size() - 1
|| target->y<0 || target->y>maze[0].size() - 1
|| IfAchievable(maze[target->x][target->y], ThisCondition) == 1
|| target->x == point->x && target->y == point->y
|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
return false;
else
{
if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以
return true;
else
{
//斜对角要判断是否绊住
if (IfAchievable(maze[point->x][target->y], ThisCondition) == 0 && IfAchievable(maze[target->x][point->y], ThisCondition) == 0)
return true;
else
return isIgnoreCorner;
}
}
}

std::vector<Point*> Astar::getSurroundPoints(const Point* point, bool isIgnoreCorner) const
{
std::vector<Point*> surroundPoints;

for (int x = point->x - 1; x <= point->x + 1; x++)
for (int y = point->y - 1; y <= point->y + 1; y++)
if (isCanreach(point, new Point(x, y), isIgnoreCorner))
surroundPoints.push_back(new Point(x, y));

return surroundPoints;
}


bool InPath(const int& row, const int& col, const std::list<Point*>& path) {
for (const auto& p : path) {
if (row == p->x && col == p->y) {
return true;
}
}
return false;
}

std::vector<std::vector<int32_t>> findPath(const std::vector<std::vector<THUAI6::PlaceType>>& map, int32_t cellX0, int32_t cellY0, int32_t cellX1, int32_t cellY1, std::vector<bool> Condition, IStudentAPI& api)
{
Astar astar(api);
astar.InitAstar(map, Condition,api);
Point start(cellX0, cellY0);
Point end(cellX1, cellY1);
std::list<Point*> path = astar.GetPath(start, end, false);
std::vector<std::vector<int>> result{};
for (auto P : path)
{
std::vector<int> Loc{ P->x,P->y };
result.push_back(Loc);
}
return result;
}

}

namespace GoToSomePlace
{
std::vector<bool> MoveToNextBlock(IStudentAPI& api, int32_t cellX, int32_t cellY)
{
auto self = api.GetSelfInfo();
if (Distance(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)) < 50)//可以调整
return { false,true };
auto p = api.Move(50, Angle(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
if (!p.get())
return { false,false };
return { true,true };
}//可以修改移动时间
//不检查是否可达,谨慎使用

class GoToAPlace
{
protected:
bool Going = false;//是否正在走
int32_t DestinationX = -1;//cell
int32_t DestinationY = -1;
std::vector<std::vector<int32_t>> Way{ {} };//没吃到
int32_t StepNumber = 0;
int32_t ThisStep = 0;
IStudentAPI& api;
std::vector<bool> ThisCondition;
int32_t LastGridX=-1;
int32_t LastGridY=-1;

public:
GoToAPlace(IStudentAPI& _api) :
Going(false), DestinationX(-1), DestinationY(-1), LastGridX(-1), LastGridY(-1), api(_api), StepNumber(0), ThisStep(0), Way({}), ThisCondition{ {} } {}

GoToAPlace& operator =(GoToAPlace P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way={ {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api=P.api;
ThisCondition=P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
return (*this);
}

bool SetDestination(int32_t cellX, int32_t cellY, std::vector<bool> Condition)
{
if (api.GridToCell(api.GetSelfInfo()->x) == cellX && api.GridToCell(api.GetSelfInfo()->y) == cellY)
Way = { {} };
else
Way = FindWay::findPath(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), cellX, cellY, Condition, api);
if (Way.empty())
{
Unset();
return false;
}
Going = true;
DestinationX = cellX;
DestinationY = cellY;
StepNumber = Way.size();//size-1是最大可访问下表
ThisStep = 0;//从0到size-1
ThisCondition = Condition;
LastGridX = -1;
LastGridY = -1;
return true;
}

void Unset()
{
Going = false;
DestinationX = -1;
DestinationY = -1;
Way = { {} };
StepNumber = 0;
ThisStep = 0;
LastGridX = -1;
LastGridY = -1;
}

void Update()
{
if (!Going)
return;
if (ThisStep >= Way.size() - 1)
{
Unset();
return;
}
return;
}

bool MoveAStep()
{
Update();
if (!Going||Way.empty())
{
Unset();
return false;
}
else
{
if ((LastGridX != -1 && Distance(LastGridX, LastGridY, api.GetSelfInfo()->x, api.GetSelfInfo()->y) < 20)
|| abs(Way[ThisStep + 1][0] - api.GridToCell(api.GetSelfInfo()->x)) + abs(Way[ThisStep + 1][1] - api.GridToCell(api.GetSelfInfo()->y)) > 5)
{
SetDestination(DestinationX, DestinationY, Condition1);
return false;
}
auto p = MoveToNextBlock(api, Way[ThisStep + 1][0], Way[ThisStep + 1][1]);
if (!p[0])
ThisStep++;
LastGridX = api.GetSelfInfo()->x;
LastGridY = api.GetSelfInfo()->y;
Update();
return true;
}
}

bool IfDone()
{
Update();
return !Going;
}
};
}

}

namespace Homework
{
struct Homework
{

int32_t x = -1;
int32_t y = -1;//cell
int32_t Progress = 0;
bool IfBeingDone = false;//待实现
Homework() :x(-1), y(-1), Progress(0), IfBeingDone(false) {}
};

enum class Direction
{
Left = 0,
Right = 1,
Up = 2,
Down = 3,
LeftUp = 4,
LeftDown = 5,
RightUp = 6,
RightDown = 7
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework);

class GoToNearestHomework :public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
Homework ThisHomework;
public:
GoToNearestHomework(IStudentAPI& _api) :
GoToAPlace(_api), ThisHomework() {}

GoToNearestHomework& operator=(GoToNearestHomework P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
ThisHomework = Homework();
return (*this);
}

Homework FindTheNearestHomework()//考虑实现对于多人走向同一份作业的规避,目前未实现
{
Homework NearestHomework;
int32_t DistanceOfTheNearestHomework = -1;
int32_t NumberOfTheNearestHomework = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 10; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), HomeworkLocations[i][0], HomeworkLocations[i][1], { false,true,false,true,true,false,false,false,true,true,true,false }, api).size();
if (i == 0)
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
else if (D < DistanceOfTheNearestHomework && api.GetClassroomProgress(HomeworkLocations[i][0], HomeworkLocations[i][1]) < 10000000)//待实现无人正在写
{
DistanceOfTheNearestHomework = D;
NumberOfTheNearestHomework = i;
}
}
if (NumberOfTheNearestHomework != -1)
{
NearestHomework.x = HomeworkLocations[NumberOfTheNearestHomework][0];
NearestHomework.y = HomeworkLocations[NumberOfTheNearestHomework][1];
NearestHomework.Progress = api.GetClassroomProgress(NearestHomework.x, NearestHomework.y);
}
return NearestHomework;
}

std::vector<bool> MoveAStepToNearestHomework(Direction ThisDirection)//第一个位置返回是否有最近作业,第二个位置返回是否成功
{
if (ThisHomework.x == -1)
return { false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
auto a = MoveAStep();
return { true, a };
}

void UnsetHomework()
{
ThisHomework = Homework();
}

std::vector<bool> FindAndDo(Direction ThisDirection = Direction::Right)//是否找到,是否赶到,是否完成
{
if (api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
{
UnsetHomework();
Unset();
}
if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
if (ThisHomework.x == -1)
return { false,false,false };
switch (ThisDirection)
{
case Direction::Left:
SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
break;
case Direction::Right:
SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
break;
case Direction::Up:
SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
break;
case Direction::Down:
SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
break;
case Direction::LeftUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
break;
case Direction::LeftDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
break;
case Direction::RightUp:
SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
break;
case Direction::RightDown:
SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
break;
}
}
/*if (ThisHomework.x == -1)
{
ThisHomework = FindTheNearestHomework();
SetDestination(ThisHomework.x, ThisHomework.y + 1);
}*/
//MoveAStep();
if (!IfDone())
{
MoveAStep();
return { true,false,false };
}
else
{
Unset();
auto a = DoHomework(api, ThisHomework);
return{ true,true,!a };
}
}
};

bool DoHomework(IStudentAPI& api, Homework ThisHomework)
{
auto self = api.GetSelfInfo();
if (abs(api.GridToCell(self->x) - ThisHomework.x) > 1 || abs(api.GridToCell(self->y) - ThisHomework.y) > 1 || api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
return false;
auto State = api.StartLearning();
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
return true;
}
}


namespace Grass
{
class MoveToGrass : public MoveFunc::GoToSomePlace::GoToAPlace
{
private:
bool Escaping = false;
public:
MoveToGrass(IStudentAPI& _api) :
GoToAPlace(_api), Escaping(false) {}

MoveToGrass& operator=(MoveToGrass P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
Escaping = false;
return (*this);
}

std::vector<int32_t> FindTheNearestGrass()
{
int32_t DistanceOfTheNearestGrass = -1;
int32_t NumberOfTheNearestGrass = -1;
//int32_t i = 0;//遍历次数

for (int32_t i = 0; i < 13; i++)
{
int32_t D = MoveFunc::FindWay::findPath
(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), GrassLocations[i][0], GrassLocations[i][1], Condition1, api).size();
if (i == 0)
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
else if (D < DistanceOfTheNearestGrass)//待实现无人正在写
{
DistanceOfTheNearestGrass = D;
NumberOfTheNearestGrass = i;
}
}
return { GrassLocations[NumberOfTheNearestGrass][0],GrassLocations[NumberOfTheNearestGrass][1] };
}

void FindAndGo()
{
if (!Escaping)
{
auto p = FindTheNearestGrass();
SetDestination(p[0], p[1], Condition1);
Escaping = true;
}
else
if (!IfDone())
{
MoveAStep();
return;
}
else
{
return;
}
}

void StopEscape()
{
Escaping = false;
}
};
}


void AI::play(IStudentAPI& api)
{
// 公共操作
static std::vector<std::vector<int>> a{ {24,6},{15,6},{15,17},{24,17} };

if (this->playerID == 0)//三教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家0执行操作
}
else if (this->playerID == 1)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
//玩家1执行操作
}
else if (this->playerID == 2)//外边
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家2执行操作
}
else if (this->playerID == 3)//六教
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 871
- 0
players/京ICP备2022019669号-1 2022 EESAST/player5.cpp View File

@@ -0,0 +1,871 @@
//四学霸策略

#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"
#include "API.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType =
{
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent
};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::ANoisyPerson;

// 可以在AI.cpp内部声明变量与函数

//全局变量
int32_t HomeworkLocations[10][2]{ {8,31},{18,5},{10,38},{19,41},{22,18},{28,26},{30,7},{33,40},{40,12},{44,32} };
int32_t GrassLocations[13][2]{ {8,2},{8,16},{5,25},{4,29},{10,46},{18,46},{20,36},{15,29},{20,1},{30,25},{40,24},{39,35},{46,8} };

bool IfResetDestination = true;

std::vector<bool> Condition1 = { false, true, false, true, false, false, false, false, true ,true ,true, false };//门都可以,草地,land可以



namespace MoveFunc
{
int32_t Distance(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return int32_t(sqrt((gridX0 - gridX1) * (gridX0 - gridX1) + (gridY0 - gridY1) * (gridY0 - gridY1)));
}

//角度为0指向1
double Angle(int32_t gridX0, int32_t gridY0, int32_t gridX1, int32_t gridY1)
{
return atan2(gridY1 - gridY0, gridX1 - gridX0);
}

namespace FindWay
{

int IfAchievable(THUAI6::PlaceType ThisPlace, std::vector<bool> Condition)
{
//是否可以通过的条件可以进一步完善
if ((ThisPlace == THUAI6::PlaceType::NullPlaceType && Condition[0])
|| (ThisPlace == THUAI6::PlaceType::Land && Condition[1])
|| (ThisPlace == THUAI6::PlaceType::Wall && Condition[2])
|| (ThisPlace == THUAI6::PlaceType::Grass && Condition[3])
|| (ThisPlace == THUAI6::PlaceType::ClassRoom && Condition[4])
|| (ThisPlace == THUAI6::PlaceType::Gate && Condition[5])
|| (ThisPlace == THUAI6::PlaceType::HiddenGate && Condition[6])
|| (ThisPlace == THUAI6::PlaceType::Window && Condition[7])
|| (ThisPlace == THUAI6::PlaceType::Door3 && Condition[8])
|| (ThisPlace == THUAI6::PlaceType::Door5 && Condition[9])
|| (ThisPlace == THUAI6::PlaceType::Door6 && Condition[10])
|| (ThisPlace == THUAI6::PlaceType::Chest && Condition[11]))
return 0;
else
return 1;//1不可达
}

const int kCost1 = 10; //直移一格消耗
const int kCost2 = 14; //斜移一格消耗

struct Point
{
int x, y; //点坐标,这里为了方便按照C++的数组来计算,x代表横排,y代表竖列
int F, G, H; //F=G+H
Point* parent; //parent的坐标,这里没有用指针,从而简化代码
Point(int _x, int _y) :x(_x), y(_y), F(0), G(0), H(0), parent(NULL) //变量初始化
{
}
};

class Astar
{
public:
void InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, ITrickerAPI& api);
std::list<Point*> GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<bool> ThisCondition;
Astar(ITrickerAPI& _api) :
maze({ {} }), api(_api), openList({}), closeList({}) {}

private:
Point* findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner);
std::vector<Point*> getSurroundPoints(const Point* point, bool isIgnoreCorner) const;
bool isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const; //判断某点是否可以用于下一步判断
Point* isInList(const std::list<Point*>& list, const Point* point) const; //判断开启/关闭列表中是否包含某点
Point* getLeastFpoint(); //从开启列表中返回F值最小的节点
//计算FGH值
int calcG(Point* temp_start, Point* point);
int calcH(Point* point, Point* end);
int calcF(Point* point);
private:
std::vector<std::vector<THUAI6::PlaceType>> maze;
std::list<Point*> openList; //开启列表
std::list<Point*> closeList; //关闭列表
ITrickerAPI& api;
};




void Astar::InitAstar(const std::vector<std::vector<THUAI6::PlaceType>>& _maze, std::vector<bool> Condition, ITrickerAPI& _api)
{
maze = _maze;
ThisCondition = Condition;
api = _api;
}

int Astar::calcG(Point* temp_start, Point* point)
{
int extraG = (abs(point->x - temp_start->x) + abs(point->y - temp_start->y)) == 1 ? kCost1 : kCost2;
int parentG = point->parent == NULL ? 0 : point->parent->G; //如果是初始节点,则其父节点是空
return parentG + extraG;
}

int Astar::calcH(Point* point, Point* end)
{
//用简单的欧几里得距离计算H,这个H的计算是关键,还有很多算法,没深入研究^_^
return sqrt((double)(end->x - point->x) * (double)(end->x - point->x) + (double)(end->y - point->y) * (double)(end->y - point->y)) * kCost1;
}

int Astar::calcF(Point* point)
{
return point->G + point->H;
}

Point* Astar::getLeastFpoint()
{
if (!openList.empty())
{
auto resPoint = openList.front();
for (auto& point : openList)
if (point->F < resPoint->F)
resPoint = point;
return resPoint;
}
return NULL;
}

Point* Astar::findPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
openList.push_back(new Point(startPoint.x, startPoint.y)); //置入起点,拷贝开辟一个节点,内外隔离
while (!openList.empty())
{
auto curPoint = getLeastFpoint(); //找到F值最小的点
openList.remove(curPoint); //从开启列表中删除
closeList.push_back(curPoint); //放到关闭列表
//1,找到当前周围八个格中可以通过的格子
auto surroundPoints = getSurroundPoints(curPoint, isIgnoreCorner);
for (auto& target : surroundPoints)
{
//2,对某一个格子,如果它不在开启列表中,加入到开启列表,设置当前格为其父节点,计算F G H
if (!isInList(openList, target))
{
target->parent = curPoint;

target->G = calcG(curPoint, target);
target->H = calcH(target, &endPoint);
target->F = calcF(target);

openList.push_back(target);
}
//3,对某一个格子,它在开启列表中,计算G值, 如果比原来的大, 就什么都不做, 否则设置它的父节点为当前点,并更新G和F
else
{
int tempG = calcG(curPoint, target);
if (tempG < target->G)
{
target->parent = curPoint;

target->G = tempG;
target->F = calcF(target);
}
}
Point* resPoint = isInList(openList, &endPoint);
if (resPoint)
return resPoint; //返回列表里的节点指针,不要用原来传入的endpoint指针,因为发生了深拷贝
}
}

return NULL;
}

std::list<Point*> Astar::GetPath(Point& startPoint, Point& endPoint, bool isIgnoreCorner)
{
Point* result = findPath(startPoint, endPoint, isIgnoreCorner);
std::list<Point*> path;
//返回路径,如果没找到路径,返回空链表
while (result)
{
path.push_front(result);
result = result->parent;
}

// 清空临时开闭列表,防止重复执行GetPath导致结果异常
openList.clear();
closeList.clear();

return path;
}

Point* Astar::isInList(const std::list<Point*>& list, const Point* point) const
{
//判断某个节点是否在列表中,这里不能比较指针,因为每次加入列表是新开辟的节点,只能比较坐标
for (auto p : list)
if (p->x == point->x && p->y == point->y)
return p;
return NULL;
}

bool Astar::isCanreach(const Point* point, const Point* target, bool isIgnoreCorner) const
{
if ((target->x == api.GridToCell(api.GetSelfInfo()->x) && target->y == api.GridToCell(api.GetSelfInfo()->y))
|| target->x<0 || target->x>maze.size() - 1
|| target->y<0 || target->y>maze[0].size() - 1
|| IfAchievable(maze[target->x][target->y], ThisCondition) == 1
|| target->x == point->x && target->y == point->y
|| isInList(closeList, target)) //如果点与当前节点重合、超出地图、是障碍物、或者在关闭列表中,返回false
return false;
else
{
if (abs(point->x - target->x) + abs(point->y - target->y) == 1) //非斜角可以
return true;
else
{
//斜对角要判断是否绊住
if (IfAchievable(maze[point->x][target->y], ThisCondition) == 0 && IfAchievable(maze[target->x][point->y], ThisCondition) == 0)
return true;
else
return isIgnoreCorner;
}
}
}

std::vector<Point*> Astar::getSurroundPoints(const Point* point, bool isIgnoreCorner) const
{
std::vector<Point*> surroundPoints;

for (int x = point->x - 1; x <= point->x + 1; x++)
for (int y = point->y - 1; y <= point->y + 1; y++)
if (isCanreach(point, new Point(x, y), isIgnoreCorner))
surroundPoints.push_back(new Point(x, y));

return surroundPoints;
}


bool InPath(const int& row, const int& col, const std::list<Point*>& path) {
for (const auto& p : path) {
if (row == p->x && col == p->y) {
return true;
}
}
return false;
}

std::vector<std::vector<int32_t>> findPath(const std::vector<std::vector<THUAI6::PlaceType>>& map, int32_t cellX0, int32_t cellY0, int32_t cellX1, int32_t cellY1, std::vector<bool> Condition, ITrickerAPI& api)
{
Astar astar(api);
astar.InitAstar(map, Condition, api);
Point start(cellX0, cellY0);
Point end(cellX1, cellY1);
std::list<Point*> path = astar.GetPath(start, end, false);
std::vector<std::vector<int>> result{};
for (auto P : path)
{
std::vector<int> Loc{ P->x,P->y };
result.push_back(Loc);
}
return result;
}

}

namespace GoToSomePlace
{
std::vector<bool> MoveToNextBlock(ITrickerAPI& api, int32_t cellX, int32_t cellY)
{
auto self = api.GetSelfInfo();
if (Distance(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)) < 60)//可以调整
return { false,true };
auto p = api.Move(50, Angle(self->x, self->y, api.CellToGrid(cellX), api.CellToGrid(cellY)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
api.EndAllAction();
if (!p.get())
return { false,false };
return { true,true };
}//可以修改移动时间
//不检查是否可达,谨慎使用

class GoToAPlace
{
protected:
bool Going = false;//是否正在走
int32_t DestinationX = -1;//cell
int32_t DestinationY = -1;
std::vector<std::vector<int32_t>> Way{ {} };//没吃到
int32_t StepNumber = 0;
int32_t ThisStep = 0;
ITrickerAPI& api;
std::vector<bool> ThisCondition;
int32_t LastGridX = -1;
int32_t LastGridY = -1;

public:
GoToAPlace(ITrickerAPI& _api) :
Going(false), DestinationX(-1), DestinationY(-1), LastGridX(-1), LastGridY(-1), api(_api), StepNumber(0), ThisStep(0), Way({}), ThisCondition{ {} } {}

GoToAPlace& operator =(GoToAPlace P)
{
bool Going = false;//是否正在走
DestinationX = -1;//cell
DestinationY = -1;
Way = { {} };//没吃到
StepNumber = 0;
ThisStep = 0;
api = P.api;
ThisCondition = P.ThisCondition;
LastGridX = -1;
LastGridY = -1;
return (*this);
}

bool SetDestination(int32_t cellX, int32_t cellY, std::vector<bool> Condition)
{
if (api.GridToCell(api.GetSelfInfo()->x) == cellX && api.GridToCell(api.GetSelfInfo()->y) == cellY)
Way = { {} };
else
Way = FindWay::findPath(api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), cellX, cellY, Condition, api);
if (Way.empty())
{
Unset();
return false;
}
Going = true;
DestinationX = cellX;
DestinationY = cellY;
StepNumber = Way.size();//size-1是最大可访问下表
ThisStep = 0;//从0到size-1
ThisCondition = Condition;
LastGridX = -1;
LastGridY = -1;
return true;
}

void Unset()
{
Going = false;
DestinationX = -1;
DestinationY = -1;
Way = { {} };
StepNumber = 0;
ThisStep = 0;
LastGridX = -1;
LastGridY = -1;
}

void Update()
{
if (!Going)
return;
if (ThisStep >= Way.size() - 1)
{
Unset();
return;
}
return;
}

bool MoveAStep()
{
Update();
if (!Going || Way.empty())
{
Unset();
return false;
}
else
{
if ((LastGridX != -1 && Distance(LastGridX, LastGridY, api.GetSelfInfo()->x, api.GetSelfInfo()->y) < 20)
|| abs(Way[ThisStep + 1][0] - api.GridToCell(api.GetSelfInfo()->x)) + abs(Way[ThisStep + 1][1] - api.GridToCell(api.GetSelfInfo()->y)) > 5)
{
SetDestination(DestinationX, DestinationY, Condition1);
return false;
}
auto p = MoveToNextBlock(api, Way[ThisStep + 1][0], Way[ThisStep + 1][1]);
if (!p[0])
ThisStep++;
LastGridX = api.GetSelfInfo()->x;
LastGridY = api.GetSelfInfo()->y;
Update();
return true;
}
}

bool IfDone()
{
Update();
return !Going;
}
};
}

}

//namespace Homework
//{
// struct Homework
// {
//
// int32_t x = -1;
// int32_t y = -1;//cell
// int32_t Progress = 0;
// bool IfBeingDone = false;//待实现
// Homework() :x(-1), y(-1), Progress(0), IfBeingDone(false) {}
// };
//
// enum class Direction
// {
// Left = 0,
// Right = 1,
// Up = 2,
// Down = 3,
// LeftUp = 4,
// LeftDown = 5,
// RightUp = 6,
// RightDown = 7
// };
//
// bool DoHomework(IStudentAPI& api, Homework ThisHomework);
//
// class GoToNearestHomework :public MoveFunc::GoToSomePlace::GoToAPlace
// {
// private:
// Homework ThisHomework;
// public:
// GoToNearestHomework(IStudentAPI& _api) :
// GoToAPlace(_api), ThisHomework() {}
//
// GoToNearestHomework& operator=(GoToNearestHomework P)
// {
// bool Going = false;//是否正在走
// DestinationX = -1;//cell
// DestinationY = -1;
// Way = { {} };//没吃到
// StepNumber = 0;
// ThisStep = 0;
// api = P.api;
// ThisCondition = P.ThisCondition;
// LastGridX = -1;
// LastGridY = -1;
// ThisHomework = Homework();
// return (*this);
// }
//
// Homework FindTheNearestHomework()//考虑实现对于多人走向同一份作业的规避,目前未实现
// {
// Homework NearestHomework;
// int32_t DistanceOfTheNearestHomework = -1;
// int32_t NumberOfTheNearestHomework = -1;
// //int32_t i = 0;//遍历次数
//
// for (int32_t i = 0; i < 10; i++)
// {
// int32_t D = MoveFunc::FindWay::findPath
// (api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), HomeworkLocations[i][0], HomeworkLocations[i][1], { false,true,false,true,true,false,false,false,true,true,true,false }, api).size();
// if (i == 0)
// {
// DistanceOfTheNearestHomework = D;
// NumberOfTheNearestHomework = i;
// }
// else if (D < DistanceOfTheNearestHomework && api.GetClassroomProgress(HomeworkLocations[i][0], HomeworkLocations[i][1]) < 10000000)//待实现无人正在写
// {
// DistanceOfTheNearestHomework = D;
// NumberOfTheNearestHomework = i;
// }
// }
// if (NumberOfTheNearestHomework != -1)
// {
// NearestHomework.x = HomeworkLocations[NumberOfTheNearestHomework][0];
// NearestHomework.y = HomeworkLocations[NumberOfTheNearestHomework][1];
// NearestHomework.Progress = api.GetClassroomProgress(NearestHomework.x, NearestHomework.y);
// }
// return NearestHomework;
// }
//
// std::vector<bool> MoveAStepToNearestHomework(Direction ThisDirection)//第一个位置返回是否有最近作业,第二个位置返回是否成功
// {
// if (ThisHomework.x == -1)
// return { false,false };
// switch (ThisDirection)
// {
// case Direction::Left:
// SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
// break;
// case Direction::Right:
// SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
// break;
// case Direction::Up:
// SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
// break;
// case Direction::Down:
// SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
// break;
// case Direction::LeftUp:
// SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
// break;
// case Direction::LeftDown:
// SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
// break;
// case Direction::RightUp:
// SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
// break;
// case Direction::RightDown:
// SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
// break;
// }
// auto a = MoveAStep();
// return { true, a };
// }
//
// void UnsetHomework()
// {
// ThisHomework = Homework();
// }
//
// std::vector<bool> FindAndDo(Direction ThisDirection = Direction::Right)//是否找到,是否赶到,是否完成
// {
// if (api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
// {
// UnsetHomework();
// Unset();
// }
// if (ThisHomework.x == -1)
// {
// ThisHomework = FindTheNearestHomework();
// if (ThisHomework.x == -1)
// return { false,false,false };
// switch (ThisDirection)
// {
// case Direction::Left:
// SetDestination(ThisHomework.x, ThisHomework.y - 1, Condition1);
// break;
// case Direction::Right:
// SetDestination(ThisHomework.x, ThisHomework.y + 1, Condition1);
// break;
// case Direction::Up:
// SetDestination(ThisHomework.x - 1, ThisHomework.y, Condition1);
// break;
// case Direction::Down:
// SetDestination(ThisHomework.x + 1, ThisHomework.y, Condition1);
// break;
// case Direction::LeftUp:
// SetDestination(ThisHomework.x - 1, ThisHomework.y - 1, Condition1);
// break;
// case Direction::LeftDown:
// SetDestination(ThisHomework.x + 1, ThisHomework.y - 1, Condition1);
// break;
// case Direction::RightUp:
// SetDestination(ThisHomework.x - 1, ThisHomework.y + 1, Condition1);
// break;
// case Direction::RightDown:
// SetDestination(ThisHomework.x + 1, ThisHomework.y + 1, Condition1);
// break;
// }
// }
// /*if (ThisHomework.x == -1)
// {
// ThisHomework = FindTheNearestHomework();
// SetDestination(ThisHomework.x, ThisHomework.y + 1);
// }*/
// //MoveAStep();
// if (!IfDone())
// {
// MoveAStep();
// return { true,false,false };
// }
// else
// {
// Unset();
// auto a = DoHomework(api, ThisHomework);
// return{ true,true,!a };
// }
// }
// };
//
// bool DoHomework(IStudentAPI& api, Homework ThisHomework)
// {
// auto self = api.GetSelfInfo();
// if (abs(api.GridToCell(self->x) - ThisHomework.x) > 1 || abs(api.GridToCell(self->y) - ThisHomework.y) > 1 || api.GetClassroomProgress(ThisHomework.x, ThisHomework.y) >= 10000000)
// return false;
// auto State = api.StartLearning();
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
// api.EndAllAction();
// return true;
// }
//}
//
//
//namespace Grass
//{
// class MoveToGrass : public MoveFunc::GoToSomePlace::GoToAPlace
// {
// private:
// bool Escaping = false;
// public:
// MoveToGrass(IStudentAPI& _api) :
// GoToAPlace(_api), Escaping(false) {}
//
// MoveToGrass& operator=(MoveToGrass P)
// {
// bool Going = false;//是否正在走
// DestinationX = -1;//cell
// DestinationY = -1;
// Way = { {} };//没吃到
// StepNumber = 0;
// ThisStep = 0;
// api = P.api;
// ThisCondition = P.ThisCondition;
// LastGridX = -1;
// LastGridY = -1;
// Escaping = false;
// return (*this);
// }
//
// std::vector<int32_t> FindTheNearestGrass()
// {
// int32_t DistanceOfTheNearestGrass = -1;
// int32_t NumberOfTheNearestGrass = -1;
// //int32_t i = 0;//遍历次数
//
// for (int32_t i = 0; i < 13; i++)
// {
// int32_t D = MoveFunc::FindWay::findPath
// (api.GetFullMap(), api.GridToCell(api.GetSelfInfo()->x), api.GridToCell(api.GetSelfInfo()->y), GrassLocations[i][0], GrassLocations[i][1], Condition1, api).size();
// if (i == 0)
// {
// DistanceOfTheNearestGrass = D;
// NumberOfTheNearestGrass = i;
// }
// else if (D < DistanceOfTheNearestGrass)//待实现无人正在写
// {
// DistanceOfTheNearestGrass = D;
// NumberOfTheNearestGrass = i;
// }
// }
// return { GrassLocations[NumberOfTheNearestGrass][0],GrassLocations[NumberOfTheNearestGrass][1] };
// }
//
// void FindAndGo()
// {
// if (!Escaping)
// {
// auto p = FindTheNearestGrass();
// SetDestination(p[0], p[1], Condition1);
// Escaping = true;
// }
// else
// if (!IfDone())
// {
// MoveAStep();
// return;
// }
// else
// {
// return;
// }
// }
//
// void StopEscape()
// {
// Escaping = false;
// }
// };
//}


void AI::play(IStudentAPI& api)
{
// 公共操作
//static std::vector<std::vector<int>> a{ {24,6},{15,6},{15,17},{24,17} };

if (this->playerID == 0)//三教
{
/*static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}*/
// 玩家0执行操作
}
else if (this->playerID == 1)//外边
{
/*static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}*/
//玩家1执行操作
}
else if (this->playerID == 2)//外边
{
/*static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}*/
// 玩家2执行操作
}
else if (this->playerID == 3)//六教
{
/*static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static Homework::GoToNearestHomework HomeworkTest(api);
static Grass::MoveToGrass GrassTest(api);
static int i = 0;
if (api.GetTrickers().empty())
{
GrassTest.StopEscape();
HomeworkTest.FindAndDo();
}
else
{
GrassTest.FindAndGo();
}*/
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}


bool HaveStudentInSight(ITrickerAPI& api)//判断视野内是否有学生
{
if (api.GetStudents().empty())
return false;
else return true;
}

void MoveInFixedTrace(ITrickerAPI& api)//沿包含作业的固定路线走
{
static MoveFunc::GoToSomePlace::GoToAPlace Test(api);
static auto i = 0;
if (i == 0)
{
Test.SetDestination(28, 27, Condition1);
i++;
}
Test.MoveAStep();
if (i == 1)
{
Test.SetDestination(10, 39, Condition1);
i++;
}
Test.MoveAStep();
if (i == 2)
{
Test.SetDestination(8, 32, Condition1);
i++;
}
Test.MoveAStep();
if (i == 3)
{
Test.SetDestination(18, 6, Condition1);
i++;
}
Test.MoveAStep();
if (i == 4)
{
Test.SetDestination(30, 8, Condition1);
i++;
}
Test.MoveAStep();
if (i == 5)
{
Test.SetDestination(22, 19, Condition1);
i++;
}
Test.MoveAStep();
if (i == 6)
{
Test.SetDestination(40, 13, Condition1);
i++;
}
Test.MoveAStep();
if (i == 7)
{
Test.SetDestination(44, 33, Condition1);
i++;
}
Test.MoveAStep();
if (i == 8)
{
Test.SetDestination(33, 41, Condition1);
i++;
}
Test.MoveAStep();
if (i == 9)
{
Test.SetDestination(28, 27, Condition1);
i++;
}
Test.MoveAStep();
return;
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
//捣蛋鬼策略(喧哗者)
//沿包含所有作业的固定路线循环走,视野范围内有学生则攻击,若学生在视野内消失,则找到并前往最近的作业,回到之前的轨道
if (HaveStudentInSight(api))//视野内无学生,调用寻路函数走规定路线
{
MoveInFixedTrace(api);
}
else//视野内有学生,优先使用技能攻击,在技能CD期间用普通攻击
{
auto self = api.GetSelfInfo();
auto result1 = api.UseSkill(0);
bool actualresult = result1.get();
api.Print(fmt::format("use skill result: {}", actualresult));
//if (THUAI6::Player::timeUntilSkillAvailable <= std::chrono::milliseconds(25000))//技能在cd中
//{
// bool attackresult = result2.get();
// api.Print(fmt::format("attack a student."));
//}
//else//有技能可用
//{
// bool actualresult = result1.get();
// api.Print(fmt::format("use skill result: {}", actualresult));
//}
}
}

+ 1212
- 0
players/代码一行都不队/player1.py
File diff suppressed because it is too large
View File


+ 1212
- 0
players/代码一行都不队/player2.py
File diff suppressed because it is too large
View File


+ 1212
- 0
players/代码一行都不队/player3.py
File diff suppressed because it is too large
View File


+ 1212
- 0
players/代码一行都不队/player4.py
File diff suppressed because it is too large
View File


+ 1212
- 0
players/代码一行都不队/player5.py
File diff suppressed because it is too large
View File


+ 1226
- 0
players/你说什么都队/player1.cpp
File diff suppressed because it is too large
View File


+ 1226
- 0
players/你说什么都队/player2.cpp
File diff suppressed because it is too large
View File


+ 1226
- 0
players/你说什么都队/player3.cpp
File diff suppressed because it is too large
View File


+ 1226
- 0
players/你说什么都队/player4.cpp
File diff suppressed because it is too large
View File


+ 1226
- 0
players/你说什么都队/player5.cpp
File diff suppressed because it is too large
View File


+ 1587
- 0
players/你说得队/player1.py
File diff suppressed because it is too large
View File


+ 1587
- 0
players/你说得队/player2.py
File diff suppressed because it is too large
View File


+ 1587
- 0
players/你说得队/player3.py
File diff suppressed because it is too large
View File


+ 1556
- 0
players/你说得队/player4.py
File diff suppressed because it is too large
View File


+ 1016
- 0
players/你说得队/player5.py
File diff suppressed because it is too large
View File


+ 1596
- 0
players/劝退吧,少女/player1.cpp
File diff suppressed because it is too large
View File


+ 1596
- 0
players/劝退吧,少女/player2.cpp
File diff suppressed because it is too large
View File


+ 1596
- 0
players/劝退吧,少女/player3.cpp
File diff suppressed because it is too large
View File


+ 1596
- 0
players/劝退吧,少女/player4.cpp
File diff suppressed because it is too large
View File


+ 2041
- 0
players/劝退吧,少女/player5.cpp
File diff suppressed because it is too large
View File


+ 4043
- 0
players/努力少女戏尔危/player1.cpp
File diff suppressed because it is too large
View File


+ 4043
- 0
players/努力少女戏尔危/player2.cpp
File diff suppressed because it is too large
View File


+ 4043
- 0
players/努力少女戏尔危/player3.cpp
File diff suppressed because it is too large
View File


+ 4043
- 0
players/努力少女戏尔危/player4.cpp
File diff suppressed because it is too large
View File


+ 4043
- 0
players/努力少女戏尔危/player5.cpp
File diff suppressed because it is too large
View File


+ 310
- 0
players/卷动量守恒/player1.cpp View File

@@ -0,0 +1,310 @@
#include <future>
#include "AI.h"
#include "constants.h"
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = true;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数THUAI6::
struct node
{
int x; int y;
};
int step = 1 * 1000 * 1000 / Constants::Athlete::moveSpeed;
void LeftTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->y)
api.MoveLeft(50);
}
//右移至x处
void RightTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->y)
api.MoveRight(50);
}

//上移至x处
void UpTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->x)
api.MoveUp(50);
}

//下移至x处
void DownTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->x)
api.MoveDown(50);
}

void moveto(int a, int b, IStudentAPI& api)//移动到cell(a,b)
{
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
api.EndAllAction();
}
void moveto3(int a, int b, IStudentAPI& api)
{
while ((api.GetSelfInfo()->y < 1000 * (b + 1) - 600) || (api.GetSelfInfo()->y > 1000 * (b + 1) - 400) || (api.GetSelfInfo()->x < 1000 * (a + 1) - 600) || (api.GetSelfInfo()->x > 1000 * (a + 1) - 400))
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
api.EndAllAction();
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
api.EndAllAction();
}
}
void slide1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::Window || judge2 == THUAI6::PlaceType::Window || judge3 == THUAI6::PlaceType::Window || judge4 == THUAI6::PlaceType::Window)
{
api.SkipWindow();
}
api.EndAllAction();
}
void learn1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::ClassRoom || judge2 == THUAI6::PlaceType::ClassRoom || judge3 == THUAI6::PlaceType::ClassRoom || judge4 == THUAI6::PlaceType::ClassRoom)
{
api.StartLearning();
}
api.EndAllAction();
}
void moveto1(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
api.Move(step, atan2(y2 - y0, x2 - x0));
api.EndAllAction();
}

void moveto2(int a, int b, IStudentAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void moveto2(int a, int b, ITrickerAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void slide(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::Window)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
api.Wait();
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
}
void learn(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::ClassRoom)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
api.StartLearning();
api.EndAllAction();
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
if (api.GetClassroomProgress(22, 18) < 100)
{
moveto(22, 17, api);
}
while (api.GetClassroomProgress(22, 18) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(30, 7) < 100)
{

moveto2(30, 6, api);
}
while (api.GetClassroomProgress(30, 7) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(18, 5) < 100)
{

moveto2(18, 6, api);
}
while (api.GetClassroomProgress(18, 5) < 10000000)
{
learn1(api);
}
/*api.EndAllAction();
moveto(17, 5, api);
moveto(14, 5, api);
api.EndAllAction();
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
slide1(api);*/
moveto(14, 13, api);
moveto(9, 13, api);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
moveto2(6, 6, api);
api.EndAllAction();
while (api.GetGateProgress(5, 6) < 18000)
{
api.StartOpenGate();
}
api.EndAllAction();
api.Graduate();
api.EndAllAction();
//slide1(api);
/*moveto(22, 17, api);
while (api.GetClassroomProgress(22, 18) < 10000000)
{
learn1(api);
}
learn1(api);*/
// 玩家0执行操作
}

else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
// 玩家2执行操作
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 310
- 0
players/卷动量守恒/player2.cpp View File

@@ -0,0 +1,310 @@
#include <future>
#include "AI.h"
#include "constants.h"
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = true;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数THUAI6::
struct node
{
int x; int y;
};
int step = 1 * 1000 * 1000 / Constants::Athlete::moveSpeed;
void LeftTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->y)
api.MoveLeft(50);
}
//右移至x处
void RightTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->y)
api.MoveRight(50);
}

//上移至x处
void UpTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->x)
api.MoveUp(50);
}

//下移至x处
void DownTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->x)
api.MoveDown(50);
}

void moveto(int a, int b, IStudentAPI& api)//移动到cell(a,b)
{
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
api.EndAllAction();
}
void moveto3(int a, int b, IStudentAPI& api)
{
while ((api.GetSelfInfo()->y < 1000 * (b + 1) - 600) || (api.GetSelfInfo()->y > 1000 * (b + 1) - 400) || (api.GetSelfInfo()->x < 1000 * (a + 1) - 600) || (api.GetSelfInfo()->x > 1000 * (a + 1) - 400))
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
api.EndAllAction();
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
api.EndAllAction();
}
}
void slide1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::Window || judge2 == THUAI6::PlaceType::Window || judge3 == THUAI6::PlaceType::Window || judge4 == THUAI6::PlaceType::Window)
{
api.SkipWindow();
}
api.EndAllAction();
}
void learn1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::ClassRoom || judge2 == THUAI6::PlaceType::ClassRoom || judge3 == THUAI6::PlaceType::ClassRoom || judge4 == THUAI6::PlaceType::ClassRoom)
{
api.StartLearning();
}
api.EndAllAction();
}
void moveto1(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
api.Move(step, atan2(y2 - y0, x2 - x0));
api.EndAllAction();
}

void moveto2(int a, int b, IStudentAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void moveto2(int a, int b, ITrickerAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void slide(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::Window)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
api.Wait();
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
}
void learn(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::ClassRoom)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
api.StartLearning();
api.EndAllAction();
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
/* moveto(25, 48, api);
moveto(5, 48, api);
moveto(5, 37, api);
api.EndAllAction();
api.SkipWindow();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
slide1(api);
if (api.GetClassroomProgress(19, 41) < 100)
{
moveto(16, 37, api);
moveto2(19, 42, api);
}
while (api.GetClassroomProgress(19, 41) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(10, 38) < 100)
{
moveto(10, 39, api);
}
while (api.GetClassroomProgress(10, 38) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(8, 31) < 100)
{
moveto(8, 32, api);
}
while (api.GetClassroomProgress(8, 31) < 10000000)
{
learn1(api);
}
api.EndAllAction();
moveto(6, 32, api);
api.EndAllAction();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
slide1(api); */
moveto(42, 44, api);
/*if (api.GetGateProgress(46, 45) >0)
{
moveto(42, 43, api);
moveto(46, 44, api);
api.StartOpenGate();
}*/
std::this_thread::sleep_for(std::chrono::milliseconds(70000));
moveto(42, 43, api);
moveto(46, 44, api);
api.StartOpenGate();
api.Graduate();
api.EndAllAction();
// 玩家1执行操作
}


else if (this->playerID == 2)
{
// 玩家2执行操作
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 297
- 0
players/卷动量守恒/player3.cpp View File

@@ -0,0 +1,297 @@
#include <future>
#include "AI.h"
#include "constants.h"
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = true;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数THUAI6::
struct node
{
int x; int y;
};
int step = 1 * 1000 * 1000 / Constants::Athlete::moveSpeed;
void LeftTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->y)
api.MoveLeft(50);
}
//右移至x处
void RightTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->y)
api.MoveRight(50);
}

//上移至x处
void UpTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->x)
api.MoveUp(50);
}

//下移至x处
void DownTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->x)
api.MoveDown(50);
}

void moveto(int a, int b, IStudentAPI& api)//移动到cell(a,b)
{
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
api.EndAllAction();
}
void moveto3(int a, int b, IStudentAPI& api)
{
while ((api.GetSelfInfo()->y < 1000 * (b + 1) - 600) || (api.GetSelfInfo()->y > 1000 * (b + 1) - 400) || (api.GetSelfInfo()->x < 1000 * (a + 1) - 600) || (api.GetSelfInfo()->x > 1000 * (a + 1) - 400))
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
api.EndAllAction();
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
api.EndAllAction();
}
}
void slide1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::Window || judge2 == THUAI6::PlaceType::Window || judge3 == THUAI6::PlaceType::Window || judge4 == THUAI6::PlaceType::Window)
{
api.SkipWindow();
}
api.EndAllAction();
}
void learn1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::ClassRoom || judge2 == THUAI6::PlaceType::ClassRoom || judge3 == THUAI6::PlaceType::ClassRoom || judge4 == THUAI6::PlaceType::ClassRoom)
{
api.StartLearning();
}
api.EndAllAction();
}
void moveto1(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
api.Move(step, atan2(y2 - y0, x2 - x0));
api.EndAllAction();
}

void moveto2(int a, int b, IStudentAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void moveto2(int a, int b, ITrickerAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void slide(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::Window)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
api.Wait();
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
}
void learn(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::ClassRoom)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
api.StartLearning();
api.EndAllAction();
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
if (api.GetClassroomProgress(10, 38) < 100)
{
moveto(12, 25, api);
moveto(4, 37, api);
moveto(10, 37, api);
}
while (api.GetClassroomProgress(10, 38) < 10000000)
{
learn1(api);
}
if (api.GetClassroomProgress(8, 31) < 100)
{
moveto(8, 32, api);
}
while (api.GetClassroomProgress(8, 31) < 10000000)
{
learn1(api);
}
if (api.GetClassroomProgress(19, 41) < 100)
{
moveto2(19, 42, api);
}
while (api.GetClassroomProgress(19, 41) < 10000000)
{
learn1(api);
}
moveto2(8, 42, api);
moveto2(4, 37, api);
moveto2(4, 18, api);
moveto(2, 7, api);
moveto2(2, 4, api);
moveto(5, 5, api);
while (api.GetGateProgress(5, 6) < 18000)
{
api.StartOpenGate();
}
api.EndAllAction();
api.Graduate();
api.EndAllAction();
// 玩家2执行操作
}


else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 314
- 0
players/卷动量守恒/player4.cpp View File

@@ -0,0 +1,314 @@
#include <future>
#include "AI.h"
#include "constants.h"
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = true;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数THUAI6::
struct node
{
int x; int y;
};
int step = 1 * 1000 * 1000 / Constants::Athlete::moveSpeed;
void LeftTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->y)
api.MoveLeft(50);
}
//右移至x处
void RightTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->y)
api.MoveRight(50);
}

//上移至x处
void UpTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->x)
api.MoveUp(50);
}

//下移至x处
void DownTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->x)
api.MoveDown(50);
}

void moveto(int a, int b, IStudentAPI& api)//移动到cell(a,b)
{
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
api.EndAllAction();
}
void moveto3(int a, int b, IStudentAPI& api)
{
while ((api.GetSelfInfo()->y < 1000 * (b + 1) - 600) || (api.GetSelfInfo()->y > 1000 * (b + 1) - 400) || (api.GetSelfInfo()->x < 1000 * (a + 1) - 600) || (api.GetSelfInfo()->x > 1000 * (a + 1) - 400))
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
api.EndAllAction();
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
api.EndAllAction();
}
}
void slide1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::Window || judge2 == THUAI6::PlaceType::Window || judge3 == THUAI6::PlaceType::Window || judge4 == THUAI6::PlaceType::Window)
{
api.SkipWindow();
}
api.EndAllAction();
}
void learn1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::ClassRoom || judge2 == THUAI6::PlaceType::ClassRoom || judge3 == THUAI6::PlaceType::ClassRoom || judge4 == THUAI6::PlaceType::ClassRoom)
{
api.StartLearning();
}
api.EndAllAction();
}
void moveto1(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
api.Move(step, atan2(y2 - y0, x2 - x0));
api.EndAllAction();
}

void moveto2(int a, int b, IStudentAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void moveto2(int a, int b, ITrickerAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void slide(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::Window)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
api.Wait();
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
}
void learn(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::ClassRoom)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
api.StartLearning();
api.EndAllAction();
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
// 玩家2执行操作
}
else if (this->playerID == 3)
{
if (api.GetClassroomProgress(40, 12) < 100)
{
moveto(40, 13, api);
}
while (api.GetClassroomProgress(40, 12) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(28, 26) < 100)
{
moveto(40, 25, api);
moveto(28, 25, api);
}
while (api.GetClassroomProgress(28, 26) < 10000000)
{
learn1(api);
}
api.EndAllAction();
if (api.GetClassroomProgress(33, 40) < 100)
{
moveto(29, 34, api);
moveto(33, 39, api);
}
while (api.GetClassroomProgress(33, 40) < 10000000)
{
learn1(api);
}
api.EndAllAction();

if (api.GetClassroomProgress(44, 32) < 100)
{
moveto(33, 31, api);
moveto(44, 31, api);
}
while (api.GetClassroomProgress(44, 32) < 10000000)
{
learn1(api);
}
moveto(43, 31, api);
moveto2(41, 35, api);
moveto2(41, 39, api);
moveto(46, 44, api);
/*api.EndAllAction();
moveto(45, 37, api);
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
slide1(api);
moveto(46, 44, api);
api.EndAllAction();*/
while (api.GetGateProgress(46, 45) < 18000)
{
api.StartOpenGate();
}
api.EndAllAction();
api.Graduate();
api.EndAllAction();
// 玩家3执行操作
}


//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}

+ 342
- 0
players/卷动量守恒/player5.cpp View File

@@ -0,0 +1,342 @@
#include <future>
#include "AI.h"
#include "constants.h"
// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = true;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数THUAI6::
struct node
{
int x; int y;
};
int step = 1 * 1000 * 1000 / Constants::Athlete::moveSpeed;
void LeftTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->y)
api.MoveLeft(50);
}
//右移至x处
void RightTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->y)
api.MoveRight(50);
}

//上移至x处
void UpTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x < self->x)
api.MoveUp(50);
}

//下移至x处
void DownTo(ITrickerAPI& api, int x)
{
auto self = api.GetSelfInfo();
while (x > self->x)
api.MoveDown(50);
}

void moveto(int a, int b, IStudentAPI& api)//移动到cell(a,b)
{
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
api.EndAllAction();
}
void moveto3(int a, int b, IStudentAPI& api)
{
while ((api.GetSelfInfo()->y < 1000 * (b + 1) - 600) || (api.GetSelfInfo()->y > 1000 * (b + 1) - 400) || (api.GetSelfInfo()->x < 1000 * (a + 1) - 600) || (api.GetSelfInfo()->x > 1000 * (a + 1) - 400))
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
api.EndAllAction();
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
api.EndAllAction();
}
}
void slide1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::Window || judge2 == THUAI6::PlaceType::Window || judge3 == THUAI6::PlaceType::Window || judge4 == THUAI6::PlaceType::Window)
{
api.SkipWindow();
}
api.EndAllAction();
}
void learn1(IStudentAPI& api)
{
auto p1 = api.GetSelfInfo();
int x1 = api.GridToCell(p1->x);
int y1 = api.GridToCell(p1->y);
auto judge1 = api.GetPlaceType(x1 + 1, y1);
auto judge2 = api.GetPlaceType(x1 - 1, y1);
auto judge3 = api.GetPlaceType(x1, y1 + 1);
auto judge4 = api.GetPlaceType(x1, y1 - 1);
if (judge1 == THUAI6::PlaceType::ClassRoom || judge2 == THUAI6::PlaceType::ClassRoom || judge3 == THUAI6::PlaceType::ClassRoom || judge4 == THUAI6::PlaceType::ClassRoom)
{
api.StartLearning();
}
api.EndAllAction();
}
void moveto1(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
api.Move(step, atan2(y2 - y0, x2 - x0));
api.EndAllAction();
}

void moveto2(int a, int b, IStudentAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void moveto2(int a, int b, ITrickerAPI& api)
{
if ((b + 1) != 0)
{
while (api.GetSelfInfo()->y < 1000 * (b + 1) - 600)
{
api.MoveRight(50);
}
while (api.GetSelfInfo()->y > 1000 * (b + 1) - 400)
{
api.MoveLeft(50);
}
}
if ((a + 1) != 0)
{
while (api.GetSelfInfo()->x < 1000 * (a + 1) - 600)
{
api.MoveDown(50);
}
while (api.GetSelfInfo()->x > 1000 * (a + 1) - 400)
{
api.MoveUp(50);
}
}
api.EndAllAction();
}
void slide(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::Window)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
api.Wait();
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
}
void learn(IStudentAPI& api, node b)
{
int x2, y2;
int x0 = api.GetSelfInfo()->x;
int y0 = api.GetSelfInfo()->y;
x2 = api.CellToGrid(b.x);
y2 = api.CellToGrid(b.y);
if (api.GetPlaceType(b.x, b.y) == THUAI6::PlaceType::ClassRoom)
{
api.Move(step, atan2(y2 - y0, x2 - x0));
x0 = api.GetSelfInfo()->x;
y0 = api.GetSelfInfo()->y;
}
api.StartLearning();
api.EndAllAction();
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
// 玩家2执行操作
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
auto Student = api.GetStudents();
api.PrintStudent();
if (self->timeUntilSkillAvailable[0] == 0)
api.UseSkill(0);
if (!Student.empty())
{
int i = Student.size();
for (int k = 0; k < i; k++)
{
if (Student[k]->studentType != THUAI6::StudentType::Teacher && (Student[k]->playerState != THUAI6::PlayerState::Quit) && (Student[k]->playerState != THUAI6::PlayerState::Addicted))
{

if (sqrt(((self->y) - (Student[k]->y)) * ((self->y) - (Student[k]->y)) + ((self->x) - (Student[k]->x)) * ((self->x) - (Student[k]->x))) > 4000)
{
api.Move(50, 3.141592653589 + atan2(((self->y) - (Student[k]->y)), (self->x) - (Student[k]->x)));
api.EndAllAction();
}
if (self->timeUntilSkillAvailable[1] == 0)
{
if (sqrt(((self->y) - (Student[k]->y)) * ((self->y) - (Student[k]->y)) + ((self->x) - (Student[k]->x)) * ((self->x) - (Student[k]->x))) < 3000)
{
api.UseSkill(1);
api.Attack(3.141592653589 + atan2(((self->y) - (Student[k]->y)), (self->x) - (Student[k]->x)));
api.EndAllAction();
}
}
if (sqrt(((self->y) - (Student[k]->y)) * ((self->y) - (Student[k]->y)) + ((self->x) - (Student[k]->x)) * ((self->x) - (Student[k]->x))) > 1400)
{
api.Move(50, 3.141592653589 + atan2(((self->y) - (Student[k]->y)), (self->x) - (Student[k]->x)));
api.EndAllAction();
}
if (sqrt(((self->y) - (Student[k]->y)) * ((self->y) - (Student[k]->y)) + ((self->x) - (Student[k]->x)) * ((self->x) - (Student[k]->x))) < 1500)
{
api.Attack(3.141592653589 + atan2(((self->y) - (Student[k]->y)), (self->x) - (Student[k]->x)));
api.EndAllAction();
}
}
else break;
}
}
if (Student.empty())
{

/* if (api.GridToCell(self->x) > 21)
{
UpTo(api, 21);
if (IfTouch(api, THUAI6::PlaceType::Wall))
api.EndAllAction();
}
else if (api.GridToCell(self->x) < 21)
{
DownTo(api, 21);
if (IfTouch(api, THUAI6::PlaceType::Wall))
api.EndAllAction();
}
if (api.GridToCell(self->y) > 25)
{
LeftTo(api, 25);
if (IfTouch(api, THUAI6::PlaceType::Wall))
api.EndAllAction();
}
else if (api.GridToCell(self->y) < 25)
{
RightTo(api, 25);
if (IfTouch(api, THUAI6::PlaceType::Wall))
api.EndAllAction();
}*/

while (api.GetPlaceType(api.GridToCell(self->x) - 1, api.GridToCell(self->y)) == THUAI6::PlaceType::Wall)
{
api.MoveLeft(100);
api.EndAllAction();
}

if (api.GridToCell(self->x) != 5 && api.GridToCell(self->y) != 3)
{
moveto2(2, api.GridToCell(self->y), api);
moveto2(2, 3, api);
moveto2(5, 3, api);
}



}
}




+ 1622
- 0
players/叛逃者联盟/player1.cpp
File diff suppressed because it is too large
View File


+ 1622
- 0
players/叛逃者联盟/player2.cpp
File diff suppressed because it is too large
View File


+ 1622
- 0
players/叛逃者联盟/player3.cpp
File diff suppressed because it is too large
View File


+ 1622
- 0
players/叛逃者联盟/player4.cpp
File diff suppressed because it is too large
View File


+ 1622
- 0
players/叛逃者联盟/player5.cpp
File diff suppressed because it is too large
View File


+ 425
- 0
players/土木清华没有水/player1.cpp View File

@@ -0,0 +1,425 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数
bool move = false;
int place[2] = { 2,2 };
//全局变量,坐标
long long abs_X = 0;
long long abs_Y = 0;
//卡位微调参量
int Turn_little = 0;
bool Turn_can = 0;
bool Turn_flag = 1;
int Y_change = 0;
void GetTo(int32_t X, int32_t Y, IStudentAPI& api)//X,Y为格子坐标,api直接放api即可
{
//初始化参量
bool Y_can_go = 1, X_can_go = 1;
bool Down_Player;//下移参量,判断是否下移
bool Up_Player;//上移参量,判断是否上移
bool Left_Player;//左移参量
bool Right_Player;//右移参量
bool Go_Go_X = 1;//卡位参量 0卡位,1不卡位
bool Go_Go_Y = 1;//卡位参量 0卡位,1不卡位
auto Selfinfo = api.GetSelfInfo();//获取人物信息
auto X_player = api.GridToCell(Selfinfo->x);//得到人物坐标X(格子)
auto Y_player = api.GridToCell(Selfinfo->y);//得到人物坐标Y(格子)
//获得人物周边信息
auto Placetype_LU = api.GetPlaceType(X_player - 1, Y_player - 1);
auto Placetype_L0 = api.GetPlaceType(X_player, Y_player - 1);
auto Placetype_LD = api.GetPlaceType(X_player + 1, Y_player - 1);
auto Placetype_0U = api.GetPlaceType(X_player - 1, Y_player);
auto Placetype_00 = api.GetPlaceType(X_player, Y_player);
auto Placetype_0D = api.GetPlaceType(X_player + 1, Y_player);
auto Placetype_RU = api.GetPlaceType(X_player - 1, Y_player + 1);
auto Placetype_R0 = api.GetPlaceType(X_player, Y_player + 1);
auto Placetype_RD = api.GetPlaceType(X_player + 1, Y_player + 1);
//判断上下左右是否可走
int Left_can_go = (Placetype_L0 == THUAI6::PlaceType::Land || Placetype_L0 == THUAI6::PlaceType::Grass);
int Right_can_go = (Placetype_R0 == THUAI6::PlaceType::Land || Placetype_R0 == THUAI6::PlaceType::Grass);
int Up_can_go = (Placetype_0U == THUAI6::PlaceType::Land || Placetype_0U == THUAI6::PlaceType::Grass);
int Down_can_go = (Placetype_0D == THUAI6::PlaceType::Land || Placetype_0D == THUAI6::PlaceType::Grass);
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//判断朝向
if (X > X_player)//Down
{
Down_Player = true;
}
else Down_Player = false;
if (X < X_player)//Up
{
Up_Player = true;
}
else Up_Player = false;
if (Y < Y_player)//Left
{
Left_Player = true;
}
else Left_Player = false;
if (Y < Y_player)//Right
{
Right_Player = true;
}
else Right_Player = false;
//先保证X对齐
//可走则走
if (Down_Player == true && Down_can_go && Go_Go_X)
{
api.MoveDown(10);
}
if (Up_Player == true && Up_can_go && Go_Go_X)
{
api.MoveUp(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Down_Player == true && Down_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Up_Player == true && Up_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_X == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Go_Go_X == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Down_Player == 1 && !Down_can_go && Go_Go_X)
{
if (Right_Player && Right_can_go)
{
api.MoveRight(20);
}
else if (Left_Player && Left_can_go)
{
api.MoveLeft(20);
}
else if (Left_can_go)
{
api.MoveLeft(20);
}
else if (Right_can_go)
{
api.MoveRight(20);
}
else Y_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!Y_can_go)
{
api.MoveUp(100);
}
else;
//
//Y方向在X对齐后仍采用相同的方法,但是调整后成功Y对齐后需要进行再一次X对齐,反复循环直到对齐
//
//
//
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}

//可走则走
if (Right_Player == true && Right_can_go && Go_Go_Y)
{
api.MoveRight(10);
}
if (Left_Player == true && Left_can_go && Go_Go_Y)
{
api.MoveLeft(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Right_Player == true && Right_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Left_Player == true && Left_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_Y == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Go_Go_Y == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Right_Player == 1 && !Right_can_go && Go_Go_Y)
{
if (Down_Player && Down_can_go)
{
api.MoveDown(20);
}
else if (Up_Player && Up_can_go)
{
api.MoveUp(20);
}
else if (Up_can_go)
{
api.MoveUp(20);
}
else if (Down_can_go)
{
api.MoveDown(20);
}
else X_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!X_can_go)
{
api.MoveUp(100);
}
else;







//保留最后坐标
auto Selfinfo_Last = api.GetSelfInfo();
abs_X = Selfinfo_Last->x;
abs_Y = Selfinfo_Last->y;

}


void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
GetTo(30, 30, api);




// 玩家0执行操作
}
else if (this->playerID == 1)
{
GetTo(10, 10, api);
// 玩家1执行操作
}
else if (this->playerID == 2)
{
auto mapInfo = api.GetFullMap();
auto SelfInfo = api.GetSelfInfo();
auto cellx = api.GridToCell(SelfInfo->x);
auto celly = api.GridToCell(SelfInfo->y);
int flash = 0;
int i = cellx, j = celly;
if (place[0] == 2 )
{
for (flash = 0; i < (cellx + 10); i = i + 1)
{

for (; j < (celly + 10); j = j + 1)
{
if (mapInfo[i][j] == THUAI6::PlaceType::Chest)
{
flash = 1;
break;
}
}
if (flash == 1) break;
}
if (flash == 1)
{
place[0] = i; place[1] = j;
}
}
else if(1)
{double angle = atan2(place[1] - celly, place[0] - cellx);
api.Move(50, angle);
}
else
{
if (api.GetChestProgress(place[0], place[1]) < 10000000)
{
api.StartOpenChest();
}
else
{
auto PropInfo = api.GetProps();
api.PickProp(PropInfo[0]->type);
api.PickProp(PropInfo[1]->type);
}
}



// 玩家2执行操作
}
else if (this->playerID == 3)
{
GetTo(20, 20, api);
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}


+ 425
- 0
players/土木清华没有水/player2.cpp View File

@@ -0,0 +1,425 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数
bool move = false;
int place[2] = { 2,2 };
//全局变量,坐标
long long abs_X = 0;
long long abs_Y = 0;
//卡位微调参量
int Turn_little = 0;
bool Turn_can = 0;
bool Turn_flag = 1;
int Y_change = 0;
void GetTo(int32_t X, int32_t Y, IStudentAPI& api)//X,Y为格子坐标,api直接放api即可
{
//初始化参量
bool Y_can_go = 1, X_can_go = 1;
bool Down_Player;//下移参量,判断是否下移
bool Up_Player;//上移参量,判断是否上移
bool Left_Player;//左移参量
bool Right_Player;//右移参量
bool Go_Go_X = 1;//卡位参量 0卡位,1不卡位
bool Go_Go_Y = 1;//卡位参量 0卡位,1不卡位
auto Selfinfo = api.GetSelfInfo();//获取人物信息
auto X_player = api.GridToCell(Selfinfo->x);//得到人物坐标X(格子)
auto Y_player = api.GridToCell(Selfinfo->y);//得到人物坐标Y(格子)
//获得人物周边信息
auto Placetype_LU = api.GetPlaceType(X_player - 1, Y_player - 1);
auto Placetype_L0 = api.GetPlaceType(X_player, Y_player - 1);
auto Placetype_LD = api.GetPlaceType(X_player + 1, Y_player - 1);
auto Placetype_0U = api.GetPlaceType(X_player - 1, Y_player);
auto Placetype_00 = api.GetPlaceType(X_player, Y_player);
auto Placetype_0D = api.GetPlaceType(X_player + 1, Y_player);
auto Placetype_RU = api.GetPlaceType(X_player - 1, Y_player + 1);
auto Placetype_R0 = api.GetPlaceType(X_player, Y_player + 1);
auto Placetype_RD = api.GetPlaceType(X_player + 1, Y_player + 1);
//判断上下左右是否可走
int Left_can_go = (Placetype_L0 == THUAI6::PlaceType::Land || Placetype_L0 == THUAI6::PlaceType::Grass);
int Right_can_go = (Placetype_R0 == THUAI6::PlaceType::Land || Placetype_R0 == THUAI6::PlaceType::Grass);
int Up_can_go = (Placetype_0U == THUAI6::PlaceType::Land || Placetype_0U == THUAI6::PlaceType::Grass);
int Down_can_go = (Placetype_0D == THUAI6::PlaceType::Land || Placetype_0D == THUAI6::PlaceType::Grass);
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//判断朝向
if (X > X_player)//Down
{
Down_Player = true;
}
else Down_Player = false;
if (X < X_player)//Up
{
Up_Player = true;
}
else Up_Player = false;
if (Y < Y_player)//Left
{
Left_Player = true;
}
else Left_Player = false;
if (Y < Y_player)//Right
{
Right_Player = true;
}
else Right_Player = false;
//先保证X对齐
//可走则走
if (Down_Player == true && Down_can_go && Go_Go_X)
{
api.MoveDown(10);
}
if (Up_Player == true && Up_can_go && Go_Go_X)
{
api.MoveUp(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Down_Player == true && Down_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Up_Player == true && Up_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_X == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Go_Go_X == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Down_Player == 1 && !Down_can_go && Go_Go_X)
{
if (Right_Player && Right_can_go)
{
api.MoveRight(20);
}
else if (Left_Player && Left_can_go)
{
api.MoveLeft(20);
}
else if (Left_can_go)
{
api.MoveLeft(20);
}
else if (Right_can_go)
{
api.MoveRight(20);
}
else Y_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!Y_can_go)
{
api.MoveUp(100);
}
else;
//
//Y方向在X对齐后仍采用相同的方法,但是调整后成功Y对齐后需要进行再一次X对齐,反复循环直到对齐
//
//
//
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}

//可走则走
if (Right_Player == true && Right_can_go && Go_Go_Y)
{
api.MoveRight(10);
}
if (Left_Player == true && Left_can_go && Go_Go_Y)
{
api.MoveLeft(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Right_Player == true && Right_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Left_Player == true && Left_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_Y == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Go_Go_Y == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Right_Player == 1 && !Right_can_go && Go_Go_Y)
{
if (Down_Player && Down_can_go)
{
api.MoveDown(20);
}
else if (Up_Player && Up_can_go)
{
api.MoveUp(20);
}
else if (Up_can_go)
{
api.MoveUp(20);
}
else if (Down_can_go)
{
api.MoveDown(20);
}
else X_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!X_can_go)
{
api.MoveUp(100);
}
else;







//保留最后坐标
auto Selfinfo_Last = api.GetSelfInfo();
abs_X = Selfinfo_Last->x;
abs_Y = Selfinfo_Last->y;

}


void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
GetTo(30, 30, api);




// 玩家0执行操作
}
else if (this->playerID == 1)
{
GetTo(10, 10, api);
// 玩家1执行操作
}
else if (this->playerID == 2)
{
auto mapInfo = api.GetFullMap();
auto SelfInfo = api.GetSelfInfo();
auto cellx = api.GridToCell(SelfInfo->x);
auto celly = api.GridToCell(SelfInfo->y);
int flash = 0;
int i = cellx, j = celly;
if (place[0] == 2 )
{
for (flash = 0; i < (cellx + 10); i = i + 1)
{

for (; j < (celly + 10); j = j + 1)
{
if (mapInfo[i][j] == THUAI6::PlaceType::Chest)
{
flash = 1;
break;
}
}
if (flash == 1) break;
}
if (flash == 1)
{
place[0] = i; place[1] = j;
}
}
else if(1)
{double angle = atan2(place[1] - celly, place[0] - cellx);
api.Move(50, angle);
}
else
{
if (api.GetChestProgress(place[0], place[1]) < 10000000)
{
api.StartOpenChest();
}
else
{
auto PropInfo = api.GetProps();
api.PickProp(PropInfo[0]->type);
api.PickProp(PropInfo[1]->type);
}
}



// 玩家2执行操作
}
else if (this->playerID == 3)
{
GetTo(20, 20, api);
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}


+ 425
- 0
players/土木清华没有水/player3.cpp View File

@@ -0,0 +1,425 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数
bool move = false;
int place[2] = { 2,2 };
//全局变量,坐标
long long abs_X = 0;
long long abs_Y = 0;
//卡位微调参量
int Turn_little = 0;
bool Turn_can = 0;
bool Turn_flag = 1;
int Y_change = 0;
void GetTo(int32_t X, int32_t Y, IStudentAPI& api)//X,Y为格子坐标,api直接放api即可
{
//初始化参量
bool Y_can_go = 1, X_can_go = 1;
bool Down_Player;//下移参量,判断是否下移
bool Up_Player;//上移参量,判断是否上移
bool Left_Player;//左移参量
bool Right_Player;//右移参量
bool Go_Go_X = 1;//卡位参量 0卡位,1不卡位
bool Go_Go_Y = 1;//卡位参量 0卡位,1不卡位
auto Selfinfo = api.GetSelfInfo();//获取人物信息
auto X_player = api.GridToCell(Selfinfo->x);//得到人物坐标X(格子)
auto Y_player = api.GridToCell(Selfinfo->y);//得到人物坐标Y(格子)
//获得人物周边信息
auto Placetype_LU = api.GetPlaceType(X_player - 1, Y_player - 1);
auto Placetype_L0 = api.GetPlaceType(X_player, Y_player - 1);
auto Placetype_LD = api.GetPlaceType(X_player + 1, Y_player - 1);
auto Placetype_0U = api.GetPlaceType(X_player - 1, Y_player);
auto Placetype_00 = api.GetPlaceType(X_player, Y_player);
auto Placetype_0D = api.GetPlaceType(X_player + 1, Y_player);
auto Placetype_RU = api.GetPlaceType(X_player - 1, Y_player + 1);
auto Placetype_R0 = api.GetPlaceType(X_player, Y_player + 1);
auto Placetype_RD = api.GetPlaceType(X_player + 1, Y_player + 1);
//判断上下左右是否可走
int Left_can_go = (Placetype_L0 == THUAI6::PlaceType::Land || Placetype_L0 == THUAI6::PlaceType::Grass);
int Right_can_go = (Placetype_R0 == THUAI6::PlaceType::Land || Placetype_R0 == THUAI6::PlaceType::Grass);
int Up_can_go = (Placetype_0U == THUAI6::PlaceType::Land || Placetype_0U == THUAI6::PlaceType::Grass);
int Down_can_go = (Placetype_0D == THUAI6::PlaceType::Land || Placetype_0D == THUAI6::PlaceType::Grass);
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//判断朝向
if (X > X_player)//Down
{
Down_Player = true;
}
else Down_Player = false;
if (X < X_player)//Up
{
Up_Player = true;
}
else Up_Player = false;
if (Y < Y_player)//Left
{
Left_Player = true;
}
else Left_Player = false;
if (Y < Y_player)//Right
{
Right_Player = true;
}
else Right_Player = false;
//先保证X对齐
//可走则走
if (Down_Player == true && Down_can_go && Go_Go_X)
{
api.MoveDown(10);
}
if (Up_Player == true && Up_can_go && Go_Go_X)
{
api.MoveUp(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Down_Player == true && Down_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Up_Player == true && Up_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_X == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Go_Go_X == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Down_Player == 1 && !Down_can_go && Go_Go_X)
{
if (Right_Player && Right_can_go)
{
api.MoveRight(20);
}
else if (Left_Player && Left_can_go)
{
api.MoveLeft(20);
}
else if (Left_can_go)
{
api.MoveLeft(20);
}
else if (Right_can_go)
{
api.MoveRight(20);
}
else Y_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!Y_can_go)
{
api.MoveUp(100);
}
else;
//
//Y方向在X对齐后仍采用相同的方法,但是调整后成功Y对齐后需要进行再一次X对齐,反复循环直到对齐
//
//
//
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}

//可走则走
if (Right_Player == true && Right_can_go && Go_Go_Y)
{
api.MoveRight(10);
}
if (Left_Player == true && Left_can_go && Go_Go_Y)
{
api.MoveLeft(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Right_Player == true && Right_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Left_Player == true && Left_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_Y == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Go_Go_Y == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Right_Player == 1 && !Right_can_go && Go_Go_Y)
{
if (Down_Player && Down_can_go)
{
api.MoveDown(20);
}
else if (Up_Player && Up_can_go)
{
api.MoveUp(20);
}
else if (Up_can_go)
{
api.MoveUp(20);
}
else if (Down_can_go)
{
api.MoveDown(20);
}
else X_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!X_can_go)
{
api.MoveUp(100);
}
else;







//保留最后坐标
auto Selfinfo_Last = api.GetSelfInfo();
abs_X = Selfinfo_Last->x;
abs_Y = Selfinfo_Last->y;

}


void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
GetTo(30, 30, api);




// 玩家0执行操作
}
else if (this->playerID == 1)
{
GetTo(10, 10, api);
// 玩家1执行操作
}
else if (this->playerID == 2)
{
auto mapInfo = api.GetFullMap();
auto SelfInfo = api.GetSelfInfo();
auto cellx = api.GridToCell(SelfInfo->x);
auto celly = api.GridToCell(SelfInfo->y);
int flash = 0;
int i = cellx, j = celly;
if (place[0] == 2 )
{
for (flash = 0; i < (cellx + 10); i = i + 1)
{

for (; j < (celly + 10); j = j + 1)
{
if (mapInfo[i][j] == THUAI6::PlaceType::Chest)
{
flash = 1;
break;
}
}
if (flash == 1) break;
}
if (flash == 1)
{
place[0] = i; place[1] = j;
}
}
else if(1)
{double angle = atan2(place[1] - celly, place[0] - cellx);
api.Move(50, angle);
}
else
{
if (api.GetChestProgress(place[0], place[1]) < 10000000)
{
api.StartOpenChest();
}
else
{
auto PropInfo = api.GetProps();
api.PickProp(PropInfo[0]->type);
api.PickProp(PropInfo[1]->type);
}
}



// 玩家2执行操作
}
else if (this->playerID == 3)
{
GetTo(20, 20, api);
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}


+ 425
- 0
players/土木清华没有水/player4.cpp View File

@@ -0,0 +1,425 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

// 可以在AI.cpp内部声明变量与函数
bool move = false;
int place[2] = { 2,2 };
//全局变量,坐标
long long abs_X = 0;
long long abs_Y = 0;
//卡位微调参量
int Turn_little = 0;
bool Turn_can = 0;
bool Turn_flag = 1;
int Y_change = 0;
void GetTo(int32_t X, int32_t Y, IStudentAPI& api)//X,Y为格子坐标,api直接放api即可
{
//初始化参量
bool Y_can_go = 1, X_can_go = 1;
bool Down_Player;//下移参量,判断是否下移
bool Up_Player;//上移参量,判断是否上移
bool Left_Player;//左移参量
bool Right_Player;//右移参量
bool Go_Go_X = 1;//卡位参量 0卡位,1不卡位
bool Go_Go_Y = 1;//卡位参量 0卡位,1不卡位
auto Selfinfo = api.GetSelfInfo();//获取人物信息
auto X_player = api.GridToCell(Selfinfo->x);//得到人物坐标X(格子)
auto Y_player = api.GridToCell(Selfinfo->y);//得到人物坐标Y(格子)
//获得人物周边信息
auto Placetype_LU = api.GetPlaceType(X_player - 1, Y_player - 1);
auto Placetype_L0 = api.GetPlaceType(X_player, Y_player - 1);
auto Placetype_LD = api.GetPlaceType(X_player + 1, Y_player - 1);
auto Placetype_0U = api.GetPlaceType(X_player - 1, Y_player);
auto Placetype_00 = api.GetPlaceType(X_player, Y_player);
auto Placetype_0D = api.GetPlaceType(X_player + 1, Y_player);
auto Placetype_RU = api.GetPlaceType(X_player - 1, Y_player + 1);
auto Placetype_R0 = api.GetPlaceType(X_player, Y_player + 1);
auto Placetype_RD = api.GetPlaceType(X_player + 1, Y_player + 1);
//判断上下左右是否可走
int Left_can_go = (Placetype_L0 == THUAI6::PlaceType::Land || Placetype_L0 == THUAI6::PlaceType::Grass);
int Right_can_go = (Placetype_R0 == THUAI6::PlaceType::Land || Placetype_R0 == THUAI6::PlaceType::Grass);
int Up_can_go = (Placetype_0U == THUAI6::PlaceType::Land || Placetype_0U == THUAI6::PlaceType::Grass);
int Down_can_go = (Placetype_0D == THUAI6::PlaceType::Land || Placetype_0D == THUAI6::PlaceType::Grass);
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//判断朝向
if (X > X_player)//Down
{
Down_Player = true;
}
else Down_Player = false;
if (X < X_player)//Up
{
Up_Player = true;
}
else Up_Player = false;
if (Y < Y_player)//Left
{
Left_Player = true;
}
else Left_Player = false;
if (Y < Y_player)//Right
{
Right_Player = true;
}
else Right_Player = false;
//先保证X对齐
//可走则走
if (Down_Player == true && Down_can_go && Go_Go_X)
{
api.MoveDown(10);
}
if (Up_Player == true && Up_can_go && Go_Go_X)
{
api.MoveUp(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Down_Player == true && Down_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Up_Player == true && Up_can_go)
{
if ((Go_Go_X == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveLeft(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_X == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveRight(3);
}
else;
}
else;
if (Go_Go_X == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Down_Player == 1 && !Down_can_go && Go_Go_X)
{
if (Right_Player && Right_can_go)
{
api.MoveRight(20);
}
else if (Left_Player && Left_can_go)
{
api.MoveLeft(20);
}
else if (Left_can_go)
{
api.MoveLeft(20);
}
else if (Right_can_go)
{
api.MoveRight(20);
}
else Y_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!Y_can_go)
{
api.MoveUp(100);
}
else;
//
//Y方向在X对齐后仍采用相同的方法,但是调整后成功Y对齐后需要进行再一次X对齐,反复循环直到对齐
//
//
//
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}

//可走则走
if (Right_Player == true && Right_can_go && Go_Go_Y)
{
api.MoveRight(10);
}
if (Left_Player == true && Left_can_go && Go_Go_Y)
{
api.MoveLeft(10);
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//可走但是卡位,则微调,需要每次检查是否仍卡位
if (Right_Player == true && Right_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 15) Turn_flag = 0;
else;
if ((Go_Go_X == 0) && Turn_flag == 1 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Left_Player == true && Left_can_go)
{
if ((Go_Go_Y == 0) && Turn_can == 0 && Turn_flag == 1)
{
api.MoveUp(3);
Turn_little += 1;
}
else;
if (Turn_little >= 5) Turn_flag = 1;
else;
if ((Go_Go_Y == 0) && Turn_flag == 0 && Turn_can == 0)
{
api.MoveDown(3);
}
else;
}
else;
if (Go_Go_Y == 1)
{
Turn_little = 0;
Turn_can = 0;
Turn_flag = 1;
}
//判断是否卡位
Selfinfo = api.GetSelfInfo();
if ((abs_X == Selfinfo->x) && (abs_Y == Selfinfo->y))
{
Go_Go_X = 0;
Go_Go_Y = 0;//卡位
}
else
{
Go_Go_X = 1;
Go_Go_Y = 1;//未卡
}
//若X对齐时竖直受阻,则调整Y参量,直到可以继续对齐
//若是不可走,则水平调整,直到可走,先朝向Y调整,直到可走或者卡位,可走则继续,卡位则反向调整
if (Right_Player == 1 && !Right_can_go && Go_Go_Y)
{
if (Down_Player && Down_can_go)
{
api.MoveDown(20);
}
else if (Up_Player && Up_can_go)
{
api.MoveUp(20);
}
else if (Up_can_go)
{
api.MoveUp(20);
}
else if (Down_can_go)
{
api.MoveDown(20);
}
else X_can_go = 0;
}
//若反向调整仍不行,则向原X方向反向移动,再进行上述相同的调整,直到可以继续对齐
if (!X_can_go)
{
api.MoveUp(100);
}
else;







//保留最后坐标
auto Selfinfo_Last = api.GetSelfInfo();
abs_X = Selfinfo_Last->x;
abs_Y = Selfinfo_Last->y;

}


void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
GetTo(30, 30, api);




// 玩家0执行操作
}
else if (this->playerID == 1)
{
GetTo(10, 10, api);
// 玩家1执行操作
}
else if (this->playerID == 2)
{
auto mapInfo = api.GetFullMap();
auto SelfInfo = api.GetSelfInfo();
auto cellx = api.GridToCell(SelfInfo->x);
auto celly = api.GridToCell(SelfInfo->y);
int flash = 0;
int i = cellx, j = celly;
if (place[0] == 2 )
{
for (flash = 0; i < (cellx + 10); i = i + 1)
{

for (; j < (celly + 10); j = j + 1)
{
if (mapInfo[i][j] == THUAI6::PlaceType::Chest)
{
flash = 1;
break;
}
}
if (flash == 1) break;
}
if (flash == 1)
{
place[0] = i; place[1] = j;
}
}
else if(1)
{double angle = atan2(place[1] - celly, place[0] - cellx);
api.Move(50, angle);
}
else
{
if (api.GetChestProgress(place[0], place[1]) < 10000000)
{
api.StartOpenChest();
}
else
{
auto PropInfo = api.GetProps();
api.PickProp(PropInfo[0]->type);
api.PickProp(PropInfo[1]->type);
}
}



// 玩家2执行操作
}
else if (this->playerID == 3)
{
GetTo(20, 20, api);
// 玩家3执行操作
}
// 当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
}


+ 168
- 0
players/土木清华没有水/player5.cpp View File

@@ -0,0 +1,168 @@
#include <vector>
#include <thread>
#include <array>
#include <chrono>
#include <cmath>
#include "AI.h"
#include "constants.h"

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义

extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::Athlete,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine};

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
// 玩家2执行操作
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作
}

int PatrolMode = 0;

bool Passable(THUAI6::PlaceType a)
{
if (a == THUAI6::PlaceType::Land)return true;
else if (a == THUAI6::PlaceType::Grass)return true;
else return false;
}
void AI::play(ITrickerAPI& api)
{
auto self = api.GetSelfInfo();
api.PrintSelfInfo();
auto AllMap = api.GetFullMap();
int NumberOfAims = 0;
int x = api.GridToCell(self->x);
int y = api.GridToCell(self->y);
bool CenterLeft = self->y % 1000 <= 500;
bool CenterUp = self->x % 1000 <= 500;
auto Aims = api.GetStudents();
auto Aims_location = Aims.begin();
if(Aims.size() != 0)
for(;Aims_location!=Aims.end();++Aims_location)
{
if ((*Aims_location)->playerState != THUAI6::PlayerState::Addicted)NumberOfAims++;

}
Aims_location = Aims.begin();
if (NumberOfAims!=0)
{
int Aims_x = api.GridToCell((*Aims_location)->x);
int Aims_y = api.GridToCell((*Aims_location)->y);
double relative_x = (*Aims_location)->x - self->x;
double relative_y = (*Aims_location)->y - self->y;
double Aims_angle = atan2(relative_y,relative_x);
api.Move(20, Aims_angle);
if (relative_x*relative_x+relative_y*relative_y<=4000000&&(*Aims_location)->playerState!=THUAI6::PlayerState::Addicted)
{
api.Attack(Aims_angle);
}
//else if ((*Aims_location)->playerState == THUAI6::PlayerState::Addicted && Aims_location != Aims.end())
// {
// Aims_location++;
// }
//else if((*Aims_location)->playerState == THUAI6::PlayerState::Addicted)
}
else
{
switch (PatrolMode)
{
case 0:
if (Passable(api.GetPlaceType(x + 1, y)) && Passable(api.GetPlaceType(x + 1, y + 1 - CenterLeft * 2)))
{
api.MoveDown(20);
}
else
{
PatrolMode++;
}
break;
case 1:
if (Passable(api.GetPlaceType(x, y + 1)) && Passable(api.GetPlaceType(x + 1 - CenterUp * 2, y + 1 )) )
{
api.MoveRight(20);
}
else
{
PatrolMode++;
}
break;
case 2:
if (Passable(api.GetPlaceType(x-1, y )) && Passable(api.GetPlaceType(x - 1, y + 1 - CenterLeft * 2)) )
{
api.MoveUp(20);
}
else
{
PatrolMode++;
}
break;
case 3:
if (Passable(api.GetPlaceType(x, y - 1)) && Passable(api.GetPlaceType(x + 1 - CenterUp * 2, y - 1)))
{
api.MoveLeft(20);
}
else
{
PatrolMode++;
}
break;
default:
PatrolMode = 0;
break;
}
if (PatrolMode == 4)PatrolMode =0;

}
/*NullPlaceType = 0,
Land = 1,
Wall = 2,
Grass = 3,
ClassRoom = 4,
Gate = 5,
HiddenGate = 6,
Window = 7,
Door3 = 8,
Door5 = 9,
Door6 = 10,
Chest = 11,*/
}

+ 899
- 0
players/大括号换行委员会/player1.cpp View File

@@ -0,0 +1,899 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

#define M_PI 3.1415926535

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
auto sec = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();

class Point
{
public:
Point()
{
x = 0;
y = 0;
prex = 0;
prey = 0;
cost = 1;
sumcost = 0;
}
Point(int tx, int ty, int tprex = 0, int tprey = 0, int tcost = 0, int tsumcost = 0)
{
x = tx;
y = ty;
prex = tprex;
prey = tprey;
cost = tcost;
sumcost = tsumcost;
}

int x;
int y;
int prex;
int prey;
int cost;
int sumcost;
inline int32_t operator-(Point& p)
{
return (this->x - p.x) * (this->x - p.x) + (this->y - p.y) * (this->y - p.y);
}
};

int direction[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int moveStep = 50;
std::vector<Point> path;
int iPath = 0; // 指向下一目标位置的指针
const int x = 50;
const int y = 50;
Point map[x][y];

bool hasLearned[10] = { false, false, false, false, false, false, false, false, false, false };

using Place = THUAI6::PlaceType;
const std::vector<std::vector<THUAI6::PlaceType>> Map =
{
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Chest, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Gate, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Door5, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Door3, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Window,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Window, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Door5, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Chest, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Window,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Door3,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Door6,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Door6, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Chest, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Wall, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Door6, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Wall,
Place::Wall, Place::Window, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Gate, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
};




std::vector<Point> classrooms = {
{18, 5}, {30, 7}, {22, 18}, // Building 3
{8, 31}, {10, 38}, {19, 41}, // Building 5
{28, 26}, {33, 40}, {40, 12}, {44, 32} // Building 6
};


void initmap()
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
map[i][j].x = i;
map[i][j].y = j;
switch (Map[i][j])
{
case Place::Wall:
map[i][j].cost = 1000;
break;
default:
map[i][j].cost = 1;
break;
}
}
}
}

void findPath(Point begin, Point end)
{
path.clear();
iPath = 0;
std::vector<Point> extending;
std::vector<Point> unextended;
std::vector<Point> extended;
int min = 0;

extended.push_back(begin);

for (int i = 0; i < 4; i++)
{
if (extended[0].x + direction[i][0] >= 0 && extended[0].x + direction[i][0] < x && extended[0].y + direction[i][1] < y && extended[0].y + direction[i][1] >= 0)
{
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].sumcost = extended[0].sumcost + map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].cost;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prex = begin.x;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prey = begin.y;

extending.push_back(map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]]);

}
}

while (!extending.empty())
{

if (extending.size() > 1)
{
min = 0;
for (int i = 1; i < extending.size(); i++)
{
//find the point in extending whose sumcost is least
if (extending[i].sumcost < extending[min].sumcost)
{
min = i;
}
}
}
else
{
min = 0;
}
int flag = 0;
int flag1 = 0;
for (int i = 0; i < 4; i++)
{
if (extending[min].x + direction[i][0] >= 0 && extending[min].x + direction[i][0] < x && extending[min].y + direction[i][1] < y && extending[min].y + direction[i][1] >= 0)
{
for (int j = 0; j < extended.size(); j++)
{
if (extending[min].x + direction[i][0] == extended[j].x && extending[min].y + direction[i][1] == extended[j].y)
{

flag++; //the point has added in extended
}
}

if (flag == 0) //the point is not extended
{
for (int k = 0; k < extending.size(); k++)
{
if (map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].x == extending[k].x && map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].y == extending[k].y)
{
if (extending[k].sumcost > extending[min].sumcost + extending[k].cost)
{
extending[k].sumcost = extending[min].sumcost + extending[k].cost;
extending[k].prex = extending[min].x;
extending[k].prey = extending[min].y;
}
flag1++;
}
}
if (flag1 == 0)
{
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].sumcost = extending[min].sumcost + map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].cost;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prex = extending[min].x;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prey = extending[min].y;
extending.push_back(map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]]);
}

}
}
flag = 0;
flag1 = 0;
}
extended.push_back(extending[min]);
extending.erase(extending.begin() + min);
}


Point temp;
for (int i = 0; i < extended.size(); i++)
{
if (extended[i].x == end.x && extended[i].y == end.y)
{
temp = extended[i];
while (1)
{
if (temp.x != begin.x || temp.y != begin.y)
{
path.push_back(temp);
temp = map[temp.prex][temp.prey];
}
else
{
path.push_back(begin);
return;
}
}
while (temp.prex != begin.x || temp.prey != begin.y);
{

}
path.push_back(begin);

}
}

}


Point GetNearestClass(int xCell, int yCell)
{
Point res, now{ xCell, yCell };
int32_t min = 0x3f3f3f3f;
for (int i = 0; i < classrooms.size(); ++i)
{
Point temp = classrooms[i];
if (!hasLearned[i])
{
int32_t dist = temp - now;
if (dist < min)
{
min = dist;
res = temp;
}
}
}
return res;
}

Point GoToClass(IStudentAPI& api)
{
auto self = api.GetSelfInfo();
auto target = GetNearestClass(api.GridToCell(self->x), api.GridToCell(self->y));

double deg = atan2(target.y - api.GridToCell(self->y), target.x - api.GridToCell(self->x));
api.Move(Constants::frameDuration, deg);
return target;
}

void EscapeFromTricker(IStudentAPI& api)
{
auto tricker = api.GetTrickers();
if (!tricker.size()) return;

auto player = api.GetSelfInfo();
double deg = atan2(player->y - tricker[0]->y, player->x - tricker[0]->x);
int xCell = api.GridToCell(player->x), yCell = api.GridToCell(player->y);
auto gridType = api.GetPlaceType(xCell, yCell);

//switch (gridType)
//{
// case THUAI6::PlaceType::Land:
// api.Move(Constants::frameDuration, deg);
// break;
//}

api.Move(Constants::frameDuration, deg);
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作

if (api.GetFrameCount() == 1) {
initmap(); // 初始化地图
api.Print("地图初始化完毕");
}

EscapeFromTricker(api);
Point classroom = GoToClass(api);
api.StartLearning();
if (api.GetClassroomProgress(classroom.x, classroom.y) == Constants::maxClassroomProgress)
{
for (int i = 0; i < classrooms.size(); ++i)
{
if (classrooms[i].x == classroom.x && classrooms[i].y == classroom.y)
{
hasLearned[i] = true;
for (int j = 0; j < 4; ++j)
{
api.SendMessage(j, fmt::format("{}", i));
}
break;
}
}
}

if (api.HaveMessage())
{
auto msg = api.GetMessage();
int classroomID = msg.second[0] - '0';
hasLearned[classroomID] = true;
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}



/*鬼相关函数*/

// 视野内有人
int isStudentinView(ITrickerAPI& api) {
auto info = api.GetStudents();
return (info.size() != 0);
}

void avoidObstacles(ITrickerAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

void AI::play(ITrickerAPI& api)
{
auto selfInfo = api.GetSelfInfo();
auto myPos = Point(selfInfo->x, selfInfo->y);
api.PrintSelfInfo();
if (isStudentinView(api)) {

// 追击
auto studentInfo = api.GetStudents();
auto selfInfo = api.GetSelfInfo();
auto dx = studentInfo[0]->x - selfInfo->x;
auto dy = studentInfo[0]->y - selfInfo->y;
auto dirc = atan2(dy, dx);

avoidObstacles(api, dirc);
api.Move(moveStep, dirc);
double distance = sqrt(dx * dx + dy + dy);
if (distance < Constants::basicAttackShortRange) {
api.Attack(dirc);
}
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}

+ 899
- 0
players/大括号换行委员会/player2.cpp View File

@@ -0,0 +1,899 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

#define M_PI 3.1415926535

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
auto sec = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();

class Point
{
public:
Point()
{
x = 0;
y = 0;
prex = 0;
prey = 0;
cost = 1;
sumcost = 0;
}
Point(int tx, int ty, int tprex = 0, int tprey = 0, int tcost = 0, int tsumcost = 0)
{
x = tx;
y = ty;
prex = tprex;
prey = tprey;
cost = tcost;
sumcost = tsumcost;
}

int x;
int y;
int prex;
int prey;
int cost;
int sumcost;
inline int32_t operator-(Point& p)
{
return (this->x - p.x) * (this->x - p.x) + (this->y - p.y) * (this->y - p.y);
}
};

int direction[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int moveStep = 50;
std::vector<Point> path;
int iPath = 0; // 指向下一目标位置的指针
const int x = 50;
const int y = 50;
Point map[x][y];

bool hasLearned[10] = { false, false, false, false, false, false, false, false, false, false };

using Place = THUAI6::PlaceType;
const std::vector<std::vector<THUAI6::PlaceType>> Map =
{
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Chest, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Gate, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Door5, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Door3, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Window,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Window, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Door5, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Chest, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Window,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Door3,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Door6,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Door6, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Chest, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Wall, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Door6, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Wall,
Place::Wall, Place::Window, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Gate, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
};




std::vector<Point> classrooms = {
{18, 5}, {30, 7}, {22, 18}, // Building 3
{8, 31}, {10, 38}, {19, 41}, // Building 5
{28, 26}, {33, 40}, {40, 12}, {44, 32} // Building 6
};


void initmap()
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
map[i][j].x = i;
map[i][j].y = j;
switch (Map[i][j])
{
case Place::Wall:
map[i][j].cost = 1000;
break;
default:
map[i][j].cost = 1;
break;
}
}
}
}

void findPath(Point begin, Point end)
{
path.clear();
iPath = 0;
std::vector<Point> extending;
std::vector<Point> unextended;
std::vector<Point> extended;
int min = 0;

extended.push_back(begin);

for (int i = 0; i < 4; i++)
{
if (extended[0].x + direction[i][0] >= 0 && extended[0].x + direction[i][0] < x && extended[0].y + direction[i][1] < y && extended[0].y + direction[i][1] >= 0)
{
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].sumcost = extended[0].sumcost + map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].cost;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prex = begin.x;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prey = begin.y;

extending.push_back(map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]]);

}
}

while (!extending.empty())
{

if (extending.size() > 1)
{
min = 0;
for (int i = 1; i < extending.size(); i++)
{
//find the point in extending whose sumcost is least
if (extending[i].sumcost < extending[min].sumcost)
{
min = i;
}
}
}
else
{
min = 0;
}
int flag = 0;
int flag1 = 0;
for (int i = 0; i < 4; i++)
{
if (extending[min].x + direction[i][0] >= 0 && extending[min].x + direction[i][0] < x && extending[min].y + direction[i][1] < y && extending[min].y + direction[i][1] >= 0)
{
for (int j = 0; j < extended.size(); j++)
{
if (extending[min].x + direction[i][0] == extended[j].x && extending[min].y + direction[i][1] == extended[j].y)
{

flag++; //the point has added in extended
}
}

if (flag == 0) //the point is not extended
{
for (int k = 0; k < extending.size(); k++)
{
if (map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].x == extending[k].x && map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].y == extending[k].y)
{
if (extending[k].sumcost > extending[min].sumcost + extending[k].cost)
{
extending[k].sumcost = extending[min].sumcost + extending[k].cost;
extending[k].prex = extending[min].x;
extending[k].prey = extending[min].y;
}
flag1++;
}
}
if (flag1 == 0)
{
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].sumcost = extending[min].sumcost + map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].cost;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prex = extending[min].x;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prey = extending[min].y;
extending.push_back(map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]]);
}

}
}
flag = 0;
flag1 = 0;
}
extended.push_back(extending[min]);
extending.erase(extending.begin() + min);
}


Point temp;
for (int i = 0; i < extended.size(); i++)
{
if (extended[i].x == end.x && extended[i].y == end.y)
{
temp = extended[i];
while (1)
{
if (temp.x != begin.x || temp.y != begin.y)
{
path.push_back(temp);
temp = map[temp.prex][temp.prey];
}
else
{
path.push_back(begin);
return;
}
}
while (temp.prex != begin.x || temp.prey != begin.y);
{

}
path.push_back(begin);

}
}

}


Point GetNearestClass(int xCell, int yCell)
{
Point res, now{ xCell, yCell };
int32_t min = 0x3f3f3f3f;
for (int i = 0; i < classrooms.size(); ++i)
{
Point temp = classrooms[i];
if (!hasLearned[i])
{
int32_t dist = temp - now;
if (dist < min)
{
min = dist;
res = temp;
}
}
}
return res;
}

Point GoToClass(IStudentAPI& api)
{
auto self = api.GetSelfInfo();
auto target = GetNearestClass(api.GridToCell(self->x), api.GridToCell(self->y));

double deg = atan2(target.y - api.GridToCell(self->y), target.x - api.GridToCell(self->x));
api.Move(Constants::frameDuration, deg);
return target;
}

void EscapeFromTricker(IStudentAPI& api)
{
auto tricker = api.GetTrickers();
if (!tricker.size()) return;

auto player = api.GetSelfInfo();
double deg = atan2(player->y - tricker[0]->y, player->x - tricker[0]->x);
int xCell = api.GridToCell(player->x), yCell = api.GridToCell(player->y);
auto gridType = api.GetPlaceType(xCell, yCell);

//switch (gridType)
//{
// case THUAI6::PlaceType::Land:
// api.Move(Constants::frameDuration, deg);
// break;
//}

api.Move(Constants::frameDuration, deg);
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作

if (api.GetFrameCount() == 1) {
initmap(); // 初始化地图
api.Print("地图初始化完毕");
}

EscapeFromTricker(api);
Point classroom = GoToClass(api);
api.StartLearning();
if (api.GetClassroomProgress(classroom.x, classroom.y) == Constants::maxClassroomProgress)
{
for (int i = 0; i < classrooms.size(); ++i)
{
if (classrooms[i].x == classroom.x && classrooms[i].y == classroom.y)
{
hasLearned[i] = true;
for (int j = 0; j < 4; ++j)
{
api.SendMessage(j, fmt::format("{}", i));
}
break;
}
}
}

if (api.HaveMessage())
{
auto msg = api.GetMessage();
int classroomID = msg.second[0] - '0';
hasLearned[classroomID] = true;
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}



/*鬼相关函数*/

// 视野内有人
int isStudentinView(ITrickerAPI& api) {
auto info = api.GetStudents();
return (info.size() != 0);
}

void avoidObstacles(ITrickerAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

void AI::play(ITrickerAPI& api)
{
auto selfInfo = api.GetSelfInfo();
auto myPos = Point(selfInfo->x, selfInfo->y);
api.PrintSelfInfo();
if (isStudentinView(api)) {

// 追击
auto studentInfo = api.GetStudents();
auto selfInfo = api.GetSelfInfo();
auto dx = studentInfo[0]->x - selfInfo->x;
auto dy = studentInfo[0]->y - selfInfo->y;
auto dirc = atan2(dy, dx);

avoidObstacles(api, dirc);
api.Move(moveStep, dirc);
double distance = sqrt(dx * dx + dy + dy);
if (distance < Constants::basicAttackShortRange) {
api.Attack(dirc);
}
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}

+ 899
- 0
players/大括号换行委员会/player3.cpp View File

@@ -0,0 +1,899 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

#define M_PI 3.1415926535

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
auto sec = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();

class Point
{
public:
Point()
{
x = 0;
y = 0;
prex = 0;
prey = 0;
cost = 1;
sumcost = 0;
}
Point(int tx, int ty, int tprex = 0, int tprey = 0, int tcost = 0, int tsumcost = 0)
{
x = tx;
y = ty;
prex = tprex;
prey = tprey;
cost = tcost;
sumcost = tsumcost;
}

int x;
int y;
int prex;
int prey;
int cost;
int sumcost;
inline int32_t operator-(Point& p)
{
return (this->x - p.x) * (this->x - p.x) + (this->y - p.y) * (this->y - p.y);
}
};

int direction[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int moveStep = 50;
std::vector<Point> path;
int iPath = 0; // 指向下一目标位置的指针
const int x = 50;
const int y = 50;
Point map[x][y];

bool hasLearned[10] = { false, false, false, false, false, false, false, false, false, false };

using Place = THUAI6::PlaceType;
const std::vector<std::vector<THUAI6::PlaceType>> Map =
{
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Chest, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Gate, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Door5, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Door3, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Window,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Window, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Door5, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Chest, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Window,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Door3,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Door6,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Door6, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Chest, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Wall, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Door6, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Wall,
Place::Wall, Place::Window, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Gate, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
};




std::vector<Point> classrooms = {
{18, 5}, {30, 7}, {22, 18}, // Building 3
{8, 31}, {10, 38}, {19, 41}, // Building 5
{28, 26}, {33, 40}, {40, 12}, {44, 32} // Building 6
};


void initmap()
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
map[i][j].x = i;
map[i][j].y = j;
switch (Map[i][j])
{
case Place::Wall:
map[i][j].cost = 1000;
break;
default:
map[i][j].cost = 1;
break;
}
}
}
}

void findPath(Point begin, Point end)
{
path.clear();
iPath = 0;
std::vector<Point> extending;
std::vector<Point> unextended;
std::vector<Point> extended;
int min = 0;

extended.push_back(begin);

for (int i = 0; i < 4; i++)
{
if (extended[0].x + direction[i][0] >= 0 && extended[0].x + direction[i][0] < x && extended[0].y + direction[i][1] < y && extended[0].y + direction[i][1] >= 0)
{
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].sumcost = extended[0].sumcost + map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].cost;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prex = begin.x;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prey = begin.y;

extending.push_back(map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]]);

}
}

while (!extending.empty())
{

if (extending.size() > 1)
{
min = 0;
for (int i = 1; i < extending.size(); i++)
{
//find the point in extending whose sumcost is least
if (extending[i].sumcost < extending[min].sumcost)
{
min = i;
}
}
}
else
{
min = 0;
}
int flag = 0;
int flag1 = 0;
for (int i = 0; i < 4; i++)
{
if (extending[min].x + direction[i][0] >= 0 && extending[min].x + direction[i][0] < x && extending[min].y + direction[i][1] < y && extending[min].y + direction[i][1] >= 0)
{
for (int j = 0; j < extended.size(); j++)
{
if (extending[min].x + direction[i][0] == extended[j].x && extending[min].y + direction[i][1] == extended[j].y)
{

flag++; //the point has added in extended
}
}

if (flag == 0) //the point is not extended
{
for (int k = 0; k < extending.size(); k++)
{
if (map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].x == extending[k].x && map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].y == extending[k].y)
{
if (extending[k].sumcost > extending[min].sumcost + extending[k].cost)
{
extending[k].sumcost = extending[min].sumcost + extending[k].cost;
extending[k].prex = extending[min].x;
extending[k].prey = extending[min].y;
}
flag1++;
}
}
if (flag1 == 0)
{
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].sumcost = extending[min].sumcost + map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].cost;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prex = extending[min].x;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prey = extending[min].y;
extending.push_back(map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]]);
}

}
}
flag = 0;
flag1 = 0;
}
extended.push_back(extending[min]);
extending.erase(extending.begin() + min);
}


Point temp;
for (int i = 0; i < extended.size(); i++)
{
if (extended[i].x == end.x && extended[i].y == end.y)
{
temp = extended[i];
while (1)
{
if (temp.x != begin.x || temp.y != begin.y)
{
path.push_back(temp);
temp = map[temp.prex][temp.prey];
}
else
{
path.push_back(begin);
return;
}
}
while (temp.prex != begin.x || temp.prey != begin.y);
{

}
path.push_back(begin);

}
}

}


Point GetNearestClass(int xCell, int yCell)
{
Point res, now{ xCell, yCell };
int32_t min = 0x3f3f3f3f;
for (int i = 0; i < classrooms.size(); ++i)
{
Point temp = classrooms[i];
if (!hasLearned[i])
{
int32_t dist = temp - now;
if (dist < min)
{
min = dist;
res = temp;
}
}
}
return res;
}

Point GoToClass(IStudentAPI& api)
{
auto self = api.GetSelfInfo();
auto target = GetNearestClass(api.GridToCell(self->x), api.GridToCell(self->y));

double deg = atan2(target.y - api.GridToCell(self->y), target.x - api.GridToCell(self->x));
api.Move(Constants::frameDuration, deg);
return target;
}

void EscapeFromTricker(IStudentAPI& api)
{
auto tricker = api.GetTrickers();
if (!tricker.size()) return;

auto player = api.GetSelfInfo();
double deg = atan2(player->y - tricker[0]->y, player->x - tricker[0]->x);
int xCell = api.GridToCell(player->x), yCell = api.GridToCell(player->y);
auto gridType = api.GetPlaceType(xCell, yCell);

//switch (gridType)
//{
// case THUAI6::PlaceType::Land:
// api.Move(Constants::frameDuration, deg);
// break;
//}

api.Move(Constants::frameDuration, deg);
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作

if (api.GetFrameCount() == 1) {
initmap(); // 初始化地图
api.Print("地图初始化完毕");
}

EscapeFromTricker(api);
Point classroom = GoToClass(api);
api.StartLearning();
if (api.GetClassroomProgress(classroom.x, classroom.y) == Constants::maxClassroomProgress)
{
for (int i = 0; i < classrooms.size(); ++i)
{
if (classrooms[i].x == classroom.x && classrooms[i].y == classroom.y)
{
hasLearned[i] = true;
for (int j = 0; j < 4; ++j)
{
api.SendMessage(j, fmt::format("{}", i));
}
break;
}
}
}

if (api.HaveMessage())
{
auto msg = api.GetMessage();
int classroomID = msg.second[0] - '0';
hasLearned[classroomID] = true;
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}



/*鬼相关函数*/

// 视野内有人
int isStudentinView(ITrickerAPI& api) {
auto info = api.GetStudents();
return (info.size() != 0);
}

void avoidObstacles(ITrickerAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

void AI::play(ITrickerAPI& api)
{
auto selfInfo = api.GetSelfInfo();
auto myPos = Point(selfInfo->x, selfInfo->y);
api.PrintSelfInfo();
if (isStudentinView(api)) {

// 追击
auto studentInfo = api.GetStudents();
auto selfInfo = api.GetSelfInfo();
auto dx = studentInfo[0]->x - selfInfo->x;
auto dy = studentInfo[0]->y - selfInfo->y;
auto dirc = atan2(dy, dx);

avoidObstacles(api, dirc);
api.Move(moveStep, dirc);
double distance = sqrt(dx * dx + dy + dy);
if (distance < Constants::basicAttackShortRange) {
api.Attack(dirc);
}
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}

+ 899
- 0
players/大括号换行委员会/player4.cpp View File

@@ -0,0 +1,899 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

#define M_PI 3.1415926535

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::StraightAStudent };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
auto sec = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();

class Point
{
public:
Point()
{
x = 0;
y = 0;
prex = 0;
prey = 0;
cost = 1;
sumcost = 0;
}
Point(int tx, int ty, int tprex = 0, int tprey = 0, int tcost = 0, int tsumcost = 0)
{
x = tx;
y = ty;
prex = tprex;
prey = tprey;
cost = tcost;
sumcost = tsumcost;
}

int x;
int y;
int prex;
int prey;
int cost;
int sumcost;
inline int32_t operator-(Point& p)
{
return (this->x - p.x) * (this->x - p.x) + (this->y - p.y) * (this->y - p.y);
}
};

int direction[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int moveStep = 50;
std::vector<Point> path;
int iPath = 0; // 指向下一目标位置的指针
const int x = 50;
const int y = 50;
Point map[x][y];

bool hasLearned[10] = { false, false, false, false, false, false, false, false, false, false };

using Place = THUAI6::PlaceType;
const std::vector<std::vector<THUAI6::PlaceType>> Map =
{
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Chest, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Gate, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Door5, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Door3, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Window,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Window, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Door5, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Chest, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Window,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Door3,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Door6,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Door6, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Chest, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Wall, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Door6, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Wall,
Place::Wall, Place::Window, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Gate, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
};




std::vector<Point> classrooms = {
{18, 5}, {30, 7}, {22, 18}, // Building 3
{8, 31}, {10, 38}, {19, 41}, // Building 5
{28, 26}, {33, 40}, {40, 12}, {44, 32} // Building 6
};


void initmap()
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
map[i][j].x = i;
map[i][j].y = j;
switch (Map[i][j])
{
case Place::Wall:
map[i][j].cost = 1000;
break;
default:
map[i][j].cost = 1;
break;
}
}
}
}

void findPath(Point begin, Point end)
{
path.clear();
iPath = 0;
std::vector<Point> extending;
std::vector<Point> unextended;
std::vector<Point> extended;
int min = 0;

extended.push_back(begin);

for (int i = 0; i < 4; i++)
{
if (extended[0].x + direction[i][0] >= 0 && extended[0].x + direction[i][0] < x && extended[0].y + direction[i][1] < y && extended[0].y + direction[i][1] >= 0)
{
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].sumcost = extended[0].sumcost + map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].cost;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prex = begin.x;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prey = begin.y;

extending.push_back(map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]]);

}
}

while (!extending.empty())
{

if (extending.size() > 1)
{
min = 0;
for (int i = 1; i < extending.size(); i++)
{
//find the point in extending whose sumcost is least
if (extending[i].sumcost < extending[min].sumcost)
{
min = i;
}
}
}
else
{
min = 0;
}
int flag = 0;
int flag1 = 0;
for (int i = 0; i < 4; i++)
{
if (extending[min].x + direction[i][0] >= 0 && extending[min].x + direction[i][0] < x && extending[min].y + direction[i][1] < y && extending[min].y + direction[i][1] >= 0)
{
for (int j = 0; j < extended.size(); j++)
{
if (extending[min].x + direction[i][0] == extended[j].x && extending[min].y + direction[i][1] == extended[j].y)
{

flag++; //the point has added in extended
}
}

if (flag == 0) //the point is not extended
{
for (int k = 0; k < extending.size(); k++)
{
if (map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].x == extending[k].x && map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].y == extending[k].y)
{
if (extending[k].sumcost > extending[min].sumcost + extending[k].cost)
{
extending[k].sumcost = extending[min].sumcost + extending[k].cost;
extending[k].prex = extending[min].x;
extending[k].prey = extending[min].y;
}
flag1++;
}
}
if (flag1 == 0)
{
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].sumcost = extending[min].sumcost + map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].cost;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prex = extending[min].x;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prey = extending[min].y;
extending.push_back(map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]]);
}

}
}
flag = 0;
flag1 = 0;
}
extended.push_back(extending[min]);
extending.erase(extending.begin() + min);
}


Point temp;
for (int i = 0; i < extended.size(); i++)
{
if (extended[i].x == end.x && extended[i].y == end.y)
{
temp = extended[i];
while (1)
{
if (temp.x != begin.x || temp.y != begin.y)
{
path.push_back(temp);
temp = map[temp.prex][temp.prey];
}
else
{
path.push_back(begin);
return;
}
}
while (temp.prex != begin.x || temp.prey != begin.y);
{

}
path.push_back(begin);

}
}

}


Point GetNearestClass(int xCell, int yCell)
{
Point res, now{ xCell, yCell };
int32_t min = 0x3f3f3f3f;
for (int i = 0; i < classrooms.size(); ++i)
{
Point temp = classrooms[i];
if (!hasLearned[i])
{
int32_t dist = temp - now;
if (dist < min)
{
min = dist;
res = temp;
}
}
}
return res;
}

Point GoToClass(IStudentAPI& api)
{
auto self = api.GetSelfInfo();
auto target = GetNearestClass(api.GridToCell(self->x), api.GridToCell(self->y));

double deg = atan2(target.y - api.GridToCell(self->y), target.x - api.GridToCell(self->x));
api.Move(Constants::frameDuration, deg);
return target;
}

void EscapeFromTricker(IStudentAPI& api)
{
auto tricker = api.GetTrickers();
if (!tricker.size()) return;

auto player = api.GetSelfInfo();
double deg = atan2(player->y - tricker[0]->y, player->x - tricker[0]->x);
int xCell = api.GridToCell(player->x), yCell = api.GridToCell(player->y);
auto gridType = api.GetPlaceType(xCell, yCell);

//switch (gridType)
//{
// case THUAI6::PlaceType::Land:
// api.Move(Constants::frameDuration, deg);
// break;
//}

api.Move(Constants::frameDuration, deg);
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{
}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作

if (api.GetFrameCount() == 1) {
initmap(); // 初始化地图
api.Print("地图初始化完毕");
}

EscapeFromTricker(api);
Point classroom = GoToClass(api);
api.StartLearning();
if (api.GetClassroomProgress(classroom.x, classroom.y) == Constants::maxClassroomProgress)
{
for (int i = 0; i < classrooms.size(); ++i)
{
if (classrooms[i].x == classroom.x && classrooms[i].y == classroom.y)
{
hasLearned[i] = true;
for (int j = 0; j < 4; ++j)
{
api.SendMessage(j, fmt::format("{}", i));
}
break;
}
}
}

if (api.HaveMessage())
{
auto msg = api.GetMessage();
int classroomID = msg.second[0] - '0';
hasLearned[classroomID] = true;
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}



/*鬼相关函数*/

// 视野内有人
int isStudentinView(ITrickerAPI& api) {
auto info = api.GetStudents();
return (info.size() != 0);
}

void avoidObstacles(ITrickerAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

void AI::play(ITrickerAPI& api)
{
auto selfInfo = api.GetSelfInfo();
auto myPos = Point(selfInfo->x, selfInfo->y);
api.PrintSelfInfo();
if (isStudentinView(api)) {

// 追击
auto studentInfo = api.GetStudents();
auto selfInfo = api.GetSelfInfo();
auto dx = studentInfo[0]->x - selfInfo->x;
auto dy = studentInfo[0]->y - selfInfo->y;
auto dirc = atan2(dy, dx);

avoidObstacles(api, dirc);
api.Move(moveStep, dirc);
double distance = sqrt(dx * dx + dy + dy);
if (distance < Constants::basicAttackShortRange) {
api.Attack(dirc);
}
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}

+ 930
- 0
players/大括号换行委员会/player5.cpp View File

@@ -0,0 +1,930 @@
#include <vector>
#include <thread>
#include <array>
#include "AI.h"
#include "constants.h"

#define M_PI 3.1415926535

// 为假则play()期间确保游戏状态不更新,为真则只保证游戏状态在调用相关方法时不更新
extern const bool asynchronous = false;

// 选手需要依次将player0到player4的职业在这里定义
extern const std::array<THUAI6::StudentType, 4> studentType = {
THUAI6::StudentType::StraightAStudent,
THUAI6::StudentType::Sunshine,
THUAI6::StudentType::Teacher,
THUAI6::StudentType::StraightAStudent };

extern const THUAI6::TrickerType trickerType = THUAI6::TrickerType::Assassin;

//可以在AI.cpp内部声明变量与函数
auto sec = std::chrono::duration_cast<std::chrono::milliseconds>
(std::chrono::system_clock::now().time_since_epoch()).count();

class Point
{
public:
Point()
{
x = 0;
y = 0;
prex = 0;
prey = 0;
cost = 1;
sumcost = 0;
}
Point(int tx, int ty, int tprex = 0, int tprey = 0, int tcost = 0, int tsumcost = 0)
{
x = tx;
y = ty;
prex = tprex;
prey = tprey;
cost = tcost;
sumcost = tsumcost;
}

int x;
int y;
int prex;
int prey;
int cost;
int sumcost;
inline int32_t operator-(Point& p)
{
return (this->x - p.x) * (this->x - p.x) + (this->y - p.y) * (this->y - p.y);
}
};

int direction[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
int moveStep = 50;
std::vector<Point> path;
int iPath = 0; // 指向下一目标位置的指针
const int x = 50;
const int y = 50;
Point map[x][y];

bool hasLearned[10] = { false, false, false, false, false, false, false, false, false, false };

using Place = THUAI6::PlaceType;
const std::vector<std::vector<THUAI6::PlaceType>> Map =
{
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Chest, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Gate, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Grass, Place::Wall, Place::Wall, Place::Grass,
Place::Grass, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Door5, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Door3, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Window,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Window, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Door5, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Chest, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::ClassRoom, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Window, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Window,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Door3,
Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::ClassRoom, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Door6,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Chest, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Grass, Place::Grass,
Place::Grass, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Grass, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Window, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Grass, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::ClassRoom, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Grass,
Place::Grass, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Door6, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Chest, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Window, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Grass, Place::Grass, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Wall, Place::Grass, Place::Grass, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Wall,
Place::Door6, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Grass,
Place::Land, Place::Land, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Land, Place::Wall, Place::Wall, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Grass, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::ClassRoom, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Wall, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Wall, Place::Grass, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Window, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Wall, Place::Wall, Place::Grass, Place::Grass, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Wall, Place::Wall,
Place::Wall, Place::Window, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Gate, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Grass,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Grass, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Wall, Place::Wall, Place::Grass,
Place::Chest, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Land, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Land, Place::Wall, Place::Land,
Place::Land, Place::Land, Place::Grass, Place::Grass, Place::Wall,
Place::Wall, Place::Land, Place::Land, Place::Land, Place::Wall},
{Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall,
Place::Wall, Place::Wall, Place::Wall, Place::Wall, Place::Wall},
};




std::vector<Point> classrooms = {
{18, 5}, {30, 7}, {22, 18}, // Building 3
{8, 31}, {10, 38}, {19, 41}, // Building 5
{28, 26}, {33, 40}, {40, 12}, {44, 32} // Building 6
};


void initmap()
{
for (int i = 0; i < x; i++)
{
for (int j = 0; j < y; j++)
{
map[i][j].x = i;
map[i][j].y = j;
switch (Map[i][j])
{
case Place::Wall:
map[i][j].cost = 1000;
break;
default:
map[i][j].cost = 1;
break;
}
}
}
}

void findPath(Point begin, Point end)
{
path.clear();
iPath = 0;
std::vector<Point> extending;
std::vector<Point> unextended;
std::vector<Point> extended;
int min = 0;

extended.push_back(begin);

for (int i = 0; i < 4; i++)
{
if (extended[0].x + direction[i][0] >= 0 && extended[0].x + direction[i][0] < x && extended[0].y + direction[i][1] < y && extended[0].y + direction[i][1] >= 0)
{
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].sumcost = extended[0].sumcost + map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].cost;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prex = begin.x;
map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]].prey = begin.y;

extending.push_back(map[extended[0].x + direction[i][0]][extended[0].y + direction[i][1]]);

}
}

while (!extending.empty())
{

if (extending.size() > 1)
{
min = 0;
for (int i = 1; i < extending.size(); i++)
{
//find the point in extending whose sumcost is least
if (extending[i].sumcost < extending[min].sumcost)
{
min = i;
}
}
}
else
{
min = 0;
}
int flag = 0;
int flag1 = 0;
for (int i = 0; i < 4; i++)
{
if (extending[min].x + direction[i][0] >= 0 && extending[min].x + direction[i][0] < x && extending[min].y + direction[i][1] < y && extending[min].y + direction[i][1] >= 0)
{
for (int j = 0; j < extended.size(); j++)
{
if (extending[min].x + direction[i][0] == extended[j].x && extending[min].y + direction[i][1] == extended[j].y)
{

flag++; //the point has added in extended
}
}

if (flag == 0) //the point is not extended
{
for (int k = 0; k < extending.size(); k++)
{
if (map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].x == extending[k].x && map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].y == extending[k].y)
{
if (extending[k].sumcost > extending[min].sumcost + extending[k].cost)
{
extending[k].sumcost = extending[min].sumcost + extending[k].cost;
extending[k].prex = extending[min].x;
extending[k].prey = extending[min].y;
}
flag1++;
}
}
if (flag1 == 0)
{
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].sumcost = extending[min].sumcost + map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].cost;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prex = extending[min].x;
map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]].prey = extending[min].y;
extending.push_back(map[extending[min].x + direction[i][0]][extending[min].y + direction[i][1]]);
}

}
}
flag = 0;
flag1 = 0;
}
extended.push_back(extending[min]);
extending.erase(extending.begin() + min);
}


Point temp;
for (int i = 0; i < extended.size(); i++)
{
if (extended[i].x == end.x && extended[i].y == end.y)
{
temp = extended[i];
while (1)
{
if (temp.x != begin.x || temp.y != begin.y)
{
path.push_back(temp);
temp = map[temp.prex][temp.prey];
}
else
{
path.push_back(begin);
return;
}
}
while (temp.prex != begin.x || temp.prey != begin.y);
{

}
path.push_back(begin);

}
}

}

void avoidObstacles(IStudentAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

Point GetNearestClass(int xCell, int yCell)
{
Point res, now{ xCell, yCell };
int32_t min = 0x3f3f3f3f;
for (int i = 0; i < classrooms.size(); ++i)
{
Point temp = classrooms[i];
if (!hasLearned[i])
{
int32_t dist = temp - now;
if (dist < min)
{
min = dist;
res = temp;
}
}
}
return res;
}

Point GoToClass(IStudentAPI& api)
{
auto self = api.GetSelfInfo();
auto target = GetNearestClass(api.GridToCell(self->x), api.GridToCell(self->y));

double deg = atan2(target.y - api.GridToCell(self->y), target.x - api.GridToCell(self->x));
api.Move(Constants::frameDuration, deg);
avoidObstacles(api, deg); // 尝试避障
return target;
}

void EscapeFromTricker(IStudentAPI& api)
{
auto tricker = api.GetTrickers();
if (!tricker.size()) return;

auto player = api.GetSelfInfo();
double deg = atan2(player->y - tricker[0]->y, player->x - tricker[0]->x);
int xCell = api.GridToCell(player->x), yCell = api.GridToCell(player->y);
auto gridType = api.GetPlaceType(xCell, yCell);

//switch (gridType)
//{
// case THUAI6::PlaceType::Land:
// api.Move(Constants::frameDuration, deg);
// break;
//}

api.Move(Constants::frameDuration, deg);
}

void AI::play(IStudentAPI& api)
{
// 公共操作
if (this->playerID == 0)
{
// 玩家0执行操作
}
else if (this->playerID == 1)
{
// 玩家1执行操作
}
else if (this->playerID == 2)
{

}
else if (this->playerID == 3)
{
// 玩家3执行操作
}
//当然可以写成if (this->playerID == 2||this->playerID == 3)之类的操作
// 公共操作

if (api.GetFrameCount() == 1) {
initmap(); // 初始化地图
api.Print("地图初始化完毕");
}

EscapeFromTricker(api);
Point classroom = GoToClass(api);
api.StartLearning();
if (api.GetClassroomProgress(classroom.x, classroom.y) == Constants::maxClassroomProgress)
{
for (int i = 0; i < classrooms.size(); ++i)
{
if (classrooms[i].x == classroom.x && classrooms[i].y == classroom.y)
{
hasLearned[i] = true;
for (int j = 0; j < 4; ++j)
{
api.SendMessage(j, fmt::format("{}", i));
}
break;
}
}
}

if (api.HaveMessage())
{
auto msg = api.GetMessage();
int classroomID = msg.second[0] - '0';
hasLearned[classroomID] = true;
}

api.UseSkill(0);
api.UseSkill(1);
api.UseSkill(2);
}



/*鬼相关函数*/

// 视野内有人
int isStudentinView(ITrickerAPI& api) {
auto info = api.GetStudents();
return (info.size() != 0);
}

void avoidObstacles(ITrickerAPI& api, double dirc) {
const int selfRadius = 450;
const int moveStep = 10; // 待定
auto selfInfo = api.GetSelfInfo();
auto selfX = selfInfo->x;
auto selfY = selfInfo->y;

// 定义左右点
int leftPointX = selfX - (int)(selfRadius * sin(dirc));
int leftPointY = selfY + (int)(selfRadius * cos(dirc));
int rightPointX = selfX + (int)(selfRadius * sin(dirc));
int rightPointY = selfY - (int)(selfRadius * cos(dirc));

auto gridX = api.GridToCell(leftPointX + (int)(1000 * cos(dirc)));
auto gridY = api.GridToCell(leftPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc - M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
return;
}
gridX = api.GridToCell(rightPointX + (int)(1000 * cos(dirc)));
gridY = api.GridToCell(rightPointY + (int)(1000 * sin(dirc)));
if (api.GetPlaceType(gridX, gridY) == THUAI6::PlaceType::Wall) {
api.Move(moveStep, dirc + M_PI / 2);
avoidObstacles(api, dirc + M_PI / 10);
}
return;
}

void AI::play(ITrickerAPI& api)
{
api.UseSkill(0);

auto selfInfo = api.GetSelfInfo();
auto myPos = Point(selfInfo->x, selfInfo->y);
api.PrintSelfInfo();
if (isStudentinView(api)) {

// 追击
auto studentInfo = api.GetStudents();
auto selfInfo = api.GetSelfInfo();
auto dx = studentInfo[0]->x - selfInfo->x;
auto dy = studentInfo[0]->y - selfInfo->y;
auto dirc = atan2(dy, dx);

avoidObstacles(api, dirc);
api.Move(moveStep, dirc);
double distance = sqrt(dx * dx + dy + dy);
if (distance < Constants::basicAttackShortRange * 13 && api.UseSkill(1).get() == true) { // 飞刀
api.Attack(dirc);
}
if (distance < Constants::basicAttackShortRange) {
api.Attack(dirc);
}
}
}

+ 1830
- 0
players/孤客若风/player1.cpp
File diff suppressed because it is too large
View File


+ 1830
- 0
players/孤客若风/player2.cpp
File diff suppressed because it is too large
View File


+ 1830
- 0
players/孤客若风/player3.cpp
File diff suppressed because it is too large
View File


+ 1830
- 0
players/孤客若风/player4.cpp
File diff suppressed because it is too large
View File


+ 1782
- 0
players/孤客若风/player5.cpp
File diff suppressed because it is too large
View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save