Advertisement
Guest User

2048 Max

a guest
May 17th, 2025
605
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.46 KB | None | 0 0
  1. (function () {
  2. const directionConfig = [
  3. { key: 'ArrowLeft', rotations: 0 },
  4. { key: 'ArrowDown', rotations: 1 },
  5. { key: 'ArrowRight', rotations: 2 },
  6. { key: 'ArrowUp', rotations: 3 },
  7. ];
  8.  
  9. function clone(arr) {
  10. return arr.slice();
  11. }
  12.  
  13. class AI {
  14. constructor() {
  15. this.best_operation = -1;
  16. this.grid = Array(16);
  17. this.node = 0;
  18. this.max_depth = 3;
  19. }
  20.  
  21. MoveLeft(s) {
  22. let k = 0, base = 0, score = 0;
  23. const result = new Array(16).fill(0);
  24. for (let i = 4; i <= 16; i += 4) {
  25. while (k < i) {
  26. if (s[k] === 0) {
  27. ++k;
  28. continue;
  29. }
  30. if (k + 1 < i && s[k] === s[k + 1]) {
  31. result[base++] = s[k] * 2;
  32. score += s[k] * 2;
  33. k += 2;
  34. } else {
  35. result[base++] = s[k++];
  36. }
  37. }
  38. while (base < i) result[base++] = 0;
  39. }
  40. return [result, score];
  41. }
  42.  
  43. Rotate(s) {
  44. return [
  45. s[12], s[8], s[4], s[0],
  46. s[13], s[9], s[5], s[1],
  47. s[14], s[10], s[6], s[2],
  48. s[15], s[11], s[7], s[3]
  49. ];
  50. }
  51.  
  52. Estimate(s) {
  53. let diff = 0, sum = 0;
  54. for (let i = 0; i < 16; ++i) {
  55. sum += s[i];
  56. if (i % 4 !== 3) diff += Math.abs(s[i] - s[i + 1]);
  57. if (i < 12) diff += Math.abs(s[i] - s[i + 4]);
  58. }
  59. return (sum * 4 - diff) * 2;
  60. }
  61.  
  62. Search(s, depth) {
  63. this.node++;
  64. if (depth >= this.max_depth) return this.Estimate(s);
  65. let best = -1e30;
  66. for (let i = 0; i < 4; ++i) {
  67. const [t, score] = this.MoveLeft(s);
  68. const same = t.every((v, j) => v === s[j]);
  69. if (!same) {
  70. let temp = 0;
  71. let empty_slots = 0;
  72. for (let j = 0; j < 16; ++j) {
  73. if (t[j] === 0) {
  74. const t2 = clone(t); t2[j] = 2;
  75. temp += this.Search(t2, depth + 1) * 0.9;
  76. const t4 = clone(t); t4[j] = 4;
  77. temp += this.Search(t4, depth + 1) * 0.1;
  78. empty_slots++;
  79. }
  80. }
  81. temp = empty_slots ? temp / empty_slots : -1e10;
  82. if (score + temp > best) {
  83. best = score + temp;
  84. if (depth === 0) this.best_operation = i;
  85. }
  86. }
  87. if (i !== 3) s = this.Rotate(s);
  88. }
  89. return best;
  90. }
  91.  
  92. SetTile(x, y, v) {
  93. this.grid[x + y * 4] = v;
  94. }
  95.  
  96. StartSearch() {
  97. this.node = 0;
  98. this.max_depth = 3;
  99. while (true) {
  100. this.node = 0;
  101. this.Search(this.grid.slice(), 0);
  102. if (this.node >= 10000 || this.max_depth >= 8) break;
  103. this.max_depth++;
  104. }
  105. }
  106. }
  107.  
  108. function getBoardState() {
  109. const grid = Array(16).fill(0);
  110. const tiles = document.querySelectorAll('div.absolute');
  111.  
  112. for (const tile of tiles) {
  113. const span = tile.querySelector('span');
  114. if (!span) continue;
  115. const val = parseInt(span.innerText.trim());
  116. if (isNaN(val)) continue;
  117.  
  118. const style = tile.getAttribute('style') || '';
  119. const topMatch = style.match(/top:\s*calc\((\d+)%\s*\+\s*[\d.]+rem\)/);
  120. const leftMatch = style.match(/left:\s*calc\((\d+)%\s*\+\s*[\d.]+rem\)/);
  121.  
  122. if (!topMatch || !leftMatch) continue;
  123. const row = parseInt(topMatch[1]) / 25;
  124. const col = parseInt(leftMatch[1]) / 25;
  125. const index = row * 4 + col;
  126. if (index >= 0 && index < 16) {
  127. grid[index] = val;
  128. }
  129. }
  130.  
  131. return grid;
  132. }
  133.  
  134. function sendKey(key) {
  135. document.dispatchEvent(new KeyboardEvent('keydown', { key, bubbles: true }));
  136. }
  137.  
  138. function isValidMove(original, dirIndex, moveFn, rotateFn) {
  139. let test = original.slice();
  140. for (let i = 0; i < directionConfig[dirIndex].rotations; i++) {
  141. test = rotateFn(test);
  142. }
  143. const [moved] = moveFn(test);
  144. return !moved.every((v, j) => v === test[j]);
  145. }
  146.  
  147. let suicideMode = false;
  148. let suicideToggle = 0;
  149.  
  150. function showSuicideBanner() {
  151. const existing = document.getElementById('suicide-banner');
  152. if (existing) return;
  153.  
  154. const banner = document.createElement('div');
  155. banner.id = 'suicide-banner';
  156. banner.textContent = '💀 Suicide mode ON';
  157. banner.style.cssText = `
  158. position: fixed;
  159. top: 10px;
  160. right: 10px;
  161. background: rgba(0,0,0,0.7);
  162. color: #fff;
  163. padding: 8px 14px;
  164. font-size: 16px;
  165. font-family: sans-serif;
  166. border-radius: 6px;
  167. z-index: 9999;
  168. pointer-events: none;
  169. `;
  170. document.body.appendChild(banner);
  171. }
  172.  
  173. function makeMove() {
  174. const grid = getBoardState();
  175. const ai = new AI();
  176.  
  177. if (suicideMode) {
  178. const up = 3;
  179. const down = 1;
  180. const left = 0;
  181. const right = 2;
  182.  
  183. const canUp = isValidMove(grid, up, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai));
  184. const canDown = isValidMove(grid, down, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai));
  185.  
  186. if (canUp || canDown) {
  187. let moveIndex = suicideToggle === 0 ? up : down;
  188. suicideToggle = 1 - suicideToggle;
  189.  
  190. if (isValidMove(grid, moveIndex, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))) {
  191. sendKey(directionConfig[moveIndex].key);
  192. return;
  193. }
  194.  
  195. moveIndex = moveIndex === up ? down : up;
  196. if (isValidMove(grid, moveIndex, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))) {
  197. sendKey(directionConfig[moveIndex].key);
  198. return;
  199. }
  200.  
  201. return;
  202. }
  203.  
  204. if (isValidMove(grid, left, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))) {
  205. sendKey(directionConfig[left].key);
  206. return;
  207. }
  208. if (isValidMove(grid, right, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))) {
  209. sendKey(directionConfig[right].key);
  210. return;
  211. }
  212.  
  213. console.warn("🪦 No moves left. Game over.");
  214. return;
  215. }
  216.  
  217. // обычный AI
  218. for (let y = 0; y < 4; ++y) {
  219. for (let x = 0; x < 4; ++x) {
  220. ai.SetTile(x, y, grid[y * 4 + x]);
  221. }
  222. }
  223.  
  224. ai.StartSearch();
  225. let best = ai.best_operation;
  226.  
  227. if (best < 0 || !isValidMove(grid, best, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))) {
  228. best = directionConfig.findIndex((_, i) =>
  229. isValidMove(grid, i, ai.MoveLeft.bind(ai), ai.Rotate.bind(ai))
  230. );
  231. }
  232.  
  233. if (best < 0) {
  234. console.warn('❌ No valid move. Stopping AI.');
  235. return;
  236. }
  237.  
  238. sendKey(directionConfig[best].key);
  239. }
  240.  
  241. function playGame() {
  242. console.log('🧠 AI started. Suicide mode will trigger in 60 seconds.');
  243.  
  244. // Активировать суицид через минуту
  245. setTimeout(() => {
  246. suicideMode = true;
  247. console.warn('💀 Suicide mode ACTIVATED (after 60 seconds)');
  248. showSuicideBanner();
  249. }, 60000);
  250.  
  251. function step() {
  252. try {
  253. makeMove();
  254. } catch (err) {
  255. console.error('AI failed:', err);
  256. return;
  257. }
  258. const delay = 500 + Math.random() * 1000;
  259. setTimeout(step, delay);
  260. }
  261. step();
  262. }
  263.  
  264. playGame();
  265. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement