automata.js 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. const canvas = document.getElementById('canvas');
  2. canvas.width = window.innerWidth - 50;
  3. canvas.height = window.innerHeight - 50;
  4. const canvwidth = canvas.width,
  5. canvheight = canvas.height,
  6. ctx = canvas.getContext('2d');
  7. function randIndivC(a = 0, b = 255) {
  8. return Math.floor(Math.random() * (b-a) + a);
  9. }
  10. function cts(c) {
  11. const r = c.r < 16 ? '0' + c.r.toString(16) : c.r.toString(16),
  12. g = c.g < 16 ? '0' + c.g.toString(16) : c.g.toString(16),
  13. b = c.b < 16 ? '0' + c.b.toString(16) : c.b.toString(16);
  14. return '#' + r + g + b;
  15. }
  16. function mixedColor(base) {
  17. let randr = Math.floor(Math.random() * 200 + 55),
  18. randg = Math.floor(Math.random() * 200 + 55),
  19. randb = Math.floor(Math.random() * 200 + 55);
  20. if( base ) {
  21. randr = Math.floor((base.r + randr) / 2);
  22. randg = Math.floor((base.g + randg) / 2);
  23. randb = Math.floor((base.b + randb) / 2);
  24. }
  25. return cts({r:randr, g:randg, b:randb});
  26. }
  27. function primaryOrSecondary() {
  28. const t = Math.random(),
  29. w = Math.floor(Math.random() * 3);
  30. if( t < 0.45 ) {
  31. const r = w === 0 ? 255 : 0,
  32. g = w === 1 ? 255 : 0,
  33. b = w === 2 ? 255 : 0;
  34. return {r, g, b};
  35. }
  36. else if( t < 0.9 ) {
  37. const r = w !== 0 ? 255 : 0,
  38. g = w !== 1 ? 255 : 0,
  39. b = w !== 2 ? 255 : 0;
  40. return {r, g, b};
  41. }
  42. else {
  43. const r = randIndivC(100, 255),
  44. g = randIndivC(100, 255),
  45. b = randIndivC(100, 255);
  46. return {r, g, b};
  47. }
  48. }
  49. function spot(x, y, colour) {
  50. ctx.save();
  51. ctx.fillStyle = colour;
  52. ctx.fillRect(x, y, 10, 10);
  53. ctx.restore();
  54. }
  55. function generateInitialRow(lx = canvwidth / 10 + 1) {
  56. const row = [];
  57. for( let i = 0; i < lx; i++ ) {
  58. row.push( Math.random() < 0.5 ? false : true );
  59. }
  60. return row;
  61. }
  62. const rules = {
  63. "111": false,
  64. "110": true,
  65. "101": true,
  66. "100": false,
  67. "011": true,
  68. "010": true,
  69. "001": true,
  70. "000": false,
  71. };
  72. function applyRules(first, second, third) {
  73. return rules[ [+first, +second, +third].join('') ];
  74. }
  75. function addRow(field) {
  76. if( !field.length ) {
  77. return field;
  78. }
  79. if( field[0].length < 3 ) {
  80. return field;
  81. }
  82. const last = field[ field.length - 1 ],
  83. newRow = last.map(function iter(val, ind) {
  84. const first = last[ind - 1] || 0,
  85. second = val,
  86. third = last[ind + 1] || 0;
  87. return applyRules(first, second, third);
  88. });
  89. field.push(newRow);
  90. return field;
  91. }
  92. function drawRow(row, y) {
  93. row.forEach(function spotter(val, ind) {
  94. if( val ) {
  95. const c = mixedColor(primaryOrSecondary());
  96. spot(ind * 10, y, c);
  97. }
  98. });
  99. }
  100. function step(field) {
  101. requestAnimationFrame(descend.bind(null, field));
  102. }
  103. function descend(field) {
  104. const n = field.length - 1;
  105. drawRow(field[n], n * 10);
  106. field = addRow(field);
  107. if( n * 10 < canvheight ) {
  108. setTimeout(step, 100, field);
  109. }
  110. else {//TODO: remove this clause after tests
  111. console.log('STOP!');
  112. }
  113. }
  114. step([ generateInitialRow() ]);