Fix encoding and decoding
This commit is contained in:
parent
598902ef33
commit
22bb2d16d2
2 changed files with 83 additions and 27 deletions
|
@ -10,6 +10,7 @@ import eu.m724.tweaks.DebugLogger;
|
|||
import eu.m724.tweaks.module.wordcoords.WordList;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class Decoder {
|
||||
private final WordList wordList;
|
||||
|
@ -33,6 +34,8 @@ public class Decoder {
|
|||
}
|
||||
|
||||
public int[] decode(int[] wordIndexes) {
|
||||
DebugLogger.finer("Decoding word indexes: %s", Arrays.toString(wordIndexes));
|
||||
|
||||
int bitsRequired = wordIndexes.length * wordList.getBitsPerWord();
|
||||
int bitsRequiredPerCoordinate = bitsRequired / 2;
|
||||
DebugLogger.finer("Bits required: %d (per coord: %d)", bitsRequired, bitsRequiredPerCoordinate);
|
||||
|
@ -43,23 +46,26 @@ public class Decoder {
|
|||
|
||||
|
||||
int[] decodedCoords = decodeCoords(combinedValue, bitsRequiredPerCoordinate);
|
||||
int xCoord = decodedCoords[0];
|
||||
int zCoord = decodedCoords[1];
|
||||
DebugLogger.info("Chunk: %d, %d", xCoord, zCoord);
|
||||
int chunkX = decodedCoords[0];
|
||||
int chunkZ = decodedCoords[1];
|
||||
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
||||
|
||||
return new int[] { xCoord * 16 + 8, zCoord * 16 + 8 }; // +8 to make it center of chunk
|
||||
// +8 to make it center of chunk
|
||||
int xCoord = chunkX * 16 + 8;
|
||||
int zCoord = chunkZ * 16 + 8;
|
||||
DebugLogger.finer("Decoded to coordinates: %d, %d", xCoord, zCoord);
|
||||
|
||||
return new int[] { xCoord, zCoord };
|
||||
}
|
||||
|
||||
private long wordIndexesToCombinedValue(int[] wordIndexes) {
|
||||
long combinedValue = 0;
|
||||
|
||||
for (int i=0; i<wordIndexes.length; i++) {
|
||||
combinedValue |= wordIndexes[i];
|
||||
combinedValue <<= bitsPerWord;
|
||||
combinedValue |= wordIndexes[i];
|
||||
}
|
||||
|
||||
combinedValue >>= bitsPerWord;
|
||||
|
||||
return combinedValue;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ package eu.m724.tweaks.module.wordcoords.converter;
|
|||
|
||||
import eu.m724.tweaks.DebugLogger;
|
||||
import eu.m724.tweaks.module.wordcoords.WordList;
|
||||
|
||||
import java.util.Arrays;
|
||||
public class Encoder {
|
||||
private final WordList wordList;
|
||||
private final int bitsPerWord;
|
||||
|
@ -19,40 +19,90 @@ public class Encoder {
|
|||
}
|
||||
|
||||
public String[] encode(int xCoord, int zCoord) {
|
||||
xCoord = Math.floorDiv(xCoord, 16);
|
||||
zCoord = Math.floorDiv(zCoord, 16);
|
||||
DebugLogger.finer("Chunk: %d, %d", xCoord, zCoord);
|
||||
int chunkX = Math.floorDiv(xCoord, 16);
|
||||
int chunkZ = Math.floorDiv(zCoord, 16);
|
||||
DebugLogger.finer("Chunk: %d, %d", chunkX, chunkZ);
|
||||
|
||||
// Calculate minimum bits required per coordinate based on range
|
||||
int bitsRequiredPerCoordinate = findBitsRequiredPerCoordinate(chunkX, chunkZ);
|
||||
int minTotalBits = bitsRequiredPerCoordinate * 2;
|
||||
DebugLogger.finer("Min bits required per coordinate: %d (total: %d)", bitsRequiredPerCoordinate, minTotalBits);
|
||||
|
||||
int wordsRequired = findWordsRequired(xCoord, zCoord);
|
||||
DebugLogger.finer("Words required: %d", wordsRequired);
|
||||
// Calculate words required, ensuring total bits is sufficient and even
|
||||
int wordsRequired = 0;
|
||||
int actualTotalBits = 0;
|
||||
if (minTotalBits > 0) { // Avoid division by zero if bitsPerWord is 0, or log(0)
|
||||
wordsRequired = Math.ceilDiv(minTotalBits, bitsPerWord);
|
||||
actualTotalBits = wordsRequired * bitsPerWord;
|
||||
// Ensure total bits is sufficient
|
||||
while (actualTotalBits < minTotalBits) {
|
||||
wordsRequired++;
|
||||
actualTotalBits = wordsRequired * bitsPerWord;
|
||||
}
|
||||
} // else: coords are 0 or -1, minTotalBits=0, wordsRequired=0, actualTotalBits=0. Need special handling?
|
||||
// If x/z are 0/-1, findBitsRequired returns 1, minTotalBits=2. The loop handles it.
|
||||
|
||||
int bitsRequired = wordsRequired * bitsPerWord;
|
||||
int bitsRequiredPerCoordinate = bitsRequired / 2;
|
||||
DebugLogger.finer("Bits required: %d (per coord: %d)", bitsRequired, bitsRequiredPerCoordinate);
|
||||
// Final bits per coordinate based on words
|
||||
bitsRequiredPerCoordinate = actualTotalBits / 2;
|
||||
DebugLogger.finer("Final Words required: %d", wordsRequired);
|
||||
DebugLogger.finer("Final Bits required: %d (per coord: %d)", actualTotalBits, bitsRequiredPerCoordinate);
|
||||
|
||||
|
||||
int encodedX = encodeCoord(xCoord, bitsRequiredPerCoordinate);
|
||||
int encodedZ = encodeCoord(zCoord, bitsRequiredPerCoordinate);
|
||||
int encodedX = encodeCoord(chunkX, bitsRequiredPerCoordinate);
|
||||
int encodedZ = encodeCoord(chunkZ, bitsRequiredPerCoordinate);
|
||||
DebugLogger.finer("Encoded coordinates: %d, %d", encodedX, encodedZ);
|
||||
|
||||
|
||||
long combinedValue = ((long) encodedX << bitsRequiredPerCoordinate) | encodedZ;
|
||||
DebugLogger.finer("Combined value: %d", combinedValue);
|
||||
|
||||
|
||||
int[] wordIndexes = combinedValueToWordIndexes(combinedValue, wordsRequired);
|
||||
DebugLogger.finer("Word indexes: %s", Arrays.toString(wordIndexes));
|
||||
|
||||
return wordList.getWords(wordIndexes);
|
||||
}
|
||||
|
||||
// Calculates the minimum number of bits required to represent the coordinate
|
||||
// using the encoding scheme (offset + coord) & mask, such that the coordinate
|
||||
// fits within the range [-(1 << (bits - 1)), (1 << (bits - 1)) - 1].
|
||||
private int findBitsRequiredPerCoordinate(int x, int z) {
|
||||
int n = Math.max(Math.abs(x), Math.abs(z));
|
||||
return n == 0 ? 1 : 32 - Integer.numberOfLeadingZeros(n);
|
||||
}
|
||||
int maxVal = Math.max(x, z);
|
||||
int minVal = Math.min(x, z);
|
||||
|
||||
private int findWordsRequired(int x, int z) {
|
||||
int brpc = findBitsRequiredPerCoordinate(x, z);
|
||||
return Math.ceilDiv(brpc * 2, wordList.getBitsPerWord());
|
||||
// Determine the required positive magnitude for the encoding range's positive side.
|
||||
// We need `(1 << (bits - 1)) >= max(maxVal + 1, -minVal)`
|
||||
int requiredPositiveMagnitude = Math.max(maxVal + 1, -minVal);
|
||||
|
||||
if (requiredPositiveMagnitude <= 0) {
|
||||
// Occurs only if maxVal <= -1 and minVal >= 0, which is impossible,
|
||||
// OR maxVal <= 0 and -minVal <= 0 => maxVal <= 0 and minVal >= 0.
|
||||
// This means x and z are both 0.
|
||||
// The range for 1 bit is [-1, 0]. If coords are 0, 1 bit is not enough for offset+coord.
|
||||
// Example: bits=1. offset=1<<0=1. mask=(1<<1)-1=1.
|
||||
// encodeCoord(0, 1) = (1+0)&1 = 1.
|
||||
// decodeCoord(1, 1): val=1. mask=1. offset=1. (1&1)-1 = 0. Correct.
|
||||
// What if we need to represent -1? encodeCoord(-1, 1) = (1-1)&1 = 0.
|
||||
// decodeCoord(0, 1): val=0. (0&1)-1 = -1. Correct.
|
||||
// So 1 bit works for range [-1, 0]. Let's check the condition:
|
||||
// x=0, z=0 -> maxVal=0, minVal=0. reqPosMag = max(1, 0) = 1.
|
||||
// x=-1, z=-1 -> maxVal=-1, minVal=-1. reqPosMag = max(0, 1) = 1.
|
||||
// x=0, z=-1 -> maxVal=0, minVal=-1. reqPosMag = max(1, 1) = 1.
|
||||
// So requiredPositiveMagnitude is 1 for the range [-1, 0].
|
||||
requiredPositiveMagnitude = 1; // Ensure it's at least 1 if coords are 0 or -1.
|
||||
}
|
||||
|
||||
// Calculate p = bits - 1
|
||||
// We need the smallest integer p such that (1 << p) >= requiredPositiveMagnitude.
|
||||
// If requiredPositiveMagnitude = 1, we need 1 << p >= 1, smallest p is 0.
|
||||
// If requiredPositiveMagnitude > 1, this is equivalent to finding the number of bits
|
||||
// needed to represent (requiredPositiveMagnitude - 1) in binary.
|
||||
int p;
|
||||
if (requiredPositiveMagnitude == 1) {
|
||||
p = 0;
|
||||
} else {
|
||||
p = 32 - Integer.numberOfLeadingZeros(requiredPositiveMagnitude - 1);
|
||||
}
|
||||
|
||||
// bits = p + 1
|
||||
return p + 1;
|
||||
}
|
||||
|
||||
private int encodeCoord(int coord, int bitsRequiredPerCoordinate) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue