main.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. const fs = require('fs');
  2. const readline = require('readline');
  3. function Rope(len) {
  4. this.tokens = [];
  5. this.visited = {'0x0': true};
  6. this.visitedCoord = [[0, 0]];
  7. this.boundaries = [[0, 0], [0, 0]];
  8. this.len = len;
  9. for (let i =0; i < len +1; ++i)
  10. this.tokens.push([0, 0]);
  11. }
  12. Rope.prototype.applyMove = function(moveArr) {
  13. this.tokens[0][0] += moveArr[0];
  14. this.tokens[0][1] += moveArr[1];
  15. this.boundaries = [
  16. [ Math.min(this.boundaries[0][0], this.tokens[0][0]), Math.max(this.boundaries[0][1], this.tokens[0][0]) ],
  17. [ Math.min(this.boundaries[1][0], this.tokens[0][1]), Math.max(this.boundaries[1][1], this.tokens[0][1]) ],
  18. ];
  19. for (let i =0; i < this.tokens.length -1; ++i)
  20. this.checkAndMove(i);
  21. this.visited[this.tokens[this.tokens.length -1][0] + 'x' +this.tokens[this.tokens.length -1][1]] = true;
  22. this.visitedCoord.push([this.tokens[this.tokens.length -1][0], this.tokens[this.tokens.length -1][1]]);
  23. }
  24. Rope.prototype.checkAndMove = function(headPos) {
  25. if (Math.abs(this.tokens[headPos][0] - this.tokens[headPos +1][0]) <= 1 &&
  26. Math.abs(this.tokens[headPos][1] - this.tokens[headPos+1][1]) <= 1)
  27. return;
  28. if (this.tokens[headPos +1][1] !== this.tokens[headPos][1])
  29. this.tokens[headPos +1][1] += (this.tokens[headPos +1][1] < this.tokens[headPos][1]) ? 1 : -1;
  30. if (this.tokens[headPos +1][0] !== this.tokens[headPos][0])
  31. this.tokens[headPos +1][0] += (this.tokens[headPos +1][0] < this.tokens[headPos][0]) ? 1 : -1;
  32. }
  33. const COLORS = [ '\033[39m', '\033[31m', '\033[32m', '\033[33m', '\033[34m', '\033[35m', '\033[36m' ]
  34. function showRope(arenaSize, ropeItems) {
  35. // clear screen
  36. for (let i =0; i < 5; ++i) console.log();
  37. // /clear screen
  38. console.log('\x1Bc');
  39. let item = ropeItems.shift();
  40. for (let py =0; py < arenaSize[1]; ++py) {
  41. let line = '';
  42. for (let px =0; px < arenaSize[0]; ++px) {
  43. if (item && item.x === px && item.y === py) {
  44. line += COLORS[item.color] + item.c + COLORS[0];
  45. item = ropeItems.shift();
  46. } else {
  47. line += '.';
  48. }
  49. }
  50. console.log(line);
  51. }
  52. }
  53. function prepShowRope(arenaSize, arenaShift, replayRope) {
  54. showRope(arenaSize, replayRope.tokens
  55. .map((i, index) => { return {
  56. x: i[0]+arenaShift[0],
  57. y: i[1]+arenaShift[1],
  58. c: '#',
  59. color: index+1 >= COLORS.length ? Math.ceil(Math.random() * (COLORS.length-1)) : (index +1)
  60. };}).concat(
  61. replayRope.visitedCoord.map(i => { return {
  62. x: i[0] + arenaShift[0],
  63. y: i[1] + arenaShift[1],
  64. c: '"',
  65. color: 0
  66. };})
  67. )
  68. .sort((a, b) => {
  69. if (a.x === b.x && a.y === b.y)
  70. return a.c === '"' ? 1 : -1;
  71. if (a.y === b.y)
  72. return a.x-b.x;
  73. return a.y-b.y;
  74. })
  75. .filter((value, index, self) => self.findIndex(i => i.x === value.x && i.y === value.y) === index));
  76. }
  77. function mSleep() {
  78. return new Promise(ok => setTimeout(ok, 90));
  79. }
  80. async function showReplay(rope, actions) {
  81. let arenaSize = [ rope.boundaries[0][1] - rope.boundaries[0][0] +1, rope.boundaries[1][1] - rope.boundaries[1][0] +1];
  82. let arenaShift = [ -rope.boundaries[0][0], -rope.boundaries[1][0] ];
  83. let replayRope = new Rope(rope.len);
  84. await prepShowRope(arenaSize, arenaShift, replayRope);
  85. for (let i of actions) {
  86. await mSleep();
  87. replayRope.applyMove(i);
  88. prepShowRope(arenaSize, arenaShift, replayRope);
  89. }
  90. }
  91. async function main() {
  92. const move = {
  93. 'U': [0, -1],
  94. 'D': [0, 1],
  95. 'L': [-1, 0],
  96. 'R': [1, 0]
  97. };
  98. let tokens = new Rope(1);
  99. let tokensPart2 = new Rope(10);
  100. let moveList = [];
  101. for await (let line of readline.createInterface({ input: process.stdin })) {
  102. if (!line || !line.length)
  103. continue;
  104. let reg = /([UDLR]) (\d+)/.exec(line);
  105. for (let i =0; i < reg[2]; ++i) {
  106. moveList.push(move[reg[1]]);
  107. tokens.applyMove(move[reg[1]]);
  108. tokensPart2.applyMove(move[reg[1]]);
  109. }
  110. }
  111. await showReplay(tokensPart2, moveList);
  112. console.log("Part 1: ", Object.keys(tokens.visited).length);
  113. console.log("Part 2: ", Object.keys(tokensPart2.visited).length);
  114. };
  115. (main());