/*
* 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.dungeon.roomfinder;
import kr.syeyoung.dungeonsguide.dungeon.data.DungeonRoomInfo;
import kr.syeyoung.dungeonsguide.utils.ArrayUtils;
import kr.syeyoung.dungeonsguide.utils.ShortUtils;
import lombok.Getter;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.util.BlockPos;
import net.minecraft.world.World;
import java.util.List;
public class RoomMatcher {
private final DungeonRoom dungeonRoom;
@Getter
private DungeonRoomInfo match;
@Getter
private int rotation; // how much the "found room" has to rotate clockwise to match the given dungeon room info. !
private boolean triedMatch = false;
private final World w;
public RoomMatcher(DungeonRoom dungeonRoom) {
this.dungeonRoom = dungeonRoom;
w = dungeonRoom.getContext().getWorld();
}
public DungeonRoomInfo match() {
if (triedMatch) return match;
int zz = dungeonRoom.getMax().getZ() - dungeonRoom.getMin().getZ() + 1;
int xx = dungeonRoom.getMax().getX() - dungeonRoom.getMin().getX() + 1;
for (int z = 0; z < zz; z ++) {
for (int x = 0; x < xx; x++) {
if (x % 8 == 0 && z % 8 == 0 && dungeonRoom.getContext().getWorld().getChunkFromBlockCoords(dungeonRoom.getRelativeBlockPosAt(x, 0, z)).isEmpty()) {
throw new IllegalStateException("chunk is not loaded");
}
}
}
triedMatch = true;
int lowestcost = 10;
int lowestRot = 0;
DungeonRoomInfo bestMatch = null;
for (int rotation = 0; rotation < 4; rotation++) {
short shape = dungeonRoom.getShape();
for (int j = 0; j roomInfoList = DungeonRoomInfoRegistry.getByShape(shape);
for (DungeonRoomInfo roomInfo : roomInfoList) {
int cost = tryMatching(roomInfo, rotation);
if (cost == 0) {
match = roomInfo;
this.rotation = rotation;
return match;
}
if (cost < lowestcost) {
lowestcost = cost;
bestMatch = roomInfo;
lowestRot = rotation;
}
}
}
match = bestMatch;
this.rotation = lowestRot;
return bestMatch;
}
private int tryMatching(DungeonRoomInfo dungeonRoomInfo, int rotation) {
if (dungeonRoomInfo.getColor() != dungeonRoom.getColor()) return Integer.MAX_VALUE;
int[][] res = dungeonRoomInfo.getBlocks();
for (int i = 0; i < rotation; i++)
res = ArrayUtils.rotateCounterClockwise(res);
int wrongs = 0;
for (int z = 0; z < res.length; z ++) {
for (int x = 0; x < res[0].length; x++) {
int data = res[z][x];
if (data == -1) continue;
Block b = dungeonRoom.getRelativeBlockAt(x,0,z);
if (b == null || Block.getIdFromBlock(b) != data) {
wrongs++;
if (wrongs > 10) return wrongs;
}
}
}
return wrongs;
}
private static final int offset = 3;
public DungeonRoomInfo createNew() {
DungeonRoomInfo roomInfo = new DungeonRoomInfo(dungeonRoom.getShape(), dungeonRoom.getColor());
int maxX = dungeonRoom.getMax().getX();
int maxZ = dungeonRoom.getMax().getZ();
int minX = dungeonRoom.getMin().getX();
int minZ = dungeonRoom.getMin().getZ();
int widthX = maxX - minX + 2;
int heightZ = maxZ - minZ + 2;
int[][] data = new int[dungeonRoom.getMax().getZ() - dungeonRoom.getMin().getZ() +2][dungeonRoom.getMax().getX() - dungeonRoom.getMin().getX() + 2];
for (int z = 0; z < data.length; z++) {
for (int x = 0; x < data[0].length; x++) {
// if (!(offset < x && widthX - offset > x && offset < z && heightZ - offset > z)) {
// data[z][x] = -1;
// continue;
// }
if (!(dungeonRoom.canAccessRelative(x + offset, z + offset)
&& dungeonRoom.canAccessRelative(x - offset -1 , z - offset-1)
&& dungeonRoom.canAccessRelative(x + offset , z - offset-1)
&& dungeonRoom.canAccessRelative(x - offset -1 , z + offset))) {
data[z][x] = -1;
continue;
}
Block b = dungeonRoom.getRelativeBlockAt(x,0,z);
if (b == null || b == Blocks.chest || b == Blocks.trapped_chest) {
data[z][x] = -1;
} else {
data[z][x] = Block.getIdFromBlock(b);
}
}
}
roomInfo.setBlocks(data);
roomInfo.setUserMade(true);
return roomInfo;
}
}