Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import javax.imageio.ImageIO;
- import java.awt.*;
- import java.awt.image.BufferedImage;
- import java.io.File;
- import java.io.IOException;
- import java.io.UncheckedIOException;
- import java.lang.reflect.Field;
- import java.math.BigInteger;
- import java.util.*;
- import java.util.List;
- import java.util.concurrent.atomic.AtomicLong;
- public class Main {
- private static final double FLOOR_HEIGHT = 0.875 - 1;
- private static double initialHeight;
- private static int launchTntCount;
- private static List<Detector> detectors;
- public static void main(String[] args) {
- /*
- Scanner scan = new Scanner(System.in);
- System.out.println("Initial height (integer). The height of the TNT above the ender chests.");
- System.out.println("If the dispenser is on the same level as the ender chests, enter 0.");
- System.out.print("> ");
- initialHeight = Double.parseDouble(scan.nextLine());
- System.out.println("Launch TNT count (integer). The number of TNT used to launch the TNT.");
- System.out.print("> ");
- launchTntCount = Integer.parseInt(scan.nextLine());
- scan.close();
- generateDetectorCircle();
- for (int i = 0; i < 20; i++) {
- Random rand = new Random();
- for (int j = 0; j < 7; j++) {
- for (int k = 0; k < 2696; k++)
- rand.nextDouble();
- System.out.print(getDetectorOutput(rand.nextDouble() * 2 * Math.PI) + " ");
- }
- System.out.println(getSeed(rand));
- }
- /*
- long largestDifference = 0;
- long lastSeed = 0;
- for (int detectorId = 0; detectorId < detectors.size(); detectorId++) {
- long seed = getUpperSeedBound(detectorId);
- System.out.println(detectorId + ": " + toBinaryString(seed));
- if (seed - lastSeed > largestDifference)
- largestDifference = seed - lastSeed;
- lastSeed = seed;
- }
- System.out.println("Largest difference: " + largestDifference);
- System.out.println("Log of that: " + Math.log(largestDifference) / Math.log(2));
- System.out.println("Circle radius: " + -detectors.get(0).z);
- renderDetectors();
- */
- initialHeight = 26;
- launchTntCount = 7;
- generateDetectorCircle();
- long[] lut = new long[detectors.size()];
- for (int i = 0; i < lut.length; i++)
- lut[i] = getUpperSeedBound(i);
- final long a = 0x97be9f880aa9L;
- final long b = 0xeac471130bcaL;
- long[] bvec = {0xc8fbaf16b114L, 0xc2a36898b9feL, 0x13e60619c078L, 0xe7244157cb02L, 0x3771906241cL, 0x47d6c669fa46L, 0L};
- final long[] m6 = {0xff7392795dd6L, 0x1184f9b300L, 0xff79d1d659aeL, 0xff62f08153d5L, 0xfe64fe5e8622L, 0x24beb7ecc11L, 0x30c38f7adcL};
- final long[][] mm1 = {
- {-26, -81, -16, 50, 14, 22, -76},
- {-117, 4, -42, -45, -20, -61, -32},
- {3, 79, 1, 92, 5, 26, 8},
- {18, 28, 48, 53, -92, -33, -33},
- {43, 63, -68, -10, 33, 18, -57},
- {-21, -6, 91, -19, 56, 51, -12},
- {-44, 25, -6, -1, -44, 65, 34}
- };
- bvec = matmult(bvec, mm1);
- System.out.println(Arrays.toString(bvec));
- for (int i = 0; i < 100; i++) {
- Random rand = new Random();
- int[] detectorArray = new int[7];
- for (int j = 0; j < 7; j++) {
- for (int k = 0; k < 2696; k++)
- rand.nextDouble();
- detectorArray[j] = getDetectorOutput(rand.nextDouble() * 2 * Math.PI);
- }
- long[] penultimateVector = new long[7];
- for (int j = 0; j < 7; j++) {
- long[] v = new long[7];
- for (int k = 0; k < 7; k++) {
- int detectorId = detectorArray[k];
- if ((mm1[k][j] & 0x800000000000L) != 0) { // if it's negative mod 2^48
- detectorId--;
- if (detectorId < 0)
- detectorId += detectors.size();
- v[k] = lut[detectorId] & ~((1L << (48 - 26)) - 1);
- } else {
- v[k] = lut[detectorId];
- }
- }
- BigInteger val = dotBig(v, mm1, j);
- val = val.subtract(toBigInt48(bvec[j]));
- val = val.shiftRight(48);
- penultimateVector[j] = val.longValue();
- }
- //System.out.println(Arrays.toString(penultimateVector));
- long seed = dot(m6, penultimateVector) & 0xffffffffffffL;
- for (int j = 0; j < 1; j++) {
- //seed = ((seed - 0xbL) * 0xdfe05bcb1365L) & 0xffffffffffffL;
- seed = (seed * 0x5deece66dL + 0xbL) & 0xffffffffffffL;
- }
- System.out.println("Expected: " + getSeed(rand) + ", actual: " + seed);
- System.out.println("Diff: " + (getSeed(rand) - seed));
- }
- }
- private static BigInteger toBigInt48(long n) {
- if ((n & 0x800000000000L) != 0)
- return BigInteger.valueOf(n | 0xffff000000000000L);
- else
- return BigInteger.valueOf(n & 0xffffffffffffL);
- }
- private static BigInteger dotBig(long[] v, long[][] mat, int col) {
- BigInteger result = BigInteger.ZERO;
- for (int i = 0; i < v.length; i++) {
- result = result.add(BigInteger.valueOf(v[i] & 0xffffffffffffL).multiply(toBigInt48(mat[i][col])));
- }
- return result;
- }
- private static long dot(long[] a, long[] b) {
- long result = 0;
- for (int i = 0; i < a.length; i++)
- result += a[i] * b[i];
- return result;
- }
- private static long[] matmult(long[] vec, long[][] mat) {
- long[] result = new long[mat.length];
- for (int i = 0; i < mat.length; i++) {
- for (int j = 0; j < mat.length; j++) {
- result[i] += vec[j] * mat[j][i];
- }
- }
- return result;
- }
- private static long getSeed(Random rand) {
- try {
- Field field = Random.class.getDeclaredField("seed");
- field.setAccessible(true);
- return ((AtomicLong) field.get(rand)).get();
- } catch (ReflectiveOperationException e) {
- e.printStackTrace();
- return 0;
- }
- }
- private static void generateDetectorCircle() {
- detectors = new ArrayList<>();
- double radius = -simulateTntLaunch(0).z;
- int x = (int) (radius + 0.49 - 0.001);
- int z = 0;
- while (x >= z) {
- double dx = x - 0.99 - 0.001;
- double dz = z + 0.01 + 0.001;
- double dx2 = radius * radius - dz * dz;
- if (dx2 < dx * dx)
- x--;
- detectors.add(new Detector(x, z));
- detectors.add(new Detector(-z, x));
- detectors.add(new Detector(-x, -z));
- detectors.add(new Detector(z, -x));
- if (z != 0 && z != x) {
- detectors.add(new Detector(z, x));
- detectors.add(new Detector(-x, z));
- detectors.add(new Detector(-z, -x));
- detectors.add(new Detector(x, -z));
- }
- z++;
- }
- detectors.sort(Comparator.comparingDouble(detector -> {
- double angle = Math.atan2(-detector.x, -detector.z);
- if (angle < 0) angle += Math.PI * 2;
- return angle;
- }));
- }
- private static void renderDetectors() {
- final int CELL_SIZE = 16;
- int radius = -detectors.get(0).z;
- BufferedImage image = new BufferedImage((2 * radius + 1) * CELL_SIZE, (2 * radius + 1) * CELL_SIZE, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g = image.createGraphics();
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, image.getWidth(), image.getHeight());
- g.setColor(Color.GREEN);
- for (Detector detector : detectors) {
- g.fillRect((detector.x + radius) * CELL_SIZE, (detector.z + radius) * CELL_SIZE, CELL_SIZE, CELL_SIZE);
- }
- g.setColor(Color.BLUE);
- g.fillRect(radius * CELL_SIZE, radius * CELL_SIZE, CELL_SIZE, CELL_SIZE);
- g.setColor(Color.BLACK);
- for (int i = 0; i < 2 * radius; i++) {
- g.drawLine((i + 1) * CELL_SIZE, 0, (i + 1) * CELL_SIZE, image.getHeight());
- g.drawLine(0, (i + 1) * CELL_SIZE, image.getWidth(), (i + 1) * CELL_SIZE);
- }
- g.setColor(Color.RED);
- double preciseRadius = -simulateTntLaunch(0).z;
- g.drawOval((int) ((0.01 - preciseRadius + radius) * CELL_SIZE), (int) ((0.01 - preciseRadius + radius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE));
- g.drawOval((int) ((0.01 - preciseRadius + radius) * CELL_SIZE), (int) ((0.99 - preciseRadius + radius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE));
- g.drawOval((int) ((0.99 - preciseRadius + radius) * CELL_SIZE), (int) ((0.01 - preciseRadius + radius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE));
- g.drawOval((int) ((0.99 - preciseRadius + radius) * CELL_SIZE), (int) ((0.99 - preciseRadius + radius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE), (int) ((2 * preciseRadius) * CELL_SIZE));
- g.dispose();
- try {
- ImageIO.write(image, "PNG", new File("circle.png"));
- } catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- try {
- Desktop.getDesktop().open(new File("circle.png"));
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- private static long getUpperSeedBound(int detectorId) {
- double upperAngle = getUpperAngleBound(detectorId);
- long upperSeed = (long) (upperAngle / (2 * Math.PI) * 0x1.0p26) << (48 - 26);
- upperSeed |= (1 << (48 - 26)) - 1;
- return upperSeed;
- }
- private static double getUpperAngleBound(int detectorId) {
- final double EPSILON = 0x1.0p-28 * Math.PI;
- Detector detector = detectors.get(detectorId < 2 ? detectorId - 2 + detectors.size() : detectorId - 2);
- double lower = Math.atan2(-detector.x, -detector.z);
- detector = detectors.get((detectorId + 2) % detectors.size());
- double upper = Math.atan2(-detector.x, -detector.z);
- while (upper - lower > EPSILON) {
- double da = (upper - lower) % (Math.PI * 2);
- double diff = 2 * da % (Math.PI * 2) - da;
- double mid = lower + diff * 0.5;
- int actualDetector = getDetectorOutput(mid);
- int dd = (actualDetector - detectorId) % detectors.size();
- int detectorDiff = 2 * dd % detectors.size() - dd;
- if (detectorDiff <= 0)
- lower = mid;
- else
- upper = mid;
- }
- return upper < 0 ? upper + Math.PI * 2 : upper;
- }
- private static int getDetectorOutput(double angle) {
- TntEntity tnt = simulateTntLaunch(angle);
- int detectorId = 0;
- boolean foundDetector = false;
- while (true) {
- double minX = tnt.x - 0.49 + 0.001, maxX = tnt.x + 0.49 - 0.001;
- double minZ = tnt.z - 0.49 + 0.001, maxZ = tnt.z + 0.49 - 0.001;
- Detector detector = detectors.get(detectorId);
- boolean intersects = minX < detector.x + 1 && maxX >= detector.x && minZ < detector.z + 1 && maxZ >= detector.z;
- if (intersects)
- foundDetector = true;
- else if (foundDetector)
- return detectorId == 0 ? detectors.size() - 1 : detectorId - 1;
- detectorId = (detectorId + 1) % detectors.size();
- }
- }
- // Simulates TNT being fired upwards from a dispenser at (0.5, initialHeight, 0.5) and being blasted by launchTntCount TNT
- private static TntEntity simulateTntLaunch(double initialAngle) {
- TntEntity tnt = new TntEntity();
- tnt.x = 0.5;
- tnt.y = initialHeight;
- tnt.z = 0.5;
- tnt.vx = -Math.sin(initialAngle) * 0.02;
- tnt.vy = 0.2;
- tnt.vz = -Math.cos(initialAngle) * 0.02;
- for (int i = 0; i < 29; i++)
- tnt.update(initialHeight);
- double dx = tnt.x - 0.5;
- double dy = -0.98/16;
- double dz = tnt.z - 0.5;
- double distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
- double multiplier = (1 - (distance / 8)) / distance;
- tnt.vx += dx * multiplier * launchTntCount;
- tnt.vy += dy * multiplier * launchTntCount;
- tnt.vz += dz * multiplier * launchTntCount;
- for (int i = 0; i < 80 - 29; i++) {
- double minX = tnt.x - 0.49, maxX = tnt.x + 0.49;
- double minZ = tnt.z - 0.49, maxZ = tnt.z + 0.49;
- boolean offDispenser = maxX < 0 || minX > 1 || maxZ < 0 || minZ > 1;
- tnt.update(offDispenser ? FLOOR_HEIGHT : initialHeight);
- }
- return tnt;
- }
- private static class TntEntity {
- private double x, y, z, vx, vy, vz;
- void update(double floorHeight) {
- vy -= 0.04;
- double dx = vx, dy = vy, dz = vz;
- double prevVy = vy;
- if (y + dy < floorHeight)
- dy = floorHeight - y;
- y += dy;
- x += dx;
- z += dz;
- boolean onGround = dy != prevVy && prevVy < 0;
- if (dy != prevVy)
- vy = 0;
- vx *= 0.98;
- vy *= 0.98;
- vz *= 0.98;
- if (onGround) {
- vx *= 0.7;
- vz *= 0.7;
- vy *= -0.5;
- }
- }
- }
- private static class Detector {
- private int x, z;
- public Detector(int x, int z) {
- this.x = x;
- this.z = z;
- }
- }
- private static String toBinaryString(long l) {
- StringBuilder str = new StringBuilder(Long.toBinaryString(l));
- while (str.length() < 48)
- str.insert(0, "0");
- return str.toString();
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement