Zamiel icon

boirlg_bot.linq

Zamiel | PRO | 09/04/18 04:52:38 PM UTC | 0 ⭐ | 401 👁️ | Never ⏰ | []
text |

19.83 KB

|

None

|

0 👍

/

0 👎

<Query Kind="Program">
  <Reference>&lt;RuntimeDirectory&gt;\System.Drawing.dll</Reference>
  <Namespace>System.Drawing</Namespace>
</Query>
 void Main()
{
	var roomDescs = new RoomsProvider();
	roomDescs.Load(@"C:\Users\Admin\Documents\isaac\levelgen\resources\rooms");
 	var bot1Total = new int[14];
	var bot2Total = new int[14];
	foreach (var fp in new DirectoryInfo(@"C:\Users\Admin\Documents\isaac\levelgen\dump2").GetFiles())
	{
		using (var file = File.OpenRead(fp.FullName))
		{
			Console.WriteLine(file.Name);
			var reader = new LayoutReader(file, roomDescs);
			StageBlock sb;
			while ((sb = reader.Read()) != null)
			{
				for (var i = 0; i < sb.Stages.Length; i++)
				{
					if (sb.Stages[i].StageId == 9 || sb.Stages[i].StageId == 12 || (sb.Stages[i].StageId == 10 && sb.Stages[i].StageType == 1) || (sb.Stages[i].StageId == 11 && sb.Stages[i].StageType == 1))
						continue;
					var seedStr = SeedToString(sb.Seed);
					//Console.WriteLine("{0} (Stage {1})", SeedToString(sb.Seed), sb.Stages[i].StageId);
					//Console.WriteLine("--------");
					Func<Room, string> roomToChar = (room) =>
						{
							if (room == null)
								return "O";
							if (room.StageIndex == 0 && room.RoomType == RoomType.ROOM_DEFAULT && room.RoomId == 2)
								return "S";
							if (room.RoomType == RoomType.ROOM_BOSS)
								return "B";
							return "X";
						};
					for (var y = 0; y < 13; y++)
					{
 						var line = string.Join("", Enumerable.Range(0, 13).Select(k => roomToChar(sb.Stages[i].RoomGrid[y][k])));
						//Console.WriteLine(line);
					}
 					var bot = new Bot1();
					bot.Start(sb.Stages[i]);
					do
					{
					} while (bot.Think());
					var bot2 = new Bot2();
					bot2.Start(sb.Stages[i]);
					do
					{
					} while (bot2.Think());
					//Console.WriteLine(bot.RoomsVisited);
					//Console.WriteLine(bot2.RoomsVisited);
					bot1Total[sb.Stages[i].StageId] += bot.RoomsVisited;
					bot2Total[sb.Stages[i].StageId] += bot2.RoomsVisited;
				}
			}
		}
	}
	bot1Total.Dump();
	bot2Total.Dump();
}
 public class RoomState
{
	public bool Visited = false;
	public bool Revealed = false;
	public Room Room;
}
public class BotState
{
	public Stage Stage;
	public Point Pos;
	public RoomState[][] GridState;
	public Room CurrentRoom { get { return GridState[Pos.Y][Pos.X].Room; }}
	public BotState(Stage stage)
	{
		Stage = stage;
		GridState = new RoomState[13][];
		for (var j = 0; j < GridState.Length; j++)
			GridState[j] = new RoomState[13];
 		var gridStateArr = new RoomState[Stage.Rooms.Length];
		for (var y = 0; y < 13; y++)
		{
			for (var x = 0; x < 13; x++)
			{
				var room = stage.RoomGrid[y][x];
				if (room == null)
				{
					GridState[y][x] = new RoomState();
					continue;
				}
 				var state = gridStateArr[room.RoomOffset] ?? new RoomState { Room = room};
				gridStateArr[room.RoomOffset] = state;
				GridState[y][x] = state;
			}
		}
	}
}
public abstract class Bot
{
	public BotState State;
	public Room[][] Grid { get { return State.Stage.RoomGrid; } }
	public RoomState[][] GridState { get { return State.GridState; } }
 	public Point GetStart()
	{
		for (var y = 0; y < 13; y++)
		{
			for (var x = 0; x < 13; x++)
			{
				var room = Grid[y][x];
				if (room == null)
					continue;
				if (room.StageIndex == 0 && room.RoomType == RoomType.ROOM_DEFAULT && room.RoomId == 2 //Standard start room
					|| ((room.StageIndex == 16 || room.StageIndex == 17) && room.RoomType == RoomType.ROOM_DEFAULT && room.RoomId == 0)) //Chest/DarkRoom start rooms
				{
					return new Point(x, y);
				}
			}
		}
		throw new Exception("Start room not found D:");
	}
	public Point GetEnd()
	{
		for (var y = 0; y < 13; y++)
		{
			for (var x = 0; x < 13; x++)
			{
				var room = Grid[y][x];
				if (room == null)
					continue;
				if (room.RoomType == RoomType.ROOM_BOSS)
				{
					return new Point(x, y);
				}
			}
		}
		throw new Exception("Boss room not found D:");
	}
 	public virtual void Start(Stage stage)
	{
		State = new BotState(stage);
		State.Pos = GetStart();
	}
	public abstract bool Think();
	public virtual void End()
	{
	}
 	public static bool InBounds(Point p)
	{
		return p.X >= 0 && p.Y >= 0 && p.X < 13 && p.Y < 13;
	}
 	//The points are using the top/left most grid x/y.
	#region shape doors
	public static Dictionary<RoomShape, Point[]> ShapeDoors = new Dictionary<UserQuery.RoomShape, System.Drawing.Point[]>
	{
		// U R D L, U R D L
		{RoomShape.ROOMSHAPE_1x1, new [] { new Point(0, -1),  new Point(1, 0),  new Point(0, 1),  new Point(-1, 0),     default(Point), default(Point), default(Point), default(Point) } },
		{RoomShape.ROOMSHAPE_1x2, new [] { new Point(0, -1),  new Point(1, 0),  new Point(0, 2),  new Point(-1, 0),     default(Point), new Point(1, 1), default(Point), new Point(-1, 1) } },
		{RoomShape.ROOMSHAPE_2x1, new [] { new Point(0, -1),  new Point(2, 0),  new Point(0, 1),  new Point(-1, 0),    new Point(1, -1), default(Point), new Point(1, 1), default(Point) } },
		{RoomShape.ROOMSHAPE_2x2, new [] { new Point(0, -1),  new Point(2, 0),  new Point(0, 2),  new Point(-1, 0),     new Point(1, -1), new Point(2, 1), new Point(1, 2), new Point(-1, 1)} },
		{RoomShape.ROOMSHAPE_IH,  new [] { default(Point), new Point(1, 0), default(Point), new Point(-1, 0) ,       default(Point), default(Point), default(Point), default(Point) } },
		{RoomShape.ROOMSHAPE_IIH, new [] { default(Point), new Point(2, 0), default(Point), new Point(-1, 0) ,        default(Point), default(Point), default(Point), default(Point) } },
		{RoomShape.ROOMSHAPE_IV, new [] { new Point(0, -1), default(Point),  new Point(0, 1), default(Point),        default(Point), default(Point), default(Point), default(Point) } },
		{RoomShape.ROOMSHAPE_IIV, new [] { new Point(0, -1), default(Point),  new Point(0, 2), default(Point),       default(Point), default(Point), default(Point), default(Point) } },
		{RoomShape.ROOMSHAPE_LTL, new [] { new Point(-1, 0), new Point(1, 0), new Point(-1, 2), new Point(-1, 0),     new Point(0, -1), new Point(1, 1), new Point(0, 2), new Point(-2, 1) } },
		{RoomShape.ROOMSHAPE_LTR, new [] { new Point(0, -1), new Point(1, 0), new Point(0, 2), new Point(-1, 0),     new Point(1, 0), new Point(2, 1), new Point(1, 2), new Point(-1, 1) } },
		{RoomShape.ROOMSHAPE_LBL, new [] { new Point(0, -1), new Point(2, 0), new Point(0, 1), new Point(-1, 0),     new Point(1, -1), new Point(2, 1), new Point(1, 2), new Point(0,-1) } },
		{RoomShape.ROOMSHAPE_LBR, new [] { new Point(0, -1), new Point(2, 0), new Point(0, 2), new Point(-1, 0),     new Point(1, -1), new Point(1, 1), new Point(1, 1), new Point(-1, 1) } },
	};
	#endregion
}
 public class Bot1 : Bot
{
	Stack<Point> Visited = new Stack<System.Drawing.Point>();
	public int RoomsVisited;
  	static RoomState[] exitRooms = new RoomState[8];
	#region weights
	static Dictionary<RoomShape, float> ShapeWeights = new Dictionary<UserQuery.RoomShape, float>
	{
		{RoomShape.ROOMSHAPE_1x1, 1},
		{RoomShape.ROOMSHAPE_1x2, 1.5f},
		{RoomShape.ROOMSHAPE_2x1, 1.5f},
		{RoomShape.ROOMSHAPE_2x2, 2},
		{RoomShape.ROOMSHAPE_IH, 1f},
		{RoomShape.ROOMSHAPE_IIH, 1.5f},
		{RoomShape.ROOMSHAPE_IIV, 1.5f},
		{RoomShape.ROOMSHAPE_IV, 1f},
		{RoomShape.ROOMSHAPE_LBL, 1.75f},
		{RoomShape.ROOMSHAPE_LBR, 1.75f},
		{RoomShape.ROOMSHAPE_LTL, 1.75f},
		{RoomShape.ROOMSHAPE_LTR, 1.75f},
	};
	#endregion
 	void RevealRooms()
	{
		//Revealing secret rooms is fine for now since we don't actually enter them.
		GridState[State.Pos.Y][State.Pos.X].Revealed = true;
		var exits = ShapeDoors[State.CurrentRoom.Shape];
		for (var i = 0; i < exits.Length; i++)
		{
			if (exits[i] == default(Point))
				continue;
 			var dstP = State.Pos.Add(exits[i]);
			if (!InBounds(dstP))
				continue;
 			var dstRoom = State.GridState[dstP.Y][dstP.X];
			dstRoom.Revealed = true;
		}
	}
	bool IsPossible(Point pos, HashSet<Point> visited)
	{
		var room = State.GridState[pos.Y][pos.X];
		if (!room.Revealed)
			return true;
		if (room.Revealed && room.Room == null)
			return false;
 		visited.Add(pos);
 		var exits = ShapeDoors[room.Room.Shape];
		for (var i = 0; i < exits.Length; i++)
		{
			if (exits[i] == default(Point))
				continue; 
 			var dstP = State.Pos.Add(exits[i]);
			if (!InBounds(dstP))
				continue;
 			if (visited.Contains(dstP))
				continue;
 			var dstRoom = State.GridState[dstP.Y][dstP.X];
			if (dstRoom.Revealed && dstRoom.Room != null && !IsPossible(dstP, visited))
				return false;
		}
		return true;
	}
 	Point ChooseNextRoom()
	{
		var exits = ShapeDoors[State.CurrentRoom.Shape];
		for (var i = 0; i < exits.Length; i++)
		{
			exitRooms[i] = null;
			if (exits[i] == default(Point))
				continue;
 			var dstP = State.Pos.Add(exits[i]);
			if (!InBounds(dstP))
				continue;
 			var dstRoom = State.GridState[dstP.Y][dstP.X];
			if (dstRoom.Visited || dstRoom.Room == null)
				continue;
 			if (dstRoom.Room.RoomType == RoomType.ROOM_BOSS)
				return dstP;
 			if (dstRoom.Room.RoomType != RoomType.ROOM_DEFAULT)
				continue;
 			if (!IsPossible(dstP, new HashSet<Point>()))
			{
				Func<RoomState, string> roomToChar = (room) =>
				{
					if (room == null || room.Room == null)
						return "O";
					return room.Visited ? "1" : "2";
				};
				for (var y = 0; y < 13; y++)
				{
 					var line = string.Join("", Enumerable.Range(0, 13).Select(k => roomToChar(this.GridState[y][k])));
					Console.WriteLine(line);
				}
				IsPossible(dstP, new HashSet<Point>());
				continue;
			}
 			exitRooms[i] = dstRoom;
		}
 		Array.Sort(exitRooms, (l, r) =>
		{
			if (l == null && r != null)
				return 1;
			if (r == null && l != null)
				return -1;
			if (l == null && r == null)
				return 0;
			return ShapeWeights[l.Room.Shape].CompareTo(ShapeWeights[r.Room.Shape]);
		});
 		return exitRooms[0] != null && exitRooms[0].Room != null ? new Point(exitRooms[0].Room.RoomX, exitRooms[0].Room.RoomY) : new Point(-1,-1);
	}
 	public override bool Think()
	{
		GridState[State.Pos.Y][State.Pos.X].Visited = true;
		RevealRooms();
 		var nextRoomPos = ChooseNextRoom();
		if (nextRoomPos.X == -1 && nextRoomPos.Y == -1)
		{
			if (Visited.Count < 1)
			{
				Func<RoomState, string> roomToChar = (room) =>
				{
					if (room == null || room.Room == null)
						return "O";
					return room.Visited ? "1" : "2";
				};
				for (var y = 0; y < 13; y++)
				{
 					var line = string.Join("", Enumerable.Range(0, 13).Select(k => roomToChar(this.GridState[y][k])));
					Console.WriteLine(line);
				}
				throw new Exception("Ran out of choices before finding the boss room");
			}
			State.Pos = Visited.Pop();
			return true;
		}
 		RoomsVisited++;
		var nextRoom = Grid[nextRoomPos.Y][nextRoomPos.X];
		var adjNextRoomPos = new Point(nextRoom.RoomX, nextRoom.RoomY);
		Visited.Push(State.Pos);
		State.Pos = adjNextRoomPos;		
 		if (State.CurrentRoom.RoomType == RoomType.ROOM_BOSS)
			return false;
		return true;
	}
}
public class Bot2 : Bot
{
	Stack<Point> Visited = new Stack<System.Drawing.Point>();
	public int RoomsVisited;
  	static RoomState[] exitRooms = new RoomState[8];
	#region weights
	static Dictionary<RoomShape, float> ShapeWeights = new Dictionary<UserQuery.RoomShape, float>
	{
		{RoomShape.ROOMSHAPE_1x1, 1},
		{RoomShape.ROOMSHAPE_1x2, 1.5f},
		{RoomShape.ROOMSHAPE_2x1, 1.5f},
		{RoomShape.ROOMSHAPE_2x2, 2},
		{RoomShape.ROOMSHAPE_IH, 1f},
		{RoomShape.ROOMSHAPE_IIH, 1.5f},
		{RoomShape.ROOMSHAPE_IIV, 1.5f},
		{RoomShape.ROOMSHAPE_IV, 1f},
		{RoomShape.ROOMSHAPE_LBL, 1.75f},
		{RoomShape.ROOMSHAPE_LBR, 1.75f},
		{RoomShape.ROOMSHAPE_LTL, 1.75f},
		{RoomShape.ROOMSHAPE_LTR, 1.75f},
	};
	#endregion
	Point ChooseNextRoom()
	{
		var exits = ShapeDoors[State.CurrentRoom.Shape];
		for (var i = 0; i < exits.Length; i++)
		{
			exitRooms[i] = null;
			if (exits[i] == default(Point))
				continue;
 			var dstP = State.Pos.Add(exits[i]);
			if (!InBounds(dstP))
				continue;
 			var dstRoom = State.GridState[dstP.Y][dstP.X];
			if (dstRoom.Visited || dstRoom.Room == null)
				continue;
 			if (dstRoom.Room.RoomType != RoomType.ROOM_DEFAULT && dstRoom.Room.RoomType != RoomType.ROOM_BOSS)
				continue;
 			exitRooms[i] = dstRoom;
		}
 		Array.Sort(exitRooms, (l, r) =>
		{
			if (l == null && r != null)
				return 1;
			if (r == null && l != null)
				return -1;
			if (l == null && r == null)
				return 0;
			if (l.Room == null && r.Room != null)
				return 1;
			if (r.Room == null && l.Room != null)
				return -1;
			return -ShapeWeights[l.Room.Shape].CompareTo(ShapeWeights[r.Room.Shape]);
		});
 		return exitRooms[0] != null && exitRooms[0].Room != null ? new Point(exitRooms[0].Room.RoomX, exitRooms[0].Room.RoomY) : new Point(-1, -1);
	}
 	public override bool Think()
	{
		GridState[State.Pos.Y][State.Pos.X].Visited = true;
 		var nextRoomPos = ChooseNextRoom();
		if (nextRoomPos.X == -1 && nextRoomPos.Y == -1)
		{
			if (Visited.Count < 1)
				throw new Exception("Ran out of choices before finding the boss room");
			State.Pos = Visited.Pop();
			return true;
		}
 		RoomsVisited++;
		var nextRoom = Grid[nextRoomPos.Y][nextRoomPos.X];
		var adjNextRoomPos = new Point(nextRoom.RoomX, nextRoom.RoomY);
		Visited.Push(State.Pos);
		State.Pos = adjNextRoomPos;
 		if (State.CurrentRoom.RoomType == RoomType.ROOM_BOSS)
			return false;
		return true;
	}
}
public static class PointExt
{
	public static Point Add(this Point l, Point r)
	{
		return new Point(l.X+r.X, l.Y + r.Y);
	}
}
 public class RoomDescriptor
{
	public RoomType RoomType;
	public int RoomId; //variant
	public int RoomSubType;
	public RoomShape RoomShape;
}
public class RoomsProvider
{
	public Dictionary<int, Dictionary<Tuple<RoomType, int>, RoomDescriptor>> StageRooms;
	public void Load(string path)
	{
		var xmlFiles = new DirectoryInfo(path).GetFiles("*.xml");
		StageRooms = new Dictionary<int, Dictionary<Tuple<RoomType, int>, RoomDescriptor>>();
		for (var i = 0; i < xmlFiles.Length; i++)
		{
			var stageIdx = int.Parse(Regex.Match(xmlFiles[i].Name, "^(\\d\\d)").Groups[1].Value);
			var doc = XDocument.Load(xmlFiles[i].FullName);
			var xmlRooms = doc.XPathSelectElements("//rooms/room").ToList();
 		    var rooms = new Dictionary<Tuple<RoomType, int>, RoomDescriptor>();
			for (var j = 0; j < xmlRooms.Count; j++)
			{
				var id = xmlRooms[j].Get<int>("variant");
				var type = (RoomType)xmlRooms[j].Get<int>("type");
				rooms[Tuple.Create(type, id)] = new RoomDescriptor
				{
					RoomType = type,
					RoomId = id,
		            RoomSubType = xmlRooms[j].Get<int>("subtype"),
		            RoomShape = (RoomShape)xmlRooms[j].Get<int>("shape")
				};
			}
			StageRooms[stageIdx] = rooms;
		}
 		StageRooms[3] = StageRooms[1];
		StageRooms[6] = StageRooms[4];
		StageRooms[9] = StageRooms[7];
		StageRooms[12] = StageRooms[10];
	}
}
 public class LayoutReader
{
	Stream stream;
	RoomsProvider RoomsProv;
	public LayoutReader(Stream s, RoomsProvider roomsProv)
	{
		stream = s;
		RoomsProv = roomsProv;
	}
 	public StageBlock Read()
	{
		if (stream.Position >= stream.Length)
			return null;
		var stages = new Stage[14];
		var seed = stream.ReadUInt32();
		for (var i = 0; i < 14; i++)
		{
			var stageId = stream.ReadInt8();
			var stageType = stream.ReadInt8();
			var roomCount = stream.ReadInt8();
			var gridCount = stream.ReadInt8();
			var grid = new Room[13][];
			for (var j = 0; j < grid.Length; j++)
				grid[j] = new Room[13];
 			var seedStr = SeedToString(seed);
 			var rooms = new Room[roomCount];
			for (var j = 0; j < gridCount; j++)
			{
				var sRoom = Room.ReadRoom(stream, RoomsProv);
				var room = rooms[sRoom.RoomOffset] ?? sRoom; //Have all of the grid parts of a room point to the same reference.
 				grid[sRoom.RoomY][sRoom.RoomX] = room;
				rooms[room.RoomOffset] = room;
			}
 			var iAmEror = Room.ReadNonGridRoom(stream, RoomsProv);
			var crawlSpace = Room.ReadNonGridRoom(stream, RoomsProv);
			var blackMarket = Room.ReadNonGridRoom(stream, RoomsProv);
			Room bossRush = null;
			if (stageId == 6)
				bossRush = Room.ReadNonGridRoom(stream, RoomsProv);
 			stages[i] = new Stage(stageId, stageType, grid, rooms);
		}
		return new StageBlock { Seed = seed, Stages = stages };
	}
 }
 public class Room
{
	public int StageIndex;
	public int RoomOffset;
	public int RoomX;
	public int RoomY;
	public RoomType RoomType;
	public int RoomSubType;
	public int RoomId;
	public RoomShape Shape;
	public static Room ReadRoom(Stream s, RoomsProvider prov)
	{
		var r = new Room
		{
			RoomOffset = s.ReadInt8(),
			RoomX = s.ReadInt8(),
			RoomY = s.ReadInt8(),
			StageIndex = s.ReadInt8(),
			RoomType = (RoomType)s.ReadInt8(),
			RoomSubType = s.ReadInt8(),
			RoomId = s.ReadInt16(),
		};
		r.Shape = prov.StageRooms[r.StageIndex][Tuple.Create(r.RoomType, r.RoomId)].RoomShape;
		return r;
	}
	public static Room ReadNonGridRoom(Stream s, RoomsProvider prov)
	{
		var r = new Room
		{
			RoomOffset = -1,
			RoomX = -1,
			RoomY = -1,
			StageIndex = s.ReadInt8(),
			RoomType = (RoomType)s.ReadInt8(),
			RoomSubType = s.ReadInt8(),
			RoomId = s.ReadInt16(),
		};
		r.Shape = prov.StageRooms[r.StageIndex][Tuple.Create(r.RoomType, r.RoomId)].RoomShape;
		return r;
	}
}
 public enum FloorType
{
	Special = 0,
	Basement = 1,
	Cellar = 2,
	BurningBasement = 3,
	Caves = 4,
	Catacombs = 5,
	FloodedCaves = 6,
	Depths = 7,
	Necropolis = 8,
	DankDepths = 9,
	Womb = 10,
	Utero = 11,
	ScarredWomb = 12,
	BlueWomb = 13,
	Sheol = 14,
	Cathedral = 15,
	DarkRoom = 16,
	Chest = 17,
}
  public enum RoomType
{
	ROOM_NULL = 0,
	ROOM_DEFAULT = 1,
	ROOM_SHOP = 2,
	ROOM_ERROR = 3,
	ROOM_TREASURE = 4,
	ROOM_BOSS = 5,
	ROOM_MINIBOSS = 6,
	ROOM_SECRET = 7,
	ROOM_SUPERSECRET = 8,
	ROOM_ARCADE = 9,
	ROOM_CURSE = 10,
	ROOM_CHALLENGE = 11,
	ROOM_LIBRARY = 12,
	ROOM_SACRIFICE = 13,
	ROOM_DEVIL = 14,
	ROOM_ANGEL = 15,
	ROOM_DUNGEON = 16,
	ROOM_BOSSRUSH = 17,
	ROOM_ISAACS = 18,
	ROOM_BARREN = 19,
	ROOM_CHEST = 20,
	ROOM_DICE = 21,
	ROOM_BLACK_MARKET = 22,
	ROOM_GREED_EXIT = 23,
	NUM_ROOMTYPES = 24
}
 public enum RoomShape
{
	ROOMSHAPE_NULL = 0,
	ROOMSHAPE_1x1 = 1,
	ROOMSHAPE_IH = 2,
	ROOMSHAPE_IV = 3,
	ROOMSHAPE_1x2 = 4,
	ROOMSHAPE_IIV = 5,
	ROOMSHAPE_2x1 = 6,
	ROOMSHAPE_IIH = 7,
	ROOMSHAPE_2x2 = 8,
	ROOMSHAPE_LTL = 9,
	ROOMSHAPE_LTR = 10,
	ROOMSHAPE_LBL = 11,
	ROOMSHAPE_LBR = 12,
	NUM_ROOMSHAPES = 13
}
 public class Stage
{
	public int StageId;
	public int StageType;
	public Room[][] RoomGrid;
	public Room[] Rooms;
 	public Stage(int stageId, int stageType, Room[][] grid, Room[] rooms)
	{
		StageId = stageId;
		StageType = stageType;
		RoomGrid = grid;
		Rooms = rooms;
	}
}
 public class StageBlock
{
	public uint Seed;
	public Stage[] Stages;
}
 enum Direction : int
{
	None = 0,
	North = 1,
	East = 2,
	South = 4,
	West = 8,
	NorthEast = North | East,
	NorthWest = North | West,
	SouthEast = South | East,
	SouthWest = South | West,
}
 // Define other methods and classes here
static string SeedToString(uint num)
{
	const string chars = "ABCDEFGHJKLMNPQRSTWXYZ01234V6789";
	byte x = 0;
	var tnum = num;
	while (tnum != 0)
	{
		x += ((byte)tnum);
		x += (byte)(x + (x >> 7));
		tnum >>= 5;
	}
	num ^= 0x0FEF7FFD;
	tnum = (num) << 8 | x;
 	var ret = new char[8];
	for (int i = 0; i < 6; i++)
	{
		ret[i] = chars[(int)(num >> (27 - (i * 5)) & 0x1F)];
	}
	ret[6] = chars[(int)(tnum >> 5 & 0x1F)];
	ret[7] = chars[(int)(tnum & 0x1F)];
 	return new string(ret);
}
 class Rng
{
    public uint seed;
	public int shift1;
	public int shift2;
	public int shift3;
	public uint next()
	{
		var num = seed;
		num ^= num >> shift1;
		num ^= num << shift2;
		num ^= num >> shift3;
		seed = num;
		return num;
	}
};

Comments