telegram Mineroobot solver

resolve telegram mineroobot automatically

  1. // ==UserScript==
  2. // @name telegram Mineroobot solver
  3. // @version 0.0.1
  4. // @include https://web.telegram.org/*
  5. // @description resolve telegram mineroobot automatically
  6. // @namespace mineroobot-solver.mmis1000.me
  7. // @run-at document-start
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
  12.  
  13. /**
  14. * Converts an HSL color value to RGB. Conversion formula
  15. * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
  16. * Assumes h, s, and l are contained in the set [0, 1] and
  17. * returns r, g, and b in the set [0, 255].
  18. *
  19. * @param Number h The hue
  20. * @param Number s The saturation
  21. * @param Number l The lightness
  22. * @return Array The RGB representation
  23. */
  24.  
  25. function hslToRgb(h, s, l) {
  26. var r, g, b;
  27. if (s == 0) {
  28. r = g = b = l; // achromatic
  29.  
  30. }
  31. else {
  32. var hue2rgb = function hue2rgb(p, q, t) {
  33. if (t < 0) t += 1;
  34. if (t > 1) t -= 1;
  35. if (t < 1 / 6) return p + (q - p) * 6 * t;
  36. if (t < 1 / 2) return q;
  37. if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
  38. return p;
  39. };
  40.  
  41. var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
  42. var p = 2 * l - q;
  43. r = hue2rgb(p, q, h + 1 / 3);
  44. g = hue2rgb(p, q, h);
  45. b = hue2rgb(p, q, h - 1 / 3);
  46. }
  47. return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
  48. }
  49.  
  50. /**
  51. * @param {number} r range between 0-256
  52. * @param {number} g range between 0-256
  53. * @param {number} b range between 0-256
  54. * @return {string}
  55. */
  56. function rgbColor(r, g, b) {
  57. // return `\u001b[${bg ? 48 : 38};2;${r};${g};${b}m`;
  58. var str = ((r << 16) + (g << 8) + b).toString(16);
  59. while (str.length < 6) str = '0' + str;
  60. return '#' + str;
  61. }
  62.  
  63. /**
  64. * @param {number} h range between 0-1
  65. * @param {number} s range between 0-1
  66. * @param {number} l range between 0-1
  67. * @return {string}
  68. */
  69. function hslColor(h, s, l) {
  70. var [r, g, b] = hslToRgb(h, s, l);
  71. return rgbColor(r, g, b);
  72. }
  73.  
  74. /**
  75. * @param {number} m total
  76. * @param {number} n selected
  77. * @return {number}
  78. */
  79. function c(m, n) {
  80. var val = 1;
  81.  
  82. for (let temp = m; temp > m - n; temp--) {
  83. val = val * temp / (temp - m + n);
  84. }
  85. return val;
  86. }
  87.  
  88. /**
  89. * @param {number} w width
  90. * @param {number} h height
  91. * @return {function}
  92. */
  93. function p(w, h) {
  94. return function ptr(x, y) {
  95. var pos = {x, y};
  96. pos.next = function () {
  97. if (x < 0 || x >= w || y < 0 && y >= h) {
  98. return null;
  99. }
  100.  
  101. // highest valid pointer
  102. if (x >= w - 1 && y >= h - 1) {
  103. return null;
  104. }
  105.  
  106. if (x < w - 1) {
  107. return ptr(x + 1, y);
  108. } else {
  109. return ptr(0, y + 1);
  110. }
  111. };
  112.  
  113. if (x >= 0 && x < w && y >= 0 && y < h) {
  114. pos.offset = x + y * w;
  115. } else {
  116. pos.offset = null;
  117. }
  118.  
  119. pos.neighbors = function() {
  120. return [
  121. ptr(x - 1, y - 1),
  122. ptr(x, y - 1),
  123. ptr(x + 1, y - 1),
  124. ptr(x - 1, y),
  125. ptr(x + 1, y),
  126. ptr(x - 1, y + 1),
  127. ptr(x, y + 1),
  128. ptr(x + 1, y + 1)
  129. ];
  130. };
  131.  
  132. return pos;
  133. };
  134. }
  135.  
  136. /**
  137. * @param {number} w width
  138. * @param {number} h height
  139. * @param (any} init init value
  140. * @param {any} outBoundVal value access out of table bound
  141. * @return {function}
  142. */
  143. function t(w, h, init, outBoundVal) {
  144. var data = [];
  145. var Ptr = p(w, h);
  146.  
  147. function table(ptr, val) {
  148. if (val != null) {
  149. if (ptr.offset != null) {
  150. data[ptr.offset] = val;
  151. }
  152. } else {
  153. if (ptr.offset != null) {
  154. return data[ptr.offset];
  155. } else {
  156. return outBoundVal;
  157. }
  158. }
  159. }
  160.  
  161. table.w = w;
  162. table.h = h;
  163. table.data = data;
  164.  
  165. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  166. data[ptr.offset] = init;
  167. }
  168.  
  169. table.clone = function () {
  170. var newTable = t(w, h, init, outBoundVal);
  171. var ptr = p(w, h)(0, 0);
  172.  
  173. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  174. newTable(ptr, table(ptr));
  175. }
  176.  
  177. return newTable;
  178. };
  179.  
  180. //regex must has global flag
  181. table.countRegex = function(regex) {
  182. var counter = 0;
  183.  
  184. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  185. if (regex.test(table(ptr))) {
  186. counter += 1;
  187. }
  188. }
  189.  
  190. return counter;
  191. };
  192.  
  193. table.count = function (val) {
  194. var counter = 0;
  195.  
  196. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  197. if (table(ptr) === val) {
  198. counter += 1;
  199. }
  200. }
  201.  
  202. return counter;
  203. };
  204.  
  205. table.toString = function (seperator) {
  206. var res = [];
  207. seperator = seperator == null ? ' ,' : seperator;
  208. for (var i = 0; i < data.length; i += w) {
  209. res.push(data.slice(i, i + w).join(seperator));
  210. }
  211.  
  212. return res.join('\r\n');
  213. };
  214.  
  215. return table;
  216. }
  217.  
  218. /**
  219. * @param {number} w width
  220. * @param {number} h height
  221. * @param (number} totalMines total mines
  222. * @param {string} str the game board
  223. * @return {function}
  224. */
  225. function resolve(w, h, totalMines, str) {
  226. /*
  227. '-': unknown
  228. 'x': empty
  229. 'o': bomb
  230. '0' - '9': count near by
  231. */
  232. var table = t(w, h, '-', 'x');
  233.  
  234. // init
  235. var Ptr = p(w, h);
  236. var ptr = Ptr(0, 0);
  237. var temp = str.replace(/[\r\n]/g, '');
  238.  
  239. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  240. table(ptr, temp.slice(ptr.offset, ptr.offset + 1));
  241. }
  242.  
  243. // found slot with no no number neighbors
  244. // true: has neighbor
  245. // false: no neighbor
  246. var mask = t(w, h, false, false);
  247.  
  248. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  249. let neightborPtrs = ptr.neighbors();
  250. mask(ptr, neightborPtrs.reduce(function (prev, ptr) {
  251. var val = table(ptr);
  252. return prev || !!val.match(/[0-9]/);
  253. }, false));
  254. }
  255.  
  256. var unPredicableSlots = mask.count(false);
  257. var totalFoundMines = table.count('o');
  258. var minesLeft = totalMines - totalFoundMines;
  259.  
  260. // situation when there are n mines drops in unprediactable area;
  261. var unPredicableMultiplier = {};
  262. var combinationCounts = {};
  263. var guessTables = [];
  264.  
  265. for (let unPredicableCount = minesLeft; unPredicableCount >= 0; unPredicableCount--) {
  266. unPredicableMultiplier[unPredicableCount] = c(unPredicableSlots, unPredicableCount);
  267. combinationCounts[unPredicableCount] = 0;
  268. guessTables[unPredicableCount] = t(w, h, 0, 0);
  269. }
  270.  
  271. // solve until there is no other possible combination
  272. function solve(ptr, currentTable, minesLeft) {
  273. // move until guessable Slot
  274. while (ptr && (!mask(ptr) || currentTable(ptr) !== '-')) {
  275. ptr = ptr.next();
  276. }
  277.  
  278. if (!ptr && minesLeft >= 0) {
  279. // found a possible solution;
  280. // console.log('hit #' + combinationCounts[minesLeft] + '\r\n' + currentTable.toString());
  281. combinationCounts[minesLeft] += 1;
  282. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  283. if (mask(ptr)) {
  284. var guessTable = guessTables[minesLeft];
  285. if (!guessTable) {
  286. console.log(minesLeft);
  287. return;
  288. }
  289. if (currentTable(ptr) === 'o') {
  290. guessTable(ptr, guessTable(ptr) + 1);
  291. }
  292. }
  293. }
  294.  
  295. return;
  296. }
  297.  
  298. // check if this slot can be mine or not be mine
  299. // and abort the branch if that branch failed;
  300. var neightbors = ptr.neighbors();
  301. var canBeMine = true;
  302. var canBeEmpty = true;
  303.  
  304. neightbors.forEach(function (neightbor) {
  305. if (currentTable(neightbor).match(/[0-9\s]/)) {
  306. var neightborsOfNeighbor = neightbor.neighbors();
  307. var number = currentTable(neightbor);
  308. number = number === ' ' ? 0 : parseInt(number, 10);
  309.  
  310. var minesNearBy = neightborsOfNeighbor.reduce(function (prev, curr) {
  311. if (currentTable(curr) === 'o') {
  312. return prev + 1;
  313. } else {
  314. return prev;
  315. }
  316. }, 0);
  317.  
  318. var emptyNearBy = neightborsOfNeighbor.reduce(function (prev, curr) {
  319. if (currentTable(curr).match(/[0-9x\s]/)) {
  320. return prev + 1;
  321. } else {
  322. return prev;
  323. }
  324. }, 0);
  325.  
  326. var unknownNearBy = 8 - minesNearBy - emptyNearBy;
  327.  
  328. var minesToPlace = number - minesNearBy;
  329. if (minesToPlace === unknownNearBy) canBeEmpty = false;
  330. if (minesToPlace === 0) canBeMine = false;
  331. }
  332. });
  333.  
  334. if (canBeMine && minesLeft !== 0) {
  335. let newTable = currentTable.clone();
  336. newTable(ptr, 'o');
  337. solve(ptr.next(), newTable, minesLeft - 1);
  338. // we still have mine, and we can put mine here
  339. }
  340.  
  341. if (canBeEmpty) {
  342. let newTable = currentTable.clone();
  343. newTable(ptr, 'x');
  344. solve(ptr.next(), newTable, minesLeft);
  345. }
  346.  
  347. // if (!canBeMine && !canBeEmpty) {
  348. // console.log('badGuess\r\n' + currentTable)
  349. // }
  350. }
  351.  
  352. solve(Ptr(0, 0), table.clone(), minesLeft);
  353.  
  354. // console.log(unPredicableMultiplier)
  355. // console.log(combinationCounts)
  356. // console.log(guessTables.map(function (table, i) {
  357. // return '# guessTable ' + i + '\r\n' + table.toString();
  358. // }).join('\r\n'))
  359.  
  360. // sum up the possibility
  361. var finalBoardCount = 0;
  362. var finalBoard = t(w, h, 0, 0);
  363.  
  364. for (let unPredicableCount = minesLeft; unPredicableCount >= 0; unPredicableCount--) {
  365. finalBoardCount += (unPredicableMultiplier[unPredicableCount] * combinationCounts[unPredicableCount]);
  366.  
  367. // init possibility for unPredicable slot;
  368. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  369. if (!mask(ptr)) {
  370. guessTables[unPredicableCount](ptr, combinationCounts[unPredicableCount] * (unPredicableCount / unPredicableSlots));
  371. }
  372. }
  373.  
  374. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  375. finalBoard(ptr, finalBoard(ptr) + guessTables[unPredicableCount](ptr) * unPredicableMultiplier[unPredicableCount]);
  376. }
  377. }
  378.  
  379. if (finalBoardCount === 0) {
  380. throw new Error('invalid board');
  381. }
  382.  
  383. function formatToPercent(num, small) {
  384. small = small || 2;
  385. var val = parseFloat(num * 100).toFixed(small) + "%";
  386. // xxx.<small>
  387. var totalLength = small + 5;
  388. while (val.length < totalLength) {
  389. val = ' ' + val;
  390. }
  391. return val;
  392. }
  393.  
  394. var finalBoardPercent = t(w, h, "", "");
  395.  
  396. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  397. finalBoard(ptr, finalBoard(ptr) / finalBoardCount);
  398. finalBoardPercent(ptr, formatToPercent(finalBoard(ptr)));
  399.  
  400. if (table(ptr) !== '-') {
  401. finalBoard(ptr, -1);
  402. finalBoardPercent(ptr, ' <N/A>');
  403. }
  404. }
  405.  
  406. var map = {
  407. '-8': '░',
  408. '0': '□',
  409. '1': '▁',
  410. '2': '▂',
  411. '3': '▃',
  412. '4': '▄',
  413. '5': '▅',
  414. '6': '▆',
  415. '7': '▇',
  416. '8': '█'
  417. };
  418.  
  419. var visualBoard = t(w, h, " ", " ");
  420. // var visualColorBoard = t(w, h, " ", " ");
  421.  
  422. for (let ptr = Ptr(0, 0); ptr; ptr = ptr.next()) {
  423. visualBoard(ptr, map[Math.floor(finalBoard(ptr) * 8)]);
  424. // if(finalBoard(ptr) >= 0) {
  425. // visualColorBoard(ptr, hslColor(finalBoard(ptr) / 3, 1, 0.5, true) + ' ' + table(ptr) + '\u001b[0m');
  426. // } else {
  427. // visualColorBoard(ptr, hslColor(2 / 3, 1, 0.5, true) + ' ' + table(ptr) + '\u001b[0m' );
  428. // }
  429. }
  430.  
  431. console.log('board with ' + totalMines + ' mines');
  432. console.log(table.toString());
  433. console.log('result is');
  434. console.log(finalBoardPercent.toString());
  435. console.log(visualBoard.toString(' '));
  436. // console.log(visualColorBoard.toString(''));
  437. return finalBoard;
  438. }
  439.  
  440. var map = {
  441. '?': 'o',
  442. '?️': 'o',
  443. '1\u20E3': '1',
  444. '2\u20E3': '2',
  445. '3\u20E3': '3',
  446. '4\u20E3': '4',
  447. '5\u20E3': '5',
  448. '6\u20E3': '6',
  449. '7\u20E3': '7',
  450. '8\u20E3': '8',
  451. '9\u20E3': '9',
  452. ' ': '0',
  453. '⬜️': '-',
  454. '?': 'o',
  455. };
  456.  
  457. var ended = /^? Winner\:/g;
  458.  
  459. function check() {
  460. var historyRoot = $('.im_history_messages_peer:visible');
  461. var topScope = historyRoot.scope();
  462. var messages = topScope.peerHistory.messages;
  463. var boardMesssages = messages.filter((m)=> m.viaBotID === 223493268);
  464. // interate through messages to find board
  465. // and find board element by id
  466. var messageEls = historyRoot.find('.im_content_message_wrap');
  467. boardMesssages.forEach((message)=>{
  468. var messageEl = messageEls.filter((i, el)=>{
  469. return $(el).scope().historyMessage.$$hashKey === message.$$hashKey;
  470. });
  471.  
  472. if (messageEl.length > 0 && !messageEl.get(0).watching) {
  473. track(messageEl.scope(), messageEl);
  474. }
  475. });
  476. }
  477.  
  478. if (typeof unsafeWindow !== 'undefined') {
  479. window.check = unsafeWindow.check = check;
  480. } else {
  481. window.check = check;
  482. }
  483.  
  484.  
  485. function track($scope, $el) {
  486. var reply_markup = $scope.historyMessage.reply_markup.rows.map((i)=>i.buttons);
  487. var buttonEls = $el.find('.reply_markup_button_wrap');
  488. var reply_markup_els = reply_markup.map((row)=>row.map((button)=>
  489. buttonEls.filter((i,el)=>$(el).scope().button.$$hashKey === button.$$hashKey)
  490. ));
  491. console.log(reply_markup_els);
  492.  
  493. if(reply_markup_els.length < 8) {
  494. // not yet started
  495. return;
  496. }
  497.  
  498. //$el.get(0).watching = true;
  499.  
  500. function compute() {
  501. var reply_markup = $scope.historyMessage.reply_markup.rows.map((i)=>i.buttons);
  502. var buttonEls = $el.find('.reply_markup_button_wrap');
  503. var reply_markup_els = reply_markup.map((row)=>row.map((button)=>
  504. buttonEls.filter((i,el)=>$(el).scope().button.$$hashKey === button.$$hashKey)
  505. ));
  506.  
  507. console.log(reply_markup_els);
  508. reply_markup = reply_markup.slice(0, 8);
  509. reply_markup_els = reply_markup_els.slice(0, 8);
  510. var board = reply_markup.map((row)=>{
  511. return row.map((button)=>{
  512. var mapped = map[button.text];
  513. if (mapped == null) {
  514. throw new Error('cannot map ' + button.text);
  515. }
  516. return mapped;
  517. }).join('');
  518. }).join('\r\n');
  519. console.log(board);
  520. try {
  521. var result = resolve(7, 8, 15, board);
  522. var ptr = p(7, 8)(0, 0);
  523. for (let ptr = p(7, 8)(0, 0); ptr; ptr = ptr.next()) {
  524. if (result(ptr) >= 0) {
  525. $(reply_markup_els[ptr.y][ptr.x]).find('button').css('background', hslColor(result(ptr) / 3, 1, 0.5));
  526. } else {
  527. console.log(hslColor(2 / 3, 1, 0.5));
  528. $(reply_markup_els[ptr.y][ptr.x]).find('button').css('background', hslColor(2 / 3, 1, 0.5));
  529. }
  530. }
  531. } catch(e){}
  532. }
  533.  
  534. compute();
  535.  
  536. $scope.$watch('historyMessage.message', compute);
  537. }
  538.  
  539. setInterval(check, 10000);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址