Greasy Fork is available in English.

BVS Flower Wars AI

Makes play choices for the bvs game Flower Wars

Από την 19/05/2017. Δείτε την τελευταία έκδοση.

  1. // ==UserScript==
  2. // @name BVS Flower Wars AI
  3. // @namespace chris
  4. // @description Makes play choices for the bvs game Flower Wars
  5. // @include http*://*animecubed.com/billy/bvs/partyhouse-hanafudaplay.html
  6. // @include http*://*animecubed.com/billy/bvs/partyhouse-hanafuda.html
  7. // @version 2.1
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_deleteValue
  11. // ==/UserScript==
  12.  
  13. // hotkeys: d - take the selected action
  14. // c - use if you want the script to select cheats to use
  15. // v - open debug console
  16.  
  17. //change log
  18. // <version> 2.1 - Now https compatible (Updated by Channel28)
  19. // <version> 2.0 - Fix bugs (Thanks to Terrec. Updated by Channel28)
  20. // <version> 1.1112 - Added grant permissions (Updated by Channel28)
  21. // <version> 1.1111 - added google chrome support
  22. // <version> 1.11 - many tweak to choice decisions
  23. // - cheats added over from test version
  24. // <version> 1.11 - fixed a bug in discard when attempting to discard a card
  25. // - with a matching month
  26. // <version> 1.1 - new hotkey V now opens the debug console
  27. // - made some minor adjustments to card values
  28. // <version> 1.09.1 - fixed discard (no clue how i made that mistake)
  29. // <version> 1.09 - Added a "debug console" button that shows value breakdowns
  30. // (if anyone is interested in why the script makes its choices)
  31. // - Tweaked several values to increase performance
  32. // <version> 1.08.2 - Slightly modified for Firefox 3.6 compatability
  33. // <version> 1.08.1 - fixed several issues from version 1.08 to get the script stable
  34. // <version> 1.08 - code for playing month cards to block opponent altered to be based on enemy yakus
  35. // - koikoi should work better (when you're really pummeling the computer)
  36. // <version> 1.07 - Added recommended action text for koikoi/bank
  37. // - several tweaks to card rankings/yakus to improve decisions
  38. // - script will now "pass" on matching month cards to wait for yakus
  39. // <version> 1.06 - koikoi now determines not only distance from enemy yakus,
  40. // but whether they are possible given the field
  41. // - minor tweaks to fix how often koikoi is called
  42. // <version> 1.05.0 - revamped to koikoi source, should work properly when opponent has 8+ plains
  43. // - decisions relating to obtaining a yaku improved
  44. // <version> 1.04.2 - fixed a minor issue that could cause a failure to koikoi
  45. // <version> 1.04.1 - added auto-updater (hopefully)
  46. // <version> 1.04 - several minor tweaks
  47. // - when discarding, possible cards are now weighted into the descision
  48. // <version> 1.03 - tweaked values for better gameplay
  49. // - fixed errors in counting opponents cards
  50. // <version> 1.02 - fixed a few errors in ranking wet brights
  51. // <version> 1.01 - tweaked script to koikoi more often
  52. // - fixed an error that could cause koikoi/bank to fail
  53. // <version> 1.00
  54.  
  55. try {
  56. if (!this.GM_getValue || (this.GM_getValue.toString && this.GM_getValue.toString().indexOf("not supported")>-1)) {
  57. this.GM_getValue=function (key,def) {
  58. return localStorage[key] || def;
  59. };
  60. this.GM_setValue=function (key,value) {
  61. return localStorage[key]=value;
  62. };
  63. this.GM_deleteValue=function (key) {
  64. return delete localStorage[key];
  65. };
  66. }
  67. } catch (e) {}
  68.  
  69. var pageLoc = "/billy/bvs/partyhouse-hanafuda.html"
  70. if(location.href.indexOf(pageLoc) != -1)
  71. {
  72. GM_setValue("forcedKoi",false)
  73. return;
  74. }
  75.  
  76. var forceKoi = GM_getValue("forcedKoi",false)
  77. var forceMatch = /Next Opponent Koi-Koi forced!/.exec(document.body.innerHTML);
  78. if (forceMatch)
  79. {
  80. forceKoi = true;
  81. GM_setValue("forcedKoi",true)
  82. }
  83.  
  84. var cheatMonth = 0;
  85. var noPlayMonth = 0;
  86. var enemyHasKoiKoi = false;
  87. var youHaveKoiKoi = false;
  88. var canCheat = true;
  89. var availCheats = [];
  90. var useCheat = null;
  91. var yakuHandCard = null;
  92. var yakuFieldCard = null;
  93.  
  94. if(/They play .* and call Koi-Koi!/.exec(document.body.innerHTML))
  95. enemyHasKoiKoi=true;
  96. else if(/Koi-Koi - No Cheating!<br>\(Them/.exec(document.body.innerHTML))
  97. enemyHasKoiKoi=true;
  98.  
  99. if(/Koi-Koi - No Cheating!<br>\(You/.exec(document.body.innerHTML))
  100. youHaveKoiKoi = true;
  101. if (youHaveKoiKoi || enemyHasKoiKoi)
  102. canCheat = false;
  103. var match = /Select cheat \((\d+) remaining\):/.exec(document.body.innerHTML);
  104. if (!match || match[1] == 0)
  105. canCheat = false;
  106. if (/Shuffle \+ Redraw/.exec(document.body.innerHTML)) availCheats.push("redrawCheat");
  107. if (/View top of deck/.exec(document.body.innerHTML)) availCheats.push("showTopCard");
  108. if (/Opp. -1 Take/.exec(document.body.innerHTML)) availCheats.push("enemyCardCheat");
  109. if (/Force Koi-Koi/.exec(document.body.innerHTML)) availCheats.push("forceKoiKoi");
  110. //set value modifiers
  111. var monthMult = [];
  112. for (var i =1;i<13;i++)
  113. monthMult[i] = 0
  114.  
  115. //lower values make the script play more defensively
  116. // (I'd recommend not going any lower than 1)
  117. var offensive = 1.4
  118. //increase this value to decrease the month blocking affect
  119. var monthBlock = 2.0
  120.  
  121. //yaku value modifiers (+ per card owned in the yaku)
  122. var plain = 1.0;
  123. var ribbon = 1.0;
  124. var animal = 1.0;
  125. var Rribbon = 5.0; //add code to drop this value when 1 owned by each player
  126. var Bribbon = 5.0; //add code to drop this value when 1 owned by each player
  127. var RoShamBo= 5.0; //add code to drop this value when 1 owned by each player
  128. var brights = 6.0;
  129. var loop = 5.0;
  130. var sacrifice = 5.0;
  131. var wetBright = .6; //only increases when brights are obtained
  132.  
  133. var onFieldMult = 1.5;
  134. var twoInHand = .7;
  135. var threeInPlay = .5; //this does not apply to cards on the field
  136. var guaranteeMult=.01;
  137. var yakuMult = 5.0;
  138. var cheatThreshold = 20.0;
  139.  
  140. var discarding = false;
  141.  
  142. //get the top deck card
  143. var deckCard = getDeckCard();
  144. //get hand cards
  145. var hand = getHand();
  146. //get field cards and set empty slot
  147. var emptySlot;
  148. var playField = getFieldCards();
  149. //get your owned cards
  150. var yourCards = getYourCards();
  151. //get enemies cards
  152. var enemyCards = getEnemyCards();
  153.  
  154. //if the enemy is the dealer, disable force koikoi strat when you hit 2 cards in hand (so enemy doesn't actually win)
  155. var dealMatch = /-- Them \((Dealer) - Current/.exec(document.body.innerHTML);
  156. if (dealMatch && dealMatch[1] == "Dealer")
  157. if (hand.length == 2)
  158. {
  159. enemyHasKoiKoi = true;
  160. forceKoi = true;
  161. }
  162. updateMultipliers();
  163. setValues(hand, false);
  164. setValues(playField, true);
  165.  
  166. var mc = /option to put at bottom\):<br><img src="\/billy.layout.hcards.(thumbs.)?(\d+).jpg">/.exec(document.body.innerHTML)
  167. var mc = []
  168. var cheatCard = new Card(0);
  169.  
  170. if (mc && mc.length > 1)
  171. {
  172. //decide whether to put it on bottom, or play
  173. var tmpCard = new Card(mc[2]);
  174. var month = tmpCard.month;
  175. //if the month is not on the field/in hand, put it at the bottom
  176. if (!hasMonth(playField, month) && !hasMonth(hand, month))
  177. setCheat("bottom");
  178. else
  179. {
  180. cheatMonth = month;
  181. //get the value of card on top of deck
  182. cheatCard.value = getValue(tmpCard);
  183. //add other multipliers
  184. var num = tmpCard.num;
  185.  
  186. cheatCard.value += monthMult[tmpCard.month];
  187. //guaranteed type 2 done after block (you are guaranteed the card regardless, and can do nothing to block a play)
  188. if (guaranteed(tmpCard) == 2)
  189. cheatCard.value *= guaranteeMult;
  190. cheatCard.value *= onFieldMult;
  191. if (givesYaku(yourCards, tmpCard.num))
  192. cheatCard.value *= yakuMult;
  193. //find the best card in hand
  194. var bCard = null;
  195. for (var i=0;i<hand.length;i++)
  196. if ((bCard == null || bCard.value < hand[i].value) && hand[i].month == tmpCard.month)
  197. bCard = hand[i];
  198. cheatCard.num = bCard.num;
  199. cheatCard.month = bCard.month;
  200. cheatCard.element = bCard.element;
  201. cheatCard.playable = true;
  202. cheatCard.value += bCard.value;
  203. }
  204. }
  205.  
  206. //stores reasons why the script should perform each action
  207. var koiReasons = [];
  208. var bankReasons = [];
  209.  
  210. if (!document.forms.namedItem("bankpoints") && !document.forms.namedItem("koikoi"))
  211. {
  212. if (deckCard)
  213. playDeck();
  214. if (tryShowTopCardCheat())
  215. {
  216. var newButton = document.createElement("btn");
  217. var targetElement = document.forms.namedItem("placecard");
  218. newButton.style.fontSize = "20px";
  219. newButton.innerHTML = "<b>Suggested Action : Cheat (Show Top Card)<BR></b>";
  220. targetElement.parentNode.insertBefore(newButton, targetElement);
  221. setCheat("topCard");
  222. }
  223. if (tryEnemyCardCheat())
  224. {
  225. var newButton = document.createElement("btn");
  226. var targetElement = document.forms.namedItem("placecard");
  227. newButton.style.fontSize = "20px";
  228. newButton.innerHTML = "<b>Suggested Action : Cheat (-1 enemy cards)<BR></b>";
  229. targetElement.parentNode.insertBefore(newButton, targetElement);
  230. setCheat("minusCard");
  231. }
  232. if (tryForceKoiKoiCheat())
  233. {
  234. var newButton = document.createElement("btn");
  235. var targetElement = document.forms.namedItem("placecard");
  236. newButton.style.fontSize = "20px";
  237. newButton.innerHTML = "<b>Suggested Action : Cheat (Force KoiKoi)<BR></b>";
  238. targetElement.parentNode.insertBefore(newButton, targetElement);
  239. setCheat("koi");
  240. }
  241. if (!deckCard && !playCard())
  242. {
  243. discarding = true;
  244. discard();
  245. if (tryRedrawCheat())
  246. {
  247. var newButton = document.createElement("btn");
  248. var targetElement = document.forms.namedItem("placecard");
  249. newButton.style.fontSize = "20px";
  250. newButton.innerHTML = "<b>Suggested Action : Cheat (redraw hand)<BR></b>";
  251. targetElement.parentNode.insertBefore(newButton, targetElement);
  252. setCheat("redraw");
  253. }
  254. }
  255. }
  256. else
  257. {
  258. var newButton = document.createElement("btn");
  259. var targetElement;
  260. if (!document.forms.namedItem("koikoi"))
  261. targetElement = document.forms.namedItem("bankpoints");
  262. else if (koikoi())
  263. targetElement = document.forms.namedItem("koikoi");
  264. else
  265. targetElement = document.forms.namedItem("bankpoints");
  266. newButton.innerHTML = "<b>Suggested Action</b>";
  267. insertAfter(newButton, targetElement);
  268. }
  269. function contains(list, string)
  270. {
  271. if (!list) return false;
  272. for (var i=0;i<list.length;i++)
  273. if (list[i] == string)
  274. return true;
  275. return false;
  276. }
  277.  
  278. function tryForceKoiKoiCheat()
  279. {
  280. if (!canCheat || !contains(availCheats,"forceKoiKoi"))
  281. return false;
  282. if (guaranteedYaku() && hand.length > 2)
  283. return true;
  284. return false;
  285. }
  286. //this cheat runs if there is at least 3 valuable cards in play (that you can match cards with, none of which are guaranteed)
  287. function tryShowTopCardCheat()
  288. {
  289. if (!canCheat || !contains(availCheats,"showTopCard"))
  290. return false;
  291.  
  292. var count = 0;
  293. for (var i=0;i<playField.length;i++)
  294. if (hasMonth(hand,playField[i].month))
  295. if (playField[i].value >= 1.5)
  296. count++;
  297. if (count >= 3)
  298. return true;
  299. return false;
  300. }
  301.  
  302. //this cheat runs if enemy has 4 cards or less, where 1 is from a 2 yaku, and at least 1 other is from a 3 yaku
  303. function tryEnemyCardCheat()
  304. {
  305. if (!canCheat || !contains(availCheats,"enemyCardCheat"))
  306. return false;
  307.  
  308. var hasLpA = 0;
  309. var hasSacP = 0;
  310. for (var i=0;i<enemyCards.length;i++)
  311. {
  312. if (enemyCards[i].num == 44)
  313. hasLpA = 1;
  314. else if (enemyCards[i].num == 17)
  315. hasSacP = 1;
  316. }
  317. //add all low value yaku cards
  318. var negCount = plainCount(enemyCards) + animalCount(enemyCards) + ribbonCount(enemyCards);
  319. //subtract out the ones that give larger yakus
  320. if (!rRibbonConflict()) negCount -= rRibbonCount(enemyCards);
  321. if (!bRibbonConflict()) negCount -= bRibbonCount(enemyCards);
  322. if (!roConflict() ) negCount -= roCount(enemyCards);
  323. if (!sacConflict() ) negCount -= hasSacP;
  324. if (!loopConflict() ) negCount -= hasLpA;
  325. var posCount = 0;
  326. if (!rRibbonConflict()) posCount += rRibbonCount(enemyCards);
  327. if (!bRibbonConflict()) posCount += bRibbonCount(enemyCards);
  328. if (!roConflict() ) posCount += roCount(enemyCards);
  329. if (!sacConflict() ) posCount += hasSacP;
  330. if (!loopConflict() ) posCount += hasLpA;
  331. if (!brightConflict() ) posCount += brightCount(enemyCards);
  332. if ((hasBright(enemyCards) && !brightConflict() ||
  333. hasLoop(enemyCards) && !loopConflict() ||
  334. hasSac(enemyCards) && !sacConflict() )&&
  335. negCount < 3||
  336. posCount - negCount > 1)
  337. return true;
  338. return false;
  339. }
  340.  
  341. function tryRedrawCheat()
  342. {
  343. if (!canCheat || !contains(availCheats,"redrawCheat") || guaranteedYaku())
  344. return false;
  345. //if aug bright is in play, and no august cards in hand
  346. if (hasCard(playField, "29") && monthCount(8, playField) <= 2)
  347. if (monthCount(8, hand) == 0)
  348. return true;
  349. //an alternate way to redraw, if you have less than 4 cards, and they all give the enemy big yakus
  350. if (hand.length < 4)
  351. {
  352. for (var i=0;i<hand.length;i++)
  353. {
  354. var num = hand[i].num;
  355. if (isRoShamBo(num) && roCount(enemyCards) == 2) continue;
  356. if (isRribbon(num) && rRibbonCount(enemyCards) == 2) continue;
  357. if (isBribbon(num) && bRibbonCount(enemyCards) == 2) continue;
  358. if (isBright(num) && brightCount(enemyCards) >= 2) continue;
  359. if (isLoop(num) && loopCount(enemyCards) == 1) continue;
  360. if (isSac(num) && sacCount(enemyCards) == 1) continue;
  361. if (isWet(num) && brightCount(enemyCards) >= 2) continue;
  362. //if no big wins where available, this mode fails and we return false
  363. return false;
  364. }
  365. //return true to cheat here (this indicates all cards in your hand gave the enemy a 5 pt yaku)
  366. return true;
  367. }
  368. else if (playField.length < 4)
  369. return false;
  370. var total=0;
  371. var goodYakuCount = 0;
  372. for (var i=1;i<13;i++)
  373. if (monthCount(i, hand) > 2)
  374. return false;
  375.  
  376. for (var i=0;i<hand.length;i++)
  377. {
  378. var num = hand[i].num;
  379. if (isSac(num) && !sacConflict() ) goodYakuCount++;
  380. if (isLoop(num) && !loopConflict() ) goodYakuCount++;
  381. if (isBright(num) && !brightConflict() ) goodYakuCount++;
  382. if (isRribbon(num) && !rRibbonConflict()) goodYakuCount++;
  383. if (isBribbon(num) && !bRibbonConflict() ) goodYakuCount++;
  384. if (isRoShamBo(num) && !roConflict() ) goodYakuCount++;
  385. total += hand[i].value;
  386.  
  387. if (guaranteed(hand[i])>0)
  388. return false;
  389. }
  390. if ((total <= cheatThreshold && goodYakuCount == 0) ||
  391. (total <= cheatThreshold/2 && goodYakuCount == 1) ||
  392. (total <= cheatThreshold/4 && goodYakuCount == 2))
  393. return true;
  394.  
  395. return false;
  396. }
  397. function setValues(list, inField)
  398. {
  399. for (var i=0;i<list.length;i++)
  400. {
  401. var num = list[i].num;
  402. list[i].value = getValue(list[i]);
  403. if (monthCount(list[i].month, hand) > 1 && !inField)
  404. list[i].value *= twoInHand;
  405. if (monthCount(list[i].month, hand) + monthCount(list[i].month, playField) > 2 && !inField)
  406. list[i].value *= threeInPlay;
  407. //guaranteed type 1 done before block (you are guaranteed 1 of 2 cards,however enemy can still play the suit)
  408. if (guaranteed(list[i]) == 1)
  409. list[i].value *= guaranteeMult;
  410. list[i].value += monthMult[list[i].month];
  411. //guaranteed type 2 done after block (you are guaranteed the card regardless, and can do nothing to block a play)
  412. if (guaranteed(list[i]) == 2)
  413. list[i].value *= guaranteeMult;
  414. if (inField)
  415. list[i].value *= onFieldMult;
  416. }
  417. }
  418.  
  419. function monthCount(month, list)
  420. {
  421. var count = 0;
  422. for (var i=0;i<list.length;i++)
  423. if (list[i].month == month)
  424. count++;
  425. return count;
  426. }
  427. function insertAfter(newElement,targetElement)
  428. {
  429. var parent = targetElement.parentNode;
  430. if(parent.lastchild == targetElement)
  431. parent.appendChild(newElement);
  432. else
  433. parent.insertBefore(newElement, targetElement.nextSibling);
  434. }
  435.  
  436. //initiate a card object
  437. function Card(Num, element)
  438. {
  439. this.num = Num;
  440. this.month = Math.ceil(Num/4);
  441. this.element = element;
  442. this.playable = false;
  443. this.value = 0;
  444. }
  445. //creates and returns a card object from a card in hand element
  446. function getCard(element)
  447. {
  448. cardNum = element.getAttribute("for");
  449. num = /handcard(\d+)/.exec(cardNum);
  450. if (!num)
  451. ShowMsg("Failed to get Card Number");
  452. return new Card(parseInt(num[1]), element);
  453. }
  454.  
  455. //getType functions
  456. function isRoShamBo(num) { return (num == 21 || num == 25 || num == 37); }
  457. function isRribbon(num) { return (num == 2 || num == 6 || num == 10); }
  458. function isBribbon(num) { return (num == 22 || num == 34 || num == 38); }
  459. function isBright(num) { return (num == 29 || num == 45 || num == 1 || num == 9); }
  460. function isLoop(num) { return (num == 29 || num == 17); }
  461. function isSac(num) { return (num == 29 || num == 44); }
  462. function isWet(num) { return num == 41;}
  463. function isRibbon(num) { return (isRribbon(num) || isBribbon(num) || num == 43 || num == 26 || num == 18 || num == 14);}
  464. function isAnimal(num) { return (isRoShamBo(num) || num == 42 || num == 33 || num == 30 || num == 17 || num == 13 || num == 5);}
  465. function isPlain(num) { return ((!isAnimal(num) || num == 33) && !isBright(num) && !isRibbon(num) && !isWet(num));}
  466.  
  467. //functions to get card values (based on yaku counts)
  468. function plainMult () {return (plain * ( 1 + plainCount(yourCards) + plainCount(enemyCards) / offensive) / 10);}
  469. function ribbonMult () {return (ribbon * ( 1 + ribbonCount(yourCards) + ribbonCount(enemyCards) / offensive) / 5);}
  470. function animalMult () {return (animal * ( 1 + animalCount(yourCards) + animalCount(enemyCards) / offensive) / 5);}
  471. function RribbonMult () {return (Rribbon * ( 1 + rRibbonCount(yourCards) + rRibbonCount(enemyCards) / offensive) / 3);}
  472. function BribbonMult () {return (Bribbon * ( 1 + bRibbonCount(yourCards) + bRibbonCount(enemyCards) / offensive) / 3);}
  473. function RoShamBoMult () {return (RoShamBo * ( 1 + roCount(yourCards) + roCount(enemyCards) / offensive) / 3);}
  474. function brightMult () {return (brights * ( 1 + brightCount(yourCards) + brightCount(enemyCards) / offensive) / 3);}
  475. function loopMult () {return (loop * ( 1 + loopCount(yourCards) + loopCount(enemyCards) / offensive) / 2);}
  476. function sacMult () {return (sacrifice * ( 1 + sacrificeCount(yourCards) + sacrificeCount(enemyCards)/ offensive) / 2);}
  477. function wetMult () {return (wetBright * ( 1 + brightCount(yourCards) + brightCount(enemyCards) / offensive) / 4);}
  478.  
  479. function rRibbonConflict() {return (hasRed (yourCards) && hasRed (enemyCards));}
  480. function bRibbonConflict() {return (hasBlue (yourCards) && hasBlue (enemyCards));}
  481. function roConflict() {return (hasRo (yourCards) && hasRo (enemyCards));}
  482. function brightConflict() {return (has2Bri (yourCards) && has2Bri (enemyCards));}
  483. function sacConflict() {return (hasSac (yourCards) && hasSac (enemyCards));}
  484. function loopConflict() {return (hasLoop (yourCards) && hasLoop (enemyCards));}
  485.  
  486. //returns -1 if it made a play, 0 if no guaranteed yakus (continue game)
  487. // otherwise it returns a month value (to protect if forced koi)
  488. function guaranteedYaku()
  489. {
  490. //for all months
  491. for (var i = 1;i < 13;i++)
  492. {
  493. var yakuList = [];
  494. var handMonths = getMonthFromList(hand, i);
  495. var fieldMonths = getMonthFromList(playField, i);
  496. if (!handMonths)
  497. continue;
  498. var combineCards = handMonths.concat(fieldMonths);
  499. if (!listGivesYaku(yourCards, combineCards) || handMonths.length < 1)
  500. continue;
  501. //get a list of all pairs that can give yakus
  502. for (var j=0;j<combineCards.length;j++)
  503. for (var k=0;k<combineCards.length;k++)
  504. if (j != k && guaranteed(combineCards[j])>0 && guaranteed(combineCards[j])>0)
  505. {
  506. var tmpList = [];
  507. tmpList.push(combineCards[j]);
  508. tmpList.push(combineCards[k]);
  509. if (listGivesYaku(yourCards, tmpList))
  510. {
  511. yakuList.push(new cardPair(combineCards[j],combineCards[k]));
  512. }
  513. }
  514. //for all the pairs, skip it if its not possible
  515. for (var b=0;b<yakuList.length;b++)
  516. {
  517. var inHand = 0;
  518. var onField = 0;
  519. var handC = null;
  520. if (hasCard(hand, yakuList[b].card1.num)) { inHand++; handC = yakuList[b].card1; }
  521. if (hasCard(hand, yakuList[b].card2.num)) { inHand++; handC = yakuList[b].card2; }
  522. if (hasCard(playField, yakuList[b].card1.num)) onField++;
  523. if (hasCard(playField, yakuList[b].card2.num)) onField++;
  524. //this is the easiest case, simply play the yaku
  525. if (inHand == 1 && onField == 1 && guaranteed(yakuList[b].card1)>0 && guaranteed(yakuList[b].card2)>0)
  526. return true;
  527. // this is the harder case, you must first play 2 cards, so just pick the 2 highest value cards
  528. else if (inHand == 2 && fieldMonths == 2)
  529. return true;
  530. else if (inHand == 2 && fieldMonths <= 1)
  531. return true;
  532. else if (inHand == 1 && fieldMonths >= 2 && givesYaku(yourCards, handC.num))
  533. return true;
  534. }
  535. }
  536. return false;
  537. }
  538.  
  539. //functions for checking yakus
  540. function hasRo (list)
  541. {
  542. for (var i=0;i<list.length;i++)
  543. if (isRoShamBo(list[i].num))
  544. return true;
  545. return false;
  546. }
  547. function hasRed (list)
  548. {
  549. for (var i=0;i<list.length;i++)
  550. if (isRribbon(list[i].num))
  551. return true;
  552. return false;
  553. }
  554. function hasBlue(list)
  555. {
  556. for (var i=0;i<list.length;i++)
  557. if (isBribbon(list[i].num))
  558. return true;
  559. return false;
  560. }
  561. function hasBright(list)
  562. {
  563. for (var i=0;i<list.length;i++)
  564. if (isBright(list[i].num))
  565. return true;
  566. return false;
  567. }
  568. function has2Bri(list)
  569. {
  570. count = 0;
  571. for (var i=0;i<list.length;i++)
  572. if (isBright(list[i].num))
  573. {
  574. count++;
  575. if (count == 2)
  576. return true;
  577. }
  578. return false;
  579. }
  580. function hasLoop(list)
  581. {
  582. for (var i=0;i<list.length;i++)
  583. if (isLoop(list[i].num))
  584. return true;
  585. return false;
  586. }
  587. function hasSac (list)
  588. {
  589. for (var i=0;i<list.length;i++)
  590. if (isSac(list[i].num))
  591. return true;
  592. return false;
  593. }
  594. //check if any card from a month is contained in the list
  595. function hasMonth(cardList, month)
  596. {
  597. if (!cardList)
  598. return false;
  599. for (var i=0;i<cardList.length;i++)
  600. if (cardList[i].month == month)
  601. return true;
  602. return false;
  603. }
  604. function plainCount(list)
  605. {
  606. var count = 0;
  607. for (var i = 0;i<list.length;i++)
  608. if (isPlain(list[i].num))
  609. count++;
  610. return count;
  611. }
  612. function animalCount(list)
  613. {
  614. var count = 0;
  615. for (var i = 0;i<list.length;i++)
  616. if (isAnimal(list[i].num))
  617. count++;
  618. return count;
  619. }
  620. function ribbonCount(list)
  621. {
  622. var count = 0;
  623. for (var i = 0;i<list.length;i++)
  624. if (isRibbon(list[i].num))
  625. count++;
  626. return count;
  627. }
  628. function redCount(list) {return rRibbonCount(list);}
  629. function blueCount(list) {return bRibbonCount(list);}
  630. function rRibbonCount(list)
  631. {
  632. var count = 0;
  633. for (var i = 0;i<list.length;i++)
  634. if (isRribbon(list[i].num))
  635. count++;
  636. return count;
  637. }
  638. function bRibbonCount(list)
  639. {
  640. var count = 0;
  641. for (var i = 0;i<list.length;i++)
  642. if (isBribbon(list[i].num))
  643. count++;
  644. return count;
  645. }
  646. function roCount(list)
  647. {
  648. var count = 0;
  649. for (var i = 0;i<list.length;i++)
  650. if (isRoShamBo(list[i].num))
  651. count++;
  652. return count;
  653. }
  654. function brightCount(list)
  655. {
  656. var count = 0;
  657. for (var i = 0;i<list.length;i++)
  658. if (isBright(list[i].num))
  659. count++;
  660. return count;
  661. }
  662. function loopCount(list)
  663. {
  664. var count = 0;
  665. for (var i = 0;i<list.length;i++)
  666. if (isLoop(list[i].num))
  667. count++;
  668. return count;
  669. }
  670. function sacCount(list)
  671. {
  672. return sacrificeCount(list);
  673. }
  674. function sacrificeCount(list)
  675. {
  676. var count = 0;
  677. for (var i = 0;i<list.length;i++)
  678. if (isSac(list[i].num))
  679. count++;
  680. return count;
  681. }
  682.  
  683. function findLoop(list)
  684. {
  685. for (var i=0;i<list.length;i++)
  686. if (isLoop(list[i].num))
  687. return list[i];
  688. return null;
  689. }
  690. function findSac(list)
  691. {
  692. for (var i=0;i<list.length;i++)
  693. if (isSac(list[i].num))
  694. return list[i];
  695. return null;
  696. }
  697. function findRo(list)
  698. {
  699. for (var i=0;i<list.length;i++)
  700. if (isRo(list[i].num))
  701. return list[i];
  702. return null;
  703. }
  704. function findRed(list)
  705. {
  706. for (var i=0;i<list.length;i++)
  707. if (isRed(list[i].num))
  708. return list[i];
  709. return null;
  710. }
  711. function findBlue(list)
  712. {
  713. for (var i=0;i<list.length;i++)
  714. if (isBlue(list[i].num))
  715. return list[i];
  716. return null;
  717. }
  718. function findBright(list)
  719. {
  720. for (var i=0;i<list.length;i++)
  721. if (isBright(list[i].num))
  722. return list[i];
  723. return null;
  724. }
  725.  
  726. function givesYaku(cardList, cardNum)
  727. {
  728. var yaku = 0, Ro=0,Red=0,Blue=0,Bright=0,Loop=0,Sac=0,Ribbon=0,Animal=0,Plain=0;
  729. //get yaku counts
  730. for (var i=0;i<cardList.length;i++)
  731. {
  732. num = cardList[i].num;
  733. if (isRoShamBo(num)) Ro++;
  734. if (isRribbon(num) ) Red++;
  735. if (isBribbon(num) ) Blue++;
  736. if (isBright(num) ) Bright++;
  737. if (isLoop(num) ) Loop++;
  738. if (isSac(num) ) Sac++;
  739. if (isRibbon(num) ) Ribbon++;
  740. if (isAnimal(num) ) Animal++;
  741. if (isPlain(num) ) Plain++;
  742. }
  743.  
  744. if (isRoShamBo(cardNum)&& Ro == 2) yaku++;
  745. if (isRribbon(cardNum) && Red == 2) yaku++;
  746. if (isBribbon(cardNum) && Blue == 2) yaku++;
  747. if (isBright(cardNum) && Bright >= 2) yaku++;
  748. if (isLoop(cardNum) && Loop == 1) yaku++;
  749. if (isSac(cardNum) && Sac == 1) yaku++;
  750. if (isRibbon(cardNum) && Ribbon >= 4) yaku++;
  751. if (isAnimal(cardNum) && Animal >= 4) yaku++;
  752. if (isPlain(cardNum) && Plain >= 9) yaku++;
  753. if (isWet(cardNum) && Bright > 2 ) yaku++;
  754.  
  755. return yaku;
  756. }
  757.  
  758. function listHasYakus(cardList)
  759. {
  760. var yaku = 0, Ro=0,Red=0,Blue=0,Bright=0,Loop=0,Sac=0,Ribbon=0,Animal=0,Plain=0,num=0,Wet=false;
  761. //get yaku counts
  762. for (var i=0;i<cardList.length;i++)
  763. {
  764. num = cardList[i].num;
  765. //these values are kept at most 1 below the yaku values
  766. //(this function finds new yakus, not existing ones)
  767. if (isRoShamBo(num)) Ro += 1;
  768. if (isRribbon(num) ) Red += 1;
  769. if (isBribbon(num) ) Blue += 1;
  770. if (isBright(num) ) Bright += 1;
  771. if (isLoop(num) ) Loop += 1;
  772. if (isSac(num) ) Sac += 1;
  773. if (isRibbon(num) ) Ribbon += 1;
  774. if (isAnimal(num) ) Animal += 1;
  775. if (isPlain(num) ) Plain += 1;
  776. if (isWet(num) ) wet = true;
  777. }
  778. if (Ro>=3) yaku++;
  779. if (Red>=3) yaku++;
  780. if (Blue>=3) yaku++;
  781. if (Bright>=3) yaku++;
  782. if (Loop>=2) yaku++;
  783. if (Sac>=2) yaku++;
  784. if (Ribbon>=5) yaku++;
  785. if (Animal>=5) yaku++;
  786. if (Plain>=10) yaku++;
  787. if (Wet && Bright >= 3) yaku++;
  788. return yaku;
  789. }
  790.  
  791. function listGivesYaku(cardList, checkList)
  792. {
  793. var yaku = 0, Ro=0,Red=0,Blue=0,Bright=0,Loop=0,Sac=0,Ribbon=0,Animal=0,Plain=0,num=0,realB=0,Wet=false;
  794. //get yaku counts
  795. for (var i=0;i<cardList.length;i++)
  796. {
  797. num = cardList[i].num;
  798. //these values are kept at most 1 below the yaku values
  799. //(this function finds new yakus, not existing ones)
  800. if (isRoShamBo(num)) Ro = Math.min(Ro + 1, 2);
  801. if (isRribbon(num) ) Red = Math.min(Red + 1, 2);
  802. if (isBribbon(num) ) Blue = Math.min(Blue + 1, 2);
  803. if (isBright(num) ) { Bright = Math.min(Bright + 1, 2); realB ++;}
  804. if (isLoop(num) ) Loop = Math.min(Loop + 1, 1);
  805. if (isSac(num) ) Sac = Math.min(Sac + 1, 1);
  806. if (isRibbon(num) ) Ribbon = Math.min(Ribbon + 1, 4);
  807. if (isAnimal(num) ) Animal = Math.min(Animal + 1, 4);
  808. if (isPlain(num) ) Plain = Math.min(Plain + 1, 9);
  809. }
  810. for (var i=0;i<checkList.length;i++)
  811. {
  812. num = checkList[i].num;
  813. if (isRoShamBo(num)) Ro++;
  814. if (isRribbon(num) ) Red++;
  815. if (isBribbon(num) ) Blue++;
  816. if (isBright(num) ) Bright++;
  817. if (isLoop(num) ) Loop++;
  818. if (isSac(num) ) Sac++;
  819. if (isRibbon(num) ) Ribbon++;
  820. if (isAnimal(num) ) Animal++;
  821. if (isPlain(num) ) Plain++;
  822. if (isWet(num) ) Wet=true;
  823. }
  824. if (Ro > 2) yaku++;
  825. if (Red > 2) yaku++;
  826. if (Blue > 2) yaku++;
  827. if (Bright > 2) yaku++;
  828. if (Loop > 1) yaku++;
  829. if (Sac > 1) yaku++;
  830. if (Ribbon > 4) yaku++;
  831. if (Animal > 4) yaku++;
  832. if (Plain > 9) yaku++;
  833. if (realB > 2 && Wet) yaku++;
  834.  
  835. return yaku;
  836. }
  837. //gets the value of a card
  838. function getValue(card)
  839. {
  840. var num = card.num;
  841. return (isPlain(num) * plainMult()+
  842. isRibbon(num) * ribbonMult()+
  843. isAnimal(num) * animalMult()+
  844. isRribbon(num) * RribbonMult()+
  845. isBribbon(num) * BribbonMult()+
  846. isRoShamBo(num) * RoShamBoMult()+
  847. isBright(num) * brightMult()+
  848. isLoop(num) * loopMult()+
  849. isSac(num) * sacMult()+
  850. isWet(num) * wetMult());
  851. }
  852.  
  853. // 2 for completely guaranteed (all cards are yours)
  854. // 1 if partial guaranteed (you get to pick between 2 cards)
  855. // -1 if the card is impossible to obtain
  856. // 0 otherwise
  857. function guaranteed(card)
  858. {
  859. var month = card.month;
  860. var inHand = false;
  861. var hCards = 0, oCards = 0, fCards = 0;
  862. for (var i = 0;i<hand.length;i++)
  863. if (hand[i].month == month)
  864. {
  865. hCards++;
  866. if (card.num == hand[i].num)
  867. inHand = true;
  868. }
  869.  
  870. for (var i = 0;i<playField.length;i++)
  871. if (playField[i].month == month)
  872. fCards++;
  873. for (var i = 0;i<yourCards.length;i++)
  874. if (yourCards[i].month == month)
  875. oCards++;
  876. for (var i = 0;i<enemyCards.length;i++)
  877. if (enemyCards[i].month == month)
  878. oCards++;
  879. var count = hCards+oCards+fCards;
  880. if (oCards == 3)
  881. return -1;
  882. if (fCards == 2 && hCards == 2 ||
  883. hCards == 3 && fCards == 1 ||
  884. hCards == 4 ||
  885. hCards == 1 && fCards >= 1 && count == 4)
  886. return 2;
  887. if (oCards == 1)
  888. if (hCards == 2 && fCards == 1 && inHand ||
  889. hCards == 3 && fCards == 0 ||
  890. hCards == 1 && fCards == 2 && !inHand)
  891. return 1;
  892. else if (oCards == 0)
  893. if (hCards == 2 && fCards == 1 && inHand ||
  894. hCards == 3 && fCards == 0 ||
  895. hCards == 1 && fCards == 2 && !inHand ||
  896. hCards == 1 && fCards == 3 && !inHand )
  897. return 1;
  898. return 0;
  899. }
  900.  
  901.  
  902. function getDeckCard()
  903. {
  904. var elems, current;
  905. var deckCard;
  906. elems = document.evaluate(
  907. ".//td[contains(./b/text(),'Game')]",
  908. document,
  909. null,
  910. XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  911. null);
  912.  
  913. for (var i = 0; i < elems.snapshotLength; i++)
  914. {
  915. current = elems.snapshotItem(i);
  916. match = current.innerHTML.match(/billy.layout.hcards.(thumbs.)?(\d+).jpg/i);
  917. if(!match || match.length != 3)
  918. continue;
  919. deckCard = new Card(match[2], current);
  920. }
  921. return deckCard
  922. }
  923. function getHand()
  924. {
  925. var elems, current;
  926. hand = [];
  927. //get your hand
  928. elems = document.evaluate(
  929. ".//label[contains(@for,'handcard')]",
  930. document,
  931. null,
  932. XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
  933. null);
  934.  
  935. for (var i = 0; i < elems.snapshotLength; i++)
  936. {
  937. current = elems.snapshotItem(i);
  938. addcard = getCard(current);
  939. hand.push(addcard);
  940. }
  941. return hand;
  942. }
  943. function getYourCards()
  944. {
  945. var hasDual = false
  946. var yourCards = []
  947. cards = /You .*Current Score.*(billy.layout.hcards.(thumbs.)?\d+.jpg.*).*/i.exec(document.body.innerHTML);
  948. if (cards)
  949. cards = cards[0];
  950.  
  951. while (cards)
  952. {
  953. temp = /billy.layout.hcards.(thumbs.)?(\d+).jpg(.*)/.exec(cards);
  954. if (!temp || temp.length != 4)
  955. break;
  956. cards = temp[3];
  957. if (temp[2] != 33) //dual card
  958. yourCards.push(new Card(temp[2]));
  959. else
  960. {
  961. if (!hasDual)
  962. {
  963. hasDual = true;
  964. yourCards.push(new Card(temp[2]));
  965. }
  966. }
  967. }
  968. return yourCards;
  969. }
  970. function getEnemyCards()
  971. {
  972. var enemyCards = []
  973. cards = /Them .*Current Score.*(billy.layout.hcards.(thumbs.)?\d+.jpg.*).*/i.exec(document.body.innerHTML);
  974. if (cards)
  975. cards = cards[0];
  976. var hasDual = false;
  977. while (cards)
  978. {
  979. temp = /billy.layout.hcards.(thumbs.)?(\d+).jpg(.*)/.exec(cards);
  980. if (!temp || temp.length != 4)
  981. break;
  982. cards = temp[3];
  983.  
  984. if (temp[2] != 33) //dual card
  985. enemyCards.push(new Card(temp[2]));
  986. else
  987. {
  988. if (!hasDual)
  989. {
  990. hasDual = true;
  991. enemyCards.push(new Card(temp[2]));
  992. }
  993. }
  994. }
  995. return enemyCards;
  996. }
  997. function getFieldCards()
  998. {
  999. var playField = [];
  1000. elems = document.evaluate(
  1001. ".//label[contains(@for,'cardinbutton')]",
  1002. document,
  1003. null,
  1004. XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
  1005. null);
  1006.  
  1007. for (var i = 0; i < elems.snapshotLength; i++)
  1008. {
  1009. current = elems.snapshotItem(i);
  1010. match = current.innerHTML.match(/billy.layout.hcards.(thumbs.)?(\d+).jpg/i);
  1011. if(!match)
  1012. {
  1013. emptySlot = current;
  1014. continue;
  1015. }
  1016. if(match.length != 3)
  1017. ShowMsg("Failed to get field cards");
  1018. cardNum = match[2];
  1019. addCard = new Card(cardNum, current);
  1020. playField.push(addCard);
  1021. }
  1022. return playField;
  1023. }
  1024. function getAvailable(month)
  1025. {
  1026. var list = []
  1027. for (var i = 4*(month-1) + 1;i < 4*month+1;i++)
  1028. {
  1029. if (isAvailable(i))
  1030. {
  1031. list.push(new Card(i,null));
  1032. }
  1033. }
  1034. return list;
  1035. }
  1036. function isAvailable(num)
  1037. {
  1038. avail = true;
  1039. for (var i=0;i<hand.length;i++)
  1040. if (num == hand[i].num)
  1041. avail = false;
  1042. for (var i=0;i<playField.length;i++)
  1043. if (num == playField[i].num)
  1044. avail = false;
  1045. for (var i=0;i<yourCards.length;i++)
  1046. if (num == yourCards[i].num)
  1047. avail = false;
  1048. for (var i=0;i<enemyCards.length;i++)
  1049. if (num == enemyCards[i].num)
  1050. avail = false;
  1051. return avail;
  1052. }
  1053. //true if script recommends koikoi
  1054. function koikoi()
  1055. {
  1056. var gYaku = guaranteedYaku();
  1057. if (forceKoi && !enemyHasKoiKoi && gYaku)
  1058. {
  1059. koiReasons.push(new Reason("Since the enemy is forced to koikoi, and you have a guaranteed play, it is perfectly safe to keep playing"));
  1060. return true;
  1061. }
  1062. var toKoi = 0; //increases based on how close you are to getting more points
  1063. var toBank = 0; //increases based on how close enemy is to winning
  1064. var threshold = 0;
  1065. //add likelyhood of yakus for matching pairs in play, and 1/2 the amt for non matching
  1066. for (var i=0;i<hand.length;i++)
  1067. {
  1068. if (givesYaku(yourCards, hand[i].num))
  1069. {
  1070. if (guaranteed(hand[i]) > 0) { toKoi += 5; koiReasons.push(new Reason("Guaranteed a yaku",5)); }
  1071. else if (hasMonth(playField, hand[i].month)) { toKoi+=1; koiReasons.push(new Reason("likely to get a yaku (2 cards visible that will give a yaku if taken)",1)); }
  1072. else { toKoi += .4; koiReasons.push(new Reason("possible yaku available if a month match is drawn",.4)); }
  1073. }
  1074. else
  1075. {
  1076. //get all possible deck cards that can match
  1077. var cardsAvail = getMonthCards(hand[i].month)
  1078. if (cardsAvail)
  1079. {
  1080. //get values for unseen cards
  1081. for (var k = 0;k<cardsAvail.length;k++)
  1082. cardsAvail[k].value = getValue(cardsAvail[k]);
  1083. var bestCard = getHighestValue(cardsAvail);
  1084.  
  1085. //at this point, this should always be true
  1086. if (hand[i] && bestCard)
  1087. {
  1088. var yakus = getYakus(yourCards, enemyCards, hand[i], bestCard);
  1089. for (var k=0;k<10;k++)
  1090. if (yakus[k] > 0)
  1091. {
  1092. var dist = yakus[k];
  1093. toKoi += 1/(dist*dist) / 10;
  1094. var text = "card " + getCardType(hand[i]) + " + "+ getCardType(bestCard) + " yields dist " + dist + " away from a ";
  1095. if (k == 0)
  1096. text+="plain yaku";
  1097. else if (k == 1)
  1098. text+="ribbon yaku";
  1099. else if (k == 2)
  1100. text+="animal yaku";
  1101. else if (k == 3)
  1102. text+="RoShamBo yaku";
  1103. else if (k == 4)
  1104. text+="red ribbon yaku";
  1105. else if (k == 5)
  1106. text+="blue ribbon yaku";
  1107. else if (k == 6)
  1108. text+="bright yaku";
  1109. else if (k == 7)
  1110. text+="loop yaku";
  1111. else if (k == 8)
  1112. text+="sacrifice yaku";
  1113. else
  1114. text="card " + getCardType(hand[i]) + " on "+ getCardType(bestCard) +" gives a wet yaku";
  1115. if (1/(dist*dist)/10 >= .03)
  1116. koiReasons.push(new Reason(text,Math.round(100/(dist*dist))/1000));
  1117. }
  1118. }
  1119. }
  1120. }
  1121. }
  1122. //perform the same check on field cards (with even lower likelihoods)
  1123. for (var i=0;i<playField.length;i++)
  1124. {
  1125. if (givesYaku(yourCards, playField[i].num))
  1126. {
  1127. if (guaranteed(playField[i]) > 0) { toKoi += 5; koiReasons.push(new Reason("Guaranteed a yaku",5)); }
  1128. else if (hasMonth(hand, playField[i].month)) { toKoi+=1; koiReasons.push(new Reason("likely to get a yaku (2 cards visible that will give a yaku if taken)",1)); }
  1129. else { toKoi += .4; koiReasons.push(new Reason("possible yaku available if a month match is drawn",.4)); }
  1130. }
  1131. //get all possible cards in the deck cards that can match
  1132. var cardsAvail = getMonthCards(playField[i].month)
  1133. if (cardsAvail)
  1134. {
  1135. //get values for unseen cards
  1136. for (var k = 0;k<cardsAvail.length;k++)
  1137. cardsAvail[k].value = getValue(cardsAvail[k]);
  1138. var bestCard = getHighestValue(cardsAvail)
  1139. //at this point, this should always be true
  1140. if (playField[i] && bestCard)
  1141. {
  1142. var yakus = getYakus(yourCards, enemyCards, playField[i], bestCard);
  1143. for (var k=0;k<10;k++)
  1144. if (yakus[k] > 0)
  1145. {
  1146. var dist = yakus[k];
  1147. toKoi += 1/(dist*dist) / 10;
  1148. var text = "card " + playField[i].num + " + "+ bestCard.num + " yields dist " + dist + " away from a ";
  1149. if (k == 0)
  1150. text+="plain yaku";
  1151. else if (k == 1)
  1152. text+="ribbon yaku";
  1153. else if (k == 2)
  1154. text+="animal yaku";
  1155. else if (k == 3)
  1156. text+="RoShamBo yaku";
  1157. else if (k == 4)
  1158. text+="red ribbon yaku";
  1159. else if (k == 5)
  1160. text+="blue ribbon yaku";
  1161. else if (k == 6)
  1162. text+="bright yaku";
  1163. else if (k == 7)
  1164. text+="loop yaku";
  1165. else if (k == 8)
  1166. text+="sacrifice yaku";
  1167. else
  1168. text="card " + playField[i].num + " on "+ bestCard.num +" gives a wet yaku";
  1169. if (1/(dist*dist)/10 >= .03)
  1170. koiReasons.push(new Reason(text,Math.round(100/(dist*dist))/1000));
  1171. }
  1172. }
  1173. }
  1174. }
  1175.  
  1176. var checkList = []
  1177. for (var gg = 0;gg<hand.length;gg++)
  1178. checkList.push(hand[gg]);
  1179. for (var gg = 0;gg<playField.length;gg++)
  1180. checkList.push(playField[gg]);
  1181. //check enemy yakus
  1182. toBank += listHasYakus(enemyCards);
  1183. if (toBank > 0)
  1184. bankReasons.push(new Reason("Enemy Already Has Yakus", toBank));
  1185.  
  1186. for (var i=0;i<checkList.length;i++)
  1187. {
  1188. if (guaranteed(checkList[i].num) > 0)
  1189. continue;
  1190. var yakus = [], total = 0;
  1191. var possibleCards = getAvailable(checkList[i].month);
  1192. var storedBankReasons = [];
  1193. if (possibleCards)
  1194. {
  1195. for (var j = 0;j<possibleCards.length;j++)
  1196. {
  1197. if (possibleCards[j].num != checkList[i].num)
  1198. {
  1199. var tmpList = [];
  1200. var enemyYakus = 0;
  1201. tmpList.push(possibleCards[j]);
  1202. tmpList.push(checkList[i]);
  1203. enemyYakus = listGivesYaku(enemyCards, tmpList);
  1204. if (enemyYakus > 0)
  1205. {
  1206. bankReasons.push(new Reason("If the enemy plays " + getCardType(checkList[i])+ " with " + getCardType(possibleCards[j]) + " he can get a yaku", enemyYakus));
  1207. toBank += enemyYakus;
  1208. break;
  1209. }
  1210. else
  1211. {
  1212. var count = 0;
  1213. yakus = getYakus(enemyCards, yourCards, possibleCards[j], checkList[i]);
  1214. var tmpBankReasons = [];
  1215. for (var k=0;k<10;k++)
  1216. if (yakus[k] > 0)
  1217. {
  1218. var dist = yakus[k];
  1219. count += 3/(dist*dist) / 10;
  1220. var text = "card " + getCardType(checkList[i]) + " + "+ getCardType(possibleCards[j]) + " yields dist " + dist + " away from a ";
  1221. if (k == 0)
  1222. text+="plain yaku";
  1223. else if (k == 1)
  1224. text+="ribbon yaku";
  1225. else if (k == 2)
  1226. text+="animal yaku";
  1227. else if (k == 3)
  1228. text+="RoShamBo yaku";
  1229. else if (k == 4)
  1230. text+="red ribbon yaku";
  1231. else if (k == 5)
  1232. text+="blue ribbon yaku";
  1233. else if (k == 6)
  1234. text+="bright yaku";
  1235. else if (k == 7)
  1236. text+="loop yaku";
  1237. else if (k == 8)
  1238. text+="sacrifice yaku";
  1239. else
  1240. text="card " + getCardType(checkList[i]) + " with "+ getCardType(possibleCards[j]) +"gives a wet yaku";
  1241. if (3/(dist*dist)/10 >= .03)
  1242. tmpBankReasons.push(new Reason(text,Math.round(300/(dist*dist))/1000));
  1243. }
  1244. if (count > total)
  1245. {
  1246. total = count;
  1247. storedBankReasons = tmpBankReasons;
  1248. }
  1249. }
  1250. }
  1251. }
  1252. }
  1253. if (total > 0)
  1254. {
  1255. for (var bb = 0;bb < storedBankReasons.length;bb++)
  1256. bankReasons.push(storedBankReasons[bb]);
  1257. threshold += total;
  1258. total = 0;
  1259. }
  1260. }
  1261. if (getYourScoreToWin() - getScore() <= 0)
  1262. {
  1263. if (toBank > 0 || !gYaku)
  1264. {
  1265. bankReasons.push(new Reason("If you bank now, you win and this game is not guaranteed",""));
  1266. return false;
  1267. }
  1268. }
  1269. if (toBank >= 2)
  1270. {
  1271. bankReasons.push(new Reason("Since the enemy is close to obtaining 2 yakus, I've decided to bank",""));
  1272. return false;
  1273. }
  1274. if (getScore() < 7)
  1275. {
  1276. toKoi += .5;
  1277. koiReasons.push(new Reason("Your point score is low, and not as much to lose by koikoi",.3));
  1278. }
  1279. if (getScore() >= 7)
  1280. {
  1281. toBank += (getScore()-7)/2;
  1282. bankReasons.push(new Reason("You've exceeded the 2x multiplier, its best to bail before you lose big",Math.round(100*(getScore()-7)/3)/100));
  1283. }
  1284. var reason1 = new Reason("The total sum of weighted distances to enemy yakus is " + Math.round((threshold + toBank)*100)/100,"");
  1285. var reason2 = new Reason("The total sum of weighted distances to your yakus is " + Math.round(toKoi*100)/100,"");
  1286. koiReasons.push(reason2);
  1287. bankReasons.push(reason1);
  1288.  
  1289. if (toKoi < (threshold + toBank))
  1290. {
  1291. bankReasons.push(new Reason("Since the enemy has been calculated to have a high chance of reaching a yaku, I think its best if you bank now",""));
  1292. return false;
  1293. }
  1294. koiReasons.push(new Reason("Since the enemy seems much further from reaching a yaku then you, I would suggest koikoi",""));
  1295. return true;
  1296. }
  1297. function showCardList(List)
  1298. {
  1299. var sum = "";
  1300. for (var i=0;i<List.length;i++)
  1301. sum = sum + " " + List[i].num;
  1302. alert(sum)
  1303. }
  1304. //Debug method for displaying a list of card values in BVS Daily (for a card list)
  1305. function showCardValues(List)
  1306. {
  1307. var sum = "";
  1308. for (var i=0;i<List.length;i++)
  1309. sum = sum + " " + List[i].value;
  1310. alert(sum)
  1311. }
  1312. //returns an array distance values from yakus
  1313. function getYakus(list, blockList, card1, card2)
  1314. {
  1315. if (!card2)
  1316. card2 = new Card(-1,null)
  1317. if (!card1)
  1318. card1 = new Card(-1,null)
  1319. var yaku = [];
  1320. if (isPlain(card1.num) || isPlain(card2.num )) yaku[0] = Math.max(1, 9 - plainCount(list) ); else yaku[0] = 0;
  1321. if (isPlain(card1.num) && isPlain(card2.num )) yaku[0] = Math.max(1, 8 - plainCount(list) ); else yaku[0] = 0;
  1322. if (isRibbon(card1.num) || isRibbon(card2.num )) yaku[1] = Math.max(1, 4 - ribbonCount(list) ); else yaku[1] = 0;
  1323. if (isAnimal(card1.num) || isAnimal(card2.num )) yaku[2] = Math.max(1, 4 - animalCount(list) ); else yaku[2] = 0;
  1324. if (isRoShamBo(card1.num) || isRoShamBo(card2.num)) yaku[3] = Math.max(1, 2 - roCount(list) ); else yaku[3] = 0;
  1325. if (isRribbon(card1.num) || isRribbon(card2.num )) yaku[4] = Math.max(1, 2 - rRibbonCount(list) ); else yaku[4] = 0;
  1326. if (isBribbon(card1.num) || isBribbon(card2.num )) yaku[5] = Math.max(1, 2 - bRibbonCount(list) ); else yaku[5] = 0;
  1327. if (isBright(card1.num) || isBright(card2.num )) yaku[6] = Math.max(1, 2 - brightCount(list) ); else yaku[6] = 0;
  1328. if (isLoop(card1.num) || isLoop(card2.num )) yaku[7] = Math.max(1, 1 - loopCount(list) ); else yaku[7] = 0;
  1329. if (isSac(card1.num) || isSac(card2.num )) yaku[8] = Math.max(1, 1 - sacrificeCount(list)); else yaku[8] = 0;
  1330. if ( (isWet(card1.num) || isWet(card2.num )) &&
  1331. brightCount(list) > 2) yaku[9] = 1; else yaku[9] = 0;
  1332. if (has2Bri(blockList)) yaku[6] = 0;
  1333. if (hasRo(blockList)) yaku[3] = 0;
  1334. if (hasRed(blockList)) yaku[4] = 0;
  1335. if (hasBlue(blockList)) yaku[5] = 0;
  1336. if (hasSac(blockList)) yaku[8] = 0;
  1337. if (hasLoop(blockList)) yaku[7] = 0;
  1338. return yaku;
  1339. }
  1340. //returns the card with the highest value from a list
  1341. function getHighestValue(cardList)
  1342. {
  1343. if (!cardList)
  1344. return null;
  1345. //find the best highest valued card that matches
  1346. var bestCard = cardList[0];
  1347. for (var k = 1;k<cardList.length;k++)
  1348. if (cardList[k].value > bestCard.value)
  1349. bestCard = cardList[k];
  1350. return bestCard;
  1351. }
  1352. function getLowestValue(cardList)
  1353. {
  1354. if (!cardList)
  1355. return null;
  1356. //find the best highest valued card that matches
  1357. var worst=cardList[0];
  1358. for (var k = 1;k<cardList.length;k++)
  1359. if (cardList[k].value < worst.value)
  1360. worst = cardList[k];
  1361. return worst;
  1362. }
  1363. function playDeck()
  1364. {
  1365. var playOn = [];
  1366.  
  1367. //handle playing a card off deck if necessary
  1368. for (var i=0;i<playField.length;i++)
  1369. if (playField[i].month == deckCard.month)
  1370. playOn.push(playField[i]);
  1371.  
  1372. for (var i=0;i<playOn.length;i++)
  1373. playOn[i].playable = true;
  1374. //find the best card and pick it
  1375. var bestCard = getHighestValue(playOn)
  1376. if (bestCard)
  1377. clickRadioButton(bestCard.element);
  1378. else
  1379. clickRadioButton(emptySlot);
  1380. }
  1381. function playCard()
  1382. {
  1383. //if a yaku is guaranteed, let this function handle it, and do nothing
  1384. if (playGuaranteedYaku())
  1385. return true;
  1386.  
  1387. //get a list of cards in hand with matching months to cards on field
  1388. var playList = [];
  1389. var playOn = [];
  1390. //get a list of cards in month/hand with matching months
  1391.  
  1392. for (var k = 1;k<13;k++) //for all the months
  1393. {
  1394. var list1 = getMonthFromList(hand,k);
  1395. var list2 = getMonthFromList(playField,k);
  1396.  
  1397. if (list1.length == 0 || list2.length == 0 || noPlayMonth == k || cheatMonth == k)
  1398. continue;
  1399. for (var i=0;i<list1.length;i++)
  1400. {
  1401. list1[i].playable = true;
  1402. playList.push(list1[i]);
  1403. }
  1404. for (var i=0;i<list2.length;i++)
  1405. {
  1406. list2[i].playable = true;
  1407. playOn.push(list2[i]);
  1408. }
  1409. }
  1410.  
  1411.  
  1412. if (playOn.length == 0)
  1413. return false;
  1414. var newPlayList = [];
  1415. for (var i=0;i<playList.length;i++)
  1416. {
  1417. if (guaranteed(playList[i])>0)
  1418. newPlayList.push(playList[i]);
  1419. else
  1420. {
  1421. //get all possible deck cards that can match
  1422. var cardsAvail = getMonthCards(playList[i].month)
  1423. //get values (and half them) for unseen cards
  1424. for (var k = 0;k<cardsAvail.length;k++)
  1425. cardsAvail[k].value /= 2;
  1426. //find the best matching field card
  1427. bestCard=null, omit = false;
  1428. for (var k = 0;k<playField.length;k++)
  1429. if (playField[k].month == playList[i].month)
  1430. {
  1431. if (!bestCard)
  1432. bestCard = playField[k];
  1433. else if (playField[k].value > bestCard.value)
  1434. bestCard = playField[k];
  1435. }
  1436.  
  1437. for (var k = 0;k<cardsAvail.length;k++)
  1438. if (bestCard && bestCard.value < cardsAvail[k].value)
  1439. omit = true;
  1440.  
  1441. //if the unseen card is worth more than double a known card, wait (remove it from possiblities)
  1442. if (!omit)
  1443. newPlayList.push(playList[i]);
  1444. }
  1445. }
  1446. playList = newPlayList;
  1447. var handCard = null;
  1448. var fieldCard = null;
  1449. //loop and find the best pair
  1450. for (var i=0;i<playList.length;i++)
  1451. for (var j=0;j<playOn.length;j++)
  1452. {
  1453. if (playList[i].month != playOn[j].month)
  1454. continue;
  1455. if (!handCard || !fieldCard)
  1456. {
  1457. handCard = playList[i];
  1458. fieldCard = playOn[j];
  1459. }
  1460. else if ((playList[i].value + playOn[j].value) > (handCard.value + fieldCard.value))
  1461. {
  1462. handCard = playList[i];
  1463. fieldCard = playOn[j];
  1464. }
  1465. }
  1466.  
  1467. if (!handCard || !fieldCard)
  1468. return false;
  1469. if (cheatCard.value > (handCard.value + fieldCard.value))
  1470. return false;
  1471.  
  1472. //click the form radio buttons
  1473. clickRadioButton(handCard.element);
  1474. clickRadioButton(fieldCard.element);
  1475. return true;
  1476. }
  1477. //returns -1 if it made a play, 0 if no guaranteed yakus (continue game)
  1478. // otherwise it returns a month value (to protect if forced koi)
  1479. function playGuaranteedYaku()
  1480. {
  1481. //for all months
  1482. for (var i = 1;i < 13;i++)
  1483. {
  1484. var yakuList = [];
  1485. var handMonths = getMonthFromList(hand, i);
  1486. var fieldMonths = getMonthFromList(playField, i);
  1487. if (!handMonths)
  1488. continue;
  1489. var combineCards = handMonths.concat(fieldMonths);
  1490. if (!listGivesYaku(yourCards, combineCards) || handMonths.length < 1)
  1491. continue;
  1492. //get a list of all pairs that can give yakus
  1493. for (var j=0;j<combineCards.length;j++)
  1494. for (var k=0;k<combineCards.length;k++)
  1495. if (j != k && guaranteed(combineCards[j])>0 && guaranteed(combineCards[j])>0)
  1496. {
  1497. var tmpList = [];
  1498. tmpList.push(combineCards[j]);
  1499. tmpList.push(combineCards[k]);
  1500. if (listGivesYaku(yourCards, tmpList))
  1501. yakuList.push(new cardPair(combineCards[j],combineCards[k]));
  1502. }
  1503. //for all the pairs, skip it if its not possible
  1504. for (var b=0;b<yakuList.length;b++)
  1505. {
  1506. var inHand = 0;
  1507. var onField = 0;
  1508. if (hasCard(hand, yakuList[b].card1.num)) inHand++;
  1509. if (hasCard(hand, yakuList[b].card2.num)) inHand++;
  1510. if (hasCard(playField, yakuList[b].card1.num)) onField++;
  1511. if (hasCard(playField, yakuList[b].card2.num)) onField++;
  1512. //this is the easiest case, simply play the yaku
  1513. if (inHand == 1 && onField == 1 && onField)
  1514. {
  1515. if (forceKoi && !enemyHasKoiKoi && guaranteed(yakuList[b].card1)>0 && guaranteed(yakuList[b].card2)>0)
  1516. {
  1517. if (hasCard(hand, yakuList[b].card1.num))
  1518. {
  1519. yakuHandCard = yakuList[b].card1;
  1520. yakuFieldCard = yakuList[b].card2;
  1521. }
  1522. else
  1523. {
  1524. yakuHandCard = yakuList[b].card2;
  1525. yakuFieldCard = yakuList[b].card1;
  1526. }
  1527. noPlayMonth = i;
  1528. return false;
  1529. }
  1530. clickRadioButton(yakuList[b].card1.element);
  1531. clickRadioButton(yakuList[b].card2.element);
  1532. return true;
  1533. }
  1534. // this is the harder case, you must first play 2 cards, so just pick the 2 highest value cards
  1535. else if (monthCount(yakuList[b].card1.month, playField) > 0)
  1536. continue;
  1537. else if (inHand == 2 && fieldMonths == 0)
  1538. {
  1539. //discard either one (both are guaranteed)
  1540. clickRadioButton(yakuList[b].card1.element);
  1541. clickRadioButton(emptySlot);
  1542. return true;
  1543. }
  1544. }
  1545. }
  1546.  
  1547. //run a second check to see if there is a guaranteed yaku made up of 2+ guaranteed cards
  1548. var gList = [], card1, card2;
  1549. for (var i=0;i<hand.length;i++)
  1550. if (guaranteed(hand[i])>0)
  1551. gList.push(hand[i]);
  1552. for (var i=0;i<playField.length;i++)
  1553. if (guaranteed(playField[i])>0)
  1554. gList.push(playField[i]);
  1555. //this runs if you're playing towards 1 card from a guaranteed yaku
  1556.  
  1557. var playCard = null;
  1558. if (sacCount(yourCards) + sacCount(gList) == 3 && sacCount(gList) > 1) playCard = findSac(gList);
  1559. if (loopCount(yourCards) + loopCount(gList) == 3 && loopCount(gList) > 1) playCard = findLoop(gList);
  1560. if (redCount(yourCards) + redCount(gList) == 3 && redCount(gList) > 1) playCard = findRed(gList);
  1561. if (blueCount(yourCards) + blueCount(gList) == 3 && blueCount(gList) > 1) playCard = findBlue(gList);
  1562. if (roCount(yourCards) + roCount(gList) == 3 && roCount(gList) > 1) playCard = findRo(gList);
  1563. if (brightCount(yourCards) + brightCount(gList) == 3 && brightCount(gList) > 1) playCard = findBright(gList);
  1564.  
  1565. if (!playCard)
  1566. return false;
  1567. //find playcard, and match it with another card
  1568. var month = playCard.month;
  1569. var otherCard = null;
  1570. if (hasCard(hand, playCard.num))
  1571. {
  1572. for (var i=0;i<playField.length;i++)
  1573. if (playField[i].month == month)
  1574. {
  1575. otherCard = playField[i];
  1576. break;
  1577. }
  1578. }
  1579. else if (hasCard(playField, playCard.num))
  1580. {
  1581. for (var i=0;i<hand.length;i++)
  1582. if (hand[i].month == month)
  1583. {
  1584. otherCard = hand[i];
  1585. break;
  1586. }
  1587. }
  1588. if (!playCard || !otherCard)
  1589. return false;
  1590. clickRadioButton(playCard.element);
  1591. clickRadioButton(otherCard.element);
  1592. }
  1593. function cardPair(card1, card2)
  1594. {
  1595. this.card1 = card1;
  1596. this.card2 = card2;
  1597. }
  1598. function getMonthFromList(list, month)
  1599. {
  1600. var cardList = [];
  1601. for (var h = 0;h < list.length;h++)
  1602. if (list[h].month == month)
  1603. cardList.push(list[h]);
  1604. return cardList;
  1605. }
  1606. function getMonthCards(month)
  1607. {
  1608. var cardList = [];
  1609. for (var h = 0;h < 4;h++)
  1610. if (isAvailable(h+(month-1)*4+1))
  1611. cardList.push(new Card(h+(month-1)*4+1,null));
  1612. return cardList;
  1613. }
  1614. function discard()
  1615. {
  1616. var worstCard = null;
  1617. if ((cheatMonth > 0 && !hasMonth(playField, cheatMonth) && hasMonth(hand, cheatMonth)))
  1618. worstCard = cheatCard;
  1619. else
  1620. {
  1621. // calculate card values for cards in hand
  1622. for (var i=0;i<hand.length;i++)
  1623. {
  1624. if (guaranteed(hand[i]) == -1)
  1625. {
  1626. worstCard = hand[i];
  1627. break;
  1628. }
  1629. hand[i].playable=true;
  1630. var month = hand[i].month;
  1631. // this is designed to help with the selection of guaranteed cards
  1632. // (the best guaranteed card will be discarded to be taken)
  1633. if (guaranteed(hand[i])>0)
  1634. hand[i].value = 0.01 - hand[i].value;
  1635. //add the value of the highest valued card (for that month) to the discard value
  1636. else if (!guaranteed(hand[i])>0)
  1637. {
  1638. var cardsAvail = getAvailable(month);
  1639. var bestVal=0
  1640. for (var k=0;k<cardsAvail.length;k++)
  1641. {
  1642. var newVal = cardsAvail[k].value;
  1643. if (newVal > bestVal)
  1644. bestVal = newVal;
  1645. }
  1646. hand[i].value += bestVal;
  1647. }
  1648. }
  1649. //find the worst card and drop it
  1650. worstCard = null;
  1651. for (var k = 0;k<hand.length;k++)
  1652. if ((worstCard == null || hand[k].value < worstCard.value) && hand[k].month != noPlayMonth)
  1653. worstCard = hand[k];
  1654. }
  1655. if (worstCard)
  1656. {
  1657. clickRadioButton(worstCard.element);
  1658. clickRadioButton(emptySlot);
  1659. var otherCard=null;
  1660. //in case we have a matching month check here
  1661. for (var g =0;g<playField.length;g++)
  1662. if (playField[g].month == worstCard.month)
  1663. {
  1664. playField[g].playable = true;
  1665. if(!otherCard)
  1666. otherCard = playField[g];
  1667. else if (otherCard.value > playField[g].value)
  1668. otherCard = playField[g];
  1669. }
  1670. if (otherCard)
  1671. clickRadioButton(otherCard.element);
  1672. }
  1673. else
  1674. {
  1675. if (yakuHandCard && yakuFieldCard)
  1676. {
  1677. clickRadioButton(yakuHandCard.element);
  1678. clickRadioButton(yakuFieldCard.element);
  1679. }
  1680. }
  1681. }
  1682. function updateMultipliers()
  1683. {
  1684. //check for conflicting cards
  1685. var conflictBlue = false;
  1686. var conflictRed = false;
  1687. var conflictRo = false;
  1688. var conflictBright = 0;
  1689. var conflictLoop = false;
  1690. var conflictSac = false;
  1691. //update card multipliers from cards possesed by you and opponent
  1692. for (var i=0;i<yourCards.length;i++)
  1693. {
  1694. num = yourCards[i].num;
  1695. if (isRoShamBo(num)) conflictRo = true;
  1696. if (isRribbon(num) ) conflictRed = true;
  1697. if (isBribbon(num) ) conflictBlue = true;
  1698. if (isBright(num) ) conflictBright += 1;
  1699. if (isLoop(num) ) conflictLoop = true;
  1700. if (isSac(num) ) conflictSac = true;
  1701. }
  1702. var chkBright = 0;
  1703. for (var i=0;i<enemyCards.length;i++)
  1704. {
  1705. num = enemyCards[i].num;
  1706. if (isRoShamBo(num) && conflictRo ) RoShamBo = 0;
  1707. if (isRribbon(num) && conflictRed ) Rribbon = 0;
  1708. if (isBribbon(num) && conflictBlue ) Bribbon = 0;
  1709. if (isBright(num) && conflictBright > 1) chkBright ++;
  1710. if (isLoop(num) && conflictLoop ) loop = 0;
  1711. if (isSac(num) && conflictSac ) sacrifice = 0;
  1712. }
  1713. if (chkBright == 2)
  1714. brights = 0;
  1715. ////for all cards in the deck, add a block factor based on enemy yakus
  1716. for (var k =1;k<13;k++)
  1717. {
  1718. possibleCards = getMonthCards(k);
  1719. for (var i = 0;i<possibleCards.length;i++)
  1720. {
  1721. var ccard = possibleCards[i];
  1722. if (isRoShamBo(ccard.num)) monthMult[k] += (RoShamBo * roCount(enemyCards)) / monthBlock / 3;
  1723. if (isRribbon(ccard.num)) monthMult[k] += (Rribbon * rRibbonCount(enemyCards)) / monthBlock / 3;
  1724. if (isBribbon(ccard.num)) monthMult[k] += (Bribbon * bRibbonCount(enemyCards)) / monthBlock / 3;
  1725. if (isBright(ccard.num)) monthMult[k] += (brights * brightCount(enemyCards)) / monthBlock / 3;
  1726. if (isLoop(ccard.num)) monthMult[k] += (loop * loopCount(enemyCards)) / monthBlock / 2;
  1727. if (isSac(ccard.num)) monthMult[k] += (sacrifice * sacrificeCount(enemyCards)) / monthBlock / 2;
  1728. if (isRibbon(ccard.num)) monthMult[k] += (ribbon * ribbonCount(enemyCards)) / monthBlock / 5;
  1729. if (isAnimal(ccard.num)) monthMult[k] += (animal * animalCount(enemyCards)) / monthBlock / 5;
  1730. if (isPlain(ccard.num)) monthMult[k] += (plain * plainCount(enemyCards)) / monthBlock / 10;
  1731. }
  1732. }
  1733. }
  1734.  
  1735. function getCardType(card)
  1736. {
  1737. var num = card.num;
  1738. retString = "";
  1739. if (card.month == 1 ) retString += "Jan";
  1740. if (card.month == 2 ) retString += "Feb";
  1741. if (card.month == 3 ) retString += "Mar";
  1742. if (card.month == 4 ) retString += "Apr";
  1743. if (card.month == 5 ) retString += "May";
  1744. if (card.month == 6 ) retString += "Jun";
  1745. if (card.month == 7 ) retString += "jul";
  1746. if (card.month == 8 ) retString += "Aug";
  1747. if (card.month == 9 ) retString += "Sep";
  1748. if (card.month == 10) retString += "Oct";
  1749. if (card.month == 11) retString += "Nov";
  1750. if (card.month == 12) retString += "dec";
  1751. if (isRoShamBo(num)) retString += " A(Ro)";
  1752. else if (isRribbon (num)) retString += " R(Red)";
  1753. else if (isBribbon (num)) retString += " R(Blue)";
  1754. else if (isWet (num)) retString += " B(wet)";
  1755. else if (isBright (num)) retString += " B(dry)";
  1756. else if (isLoop (num)) retString += " P(loop)";
  1757. else if (isSac (num)) retString += " A(sac)";
  1758. else if (isRibbon (num)) retString += " R";
  1759. else if (isAnimal (num)
  1760. && isPlain (num)) retString += " P+A";
  1761. else if (isAnimal (num)) retString += " A";
  1762. else if (isPlain (num)) retString += " P";
  1763. return retString;
  1764. }
  1765.  
  1766. function hasCard(list, num)
  1767. {
  1768. for (var i = 0;i<list.length;i++)
  1769. if (list[i].num == num)
  1770. return true;
  1771. return false;
  1772. }
  1773.  
  1774. function clickRadioButton(element)
  1775. {
  1776. if (!element)
  1777. return false;
  1778. var strXPath = "";
  1779. strXPath += '//form[@name=\'' + "placecard" + '\']';
  1780. strXPath += '//input[@id=\'' + element.getAttribute("for") + '\']';
  1781. var elem = document.evaluate(strXPath, document, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
  1782. elem.checked = true;
  1783. }
  1784.  
  1785. function submitForm(formName)
  1786. {
  1787. if (document.forms.namedItem(formName))
  1788. document.forms.namedItem(formName).submit();
  1789. }
  1790.  
  1791. function getMultipliers(card, isField)
  1792. {
  1793. var num = card.num;
  1794. var month = card.month;
  1795. var multList = []
  1796. if (isPlain(num) ) multList.push(new Mult("is a member of plain yaku", Math.round(plainMult () *1000)/1000));
  1797. if (isRibbon(num) ) multList.push(new Mult("is a member of ribbon yaku", Math.round(ribbonMult () *1000)/1000));
  1798. if (isAnimal(num) ) multList.push(new Mult("is a member of animal yaku", Math.round(animalMult () *1000)/1000));
  1799. if (isRribbon(num) ) multList.push(new Mult("is a member of red ribbon yaku", Math.round(RribbonMult () *1000)/1000));
  1800. if (isBribbon(num) ) multList.push(new Mult("is a member of blue ribbon yaku", Math.round(BribbonMult () *1000)/1000));
  1801. if (isRoShamBo(num) ) multList.push(new Mult("is a member of roshambo yaku", Math.round(RoShamBoMult() *1000)/1000));
  1802. if (isBright(num) ) multList.push(new Mult("is a member of bright yaku", Math.round(brightMult () *1000)/1000));
  1803. if (isLoop(num) ) multList.push(new Mult("is a member of loop yaku", Math.round(loopMult () *1000)/1000));
  1804. if (isSac(num) ) multList.push(new Mult("is a member of sacrifice yaku", Math.round(sacMult () *1000)/1000));
  1805. if (isWet(num) ) multList.push(new Mult("can combine with 3+ brights", Math.round(wetMult () *1000)/1000));
  1806. if (givesYaku(yourCards, num)) multList.push(new Mult("This card gives you a yaku", Math.round(yakuMult *1000)/1000));
  1807. if (monthMult[month] > 0)
  1808. multList.push(new Mult("Month Deny (this value is added after 2/3 card negative multiplyers)", Math.round(monthMult[month]*1000)/1000))
  1809. if (isField)
  1810. multList.push(new Mult("Card is on field", "+" + ((Math.round(onFieldMult*1000)/1000) * 100) + "%"))
  1811. if (guaranteed(card)>0)
  1812. multList.push(new Mult(" of normal value (card is guaranteed)", guaranteeMult *100 + "%"))
  1813. if (discarding && monthCount(month, hand) > 1)
  1814. multList.push(new Mult("2 of a kind in hand", "-" +((Math.round((1- twoInHand)*1000)/1000) * 100) + "%"))
  1815. if (discarding && monthCount(month, hand) > 2)
  1816. multList.push(new Mult("3 of a kind in hand (stacks with 2 of a kind)", "-" + ((Math.round((1- threeInPlay)*1000)/1000) * 100) + "%"))
  1817. return multList;
  1818. }
  1819.  
  1820. //initiate a card object
  1821. function Mult(Name, Value)
  1822. {
  1823. this.name = Name;
  1824. this.value = Value;
  1825. }
  1826.  
  1827. function Reason(Text, Value)
  1828. {
  1829. this.text = Text;
  1830. this.value = Value;
  1831. }
  1832.  
  1833. function getScore()
  1834. {
  1835. var mtch = /: <b><i>(\d+)\S+?;Points<\/i><\/b><ta/.exec(document.body.innerHTML);
  1836. if (!mtch)
  1837. return -1;
  1838. return parseInt(mtch[1]);
  1839. }
  1840.  
  1841. this.debugBtn = document.createElement("a");
  1842. this.debugWindow1 = document.createElement("db1");
  1843. this.debugWindow2 = document.createElement("db2");
  1844. var forfForm = document.forms.namedItem("forfeit");
  1845. // add the debug popup button
  1846. insertAfter(this.debugBtn, forfForm);
  1847. this.debugBtn.style.color = "#000066";
  1848. this.debugBtn.style.fontSize = "25px";
  1849. if (document.forms.namedItem("bankpoints") || document.forms.namedItem("koikoi"))
  1850. this.debugBtn.href = "javascript:document.getElementById('debugWindow2').style.display = ''; void(0);";
  1851. else
  1852. this.debugBtn.href = "javascript:document.getElementById('debugWindow1').style.display = ''; void(0);";
  1853. this.debugBtn.innerHTML = "<b>debug script &gt;</b>";
  1854. insertAfter(document.createElement("br"), forfForm);
  1855.  
  1856. // add the debug window information
  1857. this.debugWindow1.id = "debugWindow1" ; this.debugWindow2.id = "debugWindow2"
  1858. this.debugWindow1.style.display = "none" ; this.debugWindow2.style.display = "none"
  1859. this.debugWindow1.style.fontFamily = "arial" ; this.debugWindow2.style.fontFamily = "arial"
  1860. this.debugWindow1.style.fontSize = "20px" ; this.debugWindow2.style.fontSize = "20px"
  1861. this.debugWindow1.style.position = "fixed" ; this.debugWindow2.style.position = "fixed"
  1862. this.debugWindow1.style.bottom = "0px" ; this.debugWindow2.style.bottom = "0px"
  1863. this.debugWindow1.style.right = "0px" ; this.debugWindow2.style.right = "0px"
  1864. this.debugWindow1.style.width = "400px" ; this.debugWindow2.style.width = "600px"
  1865. this.debugWindow1.style.height = "500px" ; this.debugWindow2.style.height = "550px"
  1866. this.debugWindow1.style.textalign = "center" ; this.debugWindow2.style.textalign = "center"
  1867. this.debugWindow1.style.backgroundColor = "#B5D7E0"; this.debugWindow2.style.backgroundColor = "#B5D7E0"
  1868. if (document.forms.namedItem("bankpoints") || document.forms.namedItem("koikoi"))
  1869. {
  1870. var tmpList = [
  1871. "<span style=\"float: right; cursor: pointer;\" onclick=\"document.getElementById('debugWindow2').style.display='none';\"><b>Close [X]</b></span><br/>",
  1872. "<b>Reasons to KoiKoi&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbspReasons to Bank</b>",
  1873. "<table style=\"z-index: 50; width: 600px; font-size: 10px; height: 12px;\">",
  1874. "<tr>"].join("");
  1875. var currKoi=0;
  1876. var currBank=0;
  1877. while (currKoi < koiReasons.length || currBank < bankReasons.length)
  1878. {
  1879. if (currKoi < koiReasons.length)
  1880. {
  1881. tmpList+= "<td style=\"left: 0px;\"><b>"+koiReasons[currKoi].value+"</b></td>";
  1882. tmpList+= "<td style=\"left: 30px;\"><b>"+koiReasons[currKoi].text+"</b></td>";
  1883. currKoi++;
  1884. }
  1885. else
  1886. {
  1887. tmpList+= "<td style=\"left: 0px;\"><b></b></td>";
  1888. tmpList+= "<td style=\"left: 30px;\"><b></b></td>";
  1889. }
  1890. if (currBank < bankReasons.length)
  1891. {
  1892. tmpList+= "<td style=\"left: 400px;\"><b>"+bankReasons[currBank].value+"</b></td>";
  1893. tmpList+= "<td style=\"left: 430px;\"><b>"+bankReasons[currBank].text+"</b></td>";
  1894. currBank++;
  1895. }
  1896. else
  1897. {
  1898. tmpList+= "<td style=\"left: 0px;\"><b></b></td>";
  1899. tmpList+= "<td style=\"left: 30px;\"><b></b></td>";
  1900. }
  1901. tmpList+="</tr>";
  1902. }
  1903. tmpList+="</table>";
  1904. this.debugWindow2.innerHTML = tmpList;
  1905. document.body.appendChild(this.debugWindow2);
  1906. }
  1907. else
  1908. {
  1909. var tmpList = [
  1910. "<span style=\"float: right; cursor: pointer;\" onclick=\"document.getElementById('debugWindow1').style.display='none';\"><b>Close [X]</b></span><br/>",
  1911. "<b>Hand</b>",
  1912. "<table style=\"z-index: 50; width: 400px; font-size: 10px; height: 12px;\">",
  1913. "<tr>",
  1914. "<td style=\"left: 0px;\"><b>Card</b></td>",
  1915. "<td style=\"left: 80px;\"><b>Value</b></td>",
  1916. "<td style=\"left: 160px;\"><b>Point BreakDown</b></td>",
  1917. "</tr>"].join("");
  1918. for (var g = 0;g < hand.length;g++)
  1919. {
  1920. if (hand[g].playable)
  1921. {
  1922. tmpList+= [ "<tr>",
  1923. "<td style=\"left: 0px;\"><b>" + getCardType(hand[g]) + "</b></td>",
  1924. "<td style=\"left: 80px;\"><b>" + Math.round(hand[g].value*1000)/1000 + "</b></td>",
  1925. "<td style=\"left: 160px;\"><b>" ].join("");
  1926. var mults = getMultipliers(hand[g], false);
  1927. if (mults)
  1928. {
  1929. for (var d = 0;d < mults.length;d++)
  1930. tmpList += mults[d].value + " " + mults[d].name + "<BR>";
  1931. }
  1932. tmpList += ["</b></td></tr>"].join("");
  1933. }
  1934. }
  1935. tmpList += "</table>";
  1936. tmpList += "<b>Field</b>" +
  1937. "<table style=\"z-index: 50; width: 400px; font-size: 10px; height: 12px;\">" +
  1938. "<tr>" +
  1939. "<td style=\"left: 0px;\"><b>Card</b></td>"+
  1940. "<td style=\"left: 80px;\"><b>Value</b></td>"+
  1941. "<td style=\"left: 160px;\"><b>Point BreakDown</b></td>"+
  1942. "</tr>";
  1943. for (var g = 0;g < playField.length;g++)
  1944. {
  1945. if (playField[g].playable)
  1946. {
  1947. tmpList+= [ "<tr>",
  1948. "<td style=\"left: 0px;\"><b>" + getCardType(playField[g]) + "</b></td>",
  1949. "<td style=\"left: 80px;\"><b>" + Math.round(playField[g].value*1000)/1000 + "</b></td>",
  1950. "<td style=\"left: 160px;\"><b>" ].join("");
  1951. var mults = getMultipliers(playField[g], true);
  1952. if (mults)
  1953. {
  1954. for (var d = 0;d < mults.length;d++)
  1955. tmpList += mults[d].value + " " + mults[d].name + "<BR>";
  1956. }
  1957. tmpList += ["</b></td></tr>"].join("");
  1958. }
  1959. }
  1960. tmpList += "</table>";
  1961. this.debugWindow1.innerHTML = tmpList;
  1962. document.body.appendChild(this.debugWindow1);
  1963. }
  1964.  
  1965. function getYourScoreToWin()
  1966. {
  1967. var mtches = /You \((Dealer - )?Current Score: (\d+) :: (\d+) to win\)/.exec(document.body.innerHTML);
  1968. return parseInt(mtches[3]) - parseInt(mtches[2]);
  1969. }
  1970. function getEnemyScoreToWin()
  1971. {
  1972. var mtches = /Them \((Dealer - )?Current Score: (\d+) :: (\d+) to win\)/.exec(document.body.innerHTML);
  1973. return parseInt(mtches[3]) - parseInt(mtches[2]);
  1974. }
  1975.  
  1976. function setCheat(inStr)
  1977. {
  1978. var defaultChoice;
  1979. if (inStr == "koi")
  1980. defaultChoice = /value="(\d)">Force Koi-Koi/.exec(document.body.innerHTML)[1];
  1981. if (inStr == "topCard")
  1982. defaultChoice = /value="(\d)">View top of deck/.exec(document.body.innerHTML)[1];
  1983. if (inStr == "minusCard")
  1984. defaultChoice = /value="(\d)">Opp. -1 Take/.exec(document.body.innerHTML)[1];
  1985. if (inStr == "redraw")
  1986. defaultChoice = /value="(\d)">Shuffle \+ Redraw/.exec(document.body.innerHTML)[1];
  1987. if (inStr == "bottom")
  1988. defaultChoice = /value="(.*)">Top Card to Bottom/.exec(document.body.innerHTML)[1];
  1989.  
  1990. if (!defaultChoice)
  1991. defaultChoice = "none";
  1992. if (defaultChoice != "none")
  1993. useCheat = inStr;
  1994. var elems = document.forms.namedItem("cheat").elements;
  1995. for (var i=0;i<elems.length;i++)
  1996. if (elems[i].getAttribute("name") == "hanacheat")
  1997. elem = elems[i];
  1998. elem.value = defaultChoice;
  1999. }
  2000.  
  2001. function processEvent(event)
  2002. {
  2003. var input = event.keyCode;
  2004. if(input==67)
  2005. {
  2006. if (useCheat)
  2007. submitForm("cheat");
  2008. else //change the keycode to run regular script choice
  2009. input = 68;
  2010. }
  2011. if(input==68)
  2012. {
  2013. if(document.forms.namedItem("nextround"))
  2014. {
  2015. //disable forced koi flag at end of round
  2016. GM_setValue("forcedKoi", false);
  2017. submitForm("nextround");
  2018. }
  2019. else if (document.forms.namedItem("bankpoints") && !document.forms.namedItem("koikoi"))
  2020. submitForm("bankpoints");
  2021. else if (document.forms.namedItem("bankpoints") && document.forms.namedItem("koikoi"))
  2022. {
  2023. if (koikoi())
  2024. submitForm("koikoi");
  2025. else
  2026. submitForm("bankpoints");
  2027. }
  2028. else
  2029. submitForm("placecard");
  2030. }
  2031. if(input==86)
  2032. {
  2033. if (document.forms.namedItem("bankpoints") || document.forms.namedItem("koikoi"))
  2034. {
  2035. if (document.getElementById('debugWindow2').style.display == '')
  2036. document.getElementById('debugWindow2').style.display = 'none'
  2037. else
  2038. document.getElementById('debugWindow2').style.display = '';
  2039. }
  2040. else
  2041. {
  2042. if (document.getElementById('debugWindow1').style.display == '')
  2043. document.getElementById('debugWindow1').style.display = 'none'
  2044. else
  2045. document.getElementById('debugWindow1').style.display = '';
  2046. }
  2047. }
  2048. }
  2049. window.addEventListener("keyup", processEvent, false);