查看“Tetris”的源代码
←
Tetris
跳转至:
导航
,
搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看与复制此页面的源代码。
俄罗斯方块(Tetris)是[[Botzone]]平台上的双人回合制[[游戏]]。 == 作者 == 裁判程序 ''zys'' 播放器 ''zhouhy'' == 游戏规则 == 本游戏为'''双人回合制'''游戏,每个玩家在独立的矩阵场地上进行游戏。 每回合,双方玩家同时决策,既需要控制自己的方块落地,又需要为对手指定下一回合的方块。 玩家消去行后,方块会转移到对方场地底部,从而给对方增加难度。 === 地图 === 每个玩家的场地是高20格、宽10格的矩阵。在程序中,坐标是(x, y)的形式,其中x是横坐标,y是纵坐标。最左下方的格子的坐标是(1, 1)。 === 方块 === 游戏中,方块共有七种类型,每种类型的方块有四种姿态(即方向)。 方块只能逆时针旋转(即上左下右的顺序进行旋转)。旋转时旋转中心不动。 [[File:Tetris.Blocks.png]] 上图的方块在程序中,从左到右的类型编号分别是数字0~6,上左下右四种方向分别对应着数字0~3。 方块的坐标即其旋转中心的坐标。 === 给对手指定方块 === 第一回合,双方的方块类型由<del>玄学</del>系统指定,而且是相同的类型。 除了第一回合之外,每个回合的方块类型都是由对方指定的。因此,每回合玩家都要给出对方下一个方块的类型。 指定方块时,必须保证对方的各类方块的数目的极差(即最大值减最小值)不超过2,否则将会被视为非法行为。 === 描述自己的方块落地序列 === 每回合,玩家可以得知自己本回合控制的方块类型。 为了保证方块能够穿过重重障碍来到地面,我们要求玩家给出方块在落地的必经之路中,在各个纵坐标下的姿态,即方块落地序列。 记元组(横坐标,纵坐标,姿态)构成了一个序列[[File:Tetris.B.png]],该序列有如下要求: * 每个元组指定的方块状态必须是合法的(即方块可以放置在指定位置) * [[File:Tetris.C.png]]必须是不合法的(即方块最后停在了不能继续下落的位置) * 必须保证方块能从[[File:Tetris.D.png]]“畅通无阻”地落到[[File:Tetris.E.png]] * 对于相邻的一对元组[[File:Tetris.F.png]]: ** 必须保证[[File:Tetris.G.png]]; ** 如果[[File:Tetris.H.png]],那么必须保证[[File:Tetris.I.png]]和[[File:Tetris.J.png]]。否则无要求。 === 方块的消除与转移 === 每回合方块落地后,如果有行已满,那么这些行将会被“消除”,其它的行下落补上空行。 被消除的行并不会消失,而是会去除最后一个落地的方块(即本回合刚刚造成这几行消除的方块),然后按照同样的顺序堆叠起来,放置在对方的场地底部。对方场地原有的方块就会被“顶起来”。 === 积分 === 玩家具有积分,但是仅用于平局时的处理。 对于每一回合,玩家一次性消去1、2、3、4行的积分分别是1、3、5、7。 总积分是上述积分的和。 === 胜负 === 一切非法行为会被立即判负,包括程序崩溃、超时、坐标越界、格式错误等。 在发生方块转移后,如果场地的最高方块高度超过边界,则会被判负。 如果双方同时超过边界,那么积分高者胜。 如果双方积分相同,那么游戏平局。 ==游戏交互方式== '''与[[Botzone]]上其他游戏一样,本游戏每步(每次程序运行)限时1秒。''' ===提示=== '''如果你不能理解以下交互方式,可以直接看[[#样例程序]],按照说明填写代码,并修改其中''' // 做出决策(你只需修改以下部分) '''到''' // 决策结束,输出结果(你只需修改以上部分) '''之间的部分即可!''' 本游戏与Botzone上其他游戏一样,使用相同的交互方式:[[Bot#交互]] ===简单交互=== ;request : 第一回合的request是一行两个数字t和c,空格分隔,t表示自己拿到的方块类型,n表示自己的颜色(0红1蓝) : 以后的request是一行四个数字t、x、y、o,空格分隔,t表示自己拿到的方块类型,x和y表示对方方块落在的位置坐标,o表示对方方块的姿态 ;response : 每个回合的response都是一行若干数字,用空格分隔。第一个数字是t,表示给对方下一回合的方块,第二个数字是n,表示方块落地序列的长度,此后有3n个数字表示序列中的元组,每相邻的三个分别是x、y、o。 定义了request和response后,玩家的输入总体格式可以参看[[Bot#简化交互]]。 对于[https://www.botzone.org/match/58f5a8b6cefd1948b754b0cb 样例对局],第四回合蓝色玩家的样例输入和样例输出如下: '''输入''' <pre class="mw-collapsible mw-collapsed"> 4 1 1 4 1 2 1 2 6 2 1 2 4 1 4 1 3 4 5 1 0 0 1 7 1 0 4 8 1 0 </pre> '''输出''' <pre class="mw-collapsible mw-collapsed"> 0 1 9 2 0 </pre> ===[[JSON]]交互=== 每回合[[Bot]]收到的request'''不是字符串''',而是一个[[JSON]]对象,格式如下: '''第一回合''' <syntaxhighlight lang="javascript"> { "block": Number, // 表示玩家本回合块类型 "color": Number // 表示玩家颜色 } </syntaxhighlight> '''其他回合''' <syntaxhighlight lang="javascript"> { "x": Number, // x和y表示对方方块落在的位置坐标,o表示对方方块的姿态 "y": Number, "o": Number, "block": Number // 表示给对手的下回合块类型 } </syntaxhighlight> Bot所需要输出的response也是[[JSON]]对象,格式如下: <syntaxhighlight lang="javascript"> { "seq": [ // 方块落地序列 { "x": Number, "y": Number, "o": Number } ], "block": Number // 表示给对手的下回合块类型 } </syntaxhighlight> 对于[https://www.botzone.org/match/58f5a8b6cefd1948b754b0cb 样例对局],第四回合蓝色玩家的样例输入和样例输出如下:(实际是单行紧缩的) '''输入''' <pre class="mw-collapsible mw-collapsed"> { "requests": [ { "block": 1, "color": 1 }, { "block": 6, "o": 2, "x": 2, "y": 1 }, { "block": 4, "o": 0, "x": 5, "y": 1 }, { "block": 4, "o": 0, "x": 8, "y": 1 } ], "responses": [ { "seq": [ { "x": 2, "y": 1, "o": 2 } ], "block": 4 },{ "seq": [ { "x": 4, "y": 1, "o": 3 } ], "block": 4 },{ "seq": [ { "x": 7, "y": 1, "o": 0 } ], "block": 0 } ] } </pre> '''输出''' <pre class="mw-collapsible mw-collapsed"> { "response": { "seq": [ { "x": 9, "y": 2, "o": 0 } ], "block": 0 } } </pre> == 样例程序 == === 简单交互样例程序 === <syntaxhighlight lang="cpp" class="mw-collapsible mw-collapsed"> /** * Tetris 简单交互样例程序 * https://wiki.botzone.org/index.php?title=Tetris */ // 注意:x的范围是1~MAPWIDTH,y的范围是1~MAPHEIGHT // 数组是先行(y)后列(c) // 坐标系:原点在左下角 #include <iostream> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <ctime> using namespace std; #define MAPWIDTH 10 #define MAPHEIGHT 20 // 我所在队伍的颜色(0为红,1为蓝,仅表示队伍,不分先后) int currBotColor; int enemyColor; // 先y后x,记录地图状态,0为空,1为以前放置,2为刚刚放置,负数为越界 // (2用于在清行后将最后一步撤销再送给对方) int gridInfo[2][MAPHEIGHT + 2][MAPWIDTH + 2] = { 0 }; // 代表分别向对方转移的行 int trans[2][4][MAPWIDTH + 2] = { 0 }; // 转移行数 int transCount[2] = { 0 }; // 运行eliminate后的当前高度 int maxHeight[2] = { 0 }; // 总消去行数的分数之和 int elimTotal[2] = { 0 }; // 一次性消去行数对应分数 const int elimBonus[4] = { 1, 3, 5, 7 }; // 给对应玩家的各类块的数目总计 int typeCountForColor[2][7] = { 0 }; const int blockShape[7][4][8] = { { { 0,0,1,0,-1,0,-1,-1 },{ 0,0,0,1,0,-1,1,-1 },{ 0,0,-1,0,1,0,1,1 },{ 0,0,0,-1,0,1,-1,1 } }, { { 0,0,-1,0,1,0,1,-1 },{ 0,0,0,-1,0,1,1,1 },{ 0,0,1,0,-1,0,-1,1 },{ 0,0,0,1,0,-1,-1,-1 } }, { { 0,0,1,0,0,-1,-1,-1 },{ 0,0,0,1,1,0,1,-1 },{ 0,0,-1,0,0,1,1,1 },{ 0,0,0,-1,-1,0,-1,1 } }, { { 0,0,-1,0,0,-1,1,-1 },{ 0,0,0,-1,1,0,1,1 },{ 0,0,1,0,0,1,-1,1 },{ 0,0,0,1,-1,0,-1,-1 } }, { { 0,0,-1,0,0,1,1,0 },{ 0,0,0,-1,-1,0,0,1 },{ 0,0,1,0,0,-1,-1,0 },{ 0,0,0,1,1,0,0,-1 } }, { { 0,0,0,-1,0,1,0,2 },{ 0,0,1,0,-1,0,-2,0 },{ 0,0,0,1,0,-1,0,-2 },{ 0,0,-1,0,1,0,2,0 } }, { { 0,0,0,1,-1,0,-1,1 },{ 0,0,-1,0,0,-1,-1,-1 },{ 0,0,0,-1,1,-0,1,-1 },{ 0,0,1,0,0,1,1,1 } } };// 7种形状(长L| 短L| 反z| 正z| T| 直一| 田格),4种朝向(上左下右),8:每相邻的两个分别为x,y class Tetris { public: const int blockType; // 标记方块类型的序号 0~6 int blockX; // 旋转中心的x轴坐标 int blockY; // 旋转中心的y轴坐标 int orientation; // 标记方块的朝向 0~3 const int(*shape)[8]; // 当前类型方块的形状定义 int color; Tetris(int t, int color) : blockType(t), shape(blockShape[t]), color(color) { } inline Tetris &set(int x = -1, int y = -1, int o = -1) { blockX = x == -1 ? blockX : x; blockY = y == -1 ? blockY : y; orientation = o == -1 ? orientation : o; return *this; } // 判断当前位置是否合法 inline bool isValid(int x = -1, int y = -1, int o = -1) { x = x == -1 ? blockX : x; y = y == -1 ? blockY : y; o = o == -1 ? orientation : o; if (o < 0 || o > 3) return false; int i, tmpX, tmpY; for (i = 0; i < 4; i++) { tmpX = x + shape[o][2 * i]; tmpY = y + shape[o][2 * i + 1]; if (tmpX < 1 || tmpX > MAPWIDTH || tmpY < 1 || tmpY > MAPHEIGHT || gridInfo[color][tmpY][tmpX] != 0) return false; } return true; } // 判断是否落地 inline bool onGround() { if (isValid() && !isValid(-1, blockY - 1)) return true; return false; } // 将方块放置在场地上 inline bool place() { if (!onGround()) return false; int i, tmpX, tmpY; for (i = 0; i < 4; i++) { tmpX = blockX + shape[orientation][2 * i]; tmpY = blockY + shape[orientation][2 * i + 1]; gridInfo[color][tmpY][tmpX] = 2; } return true; } // 检查能否逆时针旋转自己到o inline bool rotation(int o) { if (o < 0 || o > 3) return false; if (orientation == o) return true; int fromO = orientation; while (true) { if (!isValid()) return false; if (fromO == o) break; fromO = (fromO + 1) % 4; } return true; } }; // 围一圈护城河 void init() { int i; for (i = 0; i < MAPHEIGHT + 2; i++) { gridInfo[1][i][0] = gridInfo[1][i][MAPWIDTH + 1] = -2; gridInfo[0][i][0] = gridInfo[0][i][MAPWIDTH + 1] = -2; } for (i = 0; i < MAPWIDTH + 2; i++) { gridInfo[1][0][i] = gridInfo[1][MAPHEIGHT + 1][i] = -2; gridInfo[0][0][i] = gridInfo[0][MAPHEIGHT + 1][i] = -2; } } namespace Util { // 检查能否从场地顶端直接落到当前位置 inline bool checkDirectDropTo(int color, int blockType, int x, int y, int o) { auto &def = blockShape[blockType][o]; for (; y <= MAPHEIGHT; y++) for (int i = 0; i < 4; i++) { int _x = def[i * 2] + x, _y = def[i * 2 + 1] + y; if (_y > MAPHEIGHT) continue; if (_y < 1 || _x < 1 || _x > MAPWIDTH || gridInfo[color][_y][_x]) return false; } return true; } // 消去行 void eliminate(int color) { int &count = transCount[color] = 0; int i, j, emptyFlag, fullFlag; maxHeight[color] = MAPHEIGHT; for (i = 1; i <= MAPHEIGHT; i++) { emptyFlag = 1; fullFlag = 1; for (j = 1; j <= MAPWIDTH; j++) { if (gridInfo[color][i][j] == 0) fullFlag = 0; else emptyFlag = 0; } if (fullFlag) { for (j = 1; j <= MAPWIDTH; j++) { // 注意这里只转移以前的块,不包括最后一次落下的块(“撤销最后一步”) trans[color][count][j] = gridInfo[color][i][j] == 1 ? 1 : 0; gridInfo[color][i][j] = 0; } count++; } else if (emptyFlag) { maxHeight[color] = i - 1; break; } else for (j = 1; j <= MAPWIDTH; j++) { gridInfo[color][i - count][j] = gridInfo[color][i][j] > 0 ? 1 : gridInfo[color][i][j]; if (count) gridInfo[color][i][j] = 0; } } maxHeight[color] -= count; elimTotal[color] += elimBonus[count]; } // 转移双方消去的行,返回-1表示继续,否则返回输者 int transfer() { int color1 = 0, color2 = 1; if (transCount[color1] == 0 && transCount[color2] == 0) return -1; if (transCount[color1] == 0 || transCount[color2] == 0) { if (transCount[color1] == 0 && transCount[color2] > 0) swap(color1, color2); int h2; maxHeight[color2] = h2 = maxHeight[color2] + transCount[color1]; if (h2 >= MAPHEIGHT) return color2; int i, j; for (i = h2; i > transCount[color1]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = gridInfo[color2][i - transCount[color1]][j]; for (i = transCount[color1]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = trans[color1][i - 1][j]; return -1; } else { int h1, h2; maxHeight[color1] = h1 = maxHeight[color1] + transCount[color2];//从color1处移动count1去color2 maxHeight[color2] = h2 = maxHeight[color2] + transCount[color1]; if (h1 > MAPHEIGHT) return color1; if (h2 > MAPHEIGHT) return color2; int i, j; for (i = h2; i > transCount[color1]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = gridInfo[color2][i - transCount[color1]][j]; for (i = transCount[color1]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = trans[color1][i - 1][j]; for (i = h1; i > transCount[color2]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color1][i][j] = gridInfo[color1][i - transCount[color2]][j]; for (i = transCount[color2]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color1][i][j] = trans[color2][i - 1][j]; return -1; } } // 颜色方还能否继续游戏 inline bool canPut(int color, int blockType) { Tetris t(blockType, color); for (int y = MAPHEIGHT; y >= 1; y--) for (int x = 1; x <= MAPWIDTH; x++) for (int o = 0; o < 4; o++) { t.set(x, y, o); if (t.isValid() && checkDirectDropTo(color, blockType, x, y, o)) return true; } return false; } // 打印场地用于调试 inline void printField() { #ifndef _BOTZONE_ONLINE static const char *i2s[] = { "~~", "~~", " ", "[]", "##" }; cout << "~~:墙,[]:块,##:新块" << endl; for (int y = MAPHEIGHT + 1; y >= 0; y--) { for (int x = 0; x <= MAPWIDTH + 1; x++) cout << i2s[gridInfo[0][y][x] + 2]; for (int x = 0; x <= MAPWIDTH + 1; x++) cout << i2s[gridInfo[1][y][x] + 2]; cout << endl; } #endif } } int main() { // 加速输入 istream::sync_with_stdio(false); srand(time(NULL)); init(); int turnID, blockType; int nextTypeForColor[2]; cin >> turnID; // 先读入第一回合,得到自己的颜色 // 双方的第一块肯定是一样的 cin >> blockType >> currBotColor; enemyColor = 1 - currBotColor; nextTypeForColor[0] = blockType; nextTypeForColor[1] = blockType; typeCountForColor[0][blockType]++; typeCountForColor[1][blockType]++; // 然后分析以前每回合的输入输出,并恢复状态 // 循环中,color 表示当前这一行是 color 的行为 // 平台保证所有输入都是合法输入 for (int i = 1; i < turnID; i++) { int currTypeForColor[2] = { nextTypeForColor[0], nextTypeForColor[1] }; int n, x, y, o; // 根据这些输入输出逐渐恢复状态到当前回合 // 先读自己的输出,也就是自己的行为 // 自己的输出是一个序列,但是只有最后一步有用 // 所以只保留最后一步 // 然后模拟最后一步放置块 cin >> blockType >> n; for (int j = 0; j < n; j++) cin >> x >> y >> o; // 我当时把上一块落到了 x y o! Tetris myBlock(currTypeForColor[currBotColor], currBotColor); myBlock.set(x, y, o).place(); // 我给对方什么块来着? typeCountForColor[enemyColor][blockType]++; nextTypeForColor[enemyColor] = blockType; // 然后读自己的输入,也就是对方的行为 // 裁判给自己的输入只有对方的最后一步 cin >> blockType >> x >> y >> o; // 对方当时把上一块落到了 x y o! Tetris enemyBlock(currTypeForColor[enemyColor], enemyColor); enemyBlock.set(x, y, o).place(); // 对方给我什么块来着? typeCountForColor[currBotColor][blockType]++; nextTypeForColor[currBotColor] = blockType; // 检查消去 Util::eliminate(0); Util::eliminate(1); // 进行转移 Util::transfer(); } int blockForEnemy, seqX[MAPHEIGHT + 1], seqY[MAPHEIGHT + 1], seqO[MAPHEIGHT + 1], seqLength = 0; // 做出决策(你只需修改以下部分) // 遇事不决先输出(平台上编译不会输出) Util::printField(); // 贪心决策 // 从下往上以各种姿态找到第一个位置,要求能够直着落下 Tetris block(nextTypeForColor[currBotColor], currBotColor); for (int y = 1; y <= MAPHEIGHT; y++) for (int x = 1; x <= MAPWIDTH; x++) for (int o = 0; o < 4; o++) { if (block.set(x, y, o).isValid() && Util::checkDirectDropTo(currBotColor, block.blockType, x, y, o)) { seqX[0] = x; seqY[0] = y; seqO[0] = o; seqLength = 1; goto determined; } } determined: // 再看看给对方什么好 int maxCount = 0, minCount = 99; for (int i = 0; i < 7; i++) { if (typeCountForColor[enemyColor][i] > maxCount) maxCount = typeCountForColor[enemyColor][i]; if (typeCountForColor[enemyColor][i] < minCount) minCount = typeCountForColor[enemyColor][i]; } if (maxCount - minCount == 2) { // 危险,找一个不是最大的块给对方吧 for (blockForEnemy = 0; blockForEnemy < 7; blockForEnemy++) if (typeCountForColor[enemyColor][blockForEnemy] != maxCount) break; } else { blockForEnemy = rand() % 7; } // 决策结束,输出结果(你只需修改以上部分) cout << blockForEnemy << " " << seqLength; for (int i = 0; i < seqLength; i++) cout << " " << seqX[i] << " " << seqY[i] << " " << seqO[i]; return 0; } </syntaxhighlight> === [[JSON]]交互样例程序 === 本地编译和调试的方式请查看 [[JSONCPP]]。 <syntaxhighlight lang="cpp" class="mw-collapsible mw-collapsed"> /** * Tetris JSON交互样例程序 * https://wiki.botzone.org/index.php?title=Tetris */ // 注意:x的范围是1~MAPWIDTH,y的范围是1~MAPHEIGHT // 数组是先行(y)后列(c) // 坐标系:原点在左下角 #include <iostream> #include <string> #include <cmath> #include <algorithm> #include <cstdlib> #include <ctime> #include "jsoncpp/json.h" using namespace std; #define MAPWIDTH 10 #define MAPHEIGHT 20 // 我所在队伍的颜色(0为红,1为蓝,仅表示队伍,不分先后) int currBotColor; int enemyColor; // 先y后x,记录地图状态,0为空,1为以前放置,2为刚刚放置,负数为越界 // (2用于在清行后将最后一步撤销再送给对方) int gridInfo[2][MAPHEIGHT + 2][MAPWIDTH + 2] = { 0 }; // 代表分别向对方转移的行 int trans[2][4][MAPWIDTH + 2] = { 0 }; // 转移行数 int transCount[2] = { 0 }; // 运行eliminate后的当前高度 int maxHeight[2] = { 0 }; // 总消去行数的分数之和 int elimTotal[2] = { 0 }; // 一次性消去行数对应分数 const int elimBonus[4] = { 1, 3, 5, 7 }; // 给对应玩家的各类块的数目总计 int typeCountForColor[2][7] = { 0 }; const int blockShape[7][4][8] = { { { 0,0,1,0,-1,0,-1,-1 },{ 0,0,0,1,0,-1,1,-1 },{ 0,0,-1,0,1,0,1,1 },{ 0,0,0,-1,0,1,-1,1 } }, { { 0,0,-1,0,1,0,1,-1 },{ 0,0,0,-1,0,1,1,1 },{ 0,0,1,0,-1,0,-1,1 },{ 0,0,0,1,0,-1,-1,-1 } }, { { 0,0,1,0,0,-1,-1,-1 },{ 0,0,0,1,1,0,1,-1 },{ 0,0,-1,0,0,1,1,1 },{ 0,0,0,-1,-1,0,-1,1 } }, { { 0,0,-1,0,0,-1,1,-1 },{ 0,0,0,-1,1,0,1,1 },{ 0,0,1,0,0,1,-1,1 },{ 0,0,0,1,-1,0,-1,-1 } }, { { 0,0,-1,0,0,1,1,0 },{ 0,0,0,-1,-1,0,0,1 },{ 0,0,1,0,0,-1,-1,0 },{ 0,0,0,1,1,0,0,-1 } }, { { 0,0,0,-1,0,1,0,2 },{ 0,0,1,0,-1,0,-2,0 },{ 0,0,0,1,0,-1,0,-2 },{ 0,0,-1,0,1,0,2,0 } }, { { 0,0,0,1,-1,0,-1,1 },{ 0,0,-1,0,0,-1,-1,-1 },{ 0,0,0,-1,1,-0,1,-1 },{ 0,0,1,0,0,1,1,1 } } };// 7种形状(长L| 短L| 反z| 正z| T| 直一| 田格),4种朝向(上左下右),8:每相邻的两个分别为x,y class Tetris { public: const int blockType; // 标记方块类型的序号 0~6 int blockX; // 旋转中心的x轴坐标 int blockY; // 旋转中心的y轴坐标 int orientation; // 标记方块的朝向 0~3 const int(*shape)[8]; // 当前类型方块的形状定义 int color; Tetris(int t, int color) : blockType(t), shape(blockShape[t]), color(color) { } inline Tetris &set(int x = -1, int y = -1, int o = -1) { blockX = x == -1 ? blockX : x; blockY = y == -1 ? blockY : y; orientation = o == -1 ? orientation : o; return *this; } // 判断当前位置是否合法 inline bool isValid(int x = -1, int y = -1, int o = -1) { x = x == -1 ? blockX : x; y = y == -1 ? blockY : y; o = o == -1 ? orientation : o; if (o < 0 || o > 3) return false; int i, tmpX, tmpY; for (i = 0; i < 4; i++) { tmpX = x + shape[o][2 * i]; tmpY = y + shape[o][2 * i + 1]; if (tmpX < 1 || tmpX > MAPWIDTH || tmpY < 1 || tmpY > MAPHEIGHT || gridInfo[color][tmpY][tmpX] != 0) return false; } return true; } // 判断是否落地 inline bool onGround() { if (isValid() && !isValid(-1, blockY - 1)) return true; return false; } // 将方块放置在场地上 inline bool place() { if (!onGround()) return false; int i, tmpX, tmpY; for (i = 0; i < 4; i++) { tmpX = blockX + shape[orientation][2 * i]; tmpY = blockY + shape[orientation][2 * i + 1]; gridInfo[color][tmpY][tmpX] = 2; } return true; } // 检查能否逆时针旋转自己到o inline bool rotation(int o) { if (o < 0 || o > 3) return false; if (orientation == o) return true; int fromO = orientation; while (true) { if (!isValid()) return false; if (fromO == o) break; fromO = (fromO + 1) % 4; } return true; } }; // 围一圈护城河 void init() { int i; for (i = 0; i < MAPHEIGHT + 2; i++) { gridInfo[1][i][0] = gridInfo[1][i][MAPWIDTH + 1] = -2; gridInfo[0][i][0] = gridInfo[0][i][MAPWIDTH + 1] = -2; } for (i = 0; i < MAPWIDTH + 2; i++) { gridInfo[1][0][i] = gridInfo[1][MAPHEIGHT + 1][i] = -2; gridInfo[0][0][i] = gridInfo[0][MAPHEIGHT + 1][i] = -2; } } namespace Util { // 检查能否从场地顶端直接落到当前位置 inline bool checkDirectDropTo(int color, int blockType, int x, int y, int o) { auto &def = blockShape[blockType][o]; for (; y <= MAPHEIGHT; y++) for (int i = 0; i < 4; i++) { int _x = def[i * 2] + x, _y = def[i * 2 + 1] + y; if (_y > MAPHEIGHT) continue; if (_y < 1 || _x < 1 || _x > MAPWIDTH || gridInfo[color][_y][_x]) return false; } return true; } // 消去行 void eliminate(int color) { int &count = transCount[color] = 0; int i, j, emptyFlag, fullFlag; maxHeight[color] = MAPHEIGHT; for (i = 1; i <= MAPHEIGHT; i++) { emptyFlag = 1; fullFlag = 1; for (j = 1; j <= MAPWIDTH; j++) { if (gridInfo[color][i][j] == 0) fullFlag = 0; else emptyFlag = 0; } if (fullFlag) { for (j = 1; j <= MAPWIDTH; j++) { // 注意这里只转移以前的块,不包括最后一次落下的块(“撤销最后一步”) trans[color][count][j] = gridInfo[color][i][j] == 1 ? 1 : 0; gridInfo[color][i][j] = 0; } count++; } else if (emptyFlag) { maxHeight[color] = i - 1; break; } else for (j = 1; j <= MAPWIDTH; j++) { gridInfo[color][i - count][j] = gridInfo[color][i][j] > 0 ? 1 : gridInfo[color][i][j]; if (count) gridInfo[color][i][j] = 0; } } maxHeight[color] -= count; elimTotal[color] += elimBonus[count]; } // 转移双方消去的行,返回-1表示继续,否则返回输者 int transfer() { int color1 = 0, color2 = 1; if (transCount[color1] == 0 && transCount[color2] == 0) return -1; if (transCount[color1] == 0 || transCount[color2] == 0) { if (transCount[color1] == 0 && transCount[color2] > 0) swap(color1, color2); int h2; maxHeight[color2] = h2 = maxHeight[color2] + transCount[color1]; if (h2 >= MAPHEIGHT) return color2; int i, j; for (i = h2; i > transCount[color1]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = gridInfo[color2][i - transCount[color1]][j]; for (i = transCount[color1]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = trans[color1][i - 1][j]; return -1; } else { int h1, h2; maxHeight[color1] = h1 = maxHeight[color1] + transCount[color2];//从color1处移动count1去color2 maxHeight[color2] = h2 = maxHeight[color2] + transCount[color1]; if (h1 > MAPHEIGHT) return color1; if (h2 > MAPHEIGHT) return color2; int i, j; for (i = h2; i > transCount[color1]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = gridInfo[color2][i - transCount[color1]][j]; for (i = transCount[color1]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color2][i][j] = trans[color1][i - 1][j]; for (i = h1; i > transCount[color2]; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color1][i][j] = gridInfo[color1][i - transCount[color2]][j]; for (i = transCount[color2]; i > 0; i--) for (j = 1; j <= MAPWIDTH; j++) gridInfo[color1][i][j] = trans[color2][i - 1][j]; return -1; } } // 颜色方还能否继续游戏 inline bool canPut(int color, int blockType) { Tetris t(blockType, color); for (int y = MAPHEIGHT; y >= 1; y--) for (int x = 1; x <= MAPWIDTH; x++) for (int o = 0; o < 4; o++) { t.set(x, y, o); if (t.isValid() && checkDirectDropTo(color, blockType, x, y, o)) return true; } return false; } // 打印场地用于调试 inline void printField() { #ifndef _BOTZONE_ONLINE static const char *i2s[] = { "~~", "~~", " ", "[]", "##" }; cout << "~~:墙,[]:块,##:新块" << endl; for (int y = MAPHEIGHT + 1; y >= 0; y--) { for (int x = 0; x <= MAPWIDTH + 1; x++) cout << i2s[gridInfo[0][y][x] + 2]; for (int x = 0; x <= MAPWIDTH + 1; x++) cout << i2s[gridInfo[1][y][x] + 2]; cout << endl; } #endif } } int main() { // 加速输入 istream::sync_with_stdio(false); srand(time(NULL)); init(); int turnID, blockType; int nextTypeForColor[2]; // 读入JSON string str; getline(cin, str); Json::Reader reader; Json::Value input; reader.parse(str, input); // 先读入第一回合,得到自己的颜色 // 双方的第一块肯定是一样的 turnID = input["responses"].size() + 1; auto &first = input["requests"][(Json::UInt) 0]; blockType = first["block"].asInt(); currBotColor = first["color"].asInt(); enemyColor = 1 - currBotColor; nextTypeForColor[0] = blockType; nextTypeForColor[1] = blockType; typeCountForColor[0][blockType]++; typeCountForColor[1][blockType]++; // 然后分析以前每回合的输入输出,并恢复状态 // 循环中,color 表示当前这一行是 color 的行为 // 平台保证所有输入都是合法输入 for (int i = 1; i < turnID; i++) { int currTypeForColor[2] = { nextTypeForColor[0], nextTypeForColor[1] }; int x, y, o; // 根据这些输入输出逐渐恢复状态到当前回合 // 先读自己的输出,也就是自己的行为 // 自己的输出是一个序列,但是只有最后一步有用 // 所以只保留最后一步 // 然后模拟最后一步放置块 auto &myOutput = input["responses"][i - 1]; blockType = myOutput["block"].asInt(); auto &seq = myOutput["seq"]; auto &lastPos = seq[seq.size() - 1]; x = lastPos["x"].asInt(); y = lastPos["y"].asInt(); o = lastPos["o"].asInt(); // 我当时把上一块落到了 x y o! Tetris myBlock(currTypeForColor[currBotColor], currBotColor); myBlock.set(x, y, o).place(); // 我给对方什么块来着? typeCountForColor[enemyColor][blockType]++; nextTypeForColor[enemyColor] = blockType; // 然后读自己的输入,也就是对方的行为 // 裁判给自己的输入只有对方的最后一步 auto &myInput = input["requests"][i]; blockType = myInput["block"].asInt(); x = myInput["x"].asInt(); y = myInput["y"].asInt(); o = myInput["o"].asInt(); // 对方当时把上一块落到了 x y o! Tetris enemyBlock(currTypeForColor[enemyColor], enemyColor); enemyBlock.set(x, y, o).place(); // 对方给我什么块来着? typeCountForColor[currBotColor][blockType]++; nextTypeForColor[currBotColor] = blockType; // 检查消去 Util::eliminate(0); Util::eliminate(1); // 进行转移 Util::transfer(); } int blockForEnemy, seqX[MAPHEIGHT + 1], seqY[MAPHEIGHT + 1], seqO[MAPHEIGHT + 1], seqLength = 0; // 做出决策(你只需修改以下部分) // 遇事不决先输出(平台上运行不会输出) Util::printField(); // 贪心决策 // 从下往上以各种姿态找到第一个位置,要求能够直着落下 Tetris block(nextTypeForColor[currBotColor], currBotColor); for (int y = 1; y <= MAPHEIGHT; y++) for (int x = 1; x <= MAPWIDTH; x++) for (int o = 0; o < 4; o++) { if (block.set(x, y, o).isValid() && Util::checkDirectDropTo(currBotColor, block.blockType, x, y, o)) { seqX[0] = x; seqY[0] = y; seqO[0] = o; seqLength = 1; goto determined; } } determined: // 再看看给对方什么好 int maxCount = 0, minCount = 99; for (int i = 0; i < 7; i++) { if (typeCountForColor[enemyColor][i] > maxCount) maxCount = typeCountForColor[enemyColor][i]; if (typeCountForColor[enemyColor][i] < minCount) minCount = typeCountForColor[enemyColor][i]; } if (maxCount - minCount == 2) { // 危险,找一个不是最大的块给对方吧 for (blockForEnemy = 0; blockForEnemy < 7; blockForEnemy++) if (typeCountForColor[enemyColor][blockForEnemy] != maxCount) break; } else { blockForEnemy = rand() % 7; } // 决策结束,输出结果(你只需修改以上部分) Json::Value output; Json::FastWriter writer; output["response"]["block"] = blockForEnemy; auto &seq = output["response"]["seq"]; for (int i = 0; i < seqLength; i++) { seq[i]["x"] = seqX[i]; seq[i]["y"] = seqY[i]; seq[i]["o"] = seqO[i]; } cout << writer.write(output); return 0; } </syntaxhighlight>
返回至
Tetris
。
导航菜单
个人工具
中文(中国大陆)
创建账户
登录
命名空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
最近更改
随机页面
帮助
工具
链入页面
相关更改
特殊页面
页面信息