main.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. Array.prototype.count = function(fnc) {
  2. return this.reduce((total, i, index) => fnc(i, index) ? total+1 : total, 0);
  3. }
  4. Array.prototype.countUnique = function(fnc) {
  5. return this.reduce((total, i, index) => (total.indexOf(i) === -1 && fnc(i, index)) ? total.concat(i):total, []).length;
  6. }
  7. const COLOR_RESET = '\x1B[39m';
  8. const CLEAR_SCR = '\033[2J';
  9. const COLOR_MAP = [ '\033[31m', '\033[32m', '\033[33m', '\033[35m', '\033[36m' ];
  10. const chars = ['@', '!', '$', '%', '+', '=', '?', '#'];
  11. function Elf(px, py) {
  12. this.px = px;
  13. this.py = py;
  14. this.nextX = 0;
  15. this.nextY = 0;
  16. this.moveList = [
  17. {
  18. cond: (surrounding) => !surrounding[0][0] && !surrounding[1][0] && !surrounding[2][0],
  19. action: (self) => { self.nextX = self.px; self.nextY = self.py -1; }
  20. },
  21. {
  22. cond: (surrounding) => !surrounding[0][2] && !surrounding[1][2] && !surrounding[2][2],
  23. action: (self) => { self.nextX = self.px; self.nextY = self.py +1; }
  24. },
  25. {
  26. cond: (surrounding) => !surrounding[0][0] && !surrounding[0][1] && !surrounding[0][2],
  27. action: (self) => { self.nextX = self.px -1; self.nextY = self.py; }
  28. },
  29. {
  30. cond: (surrounding) => !surrounding[2][0] && !surrounding[2][1] && !surrounding[2][2],
  31. action: (self) => { self.nextX = self.px +1; self.nextY = self.py; }
  32. }
  33. ];
  34. this.color = COLOR_MAP[Math.floor(Math.random() * COLOR_MAP.length)];
  35. this.c = chars[Math.floor(Math.random() * chars.length)];
  36. this.done = false;
  37. }
  38. Elf.prototype.round = function(pool, roundId) {
  39. const surrounding = pool.surround(this.px, this.py);
  40. if (surrounding._count === 0) {
  41. this.nextX = this.px;
  42. this.nextY = this.py;
  43. } else for (let i =0; i < 4; ++i) {
  44. if (this.moveList[(i + roundId) % this.moveList.length].cond(surrounding)) {
  45. this.moveList[(i + roundId) % this.moveList.length].action(this);
  46. return;
  47. }
  48. }
  49. this.nextX = this.px;
  50. this.nextY = this.py;
  51. }
  52. function ElfPool() {
  53. this.elves = [];
  54. this.boundaries = [[Infinity, -Infinity], [Infinity, -Infinity]];
  55. }
  56. ElfPool.prototype.dopush = function(px, py) {
  57. this.elves.push(new Elf(px, py));
  58. this.boundaries = [
  59. [Math.min(this.boundaries[0][0], px), Math.max(this.boundaries[0][1], px)],
  60. [Math.min(this.boundaries[1][0], py), Math.max(this.boundaries[1][1], py)]];
  61. }
  62. ElfPool.prototype.round = function(roundId) {
  63. for (let i of this.elves)
  64. i.round(this, roundId);
  65. if (this.elves.every(x => x.px === x.nextX && x.py === x.nextY)) return true;
  66. this.elves.forEach(i => i.done = false);
  67. this.boundaries = [[Infinity, -Infinity], [Infinity, -Infinity]];
  68. for (let i =0; i < this.elves.length; ++i) {
  69. if (!this.elves[i].done)
  70. for (let j =i +1; j < this.elves.length; ++j) {
  71. if (this.elves[i].nextX === this.elves[j].nextX &&
  72. this.elves[i].nextY === this.elves[j].nextY)
  73. this.elves[i].done = this.elves[j].done = true;
  74. }
  75. if (!this.elves[i].done) {
  76. this.elves[i].px = this.elves[i].nextX;
  77. this.elves[i].py = this.elves[i].nextY;
  78. this.boundaries = [
  79. [Math.min(this.boundaries[0][0], this.elves[i].px), Math.max(this.boundaries[0][1], this.elves[i].px)],
  80. [Math.min(this.boundaries[1][0], this.elves[i].py), Math.max(this.boundaries[1][1], this.elves[i].py)]];
  81. }
  82. }
  83. return false;
  84. }
  85. ElfPool.prototype.surround = function(px, py) {
  86. let result = [ [ false, false, false], [ false, false, false ], [ false, false, false ]];
  87. result._count = 0;
  88. for (let i = px-1; i <= px+1; ++i)
  89. for (let j=py -1; j <= py +1; ++j)
  90. if ((i !== px || j !== py) && this.elves.some(x => x.py === j && x.px === i)) {
  91. result[i-px+1][j-py+1] = true;
  92. result._count++;
  93. }
  94. return result;
  95. }
  96. ElfPool.prototype.display = async function() {
  97. let minY = this.boundaries[1][0];
  98. let minX = this.boundaries[0][0];
  99. let maxX = this.boundaries[0][1];
  100. let elvesRows = [];
  101. console.log(CLEAR_SCR);
  102. for (let i of this.elves) {
  103. if (!elvesRows[i.py - minY])
  104. elvesRows[i.py - minY] = [];
  105. elvesRows[i.py - minY].push({x: i.px, color: i.color, c: i.c });
  106. }
  107. for (let i =0; i < elvesRows.length; ++i) {
  108. _i = (elvesRows[i] || []).sort((a, b) => a.x-b.x);
  109. let line = '';
  110. for (let pos = minX; pos <= maxX; ++pos) {
  111. if (_i[0]?.x === pos) {
  112. line += _i[0].color+_i[0].c+COLOR_RESET;
  113. _i.shift();
  114. } else {
  115. line += '.';
  116. }
  117. }
  118. console.log(line);
  119. }
  120. return new Promise((ok, ko) => setTimeout(ok, 450));
  121. }
  122. let _main = (async()=>{
  123. let pool = new ElfPool();
  124. let lineIndex = 0;
  125. for await (let line of require('readline').createInterface({ input: process.stdin })) {
  126. for (let i =0; i < line.length; ++i)
  127. if (line[i] === '#')
  128. pool.dopush(i, lineIndex);
  129. ++lineIndex;
  130. }
  131. let i =0;
  132. let part1Solution = 0;
  133. while (true) {
  134. if (i === 10)
  135. part1Solution = ((pool.boundaries[0][1]-pool.boundaries[0][0]+1) * (pool.boundaries[1][1]-pool.boundaries[1][0]+1)) - pool.elves.length;
  136. if (pool.round(i))
  137. break;
  138. ++i;
  139. await pool.display();
  140. }
  141. await pool.display();
  142. console.log("Part 1: ", part1Solution);
  143. console.log("Part 2: ", ++i);
  144. });
  145. // response < 4241
  146. // > 4076
  147. _main();