65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2023年12月25日

公共领域

14分钟阅读

viewsIcon

7983

downloadIcon

130

您需要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是可选的。它允许将类名更改为用户看到的更友好的名称,并指示该机器人是否应用作默认选项。

RobotSimpleRobot提供了对Player(机器人本身)、GameMapRobotCountryIds(拥有的国家)和Results的便捷访问。

请注意,机器人每次移动都会获得全新的Game、国家等实例。例如,不可能从之前的移动中重用一个国家实例。但是,Country.IDPlayer.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上与我们分享?

© . All rights reserved.