private void MakeTunnels(Dictionary<string, XElement> provinceXml) { var todo = (from tunnel in provinceXml.Values where tunnel.Element("type").Value == "tunnel" || tunnel.Element("type").Value == "chamber" let routes = tunnel.Descendants("route") select new TempProvince { Id = tunnel.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), Up = GetDirection(routes, "Up"), Down = GetDirection(routes, "Down"), IsSeed = GetDirection(routes, "Up") != null }) .ToDictionary(k => k.Id); if (!todo.Any()) return; //starting points for each level var seeds = todo.Values.Where(t => t.IsSeed).Select(t => t.Id).ToArray(); var tunnelDict = new Dictionary<string, TempProvince>(todo); //first find all the connected sets, i.e. levels, per seed, i.e. tunnel where you first enter that level var connectedSetsPerSeed = new Dictionary<string, List<TempProvince>>(); // the set at index i contains the id of the sewer of the tunnels originating there. foreach (var seed in seeds) { var connected = new List<TempProvince>(); MakeConnectedSet(todo[seed], todo, connected); connectedSetsPerSeed.Add(seed, connected); } //now organize the connected sets according to the sewer they originate from (the string key), and level (index in the first list) var tunnelSets = new Dictionary<string, List<List<TempProvince>>>(); foreach (var seed in seeds.Where(s => new Regex(@"\w\d\d\d").IsMatch(tunnelDict[s].Up))) //get all the sewers - basically entry to level 0 { var levelsPerSewer = new List<List<TempProvince>>(); levelsPerSewer.Add(connectedSetsPerSeed[seed]); string nextDownId = seed; List<TempProvince> nextDown = null; while (FindLevelDown(connectedSetsPerSeed[nextDownId], out nextDownId) && connectedSetsPerSeed.TryGetValue(nextDownId, out nextDown)) { //ok, we've got the next set levelsPerSewer.Add(nextDown); } //levelsPerSewer is now filled up with levels from 0 -> n tunnelSets.Add(seed, levelsPerSewer); } //finally, lay them out per set left to right, level 0 -> n int startX = 0, startY = 0, bottomMost = 0; foreach (var sewer in tunnelSets.Keys) { foreach (var level in tunnelSets[sewer]) { var leftMost = level.Min(tp => tp.X); var topMost = level.Min(tp => tp.Y); foreach (var t in level) { t.X += (-leftMost + startX); t.Y += (-topMost + startY); } //put all disconnected parts next to one another for now var rightMost = level.Max(tp => tp.X); bottomMost = Math.Max(bottomMost, level.Max(tp => tp.Y)); startX = (rightMost + 2); } //wrap startX = 0; startY = bottomMost + 2; } //} var tunnels = tunnelDict.Values; var right = tunnels.Max(tp => tp.X); var bottom = tunnels.Max(tp => tp.Y); width = right + 1; height = bottom + 1; provinces = new Province[width * height]; for (int c = 0; c < width; c++) for (int r = 0; r < height; r++) { var found = tunnels.FirstOrDefault(tun => tun.X == c && tun.Y == r); if ((found != null)) { provinces[Index(r, c)] = MakeProvince(provinceXml, found.Id, r, c); } else { provinces[Index(r, c)] = new UndergroundProvince { Id = "", Name = "", Height = length, Width = length, X = c * length, Y = r * length }; } } }
private void MakeRegionKnownSize(Dictionary<string, XElement> provinceXml, string region, int xSize, int ySize) { // these are just the visited ones - for the neightboring ones we don't have a region. var todo = (from province in provinceXml.Values where province.Element("region").Value == region || province.Element("name").Value == region //second is for Hades let routes = province.Descendants("route") select new TempProvince { Id = province.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), IsSeed = province.Descendants("visit").Any() //we'll start to look from these preferentially, so that if a route is not bi //directional as in Hades, we start from the best explored provinces. Otherwise pieces mights show as disconnected that reallyl aren't }) .ToDictionary(k => k.Id); // now, for each of those provinces add the n,s,e,w routes that we know of var copy = new List<TempProvince>(todo.Values); foreach (var vis in copy) { if (vis.North != null && !todo.ContainsKey(vis.North)) { var province = provinceXml[vis.North]; var routes = province.Descendants("route"); todo.Add(vis.North, new TempProvince { Id = province.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), }); } if (vis.South != null && !todo.ContainsKey(vis.South)) { var province = provinceXml[vis.South]; var routes = province.Descendants("route"); todo.Add(vis.South,new TempProvince { Id = province.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), }); } if (vis.West != null && !todo.ContainsKey(vis.West)) { var province = provinceXml[vis.West]; var routes = province.Descendants("route"); todo.Add(vis.West,new TempProvince { Id = province.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), }); } if (vis.East != null && !todo.ContainsKey(vis.East)) { var province = provinceXml[vis.East]; var routes = province.Descendants("route"); todo.Add(vis.East,new TempProvince { Id = province.Element("id").Value, North = GetDirection(routes, "North"), South = GetDirection(routes, "South"), East = GetDirection(routes, "East"), West = GetDirection(routes, "West"), }); } } if (!todo.Any()) return; //starting points var seeds = todo.OrderBy(v => v.Value.IsSeed ? 0 : 1).Select( v => v.Key).ToArray(); //we want the seeds first var allFaery = new Dictionary<string, TempProvince>(todo); //first find all the connected provinces to the first seed, removing seeds var connectedSetsPerSeed = new Dictionary<string, List<TempProvince>>(); // the set at index i contains the id of the sewer of the tunnels originating there. //while (todo.Any()) foreach (var seed in seeds) { //var seed = todo.First().Key; if (todo.ContainsKey(seed)) { var connected = new List<TempProvince>(); MakeConnectedSet(todo[seed], todo, connected); connectedSetsPerSeed.Add(seed, connected); } } //finally, lay them out per set left to right, level 0 -> n int startX = 0, startY = 0, bottomMost = 0; foreach (var connectedSet in connectedSetsPerSeed.Values) { var leftMost = connectedSet.Min(tp => tp.X); var topMost = connectedSet.Min(tp => tp.Y); foreach (var t in connectedSet) { t.X += (-leftMost + startX); t.Y += (-topMost + startY); t.Y %= ySize; //faery is max 7 provinces high t.X %= xSize; } //put all disconnected parts next to one another for now var rightMost = connectedSet.Max(tp => tp.X); bottomMost = Math.Max(bottomMost, connectedSet.Max(tp => tp.Y)); startX = (rightMost + 2); //wrap //if (startX > 20) //{ // startX = 0; // startY = bottomMost + 2; //} } //} var faeryProvinces = allFaery.Values; var right = faeryProvinces.Max(tp => tp.X); var bottom = faeryProvinces.Max(tp => tp.Y); width = right + 1; height = bottom + 1; provinces = new Province[width * height]; for (int c = 0; c < width; c++) for (int r = 0; r < height; r++) { var found = faeryProvinces.FirstOrDefault(tun => tun.X == c && tun.Y == r); if ((found != null)) { provinces[Index(r, c)] = MakeProvince(provinceXml, found.Id, r, c); } else { provinces[Index(r, c)] = new UndergroundProvince { Id = "", Name = "", Height = length, Width = length, X = c * length, Y = r * length }; } } }