Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import java.util.*;
- public class floot {
- public static HashMap<Integer, Movement> movementMap = new HashMap<>();
- public static HashMap<Long, Movement> startMap = new HashMap<>();
- //finds large starting movements to get "close to the target" and smaller movements to cover that distance later
- //most times there's too many floats between raw start->target, so the starting movements cuts down that distance
- //this way there's less distance to search through, and the distance is easily covered with a few smaller movements
- //startLimit is how many floats the starting movements have to be within the target, and offsetLimit is how many floats the offsets can be
- //fwiw 256.9999999-257.0(my usual goal) is about 2 million floats. And the closer to 0 the more it'll be(5.9999999-6.0 is ~100 million)
- //the whole simulation is jankily crammed in here because I'm impatient and its like 5x faster to do stupidly than think critically
- public static void createMovements(Set<Long> starts, Set<Integer> offsets, long startLimit, long offsetLimit, double start, double target){
- //could be adjusted to do more or be rta friendly i just think this is fine generally
- System.out.println("creating movements...");
- long startTime = System.currentTimeMillis();
- long targetLong = Double.doubleToLongBits(target);
- long startLong = Double.doubleToLongBits(start);
- boolean[] truefalse = {true,false};
- boolean ground = false;
- for(boolean sneak : truefalse) {
- for(int strafe = 0; strafe < 2; strafe++) {
- double inputForward = 1 * (sneak ? 0.2940000295639038 : 0.9800000190734863);
- double inputSideways = strafe * (sneak ? 0.2940000295639038 : 0.9800000190734863);
- float speed = ground ? 0.1f : 0.02f;
- float friction = ground ? 0.54600006f : 0.91f;
- for (int yawIndex = 0; yawIndex < 65536; yawIndex += 1) {
- double pos = start;
- double vel = 0;
- double inputMag = inputForward * inputForward + inputSideways * inputSideways; //1 tick holding forward
- if(inputMag > 1){
- inputMag = (float)Math.sqrt(inputMag);
- inputForward/= inputMag;
- inputSideways/= inputMag;
- }
- vel += ((inputForward * (double)speed) * (double)MathHelp.MCsins[(yawIndex + 16384) & 0xFFFF]) +
- ((inputSideways * (double)speed) * (double)MathHelp.MCsins[(yawIndex) & 0xFFFF]);
- if (Math.abs(vel) < 1e-7) vel = 0; //:3
- pos+= vel;
- vel*= friction;
- if (Math.abs(vel) < 0.003) vel = 0; //1 tick holding back
- inputMag = inputForward * inputForward + inputSideways * inputSideways;
- if(inputMag > 1){
- inputMag = (float)Math.sqrt(inputMag);
- inputForward/= inputMag;
- inputSideways/= inputMag;
- }
- vel += ((-inputForward * (double)speed) * (double)MathHelp.MCsins[(yawIndex + 16384) & 0xFFFF]) +
- ((-inputSideways * (double)speed) * (double)MathHelp.MCsins[(yawIndex) & 0xFFFF]);
- if (Math.abs(vel) < 1e-7) vel = 0; //:3
- pos+= vel;
- vel*= friction;
- while(vel != 0) { //tick until stopped just in case
- if (Math.abs(vel) < 0.003) vel = 0;
- pos+= vel;
- vel*= friction;
- }
- for (int yawIndex1 = 0; yawIndex1 < 65536; yawIndex1 += 1) {
- double pos1 = pos;
- double vel1 = 0;
- inputMag = inputForward * inputForward + inputSideways * inputSideways; //1 tick holding forward
- if(inputMag > 1){
- inputMag = (float)Math.sqrt(inputMag);
- inputForward/= inputMag;
- inputSideways/= inputMag;
- }
- vel1 += ((inputForward * (double)speed) * (double)MathHelp.MCsins[(yawIndex1 + 16384) & 0xFFFF]) +
- ((inputSideways * (double)speed) * (double)MathHelp.MCsins[(yawIndex1) & 0xFFFF]);
- if (Math.abs(vel1) < 1e-7) vel1 = 0; //:3
- pos1+= vel1;
- vel1*= friction;
- if (Math.abs(vel1) < 0.003) vel1 = 0; //1 tick holding back
- inputMag = inputForward * inputForward + inputSideways * inputSideways;
- if(inputMag > 1){
- inputMag = (float)Math.sqrt(inputMag);
- inputForward/= inputMag;
- inputSideways/= inputMag;
- }
- vel1 += ((-inputForward * (double)speed) * (double)MathHelp.MCsins[(yawIndex1 + 16384) & 0xFFFF]) +
- ((-inputSideways * (double)speed) * (double)MathHelp.MCsins[(yawIndex1) & 0xFFFF]);
- if (Math.abs(vel1) < 1e-7) vel1 = 0; //:3
- pos1+= vel1;
- vel1*= friction;
- while(vel1 != 0) { //tick until stopped just in case
- if (Math.abs(vel1) < 0.003) vel1 = 0;
- pos1+= vel1;
- vel1*= friction;
- }
- long posLong = Double.doubleToLongBits(pos1);
- long startDiff = (posLong - startLong); //surely
- if(startDiff == 0) continue;
- if((Math.abs(posLong - targetLong) < startLimit) && starts.add(posLong)) { //is this a good lorge starting movement?
- startMap.put(startDiff, new Movement(new int[]{yawIndex, yawIndex, yawIndex1, yawIndex1}, new int[]{1,-1,1,-1}, new int[]{strafe, -strafe, strafe, -strafe}, false, sneak));
- }if((Math.abs(startDiff) < offsetLimit) && offsets.add((int)(posLong - startLong))) { //is this a good small offset?
- movementMap.put((int)startDiff, new Movement(new int[]{yawIndex, yawIndex, yawIndex1, yawIndex1}, new int[]{1,-1,1,-1}, new int[]{strafe, -strafe, strafe, -strafe}, false, sneak));
- }
- }
- if((yawIndex & 16383) == 0) System.out.println(".." + yawIndex);
- }
- }
- }
- System.out.println(String.format("created %d starts within %d floats and %d < %d float offsets within in %.3f seconds.", starts.size(), startLimit, offsets.size(), offsetLimit, (double)(System.currentTimeMillis() - startTime) / 1000.0));
- }
- //given a relatively close starting and target position on an axis
- //find a set of inputs that moves that postion into that exact float target position
- //this assumes no powers of two are passed during this, since it measures in numbers of float values passed per movement
- //there's definitely better ways to do this that aren't jank or slow but I am not that smart
- public static void main(String args[])
- {
- //starting position(aka hitbox position...)
- double startPos = 1050;
- //position to target
- double targetPos = 1049.9999999;
- //max number of acceptable movements before giving up and crying
- int maxPath = 50;
- Set<Integer> offsets = new HashSet<>();
- Set<Long> startOffsets = new HashSet<>();
- //sim heavy stuff to get movements that'll be used
- createMovements(startOffsets, offsets, 2_000_000L, 2_000_000L, startPos, targetPos);
- //setup start/end indexes for actual search
- long targetLong = Double.doubleToLongBits(targetPos);
- long longOffset = Math.min(Collections.min(startOffsets), targetLong);
- Set<Integer> starts = new HashSet<>();
- for(Long a : startOffsets){
- starts.add((int)(a - longOffset));
- }
- startOffsets.clear();
- int targetIndex = (int)(targetLong - longOffset);
- //I'm not actually sure how large this should be mathematically but ig this works?
- int searchRange = 1 + Math.max(Collections.max(starts), targetIndex) + Collections.max(offsets);
- System.out.println("finding path...");
- long searchTime = System.currentTimeMillis();
- LinkedList<Integer> path = findPath(starts, targetIndex, offsets, searchRange, maxPath);
- if(path != null){
- System.out.println(String.format("%d movement solution from %.16f(%d) found in %f seconds \nPath: ", path.size(), startPos, Double.doubleToLongBits(startPos), (double)(System.currentTimeMillis() - searchTime) / 1000.0));
- StringBuilder movementsString = new StringBuilder(Double.longBitsToDouble(path.get(path.size() - 1) + longOffset) + String.format("(%d) ", path.get(path.size() - 1) + longOffset) + startMap.get((path.get(path.size() - 1) + longOffset) - Double.doubleToLongBits(startPos)).toString());
- for (int i = path.size() - 1; i >= 0; i--) {
- long currentfloat = path.get(i) + longOffset;
- if(i != path.size() -1) movementsString.append(Double.longBitsToDouble(currentfloat) + String.format("(%d) ", currentfloat) + movementMap.get((int)(currentfloat - (path.get(i + 1) + longOffset))).toString());
- }
- System.out.println(movementsString);
- }else{
- System.out.println(String.format("no solution found within %d movements in %f seconds", maxPath, (double)(System.currentTimeMillis() - searchTime) / 1000.0));
- }
- }
- //try and get from specified starting points to the destination w/ only increments of the provided offsets
- //each index represents one float value. kinda looks like the dragon ai
- public static LinkedList<Integer> findPath(Set<Integer> starts, int target, Set<Integer> offsets, int range, int maxMovements){
- int[] prevFloat = new int[range]; //tracks our path through the floats by linking each index to its previous
- short[] movements = new short[range]; //number of movements to get here
- boolean[] visited = new boolean[range]; //number of movements to get here
- Queue<Integer> queue = new LinkedList<>();
- for(int i = 0; i < range; i++){
- movements[i] = -1;
- prevFloat[i] = -1;
- }
- for(int start : starts){ //start branching from all of these at once
- visited[start] = true;
- movements[start] = 0;
- queue.add(start);
- }
- int c = 0;
- search: {
- while (!queue.isEmpty()) { // search as long as there's stuff to search from
- int index = queue.remove();
- if (movements[index] > maxMovements) continue;
- for (int offset : offsets) { //branch out to all our possible offsets
- int offIndex = offset + index;
- if (offIndex > -1 && offIndex < range && !visited[offIndex]) { //have we been here/is it in bounds/is it worth
- visited[offIndex] = true;
- movements[offIndex] = (short) (movements[index] + 1);
- prevFloat[offIndex] = index;
- queue.add(offIndex); //link up and advance this offset
- c++;
- if (offIndex == target) { //wow we made it this is so epic sauce
- break search;
- }
- }
- }
- if((c & 32767) == 0) System.out.println(String.format("%.3f",(double)c/range));
- }
- return null; //we couldn't get anywhere reasonably rest in peace
- }
- //your royal success... you should be out changing your life for the better!
- //but instead you just sit, hoping that today will be the day, all while praying that each tomorrow will be the same as before.
- //is there something i just can't see? what more can you be waiting for? surely you can't run in circles forever?
- int traverse = target;
- LinkedList<Integer> path = new LinkedList<>(List.of(traverse));
- while(prevFloat[traverse] != -1){
- traverse = prevFloat[traverse];
- path.add(traverse);
- }
- return path;
- }
- }
- class MathHelp { //does silly math stuff to mimic how minecraft handles it
- //lookup table used by minecraft trigonometry functions
- public static final float[] MCsins = constructSines();
- //radian value thingy to make my life easier
- //or smthn ig idk what a math is
- private static final float RAD = ((float)Math.PI / 180);
- //builds the sin table from minecraft
- public static float[] constructSines(){
- float[] MCsins = new float[65536];
- for (int i = 0; i < 65536; ++i) {
- MCsins[i] = (float)Math.sin((double)i * Math.PI * 2.0 / 65536.0);
- }
- return MCsins;
- }
- //returns whether the two doubles are almost the same(within .00001)
- public static boolean isNear(double a, double b){
- return Math.abs(b - a) < 1.0E-5f;
- }
- //ceiling function
- public static int ceil(float f) {
- int i = (int)f;
- return f > (float)i ? i + 1 : i;
- }
- //flooring functions
- public static int floor(double d) {
- int i = (int)d;
- return d < (double)i ? i - 1 : i;
- }
- public static long lfloor(double d) {
- long l = (long)d;
- return d < (double)l ? l - 1L : l;
- }
- //returns the stuff after the period.
- public static double fractionalPart(double value) {
- return value - (double) MathHelp.lfloor(value);
- }
- //returns the sign of a double
- public static int sign(double d) {
- if (d == 0.0) {
- return 0;
- }
- return d > 0.0 ? 1 : -1;
- }
- //returns the sin value of a given radian
- //but using minecraft's quirky table
- public static float MCsin(float f) {
- return MCsins[(int)(f * 10430.378f) & 0xFFFF];
- }
- //returns the cos value of a given radian
- //but also using minecraft's quirky table
- public static float MCcos(float f) {
- return MCsins[(int)(f * 10430.378f + 16384.0f) & 0xFFFF];
- }
- //returns the funky radian value to make my life easier
- public static float RAD(){
- return RAD;
- }
- }
- //jank info about a specific movement
- class Movement{
- boolean ground;
- boolean sneak;
- int[] forwards;
- int[] strafes;
- int[] yaws;
- public Movement(int[] yaws, int[] forwards, int[] strafes, boolean ground, boolean sneak){
- this.yaws = yaws;
- this.forwards = forwards;
- this.strafes = strafes;
- this.ground = ground;
- this.sneak = sneak;
- }
- //tries to recreate a in-game angle from a specific index into the sin table
- public static float estimateAngle(int angleIndex){
- float guess = ((float)angleIndex / 10430.378f) / MathHelp.RAD();
- if(angleIndex == ((int)((guess * MathHelp.RAD()) * 10430.378f) & 0xFFFF) && angleIndex + 16384 == ((int)((guess * MathHelp.RAD()) * 10430.378f + 16384.0f) & 0xFFFF)){
- return guess;
- }else{
- for(float guess1 = guess - 0.01f; guess1 < guess + 0.01; guess1+= 0.001f){
- if(angleIndex == ((int)((guess1 * MathHelp.RAD()) * 10430.378f) & 0xFFFF) && angleIndex + 16384 == ((int)((guess1 * MathHelp.RAD()) * 10430.378f + 16384.0f) & 0xFFFF)){
- return guess1;
- }
- }
- return -1f;
- }
- }
- // ?
- public String toString() {
- StringBuilder string = new StringBuilder((ground ? "ground " : "air ") + (sneak ? "sneak " : "walk ") + "w/ inputs: ");
- for(int i = 0; i < yaws.length; i++){
- string.append(String.format("%d: (yaw: %d[%.10f], " + (forwards[i] == 1 ? "forward, " : (forwards[i] == -1 ? "back, " : " ")) + (strafes[i] == 1 ? "left" : (strafes[i] == -1 ? "right" : "")) + ") ", i, yaws[i], estimateAngle(yaws[i])));
- }
- string.append("\n");
- return string.toString();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement