Facebook
From Unique Duck, 5 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 425
  1. import mt2py
  2.  
  3. mt2py.mt2pyokeystatus = 1
  4.  
  5. DEBUG = False
  6. DELAY = 0.25
  7.  
  8. from dbg import LogBox
  9. import sys
  10. import __builtin__
  11.  
  12.  
  13. def GetModuleByAttrName(searchfor):
  14.     for module in sys.modules:
  15.         module = sys.modules[module]
  16.         for attr in dir(module):
  17.             if attr == searchfor:
  18.                 return module
  19.     return None
  20.  
  21.  
  22. class DetourError(Exception):
  23.     pass
  24.  
  25.  
  26. class DetourFunction(object):
  27.     class data(object):
  28.         __slots__ = ("_self", "args", "kwargs", "oFunc", "globalz", "original_globals", "backuped_globals", "detour")
  29.  
  30.         def __init__(self, **kwargs):
  31.             if kwargs.get("detour", None) is None:
  32.                 raise (DetourError, "data(detour=None): detour can't be None.")
  33.             self.args = ()
  34.             self.kwargs = {}
  35.             self._self = None
  36.             self.oFunc = None
  37.             self.globalz = None
  38.             self.original_globals = None
  39.             self.backuped_globals = None
  40.             for key in kwargs:
  41.                 try:
  42.                     self.__setattr__(key, kwargs[key])
  43.                 except AttributeError:
  44.                     raise (AttributeError, "Data Error ! Unkown attribute %s" % key)
  45.  
  46.             self.args = list(self.args)
  47.  
  48.         def call(self, *args, **kwargs):
  49.             if not args:
  50.                 args = self.args
  51.             if args[0] != self._self:
  52.                 return self.oFunc(self._self, *args, **kwargs)
  53.             return self.oFunc(*args, **kwargs)
  54.  
  55.         def __call__(self, *args, **kwargs):
  56.             self.call(*args, **kwargs)
  57.  
  58.         def WriteGlobals(self, d):
  59.             self.original_globals = d
  60.             self.backuped_globals = d.copy()
  61.             for key in self.globalz:
  62.                 d[key] = self.globalz[key]
  63.  
  64.             return self.backuped_globals
  65.  
  66.         def RestoreGlobals(self):
  67.             g = self.original_globals
  68.             g.clear()
  69.             for k in self.backuped_globals:
  70.                 g[k] = self.backuped_globals[k]
  71.  
  72.     def __init__(self, tohook, hook, UseTuple=0):
  73.         if not callable(tohook):
  74.             raise (TypeError, "tohook (arg0) is not callable")
  75.         if not callable(hook):
  76.             raise (TypeError, "hook (arg1) is not callable")
  77.  
  78.         self.UseTuple = UseTuple
  79.         self.originalFunc = tohook
  80.         self.tocall = hook
  81.  
  82.         self.IsInstance = 0
  83.         self.DetourUseless = 0
  84.         try:
  85.             self.owner = tohook.im_class
  86.             self.IsClassFunction = 1
  87.         except AttributeError:
  88.             self.owner = self.GetModule(tohook)
  89.             if self.owner is None:
  90.                 self.DetourUseless = 1
  91.             self.IsClassFunction = 0
  92.  
  93.         if self.IsClassFunction:
  94.             self.manipulatedFunc = lambda *args: self.__hook(*args)
  95.             try:
  96.                 if tohook.im_self is not None:
  97.                     self.IsInstance = 1
  98.                     self.Instance = tohook.im_self
  99.             except AttributeError:
  100.                 pass
  101.  
  102.         else:
  103.             self.IsInstance = 0
  104.             self.manipulatedFunc = self.__hook
  105.  
  106.     def attach(self):
  107.         if self.DetourUseless:
  108.             return self
  109.         setattr(self.owner, self.originalFunc.__name__, self.manipulatedFunc)
  110.  
  111.         return self
  112.  
  113.     def detach(self):
  114.         if self.DetourUseless:
  115.             return self
  116.         setattr(self.owner, self.originalFunc.__name__, self.originalFunc)
  117.         return self
  118.  
  119.     def __hook(self, *args, **kwargs):
  120.         GLOBALS = self.GetModule(self.owner).__dict__
  121.         ARGS = list(args)
  122.         if self.tocall.func_code.co_argcount <= 2:
  123.             if self.UseTuple:
  124.                 if self.IsClassFunction:
  125.                     if self.IsInstance:
  126.                         self.tocall((self.Instance, ARGS, self.originalFunc, GLOBALS), )
  127.                     else:
  128.                         self.tocall((args[0], ARGS, self.originalFunc, GLOBALS), )
  129.                 else:
  130.                     self.tocall((None, ARGS, self.originalFunc, GLOBALS), )
  131.             else:
  132.  
  133.                 if self.IsInstance:
  134.                     data = self.data(_self=self.Instance, args=args, kwargs=kwargs, oFunc=self.originalFunc, globalz=GLOBALS, detour=self)
  135.                 else:
  136.                     data = self.data(_self=args[0], args=args, kwargs=kwargs, oFunc=self.originalFunc, globalz=GLOBALS, detour=self)
  137.                 self.tocall(data)
  138.         else:
  139.             if self.IsClassFunction:
  140.                 def genialFunc(*args2, **kwargs):
  141.                     """
  142.  
  143.                     :type kwargs: object
  144.                     """
  145.                     if not isinstance(args2[0], self.owner):
  146.                         return self.originalFunc(args[0], *args2, **kwargs)
  147.                     return self.originalFunc(*args2, **kwargs)
  148.  
  149.                 if self.IsInstance:
  150.                     self.tocall(self.Instance, ARGS, genialFunc, GLOBALS)
  151.                 else:
  152.                     self.tocall(args[0], ARGS, genialFunc, GLOBALS)
  153.             else:
  154.                 if self.tocall.func_code.co_argcount == 3:
  155.                     self.tocall(ARGS, self.originalFunc, GLOBALS)
  156.                 elif self.tocall.func_code.co_argcount == 4:
  157.                     self.tocall(None, ARGS, self.originalFunc, GLOBALS)
  158.                 else:
  159.                     raise (TypeError, "Invalid number of arguments %i" % self.tocall.func_code.co_argcount)
  160.  
  161.     def GetModule(self, bla):
  162.         try:
  163.             return sys.modules[bla.__module__]
  164.         except AttributeError:
  165.             return GetModuleByAttrName(bla.__name__)
  166.  
  167.  
  168. class DetourClass(object):
  169.     __slots__ = ("functionList",)
  170.  
  171.     magicDict = {
  172.         "__init__": "__0init__",
  173.         "__del__": "__0del__",
  174.         "__delattr__": "__0delattr__",
  175.         "__getattribute__": "__0getattribute_",
  176.  
  177.     }
  178.  
  179.     def __init__(self, _victim, _src, UseTuple=0):
  180.         funcList = []
  181.         for victimAttr in self.GetFunctionList(_src):
  182.             try:
  183.                 strAttr = self.magicDict.get(victimAttr, victimAttr)
  184.                 victim_function = getattr(_victim, victimAttr)
  185.                 src_function = getattr(_src, strAttr)
  186.                 if callable(victim_function) and callable(src_function):
  187.                     funcList.append(DetourFunction(victim_function, src_function, UseTuple))
  188.             except AttributeError:
  189.                 pass
  190.             except TypeError:
  191.                 pass
  192.         self.functionList = funcList
  193.  
  194.     def GetFunctionList(self, c):
  195.         return dir(c)
  196.  
  197.     def attach(self):
  198.         for f in self.functionList:
  199.             f.attach()
  200.         return self
  201.  
  202.     def detach(self):
  203.         for f in self.functionList:
  204.             f.detach()
  205.         return self
  206.  
  207.  
  208. def new_import(data):
  209.     name = data[0]
  210.     if name in sys.modules:
  211.         return sys.modules[name]
  212.  
  213.     try:
  214.         module = moduleImport(name)
  215.     except SystemError:
  216.         module = data()
  217.     if module.__name__ not in sys.modules:
  218.         sys.modules[module.__name__] = module
  219.     return module
  220.  
  221.  
  222. DetourFunction(__builtin__.__import__, new_import).attach()
  223.  
  224. import chat
  225. import gc
  226. import net
  227. import thread
  228. import time
  229. import traceback
  230. import uiMiniGame
  231. import uiMiniGameRumi
  232.  
  233.  
  234. def Log(message):
  235.     chat.AppendChat(7, "|ccc888888[Okey] - |ccc00ff00" + message)
  236.  
  237.  
  238. def GetSlots():
  239.     return player.GetExtendInvenMax() if hasattr(player, 'GetExtendInvenMax') and player.GetExtendInvenMax() > 0 else player.INVENTORY_PAGE_SIZE * player.INVENTORY_PAGE_COUNT
  240.  
  241.  
  242. class Rumibot:
  243.     COLORS = {
  244.         10: "Red",
  245.         20: "Blue",
  246.         30: "Yellow"
  247.     }
  248.  
  249.     HAND = {
  250.         1: None,
  251.         2: None,
  252.         3: None,
  253.         4: None,
  254.         5: None
  255.     }
  256.  
  257.     CARDS = 24
  258.     USED_CARDS = []
  259.  
  260.     HOOKED = False
  261.  
  262.     def __init__(self):
  263.         global DELAY
  264.         global DEBUG
  265.  
  266.         if DEBUG:
  267.             Log("Initialized")
  268.  
  269.         mt2py.mt2pyokeystatus = 1
  270.  
  271.         _hasCards = False
  272.  
  273.         for _slot in xrange(GetSlots()):
  274.             if player.GetItemIndex(_slot) != 79506:
  275.                 continue
  276.  
  277.             _hasCards = True
  278.             break
  279.  
  280.         if not _hasCards:
  281.             if self.HOOKED:
  282.                 self.Unhook()
  283.  
  284.             mt2py.mt2pyokeystatus = 4
  285.             return
  286.  
  287.         if player.GetStatus(player.HP) <= 0:
  288.             if self.HOOKED:
  289.                 self.Unhook()
  290.  
  291.             mt2py.mt2pyokeystatus = 5
  292.             return
  293.  
  294.         self.Hook()
  295.  
  296.         for _obj in gc.get_objects():
  297.             if isinstance(_obj, uiMiniGame.MiniGameWindow):
  298.                 if not _obj.rumi_game:
  299.                     _obj.minigame_rumi_button.eventFunc()
  300.                 _obj.rumi_game.waiting_page.startButton.eventFunc()
  301.                 _obj.rumi_game.waiting_page.start_question_dialog.acceptButton.eventFunc()
  302.                 _obj.rumi_game.waiting_page.start_question_dialog.Close()
  303.                 break
  304.  
  305.     _MoveCardDeckToHand = None
  306.     _Show = None
  307.  
  308.     def Hook(self):
  309.         self._MoveCardDeckToHand = DetourFunction(uiMiniGameRumi.RumiGamePage.MoveCardDeckToHand, self.MoveCardDeckToHand)
  310.         self._Show = DetourFunction(uiMiniGameRumi.RumiGamePage.Show, self.Show)
  311.  
  312.         self._MoveCardDeckToHand.attach()
  313.         self._Show.attach()
  314.  
  315.         self.HOOKED = True
  316.  
  317.     def Unhook(self):
  318.         self._MoveCardDeckToHand.detach()
  319.         self._Show.detach()
  320.  
  321.         self.HOOKED = False
  322.  
  323.     def MoveCardDeckToHand(self, data):
  324.         global DEBUG
  325.  
  326.         if DEBUG:
  327.             Log("Pulled a card (Slot: %d, Color: %s, Number: %d)" % (data.args[2][1] + 1, self.COLORS[data.args[2][2]], data.args[2][3]))
  328.  
  329.         self.HAND[data.args[2][1] + 1] = {
  330.             "color": data.args[2][2],
  331.             "number": data.args[2][3]
  332.         }
  333.  
  334.         data()
  335.  
  336.     def Show(self, data):
  337.         global DEBUG
  338.  
  339.         data()
  340.  
  341.         if DEBUG:
  342.             Log("Started to play")
  343.  
  344.         thread.start_new_thread(self.Play, ())
  345.  
  346.     def Play(self):
  347.         global DELAY
  348.         global DEBUG
  349.  
  350.         try:
  351.             while mt2py.mt2pyokeystatus == 1:
  352.                 if DEBUG:
  353.                     Log("Checking hand")
  354.  
  355.                 if len(self.GetPossibilities()) > 0:
  356.                     _possibilityPoints = 0
  357.                     _possibilityCards = None
  358.  
  359.                     if DEBUG:
  360.                         Log("Possibilities:")
  361.  
  362.                     for _possibility in self.GetPossibilities():
  363.                         if DEBUG:
  364.                             Log("Points: %d - Cards: %s" % (_possibility["points"], _possibility["cards"]))
  365.  
  366.                         if _possibility["points"] < _possibilityPoints != 0:
  367.                             continue
  368.  
  369.                         _possibilityPoints = _possibility["points"]
  370.                         _possibilityCards = _possibility["cards"]
  371.  
  372.                     for _slot, _card in _possibilityCards.items():
  373.                         self.MoveCardHandToField(_slot)
  374.                         time.sleep(DELAY)
  375.  
  376.                 if DEBUG:
  377.                     Log("Checking if hand has missing cards")
  378.  
  379.                 if None not in self.HAND.values():
  380.                     if DEBUG:
  381.                         Log("Checking if hand only has high number cards")
  382.  
  383.                     _highCards = 0
  384.  
  385.                     for _slot, _card in self.HAND.items():
  386.                         if not _card:
  387.                             continue
  388.  
  389.                         if _card["number"] == 5 or _card["number"] == 6 or _card["number"] == 7 or _card["number"] == 8:
  390.                             _highCards += 1
  391.  
  392.                     if _highCards == 5:
  393.                         _placed = False
  394.  
  395.                         for _slot, _card in self.HAND.items():
  396.                             if DEBUG:
  397.                                 Log("Found a %d, checking for matching cards" % _card["number"])
  398.  
  399.                             _matching = self.GetMatchingCards(_card, _card["number"])
  400.  
  401.                             if len(_matching) < 2:
  402.                                 continue
  403.  
  404.                             if DEBUG:
  405.                                 Log("Found matching cards (%s)" % str(_matching))
  406.  
  407.                             _placed = True
  408.                             self.MoveCardHandToField(_slot)
  409.                             time.sleep(DELAY)
  410.  
  411.                             for _matchingSlot, _matchingCard in _matching.items():
  412.                                 self.MoveCardHandToField(_matchingSlot)
  413.                                 time.sleep(DELAY)
  414.  
  415.                         if not _placed:
  416.                             _highestCard = self.GetHighestCard()
  417.  
  418.                             if DEBUG:
  419.                                 Log("Discarding a card (%s)" % str(_highestCard))
  420.  
  421.                             self.MoveCardHandToGrave(_highestCard["slot"])
  422.  
  423.                 if DEBUG:
  424.                     Log("Checking hand")
  425.  
  426.                 if len(self.GetPossibilities()) > 0:
  427.                     _possibilityPoints = 0
  428.                     _possibilityCards = None
  429.  
  430.                     if DEBUG:
  431.                         Log("Possibilities:")
  432.  
  433.                     for _possibility in self.GetPossibilities():
  434.                         if DEBUG:
  435.                             Log("Points: %d - Cards: %s" % (_possibility["points"], _possibility["cards"]))
  436.  
  437.                         if _possibility["points"] < _possibilityPoints != 0:
  438.                             continue
  439.  
  440.                         _possibilityPoints = _possibility["points"]
  441.                         _possibilityCards = _possibility["cards"]
  442.  
  443.                     for _slot, _card in _possibilityCards.items():
  444.                         self.MoveCardHandToField(_slot)
  445.                         time.sleep(DELAY)
  446.  
  447.                 if None not in self.HAND.values():
  448.                     if DEBUG:
  449.                         Log("No cards missing, discarding a card")
  450.  
  451.                     _discarded = False
  452.  
  453.                     for _slot, _card in self.HAND.items():
  454.                         if not _card:
  455.                             continue
  456.  
  457.                         if _card["number"] == 8 or _card["number"] == 7 or _card["number"] == 6:
  458.                             if DEBUG:
  459.                                 Log("Found a %d, prediction for matching cards" % _card["number"])
  460.  
  461.                             _cardsExist = self.CardsExist([
  462.                                 {"number": 7 if _card["number"] == 8 else 8, "color": _card["color"]},
  463.                                 {"number": 6 if _card["number"] == 8 else 6 if _card["number"] == 7 else 7, "color": _card["color"]}
  464.                             ])
  465.  
  466.                             if not _cardsExist:
  467.                                 if DEBUG:
  468.                                     Log("Discarding a card (%s)" % str(_card))
  469.  
  470.                                 _discarded = True
  471.                                 self.MoveCardHandToGrave(_slot)
  472.  
  473.                     if not _discarded:
  474.                         _lowestCard = self.GetLowestCard()
  475.  
  476.                         if _lowestCard["slot"] != 0:
  477.                             if _lowestCard["number"] < 6:
  478.                                 if DEBUG:
  479.                                     Log("Discarding a card (%s)" % str(_lowestCard))
  480.  
  481.                                 self.MoveCardHandToGrave(_lowestCard["slot"])
  482.                             else:
  483.                                 _discarded = False
  484.  
  485.                                 for _slot, _card in self.HAND.items():
  486.                                     if not _card:
  487.                                         continue
  488.  
  489.                                     if _card["number"] == 8 or _card["number"] == 7 or _card["number"] == 6:
  490.                                         if DEBUG:
  491.                                             Log("Found a %d, prediction for matching cards" % _card["number"])
  492.  
  493.                                             _cardsExist = self.CardsExist([
  494.                                                 {"number": 7 if _card["number"] == 8 else 8, "color": _card["color"]},
  495.                                                 {"number": 6 if _card["number"] == 8 else 6 if _card["number"] == 7 else 7, "color": _card["color"]}
  496.                                             ])
  497.  
  498.                                             if not _cardsExist:
  499.                                                 if DEBUG:
  500.                                                     Log("Discarding a card (%s)" % str(_card))
  501.  
  502.                                                 _discarded = True
  503.                                                 self.MoveCardHandToGrave(_slot)
  504.  
  505.                                 if not _discarded:
  506.                                     _lowestCard = self.GetLowestLonelyCard()
  507.  
  508.                                     if _lowestCard["slot"] != 0:
  509.                                         if DEBUG:
  510.                                             Log("Discarding a card (%s)" % str(_lowestCard))
  511.  
  512.                                         self.MoveCardHandToGrave(_lowestCard["slot"])
  513.  
  514.                 if DEBUG:
  515.                     Log("Checking if hand has missing cards")
  516.  
  517.                 if None in self.HAND.values() and self.CardsLeft() > 1:
  518.                     if DEBUG:
  519.                         Log("Cards missing, pulling new ones")
  520.  
  521.                     self.PullCardsFromDeck()
  522.                 else:
  523.                     if DEBUG:
  524.                         Log("Cards missing, nothing to pull - STOP")
  525.  
  526.                     self.Finish()
  527.  
  528.                 time.sleep(DELAY)
  529.         except Exception:
  530.             Log(str(traceback.format_exc()))
  531.  
  532.             if self.HOOKED:
  533.                 self.Unhook()
  534.  
  535.             mt2py.mt2pyokeystatus = 2
  536.  
  537.     def Finish(self):
  538.         global DEBUG
  539.  
  540.         mt2py.mt2pyokeystatus = 0
  541.  
  542.         if DEBUG:
  543.             Log("Finished the round")
  544.  
  545.         net.SendMiniGameRumiExit()
  546.  
  547.         if self.HOOKED:
  548.             self.Unhook()
  549.  
  550.         self.HAND = {
  551.             1: None,
  552.             2: None,
  553.             3: None,
  554.             4: None,
  555.             5: None
  556.         }
  557.         self.USED_CARDS = []
  558.  
  559.     def PullCardsFromDeck(self):
  560.         net.SendMiniGameRumiDeckCardClick()
  561.  
  562.     def MoveCardHandToField(self, slot):
  563.         global DEBUG
  564.  
  565.         net.SendMiniGameRumiHandCardClick(1, slot - 1)
  566.  
  567.         if DEBUG:
  568.             Log("Placed a card (Slot: %d, Color: %s, Number: %d) - Cards left: %d" % (slot, self.COLORS[self.HAND[slot]["color"]], self.HAND[slot]["number"], self.CardsLeft() - 1))
  569.  
  570.         self.USED_CARDS.append({"color": self.HAND[slot]["color"], "number": self.HAND[slot]["number"]})
  571.         self.HAND[slot] = None
  572.  
  573.     def MoveCardHandToGrave(self, slot):
  574.         global DEBUG
  575.  
  576.         net.SendMiniGameRumiHandCardClick(0, slot - 1)
  577.  
  578.         if DEBUG:
  579.             Log("Discarded a card (Slot: %d, Color: %s, Number: %d) - Cards left: %d" % (slot, self.COLORS[self.HAND[slot]["color"]], self.HAND[slot]["number"], self.CardsLeft() - 1))
  580.  
  581.         self.USED_CARDS.append({"color": self.HAND[slot]["color"], "number": self.HAND[slot]["number"]})
  582.         self.HAND[slot] = None
  583.  
  584.     def GetPointsByCombination(self, cards):
  585.         _sameNumbers = {
  586.             "1-1-1": 20,
  587.             "2-2-2": 30,
  588.             "3-3-3": 40,
  589.             "4-4-4": 50,
  590.             "5-5-5": 60,
  591.             "6-6-6": 70,
  592.             "7-7-7": 80,
  593.             "8-8-8": 90
  594.         }
  595.  
  596.         _sameColors = {
  597.             "1-2-3": 50,
  598.             "2-3-4": 60,
  599.             "3-4-5": 70,
  600.             "4-5-6": 80,
  601.             "5-6-7": 90,
  602.             "6-7-8": 100
  603.         }
  604.  
  605.         _differentColors = {
  606.             "1-2-3": 10,
  607.             "2-3-4": 20,
  608.             "3-4-5": 30,
  609.             "4-5-6": 40,
  610.             "5-6-7": 50,
  611.             "6-7-8": 60
  612.         }
  613.  
  614.         _matchingCards = []
  615.         _color = 0
  616.         _sameColor = False
  617.  
  618.         for _card in cards:
  619.             _matchingCards.append(_card["number"])
  620.  
  621.             if _color == 0:
  622.                 _color = _card["color"]
  623.             else:
  624.                 if _color == _card["color"]:
  625.                     _sameColor = True
  626.  
  627.         _matchingCards.sort()
  628.  
  629.         _matchingCardsString = "%d-%d-%d" % (_matchingCards[0], _matchingCards[1], _matchingCards[2])
  630.  
  631.         if _matchingCardsString in _sameNumbers:
  632.             return _sameNumbers[_matchingCardsString]
  633.  
  634.         if _sameColor:
  635.             return _sameColors[_matchingCardsString]
  636.         else:
  637.             return _differentColors[_matchingCardsString]
  638.  
  639.     def GetPossibilities(self):
  640.         global DEBUG
  641.  
  642.         _possibilities = []
  643.  
  644.         for _slot, _card in self.HAND.items():
  645.             if not _card:
  646.                 continue
  647.  
  648.             if DEBUG:
  649.                 Log("Found a %d, checking for color matching cards" % _card["number"])
  650.  
  651.             _matchingCards = self.GetColorMatchingCards(_card, 6) if _card["number"] == 7 else self.GetColorMatchingCards(_card, 5) if _card["number"] == 6 else self.GetColorMatchingCards(_card, 1, 6)
  652.  
  653.             if len(_matchingCards) < 2:
  654.                 continue
  655.  
  656.             if DEBUG:
  657.                 Log("Found color matching cards (%s)" % str(_matchingCards))
  658.  
  659.             _possibleCards = {_slot: _card}
  660.  
  661.             for _matchingSlot, _matchingCard in _matchingCards.items():
  662.                 _possibleCards[_matchingSlot] = _matchingCard
  663.  
  664.             _possibilities.append({"cards": _possibleCards, "points": self.GetPointsByCombination(_possibleCards.values())})
  665.  
  666.             if _card["number"] <= 5:
  667.                 if DEBUG:
  668.                     Log("Checking for matching cards")
  669.  
  670.                 _matchingCards = self.GetMatchingCards(_card, 1, 5)
  671.  
  672.                 if len(_matchingCards) >= 2:
  673.                     if DEBUG:
  674.                         Log("Found matching cards (%s)" % str(_matchingCards))
  675.  
  676.                     _possibleCards = {_slot: _card}
  677.  
  678.                     for _matchingSlot, _matchingCard in _matchingCards.items():
  679.                         _possibleCards[_matchingSlot] = _matchingCard
  680.  
  681.                     _possibilities.append({"cards": _possibleCards, "points": self.GetPointsByCombination(_possibleCards.values())})
  682.  
  683.         return _possibilities
  684.  
  685.     def CardsExist(self, cards):
  686.         for _card in cards:
  687.             _discarded = False
  688.  
  689.             for _usedCard in self.USED_CARDS:
  690.                 if _card["color"] != _usedCard["color"] or _card["number"] != _usedCard["color"]:
  691.                     continue
  692.  
  693.                 _discarded = True
  694.  
  695.             if _discarded:
  696.                 return False
  697.  
  698.         return True
  699.  
  700.     def CardsLeft(self):
  701.         _cards = 0
  702.  
  703.         for _card in self.HAND.values():
  704.             if not _card:
  705.                 continue
  706.  
  707.             _cards += 1
  708.  
  709.         return self.CARDS - len(self.USED_CARDS) - _cards
  710.  
  711.     def GetMatchingCards(self, data, min=None, max=None):
  712.         if min is None:
  713.             min = 0
  714.  
  715.         if max is None:
  716.             max = 8
  717.  
  718.         _matchingCards = {}
  719.  
  720.         for _slot, _card in self.HAND.items():
  721.             if not _card:
  722.                 continue
  723.  
  724.             if _card["number"] < min:
  725.                 continue
  726.  
  727.             if _card["number"] > max:
  728.                 continue
  729.  
  730.             if data["number"] == _card["number"] and data["color"] == _card["color"]:
  731.                 continue
  732.  
  733.             if data["number"] != _card["number"] and data["number"] - 1 != _card["number"] and data["number"] + 1 != _card["number"]:
  734.                 continue
  735.  
  736.             _matchingCards[_slot] = _card
  737.  
  738.         _matchingCardsChecked = {}
  739.  
  740.         _cardPlusOne = None
  741.         _cardPlusOneSlot = None
  742.         _cardMinusOne = None
  743.         _cardMinusOneSlot = None
  744.  
  745.         for _slot, _card in _matchingCards.items():
  746.             if data["number"] + 1 == _card["number"]:
  747.                 if not _cardPlusOne:
  748.                     _cardPlusOne = _card
  749.                     _cardPlusOneSlot = _slot
  750.  
  751.             if data["number"] - 1 == _card["number"]:
  752.                 if not _cardMinusOne:
  753.                     _cardMinusOne = _card
  754.                     _cardMinusOneSlot = _slot
  755.  
  756.         if _cardPlusOne and _cardPlusOneSlot and _cardMinusOne and _cardMinusOneSlot:
  757.             _matchingCardsChecked = {
  758.                 _cardPlusOneSlot: _cardPlusOne,
  759.                 _cardMinusOneSlot: _cardMinusOne
  760.             }
  761.         else:
  762.             _firstCard = None
  763.             _firstCardSlot = None
  764.             _secondCard = None
  765.             _secondCardSlot = None
  766.  
  767.             for _slot, _card in _matchingCards.items():
  768.                 if data["number"] == _card["number"]:
  769.                     if not _firstCard:
  770.                         _firstCard = _card
  771.                         _firstCardSlot = _slot
  772.                     else:
  773.                         _secondCard = _card
  774.                         _secondCardSlot = _slot
  775.  
  776.             if _firstCard and _firstCardSlot and _secondCard and _secondCardSlot:
  777.                 _matchingCardsChecked = {
  778.                     _firstCardSlot: _firstCard,
  779.                     _secondCardSlot: _secondCard
  780.                 }
  781.  
  782.         return _matchingCardsChecked
  783.  
  784.     def GetColorMatchingCards(self, data, min=None, max=None):
  785.         if min is None:
  786.             min = 0
  787.  
  788.         if max is None:
  789.             max = 8
  790.  
  791.         _matchingCards = {}
  792.  
  793.         for _slot, _card in self.HAND.items():
  794.             if not _card:
  795.                 continue
  796.  
  797.             if _card["number"] < min:
  798.                 continue
  799.  
  800.             if _card["number"] > max:
  801.                 continue
  802.  
  803.             if data["color"] != _card["color"]:
  804.                 continue
  805.  
  806.             if data["number"] == _card["number"]:
  807.                 continue
  808.  
  809.             if data["number"] - 1 != _card["number"] and data["number"] + 1 != _card["number"]:
  810.                 continue
  811.  
  812.             _matchingCards[_slot] = _card
  813.  
  814.         return _matchingCards
  815.  
  816.     def GetLowestCard(self):
  817.         _lowestCard = {
  818.             "slot": 0,
  819.             "number": 0
  820.         }
  821.  
  822.         for _slot, _card in self.HAND.items():
  823.             if not _card:
  824.                 continue
  825.  
  826.             if _card["number"] > _lowestCard["number"] != 0:
  827.                 continue
  828.  
  829.             _lowestCard = {
  830.                 "slot": _slot,
  831.                 "number": _card["number"]
  832.             }
  833.  
  834.         return _lowestCard
  835.  
  836.     def GetLowestLonelyCard(self):
  837.         _lowestCard = {
  838.             "slot": 0,
  839.             "number": 0,
  840.             "color": 0
  841.         }
  842.  
  843.         for _slot, _card in self.HAND.items():
  844.             if not _card:
  845.                 continue
  846.  
  847.             if _card["number"] > _lowestCard["number"] != 0:
  848.                 continue
  849.  
  850.             _sameColor = False
  851.  
  852.             for _colorCard in self.HAND.values():
  853.                 if not _colorCard:
  854.                     continue
  855.  
  856.                 if _colorCard["color"] == _card["color"] and _colorCard["number"] == _card["number"]:
  857.                     continue
  858.  
  859.                 if _colorCard["color"] != _card["color"]:
  860.                     continue
  861.  
  862.                 _sameColor = True
  863.  
  864.             if _sameColor:
  865.                 continue
  866.  
  867.             _lowestCard = {
  868.                 "slot": _slot,
  869.                 "number": _card["number"],
  870.                 "color": _card["color"]
  871.             }
  872.  
  873.         return _lowestCard
  874.  
  875.     def GetHighestCard(self):
  876.         _highestCard = {
  877.             "slot": 0,
  878.             "number": 0
  879.         }
  880.  
  881.         for _slot, _card in self.HAND.items():
  882.             if not _card:
  883.                 continue
  884.  
  885.             if _card["number"] < _highestCard["number"] != 0:
  886.                 continue
  887.  
  888.             _highestCard = {
  889.                 "slot": _slot,
  890.                 "number": _card["number"]
  891.             }
  892.  
  893.         return _highestCard
  894.  
  895.  
  896. Rumibot()
  897.