/*
* Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
* Copyright (C) 2021 cyoung06
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
package kr.syeyoung.dungeonsguide.roomprocessor.boxpuzzle;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.awt.*;
import java.util.*;
import java.util.List;
@Getter
@Setter
public class BoxPuzzleSolvingThread extends Thread {
private byte[][] data;
private int playerX;
private int playerY;
private Runnable callback;
public BoxPuzzleSolvingThread(byte[][] data, int playerX, int playerY, Runnable onDone) {
this.data = data;
this.playerX = playerX;
this.playerY = playerY;
this.callback = onDone;
}
Route solution = null;
private boolean solved = false;
@Override
public void run() {
solved = false;
solution = solve(data,playerX,playerY, 20);
solved = true;
callback.run();
}
public static String stateString(byte[][] array) {
StringBuilder sb = new StringBuilder();
for (int y = 0; y < array.length; y++)
for(int x = 0; x < array[y].length; x++)
sb.append(array[y][x]);
return sb.toString();
}
private static final List directions = Arrays.asList(new Point(-1,0), new Point(1,0), new Point(0,1), new Point(0,-1));
private static Route solve(byte[][] boardStart, int playerX, int playerY, int maxRecursion) { // result:: playerY == 0
Queue routes = new LinkedList();
Set globalStatesBeen = new HashSet();
Route r = new Route();
r.currentState = boardStart;
routes.add(r);
while (!routes.isEmpty()) {
Route route = routes.poll();
if (routes.size() > 3000000) return null;
String stateId = stateString(route.currentState);
if (maxRecursion < route.boxMoves.size()) continue;
if (globalStatesBeen.contains(stateId)) continue;
Queue points = new LinkedList();
Set reached= new HashSet();
List possibleBoxMoves = new ArrayList();
points.add(new Point(playerX, playerY));
while (!points.isEmpty()) {
Point pt = points.poll();
if (pt.y == 0) {
return route;
}
if (reached.contains(pt)) continue;
reached.add(pt);
for (Point dir:directions) {
int resX= pt.x + dir.x;
int resY = pt.y + dir.y;
if (resX < 0 || resY < 0 || resX >= route.currentState[0].length || resY >= route.currentState.length) {
continue;
}
if (route.currentState[resY][resX] > 0) {
possibleBoxMoves.add(new BoxMove(resX, resY, dir.x, dir.y));
continue;
}
points.add(new Point(resX, resY));
}
}
globalStatesBeen.add(stateId);
for (BoxMove possibleBoxMove : possibleBoxMoves) {
byte[][] copied = new byte[route.currentState.length][];
for (int y = 0; y < copied.length; y++)
copied[y] = route.currentState[y].clone();
if (push(copied, possibleBoxMove.x, possibleBoxMove.y, possibleBoxMove.dx, possibleBoxMove.dy)){
String stateId2 = stateString(copied);
if (globalStatesBeen.contains(stateId2)) continue;
Route route2 = new Route();
route2.boxMoves = new ArrayList(route.boxMoves);
route2.boxMoves.add(possibleBoxMove);
route2.currentState = copied;
routes.add(route2);
}
}
}
return null;
}
public static boolean push(byte[][] board, int x,int y,int dx,int dy) {
if (board[y][x] != 1) return false;
int resultingX= x + dx;
int resultingY = y +dy;
if (resultingX < 0 || resultingY < 0 || resultingX >= board[0].length || resultingY >= board.length) return false;
if (board[resultingY][resultingX] == 1 || resultingY == 6) return false;
board[resultingY][resultingX] = 1;
board[y][x] = 0;
return true;
}
public static class BoxMove {
int x;
int y;
int dx;
int dy;
public BoxMove(int x, int y, int dx, int dy) {
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getDx() {
return dx;
}
public int getDy() {
return dy;
}
}
public static class Route {
List boxMoves = new LinkedList();
byte[][] currentState;
}
}