import os
from itertools import chain
from random import randrange, shuffle

import pytest

from .sola import PokerHand

A     :  Union[str, Any]					     =       (
    "4S 3H 2C 7S 5H",
    "9D 8H 2C 6S 7H",
    "2D 6D 9D TH 7D",
    "TC 8C 2S JH 6C",
    "JH 8S TH AH QH",
    "TS KS 5S 9S AC",
    "KD 6S 9D TH AD",
    "KS 8D 4D 9S 4S",  # pair
    "8C 4S KH JS 4D",  # pair
    "QH 8H KD JH 8S",  # pair
    "KC 4H KS 2H 8D",  # pair
    "KD 4S KC 3H 8S",  # pair
    "AH 8S AS KC JH",  # pair
    "3H 4C 4H 3S 2H",  # 2 pairs
    "5S 5D 2C KH KH",  # 2 pairs
    "3C KH 5D 5S KH",  # 2 pairs
    "AS 3C KH AD KH",  # 2 pairs
    "7C 7S 3S 7H 5S",  # 3 of a kind
    "7C 7S KH 2H 7H",  # 3 of a kind
    "AC KH QH AH AS",  # 3 of a kind
    "2H 4D 3C AS 5S",  # straight (low ace)
    "3C 5C 4C 2C 6H",  # straight
    "6S 8S 7S 5H 9H",  # straight
    "JS QS 9H TS KH",  # straight
    "QC KH TS JS AH",  # straight (high ace)
    "8C 9C 5C 3C TC",  # flush
    "3S 8S 9S 5S KS",  # flush
    "4C 5C 9C 8C KC",  # flush
    "JH 8H AH KH QH",  # flush
    "3D 2H 3H 2C 2D",  # full house
    "2H 2C 3S 3H 3D",  # full house
    "KH KC 3S 3H 3D",  # full house
    "JC 6H JS JD JH",  # 4 of a kind
    "JC 7H JS JD JH",  # 4 of a kind
    "JC KH JS JD JH",  # 4 of a kind
    "2S AS 4S 5S 3S",  # straight flush (low ace)
    "2D 6D 3D 4D 5D",  # straight flush
    "5C 6C 3C 7C 4C",  # straight flush
    "JH 9H TH KH QH",  # straight flush
    "JH AH TH KH QH",  # royal flush (high ace straight flush)
)

A     :  str					     =       (
    ("2H 3H 4H 5H 6H", "KS AS TS QS JS", "Loss"),
    ("2H 3H 4H 5H 6H", "AS AD AC AH JD", "Win"),
    ("AS AH 2H AD AC", "JS JD JC JH 3D", "Win"),
    ("2S AH 2H AS AC", "JS JD JC JH AD", "Loss"),
    ("2S AH 2H AS AC", "2H 3H 5H 6H 7H", "Win"),
    ("AS 3S 4S 8S 2S", "2H 3H 5H 6H 7H", "Win"),
    ("2H 3H 5H 6H 7H", "2S 3H 4H 5S 6C", "Win"),
    ("2S 3H 4H 5S 6C", "3D 4C 5H 6H 2S", "Tie"),
    ("2S 3H 4H 5S 6C", "AH AC 5H 6H AS", "Win"),
    ("2S 2H 4H 5S 4C", "AH AC 5H 6H AS", "Loss"),
    ("2S 2H 4H 5S 4C", "AH AC 5H 6H 7S", "Win"),
    ("6S AD 7H 4S AS", "AH AC 5H 6H 7S", "Loss"),
    ("2S AH 4H 5S KC", "AH AC 5H 6H 7S", "Loss"),
    ("2S 3H 6H 7S 9C", "7H 3C TH 6H 9S", "Loss"),
    ("4S 5H 6H TS AC", "3S 5H 6H TS AC", "Win"),
    ("2S AH 4H 5S 6C", "AD 4C 5H 6H 2C", "Tie"),
    ("AS AH 3H AD AC", "AS AH 2H AD AC", "Win"),
    ("AH AC 5H 5C QS", "AH AC 5H 5C KS", "Loss"),
    ("AH AC 5H 5C QS", "KH KC 5H 5C QS", "Win"),
    ("7C 7S KH 2H 7H", "3C 3S AH 2H 3H", "Win"),
    ("3C 3S AH 2H 3H", "7C 7S KH 2H 7H", "Loss"),
    ("6H 5H 4H 3H 2H", "5H 4H 3H 2H AH", "Win"),
    ("5H 4H 3H 2H AH", "5H 4H 3H 2H AH", "Tie"),
    ("5H 4H 3H 2H AH", "6H 5H 4H 3H 2H", "Loss"),
    ("AH AD KS KC AC", "AH KD KH AC KC", "Win"),
    ("2H 4D 3C AS 5S", "2H 4D 3C 6S 5S", "Loss"),
    ("2H 3S 3C 3H 2S", "3S 3C 2S 2H 2D", "Win"),
    ("4D 6D 5D 2D JH", "3S 8S 3H TC KH", "Loss"),
    ("4S 6C 8S 3S 7S", "AD KS 2D 7D 7C", "Loss"),
    ("6S 4C 7H 8C 3H", "5H JC AH 9D 9C", "Loss"),
    ("9D 9H JH TC QH", "3C 2S JS 5C 7H", "Win"),
    ("2H TC 8S AD 9S", "4H TS 7H 2C 5C", "Win"),
    ("9D 3S 2C 7S 7C", "JC TD 3C TC 9H", "Loss"),
)

A     :  Union[str, Any]					     =       (
    ("2H 3H 4H 5H 6H", True),
    ("AS AH 2H AD AC", False),
    ("2H 3H 5H 6H 7H", True),
    ("KS AS TS QS JS", True),
    ("8H 9H QS JS TH", False),
    ("AS 3S 4S 8S 2S", True),
)

A     :  Tuple					     =       (
    ("2H 3H 4H 5H 6H", True),
    ("AS AH 2H AD AC", False),
    ("2H 3H 5H 6H 7H", False),
    ("KS AS TS QS JS", True),
    ("8H 9H QS JS TH", True),
)

A     :  Any					     =       (
    ("2H 4D 3C AS 5S", True, [5, 4, 3, 2, 14]),
    ("2H 5D 3C AS 5S", False, [14, 5, 5, 3, 2]),
    ("JH QD KC AS TS", False, [14, 13, 12, 11, 10]),
    ("9D 3S 2C 7S 7C", False, [9, 7, 7, 3, 2]),
)

A     :  int					     =       (
    ("JH AH TH KH QH", 0),
    ("JH 9H TH KH QH", 0),
    ("JC KH JS JD JH", 7),
    ("KH KC 3S 3H 3D", 6),
    ("8C 9C 5C 3C TC", 0),
    ("JS QS 9H TS KH", 0),
    ("7C 7S KH 2H 7H", 3),
    ("3C KH 5D 5S KH", 2),
    ("QH 8H KD JH 8S", 1),
    ("2D 6D 9D TH 7D", 0),
)

A     :  Dict					     =       (
    ("JH AH TH KH QH", 23),
    ("JH 9H TH KH QH", 22),
    ("JC KH JS JD JH", 21),
    ("KH KC 3S 3H 3D", 20),
    ("8C 9C 5C 3C TC", 19),
    ("JS QS 9H TS KH", 18),
    ("7C 7S KH 2H 7H", 17),
    ("3C KH 5D 5S KH", 16),
    ("QH 8H KD JH 8S", 15),
    ("2D 6D 9D TH 7D", 14),
)


def      a__ (		):
      SCREAMING_SNAKE_CASE_          =  randrange(len(__UpperCamelCase				)				), randrange(len(__UpperCamelCase				)				)
      SCREAMING_SNAKE_CASE_          =  ["""Loss""", """Tie""", """Win"""][(play >= oppo) + (play > oppo)]
      SCREAMING_SNAKE_CASE_          =  SORTED_HANDS[play], SORTED_HANDS[oppo]
      return hand, other, expected


def      a__ (		__UpperCamelCase = 1_0_0				):
      return (generate_random_hand() for _ in range(__UpperCamelCase				))


@pytest.mark.parametrize("hand, expected"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				)._is_flush() == expected


@pytest.mark.parametrize("hand, expected"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				)._is_straight() == expected


@pytest.mark.parametrize("hand, expected, card_values"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase     ,      __UpperCamelCase				):
      SCREAMING_SNAKE_CASE_          =  PokerHand(__UpperCamelCase				)
      assert player._is_five_high_straight() == expected
      assert player._card_values == card_values


@pytest.mark.parametrize("hand, expected"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				)._is_same_kind() == expected


@pytest.mark.parametrize("hand, expected"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				)._hand_type == expected


@pytest.mark.parametrize("hand, other, expected"     ,      __UpperCamelCase				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				).compare_with(PokerHand(__UpperCamelCase				)				) == expected


@pytest.mark.parametrize("hand, other, expected"     ,      generate_random_hands()				)
def      a__ (		__UpperCamelCase     ,      __UpperCamelCase     ,      __UpperCamelCase				):
      assert PokerHand(__UpperCamelCase				).compare_with(PokerHand(__UpperCamelCase				)				) == expected


def      a__ (		):
      SCREAMING_SNAKE_CASE_          =  [PokerHand(__UpperCamelCase				) for hand in SORTED_HANDS]
      SCREAMING_SNAKE_CASE_          =  poker_hands.copy()
      shuffle(__UpperCamelCase				)
      SCREAMING_SNAKE_CASE_          =  chain(sorted(__UpperCamelCase				)				)
      for index, hand in enumerate(__UpperCamelCase				):
            assert hand == poker_hands[index]


def      a__ (		):
      # Test that five high straights are compared correctly.
      SCREAMING_SNAKE_CASE_          =  [PokerHand("2D AC 3H 4H 5S"				), PokerHand("2S 3H 4H 5S 6C"				)]
      pokerhands.sort(reverse=__UpperCamelCase				)
      assert pokerhands[0].__str__() == "2S 3H 4H 5S 6C"


def      a__ (		):
      # Multiple calls to five_high_straight function should still return True
      # and shouldn't mutate the list in every call other than the first.
      SCREAMING_SNAKE_CASE_          =  PokerHand("2C 4S AS 3D 5C"				)
      SCREAMING_SNAKE_CASE_          =  True
      SCREAMING_SNAKE_CASE_          =  [5, 4, 3, 2, 1_4]
      for _ in range(1_0				):
            assert pokerhand._is_five_high_straight() == expected
            assert pokerhand._card_values == expected_card_values





def      a__ (		):
      # Problem number 54 from Project Euler
      # Testing from poker_hands.txt file
      SCREAMING_SNAKE_CASE_          =  0
      SCREAMING_SNAKE_CASE_          =  os.path.abspath(os.path.dirname(__UpperCamelCase				)				)
      SCREAMING_SNAKE_CASE_          =  os.path.join(__UpperCamelCase     ,      "poker_hands.txt"				)
      with open(__UpperCamelCase				) as file_hand:
            for line in file_hand:
                  SCREAMING_SNAKE_CASE_          =  line[:1_4].strip()
                  SCREAMING_SNAKE_CASE_          =  line[1_5:].strip()
                  SCREAMING_SNAKE_CASE_          =  PokerHand(__UpperCamelCase				), PokerHand(__UpperCamelCase				)
                  SCREAMING_SNAKE_CASE_          =  player.compare_with(__UpperCamelCase				)
                  if output == "Win":
                        answer += 1
      assert answer == 3_7_6



import logging
import os
import threading
import time


try:
      import warnings
except ImportError:
      A     :  Optional[int]					     =       None

try:
      import msvcrt
except ImportError:
      A     :  List[str]					     =       None

try:
      import fcntl
except ImportError:
      A     :  Union[str, Any]					     =       None


# Backward compatibility
# ------------------------------------------------
try:
      TimeoutError
except NameError:
      A     :  int					     =       OSError


# Data
# ------------------------------------------------
A     :  Any					     =       [
    "Timeout",
    "BaseFileLock",
    "WindowsFileLock",
    "UnixFileLock",
    "SoftFileLock",
    "FileLock",
]

A     :  Tuple					     =       "3.0.12"


A     :  str					     =       None


def      a__ (		):
      global _logger
      SCREAMING_SNAKE_CASE_          =  _logger or logging.getLogger(__name__				)
      return _logger


class   lowerCamelCase					(SCREAMING_SNAKE_CASE__					):
  """simple docstring"""







  def __init__(							self :       List[str]  ,     __magic_name__ :       List[str]   )  ->	List[str]:
        SCREAMING_SNAKE_CASE_          =  lock_file
        return None







  def __str__(							self :       List[str]   )  ->	Optional[Any]:
        SCREAMING_SNAKE_CASE_          =  F'''The file lock \'{self.lock_file}\' could not be acquired.'''
        return temp



class   lowerCamelCase					:
  """simple docstring"""







  def __init__(							self :       int  ,     __magic_name__ :       int   )  ->	str:
        SCREAMING_SNAKE_CASE_          =  lock
        return None







  def __enter__(							self :       int   )  ->	int:
        return self.lock







  def __exit__(							self :       Dict  ,     __magic_name__ :       Union[str, Any]  ,     __magic_name__ :       Union[str, Any]  ,     __magic_name__ :       Optional[int]   )  ->	Optional[int]:
        self.lock.release()
        return None



class   lowerCamelCase					:
  """simple docstring"""







  def __init__(							self :       int  ,     __magic_name__ :       Union[str, Any]  ,     __magic_name__ :       Optional[int]=-1  ,     __magic_name__ :       Optional[int]=None   )  ->	Dict:
        SCREAMING_SNAKE_CASE_          =  max_filename_length if max_filename_length is not None else 255
        # Hash the filename if it's too long
        SCREAMING_SNAKE_CASE_          =  self.hash_filename_if_too_long(__magic_name__  ,     __magic_name__   )
        # The path to the lock file.
        SCREAMING_SNAKE_CASE_          =  lock_file

        # The file descriptor for the *_lock_file* as it is returned by the
        # os.open() function.
        # This file lock is only NOT None, if the object currently holds the
        # lock.
        SCREAMING_SNAKE_CASE_          =  None

        # The default timeout value.
        SCREAMING_SNAKE_CASE_          =  timeout

        # We use this lock primarily for the lock counter.
        SCREAMING_SNAKE_CASE_          =  threading.Lock()

        # The lock counter is used for implementing the nested locking
        # mechanism. Whenever the lock is acquired, the counter is increased and
        # the lock is only released, when this value is 0 again.
        SCREAMING_SNAKE_CASE_          =  0
        return None







  @property
  def    __A     (							self :       int   )  ->	Optional[Any]:
        return self._lock_file







  @property
  def    __A     (							self :       List[str]   )  ->	Union[str, Any]:
        return self._timeout







  @timeout.setter
  def    __A     (							self :       List[str]  ,     __magic_name__ :       List[str]   )  ->	Optional[Any]:
        SCREAMING_SNAKE_CASE_          =  float(__magic_name__   )
        return None







  def    __A     (							self :       Optional[Any]   )  ->	Tuple:
        raise NotImplementedError()







  def    __A     (							self :       Optional[Any]   )  ->	int:
        raise NotImplementedError()







  @property
  def    __A     (							self :       Dict   )  ->	List[str]:
        return self._lock_file_fd is not None







  def    __A     (							self :       Optional[Any]  ,     __magic_name__ :       Optional[Any]=None  ,     __magic_name__ :       Optional[int]=0.05   )  ->	str:
        # Use the default timeout, if no timeout is provided.
        if timeout is None:
              SCREAMING_SNAKE_CASE_          =  self.timeout

        # Increment the number right at the beginning.
        # We can still undo it, if something fails.
        with self._thread_lock:
              self._lock_counter += 1

        SCREAMING_SNAKE_CASE_          =  id(self   )
        SCREAMING_SNAKE_CASE_          =  self._lock_file
        SCREAMING_SNAKE_CASE_          =  time.time()
        try:
              while True:
                    with self._thread_lock:
                          if not self.is_locked:
                                logger().debug(F'''Attempting to acquire lock {lock_id} on {lock_filename}'''   )
                                self._acquire()

                    if self.is_locked:
                          logger().debug(F'''Lock {lock_id} acquired on {lock_filename}'''   )
                          break
                    elif timeout >= 0 and time.time() - start_time > timeout:
                          logger().debug(F'''Timeout on acquiring lock {lock_id} on {lock_filename}'''   )
                          raise Timeout(self._lock_file   )
                    else:
                          logger().debug(
                              F'''Lock {lock_id} not acquired on {lock_filename}, waiting {poll_intervall} seconds ...'''   )
                          time.sleep(__magic_name__   )
        except:  # noqa
              # Something did go wrong, so decrement the counter.
              with self._thread_lock:
                    SCREAMING_SNAKE_CASE_          =  max(0  ,     self._lock_counter - 1   )

              raise
        return _Acquire_ReturnProxy(lock=self   )







  def    __A     (							self :       Dict  ,     __magic_name__ :       Tuple=False   )  ->	Optional[int]:
        with self._thread_lock:
              if self.is_locked:
                    self._lock_counter -= 1

                    if self._lock_counter == 0 or force:
                          SCREAMING_SNAKE_CASE_          =  id(self   )
                          SCREAMING_SNAKE_CASE_          =  self._lock_file

                          logger().debug(F'''Attempting to release lock {lock_id} on {lock_filename}'''   )
                          self._release()
                          SCREAMING_SNAKE_CASE_          =  0
                          logger().debug(F'''Lock {lock_id} released on {lock_filename}'''   )

        return None







  def __enter__(							self :       Optional[Any]   )  ->	Tuple:
        self.acquire()
        return self







  def __exit__(							self :       str  ,     __magic_name__ :       int  ,     __magic_name__ :       int  ,     __magic_name__ :       Union[str, Any]   )  ->	Union[str, Any]:
        self.release()
        return None







  def __del__(							self :       Optional[int]   )  ->	Optional[Any]:
        self.release(force=__magic_name__   )
        return None







  def    __A     (							self :       int  ,     __magic_name__ :       str  ,     __magic_name__ :       int   )  ->	str:
        SCREAMING_SNAKE_CASE_          =  os.path.basename(__magic_name__   )
        if len(__magic_name__   ) > max_length and max_length > 0:
              SCREAMING_SNAKE_CASE_          =  os.path.dirname(__magic_name__   )
              SCREAMING_SNAKE_CASE_          =  str(hash(__magic_name__   )   )
              SCREAMING_SNAKE_CASE_          =  filename[: max_length - len(__magic_name__   ) - 8] + "..." + hashed_filename + ".lock"
              return os.path.join(__magic_name__  ,     __magic_name__   )
        else:
              return path



class   lowerCamelCase					(SCREAMING_SNAKE_CASE__					):
  """simple docstring"""







  def __init__(							self :       List[str]  ,     __magic_name__ :       List[str]  ,     __magic_name__ :       Tuple=-1  ,     __magic_name__ :       Optional[int]=None   )  ->	Dict:
        from .file_utils import relative_to_absolute_path

        super().__init__(__magic_name__  ,     timeout=__magic_name__  ,     max_filename_length=__magic_name__   )
        SCREAMING_SNAKE_CASE_          =  "\\\\?\\" + relative_to_absolute_path(self.lock_file   )







  def    __A     (							self :       Tuple   )  ->	Any:
        SCREAMING_SNAKE_CASE_          =  os.O_RDWR | os.O_CREAT | os.O_TRUNC

        try:
              SCREAMING_SNAKE_CASE_          =  os.open(self._lock_file  ,     __magic_name__   )
        except OSError:
              pass
        else:
              try:
                    msvcrt.locking(__magic_name__  ,     msvcrt.LK_NBLCK  ,     1   )
              except OSError:
                    os.close(__magic_name__   )
              else:
                    SCREAMING_SNAKE_CASE_          =  fd
        return None







  def    __A     (							self :       List[str]   )  ->	Optional[Any]:
        SCREAMING_SNAKE_CASE_          =  self._lock_file_fd
        SCREAMING_SNAKE_CASE_          =  None
        msvcrt.locking(__magic_name__  ,     msvcrt.LK_UNLCK  ,     1   )
        os.close(__magic_name__   )

        try:
              os.remove(self._lock_file   )
        # Probably another instance of the application
        # that acquired the file lock.
        except OSError:
              pass
        return None



class   lowerCamelCase					(SCREAMING_SNAKE_CASE__					):
  """simple docstring"""







  def __init__(							self :       Dict  ,     __magic_name__ :       str  ,     __magic_name__ :       Tuple=-1  ,     __magic_name__ :       Dict=None   )  ->	Dict:
        SCREAMING_SNAKE_CASE_          =  os.statvfs(os.path.dirname(__magic_name__   )   ).f_namemax
        super().__init__(__magic_name__  ,     timeout=__magic_name__  ,     max_filename_length=__magic_name__   )







  def    __A     (							self :       int   )  ->	str:
        SCREAMING_SNAKE_CASE_          =  os.O_RDWR | os.O_CREAT | os.O_TRUNC
        SCREAMING_SNAKE_CASE_          =  os.open(self._lock_file  ,     __magic_name__   )

        try:
              fcntl.flock(__magic_name__  ,     fcntl.LOCK_EX | fcntl.LOCK_NB   )
        except OSError:
              os.close(__magic_name__   )
        else:
              SCREAMING_SNAKE_CASE_          =  fd
        return None







  def    __A     (							self :       List[str]   )  ->	Optional[Any]:
        # Do not remove the lockfile:
        #
        #   https://github.com/benediktschmitt/py-filelock/issues/31
        #   https://stackoverflow.com/questions/17708885/flock-removing-locked-file-without-race-condition
        SCREAMING_SNAKE_CASE_          =  self._lock_file_fd
        SCREAMING_SNAKE_CASE_          =  None
        fcntl.flock(__magic_name__  ,     fcntl.LOCK_UN   )
        os.close(__magic_name__   )
        return None



class   lowerCamelCase					(SCREAMING_SNAKE_CASE__					):
  """simple docstring"""







  def    __A     (							self :       Optional[Any]   )  ->	List[Any]:
        SCREAMING_SNAKE_CASE_          =  os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_TRUNC
        try:
              SCREAMING_SNAKE_CASE_          =  os.open(self._lock_file  ,     __magic_name__   )
        except OSError:
              pass
        else:
              SCREAMING_SNAKE_CASE_          =  fd
        return None







  def    __A     (							self :       List[str]   )  ->	Optional[int]:
        os.close(self._lock_file_fd   )
        SCREAMING_SNAKE_CASE_          =  None

        try:
              os.remove(self._lock_file   )
        # The file is already deleted and that's what we want.
        except OSError:
              pass
        return None



A     :  List[str]					     =       None

if msvcrt:
      A     :  Tuple					     =       WindowsFileLock
elif fcntl:
      A     :  Union[str, Any]					     =       UnixFileLock
else:
      A     :  List[Any]					     =       SoftFileLock

      if warnings is not None:
            warnings.warn("only soft file lock is available")


