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
	
	 Minecon724
				Minecon724