Skip to content

Commit

Permalink
Improve the algorithm for removing Islam from the map (#1672)
Browse files Browse the repository at this point in the history
  • Loading branch information
IhateTrains authored Dec 31, 2023
1 parent c48d721 commit b0e204f
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 23 deletions.
8 changes: 4 additions & 4 deletions ImperatorToCK3.UnitTests/CK3/Map/MapDataTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Xunit;

namespace ImperatorToCK3.UnitTests.CK3.Map;
Expand All @@ -15,8 +16,8 @@ public void NeighborsDictDefaultsToEmpty() {
const string ck3Root = "TestFiles/MapData/CK3_1_province_map/game";
var ck3ModFS = new ModFilesystem(ck3Root, new List<Mod>());
var data = new MapData(ck3ModFS);

Assert.Empty(data.NeighborsDict);
new ulong[] { 0, 1, 2, 3 }.ToList().ForEach(id => Assert.Empty(data.GetNeighborProvinceIds(id)));
}

[Fact]
Expand All @@ -27,9 +28,8 @@ public void NeighborProvincesCanBeDetermined() {
var ck3ModFS = new ModFilesystem(ck3Root, new List<Mod>());
var data = new MapData(ck3ModFS);
Assert.True(data.ProvinceDefinitions.ProvinceToColorDict.ContainsKey(byzantionId));
Assert.True(data.NeighborsDict.ContainsKey(byzantionId));

var byzantionNeighborProvs = data.NeighborsDict[byzantionId];
var byzantionNeighborProvs = data.GetNeighborProvinceIds(byzantionId);
var expectedByzantionNeighborProvs = new HashSet<ulong> {
3761, // Selymbria
8668, // sea_bosporus
Expand Down
23 changes: 21 additions & 2 deletions ImperatorToCK3/CK3/Map/MapData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public override int GetHashCode() {
}
}

public SortedDictionary<ulong, HashSet<ulong>> NeighborsDict { get; } = new();
private SortedDictionary<ulong, HashSet<ulong>> NeighborsDict { get; } = [];
public ISet<ulong> ColorableImpassableProvinces { get; } = new HashSet<ulong>();
public IDictionary<ulong, ProvincePosition> ProvincePositions { get; } = new Dictionary<ulong, ProvincePosition>();
public ProvinceDefinitions ProvinceDefinitions { get; }
Expand Down Expand Up @@ -62,6 +62,25 @@ public MapData(ModFilesystem ck3ModFS) {
FindImpassables(ck3ModFS);
Logger.IncrementProgress();
}

public double GetDistanceBetweenProvinces(ulong province1, ulong province2) {
if (!ProvincePositions.TryGetValue(province1, out var province1Position)) {
Logger.Warn($"Province {province1} has no position defined!");
return 0;
}
if (!ProvincePositions.TryGetValue(province2, out var province2Position)) {
Logger.Warn($"Province {province2} has no position defined!");
return 0;
}

var xDiff = province1Position.X - province2Position.X;
var yDiff = province1Position.Y - province2Position.Y;
return Math.Sqrt(xDiff * xDiff + yDiff * yDiff);
}

public IReadOnlySet<ulong> GetNeighborProvinceIds(ulong provinceId) {
return NeighborsDict.TryGetValue(provinceId, out var neighbors) ? neighbors : [];
}

private void DetermineProvincePositions(ModFilesystem ck3ModFS) {
const string provincePositionsPath = "gfx/map/map_object_data/building_locators.txt";
Expand Down Expand Up @@ -206,7 +225,7 @@ private void AddNeighbor(ulong mainProvince, ulong neighborProvince) {
if (NeighborsDict.TryGetValue(mainProvince, out var neighbors)) {
neighbors.Add(neighborProvince);
} else {
NeighborsDict[mainProvince] = new HashSet<ulong> {neighborProvince};
NeighborsDict[mainProvince] = [neighborProvince];
}
}
}
7 changes: 7 additions & 0 deletions ImperatorToCK3/CK3/Provinces/ProvinceHistory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ public partial class Province {
_ => null
};
}

public void SetFaithIdAndOverrideExistingEntries(string faithId) {
var faithHistoryField = History.Fields["faith"];
faithHistoryField.RemoveAllEntries();
faithHistoryField.AddEntryToHistory(null, "faith", faithId);
}

public void SetFaithId(string faithId, Date? date) {
History.AddFieldValue(date, "faith", "faith", faithId);
}
Expand Down
84 changes: 72 additions & 12 deletions ImperatorToCK3/CK3/World.cs
Original file line number Diff line number Diff line change
Expand Up @@ -637,37 +637,97 @@ private void RemoveIslam(Configuration config) {
new("world_africa_west", "berber_pagan"),
new("world_africa_east", "waaqism_pagan"),
new("world_africa_sahara", "berber_pagan"),
new("world_africa", "berber_pagan"), // fallback
new("world_africa", "pagan"), // fallback
new("world_africa", "berber_pagan"),
// Rest of the world
new("world_europe", "arabic_pagan"),
new("world_asia_minor", "arabic_pagan"),
new("world_middle_east", "arabic_pagan"),
new("world_india", "arabic_pagan"),
new("world_steppe", "arabic_pagan"),
new("world_tibet", "arabic_pagan"),
new("world_burma", "arabic_pagan"),
}.Where(kvp => Religions.GetFaith(kvp.Value) is not null);

foreach (var (regionId, faithId) in regionToNewFaithMap) {
var regionProvinces = muslimProvinces
.Where(p => ck3RegionMapper.ProvinceIsInRegion(p.Id, regionId));
foreach (var province in regionProvinces) {
var faithHistoryField = province.History.Fields["faith"];
faithHistoryField.RemoveAllEntries();
faithHistoryField.AddEntryToHistory(null, "faith", faithId);

province.SetFaithIdAndOverrideExistingEntries(faithId);
muslimProvinces.Remove(province);
}
}

UseNeighborProvincesToRemoveIslam(muslimProvinces, date);
UseClosestProvincesToRemoveIslam(muslimProvinces, date);
UseFallbackNonMuslimFaithToRemoveIslam(muslimProvinces, muslimFaiths);

// Log warning if there are still muslim provinces left.
if (muslimProvinces.Count > 0) {
Logger.Warn($"{muslimProvinces.Count} muslim provinces left after removing Islam: " +
$"{string.Join(", ", muslimProvinces.Select(p => p.Id))}");
}
}

private void UseFallbackNonMuslimFaithToRemoveIslam(HashSet<Province> muslimProvinces, IdObjectCollection<string, Faith> muslimFaiths) {
if (muslimProvinces.Count <= 0) {
return;
}

var fallbackFaith = Religions.Faiths.Except(muslimFaiths).FirstOrDefault();
if (fallbackFaith is not null) {
foreach (var province in muslimProvinces.ToList()) {
Logger.Debug($"Using fallback faith \"{fallbackFaith.Id}\" for province {province.Id}");
province.SetFaithIdAndOverrideExistingEntries(fallbackFaith.Id);
muslimProvinces.Remove(province);
}
}
}

private void UseClosestProvincesToRemoveIslam(HashSet<Province> muslimProvinces, Date date) {
if (muslimProvinces.Count <= 0) {
return;
}

var provincesWithValidFaith = Provinces
.Except(muslimProvinces)
.Where(p => p.GetFaithId(date) is not null)
.ToHashSet();
foreach (var province in muslimProvinces) {
var closestValidProvince = provincesWithValidFaith
.Except(muslimProvinces)
.Select(p => new {
Province = p,
Distance = MapData.GetDistanceBetweenProvinces(province.Id, p.Id),
})
.Where(x => x.Distance > 0)
.MinBy(x => x.Distance)?.Province;
if (closestValidProvince is null) {
continue;
}

var faithId = closestValidProvince.GetFaithId(date)!;
Logger.Debug($"Using faith \"{faithId}\" of closest province for province {province.Id}");
province.SetFaithIdAndOverrideExistingEntries(faithId);
muslimProvinces.Remove(province);
}
}

private void UseNeighborProvincesToRemoveIslam(HashSet<Province> muslimProvinces, Date date) {
foreach (var province in muslimProvinces) {
var neighborIds = MapData.GetNeighborProvinceIds(province.Id);
if (neighborIds.Count == 0) {
continue;
}

var neighborFaithId = Provinces
.Except(muslimProvinces)
.Where(p => neighborIds.Contains(p.Id))
.Select(p => p.GetFaithId(date))
.FirstOrDefault(f => f is not null);
if (neighborFaithId is null) {
continue;
}

Logger.Debug($"Using neighbor's faith \"{neighborFaithId}\" for province {province.Id}.");
province.SetFaithIdAndOverrideExistingEntries(neighborFaithId);
muslimProvinces.Remove(province);
}
}

private void GenerateFillerHoldersForUnownedLands(CultureCollection cultures, Configuration config) {
Logger.Info("Generating filler holders for unowned lands...");
var date = config.CK3BookmarkDate;
Expand Down
8 changes: 3 additions & 5 deletions ImperatorToCK3/Outputter/BookmarkOutputter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,9 @@ private static void DrawBookmarkMap(Configuration config, List<Title> playerTitl
var provincesToColor = new HashSet<ulong>(heldProvinces);
var impassables = mapData.ColorableImpassableProvinces;
foreach (var impassableId in impassables) {
if (!mapData.NeighborsDict.TryGetValue(impassableId, out var neighborProvs)) {
continue;
}

var nonImpassableNeighborProvs = new HashSet<ulong>(neighborProvs.Except(impassables));
var nonImpassableNeighborProvs = mapData.GetNeighborProvinceIds(impassableId)
.Except(impassables)
.ToHashSet();
if (nonImpassableNeighborProvs.Count == 0) {
continue;
}
Expand Down

0 comments on commit b0e204f

Please sign in to comment.