diff --git a/.gitignore b/.gitignore
index eed4580..a0e76a3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ obj/
*.user
output/
+source/old/
diff --git a/README.md b/README.md
index 3998d65..6c62158 100644
--- a/README.md
+++ b/README.md
@@ -221,6 +221,7 @@ Sources of examples:
1. [SokobanLevel1](models/SokobanLevel1.xml) seems to be the first level from Hiroyuki Imabayashi's Sokoban puzzle. [SokobanLevel2](models/SokobanLevel2.xml) is the [level 452](https://www.sokobanonline.com/play/web-archive/razorflame/ionic-catalysts-xi/58022_ionic-catalysts-xi-452) from Ionic Catalysts XI set.
1. [RainbowGrowth](models/RainbowGrowth.xml) was [proposed](https://github.com/mxgmn/MarkovJunior/discussions/25) by [mure](https://github.com/mure).
1. [MultiHeadedWalk](models/MultiHeadedWalk.xml), [MultiHeadedDungeon](models/MultiHeadedDungeon.xml) and [MultiHeadedWalkDungeon](models/MultiHeadedWalkDungeon.xml) are [based](https://github.com/mxgmn/MarkovJunior/discussions/38) on the idea by [Ilya Kudritsky](https://github.com/Inferdy).
+1. [Island](models/Island.xml) model is by [Guillaume Fiette](https://github.com/woldendans/MJ-simple-island).
Voxel scenes were rendered in [MagicaVoxel](https://ephtracy.github.io/) by [ephtracy](https://github.com/ephtracy). Special thanks to [Brian Bucklew](https://github.com/unormal) for demonstrating the power of Dijkstra fields to me in roguelike level generation and [Kevin Chapelier](https://github.com/kchapelier) for a number of good suggestions. The font used in GUI is [Tamzen](https://github.com/sunaku/tamzen-font).
diff --git a/models.xml b/models.xml
index b383cd8..6335562 100644
--- a/models.xml
+++ b/models.xml
@@ -7,6 +7,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/models/Island.xml b/models/Island.xml
new file mode 100644
index 0000000..3060c53
--- /dev/null
+++ b/models/Island.xml
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/models/MultiHeadedWalk.xml b/models/MultiHeadedWalk.xml
index c8c3c61..96c481d 100644
--- a/models/MultiHeadedWalk.xml
+++ b/models/MultiHeadedWalk.xml
@@ -1,7 +1,7 @@
-
+
-
+
diff --git a/resources/palette.xml b/resources/palette.xml
index 5c57b31..16e679c 100644
--- a/resources/palette.xml
+++ b/resources/palette.xml
@@ -1,56 +1,56 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/source/Map.cs b/source/Map.cs
index 6b05fb2..93eb705 100644
--- a/source/Map.cs
+++ b/source/Map.cs
@@ -38,7 +38,7 @@ override protected bool Load(XElement xelem, bool[] parentSymmetry, Grid grid)
(NY, DY) = readScale(scales[1]);
(NZ, DZ) = readScale(scales[2]);
- newgrid = Grid.Load(xelem, NX * grid.MX / DX, NY * grid.MY / DY, NZ * grid.MZ / DZ);
+ newgrid = Grid.Load(xelem, grid.MX * NX / DX, grid.MY * NY / DY, grid.MZ * NZ / DZ);
if (newgrid == null) return false;
if (!base.Load(xelem, parentSymmetry, newgrid)) return false;
diff --git a/source/Program.cs b/source/Program.cs
index ef951e8..957d760 100644
--- a/source/Program.cs
+++ b/source/Program.cs
@@ -54,17 +54,20 @@ static void Main()
int gui = xmodel.Get("gui", 0);
if (gif) amount = 1;
+ Dictionary customPalette = new(palette);
+ foreach (var x in xmodel.Elements("color")) customPalette[x.Get("symbol")] = (255 << 24) + Convert.ToInt32(x.Get("value"), 16);
+
for (int k = 0; k < amount; k++)
{
int seed = seeds != null && k < seeds.Length ? seeds[k] : meta.Next();
foreach ((byte[] result, char[] legend, int FX, int FY, int FZ) in interpreter.Run(seed, steps, gif))
{
- int[] colors = legend.Select(ch => palette[ch]).ToArray();
+ int[] colors = legend.Select(ch => customPalette[ch]).ToArray();
string outputname = gif ? $"output/{interpreter.counter}" : $"output/{name}_{seed}";
if (FZ == 1 || iso)
{
var (bitmap, WIDTH, HEIGHT) = Graphics.Render(result, FX, FY, FZ, colors, pixelsize, gui);
- if (gui > 0) GUI.Draw(name, interpreter.root, interpreter.current, bitmap, WIDTH, HEIGHT, palette);
+ if (gui > 0) GUI.Draw(name, interpreter.root, interpreter.current, bitmap, WIDTH, HEIGHT, customPalette);
Graphics.SaveBitmap(bitmap, WIDTH, HEIGHT, outputname + ".png");
}
else VoxHelper.SaveVox(result, (byte)FX, (byte)FY, (byte)FZ, colors, outputname + ".vox");
diff --git a/source/RuleNode.cs b/source/RuleNode.cs
index 51e63e0..4641bf6 100644
--- a/source/RuleNode.cs
+++ b/source/RuleNode.cs
@@ -66,7 +66,16 @@ override protected bool Load(XElement xelem, bool[] parentSymmetry, Grid grid)
if (xfields.Any())
{
fields = new Field[grid.C];
- foreach (XElement xfield in xfields) fields[grid.values[xfield.Get("for")]] = new Field(xfield, grid);
+ foreach (XElement xfield in xfields)
+ {
+ char c = xfield.Get("for");
+ if (grid.values.TryGetValue(c, out byte value)) fields[value] = new Field(xfield, grid);
+ else
+ {
+ Interpreter.WriteLine($"unknown field value {c} at line {xfield.LineNumber()}");
+ return false;
+ }
+ }
potentials = AH.Array2D(grid.C, grid.state.Length, 0);
}
diff --git a/syntax.md b/syntax.md
index 2926ddd..32b3552 100644
--- a/syntax.md
+++ b/syntax.md
@@ -58,7 +58,7 @@ If search is set false, the interpreter can be made to follow the goal more stri
1. Integer `limit` attribute sets the maximum number of states searched. By default, the number of states is not limited.
2. Floating point `depthCoefficient` attribute [interpolates](https://github.com/mxgmn/MarkovJunior/blob/4e64162f00203f5b5753af100af0dab8d72ce805/source/Search.cs#L269) between breadth-first search and depth-first search.
-See examples of inference use in [MultiSokoban9](models/MultiSokoban9.xml), [SokobanLevel1](models/SokobanLevel1.xml), [StairsPath](models/StairsPath.xml), [KnightPatrol](models/KnightPatrol.xml), [CrossCountry](models/CrossCountry.xml), [RegularPath](models/RegularPath.xml), [DiagonalPath](models/DiagonalPath.xml), [EuclideanPath](models/EuclideanPath.xml), [BishopParity](models/BishopParity.xml), [SnellLaw](models/SnellLaw.xml), [SequentialSokoban](models/SequentialSokoban.xml), [CompleteSAW](models/CompleteSAW.xml), [CompleteSAWSmart](models/CompleteSAWSmart.xml).
+See examples of inference use in [MultiSokoban9](models/MultiSokoban9.xml), [SokobanLevel1](models/SokobanLevel1.xml), [StairsPath](models/StairsPath.xml), [KnightPatrol](models/KnightPatrol.xml), [CrossCountry](models/CrossCountry.xml), [RegularPath](models/RegularPath.xml), [DiagonalPath](models/DiagonalPath.xml), [EuclideanPath](models/EuclideanPath.xml), [BishopParity](models/BishopParity.xml), [SnellLaw](models/SnellLaw.xml), [SequentialSokoban](models/SequentialSokoban.xml), [CompleteSAW](models/CompleteSAW.xml), [CompleteSAWSmart](models/CompleteSAWSmart.xml), [Island](models/Island.xml).
@@ -91,4 +91,4 @@ See examples of `convchain` node use in [ChainMaze](models/ChainMaze.xml), [Chai
## Questions and Answers
**Q:** How to make a loop? How to make a sequence repeat?
-**A:** To make a sequence repeat, put a `sequence` node inside a `markov` node. Examples of this: [HamiltonianPath](models/HamiltonianPath.xml), [SelectLargeCaves](models/SelectLargeCaves.xml), [SelectLongKnots](models/SelectLongKnots.xml), [FireNoise](models/FireNoise.xml), [SmartSAW](models/SmartSAW.xml), [FindLongCycle](models/FindLongCycle.xml). Counters in markov/sequence nodes are not supported right now. Instead, you may want to repeat the sequence until some node is matched.
+**A:** To make a sequence repeat, put a `sequence` node inside a `markov` node or inside another `sequence` node. Examples of this: [MultiHeadedWalk](models/MultiHeadedWalk.xml), [HamiltonianPath](models/HamiltonianPath.xml), [SelectLargeCaves](models/SelectLargeCaves.xml), [SelectLongKnots](models/SelectLongKnots.xml), [FireNoise](models/FireNoise.xml), [SmartSAW](models/SmartSAW.xml), [FindLongCycle](models/FindLongCycle.xml). Counters in markov/sequence nodes are not supported right now. Instead, you may want to repeat the sequence until some node is matched.