MasterGrab:PC策略游戏,易于上手,乐趣无穷。您还可以编写自己的C#游戏机器人!





5.00/5 (4投票s)
您需要10分钟的休息时间,或者想在编程前进行一些脑力热身?这款免费游戏非常适合您。
游戏概述
MasterGrab是一款开源的回合制Windows策略游戏,玩家需要与多个电脑玩家(=机器人)对战,试图占领随机地图上的所有国家。这款游戏相当有趣,因为随机地图每次都会带来不同的挑战,而机器人之间也会互相争斗,这使得MasterGrab成为一款动态的游戏。对于程序员来说,编写自己的机器人可能更有趣,这只需要几行C#代码即可完成。
MasterGrab游戏默认显示一张包含4个玩家的地图。3个玩家由计算机控制,红色国家的拥有者是人类玩家(您)。目标是占领所有国家。
您拥有红色国家。在信息下拉菜单中,您可以点击排名查看不同玩家的统计数据。
您(用户)所有国家(屏幕像素总数)的总大小通常略大于其他玩家(机器人)的总大小,这些玩家都由MasterGrab扮演。国家越大,能容纳的军队(国家中心的数字)就越多。这个数字在开始时是随机生成的,但在每回合之后会增长一点,直到达到国家的最大容量,这由粗体数字标示。
您可以攻击任何与您已拥有国家相邻的敌国。
在右图所示的情况下,您拥有数字为7、6和6的红色国家,可以攻击数字为4的绿色国家,因为它们都是邻居。
您可以通过将鼠标悬停在某个国家上来轻松找出它的邻居。例如,在中图所示的情况下,鼠标悬停在绿色国家上时,它会有一个亮边框,而它的邻居则会有暗边框。
您可以攻击拥有4个军队的绿色国家。您有3个国家与该绿色国家相邻,总共有19个军队。要赢得一次攻击,攻击者的军队数量需要略高于被攻击国家的两倍。这里攻击国的军队总数为19,轻松胜过4个防御军队。在左图所示的情况下,您可以看到绿色国家现在变成了红色,因为您赢得了它。赢得一个国家后,您会获得一些额外的军队,这些军队将根据国家的大小分配给攻击国和被占领的国家。请注意,所有国家中的数字都已更改,它们在每回合后都会略微增长,直到达到国家的容量。同时,请注意,其他一些国家也改变了颜色,因为机器人也在互相战斗。
您还可以点击自己的国家,这样来自邻近国家的军队就会被移入被点击的国家。没有敌方邻居的国家会将其所有军队移入,而拥有敌方邻居的国家则会保留一些军队进行防御。请注意,通常情况下,该国家最多只能通过自然增长容纳7个军队,但现在它却有24个。您可以在接下来的回合中将它们移交给敌人进行攻击。或者,您也可以将其留在边境,这将阻止敌人攻击您,转而攻击其他机器人。
回到游戏整体说明。在您完成一回合后,所有机器人都会执行一回合,并且每个国家中的军队都会略微增长。试图赢得相邻的国家是一个不错的策略。
请注意,彩色箭头显示了机器人在您上次行动后所做的移动。大号的圆圈数字显示了战斗结果。小号的圆圈数字标记了最小的国家,最容易攻击。
一旦人类玩家输掉所有国家或赢得所有国家,游戏就结束了。
正如您所见,规则非常容易学习。游戏之所以有趣是因为:
- 它总是不同的,因为地图是随机生成的。
- 它比只有一名对手的游戏(例如国际象棋)更具活力,尤其是因为机器人还会互相攻击。
- 您需要制定自己的策略,让机器人互相攻击,而不是攻击您。
- 机器人并不算太聪明,这意味着大多数随机游戏都可以获胜,尽管有时可能需要几次尝试。
- 机器人也不算太笨,击败它们可能仍然是一个挑战。
- 您可以选择要生成的国家和机器人的数量,从而选择快速游戏或较长的游戏。
- 这是一款回合制游戏,您可以随时思考。机器人几乎瞬间就能完成它们的移动,您无需等待。
- 最后但同样重要的是,您可以用C#编写自己的机器人,这可以在几天内完成。
获取游戏
最简单的方法就是从Github获取完整的代码。
如果您想开发自己的机器人,或者只是想查看源代码,甚至更好地改进游戏,您就需要这些代码。
如果您只想玩游戏,也可以从CodeProject下载一个zip文件,其中包含MasterGrab.exe。
将MasterGrab.zip解压到一个文件夹中,然后双击MasterGrab.exe启动游戏。MasterGrab使用.NET 7。
地图
地图本身没有边界,就像地球一样,地球也没有边缘。窗口左侧边界的国家会环绕到右侧窗口边界,顶部的国家会延续到底部。有趣的是,四张地图的角落实际上是相互连接的。没有边界的地图的好处是,没有国家会因为是边境国家而获得优势,即它会受到更少其他国家的攻击。
Mastergrab窗口
如果您调整MasterGrab
窗口的大小,然后开始新游戏,地图将正确地填充新窗口的大小。
故意设置为无法撤销操作,否则获胜会变得太容易。但是,如果您犯了太多错误,可以点击重玩重新开始同一场游戏。
如果您不想进行任何操作(点击任何国家),可以点击下一步,这将让机器人各自执行一次移动。
帮助会显示一个窗口,解释MasterGrab,类似于本文。
选项
启动MasterGrab时,它会自动生成一个使用默认选项的新游戏。您可以通过点击选项按钮来更改它们。
国家数量
在这里,您可以告诉MasterGrab应该在地图上创建多少个国家。可以是几十个,也可以是几百个。
分布式
默认情况下,所有者会随机分配到地图上的国家。这是最容易玩的模式,因为当一个机器人的国家彼此相邻时,机器人表现更好,就像以下四种分布一样。
玩家
您可以通过点击彩色矩形来更改您国家的颜色,这将打开一个颜色选择器。
如果未启用玩家
,则只有机器人会进行游戏。这可以很有趣,用于研究机器人的策略,或者,如果您自己编写了机器人,可以观察它的行为。只有当您点击下一步按钮,或者在下拉菜单自动播放中选择机器人应移动的频率时,机器人才会进行移动。
Robots
点击添加按钮最多可以创建15个机器人,移除则移除一个。通过右侧的下拉菜单,您可以选择要使用的机器人类型。目前只有两种:基础机器人还不错,简单机器人只是一个非常简单的机器人代码示例,是编写您自己的机器人良好的起点,您的机器人也将显示在此下拉菜单中。我希望随着时间的推移,其他人也能在Github上分享他们的机器人。
2个和15个机器人的地图
您使用的机器人越多,您应该生成的国家就越多。只与1个机器人对战是具有挑战性的,因为它的全部精力都集中在攻击您身上,在这方面它相当出色。与许多机器人对战很有趣,因为您必须先击败邻近的机器人,而更远的机器人则互相争斗,其中一些机器人可能会变得相当庞大。要赢得游戏,您必须击败所有强大的机器人。
作为初学者,最好只从1个机器人和10个国家开始。这是探索您攻击某个国家会产生什么影响的好方法。当国家和机器人数量更多时,后果可能不那么清晰。
选项窗口按钮
默认:用默认值填充选项窗口:140个国家,随机分布和3个机器人。
高级:实际上有一个第二个窗口包含高级选项。一旦您对MasterGrab有了一些经验,就可以去看看。
将鼠标悬停在选项文本框上会显示一个工具提示,解释选项的作用。
启用随机选项可能会很有趣,它将为所有选项设置随机值。启用后,点击确定,这将关闭该窗口并显示选项窗口。在那里,您点击应用,MasterGrab会显示一个只读的高级选项窗口,其中包含新的随机值,您在玩该游戏时应该了解这些值。
应用:点击应用将关闭选项窗口并以选定的选项开始新游戏。
编程您的机器人
基本上,您只需要编写一个继承自Robot
的新类,并将其放入Robots项目中。MasterGrab启动时,它会搜索这些类,并在选项窗口中显示它们,用户可以选择它们进行下一场游戏。
参与游戏的相关类
游戏由GameController
管理。用户可以在选项窗口中选择要玩的机器人类型和数量、地图上的国家数量以及其他设置。当用户按下新游戏时,选项将发送到GameController
,它会启动一个新的Game
。它首先等待用户进行操作,然后要求每个Robot
进行操作(DoPlanMove()
)。机器人会收到最新游戏数据的副本,例如哪个Country
由哪个Player
(人类或机器人)拥有,以及该Country
中的军队大小。Robot
无法更改任何这些数据,这会开辟作弊的途径。Robot
只能告知GameController
它希望进行的下一个移动。
某些数据在游戏过程中会发生变化,例如谁拥有哪个国家,而其他数据在一场游戏中不会改变,例如哪些国家是邻居(Options
, GameFix
, CountryFix
)。
Options
包含创建新游戏所需的所有信息。
当一个机器人可以进行移动时,它会获得代表它的Robot
实例,其中包含机器人所需的所有信息,例如RobotCountryIds
,这是一个它拥有的所有国家(实际上是国家的ID)的集合。
Player
有一个Game
属性,它实际上是类树的根。Map
是一个特殊的集合,包含所有国家。
游戏属性
Map
是一个国家集合。Players
允许机器人检查所有其他玩家的数据。Results
显示上一轮每个玩家的移动,以及它是成功还是失败。AttackFactor
对于机器人决定是否可以攻击敌国非常重要。它首先将邻近敌国的己方国家的军队数量相加。总数乘以AttackFactor
,它小于1
。如果结果大于防御军队的数量,则攻击获胜。
玩家属性
机器人的Player
实例还包含CountryIds
,这是一个包含该玩家(机器人)拥有的所有国家列表。请注意,这些只是唯一的国家ID编号,可用于获取国家数据,如下所示:
var country = Map[countryId];
国家属性
某些Country
属性对机器人不重要,例如它在屏幕上的坐标。以下Country
属性对机器人计算其下一步行动很有用:
NeighbourIds
列出了邻近国家(的国家ID)。ArmySize
在己方国家中的攻击者数量,或在敌方国家中的防御者数量。
一个非常简单的机器人的代码
您可以将SimpleRobot.cs作为编写自己机器人的起点。
using System.Collections.Generic;
namespace MasterGrab {
/// <summary>
/// Simple Robot player using only 1 country to attack
/// </summary>
[Robot(name: "SimpleRobot", isUsedForDefault: false)]
public class SimpleRobot: Robot {
任何命名空间都可以使用。重要的是SimpleRobot
继承自Robot
。使用RobotAttribute
是可选的。它允许将类名更改为用户看到的更友好的名称,并指示该机器人是否应用作默认选项。
Robot
为SimpleRobot
提供了对Player
(机器人本身)、Game
、Map
、RobotCountryIds
(拥有的国家)和Results
的便捷访问。
请注意,机器人每次移动都会获得全新的Game
、国家等实例。例如,不可能从之前的移动中重用一个国家实例。但是,Country.ID
和Player.ID
是常量。因此,如果一个机器人想在几个回合中存储关于另一个玩家的信息,它必须将该玩家的ID与它想要存储的其余数据结合起来。
readonly List<Country> attackers;
变量attackers
不用于在两个回合之间存储信息,而是出于效率原因,它只创建一次然后持续重用。
public SimpleRobot(): base() {
attackers = new List<Country>();
}
当轮到机器人进行下一步移动时,GameController
会调用DoPlanMove()
。这就是您放置机器人代码的地方。
protected override Move DoPlanMove() {
Country? attacker = null;
Country? target = null;
double ratio = 0;
SimpleRobot
使用的策略
- 遍历该机器人拥有的所有国家。
- 找到要攻击的最佳邻居。
SimpleRobot
尝试优化:- 邻近国家的大小(越大越好)。
- 防御者数量(越少越好)。
遍历机器人拥有的每个国家。
foreach (int countryId in RobotCountryIds) {
var country = Map[countryId];
计算攻击军队的数量。
double attackingArmies = country.ArmySize * Game.AttackFactor;
遍历该国家的所有邻居。记住相对于您的攻击国家而言最弱的敌国。
foreach (int neighbourId in country.NeighbourIds) {
var neighbour = Map[neighbourId];
if (
!neighbour.IsMountain && //cannot attack mountain
neighbour.OwnerId!=Player.Id && //don't attack own country
neighbour.ArmySize<attackingArmies) //is robot strong enough ?
{
//calculate how much stronger the attacker is then the defender
double newRatio = attackingArmies / neighbour.ArmySize * neighbour.Size;
if (ratio<newRatio) {
//found a weaker country to attack
ratio = newRatio;
attacker = country;
target = neighbour;
}
}
}
}
在遍历完所有自己的国家后,决定下一步是什么。
Move move;
if (attacker==null) {
如果机器人决定不攻击,它可以选择一个国家,并将周围所有己方国家的军队移动到该国家。请参阅BasicRobot.cs了解如何执行此操作的示例。
SimpleRobot
决定跳过一个回合,如果它无法攻击。
move = Move.NoMove;
} else {
attackers.Clear();
////SimpleRobot is a bit stupid and uses only 1 of his countries to attack
////It would be better if he would use all of his countries
////which are neighbours of the attacked countries,
////like this:
////foreach (int targetNeighbourId in target.NeighbourIds) {
//// Country targetNeighbour = Map[targetNeighbourId];
//// if (targetNeighbour.OwnerId==Player.Id) {
//// attackers.Add(targetNeighbour);
//// }
////}
attackers.Add(attacker);
move = new Move(MoveTypeEnum.attack, Player, target!, attackers);
}
return move;
}
}
}
SimpleRobot
特意保持在最基本的状态。BasicRobot
稍微复杂一些,它会攻击一个敌国,该敌国的所有己方国家都是其邻居,并且当没有好的攻击目标时,它会将邻近其某个国家的己方军队移入该国家。这在游戏的后期阶段相当重要。
然而,BasicRobot
缺乏任何战略规划,例如:
- 检测攻击并进行防御。
- 一旦达到一定规模,也在不同国家增加军队,而不是尽可能多地攻击。
- 哪种攻击能改善其国家的“形状”。
- 当它的国家形成一个“圆圈”时,圆圈内的国家没有敌人。
- 当它设法在屏幕上形成一列国家时,所需的防御就减少了。
- 考虑哪个是敌人中最弱和最强的。
- 通过增加边境的军队来防止强大的邻居攻击。
- 引诱两个敌人互相攻击:如果机器人拥有一个被两个敌人包围的国家,那么这个国家会阻止这两个敌人互相争斗。如果机器人的国家攻击了一个敌国,它很可能会失败,而这两个敌人就会开始互相攻击。
当您自己玩MasterGrab时,您也会发现其他策略,然后您可以将它们教给您的Robot
。
令我惊讶的是,即使是BasicRobot
也没有策略,但实际上很难击败它。这意味着您编写一个更好的Robot
应该不会太难。
已知问题
在随机地图创建中有一个我无法解决的bug。幸运的是,这种情况很少发生,在这种情况下,只需创建一个新的随机地图即可。我将写另一篇CodeProject文章介绍MasterGrab的设计,其中我将更详细地描述这个问题。
我注意到有两个机器人一直在用完全相同的国家互相攻击,并停止对已玩内容做出反应。同样,这种情况很少发生,通常是我有一个拥有非常大军队的国家在它们旁边。我通常会通过攻击其中一个交战的国家来帮助它们。幸运的是,这种情况也非常罕见。
我需要您的帮助
我每天玩MasterGrab已经很多年了,因为它很有趣且引人入胜。我想与其他人分享它,但我不知道该如何做。您可以与朋友分享这款游戏,甚至更好的是,您能告诉我可以使用哪些其他网站来推广这款游戏吗?
而且,如果您改进了代码或添加了更多功能,您能否在Github上与我们分享?