epidemic.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. const WIDTH = 8;
  2. const HEIGHT = 8;
  3. // https://www.coding-dojo-silesia.pl/golf
  4. function point_free(x, y, people) {
  5. const pLength = people.length;
  6. for (let i = 0; i < pLength; i++) {
  7. const person = people[i];
  8. if (x === person.x && y === person.y)
  9. return false;
  10. }
  11. return true;
  12. }
  13. function check_neighborhood(person, people) {
  14. const pLength = people.length;
  15. for (let i = 0; i < pLength; i++) {
  16. const otherPerson = people[i];
  17. if ((otherPerson.x >= person.x-1 && otherPerson.x <= person.x+1) && (otherPerson.y >= person.y-1 && otherPerson.y <= person.y+1) && otherPerson.s === 'S') {
  18. return true;
  19. }
  20. }
  21. return false;
  22. }
  23. function next_iteration(people) {
  24. people.forEach(function(person, _) { // iterate in a sequence
  25. cure(person);
  26. if (person.s === 'S') person.i++;
  27. person.n = gen_n(person.n);
  28. [new_x, new_y] = gen_new_cords(person);
  29. if (point_free(new_x, new_y, people) && person.q === 0) {
  30. person.x = new_x;
  31. person.y = new_y;
  32. }
  33. if (person.s === 'H' && check_neighborhood(person, people)) {
  34. // https://en.wikipedia.org/wiki/Moore_neighborhood
  35. person.s = 'S';
  36. }
  37. });
  38. return people;
  39. }
  40. function cure(person) {
  41. if (person.s === 'S' && person.i > 13) {
  42. person.s = 'R';
  43. person.i = 1;
  44. }
  45. }
  46. function gen_n(n) {
  47. n ^= n << BigInt(13);
  48. n ^= n >> BigInt(17);
  49. n ^= n << BigInt(5);
  50. return n % BigInt(1 << 30);
  51. }
  52. function gen_new_cords(person) {
  53. x = person.x;
  54. y = person.y;
  55. switch(person.n % BigInt(4)) {
  56. case BigInt(0): x++; break;
  57. case BigInt(1): x--; break;
  58. case BigInt(2): y++; break;
  59. case BigInt(3): y--; break;
  60. }
  61. // wrap points, like in pacman game
  62. if (x >= WIDTH) {
  63. x -= WIDTH;
  64. } else if (x < 0) {
  65. x += WIDTH;
  66. }
  67. if (y >= HEIGHT) {
  68. y -= HEIGHT;
  69. } else if (y < 0) {
  70. y += HEIGHT;
  71. }
  72. return [x, y];
  73. }
  74. function get_people(peopleString) {
  75. peopleUnparsed = peopleString.split(",");
  76. let people = [];
  77. peopleUnparsed.forEach(function(item, _) {
  78. let person = {};
  79. person.x = Number(item[0]);
  80. person.y = Number(item[1]);
  81. person.s = item[2];
  82. person.q = Number(item[3]);
  83. person.n = BigInt((person.x << 2) ^ 7 * (person.y << 3) ^ 5);
  84. person.i = 1;
  85. people.push(person);
  86. });
  87. return people;
  88. }
  89. function print_field(P) {
  90. for (let i = 0; i < HEIGHT; i++) {
  91. let string = '';
  92. for (let j = 0; j < WIDTH; j++) {
  93. const person = P.find(p => p.x === j && p.y === i);
  94. if (person === undefined)
  95. string += '.';
  96. else
  97. string += person.s;
  98. }
  99. console.log(string);
  100. }
  101. }
  102. function main() {
  103. const iterations = process.argv[2];
  104. const peopleUnparsed = process.argv[3];
  105. let people = get_people(peopleUnparsed);
  106. for (let i = 0; i < iterations; i++) {
  107. people = next_iteration(people);
  108. }
  109. print_field(people);
  110. }
  111. main();