Skip to content

Instantly share code, notes, and snippets.

@itarato
Last active September 3, 2024 01:28
Show Gist options
  • Save itarato/0d6e65d538e42f559ada80decc0acc5f to your computer and use it in GitHub Desktop.
Save itarato/0d6e65d538e42f559ada80decc0acc5f to your computer and use it in GitHub Desktop.
Slider puzzle generator (crap)
using System;
using static Program.Generator;
class Program {
public class Generator {
public enum Orientation {
Vertical,
Horizontal,
}
public class Slider {
public int id;
public Orientation orientation;
public int len;
public int x;
public int y;
public int cachedMinBound = 0;
public int cachedMaxBound = 5;
public Slider(int id, Orientation orientation, int len, int x, int y) {
this.id = id;
this.orientation = orientation;
this.len = len;
this.x = x;
this.y = y;
}
public bool IsVertical() {
return orientation == Orientation.Vertical;
}
public (int, int)[] GetCoords() {
(int, int)[] coords = new (int, int)[len];
if (IsVertical()) {
for (int i = 0; i < len; i++) coords[i] = (5 - y - i, x);
} else {
for (int i = 0; i < len; i++) coords[i] = (5 - y, x + i);
}
return coords;
}
}
public void Generate(int sliderCount, int moveCount) {
if (sliderCount <= 0) throw new ArgumentException("Slider count must be greater than 1");
List<Slider> sliders = new List<Slider>();
// The exit slider (mandatory).
sliders.Add(new Slider(0, Orientation.Horizontal, 2, 4, 3));
int[,] memory = BuildMemoryForSliders(sliders);
Random rnd = new Random();
for (int id = 1; id <= sliderCount; id++) {
int len = rnd.Next(2, 4);
Orientation orientation = (rnd.Next(2) == 0) ? Orientation.Horizontal : Orientation.Vertical;
// Find all possible places for a `len` and `orientation`.
List<(int, int)> availableSlots = AvailableSlotsForLen(len, orientation, memory);
if (availableSlots.Count == 0) {
Console.WriteLine("Out of options. Cannot complete generation.");
return;
}
(int, int) pickedCoord = availableSlots[rnd.Next(availableSlots.Count)];
Slider newSlider = new Slider(id, orientation, len, pickedCoord.Item1, pickedCoord.Item2);
sliders.Add(newSlider);
RecordSliderFootprintOnMemory(newSlider, memory);
}
// Pre shuffle state.
DebugMemory(memory);
for (int _attempt = 0; _attempt < moveCount; _attempt++) {
int slideIdx = rnd.Next(sliders.Count);
List<(int, int)> availableMoves = AvailableMoveForSlider(sliders[slideIdx], memory);
if (availableMoves.Count == 0) continue;
Console.WriteLine("Moving {0} AvailableMoves {1}", slideIdx, availableMoves.Count);
// Update slider.
(int, int) selectedMove = availableMoves[rnd.Next(availableMoves.Count)];
sliders[slideIdx].x = selectedMove.Item1;
sliders[slideIdx].y = selectedMove.Item2;
// Refresh memory.
memory = BuildMemoryForSliders(sliders);
DebugMemory(memory);
}
}
private int[,] BuildMemoryForSliders(List<Slider> sliders) {
int[,] memory = new int[6, 6];
for (int i = 0; i < 6; i++) for (int j = 0; j < 6; j++) memory[i, j] = -1;
foreach (Slider slider in sliders) RecordSliderFootprintOnMemory(slider, memory);
return memory;
}
private void RecordSliderFootprintOnMemory(Slider slider, int[,] memory) {
foreach ((int, int)coord in slider.GetCoords()) {
if (memory[coord.Item1, coord.Item2] != -1) throw new ApplicationException("Occupied memory slot");
memory[coord.Item1, coord.Item2] = slider.id;
}
}
private List<(int, int)> AvailableSlotsForLen(int len, Orientation orientation, int[,] memory) {
List<(int, int)> coords = new List<(int, int)>();
if (orientation == Orientation.Vertical) {
for (int y = 6 - len; y >= 0; y--) {
for (int x = 0; x < 6; x++) {
bool failed = false;
for (int i = 0; i < len; i++) {
if (memory[5 - y - i, x] != -1) {
failed = true;
break;
}
}
if (!failed) coords.Add((x, y));
}
}
} else {
for (int y = 0; y < 6; y++) {
for (int x = 0; x <= 6 - len; x++) {
bool failed = false;
for (int i = 0; i < len; i++) {
if (memory[5 - y, x + i] != -1) {
failed = true;
break;
}
}
if (!failed) coords.Add((x, y));
}
}
}
return coords;
}
private List<(int, int)> AvailableMoveForSlider(Slider slider, int[,] memory) {
List<(int, int)> coords = new List<(int, int)> ();
if (slider.IsVertical()) {
// Min-side.
for (int i = slider.y - 1; i >= 0; i--) {
if (memory[5 - i, slider.x] == -1) {
coords.Add((slider.x, i));
} else break;
}
// Max-side.
for (int i = slider.y + 1; i + slider.len <= 6; i++) {
if (memory[5 - i - slider.len + 1, slider.x] == -1) {
coords.Add((slider.x, i));
} else break;
}
} else {
// Min-side.
for (int i = slider.x - 1; i >= 0; i--) {
if (memory[5 - slider.y, i] == -1) {
coords.Add((i, slider.y));
} else break;
}
// Max-side.
for (int i = slider.x + 1; i + slider.len <= 6; i++) {
if (memory[5 - slider.y, i + slider.len - 1] == -1) {
coords.Add((i, slider.y));
} else break;
}
}
return coords;
}
private static void DebugMemory(int[,] memory) {
Console.WriteLine(" 012345");
for (int i = 0; i < 6; i++) {
Console.Write("{0} ", 5 - i);
for (int j = 0; j < 6; j++) {
if (memory[i, j] == -1) {
Console.Write("\x1B[90m█\x1B[0m");
} else {
Console.Write("\x1B[{0}m█\x1B[0m", 97 - memory[i, j]);
}
}
Console.WriteLine();
}
}
}
public static void Main(string[] args) {
Generator generator = new Generator();
generator.Generate(6, 1000);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment