作者laechan (挥泪斩马云)
看板mud_sanc
标题[wizs] 随机地图的生成
时间Sat Nov 17 16:45:44 2018
这东西我有想过怎麽做比较好,它大致有两种做法
一、生成 m x n 格图,然後依一定的规则随机挖空
二、先生成一个点,然後采递回做法(设定边界)让它向外随机扩散
若是第一种做法,「规则」虽是重点,但其实规则也没那麽重要,
因为可以用 re-check 来确保点与点之间至少都存在两个连结。
(不过这个 re-check 会写得很复杂,所以还是回到确立规则上)
若是第二种做法,倒是不一定要用递回,比方让它每一秒自我呼叫
一次时就扩散一次,这样差不多就能达到要求,缺点是它很难避免
「中心点」的存在,而并非所有地图都有中心点。
根据以上,初步结论看起来是采第一种做法。
但是上面两种方法我都不想用。
======
假设以下格图 以及我最终希望看到的格图
x-x-x-x-x x-x-x x
| | | | | | |
x-x-x-x-x x-x x
| | | | | | |
x-x-x-x-x x-x-x x
| | | | | | |
x-x-x-x-x x-x-x-x
实际上依我先前规划的各种随机做法,都不可能产生右边的格图,
除非我制定一种规则叫做先决定起点与终点,然後再令它去爬,才
有可能,这东西看似复杂,其实它有简单的做法:
比方起点是 (0,0) 终点是 (4,0) 这样的设计,
题目就变成这两点
之间在边界范围 4, 3 之下可拉出多少条线的问题:
starts=({0,0});
ends=({4,0});
// 首先决定下一点是往右还是往下
random(2)==1 ? nexts=({0+1,0}); : nexts=({0,0+1});
starts+=({nexts});
s=1;
over_bound=0;
// 然後就可以随机了
while(starts[s]!=ends) // 实际上不会这样子写
{
x=starts[s][0]-starts[s-1][0];
y=starts[s][1]-starts[s-1][1];
// 这里只有一个规则: 不能走回头路
if(random(2)==1) // 横移
{
if(x!=0) // 代表上次是横移
{
// 就只能往同方向再横移
nexts=({starts[s][0]+x,starts[s][1]});
}
else // 上次不是横移, 那往哪个方向都可
nexts=({random(2)==1 ? starts[s][0]-1 : starts[s][0]+1,starts[s][1]});
}
else // 直移
{
if(y!=0) // 代表上次是直移
{
// 就只能往同方向再直移
nexts=({starts[s][0],starts[s][1]+y});
}
else // 上次不是直移, 那往哪个方向都可
nexts=({starts[s][0],random(2)==1 ? starts[s][1]-1 : starts[s][1]+1});
}
// 先检测 nexts 有没有在 starts 内, 有的话就是重跑
if(member_array(nexts,starts)!=-1) continue;
// 检测 nexts 有没有超过边界
if(nexts[0]<0 || nexts[0]>4 ||
nexts[1]<0 || nexts[1]>3)
{
over_bound++;
if(over_bound>10) // 保险值
break; // 中断
continue; // 在保险值内就再一次
}
// 都没超过边界就是安全的
starts+=({nexts});
s++;
over_bound=0;
// 继续跑回圈
}
// 最後列出跑出来的 starts
write(identify(starts)+"\n");
以下是跑出来的几次结果:
({ ({ 0, 0 }), ({ 1, 0 }), ({ 2, 0 }), ({ 3, 0 }), ({ 4, 0 }) })
这个再明显不过就是一直横移过去 x-x-x-x-x
({ ({ 0, 0 }), ({ 0, 1 }), ({ 0, 2 }), ({ 1, 2 }), ({ 2, 2 }),
({ 3, 2 }), ({ 3, 1 }), ({ 3, 0 }), ({ 4, 0 }) })
x x-x
| |
x x
| |
x-x-x-x
({ ({ 0, 0 }), ({ 0, 1 }), ({ 0, 2 }), ({ 0, 3 }), ({ 1, 3 }),
({ 2, 3 }), ({ 3, 3 }), ({ 4, 3 }), ({ 4, 2 }), ({ 4, 1 }),
({ 4, 0 }) })
x x
| |
x x
| |
x x
| |
x-x-x-x-x
({ ({ 0, 0 }), ({ 1, 0 }), ({ 1, 1 }), ({ 0, 1 }), ({ 0, 2 }),
({ 0, 3 }), ({ 1, 3 }), ({ 1, 2 }), ({ 2, 2 }), ({ 3, 2 }),
({ 3, 3 }), ({ 4, 3 }), ({ 4, 2 }), ({ 4, 1 }), ({ 4, 0 }) })
x-x x
| |
x-x x
| | <= 这张大致就是我们要的形式
x x-x-x x
| | | |
x-x x-x
上面打了一堆其实重点是:
一、单一路线型随机地图是可行的
二、过往我要自己产生 m x n 的图後再自己挖洞,现在可以让
程式帮我挖。
三、原本需要自己选出哪一张地图较适合,现在可以用「产生出
几%以上的点」来做为一种指标,例如以上面产生的那张图
为例为 15点/总共20点 = 75%,15 点其实就像一张正常的
地图了的意思。
这时甚至可以设定让它跑出更多的点,例如以下是 17 点:
({ ({ 0, 0 }), ({ 1, 0 }), ({ 1, 1 }), ({ 0, 1 }), ({ 0, 2 }),
({ 0, 3 }), ({ 1, 3 }), ({ 2, 3 }), ({ 2, 2 }), ({ 2, 1 }),
({ 2, 0 }), ({ 3, 0 }), ({ 3, 1 }), ({ 3, 2 }), ({ 4, 2 }),
({ 4, 1 }), ({ 4, 0 }) })
x-x x-x x
| | | |
x-x x x x
| | | |
x x x-x
| |
x-x-x
以上只是先证明这构想是可 work 的,後面的回文都会以上面
为基础继续下一步的 write & run。
PS、这东西如果我不是先前持续在写 code 以及最近清淡饮食
,要写出来有点难度。
Laechan
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 122.117.106.224
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/mud_sanc/M.1542444349.A.5C0.html
1F:→ laechan : 如果以上叫做随机地图第一工序,它其实就能应用在一 11/17 16:46
2F:→ laechan : 些地方,例如股票涨跌、台风路径的预测 11/17 16:46
3F:→ laechan : 也能用在如何找出a点到b点之间的最短路径上 11/17 16:51
4F:→ laechan : 因为它其实是暴力破解法的一种做法 11/17 16:52
5F:→ laechan : 它是建立在从有限的范围中找出非唯一符合我们所要的 11/17 16:53
6F:→ laechan : 结果的前提之上所建构的做法 11/17 16:53
※ 编辑: laechan (122.117.106.224), 11/17/2018 16:54:52