xabbo-scripts/ColorPuzzleSolver.csx
Administrator b6c31a7feb Add 165 scripts from desktop collection + update README
Added scripts from C:\Users\ploet\Desktop\Habbo\Xabbo Scripte:
- 39 KI/Chatbot scripts (ChatGPT, Gemini, Grok, DeepSeek, Ollama)
- Game solvers (Domino, Dodgeball, Obsidian Maze, IceBall)
- Collision avoidance bots (5 versions)
- Plant/breeding automation (12 scripts)
- Trading tools, packet debuggers, room utilities
- Navigation & teleport helpers

Removed: 9 files (3 empty, 2 trivial, 4 cross-duplicates)
Updated README with full categorized index of all 230+ scripts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 09:47:56 +01:00

513 lines
16 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
// ============================================================
// COLOR PUZZLE AUTO-SOLVER (Loopover 4x4)
// Layer-by-layer Ansatz: loest ALLE 4 Reihen zuverlaessig.
// Behaelt Anti-Desync + Auto-Flip-Erkennung bei.
// ============================================================
const int TILE_KIND = 3696;
const int ARROW_KIND = 17851;
const int GRID_X_MIN = 36;
const int GRID_X_MAX = 39;
const int GRID_Y_MIN = 27;
const int GRID_Y_MAX = 30;
const int CLICK_DELAY_MS = 950;
int GetState(dynamic item)
{
try { return int.Parse(item.State?.ToString() ?? "0"); }
catch { return 0; }
}
int GetKind(dynamic item)
{
try { return (int)item.Kind; }
catch { return -1; }
}
Log("=== Color Puzzle Auto-Solver (Layer-by-Layer) ===");
// ── 1. Read grid as array ─────────────────────────────────
int[,] ReadGridFromRoom()
{
int[,] g = new int[4, 4];
bool[,] found = new bool[4, 4];
foreach (var item in FloorItems)
{
if (item == null) continue;
if (GetKind(item) != TILE_KIND) continue;
int x = item.Location.X, y = item.Location.Y;
double z = item.Location.Z;
if (x < GRID_X_MIN || x > GRID_X_MAX) continue;
if (y < GRID_Y_MIN || y > GRID_Y_MAX) continue;
if (z < 18.4) continue;
g[y - GRID_Y_MIN, x - GRID_X_MIN] = GetState(item);
found[y - GRID_Y_MIN, x - GRID_X_MIN] = true;
}
int cnt = 0;
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
if (found[r, c]) cnt++;
if (cnt < 16) return null;
return g;
}
string GridDump(int[,] g)
{
return string.Join(" | ", Enumerable.Range(0, 4).Select(r =>
$"R{r}[{g[r,0]},{g[r,1]},{g[r,2]},{g[r,3]}]"));
}
var grid = ReadGridFromRoom();
if (grid == null)
{
Log("ERROR: Konnte Grid nicht lesen (nicht alle 16 Tiles gefunden).");
return;
}
Log($"Start: {GridDump(grid)}");
// ── 2. Read arrows ────────────────────────────────────────
var arrowIds = new Dictionary<string, long>();
foreach (var item in FloorItems)
{
if (item == null) continue;
if (GetKind(item) != ARROW_KIND) continue;
int x = item.Location.X, y = item.Location.Y;
if (y == GRID_Y_MIN - 1 && x >= GRID_X_MIN && x <= GRID_X_MAX)
arrowIds[$"up_{x - GRID_X_MIN}"] = item.Id;
else if (y == GRID_Y_MAX + 1 && x >= GRID_X_MIN && x <= GRID_X_MAX)
arrowIds[$"down_{x - GRID_X_MIN}"] = item.Id;
else if (x == GRID_X_MIN - 1 && y >= GRID_Y_MIN && y <= GRID_Y_MAX)
arrowIds[$"left_{y - GRID_Y_MIN}"] = item.Id;
else if (x == GRID_X_MAX + 1 && y >= GRID_Y_MIN && y <= GRID_Y_MAX)
arrowIds[$"right_{y - GRID_Y_MIN}"] = item.Id;
}
Log($"Pfeile: {arrowIds.Count}/16");
if (arrowIds.Count < 16) { Log("ERROR: Nicht alle Pfeile gefunden!"); return; }
// ── 3. Read target ────────────────────────────────────────
int[] targetRows = new int[4];
bool targetFound = false;
foreach (var item in FloorItems)
{
if (item == null) continue;
if (GetKind(item) != TILE_KIND) continue;
if (item.Location.X != 41) continue;
int y = item.Location.Y;
if (y < GRID_Y_MIN || y > GRID_Y_MAX) continue;
targetRows[y - GRID_Y_MIN] = GetState(item);
targetFound = true;
}
if (!targetFound) targetRows = new[] { 1, 2, 3, 0 };
Log($"Ziel: R0={targetRows[0]}, R1={targetRows[1]}, R2={targetRows[2]}, R3={targetRows[3]}");
// ── 4. Layer-by-Layer Solver ──────────────────────────────
// Move encoding: 0-3=RowLeft(0-3), 4-7=RowRight(0-3),
// 8-11=ColUp(0-3), 12-15=ColDown(0-3)
string MoveName(int m)
{
if (m < 4) return $"Row{m} LEFT";
if (m < 8) return $"Row{m-4} RIGHT";
if (m < 12) return $"Col{m-8} UP";
return $"Col{m-12} DOWN";
}
// Simulate a single move on a grid copy
void SimMove(int[,] g, int m)
{
if (m < 4) { // RowLeft
int r = m;
int t = g[r,0]; g[r,0]=g[r,1]; g[r,1]=g[r,2]; g[r,2]=g[r,3]; g[r,3]=t;
} else if (m < 8) { // RowRight
int r = m-4;
int t = g[r,3]; g[r,3]=g[r,2]; g[r,2]=g[r,1]; g[r,1]=g[r,0]; g[r,0]=t;
} else if (m < 12) { // ColUp
int c = m-8;
int t = g[0,c]; g[0,c]=g[1,c]; g[1,c]=g[2,c]; g[2,c]=g[3,c]; g[3,c]=t;
} else { // ColDown
int c = m-12;
int t = g[3,c]; g[3,c]=g[2,c]; g[2,c]=g[1,c]; g[1,c]=g[0,c]; g[0,c]=t;
}
}
List<int> SolveLayerByLayer(int[,] srcGrid, int[] tgtRows)
{
// Work on a copy
int[,] g = new int[4,4];
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
g[r,c] = srcGrid[r,c];
var moves = new List<int>();
void Do(int m) { moves.Add(m); SimMove(g, m); }
void DoRowRight(int r, int times) {
times = ((times % 4) + 4) % 4;
if (times == 3) { Do(r); return; } // 1x RowLeft is cheaper
for (int i = 0; i < times; i++) Do(r + 4);
}
void DoRowLeft(int r, int times) {
times = ((times % 4) + 4) % 4;
if (times == 3) { Do(r + 4); return; }
for (int i = 0; i < times; i++) Do(r);
}
void DoColUp(int c, int times) {
times = ((times % 4) + 4) % 4;
if (times == 3) { Do(c + 12); return; } // 1x ColDown is cheaper
for (int i = 0; i < times; i++) Do(c + 8);
}
void DoColDown(int c, int times) {
times = ((times % 4) + 4) % 4;
if (times == 3) { Do(c + 8); return; }
for (int i = 0; i < times; i++) Do(c + 12);
}
// ── Phase 1: Solve Row 0 ─────────────────────────────
// Use free column rotations + row shifts on rows 1-3.
int C0 = tgtRows[0];
for (int c = 0; c < 4; c++)
{
if (g[0,c] == C0) continue;
// Look in same column
int foundRow = -1;
for (int r = 1; r <= 3; r++)
if (g[r,c] == C0) { foundRow = r; break; }
if (foundRow >= 0)
{
DoColUp(c, foundRow);
}
else
{
// Find C0 anywhere in rows 1-3
bool found = false;
for (int r = 1; r <= 3 && !found; r++)
for (int c2 = 0; c2 < 4 && !found; c2++)
{
if (c2 == c) continue;
if (g[r,c2] == C0)
{
DoRowRight(r, (c - c2 + 4) % 4);
DoColUp(c, r);
found = true;
}
}
if (!found) return null; // should never happen
}
}
// ── Phase 2: Solve Row 1 (protecting Row 0) ──────────
// Commutator [RowLeft(1,k1), ColUp(c,k2), RowRight(1,k1), ColDown(c,k2)]
// creates a 3-cycle in rows 1+ only. Row 0 stays intact.
int C1 = tgtRows[1];
for (int pass = 0; pass < 4; pass++)
{
int colW = -1;
for (int c = 0; c < 4; c++)
if (g[1,c] != C1) { colW = c; break; }
if (colW < 0) break;
int srcR = -1, srcC = -1;
for (int r = 2; r <= 3 && srcR < 0; r++)
for (int c = 0; c < 4; c++)
if (g[r,c] == C1) { srcR = r; srcC = c; break; }
if (srcR < 0) return null;
// Move C1 to (srcR, colW) via row shift (safe: rows 2-3 only)
if (srcC != colW)
DoRowRight(srcR, (colW - srcC + 4) % 4);
int k2 = srcR - 1; // 1 or 2
DoRowLeft(1, 1);
DoColUp(colW, k2);
DoRowRight(1, 1);
DoColDown(colW, k2);
}
// ── Phase 3: Solve Rows 2-3 (protecting Rows 0-1) ───
// Commutator with r1=2, k2=1 only touches rows 2-3.
int C2 = tgtRows[2];
for (int pass = 0; pass < 4; pass++)
{
int colW = -1;
for (int c = 0; c < 4; c++)
if (g[2,c] != C2) { colW = c; break; }
if (colW < 0) break;
int srcC = -1;
for (int c = 0; c < 4; c++)
if (g[3,c] == C2) { srcC = c; break; }
if (srcC < 0) return null;
if (srcC != colW)
DoRowRight(3, (colW - srcC + 4) % 4);
DoRowLeft(2, 1);
DoColUp(colW, 1);
DoRowRight(2, 1);
DoColDown(colW, 1);
}
// Verify
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
if (g[r,c] != tgtRows[r]) return null;
// Optimize: remove consecutive inverse pairs
bool changed = true;
while (changed)
{
changed = false;
for (int i = 0; i < moves.Count - 1; i++)
{
int a = moves[i], b = moves[i+1];
bool cancel = false;
if (a < 4 && b == a + 4) cancel = true;
if (a >= 4 && a < 8 && b == a - 4) cancel = true;
if (a >= 8 && a < 12 && b == a + 4) cancel = true;
if (a >= 12 && b == a - 4) cancel = true;
if (cancel)
{
moves.RemoveAt(i + 1);
moves.RemoveAt(i);
changed = true;
break;
}
}
}
return moves;
}
// ── 5. Check if already solved ────────────────────────────
bool IsGridSolved(int[,] g)
{
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
if (g[r,c] != targetRows[r]) return false;
return true;
}
if (IsGridSolved(grid))
{
Log("Puzzle ist bereits geloest!");
return;
}
// ── 6. Solve ──────────────────────────────────────────────
var solution = SolveLayerByLayer(grid, targetRows);
if (solution == null || solution.Count == 0)
{
Log("ERROR: Solver konnte keine Loesung finden!");
Log("Moegliche Gruende: Farb-Verteilung nicht 4x je Farbe, oder falsche Ziel-Zuordnung.");
return;
}
Log($"Loesung gefunden: {solution.Count} Moves");
for (int i = 0; i < solution.Count; i++)
Log($" {i+1}. {MoveName(solution[i])}");
// ── 7. Execute with verification ──────────────────────────
// Track arrow direction flips (auto-detect reversed arrows)
bool[] rowFlip = new bool[4];
bool[] colFlip = new bool[4];
string KeyForMove(int m)
{
if (m < 4) {
int r = m;
return rowFlip[r] ? $"right_{r}" : $"left_{r}";
}
if (m < 8) {
int r = m - 4;
return rowFlip[r] ? $"left_{r}" : $"right_{r}";
}
if (m < 12) {
int c = m - 8;
return colFlip[c] ? $"down_{c}" : $"up_{c}";
}
int cc = m - 12;
return colFlip[cc] ? $"up_{cc}" : $"down_{cc}";
}
// Encode grid as uint for quick comparison
uint EncodeGrid(int[,] g)
{
uint s = 0;
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
s |= ((uint)(g[r,c] & 3)) << (2 * (r * 4 + c));
return s;
}
// Compute expected state after a move (using bit ops for speed)
uint ApplyMoveBits(uint s, int m)
{
if (m < 4) { // RowLeft
int sh = m * 8;
uint row = (s >> sh) & 0xFFu;
uint rot = ((row >> 2) | (row << 6)) & 0xFFu;
return (s & ~(0xFFu << sh)) | (rot << sh);
}
if (m < 8) { // RowRight
int sh = (m-4) * 8;
uint row = (s >> sh) & 0xFFu;
uint rot = ((row << 2) | (row >> 6)) & 0xFFu;
return (s & ~(0xFFu << sh)) | (rot << sh);
}
if (m < 12) { // ColUp
int b = (m-8) * 2;
uint v0=(s>>b)&3u, v1=(s>>(b+8))&3u, v2=(s>>(b+16))&3u, v3=(s>>(b+24))&3u;
uint mask = ~(3u<<b | 3u<<(b+8) | 3u<<(b+16) | 3u<<(b+24));
return (s&mask) | (v1<<b) | (v2<<(b+8)) | (v3<<(b+16)) | (v0<<(b+24));
}
{ // ColDown
int b = (m-12) * 2;
uint v0=(s>>b)&3u, v1=(s>>(b+8))&3u, v2=(s>>(b+16))&3u, v3=(s>>(b+24))&3u;
uint mask = ~(3u<<b | 3u<<(b+8) | 3u<<(b+16) | 3u<<(b+24));
return (s&mask) | (v3<<b) | (v0<<(b+8)) | (v1<<(b+16)) | (v2<<(b+24));
}
}
int InverseMove(int m)
{
if (m < 4) return m + 4;
if (m < 8) return m - 4;
if (m < 12) return m + 4;
return m - 4;
}
Log("\nFuehre Moves aus...");
uint currentState = EncodeGrid(grid);
uint goalState = EncodeGrid(new int[4,4]); // temp
{
int[,] tgt = new int[4,4];
for (int r = 0; r < 4; r++)
for (int c = 0; c < 4; c++)
tgt[r,c] = targetRows[r];
goalState = EncodeGrid(tgt);
}
int moveIdx = 0;
int retries = 0;
const int MAX_RETRIES = 3;
while (moveIdx < solution.Count)
{
if (currentState == goalState)
{
Log("=== Puzzle geloest! Alle 4 Reihen korrekt! ===");
return;
}
int move = solution[moveIdx];
uint expected = ApplyMoveBits(currentState, move);
string key = KeyForMove(move);
if (!arrowIds.ContainsKey(key))
{
Log($"ERROR: Arrow '{key}' nicht gefunden!");
return;
}
long id = arrowIds[key];
Log($" [{moveIdx+1}/{solution.Count}] {MoveName(move)} via {key}");
Send(Out["ClickFurni"], (int)id, 0);
Delay(CLICK_DELAY_MS);
// Re-read grid to verify
var newGrid = ReadGridFromRoom();
if (newGrid == null)
{
Log("WARN: Grid-Read fehlgeschlagen, retry...");
Delay(400);
continue;
}
uint afterState = EncodeGrid(newGrid);
if (afterState == expected)
{
// Move worked as expected
currentState = afterState;
moveIdx++;
retries = 0;
continue;
}
// Check if arrow direction was reversed
uint invExpected = ApplyMoveBits(currentState, InverseMove(move));
if (afterState == invExpected)
{
if (move < 8) {
int r = move < 4 ? move : move - 4;
rowFlip[r] = !rowFlip[r];
Log($" Auto-Fix: Row {r} Richtung gespiegelt.");
} else {
int c = move < 12 ? move - 8 : move - 12;
colFlip[c] = !colFlip[c];
Log($" Auto-Fix: Col {c} Richtung gespiegelt.");
}
currentState = afterState;
// Don't advance moveIdx - the move did the opposite, re-plan
Log(" Re-plane von neuem Zustand...");
grid = newGrid;
solution = SolveLayerByLayer(grid, targetRows);
if (solution == null) { Log("ERROR: Re-Plan fehlgeschlagen!"); return; }
moveIdx = 0;
retries = 0;
Log($" Neuer Plan: {solution.Count} Moves");
continue;
}
if (afterState == currentState)
{
// Click had no effect
retries++;
if (retries >= MAX_RETRIES)
{
Log("WARN: Klick ohne Effekt nach 3 Versuchen, re-plane...");
grid = newGrid;
solution = SolveLayerByLayer(grid, targetRows);
if (solution == null) { Log("ERROR: Re-Plan fehlgeschlagen!"); return; }
moveIdx = 0;
retries = 0;
}
else
{
Log(" Klick ohne Effekt, retry...");
Delay(300);
}
continue;
}
// Desync: grid changed unexpectedly (maybe another player or lag)
Log($" Desync! Neuer Zustand: {GridDump(newGrid)}");
Log(" Re-plane von neuem Zustand...");
grid = newGrid;
currentState = afterState;
if (IsGridSolved(grid))
{
Log("=== Puzzle geloest! Alle 4 Reihen korrekt! ===");
return;
}
solution = SolveLayerByLayer(grid, targetRows);
if (solution == null) { Log("ERROR: Re-Plan fehlgeschlagen!"); return; }
moveIdx = 0;
retries = 0;
Log($" Neuer Plan: {solution.Count} Moves");
}
if (currentState == goalState)
Log("=== Puzzle geloest! Alle 4 Reihen korrekt! ===");
else
Log("Alle Moves ausgefuehrt. Grid pruefen ob geloest.");