Wirelyre Select Saves (with next pc save)

save selection

  1. // ==UserScript==
  2. // @name Wirelyre Select Saves (with next pc save)
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1
  5. // @description save selection
  6. // @author 13pake, TamTheBoss111
  7. // @match https://wirelyre.github.io/tetra-tools/pc-solver.html*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=github.io
  9. // @grant GM_addStyle
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13. (function() {
  14. 'use strict';
  15.  
  16. GM_addStyle("#solutions > a { border-radius: 4px; }");
  17. GM_addStyle("#solutions { row-gap: 20px; }");
  18. GM_addStyle("#select-save { background-color: rgba(0,0,0,0.2); color: #fff; border: 1px solid rgba(0,0,0,0.3); margin-left: 5px; }");
  19. GM_addStyle("#label-save { margin-top: 10px; }");
  20.  
  21. // Constants
  22. var pieces = ['T', 'I', 'L', 'J', 'S', 'Z', 'O'];
  23. var colors = [
  24. 'rgb(180, 81, 172)', // purple
  25. 'rgb(65, 175, 222)', // cyan
  26. 'rgb(239, 149, 54)', // orange
  27. 'rgb(24, 131, 191)', // blue
  28. 'rgb(102, 198, 92)', // green
  29. 'rgb(239, 98, 77)', // red
  30. 'rgb(247, 211, 62)', // yellow
  31. ];
  32. var remainingPieces = [4, 1, 5, 2, 6, 3, 7];
  33. var piecesUsed = [3, 6, 2, 5, 1, 4, 0];
  34. var pcNumSelectOptions = ["1st", "2nd", "3rd", "4th", "5th", "6th", "7th"]
  35.  
  36.  
  37. window.onload = function() {
  38.  
  39. // Add save selection
  40. var label = document.createElement('label');
  41. label.id = 'label-save';
  42. label.innerHTML = 'Save';
  43. document.querySelectorAll('#query > div:nth-child(6)')[0].appendChild(label);
  44.  
  45. var select = document.createElement('select');
  46. label.appendChild(select);
  47. select.id = 'select-save';
  48.  
  49. var selectOptions = ['All', ...pieces];
  50.  
  51. for (var i = 0; i < selectOptions.length; i++) {
  52. var option = document.createElement('option');
  53. option.value = selectOptions[i];
  54. option.text = selectOptions[i];
  55. select.appendChild(option);
  56. }
  57.  
  58. // Add pc num selection
  59. var pcNumLabel = document.createElement('label');
  60. pcNumLabel.id = 'label-pc-num';
  61. pcNumLabel.innerHTML = 'PC # ';
  62. document.querySelectorAll('#query > div:nth-child(6)')[0].appendChild(pcNumLabel);
  63.  
  64. // Create the slider
  65. var pcNumSlider = document.createElement('input');
  66. pcNumSlider.type = 'range';
  67. pcNumSlider.id = 'slider-pc-num';
  68. pcNumSlider.min = '1';
  69. pcNumSlider.max = '7';
  70. pcNumSlider.step = '1';
  71. pcNumSlider.value = '1';
  72. pcNumLabel.appendChild(pcNumSlider);
  73.  
  74. // Display the selected value
  75. var pcNumDisplay = document.createElement('span');
  76. pcNumDisplay.id = 'slider-value';
  77. pcNumDisplay.innerHTML = '1'; // Default value
  78. pcNumLabel.appendChild(pcNumDisplay);
  79.  
  80. // Update the displayed value when the slider changes
  81. pcNumSlider.addEventListener('input', function () {
  82. pcNumDisplay.innerHTML = pcNumSlider.value;
  83.  
  84. var queue = document.getElementById('queue').value;
  85.  
  86. // check if queue is just pieces
  87. var piecesOnlyMatch = queue.match(/^[TILJSZO]*$/);
  88. if (piecesOnlyMatch) {
  89. //console.log('good queue');
  90. } else {
  91. return;
  92. }
  93.  
  94. var queuePieces = pieces.map(function(piece) {
  95. return (queue.split(piece).length - 1);
  96. });
  97.  
  98. // We're just gonna assume the queue length is correct !!!
  99.  
  100. //console.log('queue pieces', queuePieces);
  101. var solutionsContainer = document.getElementById('solutions');
  102.  
  103. // Loop over all 'a' tags inside the solutions container
  104. var aTags = solutionsContainer.getElementsByTagName('a');
  105. for (let aNode of aTags) {
  106. // console.log('A child node has been added or removed.', mutation.addedNodes[0]);
  107. try {
  108. var dataField = aNode.firstChild.getAttribute('data-field');
  109. var solutionPieces = pieces.map(function(piece) {
  110. return (dataField.split(piece).length - 1) / 4;
  111. });
  112. //console.log('pieces used', solutionPieces);
  113.  
  114. // get difference between arrays
  115. var differentIndex = -1;
  116. for (let i = 0; i < queuePieces.length; i++) {
  117. if (queuePieces[i] !== solutionPieces[i]) {
  118. differentIndex = i;
  119. }
  120. }
  121. // console.log('saved piece', pieces[differentIndex]);
  122. aNode.style.borderTop = "10px solid " + colors[differentIndex];
  123. aNode.classList.add(pieces[differentIndex]);
  124.  
  125. // Calculate what PC comes from this save
  126. let bag = new Set(["T", "I", "J", "L", "O", "S", "Z"]);
  127. // console.log("queuevalue", queue)
  128.  
  129. let currentPCNum = pcNumSlider.value - 1; // -1 so that its an index starting from 0
  130.  
  131. // If there is a saved piece (4p setup with see7/3p setup with see8)
  132. if (differentIndex != -1) {
  133. // console.log(piecesUsed[currentPCNum], currentPCNum);
  134. for (let j = 1; j < piecesUsed[currentPCNum] + 2; j++) {
  135. // console.log("inloop")
  136. // console.log("piece to remove", queue[queue.length - j])
  137. bag.delete(queue[queue.length - j]) // bag ends up being the pieces left in the bag
  138. // console.log("bag currently: ", Array.from(bag).join(""))
  139. }
  140. var save = Array.from(bag).join("");
  141. //console.log("final save", save);
  142. // Add the saved piece
  143.  
  144. // If there is a saved piece (4p setup with see7/3p setup with see8)
  145. save += pieces[differentIndex];
  146. // console.log("final save", save);
  147.  
  148. // Reorder the string
  149. const chars = save.split("");
  150.  
  151. const correctOrder = "TIJLOSZ";
  152.  
  153. // Sort the characters based on their position in the custom order
  154. chars.sort((a, b) => correctOrder.indexOf(a) - correctOrder.indexOf(b));
  155.  
  156. save = chars.join("");
  157. } else if (differentIndex == -1) {
  158. // console.log(piecesUsed[currentPCNum], currentPCNum);
  159. for (let j = 1; j < piecesUsed[currentPCNum] + 1; j++) {
  160. // console.log("inloop")
  161. // console.log("piece to remove", queue[queue.length - j])
  162. bag.delete(queue[queue.length - j]) // bag ends up being the pieces left in the bag
  163. // console.log("bag currently: ", Array.from(bag).join(""))
  164. }
  165. var save = Array.from(bag).join("");
  166. }
  167.  
  168. // hard coded stuff:
  169. //console.log(pcNumSelect.value)
  170. if (pcNumSlider.value == 2) { // for dealing with some 3+1setups on 2nd for 3rd pc saves
  171. save = pieces[differentIndex];
  172. }
  173. if (pcNumSlider.value == 3) { // for renaming 4th pc
  174. const reference = "TIJLOSZ";
  175.  
  176. const missing = reference.split("").filter(letter => !save.includes(letter));
  177. let dupe = "";
  178. if (save.includes("TT")) {
  179. dupe = "T"
  180. } else if (save.includes("II")) {
  181. dupe = "I"
  182. } else if (save.includes("JJ")) {
  183. dupe = "J"
  184. } else if (save.includes("LL")) {
  185. dupe = "L"
  186. } else if (save.includes("OO")) {
  187. dupe = "O"
  188. } else if (save.includes("SS")) {
  189. dupe = "S"
  190. } else if (save.includes("ZZ")) {
  191. dupe = "Z"
  192. }
  193. // console.log(missing, dupe)
  194.  
  195. if (missing.length > 0 && dupe == "") {
  196. save = `no ${missing.join("")}`;
  197. } else {
  198. // console.log("dupe")
  199. save = `${dupe}>${missing.join("")}`;
  200. // console.log("save", save)
  201. }
  202. }
  203. if (pcNumSlider.value == 5) { // for renaming 6th pc
  204. const reference = "TIJLOSZ";
  205.  
  206. const missing = reference.split("").filter(letter => !save.includes(letter));
  207. let dupe = "";
  208. if (save.includes("TT")) {
  209. dupe = "T"
  210. } else if (save.includes("II")) {
  211. dupe = "I"
  212. } else if (save.includes("JJ")) {
  213. dupe = "J"
  214. } else if (save.includes("LL")) {
  215. dupe = "L"
  216. } else if (save.includes("OO")) {
  217. dupe = "O"
  218. } else if (save.includes("SS")) {
  219. dupe = "S"
  220. } else if (save.includes("ZZ")) {
  221. dupe = "Z"
  222. }
  223. // console.log(missing, dupe)
  224.  
  225. if (missing.length > 0 && dupe == "") {
  226. save = `no ${missing.join("")}`;
  227. } else {
  228. // console.log("dupe")
  229. save = `${dupe}>${missing.join("")}`;
  230. // console.log("save", save)
  231. }
  232. }
  233. if (pcNumSlider.value == 7) { // for renaming 1st/8th pc
  234. const reference = "TIJLOSZ";
  235.  
  236. const missing = reference.split("").filter(letter => !save.includes(letter));
  237. let dupe = "";
  238. if (save.includes("TT")) {
  239. dupe = "T"
  240. } else if (save.includes("II")) {
  241. dupe = "I"
  242. } else if (save.includes("JJ")) {
  243. dupe = "J"
  244. } else if (save.includes("LL")) {
  245. dupe = "L"
  246. } else if (save.includes("OO")) {
  247. dupe = "O"
  248. } else if (save.includes("SS")) {
  249. dupe = "S"
  250. } else if (save.includes("ZZ")) {
  251. dupe = "Z"
  252. }
  253. // console.log(missing, dupe)
  254.  
  255. if (missing.length == 0) {
  256. save = "1st PC";
  257. } else {
  258. // console.log("dupe")
  259. save = `${dupe}>${missing.join("")} 8th PC`;
  260. // console.log("save", save)
  261. }
  262. }
  263.  
  264. // checks if the datafield is full and hence there is a pc
  265. if (!dataField.includes("_") && save != undefined) {
  266. if (currentPCNum != 6) {
  267. save += " " + pcNumSelectOptions[currentPCNum + 1]
  268. }
  269. // Check if there is an old text node there and delete it
  270. let existingTextNode = aNode.firstChild.firstChild.querySelector('text');
  271. // console.log(existingTextNode);
  272.  
  273. if (existingTextNode) {
  274. // If an existing text node is found, remove it
  275. aNode.firstChild.firstChild.removeChild(existingTextNode);
  276. }
  277. // Create the new text elem and add it
  278. const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
  279. text.setAttribute("x", "100"); // Set x to the center
  280. text.setAttribute("y", "15"); // Adjust y as needed
  281. text.setAttribute("fill", "black");
  282. text.setAttribute("text-anchor", "middle"); // Center the text horizontally
  283. text.setAttribute("font-size", "15"); // Font size
  284. text.textContent = save;
  285. aNode.firstChild.firstChild.appendChild(text);
  286. }
  287.  
  288.  
  289.  
  290.  
  291.  
  292. } catch (e) {
  293. // do nothing lol
  294. }
  295.  
  296.  
  297. }
  298.  
  299. });
  300.  
  301. // On select change
  302. select.onchange = function(event) {
  303. selectSave(event.target.value);
  304. }
  305.  
  306. function selectSave(value) {
  307. if (value !== 'All') {
  308. document.querySelectorAll('#solutions > a').forEach(function(a) {
  309. a.style.display = 'none';
  310. // a.style.borderTopWidth = '0'; commented out by tam
  311. });
  312. document.querySelectorAll('#solutions > a.' + value).forEach(function(a) {
  313. a.style.display = 'block';
  314. });
  315. } else if (value == 'All') {
  316. document.querySelectorAll('#solutions > a').forEach(function(a) {
  317. a.style.display = 'block';
  318. a.style.borderTopWidth = '10px';
  319. });
  320. }
  321. }
  322.  
  323. // Add listener for solutions and also the whole body for the slider
  324. var targetNode = document.getElementById('solutions');
  325. var config = {
  326. // attributes: true,
  327. childList: true,
  328. subtree: true,
  329. characterData: true
  330. };
  331.  
  332. var observer = new MutationObserver(function(mutationsList) {
  333.  
  334. var queue = document.getElementById('queue').value;
  335.  
  336. // check if queue is just pieces
  337. var piecesOnlyMatch = queue.match(/^[TILJSZO]*$/);
  338. if (piecesOnlyMatch) {
  339. //console.log('good queue');
  340. } else {
  341. return;
  342. }
  343.  
  344. var queuePieces = pieces.map(function(piece) {
  345. return (queue.split(piece).length - 1);
  346. });
  347.  
  348. // We're just gonna assume the queue length is correct !!!
  349.  
  350. //console.log('queue pieces', queuePieces);
  351.  
  352. for (var mutation of mutationsList) {
  353. if (mutation.type == 'childList') {
  354. // console.log('A child node has been added or removed.', mutation.addedNodes[0]);
  355. try {
  356. var aNode = mutation.addedNodes[0];
  357. var dataField = aNode.firstChild.getAttribute('data-field');
  358. var solutionPieces = pieces.map(function(piece) {
  359. return (dataField.split(piece).length - 1) / 4;
  360. });
  361. //console.log('pieces used', solutionPieces);
  362.  
  363. // get difference between arrays
  364. var differentIndex = -1;
  365. for (let i = 0; i < queuePieces.length; i++) {
  366. if (queuePieces[i] !== solutionPieces[i]) {
  367. differentIndex = i;
  368. }
  369. }
  370. // console.log('saved piece', pieces[differentIndex]);
  371. aNode.style.borderTop = "10px solid " + colors[differentIndex];
  372. aNode.classList.add(pieces[differentIndex]);
  373.  
  374. // Calculate what PC comes from this save
  375. let bag = new Set(["T", "I", "J", "L", "O", "S", "Z"]);
  376. // console.log("queuevalue", queue)
  377.  
  378. let currentPCNum = pcNumSlider.value - 1; // -1 so that its an index starting from 0
  379.  
  380. // If there is a saved piece (4p setup with see7/3p setup with see8)
  381. if (differentIndex != -1) {
  382. // console.log(piecesUsed[currentPCNum], currentPCNum);
  383. for (let j = 1; j < piecesUsed[currentPCNum] + 2; j++) {
  384. // console.log("inloop")
  385. // console.log("piece to remove", queue[queue.length - j])
  386. bag.delete(queue[queue.length - j]) // bag ends up being the pieces left in the bag
  387. // console.log("bag currently: ", Array.from(bag).join(""))
  388. }
  389. var save = Array.from(bag).join("");
  390. //console.log("final save", save);
  391. // Add the saved piece
  392.  
  393. // If there is a saved piece (4p setup with see7/3p setup with see8)
  394. save += pieces[differentIndex];
  395. // console.log("final save", save);
  396.  
  397. // Reorder the string
  398. const chars = save.split("");
  399.  
  400. const correctOrder = "TIJLOSZ";
  401.  
  402. // Sort the characters based on their position in the custom order
  403. chars.sort((a, b) => correctOrder.indexOf(a) - correctOrder.indexOf(b));
  404.  
  405. save = chars.join("");
  406. } else if (differentIndex == -1) {
  407. // console.log(piecesUsed[currentPCNum], currentPCNum);
  408. for (let j = 1; j < piecesUsed[currentPCNum] + 1; j++) {
  409. // console.log("inloop")
  410. // console.log("piece to remove", queue[queue.length - j])
  411. bag.delete(queue[queue.length - j]) // bag ends up being the pieces left in the bag
  412. // console.log("bag currently: ", Array.from(bag).join(""))
  413. }
  414. var save = Array.from(bag).join("");
  415. }
  416.  
  417. // hard coded stuff:
  418. //console.log(pcNumSelect.value)
  419. if (pcNumSlider.value == 2) { // for dealing with some 3+1setups on 2nd for 3rd pc saves
  420. save = pieces[differentIndex];
  421. }
  422. if (pcNumSlider.value == 3) { // for renaming 4th pc
  423. const reference = "TIJLOSZ";
  424.  
  425. const missing = reference.split("").filter(letter => !save.includes(letter));
  426. let dupe = "";
  427. if (save.includes("TT")) {
  428. dupe = "T"
  429. } else if (save.includes("II")) {
  430. dupe = "I"
  431. } else if (save.includes("JJ")) {
  432. dupe = "J"
  433. } else if (save.includes("LL")) {
  434. dupe = "L"
  435. } else if (save.includes("OO")) {
  436. dupe = "O"
  437. } else if (save.includes("SS")) {
  438. dupe = "S"
  439. } else if (save.includes("ZZ")) {
  440. dupe = "Z"
  441. }
  442. // console.log(missing, dupe)
  443.  
  444. if (missing.length > 0 && dupe == "") {
  445. save = `no ${missing.join("")}`;
  446. } else {
  447. // console.log("dupe")
  448. save = `${dupe}>${missing.join("")}`;
  449. // console.log("save", save)
  450. }
  451. }
  452. if (pcNumSlider.value == 5) { // for renaming 6th pc
  453. const reference = "TIJLOSZ";
  454.  
  455. const missing = reference.split("").filter(letter => !save.includes(letter));
  456. let dupe = "";
  457. if (save.includes("TT")) {
  458. dupe = "T"
  459. } else if (save.includes("II")) {
  460. dupe = "I"
  461. } else if (save.includes("JJ")) {
  462. dupe = "J"
  463. } else if (save.includes("LL")) {
  464. dupe = "L"
  465. } else if (save.includes("OO")) {
  466. dupe = "O"
  467. } else if (save.includes("SS")) {
  468. dupe = "S"
  469. } else if (save.includes("ZZ")) {
  470. dupe = "Z"
  471. }
  472. // console.log(missing, dupe)
  473.  
  474. if (missing.length > 0 && dupe == "") {
  475. save = `no ${missing.join("")}`;
  476. } else {
  477. // console.log("dupe")
  478. save = `${dupe}>${missing.join("")}`;
  479. // console.log("save", save)
  480. }
  481. }
  482. if (pcNumSlider.value == 7) { // for renaming 1st/8th pc
  483. const reference = "TIJLOSZ";
  484.  
  485. const missing = reference.split("").filter(letter => !save.includes(letter));
  486. let dupe = "";
  487. if (save.includes("TT")) {
  488. dupe = "T"
  489. } else if (save.includes("II")) {
  490. dupe = "I"
  491. } else if (save.includes("JJ")) {
  492. dupe = "J"
  493. } else if (save.includes("LL")) {
  494. dupe = "L"
  495. } else if (save.includes("OO")) {
  496. dupe = "O"
  497. } else if (save.includes("SS")) {
  498. dupe = "S"
  499. } else if (save.includes("ZZ")) {
  500. dupe = "Z"
  501. }
  502. // console.log(missing, dupe)
  503.  
  504. if (missing.length == 0) {
  505. save = "1st PC";
  506. } else {
  507. // console.log("dupe")
  508. save = `${dupe}>${missing.join("")} 8th PC`;
  509. // console.log("save", save)
  510. }
  511. }
  512.  
  513. // checks if the datafield is full and hence there is a pc
  514. if (!dataField.includes("_") && save != undefined) {
  515. if (currentPCNum != 6) {
  516. save += " " + pcNumSelectOptions[currentPCNum + 1]
  517. }
  518.  
  519. // Create the new text elem and add it
  520. const text = document.createElementNS("http://www.w3.org/2000/svg", "text");
  521. text.setAttribute("x", "100"); // Set x to the center
  522. text.setAttribute("y", "15"); // Adjust y as needed
  523. text.setAttribute("fill", "black");
  524. text.setAttribute("text-anchor", "middle"); // Center the text horizontally
  525. text.setAttribute("font-size", "15"); // Font size
  526. text.textContent = save;
  527. aNode.firstChild.firstChild.appendChild(text);
  528. }
  529.  
  530.  
  531.  
  532.  
  533.  
  534. } catch (e) {
  535. // do nothing lol
  536. }
  537.  
  538. }
  539. }
  540. });
  541.  
  542. observer.observe(targetNode, config);
  543. }
  544. })();