
from __future__ import annotations

import os







class 							lowercase						:
							lowercase_			:			List[str]			   =(
							    '''High card''',
							    '''One pair''',
							    '''Two pairs''',
							    '''Three of a kind''',
							    '''Straight''',
							    '''Flush''',
							    '''Full house''',
							    '''Four of a kind''',
							    '''Straight flush''',
							    '''Royal flush''',
							)

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




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




							@property
							def 					A__ (							self):
												return self._hand




							def 					A__ (							self  ,A__):
												# 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(A__)
																	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):
												lowercase		      =		PokerHand._HAND_NAME[self._hand_type - 1_4]
												lowercase		      =		PokerHand._CARD_NAME[self._high_card]
												lowercase		      =		PokerHand._CARD_NAME[self._first_pair]
												lowercase		      =		PokerHand._CARD_NAME[self._second_pair]
												if self._hand_type in [2_2, 1_9, 1_8]:
																	return name + f', {high}-high'
												elif self._hand_type in [2_1, 1_7, 1_5]:
																	return name + f', {paira}s'
												elif self._hand_type in [2_0, 1_6]:
																	lowercase		      =		'''over''' if self._hand_type == 2_0 else '''and'''
																	return name + f', {paira}s {join} {paira}s'
												elif self._hand_type == 2_3:
																	return name
												else:
																	return name + f', {high}'




							def 					A__ (							self  ,A__):
												# 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):
												# 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 2_3 if sum(self._card_values) == 6_0 else 2_2
																	return 1_9
												elif self._is_five_high_straight() or self._is_straight():
																	return 1_8
												return 1_4 + self._is_same_kind()




							def 					A__ (							self):
												return len(self._card_suit) == 1




							def 					A__ (							self):
												# 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, 1_4]:
																	if self._card_values[0] == 1_4:
																						# Remember, our list is sorted in reverse order
																						lowercase		      =		self._card_values.pop(0)
																						self._card_values.append(A__)
																	return True
												return False




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




							def 					A__ (							self):
												# 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
												lowercase		      =		lowercase		      =		lowercase		      =		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:
																											lowercase		      =		self._card_values[i]
																											kind += 1
																						elif vala == self._card_values[i]:
																											kind += 2
																						elif not vala:
																											lowercase		      =		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)
												lowercase		      =		kind + 2 if kind in [4, 5] else kind
												# first meaning first pair to compare in 'compare_with'
												lowercase		      =		max(A__  ,A__)
												lowercase		      =		min(A__  ,A__)
												# 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(A__) != 3:
																	lowercase      ,		lowercase		      =		second, first
												lowercase		      =		first
												lowercase		      =		second
												return kind




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




							def __repr__(							self):
												return f'{self.__class__}("{self._hand}")'




							def __str__(							self):
												return self._hand




							def __eq__(							self  ,A__):
												if isinstance(A__  ,A__):
																	return self.compare_with(A__) == "Tie"
												return NotImplemented




							def __lt__(							self  ,A__):
												if isinstance(A__  ,A__):
																	return self.compare_with(A__) == "Loss"
												return NotImplemented




							def __le__(							self  ,A__):
												if isinstance(A__  ,A__):
																	return self < other or self == other
												return NotImplemented




							def __gt__(							self  ,A__):
												if isinstance(A__  ,A__):
																	return not self < other and self != other
												return NotImplemented




							def __ge__(							self  ,A__):
												if isinstance(A__  ,A__):
																	return not self < other
												return NotImplemented





							def __hash__(							self):
												return object.__hash__(self)



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


if __name__ == "__main__":
							solution()






import os
import random
from pathlib import Path
from typing import List

import numpy as np
import torch
from torch.cuda.amp import GradScaler

from .utils import (
    MODEL_NAME,
    OPTIMIZER_NAME,
    RNG_STATE_NAME,
    SCALER_NAME,
    SCHEDULER_NAME,
    get_pretty_name,
    is_tpu_available,
    is_xpu_available,
    save,
)


if is_tpu_available(check_device=False):
							import torch_xla.core.xla_model as xm

from .logging import get_logger
from .state import PartialState


lowercase__						:Optional[Any]					    =       get_logger(__name__)



def 			UpperCamelCase       (				lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__ = None					,     ):
					'''simple docstring'''
					# Model states
					for i, state in enumerate(lowerCAmelCase__						):
										lowercase		      =		f'{MODEL_NAME}.bin' if i == 0 else f'{MODEL_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										save(lowerCAmelCase__					,     lowerCAmelCase__						)
										logger.info(f'Model weights saved in {output_model_file}'						)
					# Optimizer states
					for i, opt in enumerate(lowerCAmelCase__						):
										lowercase		      =		opt.state_dict()
										lowercase		      =		f'{OPTIMIZER_NAME}.bin' if i == 0 else f'{OPTIMIZER_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										save(lowerCAmelCase__					,     lowerCAmelCase__						)
										logger.info(f'Optimizer state saved in {output_optimizer_file}'						)
					# Scheduler states
					for i, scheduler in enumerate(lowerCAmelCase__						):
										lowercase		      =		scheduler.state_dict()
										lowercase		      =		f'{SCHEDULER_NAME}.bin' if i == 0 else f'{SCHEDULER_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										save(lowerCAmelCase__					,     lowerCAmelCase__						)
										logger.info(f'Scheduler state saved in {output_scheduler_file}'						)
					# GradScaler state
					if scaler is not None:
										lowercase		      =		scaler.state_dict()
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										torch.save(lowerCAmelCase__					,     lowerCAmelCase__						)
										logger.info(f'Gradient scaler state saved in {output_scaler_file}'						)
					# Random number generator states
					lowercase		      =		{}
					lowercase		      =		f'{RNG_STATE_NAME}_{process_index}.pkl'
					lowercase		      =		random.getstate()
					lowercase		      =		np.random.get_state()
					lowercase		      =		torch.get_rng_state()
					if is_xpu_available():
										lowercase		      =		torch.xpu.get_rng_state_all()
					else:
										lowercase		      =		torch.cuda.get_rng_state_all()
					if is_tpu_available():
										lowercase		      =		xm.get_rng_state()
					lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
					torch.save(lowerCAmelCase__					,     lowerCAmelCase__						)
					logger.info(f'Random states saved in {output_states_file}'						)
					return output_dir



def 			UpperCamelCase       (				lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__=None					,     lowerCAmelCase__=None					,     **lowerCAmelCase__					,     ):
					'''simple docstring'''
					if map_location not in [None, "cpu", "on_device"]:
										raise TypeError(
										    '''Unsupported optimizer map location passed, please choose one of `None`, `\'cpu\'`, or `\'on_device\'`'''						)
					if map_location is None:
										lowercase		      =		'''cpu'''
					elif map_location == "on_device":
										lowercase		      =		PartialState().device
					# Model states
					for i, model in enumerate(lowerCAmelCase__						):
										lowercase		      =		f'{MODEL_NAME}.bin' if i == 0 else f'{MODEL_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										models[i].load_state_dict(torch.load(lowerCAmelCase__					,     map_location=lowerCAmelCase__						)					,     **lowerCAmelCase__						)
					logger.info('''All model weights loaded successfully'''						)

					# Optimizer states
					for i, opt in enumerate(lowerCAmelCase__						):
										lowercase		      =		f'{OPTIMIZER_NAME}.bin' if i == 0 else f'{OPTIMIZER_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										lowercase		      =		torch.load(lowerCAmelCase__					,     map_location=lowerCAmelCase__						)
										optimizers[i].load_state_dict(lowerCAmelCase__						)
					logger.info('''All optimizer states loaded successfully'''						)

					# Scheduler states
					for i, scheduler in enumerate(lowerCAmelCase__						):
										lowercase		      =		f'{SCHEDULER_NAME}.bin' if i == 0 else f'{SCHEDULER_NAME}_{i}.bin'
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										scheduler.load_state_dict(torch.load(lowerCAmelCase__						)						)
					logger.info('''All scheduler states loaded successfully'''						)

					# GradScaler state
					if scaler is not None:
										lowercase		      =		os.path.join(lowerCAmelCase__					,     lowerCAmelCase__						)
										scaler.load_state_dict(torch.load(lowerCAmelCase__						)						)
										logger.info('''GradScaler state loaded successfully'''						)

					# Random states
					try:
										lowercase		      =		torch.load(os.path.join(lowerCAmelCase__					,     f'{RNG_STATE_NAME}_{process_index}.pkl'						)						)
										random.setstate(states['''random_state''']						)
										np.random.set_state(states['''numpy_random_seed''']						)
										torch.set_rng_state(states['''torch_manual_seed''']						)
										if is_xpu_available():
															torch.xpu.set_rng_state_all(states['''torch_xpu_manual_seed''']						)
										else:
															torch.cuda.set_rng_state_all(states['''torch_cuda_manual_seed''']						)
										if is_tpu_available():
															xm.set_rng_state(states['''xm_seed''']						)
										logger.info('''All random states loaded successfully'''						)
					except Exception:
										logger.info('''Could not load random states'''						)



def 			UpperCamelCase       (				lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__ = 0						):
					'''simple docstring'''
					lowercase		      =		Path(lowerCAmelCase__						) / f'custom_checkpoint_{index}.pkl'
					logger.info(f'Saving the state of {get_pretty_name(lowerCAmelCase__						)} to {save_location}'						)
					torch.save(obj.state_dict()					,     lowerCAmelCase__						)



def 			UpperCamelCase       (				lowerCAmelCase__					,     lowerCAmelCase__					,     lowerCAmelCase__ = 0						):
					'''simple docstring'''
					lowercase		      =		f'{path}/custom_checkpoint_{index}.pkl'
					logger.info(f'Loading the state of {get_pretty_name(lowerCAmelCase__						)} from {load_location}'						)
					obj.load_state_dict(torch.load(lowerCAmelCase__					,     map_location='''cpu'''						)						)




