High-Low.user.js 11 KB

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