High-Low.user.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. // ==UserScript==
  2. // @name High-Low
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.1.3
  5. // @description try to take over the world!
  6. // @author You
  7. // @match https://www.torn.com/loader.php?sid=high*ow
  8. // @require https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.3/vue.js
  9. // @resource sourceCodePro https://fonts.googleapis.com/css?family=Source+Code+Pro
  10. // @require https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/highlight.min.js
  11. // @resource json-formatter_css https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/default.min.css
  12. // @grant GM_getResourceText
  13. // @grant GM_addStyle
  14. // @grant GM_setValue
  15. // @grant GM_getValue
  16. // ==/UserScript==
  17. /* jshint -W097 */
  18. /*global
  19. $, console, Raven, GM_addStyle, GM_getResourceText, Vue, hljs
  20. */
  21. (function() {
  22. 'use strict';
  23. var sourceCodePro = GM_getResourceText("codeSourcePro");
  24. GM_addStyle(sourceCodePro);
  25. GM_addStyle("pre,code {font-family: 'Source Code Pro', monospace; font-size: 14px;}");
  26. var js_css = GM_getResourceText("json-formatter_css");
  27. GM_addStyle(js_css);
  28. //var bootstrap_css = GM_getResourceText("bootstrap_css");
  29. //GM_addStyle(bootstrap_css);
  30. GM_addStyle(".hljs-number { color: blue; }");
  31. var formatterConfig = {
  32. hoverPreviewEnabled: false,
  33. hoverPreviewArrayCount: 100,
  34. hoverPreviewFieldCount: 5,
  35. theme: 'dark',
  36. animateOpen: true,
  37. animateClose: true,
  38. open: 20
  39. };
  40. var changeTimeout = function() {
  41. var oldTimeout = setTimeout;
  42. /*global setTimeout:true */
  43. setTimeout = function(a, b) {
  44. return oldTimeout(a, b/3);
  45. };
  46. console.log("setTimout: changed");
  47. };
  48. let script = document.createElement('script');
  49. script.appendChild(document.createTextNode('('+ changeTimeout +')();'));
  50. (document.head || document.body || document.documentElement).appendChild(script);
  51. class Card {
  52. constructor(number) {
  53. this.number = parseInt(number, 10);
  54. let card = this.getCardFromNumber(this.number);
  55. this.color = card[0];
  56. this.rank = card[1];
  57. }
  58. getCardFromNumber(number) {
  59. let mod = (number-1) % 4;
  60. let color = "";
  61. if (mod === 0) {
  62. color = "spades";
  63. }
  64. if (mod === 1) {
  65. color = "diamonds";
  66. }
  67. if (mod === 2) {
  68. color = "hearts";
  69. }
  70. if (mod === 3) {
  71. color = "clubs";
  72. }
  73. let offset = 0;
  74. offset += 4; // Counter for 2 being first card, not 1
  75. offset += 3; // Counter for using floor
  76. let rank = Math.floor((parseInt(number, 10)+offset)/4);
  77. return [color, rank];
  78. }
  79. toString() {
  80. let rank = this.rank.toString();
  81. console.log("rank:", rank);
  82. /* if (rank === "10") {
  83. rank = "T";
  84. } */
  85. if (rank === "11") {
  86. rank = "J";
  87. }
  88. if (rank === "12") {
  89. rank = "Q";
  90. }
  91. if (rank === "13") {
  92. rank = "K";
  93. }
  94. if (rank === "14") {
  95. rank = "A";
  96. }
  97. return this.color + "-" + rank;
  98. }
  99. toValue() {
  100. return this.rank;
  101. }
  102. }
  103. /* Initialize deck */
  104. let deck = GM_getValue('deck', []);
  105. let createDeck = (deck) => {
  106. for (let i = 2; i < 54; i++) {
  107. deck.push(i);
  108. }
  109. GM_setValue('deck', deck);
  110. console.warn('new deck.length:', deck.length);
  111. // console.log(deck);
  112. return deck;
  113. }
  114. if (deck.length === 0) {
  115. deck = createDeck(deck);
  116. }
  117. let removeCard = (deck, card) => {
  118. /*
  119. console.log('[removeCard] card:', card);
  120. console.log('typeof card:', typeof card);
  121. console.log('typeof deck[5]:', typeof deck[5]);
  122. */
  123. for( var i = 0; i < deck.length; i++) {
  124. if ( deck[i] === card) {
  125. deck.splice(i, 1);
  126. }
  127. }
  128. GM_setValue('deck', deck);
  129. // console.log('deck.length:', deck.length);
  130. }
  131. //********
  132. // Controller
  133. //********
  134. let processStartGame = function(db) {
  135. let formulaStats = db.DB.formulaStats[0];
  136. let previousMultiplier = 0;
  137. let currentMultiplier = 0;
  138. if (formulaStats) {
  139. currentMultiplier = formulaStats.currentRatio;
  140. previousMultiplier = formulaStats.previousRatio;
  141. if (previousMultiplier !== currentMultiplier) {
  142. console.log("Multiplier changed!. Old: " + previousMultiplier + " => New: " + currentMultiplier);
  143. }
  144. }
  145. console.log("Multiplier:", currentMultiplier);
  146. //$("pre code.json").empty().append(JSON.stringify(db, null, 4));
  147. console.log('myVue:', myVue);
  148. myVue.jsonobject = JSON.stringify(db, null, 4);
  149. // myVue.jsonobject = "Test";
  150. // action.header = "Test";
  151. Vue.nextTick(function() {
  152. hljs.initHighlighting.called = false;
  153. hljs.initHighlighting();
  154. });
  155. };
  156. let processGameStarted = function(db) {
  157. // dealerCard is revealed; player picks High or Low
  158. // Note: Player also has the option to cash in but that is never considered
  159. // console.log("dealerCard:", db.currentGame[0].dealerCard);
  160. let dealerCard = new Card(db.currentGame[0].dealerCard);
  161. // console.warn('dealerCard.number:', dealerCard.number);
  162. removeCard(deck, dealerCard.number);
  163. if ('result' in db.currentGame[0]) {
  164. console.log('LOST');
  165. removeCard(deck, parseInt(db.currentGame[0].playerCard, 10));
  166. }
  167. if ('deckShuffled' in db.DB) {
  168. console.warn('db.DB.deckShuffled:', db.DB.deckShuffled);
  169. if (db.DB.deckShuffled === true) {
  170. deck = [];
  171. deck = createDeck(deck);
  172. }
  173. }
  174. console.assert(dealerCard.toString() === db.currentGame[0].dealerCardInfo.classCode,
  175. "Mismatch dealerCard " + dealerCard + " <-> " + db.currentGame[0].dealerCardInfo.classCode);
  176. console.log("dealerCard:", dealerCard.toString());
  177. let arrayWithOdds = calculateOdds(dealerCard, deck);
  178. let lower = arrayWithOdds[0];
  179. let higher = arrayWithOdds[1];
  180. let numberOfCards = arrayWithOdds[2];
  181. // testing
  182. //$('div.action-c.action-btn-wrap.active.low').addClass('iconPulseExpiring');
  183. //$('div.action-r.action-btn-wrap.active.high').removeClass('active');
  184. };
  185. let processMakeChoice = function(db) {
  186. // The deal has ended. The choice is cash in or play on.
  187. if (db.currentGame[0].dealerCard !== db.currentGame[0].lastDealerCard) {
  188. // Reveal dealerCard of next deal
  189. // Page has been refreshed
  190. // There is no playerCard (there is a lastPlayerCard)
  191. db.currentGame[0].playerCard = db.currentGame[0].lastPlayerCard;
  192. db.currentGame[0].playerCardInfo = db.currentGame[0].lastPlayerCardInfo;
  193. // dealerCard assert will fail!
  194. }
  195. console.log("step:", db.currentGame[0].step);
  196. let dealerCard = new Card(db.currentGame[0].dealerCard);
  197. console.assert(dealerCard.toString() === db.currentGame[0].dealerCardInfo.classCode,
  198. "Mismatch dealerCard " + dealerCard + " <-> " + db.currentGame[0].dealerCardInfo.classCode);
  199. let playerCard = new Card(db.currentGame[0].playerCard);
  200. console.assert(playerCard.toString() === db.currentGame[0].playerCardInfo.classCode,
  201. "Mismatch playerCard " + playerCard + " <-> " + db.currentGame[0].playerCardInfo.classCode);
  202. console.log("playerCard:", playerCard.toString());
  203. removeCard(deck, parseInt(db.currentGame[0].playerCard, 10));
  204. if (db.DB.deckShuffled) {
  205. console.log('[processMakeChoice] deckShuffled', db.DB.deckShuffled);
  206. // New deck
  207. deck = [];
  208. deck = createDeck(deck);
  209. }
  210. };
  211. $(document).ajaxSuccess(
  212. // On every detected Ajax communication
  213. function(event, jqxhr, settings, data) {
  214. // Make sure it was to or from /loader.php?sid=hiloJson&rfcv=<rfcv>
  215. if (settings.url.indexOf("loader.php?sid=hiloJson") != -1) {
  216. //console.log("event:", event);
  217. //console.log("jqxhr:", jqxhr);
  218. //console.log("settings:", settings);
  219. let db = JSON.parse(data);
  220. $("pre code.json").empty().append(JSON.stringify(db.currentGame, null, 4));
  221. hljs.initHighlighting.called = false;
  222. hljs.initHighlighting();
  223. console.log("db:", db);
  224. let status = db.status;
  225. console.log("db.status:", db.status);
  226. if (status === "startGame") {
  227. processStartGame(db);
  228. }
  229. if (status === "gameStarted") {
  230. processGameStarted(db);
  231. }
  232. if (status === "makeChoice") {
  233. processMakeChoice(db);
  234. }
  235. //console.log("db.currentGame:", db.currentGame);
  236. }
  237. });
  238. //********
  239. // VIEW
  240. //********
  241. let boxTitle = "Let's play High-Low";
  242. let boxHTML = "<div class=\"tutorial-cont m-top10\">" +
  243. "<div class=\"title-gray top-round\" role=\"heading\" aria-level=\"5\">" +
  244. "<i class=\"tutorial-icon\"></i>" +
  245. "<span style=\"padding-left: 6px\">" + boxTitle + "</span>" +
  246. "</div>" +
  247. "<div class=\"bottom-round cont-gray p10\">"+
  248. "<div id=\"app\" style=\"min-height: 450px;\">" +
  249. "<div style=\"float: left; width: 50%;\">" +
  250. "<current-action v-bind:action=\"action\"></current-action>" +
  251. "</div><div id=\"right\" style=\"float: right; width: 50%;\">"+
  252. //"<pre><code class=\"json\"></code></pre>" +
  253. "<vue-object v-bind:jsonobject=\"jsonobject\"></vue-object>" +
  254. "</div></div><div class=\"clear\"></div>" +
  255. "<hr class=\"page-head-delimiter m-top10\">" +
  256. "</div>";
  257. $('.highlow-main-wrap').after(boxHTML);
  258. // Vue.js template
  259. //creating component
  260. var currentAction = Vue.extend({
  261. template: '<h1 v-bind:style="actionStyle">{{ action.header }}</h1>',
  262. data: function() {
  263. return {
  264. // action: "Current Action",
  265. actionStyle: {
  266. marginTop: "0px"
  267. }
  268. };
  269. },
  270. props: ['action']
  271. });
  272. var vueObject = Vue.extend({
  273. template: '<div v-bind:style="vueObjectStyle"><pre><code class="json" v-html="jsonobject"></code></pre></div>',
  274. data: function() {
  275. return {
  276. vueObjectStyle: {
  277. marginTop: "0px"
  278. }
  279. };
  280. },
  281. props: ['jsonobject']
  282. });
  283. //registering component
  284. Vue.component('current-action', currentAction);
  285. Vue.component('vue-object', vueObject);
  286. //initializing the Vue application
  287. let action = {};
  288. action.header = "Current Action";
  289. let myVue = new Vue({
  290. el: "#app",
  291. data: function() {
  292. return {
  293. jsonobject: "Start",
  294. action: action
  295. };
  296. }
  297. });
  298. //********
  299. // MODEL
  300. //********
  301. /**
  302. * @param {array} deck, cards by number
  303. * @return {array} number of cards by rank where key is the rank \
  304. * and val is the number of that rank in the deck
  305. */
  306. let parseDeck = function(deck) {
  307. // Create new parsedDeck from deck
  308. let parsedDeck = [];
  309. // parsedDeck runs from 0 to 14 where 0 and 1 are always 0.
  310. // Real deck values count from 2 to 14 (ace)
  311. for (let i = 0; i <= 15; i++) {
  312. parsedDeck[i] = 0;
  313. }
  314. let deckLength = deck.length;
  315. for (let i = 0; i < deckLength; i++) {
  316. /*
  317. if (i < 10) {
  318. console.log('first cards:', deck[i]);
  319. }
  320. */
  321. let offset = 0;
  322. offset += 4; // Counter for 2 being first card, not 1
  323. offset += 3; // Counter for using floor
  324. let rank = Math.floor((parseInt(deck[i], 10)+offset)/4);
  325. parsedDeck[rank]++;
  326. }
  327. if (deckLength === 0) {
  328. // Shuffle -> create new deck
  329. for (let i = 2; i < 15; i++) {
  330. parsedDeck[i] = 4;
  331. }
  332. }
  333. return parsedDeck;
  334. };
  335. let calculateOdds = function(dealerCard, deck) {
  336. let parsedDeck = parseDeck(deck);
  337. let deckLength = parsedDeck.length;
  338. let numberOfCards = 0;
  339. let lowerDoesNotLose = 0; // Equals count as 'not lose'
  340. let higherDoesNotLose = 0; // Equals count as 'not lose'
  341. for (let i = 0; i < deckLength; i++) {
  342. if (i <= dealerCard.rank) {
  343. lowerDoesNotLose += parsedDeck[i];
  344. }
  345. if (i >= dealerCard.rank) {
  346. higherDoesNotLose += parsedDeck[i];
  347. }
  348. numberOfCards += parsedDeck[i];
  349. }
  350. console.assert(deck.length === numberOfCards, 'deck.length: '+deck.length+' <> numberOfCards: '+numberOfCards);
  351. // console.log("[calculteOdds] parsedDeck;", parsedDeck);
  352. console.log("[calculateOdds] lowerDoesNotLose:", lowerDoesNotLose);
  353. console.log("[calculateOdds] higherDoesNotLose:", higherDoesNotLose);
  354. console.log("[calculateodds] numberOfCards:", numberOfCards);
  355. return [lowerDoesNotLose, higherDoesNotLose, numberOfCards];
  356. };
  357. })();