我试图创建由PRNG程序生成的1和0的无限地图,但只存储7x7的网格,这是可见的。例如,在屏幕上,你将看到一个7x7的网格,其中显示了1和0的地图的一部分,当你向右推时,它会移动1和0,并将下一行放置到位。
如果你然后左移,因为它是伪随机生成的,它会重新生成并显示原始的。你可以无限地上下移动。
我所遇到的问题是,最初的地图看起来并不那么随机,当你向左或向右滚动时,模式会重复,我认为这与我如何生成数字有关。例如,你可以从查看x=5000和y= 10000开始,因此它需要从这两个值生成一个唯一的种子。
(复杂度是视口大小的变量)
void CreateMap(){
if(complexity%2==0) {
complexity--;
}
if (randomseed) {
levelseed=Time.time.ToString();
}
psuedoRandom = new System.Random(levelseed.GetHashCode());
offsetx=psuedoRandom.Next();
offsety=psuedoRandom.Next();
levellocation=psuedoRandom.Next();
level = new int[complexity,complexity];
middle=complexity/2;
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
int hashme=levellocation+offsetx+x*offsety+y;
psuedoRandom = new System.Random(hashme.GetHashCode());
level[x,y]=psuedoRandom.Next(0,2);
}
}
}
这是我用来左右移动的,
void MoveRight(){
offsetx++;
for (int x=0;x<complexity-1;x++){
for (int y=0;y<complexity;y++){
level[x,y]=level[x+1,y];
}
}
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random(levellocation+offsetx*y);
level[complexity-1,y]=psuedoRandom.Next(0,2);
}
}
void MoveLeft(){
offsetx--;
for (int x=complexity-1;x>0;x--){
for (int y=0;y<complexity;y++){
level[x,y]=level[x-1,y];
}
}
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random(levellocation+offsetx*y);
level[0,y]=psuedoRandom.Next(0,2);
}
}
我需要设置
水平(x, y) = Returnrandom (offsetx offsety)
int RandomReturn(int x, int y){
psuedoRandom = new System.Random(Whatseedshouldiuse);
return (psuedoRandom.Next (0,2));
}
我认为你的问题是你正在创建一个'新的'随机循环…不要像现在这样重新声明内部循环……而是在类级别声明它,然后简单地使用psuedoRandom。下一个例子,请看这篇关于你正在经历的问题的例子
而不是在每次迭代时重新实例化Random()类:
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
int hashme=levellocation+offsetx+x*offsety+y;
psuedoRandom = new System.Random(hashme.GetHashCode());
level[x,y]=psuedoRandom.Next(0,2);
}
}
更像
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
// Give me the next random integer
moreRandom = psuedoRandom.Next();
}
}
EDIT:正如Enigmativity在这篇文章下面的评论中指出的那样,在每次迭代中重新设置也是浪费时间/资源。
注:如果你真的需要这样做,那么为什么不使用"与时间相关的默认种子值"而不是指定一个呢?
我将使用SipHash来散列坐标:
- 实现起来相对简单
- 它接受一个键(地图的种子)和一个消息(坐标)作为输入
- 你可以增加或减少回合数作为质量/性能权衡。
- 不像你的代码,结果可以跨进程和机器重现。
SipHash网站列出了两个c#实现:
- https://github.com/tanglebones/ch-siphash
- https://github.com/BrandonHaynes/siphash-csharp
我已经玩了一点创建rnd(x, y, seed)
:
class Program
{
const int Min = -1000; // define the starting point
static void Main(string[] args)
{
for (int x = 0; x < 10; x++)
{
for (int y = 0; y < 10; y++)
Console.Write((RND(x, y, 123) % 100).ToString().PadLeft(4));
Console.WriteLine();
}
Console.ReadKey();
}
static int RND(int x, int y, int seed)
{
var rndX = new Random(seed);
var rndY = new Random(seed + 123); // a bit different
// because Random is LCG we can only move forward
for (int i = Min; i < x - 1; i++)
rndX.Next();
for (int i = Min; i < y - 1; i++)
rndY.Next();
// return some f(x, y, seed) = function(rnd(x, seed), rnd(y, seed))
return rndX.Next() + rndY.Next() << 1;
}
}
它可以工作,但如果一个完整的实现(因为Random
是LCG),它应该给出一个总的想法。它的内存效率(没有数组)。可接受的折衷方案是实现值缓存,然后当位于映射周围的某些部分的值将从缓存中取出,而不是生成。
对于相同的x
, y
和seed
,您将始终获得相同的值(反过来可以用作细胞种子)。
TODO:找到一种方法使Rnd(x)
和Rnd(y)
没有LCG和低效的初始化(循环)。
我用这个解决了这个问题,在你们所有的建议之后。
void Drawmap(){
for (int x=0;x<complexity;x++){
for (int y=0;y<complexity;y++){
psuedoRandom = new System.Random((x+offsetx)*(y+offsety));
level[x,y]=psuedoRandom.Next (0,2);
}
}