Aplet123

Untitled

Feb 2nd, 2020
63
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const fs = require("fs");
  2.  
  3. const alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  4.  
  5. function permutator(inputArr) {
  6.   var results = [];
  7.  
  8.   function permute(arr, memo) {
  9.     var cur, memo = memo || [];
  10.  
  11.     for (var i = 0; i < arr.length; i++) {
  12.       cur = arr.splice(i, 1);
  13.       if (arr.length === 0) {
  14.         results.push(memo.concat(cur));
  15.       }
  16.       permute(arr.slice(), memo.concat(cur));
  17.       arr.splice(i, 0, cur[0]);
  18.     }
  19.  
  20.     return results;
  21.   }
  22.  
  23.   return permute(inputArr);
  24. }
  25.  
  26. function reps(x, n) {
  27.     return new Array(n).fill(x);
  28. }
  29.  
  30. class Shift {
  31.     constructor(dir, ind) {
  32.         this.dir = dir;
  33.         this.ind = ind;
  34.     }
  35.  
  36.     serialize(len) {
  37.         if (this.dir == "l") {
  38.             return reps(alpha[this.ind], 1);
  39.         }
  40.         if (this.dir == "r") {
  41.             return reps(alpha[this.ind], len - 1);
  42.         }
  43.         if (this.dir == "u") {
  44.             return reps(this.ind.toString(), 1);
  45.         }
  46.         if (this.dir == "d") {
  47.             return reps(this.ind.toString(), len - 1);
  48.         }
  49.     }
  50. }
  51.  
  52. function serializeShifts(arr, len) {
  53.     return arr.flatMap(v => v.serialize(len)).join`,`.replace(new RegExp(String.raw`(\w+),(?:\1,){${len - 1}}`, "g"), "");
  54. }
  55.  
  56. class Point {
  57.     constructor(r, c) {
  58.         this.r = r;
  59.         this.c = c;
  60.     }
  61.  
  62.     withRow(r) {
  63.         return new Point(r, this.c);
  64.     }
  65.  
  66.     withColumn(c) {
  67.         return new Point(this.r, c);
  68.     }
  69.  
  70.     shiftedHoriz(x) {
  71.         return this.withColumn(this.c + x);
  72.     }
  73.  
  74.     shiftedVert(x) {
  75.         return this.withRow(this.r + x);
  76.     }
  77.  
  78.     shiftedHorizMod(x, m) {
  79.         return this.withColumn((this.c + x) % m);
  80.     }
  81.  
  82.     shiftedVertMod(x, m) {
  83.         return this.withRow((this.r + x) % m);
  84.     }
  85.  
  86.     equals(p) {
  87.         return this.r == p.r && this.c == p.c;
  88.     }
  89. }
  90.  
  91. // find an element e in 2d array arr
  92. function find2d(arr, e) {
  93.     for (let i = 0; i < arr.length; i ++) {
  94.         for (let j = 0; j < arr[i].length; j ++) {
  95.             if (arr[i][j] == e) {
  96.                 return new Point(i, j);
  97.             }
  98.         }
  99.     }
  100.     return null;
  101. }
  102.  
  103. let yeet = 0;
  104.  
  105. class Board {
  106.     constructor(arr) {
  107.         this.nums = arr;
  108.         this.len = arr.length;
  109.         this.ins = [];
  110.         this.last = this.len - 1;
  111.         let i = 0;
  112.         this.final = new Array(this.len).fill(0).map(v => new Array(this.len).fill(0).map(k => i ++));
  113.     }
  114.  
  115.     // find where the number n should go
  116.     dest(n) {
  117.         return find2d(this.final, n);
  118.     }
  119.  
  120.     // find what number should be a point p
  121.     desired(p) {
  122.         return this.final[p.r][p.c];
  123.     }
  124.  
  125.     at(p) {
  126.         return this.nums[p.r][p.c];
  127.     }
  128.  
  129.     // find the point where n is located
  130.     find(n) {
  131.         return find2d(this.nums, n);
  132.     }
  133.  
  134.     // find what point should end up at p
  135.     findDesired(p) {
  136.         return this.find(this.desired(p));
  137.     }
  138.  
  139.     isDesired(p) {
  140.         return p.equals(this.findDesired(p));
  141.     }
  142.  
  143.     isFinished() {
  144.         for (let i = 0; i < this.len; i ++) {
  145.             for (let j = 0; j < this.len; j ++) {
  146.                 if (!this.isDesired(new Point(i, j))) {
  147.                     return false;
  148.                 }
  149.             }
  150.         }
  151.         return true;
  152.     }
  153.  
  154.     clearIns() {
  155.         this.ins = [];
  156.     }
  157.  
  158.     makeShift(shift) {
  159.         if (shift.dir == "l") {
  160.             return this.shiftLeft(shift.ind);
  161.         }
  162.         if (shift.dir == "r") {
  163.             return this.shiftRight(shift.ind);
  164.         }
  165.         if (shift.dir == "u") {
  166.             return this.shiftUp(shift.ind);
  167.         }
  168.         if (shift.dir == "d") {
  169.             return this.shiftDown(shift.ind);
  170.         }
  171.     }
  172.  
  173.     shiftLeft(ind) {
  174.         this.ins.push(new Shift("l", ind));
  175.         this.nums[ind].push(this.nums[ind].shift());
  176.         return this;
  177.     }
  178.  
  179.     shiftRight(ind) {
  180.         this.ins.push(new Shift("r", ind));
  181.         this.nums[ind].unshift(this.nums[ind].pop());
  182.         return this;
  183.     }
  184.  
  185.     shiftUp(ind) {
  186.         this.ins.push(new Shift("u", ind));
  187.         const top = this.nums[0][ind];
  188.         for (let i = 0; i < this.last; i ++) {
  189.             this.nums[i][ind] = this.nums[i + 1][ind];
  190.         }
  191.         this.nums[this.last][ind] = top;
  192.         return this;
  193.     }
  194.  
  195.     shiftDown(ind) {
  196.         this.ins.push(new Shift("d", ind));
  197.         const bottom = this.nums[this.last][ind];
  198.         for (let i = this.last; i > 0; i --) {
  199.             this.nums[i][ind] = this.nums[i - 1][ind];
  200.         }
  201.         this.nums[0][ind] = bottom;
  202.         return this;
  203.     }
  204.  
  205.     pointLeft(p) {
  206.         return this.shiftLeft(p.r);
  207.     }
  208.  
  209.     pointRight(p) {
  210.         return this.shiftRight(p.r);
  211.     }
  212.  
  213.     pointUp(p) {
  214.         return this.shiftUp(p.c);
  215.     }
  216.  
  217.     pointDown(p) {
  218.         return this.shiftDown(p.c);
  219.     }
  220.  
  221.     // move point p horizontally to column c with only left shifts
  222.     pointHoriz(p, c) {
  223.         const diff = p.c - c;
  224.         let shifts = 0;
  225.         if (diff > 0) {
  226.             shifts = diff;
  227.         }
  228.         if (diff < 0) {
  229.             shifts = p.c + this.len - c;
  230.         }
  231.         for (let i = 0; i < shifts; i ++) {
  232.             this.shiftLeft(p.r);
  233.         }
  234.         return this;
  235.     }
  236.  
  237.     // move point p vertically to row r with only up shifts
  238.     pointVert(p, r) {
  239.         const diff = p.r - r;
  240.         let shifts = 0;
  241.         if (diff > 0) {
  242.             shifts = diff;
  243.         }
  244.         if (diff < 0) {
  245.             shifts = p.r + this.len - r;
  246.         }
  247.         for (let i = 0; i < shifts; i ++) {
  248.             this.shiftUp(p.c);
  249.         }
  250.         return this;
  251.     }
  252.  
  253.     // insert point p into row r using the last column
  254.     insertRow(p, r) {
  255.         const val = this.at(p);
  256.         if (p.r == r && p.c != this.last) {
  257.             // annoying case where you first have to get the point out
  258.             const reference = this.at(p.withColumn(this.last));
  259.             // shift to last column then shift down to remove from row
  260.             this.pointHoriz(p, this.last);
  261.             this.pointDown(this.find(val));
  262.             this.pointHoriz(this.find(reference), this.last); // restore reference point
  263.         }
  264.         // load the point into the rightmost tile in the row
  265.         this.pointHoriz(this.find(val), this.last);
  266.         this.pointVert(this.find(val), r);
  267.         // slide it in
  268.         this.pointLeft(this.find(val));
  269.         return this;
  270.     }
  271.  
  272.     // put every piece in row r in the correct place except for the one in the last column
  273.     solveRow(r) {
  274.         for (let i = 0; i < this.last; i ++) {
  275.             this.insertRow(this.findDesired(new Point(r, i)), r);
  276.         }
  277.         return this;
  278.     }
  279.  
  280.     // solve the (n - 1)x(n - 1) square starting at the top left
  281.     solveSmallSquare() {
  282.         for (let i = 0; i < this.last; i ++) {
  283.             this.solveRow(i);
  284.         }
  285.         return this;
  286.     }
  287.  
  288.     // insert point p into the last column using the bottom row
  289.     insertLastColumn(p) {
  290.         const val = this.at(p);
  291.         if (p.c == this.last && p.r != this.last) {
  292.             // annoying case where you first have to get the point out;
  293.             const reference = this.at(p.withRow(this.last));
  294.             // shift to last row then shift left to remove from column
  295.             this.pointVert(p, this.last);
  296.             this.pointLeft(this.find(val));
  297.             this.pointVert(this.find(reference), this.last);
  298.         }
  299.         // load the point into the bottom right corner
  300.         this.pointHoriz(this.find(val), this.last);
  301.         // slide it in
  302.         this.pointUp(this.find(val));
  303.         return this;
  304.     }
  305.  
  306.     // solve the last column except for the last two rows
  307.     solveLastColumn() {
  308.         for (let i = 0; i < this.len - 2; i ++) {
  309.             this.insertLastColumn(this.findDesired(new Point(i, this.last)));
  310.         }
  311.         this.shiftUp(this.last);
  312.         return this;
  313.     }
  314.  
  315.     // insert the tile in the lower insertion slot to the correct place (last column, penultimate row)
  316.     lowerInsertion() {
  317.         const p = new Point(this.last - 1, this.last);
  318.         const val = this.at(p);
  319.         let loc;
  320.         if (this.isDesired(p)) {
  321.             // annoying case where you just insert into an out-of-place tile
  322.             let broken = false;
  323.             for (let i = 0; i < this.len; i ++) {
  324.                 if (!this.isDesired(new Point(this.last, i))) {
  325.                     loc = new Point(this.last, i);
  326.                     broken = true;
  327.                     break;
  328.                 }
  329.             }
  330.             if (!broken) {
  331.                 return false;
  332.             }
  333.         } else {
  334.             loc = this.dest(val);
  335.         }
  336.         const refC = (loc.c + 1) % this.len;
  337.         const reference = this.at(new Point(this.last, refC));
  338.         // move tile over and insert down
  339.         this.pointHoriz(loc, this.last);
  340.         this.shiftDown(this.last);
  341.         this.pointHoriz(this.find(reference), refC); // restore reference point
  342.         return true;
  343.     }
  344.  
  345.     // insert the tile in the upper insertion slot to the correct place (top right corner)
  346.     upperInsertion() {
  347.         const p = new Point(0, this.last);
  348.         const val = this.at(p);
  349.         let loc = this.dest(val);
  350.         if (loc.equals(new Point(this.last - 1, this.last))) {
  351.             // annoying case where you just insert into an out-of-place tile
  352.             let broken = false;
  353.             for (let i = 0; i < this.len; i ++) {
  354.                 if (!this.isDesired(new Point(this.last, i))) {
  355.                     loc = new Point(this.last, i);
  356.                     broken = true;
  357.                     break;
  358.                 }
  359.             }
  360.             if (!broken) {
  361.                 return false;
  362.             }
  363.         }
  364.         const refC = (loc.c + 1) % this.len;
  365.         const reference = this.at(new Point(this.last, refC));
  366.         // move tile over and insert up
  367.         this.pointHoriz(loc, this.last);
  368.         this.shiftUp(this.last);
  369.         this.pointHoriz(this.find(reference), refC); // restore reference point
  370.         return true;
  371.     }
  372.  
  373.     isParity() {
  374.         if (this.len % 2 == 1) {
  375.             return false;
  376.         }
  377.         let wrong = 0;
  378.         for (let i = 0; i < this.len; i ++) {
  379.             for (let j = 0; j < this.len; j ++) {
  380.                 if (!this.isDesired(new Point(i, j))) {
  381.                     wrong ++;
  382.                 }
  383.             }
  384.         }
  385.         return wrong == 2;
  386.     }
  387.  
  388.     // solve the remaining part
  389.     solveOther() {
  390.         let looping = true;
  391.         let upper = false;
  392.         while (!this.isFinished()) {
  393.             if (upper) {
  394.                 looping = this.upperInsertion();
  395.             } else {
  396.                 looping = this.lowerInsertion();
  397.             }
  398.             // check for parity
  399.             if (upper && !looping) {
  400.                 console.log("doing parity");
  401.                 for (let i = 0; i < this.len / 2; i ++) {
  402.                     this.shiftLeft(this.last).shiftUp(this.last).shiftLeft(this.last).shiftDown(this.last);
  403.                 }
  404.                 this.shiftLeft(this.last);
  405.                 //this.shiftUp(this.last);
  406.                 looping = true;
  407.             }
  408.             upper = !upper;
  409.         }
  410.         return this;
  411.     }
  412.  
  413.     solve() {
  414.         this.solveSmallSquare();
  415.         this.solveLastColumn();
  416.         this.solveOther();
  417.         return this;
  418.     }
  419.  
  420.     serializeShifts() {
  421.         return serializeShifts(this.ins, this.len);
  422.     }
  423. }
  424.  
  425. let board = new Board(fs.readFileSync("board.txt", "utf8").split`\n`.slice(1).map(v => v.match(/\d+/g).map(x => +x)));
  426. //console.log(JSON.stringify(board.solve().ins.map(i => ({dir: i.dir, ind: i.ind}))));
  427. board.solve();
  428. console.log(board.serializeShifts());
  429. const ilen = board.ins.length;
  430. const rev = [];
  431. for (let i = 0; i < ilen; i ++) {
  432.     const ins = board.ins[ilen - i - 1];
  433.     let newdir;
  434.     if (ins.dir == "l") {
  435.         newdir = "r";
  436.     } else if (ins.dir == "r") {
  437.         newdir = "l";
  438.     } else if (ins.dir == "u") {
  439.         newdir = "d";
  440.     } else if (ins.dir == "d") {
  441.         newdir = "u";
  442.     }
  443.     rev.push(new Shift(newdir, ins.ind));
  444. }
  445. const str = board.serializeShifts() + ",\n" + serializeShifts(rev, board.len) + ",";
  446. const rowMappings = permutator([0, 1, 2, 3]);
  447. const columnMappings = permutator([0, 1, 2, 3]);
  448. let tot = "";
  449. rowMappings.map(r => columnMappings.map(c => tot += (str.replace(/[A-Z]/g, m => alpha[r[alpha.indexOf(m)]]).replace(/\d+/g, m => c[+m]))));
  450. fs.writeFileSync("yeet.txt", tot);
Advertisement
Add Comment
Please, Sign In to add comment