qweytr_1 发表于 2018-1-21 01:39

挖矿技巧

本帖最后由 qweytr_1 于 2018-1-21 18:40 编辑

不知大家有没有遇到过挖到最后一格才出通往下一层的梯子的情况
我反正经常遇到,于是我更新了自己的挖矿顺序,于是脸白了许多
手工做图或许比较麻烦,懒得做了
大约效果是这个样子,都是一次挖矿过程中(很多是手残多点了好几个点,于是没截图,外加,开始图片出了点小问题,后面补图时候发现游戏在后台似乎不是暂停……)

大家脑补细节就好了
首先,给出一个游戏会生成的布局,或许我们可以得到这样一个分布(不要管“占位”,这个字的作用是让表格对齐)

矿 占位
矿 占位
占位
梯子 占位
矿 占位
矿 占位
矿 矿 占位
占位
占位
占位 占位 占位 占位 占位 占位 占位占位
占位 占位


问最多开几个格子可以开到向下一层的梯子?
感觉一般人看到这个会很懵逼,觉得不开完小半张图应该找不到梯子,但答案是8,至多是18
首先要介绍两个引理
第一个被证实的版本是,迷宫应当是按照九宫格随机生成的,每一个九宫格只有一个功能,即,回家,有矿,没矿,向下
后两者表现相同,否则我绝对能只开4个格子解决问题。
九宫格是从左上开始的,于是可以这样划分:


矿 0 0 1 1 1 2 2 2 占位
0 0 0 1
矿 1 2 2 2 占位
0 0 0 1 1 1 2 2 2 占位
3 3 梯子 4 4 4 5 5 5 占位
3 3 3 4 4 4 5 矿 5 占位
3 3
3 4 4 矿 5 5 5 占位
7 7 7 8 矿 8 矿 9 9 占位
7 7 7 8 8 8 9 9 9 占位
7 7 7 8 8 8 9 9 9 占位
占位 占位 占位 占位 占位 占位 占位占位
占位 占位
(数数时候把6漏掉了,不要在意)
可以看出,同一编号的格子只有一个作用,即,有一格矿,什么都没有,或者有一个梯子
于是可以大胆猜测(两次开到31层也证明了这一点)
向下的梯子一定位于什么都没有的九宫格(即,标2的或者标7的)
然后呢,迷宫设计其实是有缺陷的,就是,很有可能某次生成的时候,最下面某一行或者最右边某一行被删除。
万一删掉梯子怎么办呢?
一个可行的答案是,不允许梯子随机出现在九宫格的最下或者最右
也就是,梯子只会出现在红色部分

矿 0 0 1 1 1 2 2 2 占位
0 0 0 1
矿 1 2 2 2 占位
0 0 0 1 1 1 2 2 2 占位
3 3 梯子 4 4 4 5 5 5 占位
3 3 3 4 4 4 5 矿 5 占位
3 3
3 4 4 矿 5 5 5 占位
7 7 7 8 矿 8 矿 9 9 占位
7 7 7 8 8 8 9 9 9 占位
7 7 7 8 8 8 9 9 9 占位
占位 占位 占位 占位 占位 占位 占位占位
占位 占位
虽然不清楚作者是怎么写程序的,但是根据最近10次挖洞经验,梯子的确是这样生成的
借助这个或许可以让挖矿速度x2x3x6
具体能乘多少就看原先脸有多黑了
比如先挖矿再顺路挖矿附近的……大约可以x12吧

Note:从第46层开始,分块大小变成了4x4(测试是44-49,50又回到了3x3的分块,不知具体缘由),因而上述算法需要修正
具体怎么改正在总结规律

qweytr_1 发表于 2018-1-21 18:46

本帖最后由 qweytr_1 于 2018-1-21 18:53 编辑

找到了或许相关的代码位置,有兴趣的可以分析一下,或者照着这条路继续走下去

首先这个应该说是最有用的

// MazeGenerator
public void SetFloorData()
{
    this.ReleaseAllMineral();
    this.m_upRadder.gameObject.SetActive(true);
    this.m_downRadder.gameObject.SetActive(false);
    MazeData levelData = this.m_mineData.GetLevelData();
    levelData.GenerateChip();
    MapCellData cell = MapManager.GetInstance().GetCell(levelData.m_upLevPos);
    cell.m_eventID = 2;
    this.m_upRadder.SetPos(levelData.m_upLevPos);
    this.m_downLevelPos = levelData.m_downLevPos.Clone();
    if (levelData.m_isAppearLadder)
    {
      this.SetDownLevel();
    }
    MineralManager.GetInstance().Apply(levelData.m_mineralList, true);
}

// MazeData
public void LevelGenerate(IVec2 entrancePos, MineLevel mineLevel, bool isEnableDownLevel)
{
    IVec2 vec = mineLevel.size.Clone();
    int num = (vec.x + vec.y) / 2;
    int max;
    if (num < 15)
    {
      max = 3;
    }
    else if (num < 20)
    {
      max = 4;
    }
    else
    {
      max = 5;
    }
    int num2 = UnityEngine.Random.Range(3, max);
    int num3 = UnityEngine.Random.Range(mineLevel.mineralMin, mineLevel.mineralMax);
    int breakWallCount = mineLevel.breakWallCount;
    entrancePos = this.GenerateMaze(entrancePos, vec, num2, breakWallCount);
    this.SetupRoof(MazeData.k_wallHeight);
    this.m_upLevPos = entrancePos;
    if (isEnableDownLevel)
    {
      this.m_downLevPos = this.GetEntryPoint();
      if (this.m_downLevPos != null)
      {
            this.m_downLevPos *= num2;
            this.m_downLevPos.x += UnityEngine.Random.Range(0, num2 - 1);
            this.m_downLevPos.y += UnityEngine.Random.Range(2, num2);
      }
      else
      {
            this.m_downLevPos = this.m_upLevPos.Clone();
            this.m_downLevPos.x += num2 - 1;
      }
    }
    else
    {
      this.m_downLevPos = new IVec2(0, 0);
    }
    Assert.Message(this.m_downLevPos != null, "迷路作成で下り梯子を作成できませんでした");
    IVec2 vec2 = new IVec2();
    int num4 = 0;
    for (int i = 0; i < num3; i++)
    {
      vec2 = this.GetEntryPoint();
      if (vec2 != null)
      {
            vec2 *= num2;
            vec2.x += UnityEngine.Random.Range(0, num2);
            vec2.y += UnityEngine.Random.Range(1, num2);
            int mineralID = 6 + mineLevel.mineLevel;
            this.m_mineralList.AddStatus(mineralID, vec2);
            num4++;
      }
    }
    if (num4 == 0)
    {
      vec2 = entrancePos.Clone();
      vec2.x = vec2.x / num2 * num2;
      vec2.y = vec2.y / num2 * num2;
      IVec2 vec3 = new IVec2();
      IVec2 vec4 = entrancePos.Clone();
      vec4.y--;
      int num5 = 20;
      do
      {
            vec3.x = vec2.x + UnityEngine.Random.Range(0, num2);
            vec3.y = vec2.y + UnityEngine.Random.Range(1, num2);
      }
      while ((vec3 == entrancePos || vec3 == this.m_downLevPos || vec3 == vec4) && --num5 >= 0);
      if (num5 < 0)
      {
            vec3 = entrancePos;
            vec3.x++;
      }
      int mineralID2 = 6 + mineLevel.mineLevel;
      this.m_mineralList.AddStatus(mineralID2, vec3);
    }
    Debug.Log(string.Concat(new object[]
    {
      "坑道サイズ(",
      this.m_genMazeSize.x,
      ",",
      this.m_genMazeSize.y,
      ")\n上り座標(",
      entrancePos.x,
      ",",
      entrancePos.y,
      ")\n下り座標(",
      this.m_downLevPos.x,
      ",",
      this.m_downLevPos.y,
      ")\n"
    }));
}

// MazeData
private void GenerateMaze(IVec2 bPos)
{
    this.m_createChip = 0;
    int[] array = new int[]
    {
      0,
      1,
      2,
      3
    };
    for (int i = 0; i < 4; i++)
    {
      int num = UnityEngine.Random.Range(0, 4);
      int num2 = array;
      array = array;
      array = num2;
    }
    for (int j = 0; j < 4; j++)
    {
      IVec2 vec = bPos + this.m_mzGrid];
      IVec2 vec2 = vec + this.m_mzGrid];
      if (vec2.x >= 0 && vec2.x < this.m_genMazeSize.x && vec2.y >= 0 && vec2.y < this.m_genMazeSize.y && this.m_createChip == 1 && this.m_createChip == 1)
      {
            this.m_createChip = 0;
            this.GenerateMaze(vec2);
      }
    }
}

// MazeData
private IVec2 GenerateMaze(IVec2 entrancePos, IVec2 size, int grid, int breakCount)
{
    IVec2 vec = entrancePos.Clone();
    this.m_createChip = null;
    this.m_genMazeSize = size.Clone();
    if (this.m_genMazeSize.x > this.m_size.x)
    {
      this.m_genMazeSize.x = this.m_size.x;
    }
    if (this.m_genMazeSize.y > this.m_size.y)
    {
      this.m_genMazeSize.y = this.m_size.y;
    }
    vec /= grid;
    this.m_genMazeSize /= grid;
    if (vec.x >= this.m_genMazeSize.x - 1)
    {
      vec.x = this.m_genMazeSize.x - 2;
    }
    if (vec.y >= this.m_genMazeSize.y - 1)
    {
      vec.y = this.m_genMazeSize.y - 2;
    }
    vec.x |= 1;
    vec.y |= 1;
    this.m_createChip = new int[this.m_genMazeSize.x, this.m_genMazeSize.y];
    MazeData.ccc++;
    Debug.Log(string.Concat(new object[]
    {
      MazeData.ccc,
      " MazeSize = (",
      this.m_genMazeSize.x,
      ",",
      this.m_genMazeSize.y,
      ") grid=",
      grid,
      " start pos =",
      vec.x,
      ",",
      vec.y,
      " / ",
      entrancePos.x,
      ",",
      entrancePos.y
    }));
    for (int i = 0; i < this.m_genMazeSize.y; i++)
    {
      for (int j = 0; j < this.m_genMazeSize.x; j++)
      {
            this.m_createChip = 1;
      }
    }
    this.GenerateMaze(vec);
    this.m_createChip = 0;
    this.m_entryPoint.Clear();
    IVec2 vec2 = new IVec2();
    for (int k = 0; k < this.m_genMazeSize.y; k++)
    {
      for (int l = 0; l < this.m_genMazeSize.x; l++)
      {
            vec2.x = l;
            vec2.y = k;
            if (vec != vec2 && this.m_createChip == 0)
            {
                this.m_entryPoint.Add(vec2.Clone());
            }
      }
    }
    int num = breakCount * 4;
    for (int m = 0; m < breakCount; m++)
    {
      vec2.x = UnityEngine.Random.Range(1, this.m_genMazeSize.x - 1);
      vec2.y = UnityEngine.Random.Range(1, this.m_genMazeSize.y - 1);
      bool flag = false;
      for (int n = 0; n < 4; n++)
      {
            int num2 = Mathf.Clamp(vec2.x + this.m_sideVec.x, 0, this.m_genMazeSize.x - 1);
            int num3 = Mathf.Clamp(vec2.y + this.m_sideVec.y, 0, this.m_genMazeSize.y - 1);
            if (this.m_createChip == 0)
            {
                flag = true;
            }
      }
      if (flag)
      {
            this.m_createChip = 0;
      }
      else if (--num >= 0)
      {
            m--;
      }
    }
    this.ResetChip(1);
    for (int num4 = 0; num4 < this.m_size.y; num4++)
    {
      for (int num5 = 0; num5 < this.m_size.x; num5++)
      {
            int num6 = num5 / grid;
            int num7 = num4 / grid;
            if (num6 >= 0 && num6 < this.m_genMazeSize.x && num7 >= 0 && num7 < this.m_genMazeSize.y && this.m_createChip == 0)
            {
                this.m_chip = 0;
            }
      }
    }
    vec *= grid;
    vec.y += grid - 1;
    return vec;
}

殇丶丶丶 发表于 2018-4-12 18:51

但是当到31层或者更高(记得不是很清了)这个方法就不适用了 ,应该是换了一系列代码导致下一层的楼梯不在那些位置了

qweytr_1 发表于 2018-4-12 20:49

殇丶丶丶 发表于 2018-4-12 18:51
但是当到31层或者更高(记得不是很清了)这个方法就不适用了 ,应该是换了一系列代码导致下一层的楼梯不在 ...

似乎是有的地图把3x3改成了4x4
然而梯子的位置一定还是在那四格之中

殇丶丶丶 发表于 2018-4-15 01:12

qweytr_1 发表于 2018-4-12 20:49
似乎是有的地图把3x3改成了4x4
然而梯子的位置一定还是在那四格之中

了解了:lol

sunboyzero 发表于 2018-10-17 15:23

膜拜大神!受益匪浅!{:3_113:}

666123123 发表于 2018-12-5 02:11

这个属于意外情况吗?

qweytr_1 发表于 2018-12-5 16:21

666123123 发表于 2018-12-5 02:11
这个属于意外情况吗?

话说你到底挖了多少层……

这并不是意外情况
只是布局变成了4*4而已
而这一个布局中,梯子仍然在4*4布局的左上角


666123123 发表于 2018-12-5 23:34

第八十层 一样的情况

qweytr_1 发表于 2018-12-7 17:56

本帖最后由 qweytr_1 于 2018-12-7 18:01 编辑

666123123 发表于 2018-12-5 23:34
第八十层 一样的情况
可以看出,同一编号的格子只有一个作用,即,有一格矿,什么都没有,或者有一个梯子
这张图是3x3的布局
每个3*3的格子,如果有东西(梯子/矿)就一定挖不到向下
而看上去是空的3*3的格子才有可能有向下的坑
而这样的空格子,只有左上角2*2的区域有可能是梯子

我的表述能力真的这么差吗


枯木阿 发表于 2018-12-31 17:37

可以可以,很到位

枯木阿 发表于 2019-1-6 16:21

NICE,很到位
页: [1]
查看完整版本: 挖矿技巧