'''simple docstring'''




from __future__ import annotations

import os




class       __UpperCAmelCase							:





       '''simple docstring'''



       __lowercase   :   Tuple  					=							(
           'High card',
           'One pair',
           'Two pairs',
           'Three of a kind',
           'Straight',
           'Flush',
           'Full house',
           'Four of a kind',
           'Straight flush',
           'Royal flush',
       )

       __lowercase   :   Optional[int]  					=							(
           '',  # placeholder as tuples are zero-indexed
           'One',
           'Two',
           'Three',
           'Four',
           'Five',
           'Six',
           'Seven',
           'Eight',
           'Nine',
           'Ten',
           'Jack',
           'Queen',
           'King',
           'Ace',
       )

       def __init__( self       ,	_SCREAMING_SNAKE_CASE					)						->	None:
           if not isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               A_      =  F'''Hand should be of type \'str\': {hand!r}'''
               raise TypeError(_SCREAMING_SNAKE_CASE					)
           # split removes duplicate whitespaces so no need of strip
           if len(hand.split(''' '''					)					) != 5:
               A_      =  F'''Hand should contain only 5 cards: {hand!r}'''
               raise ValueError(_SCREAMING_SNAKE_CASE					)
           A_      =  hand
           A_      =  0
           A_      =  0
           A_  ,A_      =  self._internal_state()
           A_      =  self._get_hand_type()
           A_      =  self._card_values[0]

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

       def    __A			( self       ,	_SCREAMING_SNAKE_CASE					)						->	str:
           # Breaking the tie works on the following order of precedence:
           # 1. First pair (default 0)
           # 2. Second pair (default 0)
           # 3. Compare all cards in reverse order because they are sorted.

           # First pair and second pair will only be a non-zero value if the card
           # type is either from the following:
           # 21: Four of a kind
           # 20: Full house
           # 17: Three of a kind
           # 16: Two pairs
           # 15: One pair
           if self._hand_type > other._hand_type:
               return "Win"
           elif self._hand_type < other._hand_type:
               return "Loss"
           elif self._first_pair == other._first_pair:
               if self._second_pair == other._second_pair:
                   return self._compare_cards(_SCREAMING_SNAKE_CASE					)
               else:
                   return "Win" if self._second_pair > other._second_pair else "Loss"
           return "Win" if self._first_pair > other._first_pair else "Loss"

       def    __A			( self					)						->	str:
           A_      =  PokerHand._HAND_NAME[self._hand_type - 14]
           A_      =  PokerHand._CARD_NAME[self._high_card]
           A_      =  PokerHand._CARD_NAME[self._first_pair]
           A_      =  PokerHand._CARD_NAME[self._second_pair]
           if self._hand_type in [22, 19, 18]:
               return name + F''', {high}-high'''
           elif self._hand_type in [21, 17, 15]:
               return name + F''', {paira}s'''
           elif self._hand_type in [20, 16]:
               A_      =  '''over''' if self._hand_type == 20 else '''and'''
               return name + F''', {paira}s {join} {paira}s'''
           elif self._hand_type == 23:
               return name
           else:
               return name + F''', {high}'''

       def    __A			( self       ,	_SCREAMING_SNAKE_CASE					)						->	str:
           # Enumerate gives us the index as well as the element of a list
           for index, card_value in enumerate(self._card_values					):
               if card_value != other._card_values[index]:
                   return "Win" if card_value > other._card_values[index] else "Loss"
           return "Tie"

       def    __A			( self					)						->	int:
           # Number representing the type of hand internally:
           # 23: Royal flush
           # 22: Straight flush
           # 21: Four of a kind
           # 20: Full house
           # 19: Flush
           # 18: Straight
           # 17: Three of a kind
           # 16: Two pairs
           # 15: One pair
           # 14: High card
           if self._is_flush():
               if self._is_five_high_straight() or self._is_straight():
                   return 23 if sum(self._card_values					) == 60 else 22
               return 19
           elif self._is_five_high_straight() or self._is_straight():
               return 18
           return 14 + self._is_same_kind()

       def    __A			( self					)						->	bool:
           return len(self._card_suit					) == 1

       def    __A			( self					)						->	bool:
           # If a card is a five high straight (low ace) change the location of
           # ace from the start of the list to the end. Check whether the first
           # element is ace or not. (Don't want to change again)
           # Five high straight (low ace): AH 2H 3S 4C 5D
           # Why use sorted here? One call to this function will mutate the list to
           # [5, 4, 3, 2, 14] and so for subsequent calls (which will be rare) we
           # need to compare the sorted version.
           # Refer test_multiple_calls_five_high_straight in test_poker_hand.py
           if sorted(self._card_values					) == [2, 3, 4, 5, 14]:
               if self._card_values[0] == 14:
                   # Remember, our list is sorted in reverse order
                   A_      =  self._card_values.pop(0					)
                   self._card_values.append(_SCREAMING_SNAKE_CASE					)
               return True
           return False

       def    __A			( self					)						->	bool:
           for i in range(4					):
               if self._card_values[i] - self._card_values[i + 1] != 1:
                   return False
           return True

       def    __A			( self					)						->	int:
           # Kind Values for internal use:
           # 7: Four of a kind
           # 6: Full house
           # 3: Three of a kind
           # 2: Two pairs
           # 1: One pair
           # 0: False
           A_      =  A_      =  A_      =  0
           for i in range(4					):
               # Compare two cards at a time, if they are same increase 'kind',
               # add the value of the card to val1, if it is repeating again we
               # will add 2 to 'kind' as there are now 3 cards with same value.
               # If we get card of different value than val1, we will do the same
               # thing with val2
               if self._card_values[i] == self._card_values[i + 1]:
                   if not vala:
                       A_      =  self._card_values[i]
                       kind += 1
                   elif vala == self._card_values[i]:
                       kind += 2
                   elif not vala:
                       A_      =  self._card_values[i]
                       kind += 1
                   elif vala == self._card_values[i]:
                       kind += 2
        # For consistency in hand type (look at note in _get_hand_type function)
           A_      =  kind + 2 if kind in [4, 5] else kind
           # first meaning first pair to compare in 'compare_with'
           A_      =  max(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					)
           A_      =  min(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					)
           # If it's full house (three count pair + two count pair), make sure
           # first pair is three count and if not then switch them both.
           if kind == 6 and self._card_values.count(_SCREAMING_SNAKE_CASE					) != 3:
               A_  ,A_      =  second, first
           A_      =  first
           A_      =  second
           return kind

       def    __A			( self					)						->	tuple[list[int], set[str]]:
           # Internal representation of hand as a list of card values and
           # a set of card suit
           A_      =  {"T": "10", "J": "11", "Q": "12", "K": "13", "A": "14"}
           A_      =  self._hand.translate(str.maketrans(_SCREAMING_SNAKE_CASE					)					).split()
           A_      =  [int(card[:-1]					) for card in new_hand]
           A_      =  {card[-1] for card in new_hand}
           return sorted(_SCREAMING_SNAKE_CASE       ,	reverse=_SCREAMING_SNAKE_CASE					), card_suit

       def __repr__( self					)						->	Any:
           return F'''{self.__class__}("{self._hand}")'''

       def __str__( self					)						->	Tuple:
           return self._hand

       def __eq__( self       ,	_SCREAMING_SNAKE_CASE					)						->	str:
           if isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               return self.compare_with(_SCREAMING_SNAKE_CASE					) == "Tie"
           return NotImplemented

       def __lt__( self       ,	_SCREAMING_SNAKE_CASE					)						->	Tuple:
           if isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               return self.compare_with(_SCREAMING_SNAKE_CASE					) == "Loss"
           return NotImplemented

       def __le__( self       ,	_SCREAMING_SNAKE_CASE					)						->	Optional[int]:
           if isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               return self < other or self == other
           return NotImplemented

       def __gt__( self       ,	_SCREAMING_SNAKE_CASE					)						->	Tuple:
           if isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               return not self < other and self != other
           return NotImplemented

       def __ge__( self       ,	_SCREAMING_SNAKE_CASE					)						->	Any:
           if isinstance(_SCREAMING_SNAKE_CASE       ,	_SCREAMING_SNAKE_CASE					):
               return not self < other
           return NotImplemented

       def __hash__( self					)						->	str:
           return object.__hash__(self					)





def 	_UpperCAmelCase       (				)      -> int:
    # Solution for problem number 54 from Project Euler
    # Input from poker_hands.txt file
    A_      =  0
    A_      =  os.path.abspath(os.path.dirname(_UpperCamelCase  )  )
    A_      =  os.path.join(_UpperCamelCase,  '''poker_hands.txt'''  )
    with open(_UpperCamelCase  ) as file_hand:
        for line in file_hand:
            A_      =  line[:14].strip()
            A_      =  line[15:].strip()
            A_  ,A_      =  PokerHand(_UpperCamelCase  ), PokerHand(_UpperCamelCase  )
            A_      =  player.compare_with(_UpperCamelCase  )
            if output == "Win":
                answer += 1
    return answer


if __name__ == "__main__":
  solution()







'''simple docstring'''




def 	_UpperCAmelCase       (				_UpperCamelCase       :      list[list[int]],  _UpperCamelCase       :      list[list[int]]  )      -> list[list[int]]:
    A_      =  []
    A_      =  len(_UpperCamelCase  )
    for i in range(_UpperCamelCase  ):
        A_      =  []
        for j in range(_UpperCamelCase  ):
            A_      =  0
            for k in range(_UpperCamelCase  ):
                A_      =  val + matrix_a[i][k] * matrix_b[k][j]
            list_a.append(_UpperCamelCase  )
        matrix_c.append(_UpperCamelCase  )
    return matrix_c





def 	_UpperCAmelCase       (				_UpperCamelCase       :      int  )      -> list[list[int]]:
    return [[int(row == column  ) for column in range(_UpperCamelCase  )] for row in range(_UpperCamelCase  )]





def 	_UpperCAmelCase       (				_UpperCamelCase       :      int  )      -> int:
    if n <= 1:
        return n
    A_      =  identity(2  )
    A_      =  [[1, 1], [1, 0]]
    A_      =  n - 1
    while n > 0:
        if n % 2 == 1:
            A_      =  multiply(_UpperCamelCase,  _UpperCamelCase  )
        A_      =  multiply(_UpperCamelCase,  _UpperCamelCase  )
        A_      =  int(n / 2  )
    return res_matrix[0][0]





def 	_UpperCAmelCase       (				_UpperCamelCase       :      int  )      -> int:
    if n <= 1:
        return n
    A_      =  0
    A_      =  1
    for _ in range(2,  n + 1  ):
        A_  ,A_      =  fiba, fiba + fiba
    return fiba





def 	_UpperCAmelCase       (				)      -> None:
    for ordinal in "0th 1st 2nd 3rd 10th 100th 1000th".split():
        A_      =  int(''''''.join(c for c in ordinal if c in '''0123456789'''  )  )  # 1000th --> 1000
        print(
            F'''{ordinal} fibonacci number using matrix exponentiation is '''
            F'''{nth_fibonacci_matrix(_UpperCamelCase  )} and using bruteforce is '''
            F'''{nth_fibonacci_bruteforce(_UpperCamelCase  )}\n'''  )
    # from timeit import timeit
    # print(timeit("nth_fibonacci_matrix(1000000)",
    #              "from main import nth_fibonacci_matrix", number=5))
    # print(timeit("nth_fibonacci_bruteforce(1000000)",
    #              "from main import nth_fibonacci_bruteforce", number=5))
    # 2.3342058970001744
    # 57.256506615000035


if __name__ == "__main__":
  import doctest

  doctest.testmod()
  main()






