main.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. function readAll(cb) {
  2. require("fs").readFile('./input', 'utf8', (err, data) => {
  3. var world = new World();
  4. data.split("\n").forEach(line => {
  5. if (!line)
  6. return;
  7. var numbers = line.match(/(\d+)/g).map(i => parseInt(i));
  8. if (line.charAt(0) == 'x')
  9. world.addData(numbers[0], numbers[0], numbers[1], numbers[2], 'x');
  10. else
  11. world.addData(numbers[1], numbers[2], numbers[0], numbers[0], 'x');
  12. });
  13. cb(world);
  14. });
  15. }
  16. function World() {
  17. this.data = {};
  18. this.sources = [[ 500, 0 ]];
  19. this.minX = 500;
  20. this.maxX = 500;
  21. this.minY = 0;
  22. this.maxY = 0;
  23. }
  24. World.prototype.addData = function(x1, x2, y1, y2, type) {
  25. while (y1 <= y2) {
  26. for (var j = x1; j <= x2; ++j) {
  27. this.data[y1] = this.data[y1] || {};
  28. this.data[y1][j] = type;
  29. }
  30. ++y1;
  31. }
  32. this.minX = Math.min(x1, this.minX);
  33. this.maxX = Math.max(x2, this.maxX);
  34. if (type == 'x') {
  35. this.minY = Math.min(y1, this.minY);
  36. this.maxY = Math.max(y2, this.maxY);
  37. }
  38. }
  39. World.prototype.getChar = function(x, y, defaultValue) {
  40. return this.data[y] ? this.data[y][x] || defaultValue : defaultValue;
  41. }
  42. World.prototype.isEmpty = function(x, y) {
  43. var c = this.getChar(x, y, false);
  44. return !c || c == '|';
  45. }
  46. World.prototype.nextClay = function(x, y, direction) {
  47. for (; x >= this.minX && x <= this.maxX; x += direction) {
  48. if (this.isEmpty(x, y +1))
  49. return false;
  50. if (!this.isEmpty(x, y))
  51. return x;
  52. }
  53. return false;
  54. }
  55. World.prototype.trySettle = function(minX, maxX, y) {
  56. if (minX === false || maxX === false || minX === maxX)
  57. return false;
  58. this.addData(minX +1, maxX -1, y, y, '~');
  59. return true;
  60. }
  61. World.prototype.water = function() {
  62. var x = this.sources[0][0],
  63. y = this.sources[0][1];
  64. while (this.isEmpty(x, y +1) && y <= this.maxY)
  65. ++y;
  66. if (y <= this.maxY) {
  67. var minX = this.nextClay(x, y, -1),
  68. maxX = this.nextClay(x, y, +1);
  69. if (this.trySettle(minX, maxX, y))
  70. return;
  71. var found = false;
  72. for (var tmp = x; this.isEmpty(tmp, y); ++tmp) {
  73. this.addData(tmp, tmp, y, y, '|');
  74. if (this.isEmpty(tmp, y +1)) {
  75. this.sources.push([ tmp, y ]);
  76. break;
  77. }
  78. }
  79. for (var tmp = x; this.isEmpty(tmp, y); --tmp) {
  80. this.addData(tmp, x, y, y, '|');
  81. if (this.isEmpty(tmp, y +1)) {
  82. this.addData(tmp, x, y, y, '|');
  83. this.sources.push([ tmp, y ]);
  84. break;
  85. }
  86. }
  87. }
  88. this.addData(x, x, this.sources[0][1], y, '|');
  89. this.sources.splice(0, 1);
  90. }
  91. World.prototype.countWater = function() {
  92. var count = { settled: 0, unsettled: 0 };
  93. for (var i in this.data)
  94. if (i != 0)
  95. for (var j in this.data[i])
  96. switch (this.data[i][j]) {
  97. case '~':
  98. ++count.settled;
  99. break;
  100. case '|':
  101. ++count.unsettled;
  102. break;
  103. }
  104. count.total = count.settled +count.unsettled;
  105. return count;
  106. }
  107. World.prototype.print = function() {
  108. for (var i =this.minY; i <= this.maxY; ++i) {
  109. for (var j =this.minX; j <= this.maxX; ++j)
  110. process.stdout.write(this.getChar(j, i, ' '));
  111. process.stdout.write("\n");
  112. }
  113. }
  114. function run() {
  115. readAll(world => {
  116. while (world.sources.length)
  117. world.water();
  118. //world.print();
  119. console.log("Water cell: ", world.countWater());
  120. });
  121. }
  122. run();