圈地为王示例

// 圈地为王游戏样例程序
// 最后更新 2013-06-25 21:56
// 作者:zhouhy

#include <iostream>
#include <string>
#include <ctime>
#include <set>
#include <vector>
#include <algorithm>
#define INITIAL_OWNER -1 // 无主
#define TEMPORARY_FLAG -2 // 临时标志
#define max(a, b) ((b < a) ? (a) : (b))
#define min(a, b) ((a < b) ? (a) : (b))
#define PLAYER_COUNT  4
#define FIELD_WIDTH 10
#define FIELD_HEIGHT 10

using namespace std;

struct Point
{
	int x, y;
	Point(int _x, int _y) : x(_x), y(_y) { }

	Point()
	{
		x = y = 0;
	}

	bool operator<(const Point& b) const
	{
		if (y == b.y)
			return x < b.x;
		return y < b.y;
	}

	bool operator==(const Point& b) const
	{
		return x == b.x && y == b.y;
	}

	bool operator!=(const Point& b) const
	{
		return !operator==(b);
	}

	void operator+=(const Point& b)
	{
		x += b.x;
		y += b.y;
	}
};

int playerLeft, myID, turnCount, vborders[FIELD_WIDTH + 1][FIELD_HEIGHT], hborders[FIELD_WIDTH][FIELD_HEIGHT + 1], //记录轨迹用
	vborderOwner[FIELD_WIDTH + 1][FIELD_HEIGHT], hborderOwner[FIELD_WIDTH][FIELD_HEIGHT + 1], // 记录可否行走用
	grids[FIELD_WIDTH][FIELD_HEIGHT], areaSquareSum[PLAYER_COUNT], areaSum[PLAYER_COUNT], // 记录格子占领情况
	dx[5] = {0, 0, -1, 1, 0}, dy[5] = {-1, 1, 0, 0, 0}, playerState[PLAYER_COUNT], // 0为抬笔,1为落笔,-1为死亡
	stuckStatusLeft[PLAYER_COUNT], // 玩家被束缚剩余回合数
	scoreDecline[PLAYER_COUNT]; // 玩家因施放技能损失的分数
char actions[5] = {'u', 'd', 'l', 'r', 's'},
	lastDir[PLAYER_COUNT]; // 上次走的方向,仅用于落笔后状态
Point prevPos[PLAYER_COUNT], currPos[PLAYER_COUNT];
vector<Point> trail[PLAYER_COUNT];
set<Point> traps;

struct EnclosingArgu
{
	int enclosedArea,  // 被圈住的内部面积,包括不可占据区域
		charID;
	set<Point> actuallyOccupiedArea; // 实际属于该角色的网格坐标
	bool willBeDead[PLAYER_COUNT];
	bool operator<(const EnclosingArgu& b) const
	{
		return enclosedArea < b.enclosedArea;
	}
};

inline void DrawLine(int charID, Point& prevPos, Point& currPos)
{
	if (currPos == prevPos)
		return;
	if (currPos.x == prevPos.x)
		vborders[currPos.x][min(prevPos.y, currPos.y)] = charID;
	else if (currPos.y == prevPos.y)
		hborders[min(prevPos.x, currPos.x)][currPos.y] = charID;
}

inline bool MoveStep(int &x, int &y, int dir, int charID) // 移动并检查是否撞到charID边界
{
	if (dir == 0)
	{
		if (hborders[x][y] == charID)
			return false;
	}
	else if (dir == 1)
	{
		if (hborders[x][y + 1] == charID)
			return false;
	}
	else if (dir == 2)
	{
		if (vborders[x][y] == charID)
			return false;
	}
	else if (dir == 3)
	{
		if (vborders[x + 1][y] == charID)
			return false;
	}
	x += dx[dir];
	y += dy[dir];
	if (x < 0 || x >= FIELD_WIDTH || y < 0 || y >= FIELD_HEIGHT)
		return false;
	return true;
}

inline bool MoveStep(int &x, int &y, int dir) // 移动
{
	x += dx[dir];
	y += dy[dir];
	if (x < 0 || x >= FIELD_WIDTH || y < 0 || y >= FIELD_HEIGHT)
		return false;
	return true;
}

int TryExpand(int charID, int tempBoard[FIELD_WIDTH][FIELD_HEIGHT], int gridX, int gridY,
			  set<Point>& actuallyOccupiedArea, bool willBeDead[PLAYER_COUNT]) // 试图用漫水法找出charID所围全部区域
{
	if (tempBoard[gridX][gridY] == TEMPORARY_FLAG) // tempBoard复制grids,但增加了TEMPORARY_FLAG这种状态,表示已经走过
		return 0;
	int x, y, area = 0, initialOwner = tempBoard[gridX][gridY]; // area为所围区域全部面积
	tempBoard[gridX][gridY] = TEMPORARY_FLAG;
	for (int dir = 0; dir < 4; dir++)
	{
		x = gridX;
		y = gridY;
		if (MoveStep(x, y, dir, charID))
			area += TryExpand(charID, tempBoard, x, y, actuallyOccupiedArea, willBeDead);
	}
	if (gridX > 0 && gridX < FIELD_WIDTH && gridY > 0 && gridY < FIELD_HEIGHT &&
		hborders[gridX - 1][gridY] != charID && hborders[gridX][gridY] != charID &&
		vborders[gridX][gridY - 1] != charID && vborders[gridX][gridY] != charID)
	{
		for (int i = 0; i < PLAYER_COUNT; i++)
			if (prevPos[i].x == gridX && prevPos[i].y == gridY)
				willBeDead[i] = true;
	}
	if (initialOwner == INITIAL_OWNER)
		actuallyOccupiedArea.insert(Point(gridX, gridY));
	return area + 1;
}

int TryExpand(int tempBoard[FIELD_WIDTH][FIELD_HEIGHT], int gridX, int gridY, set<Point>& allArea) // 试图用漫水法从gridX/Y开始找出内容为TEMPFLAG的连续格子面积
{
	if (tempBoard[gridX][gridY] != TEMPORARY_FLAG)
		return 0;
	int x, y, area = 0; // area为所围区域全部面积
	tempBoard[gridX][gridY] = INITIAL_OWNER;
	allArea.insert(Point(gridX, gridY));
	for (int dir = 0; dir < 4; dir++)
	{
		x = gridX;
		y = gridY;
		if (MoveStep(x, y, dir))
			area += TryExpand(tempBoard, x, y, allArea);
	}
	return area + 1;
}


// 产生圈地的参数,因为根据规则,在正式圈地之前还要从小到大排序
EnclosingArgu CalcEnclose(int charID, vector<Point>::iterator p, vector<Point>::iterator e) // p~e是真正在边界上的点
{
	EnclosingArgu tempArgu;
	for (int i = 0; i < PLAYER_COUNT; i++)
		tempArgu.willBeDead[i] = false;

	// 从最高的横线向下漫水搜索
	sort(p, e);
	vector<Point>::iterator lp = p;
	for (++p; p != e; ++p, ++lp)
		if (p->x - lp->x == 1)
			break;

	int tempGrids[FIELD_WIDTH][FIELD_HEIGHT];
	for (int x = 0; x < FIELD_WIDTH; x++)
		for (int y = 0; y < FIELD_HEIGHT; y++)
			tempGrids[x][y] = grids[x][y];

	tempArgu.enclosedArea = TryExpand(charID, tempGrids, lp->x, lp->y, tempArgu.actuallyOccupiedArea, tempArgu.willBeDead);
	tempArgu.charID = charID;
	return tempArgu;
}

// 按照圈地参数进行正式圈地
void DoEnclose(const EnclosingArgu& argu)
{
	int currArea;
	int tempGrids[FIELD_WIDTH][FIELD_HEIGHT]; // 用于找出连续区域
	for (int x = 0; x < FIELD_WIDTH; x++)
		for (int y = 0; y < FIELD_HEIGHT; y++)
			tempGrids[x][y] = INITIAL_OWNER;

	for (int i = 0; i < PLAYER_COUNT; i++)
		if (argu.willBeDead[i])
			playerState[i] = -1;

	set<Point>::const_iterator i, e;
	for (i = argu.actuallyOccupiedArea.begin(), e = argu.actuallyOccupiedArea.end(); i != e; i++)
	{
		grids[i->x][i->y] = argu.charID;
		tempGrids[i->x][i->y] = TEMPORARY_FLAG;
	}

	// 标记所有内部边
	Point x1, x2;
	for (x1.x = 0; x1.x < FIELD_WIDTH; x1.x++)
		for (x1.y = 0; x1.y < FIELD_HEIGHT; x1.y++)
		{
			if (x1.x < FIELD_WIDTH - 1)
			{
				x2.x = x1.x + 1;
				x2.y = x1.y;
				if (tempGrids[x1.x][x1.y] == TEMPORARY_FLAG && tempGrids[x2.x][x2.y] == TEMPORARY_FLAG &&
					argu.actuallyOccupiedArea.count(x1) && argu.actuallyOccupiedArea.count(x2))
					vborderOwner[x2.x][x2.y] = argu.charID;
			}
			if (x1.y < FIELD_HEIGHT - 1)
			{
				x2.x = x1.x;
				x2.y = x1.y + 1;
				if (tempGrids[x1.x][x1.y] == TEMPORARY_FLAG && tempGrids[x2.x][x2.y] == TEMPORARY_FLAG &&
					argu.actuallyOccupiedArea.count(x1) && argu.actuallyOccupiedArea.count(x2))
					hborderOwner[x2.x][x2.y] = argu.charID;
			}
		};

		areaSum[argu.charID] += argu.actuallyOccupiedArea.size();
		set<Point> allArea;

		// 找出所有连续的区域
		for (i = argu.actuallyOccupiedArea.begin(); i != e; i++)
			if (tempGrids[i->x][i->y] == TEMPORARY_FLAG)
			{
				allArea.clear();
				currArea = TryExpand(tempGrids, i->x, i->y, allArea);
				areaSquareSum[argu.charID] += currArea * currArea;
			};

			// 清除轨迹
			int x, y;
			for (x = 0; x <= FIELD_WIDTH; x++)
				for (y = 0; y <= FIELD_HEIGHT; y++)
				{
					if (x < FIELD_WIDTH && hborders[x][y] == argu.charID)
						hborders[x][y] = INITIAL_OWNER;
					if (y < FIELD_HEIGHT && vborders[x][y] == argu.charID)
						vborders[x][y] = INITIAL_OWNER;
				};
				trail[argu.charID].clear();
}

bool CheckRoute(int charID, int state, Point& prevPos, Point& currPos) // 检查路线是否可以行走
{
	if (currPos == prevPos)
		return true;
	if (currPos.y == prevPos.y)
		if (currPos.y == 0 || currPos.y == FIELD_HEIGHT)
			return true;
		else
		{
			int gridX = currPos.x;
			if (prevPos.x < gridX)
				gridX = prevPos.x;
			if ((state == 1 && hborderOwner[gridX][currPos.y] != INITIAL_OWNER) ||
				(state == 0 && hborderOwner[gridX][currPos.y] != INITIAL_OWNER && hborderOwner[gridX][currPos.y] != charID))
				return false;
			return true;
		}
	else
		if (currPos.x == 0 || currPos.x == FIELD_WIDTH)
			return true;
		else
		{
			int gridY = currPos.y;
			if (prevPos.y < gridY)
				gridY = prevPos.y;
			if ((state == 1 && vborderOwner[currPos.x][gridY] != INITIAL_OWNER) ||
				(state == 0 && vborderOwner[currPos.x][gridY] != INITIAL_OWNER && vborderOwner[currPos.x][gridY] != charID))
				return false;
			return true;
		}
}

inline bool CheckPosValidity(Point& pos)
{
	if (pos.x >= 0 && pos.x <= FIELD_WIDTH &&
		pos.y >= 0 && pos.y <= FIELD_HEIGHT)
		return true;
	return false;
}

inline bool IsReverse(int dir1, int dir2) // 判断方向是否相反
{
	if (dir1 == 0 && dir2 == 1)
		return true;
	if (dir1 == 1 && dir2 == 0)
		return true;
	if (dir1 == 2 && dir2 == 3)
		return true;
	if (dir1 == 3 && dir2 == 2)
		return true;
	return false;
}

inline int GetDistance(int ida, int idb) // 获得两名角色之间的坐标差
{
	int deltax = currPos[ida].x - currPos[idb].x, deltay = currPos[ida].y - currPos[idb].y;
	if (deltax < 0)
		deltax *= -1;
	if (deltay < 0)
		deltay *= -1;
	return deltax + deltay;
}

int main()
{
	int i, changePenState, nTraps, turnLeft;
	string cmd;
	Point temp;
	multiset<EnclosingArgu> allEnclosure;
	time_t startTick;

	for (int x = 0; x <= FIELD_WIDTH; x++)
		for (int y = 0; y <= FIELD_HEIGHT; y++)
		{
			if (x != FIELD_WIDTH)
			{
				hborderOwner[x][y] = INITIAL_OWNER;
				hborders[x][y] = INITIAL_OWNER;
			}
			if (y != FIELD_HEIGHT)
			{
				vborderOwner[x][y] = INITIAL_OWNER;
				vborders[x][y] = INITIAL_OWNER;
			}
			if (x != FIELD_WIDTH && y != FIELD_HEIGHT)
				grids[x][y] = INITIAL_OWNER;
		};
		for (i = 0; i < PLAYER_COUNT; i++)
		{
			areaSquareSum[i] = areaSum[i] = 0;
			lastDir[i] = -1;
		}
		turnCount = 0;

		while (cin >> cmd)
		{
			if (cmd == "[START]")
			{
				startTick = clock();
				while (clock() - startTick < 100); // 等待0.1秒……
				srand(clock());
				cin >> myID;
				cout << "[POS] " << rand() % (FIELD_WIDTH + 1) << ' ' << rand() % (FIELD_HEIGHT + 1) << endl;
			}
			if (cmd == "[STATUS]")
			{
				startTick = clock();
				while (clock() - startTick < 100); // 等待0.1秒……
				srand(clock());
				for (i = 0; i < PLAYER_COUNT; i++)
					cin >> currPos[i].x >> currPos[i].y >> playerState[i] >> stuckStatusLeft[i] >> scoreDecline[i];
				cin >> nTraps;
				traps.clear();
				for (i = 0; i < nTraps; i++)
				{
					cin >> temp.x >> temp.y >> turnLeft;
					traps.insert(temp);
				}

				if (++turnCount == 1) // 第一回合
					for (i = 0; i < PLAYER_COUNT; i++)
						prevPos[i] = currPos[i];
				else
				{
					for (i = 0; i < PLAYER_COUNT; i++)
					{
						vector<Point>::iterator it;
						if (playerState[i] != 1 && !trail[i].empty() && (it = find(trail[i].begin(), trail[i].end(), currPos[i])) != --trail[i].end() && it != trail[i].end())
						{
							lastDir[i] = -1;
							DrawLine(i, prevPos[i], currPos[i]);
							allEnclosure.insert(CalcEnclose(i, it, trail[i].end()));
						}
						else if (playerState[i] == 1)
						{
							if (trail[i].empty())
								trail[i].push_back(prevPos[i]);
							if (trail[i][trail[i].size() - 1] != currPos[i])
							{
								trail[i].push_back(currPos[i]);
								DrawLine(i, prevPos[i], currPos[i]);
							}
						}
					}
					for_each(allEnclosure.begin(), allEnclosure.end(), DoEnclose);
					allEnclosure.clear();
				}
				if (stuckStatusLeft[myID] > 0)
				{
					cout << "[ACTION] s 0" << endl;
					for (i = 0; i < PLAYER_COUNT; i++)
						prevPos[i] = currPos[i];
					continue;
				}

				if (playerState[myID] == 0)
				{
					for (i = 0; i < PLAYER_COUNT; i++)
						if (i != myID && playerState[i] != -1 && GetDistance(i, myID) < 4) // 如果落笔后4回合内可能被打断
							break;
					if (i != PLAYER_COUNT)
					{
						if (rand() % 2)
							changePenState = -1;
						else
							changePenState = 0;
					}
					else if (rand() % 2)
					{
						playerState[myID] = 1;
						changePenState = 1;
					}
					else
						changePenState = 0;
				}
				else
					changePenState = 0;

				if (playerState[myID] == 1) // 落笔态
				{
					while (true)
					{
						i = rand() % 5;
						temp.x = currPos[myID].x + dx[i];
						temp.y = currPos[myID].y + dy[i];
						if (!IsReverse(i, lastDir[myID]) && CheckPosValidity(temp) && CheckRoute(myID, 1, currPos[myID], temp))
							break;
					}
					if (i != 4)
						lastDir[myID] = i;
				}
				else // 抬笔态
					while (true)
					{
						i = rand() % (changePenState == -1 ? 4 : 5);
						temp.x = currPos[myID].x + dx[i];
						temp.y = currPos[myID].y + dy[i];
						if (CheckPosValidity(temp) && CheckRoute(myID, 0, currPos[myID], temp))
							break;
					};

					cout << "[ACTION] " << actions[i] << ' ' << changePenState << endl;
					for (i = 0; i < PLAYER_COUNT; i++)
						prevPos[i] = currPos[i];
			}
		}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值