生成地下城,包含房间和迷宫通路。类似:




public struct Vec2
{
public int x;
public int y;
public Vec2(int x, int y)
{
this.x = x;
this.y = y;
}
public static Vec2 Zero
{
get
{
return new Vec2(0, 0);
}
}
public override bool Equals(object obj)
{
if (!(obj is Vec2))
return false;
var o = (Vec2)obj;
return x == o.x && y == o.y;
}
public override int GetHashCode()
{
return x.GetHashCode() + y.GetHashCode();
}
public static Vec2 operator+ (Vec2 a, Vec2 b)
{
return new Vec2(a.x + b.x, a.y + b.y);
}
public static Vec2 operator* (Vec2 a, int n)
{
return new Vec2(a.x * n, a.y * n);
}
public static Vec2 operator* (int n, Vec2 a)
{
return new Vec2(a.x * n, a.y * n);
}
public static bool operator== (Vec2 a, Vec2 b)
{
return a.x == b.x && a.y == b.y;
}
public static bool operator !=(Vec2 a, Vec2 b)
{
return !(a.x == b.x && a.y == b.y);
}
}
public struct Region
{
public int id;
public List<Vec2> positions;
public Region(int id)
{
this.id = id;
positions = new List<Vec2>();
}
}
struct Room
{
public Rect rect;
public List<Vec2> borders;
public Room(int x, int y, int w, int h)
{
rect = new Rect(x, y, w, h);
borders = new List<Vec2>();
for (int i = x; i <= x + w; i++)
for (int j = y; j <= y + h; j++)
if (!(i > x && x < x + w && j > y && j < y + h))
borders.Add(new Vec2(i, j));
}
}
struct Context
{
public Vec2 size;
public int roomCnt;
public int windingPct;
public int roomSizeOff;
public int[,] map;
public List<Region> regions;
public List<Room> rooms;
public int regionIDIdx;
}
public enum EDir
{
Up = 0,
Down = 1,
Left = 2,
Right = 3,
}
static Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>
{
{EDir.Up, new Vec2(0, 1) },
{EDir.Down, new Vec2(0, -1) },
{EDir.Left, new Vec2(-1, 0) },
{EDir.Right, new Vec2(1, 0) },
};
Context context;
public void Init(int w, int h, int roomCnt, int windingPct, int roomSizeOff)
{
int x = w - w % 2 - 2 - 1;
int y = h - h % 2 - 2 - 1;
context = new Context()
{
size = new Vec2(x, y),
roomCnt = roomCnt,
windingPct = windingPct,
roomSizeOff = roomSizeOff,
map = new int[x, y],
regions = new List<Region>(),
rooms = new List<Room>(),
regionIDIdx = -1,
};
}
void GenRooms()
{
for (int i = 0; i < context.roomCnt;)
{
var size = R.Range(1, 3 + context.roomSizeOff) * 2 + 1;
var off = R.Range(0, 1 + size / 2) * 2;
var w = size;
var h = size;
if (R.Range(0, 2) > 0)
w += off;
else
h += off;
var x = R.Range(0, (context.size.x - w) / 2) * 2 ;
var y = R.Range(0, (context.size.y - h) / 2) * 2 ;
var rect = new Rect(x, y, w, h);
bool isOverlap = false;
foreach (var room in context.rooms)
if (rect.Overlaps(room.rect))
{
isOverlap = true;
break;
}
if (isOverlap)
continue;
++i;
GrowRegion();
for (int m = x; m < x + w; m++)
for (int n = y; n < y + h; n++)
Carve(m, n);
context.rooms.Add(new Room(x, y, w, h));
}
}
void GenMaze()
{
foreach (var room in context.rooms)
foreach (var pos in room.borders)
if (pos.x % 2 == 0 && pos.y % 2 == 0)
GrowMaze(pos);
}
void GrowMaze(Vec2 pos)
{
Vec2 forward = Vec2.Zero;
var stack = new Stack<Vec2>();
stack.Push(pos);
GrowRegion();
bool isStart = true;
while (stack.Count > 0)
{
var p = stack.Pop();
List<Vec2> dirs = new List<Vec2>();
foreach (var pair in dirDict)
{
var dir = pair.Value;
if (CanMazeGrow(p, dir))
dirs.Add(dir);
}
if (dirs.Count > 0)
{
if (!(dirs.Contains(forward) && R.Range(0, 100) < context.windingPct))
forward = dirs[R.Range(0, dirs.Count)];
if (isStart)
isStart = false;
else
Carve(p + forward);
Carve(p + 2 * forward);
stack.Push(p + 2 * forward);
}
else
forward = Vec2.Zero;
}
TryShrinkRegion();
}
bool CanMazeGrow(Vec2 pos, Vec2 dir)
{
return CanCarve(pos + dir) && CanCarve(pos + 2 * dir);
}
bool CanCarve(Vec2 pos)
{
return CanCarve(pos.x, pos.y);
}
bool CanCarve(int x, int y)
{
return InMap(x, y) && context.map[x, y] == 0;
}
bool InMap(Vec2 pos)
{
return InMap(pos.x, pos.y);
}
bool InMap(int x, int y)
{
var size = context.size;
return x >= 0 && x < size.x && y >= 0 && y < size.y;
}
void Carve(Vec2 pos, int ty = 1)
{
Carve(pos.x, pos.y, ty);
}
void Carve(int x, int y, int ty = 1)
{
context.map[x, y] = ty;
context.regions[context.regionIDIdx].positions.Add(new Vec2(x, y));
}
void Connect()
{
for (int i = 0; i < context.rooms.Count; i++)
{
context.regions[i].positions.Clear();
foreach (var pos in context.rooms[i].borders)
context.regions[i].positions.Add(pos);
}
Dictionary<int, Region> dict = new Dictionary<int, Region>();
for (int i = 0; i < context.regions.Count; i++)
dict[i] = context.regions[i];
var idxs = new List<int>();
while (dict.Count > 1)
{
idxs.Clear();
foreach (var pair in dict)
idxs.Add(pair.Key);
var dest = idxs[idxs.Count - 1];
idxs.RemoveAt(idxs.Count - 1);
bool isMerge = false;
foreach (var idx in idxs)
{
var connectPos = Vec2.Zero;
if (TryConnectRegion(dict[dest], dict[idx], out connectPos))
{
GrowRegion();
dict[context.regionIDIdx] = context.regions[context.regionIDIdx];
foreach (var pos in dict[dest].positions)
dict[context.regionIDIdx].positions.Add(pos);
foreach (var pos in dict[idx].positions)
dict[context.regionIDIdx].positions.Add(pos);
Carve(connectPos);
dict.Remove(dest);
dict.Remove(idx);
isMerge = true;
break;
}
}
if (!isMerge)
{
Debug.Log("Region Merge Failed!");
return;
}
}
}
bool TryConnectRegion(Region a, Region b, out Vec2 connectPos)
{
for (int i = 0; i < a.positions.Count; i++)
{
var ap = a.positions[i];
if (ap.x % 2 == 0 && ap.y % 2 == 0)
for (int j = 0; j < b.positions.Count; j++)
{
var bp = b.positions[j];
if (bp.x % 2 == 0 && bp.y % 2 == 0)
if (ap.y == bp.y)
{
if (ap.x - bp.x == 2)
{
connectPos = ap + new Vec2(-1, 0);
return true;
}
if (ap.x - bp.x == -2)
{
connectPos = ap + new Vec2(1, 0);
return true;
}
}
else if (ap.x == bp.x)
{
if (ap.y - bp.y == 2)
{
connectPos = ap + new Vec2(0, -1);
return true;
}
if (ap.y - bp.y == -2)
{
connectPos = ap + new Vec2(0, 1);
return true;
}
}
}
}
connectPos = Vec2.Zero;
return false;
}
void CutMaze()
{
var region = context.regions[context.regionIDIdx];
List<Vec2> dirs = new List<Vec2>();
foreach (var pos in region.positions)
CutMazeArrangement(pos);
}
void CutMazeArrangement(Vec2 pos)
{
if (context.map[pos.x, pos.y] == 0)
return;
List<Vec2> dirs = new List<Vec2>();
foreach (var pair in dirDict)
{
var dir = pair.Value;
var test = pos + dir;
if (!InMap(test))
continue;
if (context.map[test.x, test.y] == 1)
dirs.Add(test);
}
if (dirs.Count == 1)
{
context.map[pos.x, pos.y] = 0;
CutMazeArrangement(dirs[0]);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using R = UnityEngine.Random;
public struct Vec2
{
public int x;
public int y;
public Vec2(int x, int y)
{
this.x = x;
this.y = y;
}
public static Vec2 Zero
{
get
{
return new Vec2(0, 0);
}
}
public override bool Equals(object obj)
{
if (!(obj is Vec2))
return false;
var o = (Vec2)obj;
return x == o.x && y == o.y;
}
public override int GetHashCode()
{
return x.GetHashCode() + y.GetHashCode();
}
public static Vec2 operator+ (Vec2 a, Vec2 b)
{
return new Vec2(a.x + b.x, a.y + b.y);
}
public static Vec2 operator* (Vec2 a, int n)
{
return new Vec2(a.x * n, a.y * n);
}
public static Vec2 operator* (int n, Vec2 a)
{
return new Vec2(a.x * n, a.y * n);
}
public static bool operator== (Vec2 a, Vec2 b)
{
return a.x == b.x && a.y == b.y;
}
public static bool operator !=(Vec2 a, Vec2 b)
{
return !(a.x == b.x && a.y == b.y);
}
}
public enum EDir
{
Up = 0,
Down = 1,
Left = 2,
Right = 3,
}
public class DungeonBuild
{
public struct Region
{
public int id;
public List<Vec2> positions;
public Region(int id)
{
this.id = id;
positions = new List<Vec2>();
}
}
struct Room
{
public Rect rect;
public List<Vec2> borders;
public Room(int x, int y, int w, int h)
{
rect = new Rect(x, y, w, h);
borders = new List<Vec2>();
for (int i = x; i <= x + w; i++)
for (int j = y; j <= y + h; j++)
if (!(i > x && x < x + w && j > y && j < y + h))
borders.Add(new Vec2(i, j));
}
}
struct Context
{
public Vec2 size;
public int roomCnt;
public int windingPct;
public int roomSizeOff;
public int[,] map;
public List<Region> regions;
public List<Room> rooms;
public int regionIDIdx;
}
static Dictionary<EDir, Vec2> dirDict = new Dictionary<EDir, Vec2>
{
{EDir.Up, new Vec2(0, 1) },
{EDir.Down, new Vec2(0, -1) },
{EDir.Left, new Vec2(-1, 0) },
{EDir.Right, new Vec2(1, 0) },
};
Context context;
public void Init(int w, int h, int roomCnt, int windingPct, int roomSizeOff)
{
int x = w - w % 2 - 2 - 1;
int y = h - h % 2 - 2 - 1;
context = new Context()
{
size = new Vec2(x, y),
roomCnt = roomCnt,
windingPct = windingPct,
roomSizeOff = roomSizeOff,
map = new int[x, y],
regions = new List<Region>(),
rooms = new List<Room>(),
regionIDIdx = -1,
};
}
public void Build()
{
GenRooms();
GenMaze();
Connect();
CutMaze();
}
public int[,] GetResult()
{
return context.map;
}
public Vector2 GetSize()
{
return new Vector2(context.size.x, context.size.y);
}
void GrowRegion()
{
context.regionIDIdx++;
context.regions.Add(new Region(context.regionIDIdx));
}
void TryShrinkRegion()
{
if (context.regions[context.regionIDIdx].positions.Count == 0)
{
context.regions.RemoveAt(context.regionIDIdx);
context.regionIDIdx--;
}
}
void GenRooms()
{
for (int i = 0; i < context.roomCnt;)
{
var size = R.Range(1, 3 + context.roomSizeOff) * 2 + 1;
var off = R.Range(0, 1 + size / 2) * 2;
var w = size;
var h = size;
if (R.Range(0, 2) > 0)
w += off;
else
h += off;
var x = R.Range(0, (context.size.x - w) / 2) * 2 ;
var y = R.Range(0, (context.size.y - h) / 2) * 2 ;
var rect = new Rect(x, y, w, h);
bool isOverlap = false;
foreach (var room in context.rooms)
if (rect.Overlaps(room.rect))
{
isOverlap = true;
break;
}
if (isOverlap)
continue;
++i;
GrowRegion();
for (int m = x; m < x + w; m++)
for (int n = y; n < y + h; n++)
Carve(m, n);
context.rooms.Add(new Room(x, y, w, h));
}
}
void GenMaze()
{
foreach (var room in context.rooms)
foreach (var pos in room.borders)
if (pos.x % 2 == 0 && pos.y % 2 == 0)
GrowMaze(pos);
}
void GrowMaze(Vec2 pos)
{
Vec2 forward = Vec2.Zero;
var stack = new Stack<Vec2>();
stack.Push(pos);
GrowRegion();
bool isStart = true;
while (stack.Count > 0)
{
var p = stack.Pop();
List<Vec2> dirs = new List<Vec2>();
foreach (var pair in dirDict)
{
var dir = pair.Value;
if (CanMazeGrow(p, dir))
dirs.Add(dir);
}
if (dirs.Count > 0)
{
if (!(dirs.Contains(forward) && R.Range(0, 100) < context.windingPct))
forward = dirs[R.Range(0, dirs.Count)];
if (isStart)
isStart = false;
else
Carve(p + forward);
Carve(p + 2 * forward);
stack.Push(p + 2 * forward);
}
else
forward = Vec2.Zero;
}
TryShrinkRegion();
}
void Connect()
{
for (int i = 0; i < context.rooms.Count; i++)
{
context.regions[i].positions.Clear();
foreach (var pos in context.rooms[i].borders)
context.regions[i].positions.Add(pos);
}
Dictionary<int, Region> dict = new Dictionary<int, Region>();
for (int i = 0; i < context.regions.Count; i++)
dict[i] = context.regions[i];
var idxs = new List<int>();
while (dict.Count > 1)
{
idxs.Clear();
foreach (var pair in dict)
idxs.Add(pair.Key);
var dest = idxs[idxs.Count - 1];
idxs.RemoveAt(idxs.Count - 1);
bool isMerge = false;
foreach (var idx in idxs)
{
var connectPos = Vec2.Zero;
if (TryConnectRegion(dict[dest], dict[idx], out connectPos))
{
GrowRegion();
dict[context.regionIDIdx] = context.regions[context.regionIDIdx];
foreach (var pos in dict[dest].positions)
dict[context.regionIDIdx].positions.Add(pos);
foreach (var pos in dict[idx].positions)
dict[context.regionIDIdx].positions.Add(pos);
Carve(connectPos);
dict.Remove(dest);
dict.Remove(idx);
isMerge = true;
break;
}
}
if (!isMerge)
{
Debug.Log("Region Merge Failed!");
return;
}
}
}
bool TryConnectRegion(Region a, Region b, out Vec2 connectPos)
{
for (int i = 0; i < a.positions.Count; i++)
{
var ap = a.positions[i];
if (ap.x % 2 == 0 && ap.y % 2 == 0)
for (int j = 0; j < b.positions.Count; j++)
{
var bp = b.positions[j];
if (bp.x % 2 == 0 && bp.y % 2 == 0)
if (ap.y == bp.y)
{
if (ap.x - bp.x == 2)
{
connectPos = ap + new Vec2(-1, 0);
return true;
}
if (ap.x - bp.x == -2)
{
connectPos = ap + new Vec2(1, 0);
return true;
}
}
else if (ap.x == bp.x)
{
if (ap.y - bp.y == 2)
{
connectPos = ap + new Vec2(0, -1);
return true;
}
if (ap.y - bp.y == -2)
{
connectPos = ap + new Vec2(0, 1);
return true;
}
}
}
}
connectPos = Vec2.Zero;
return false;
}
void CutMaze()
{
var region = context.regions[context.regionIDIdx];
List<Vec2> dirs = new List<Vec2>();
foreach (var pos in region.positions)
CutMazeArrangement(pos);
}
void CutMazeArrangement(Vec2 pos)
{
if (context.map[pos.x, pos.y] == 0)
return;
List<Vec2> dirs = new List<Vec2>();
foreach (var pair in dirDict)
{
var dir = pair.Value;
var test = pos + dir;
if (!InMap(test))
continue;
if (context.map[test.x, test.y] == 1)
dirs.Add(test);
}
if (dirs.Count == 1)
{
context.map[pos.x, pos.y] = 0;
CutMazeArrangement(dirs[0]);
}
}
bool CanMazeGrow(Vec2 pos, Vec2 dir)
{
return CanCarve(pos + dir) && CanCarve(pos + 2 * dir);
}
bool CanCarve(Vec2 pos)
{
return CanCarve(pos.x, pos.y);
}
bool CanCarve(int x, int y)
{
return InMap(x, y) && context.map[x, y] == 0;
}
bool InMap(Vec2 pos)
{
return InMap(pos.x, pos.y);
}
bool InMap(int x, int y)
{
var size = context.size;
return x >= 0 && x < size.x && y >= 0 && y < size.y;
}
void Carve(Vec2 pos, int ty = 1)
{
Carve(pos.x, pos.y, ty);
}
void Carve(int x, int y, int ty = 1)
{
context.map[x, y] = ty;
context.regions[context.regionIDIdx].positions.Add(new Vec2(x, y));
}
}
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我是Rails的新手,所以请原谅简单的问题。我正在为一家公司创建一个网站。那家公司想在网站上展示它的客户。我想让客户自己管理这个。我正在为“客户”生成一个表格,我想要的三列是:公司名称、公司描述和Logo。对于名称,我使用的是name:string但不确定如何在脚本/生成脚手架终端命令中最好地创建描述列(因为我打算将其设置为文本区域)和图片。我怀疑描述(我想成为一个文本区域)应该仍然是描述:字符串,然后以实际形式进行调整。不确定如何处理图片字段。那么……说来话长:我在脚手架命令中输入什么来生成描述和图片列? 最佳答案 对于“文本”数
我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些
有这些railscast。http://railscasts.com/episodes/218-making-generators-in-rails-3有了这个,你就会知道如何创建样式表和脚手架生成器。http://railscasts.com/episodes/216-generators-in-rails-3通过这个,您可以了解如何添加一些文件来修改脚手架View。我想把两者结合起来。我想创建一个生成器,它也可以创建脚手架View。有点像RyanBates漂亮的生成器或web_app_themegem(https://github.com/pilu/web-app-theme)。我
导读语言模型给我们的生产生活带来了极大便利,但同时不少人也利用他们从事作弊工作。如何规避这些难辨真伪的文字所产生的负面影响也成为一大难题。在3月9日智源Live第33期活动「DetectGPT:判断文本是否为机器生成的工具」中,主讲人Eric为我们讲解了DetectGPT工作背后的思路——一种基于概率曲率检测的用于检测模型生成文本的工具,它可以帮助我们更好地分辨文章的来源和可信度,对保护信息真实、防止欺诈等方面具有重要意义。本次报告主要围绕其功能,实现和效果等展开。(文末点击“阅读原文”,查看活动回放。)Ericmitchell斯坦福大学计算机系四年级博士生,由ChelseaFinn和Chri
目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非
我使用的第一个解析器生成器是Parse::RecDescent,它的指南/教程很棒,但它最有用的功能是它的调试工具,特别是tracing功能(通过将$RD_TRACE设置为1来激活)。我正在寻找可以帮助您调试其规则的解析器生成器。问题是,它必须用python或ruby编写,并且具有详细模式/跟踪模式或非常有用的调试技术。有人知道这样的解析器生成器吗?编辑:当我说调试时,我并不是指调试python或ruby。我指的是调试解析器生成器,查看它在每一步都在做什么,查看它正在读取的每个字符,它试图匹配的规则。希望你明白这一点。赏金编辑:要赢得赏金,请展示一个解析器生成器框架,并说明它的
我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te