forked from logicchains/Levgen-Parallel-Benchmarks
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPC#.cs
210 lines (179 loc) · 5.97 KB
/
PC#.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
namespace Levgen
{
public enum TileType { Rock, Room }
public struct Tile
{
public TileType Type;
}
public class Room
{
public int X;
public int Y;
public int W;
public int H;
public bool Intersects(Room otherRoom)
{
var roomDoesntIntersect =
(X + W + 1) < otherRoom.X || X > (otherRoom.X + otherRoom.W + 1) ||
(Y + H + 1) < otherRoom.Y || Y > (otherRoom.Y + otherRoom.H + 1);
return !roomDoesntIntersect;
}
}
public class Level
{
private readonly List<Room> _rooms;
private readonly int _tileDim;
private readonly Tile[] _tiles;
public Level(int numRooms, int tileDim)
{
_tiles = new Tile[tileDim*tileDim];
_rooms = new List<Room>(numRooms);
_tileDim = tileDim;
}
public int NumberOfRooms
{
get { return _rooms.Count; }
}
static void GenerateTilesForRoom(Room room, Tile[] ts, int tileDim)
{
int x = room.X;
int y = room.Y;
int w = room.W;
int h = room.H;
for (int xi = x; xi <= x + w; xi++)
{
for (int yi = y; yi <= y + h; yi++)
{
int num = yi * tileDim + xi;
ts[num].Type = TileType.Room;
}
}
}
bool IntersectsExistingRooms(Room room)
{
// manual foreach is a lot faster than Any here
foreach (var r in _rooms)
{
if (r.Intersects(room))
return true;
}
return false;
}
public bool TryAddRoom(Room room)
{
if (!IntersectsExistingRooms(room))
{
_rooms.Add(room);
GenerateTilesForRoom(room, _tiles, _tileDim);
return true;
}
return false;
}
public override string ToString()
{
var tiles = _tiles;
var sb = new StringBuilder();
for (int i = 0; i < _tileDim*_tileDim; i++)
{
sb.Append(Convert.ToInt32(tiles[i].Type));
if (i % (_tileDim) == 49 && i != 0) sb.AppendLine();
}
return sb.ToString();
}
}
internal class GenRand
{
private uint _gen;
public GenRand(uint seed)
{
_gen = seed;
}
public int Next()
{
var gen = _gen;
gen += gen;
gen ^= 1;
if ((int)gen < 0)
{
gen ^= 0x88888eef;
}
_gen = gen;
return (int)gen;
}
}
public class LevelSettings
{
public LevelSettings(int maxRooms, int tileDim, int restWidMax, int widMin, int roomInsertionAttempts)
{
MaxRooms = maxRooms;
WidMin = widMin;
RoomInsertionAttempts = roomInsertionAttempts;
RestWidMax = restWidMax;
TileDim = tileDim;
}
public int TileDim { get; private set; }
public int RestWidMax { get; private set; }
public int WidMin { get; private set; }
public int RoomInsertionAttempts { get; private set; }
public int MaxRooms { get; private set; }
}
public class LevelMaker
{
private readonly GenRand _rand;
public LevelMaker(uint seed)
{
_rand = new GenRand(seed);
}
public IEnumerable<Level> MakeLevels(LevelSettings settings)
{
while(true)
{
var lev = new Level(settings.MaxRooms, settings.TileDim);
int roomCount = 0;
for (int attempt = 0; attempt < settings.RoomInsertionAttempts; attempt++)
{
var x = _rand.Next() % settings.TileDim;
var y = _rand.Next() % settings.TileDim;
var w = _rand.Next() % settings.RestWidMax + settings.WidMin;
var h = _rand.Next() % settings.RestWidMax + settings.WidMin;
if (x + w >= settings.TileDim || y + h >= settings.TileDim || x == 0 || y == 0) continue;
var room = new Room{X=x, Y=y, W=w, H=h};
if (lev.TryAddRoom(room))
{
if (++roomCount == settings.MaxRooms)
break;
}
}
yield return lev;
}
}
}
public static class Program
{
public static void Main(string[] args)
{
var sw = new Stopwatch();
sw.Start();
const int NumLevels = 800;
var numThreads = Environment.ProcessorCount;
var levelsPerThread = NumLevels / numThreads;
var seed = uint.Parse(args[0]);
Console.WriteLine("The random seed is: {0}", seed);
var levelSettings = new LevelSettings(maxRooms: 99, tileDim: 50, restWidMax: 8, widMin: 2, roomInsertionAttempts: 50000);
var levels = Enumerable.Range(0, numThreads).AsParallel().SelectMany(threadId =>
{
var threadSeed = (uint)(seed*(threadId + 1)*(threadId + 1));
Console.WriteLine("The seed for thread {0} is: {1}", threadId+1, threadSeed);
return new LevelMaker(threadSeed).MakeLevels(levelSettings).Take(levelsPerThread);
});
var bestLevel = levels.OrderByDescending(x => x.NumberOfRooms).First();
Console.WriteLine(bestLevel);
Console.WriteLine((int)Math.Round(sw.Elapsed.TotalMilliseconds));
}
}
}