A famous casino is suddenly faced with a sharp decline of their revenues. They decide to offer Texas hold'em also online. Can you help them by writing an algorithm that can rank poker hands? 

## Task

Create a poker hand that has a method to compare itself to another poker hand:

```python
compare_with(self, other_hand)
```

A poker hand has a constructor that accepts a string containing 5 cards:
```python
PokerHand("KS 2H 5C JD TD")
```

The characteristics of the string of cards are:
* Each card consists of two characters, where
 * The first character is the value of the card: `2, 3, 4, 5, 6, 7, 8, 9, T(en), J(ack), Q(ueen), K(ing), A(ce)`
 * The second character represents the suit: `S(pades), H(earts), D(iamonds), C(lubs)`
* A space is used as card separator between cards

The result of your poker hand compare can be one of these 3 options:

```python
[ "Win", "Tie", "Loss" ]
```

## Notes
* Apply the [Texas Hold'em](https://en.wikipedia.org/wiki/Texas_hold_%27em) rules for ranking the cards.
* Low aces are **NOT** valid in this kata.
* There is no ranking for the suits.

If you finished this kata, you might want to continue with [Sortable Poker Hands](https://www.codewars.com/kata/sortable-poker-hands)

Source: codewars | Difficulty: MEDIUM
Tags: Game theory

Starter code: def __init__(self, hand):
	

Solutions:
class PokerHand(object):
	CARD = '23456789TJQKA'
	RESULT = ['Loss', 'Tie', 'Win']

	def __init__(self, hand):
		values = ''.join(sorted(hand[::3], key=self.CARD.index))
		suits = set(hand[1::3])
		is_straight = values in self.CARD
		is_flush = len(suits) == 1
		self.score = (2 * sum((values.count(card) for card in values)) + 13 * is_straight + 15 * is_flush, [self.CARD.index(card) for card in values[::-1]])

	def compare_with(self, other):
		return self.RESULT[(self.score > other.score) - (self.score < other.score) + 1]


from collections import Counter

class Card(object):

	def __init__(self, card):
		if card[0] in '23456789':
			self.rank = int(card[0])
		else:
			self.rank = {'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14}.get(card[0])
		self.suit = card[1]

class PokerHand(object):

	def __init__(self, hand):
		self.hand = [Card(card) for card in hand.split()]
		self.rank_counts = Counter((card.rank for card in self.hand))

	def compare_with(self, other):
		return 'Win' if self.score > other.score else 'Loss' if self.score < other.score else 'Tie'

	@property
	def score(self):

		def is_flush():
			return len({card.suit for card in self.hand}) == 1

		def is_straight():

			def is_sequential(arr):
				return all((a + 1 == b for (a, b) in zip(arr, arr[1:])))
			arr = sorted((card.rank for card in self.hand))
			return is_sequential(arr) or (is_sequential(arr[:4]) and arr[0] == 2 and (arr[-1] == 14))

		def is_straight_flush():
			return is_flush() and is_straight()

		def is_n_of_kind(n):
			return n in list(self.rank_counts.values())

		def is_full_house():
			return is_n_of_kind(3) and is_n_of_kind(2)

		def is_2_pair():
			return list(self.rank_counts.values()).count(2) == 2

		def get_by_count(n):
			return tuple((rank for (rank, count) in sorted(list(self.rank_counts.items()), key=lambda x: (x[1], -x[0])) if count == n))
		if is_straight_flush():
			return (9, get_by_count(1))
		elif is_n_of_kind(4):
			return (8, get_by_count(4), get_by_count(1))
		elif is_full_house():
			return (7, get_by_count(3), get_by_count(2))
		elif is_flush():
			return (6, get_by_count(1))
		elif is_straight():
			return (5, get_by_count(1))
		elif is_n_of_kind(3):
			return (4, get_by_count(3), get_by_count(1))
		elif is_2_pair():
			return (3, get_by_count(2), get_by_count(1))
		elif is_n_of_kind(2):
			return (2, get_by_count(2), get_by_count(1))
		else:
			return (1, get_by_count(1))


class PokerHand:

	def __init__(self, hand):
		hand = hand.split()
		values = sorted(('__23456789TJQKA'.index(card[0]) for card in hand))[::-1]
		same_suit = len({card[1] for card in hand}) == 1
		straight = [values[0] - i for i in range(5)] == values
		kinds = {i: [] for i in range(1, 5)}
		for value in sorted(set(values))[::-1]:
			how_many = values.count(value)
			kinds[how_many].append(value)
		if same_suit and straight:
			self.rank = (8, values)
		elif kinds[4]:
			self.rank = (7, kinds[4], kinds[1])
		elif kinds[3] and kinds[2]:
			self.rank = (6, kinds[3], kinds[2])
		elif same_suit:
			self.rank = (5, values)
		elif straight:
			self.rank = (4, values)
		elif kinds[3]:
			self.rank = (3, kinds[3], kinds[1])
		elif len(kinds[2]) == 2:
			self.rank = (2, kinds[2], kinds[1])
		elif kinds[2]:
			self.rank = (1, kinds[2], kinds[1])
		else:
			self.rank = (0, values)

	def compare_with(self, other):
		return 'Win' if self.rank > other.rank else 'Loss' if self.rank < other.rank else 'Tie'


from collections import Counter
RESULT = ['Loss', 'Tie', 'Win']
HEX_CARDS = '23456789ABCDE'
CARD_TO_HEX = str.maketrans('TJQKA', 'ABCDE')
MAIN_RANK = [lambda colC, valC, isS: 5 in colC.values() and isS, lambda colC, valC, isS: 4 in valC.values(), lambda colC, valC, isS: 3 in valC.values() and 2 in valC.values(), lambda colC, valC, isS: 5 in colC.values(), lambda colC, valC, isS: isS, lambda colC, valC, isS: 3 in valC.values(), lambda colC, valC, isS: 2 in valC.values() and len(valC.keys()) == 3, lambda colC, valC, isS: 2 in valC.values() and len(valC.keys()) == 4, lambda colC, valC, isS: True]

class PokerHand(object):

	def __init__(self, hand):
		hand = hand.translate(CARD_TO_HEX)
		valCount = Counter((hand[n] for n in range(0, len(hand), 3)))
		colorCount = Counter((hand[n] for n in range(1, len(hand), 3)))
		minCardIdx = int(min(valCount.keys()), 16) - 2
		isStraight = valCount.keys() == set(HEX_CARDS[minCardIdx:minCardIdx + 5])
		hashSameRank = int(''.join(sorted(valCount.keys(), key=lambda k: (valCount[k], k), reverse=True)), 16)
		for (i, func) in enumerate(MAIN_RANK):
			if func(colorCount, valCount, isStraight):
				self.handValue = (len(MAIN_RANK) - i) * 16 ** 5 + hashSameRank
				break

	def compare_with(self, other):
		return RESULT[(self.handValue >= other.handValue) + (self.handValue > other.handValue)]


class PokerHand(object):
	FACE_VALUE = {'2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14}

	def __init__(self, hand):
		self.suits = {'S': 0, 'H': 0, 'D': 0, 'C': 0}
		self.values = {}
		self.flush = False
		for card in hand.split():
			card_val = self.FACE_VALUE.get(card[0])
			self.values[card_val] = self.values.get(card_val, 0) + 1
			self.suits[card[1]] += 1
			if self.suits[card[1]] == 5:
				self.flush = True
		self.high_low = self.high_low()
		self.straight = self.look_for_straight()
		self.rank_high_low = [self.rank()] + self.high_low[:]

	def high_low(self):
		high_low = []
		for i in range(1, 5):
			high_low += sorted([k for (k, v) in self.values.items() if v == i])
		return high_low[::-1]

	def look_for_straight(self):
		val_array = self.high_low[:]
		if 14 in val_array:
			val_array[val_array.index(14)] = 1 if 2 in val_array else 14
		return val_array == list(range(val_array[0], val_array[0] - 5, -1))

	def rank(self):
		num_vals = list(self.values.values())
		if self.flush:
			return 9 if self.straight else 6
		if num_vals.count(4) == 1:
			return 8
		if num_vals.count(3) == 1:
			return 7 if num_vals.count(2) == 1 else 4
		if self.straight:
			return 5
		if num_vals.count(2) > 0:
			return 3 if num_vals.count(2) == 2 else 2
		return 1

	def compare_with(self, other):
		for i in range(len(self.rank_high_low)):
			if self.rank_high_low[i] > other.rank_high_low[i]:
				return 'Win'
			if self.rank_high_low[i] < other.rank_high_low[i]:
				return 'Loss'
		return 'Tie'


from collections import Counter

class CardValue(str):
	ORDER = '23456789TJQKA'

	def __lt__(self, other):
		return self.ORDER.index(self) < self.ORDER.index(other)

	def __gt__(self, other):
		return self.ORDER.index(self) > self.ORDER.index(other)

class Card:
	ORDER = CardValue.ORDER

	def __init__(self, card_str):
		self.value = CardValue(card_str[0])
		self.color = card_str[1]

	def __lt__(self, other):
		return self.value < other.value

	def __str__(self):
		return ''.join((self.value, self.color))

class HandValue:

	def __init__(self, poker_hand):
		self.poker_hand = poker_hand

	def compare(self, other):
		return 'Tie'

	def __str__(self):
		return self.__class__.__name__

	@property
	def pretty_string(self):
		return '{} is {}'.format(self.poker_hand, self)

class RoyalFlush(HandValue):

	@staticmethod
	def is_valid(poker_hand):
		if poker_hand.is_same_color:
			if {card.value for card in poker_hand.cards} == {'A', 'K', 'Q', 'J', 'T'}:
				return True
		return False

class HighCard(HandValue):

	def compare(self, other):
		self_value_remaining = sorted(self.poker_hand.card_values, reverse=True)
		other_value_remaining = sorted(other.poker_hand.card_values, reverse=True)
		for i in range(5):
			if self_value_remaining[i] > other_value_remaining[i]:
				return 'Win'
			if self_value_remaining[i] < other_value_remaining[i]:
				return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		return True

class Pairs(HandValue):

	def compare(self, other):
		counter_self_values = Counter(self.poker_hand.card_values)
		counter_other_values = Counter(other.poker_hand.card_values)
		self_value_2 = next((value for (value, nb_repet) in counter_self_values.items() if nb_repet == 2))
		other_value_2 = next((value for (value, nb_repet) in counter_other_values.items() if nb_repet == 2))
		if self_value_2 > other_value_2:
			return 'Win'
		if self_value_2 < other_value_2:
			return 'Loss'
		self_value_remaining = sorted((value for (value, nb_repet) in counter_self_values.items() if nb_repet == 1), reverse=True)
		other_value_remaining = sorted((value for (value, nb_repet) in counter_other_values.items() if nb_repet == 1), reverse=True)
		for i in range(3):
			if self_value_remaining[i] > other_value_remaining[i]:
				return 'Win'
			if self_value_remaining[i] < other_value_remaining[i]:
				return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		counter_values = Counter(poker_hand.card_values)
		return 2 in counter_values.values()

class TwoPairs(HandValue):

	def compare(self, other):
		counter_self_values = Counter(self.poker_hand.card_values)
		counter_other_values = Counter(other.poker_hand.card_values)
		max_self_value_2 = max([value for (value, nb_repet) in counter_self_values.items() if nb_repet == 2])
		max_other_value_2 = max([value for (value, nb_repet) in counter_other_values.items() if nb_repet == 2])
		if max_self_value_2 > max_other_value_2:
			return 'Win'
		if max_self_value_2 < max_other_value_2:
			return 'Loss'
		min_self_value_2 = min([value for (value, nb_repet) in counter_self_values.items() if nb_repet == 2])
		min_other_value_2 = min([value for (value, nb_repet) in counter_other_values.items() if nb_repet == 2])
		if min_self_value_2 > min_other_value_2:
			return 'Win'
		if min_self_value_2 < min_other_value_2:
			return 'Loss'
		self_value_1 = next((value for (value, nb_repet) in counter_self_values.items() if nb_repet == 1))
		other_value_1 = next((value for (value, nb_repet) in counter_other_values.items() if nb_repet == 1))
		if self_value_1 > other_value_1:
			return 'Win'
		if self_value_1 < other_value_1:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		counter_values = Counter(poker_hand.card_values)
		return list(counter_values.values()).count(2) == 2

class ThreeOfAKind(HandValue):

	def compare(self, other):
		counter_self_values = Counter(self.poker_hand.card_values)
		counter_other_values = Counter(other.poker_hand.card_values)
		max_self_value_3 = [value for (value, nb_repet) in counter_self_values.items() if nb_repet == 3][0]
		max_other_value_3 = [value for (value, nb_repet) in counter_other_values.items() if nb_repet == 3][0]
		if max_self_value_3 > max_other_value_3:
			return 'Win'
		if max_self_value_3 < max_other_value_3:
			return 'Loss'
		max_self_value_2 = max((value for (value, nb_repet) in counter_self_values.items() if nb_repet == 1))
		max_other_value_2 = max((value for (value, nb_repet) in counter_other_values.items() if nb_repet == 1))
		if max_self_value_2 > max_other_value_2:
			return 'Win'
		if max_self_value_2 < max_other_value_2:
			return 'Loss'
		min_self_value_2 = min((value for (value, nb_repet) in counter_self_values.items() if nb_repet == 1))
		min_other_value_2 = min((value for (value, nb_repet) in counter_other_values.items() if nb_repet == 1))
		if min_self_value_2 > min_other_value_2:
			return 'Win'
		if min_self_value_2 < min_other_value_2:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		counter_self_values = Counter(poker_hand.card_values)
		return 3 in counter_self_values.values()

class FullHouse(HandValue):

	def compare(self, other):
		counter_self_values = Counter(self.poker_hand.card_values)
		counter_other_values = Counter(other.poker_hand.card_values)
		max_self_value_3 = [value for (value, nb_repet) in counter_self_values.items() if nb_repet == 3][0]
		max_other_value_3 = [value for (value, nb_repet) in counter_other_values.items() if nb_repet == 3][0]
		if max_self_value_3 > max_other_value_3:
			return 'Win'
		if max_self_value_3 < max_other_value_3:
			return 'Loss'
		max_self_value_2 = [value for (value, nb_repet) in counter_self_values.items() if nb_repet == 2][0]
		max_other_value_2 = [value for (value, nb_repet) in counter_other_values.items() if nb_repet == 2][0]
		if max_self_value_2 > max_other_value_2:
			return 'Win'
		if max_self_value_2 < max_other_value_2:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		counter_self_values = Counter(poker_hand.card_values)
		return set(counter_self_values.values()) == {2, 3}

class FourOfAKind(HandValue):

	def compare(self, other):
		counter_self_values = Counter(self.poker_hand.card_values)
		counter_other_values = Counter(other.poker_hand.card_values)
		max_self_value = [value for (value, nb_repet) in counter_self_values.items() if nb_repet == 4][0]
		max_other_value = [value for (value, nb_repet) in counter_other_values.items() if nb_repet == 4][0]
		if max_self_value > max_other_value:
			return 'Win'
		if max_self_value < max_other_value:
			return 'Loss'
		max_self_value = [value for (value, nb_repet) in counter_self_values.items() if nb_repet == 1][0]
		max_other_value = [value for (value, nb_repet) in counter_other_values.items() if nb_repet == 1][0]
		if max_self_value > max_other_value:
			return 'Win'
		if max_self_value < max_other_value:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		counter_self_values = Counter(poker_hand.card_values)
		return 4 in counter_self_values.values()

class Straight(HandValue):

	def compare(self, other):
		max_self_value = max(self.poker_hand.card_values)
		max_other_value = max(other.poker_hand.card_values)
		if max_self_value > max_other_value:
			return 'Win'
		if max_self_value < max_other_value:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		sorted_values = list(sorted((Card.ORDER.index(card.value) for card in poker_hand.cards)))
		return sorted_values == list(range(sorted_values[0], sorted_values[0] + 5))

class Flush(HandValue):

	def compare(self, other):
		return HighCard.compare(self, other)

	@staticmethod
	def is_valid(poker_hand):
		return poker_hand.is_same_color

class StraightFlush(HandValue):

	def compare(self, other):
		max_self_value = max(self.poker_hand.card_values)
		max_other_value = max(other.poker_hand.card_values)
		if max_self_value > max_other_value:
			return 'Win'
		if max_self_value < max_other_value:
			return 'Loss'
		return 'Tie'

	@staticmethod
	def is_valid(poker_hand):
		if poker_hand.is_same_color:
			sorted_values = list(sorted((Card.ORDER.index(card.value) for card in poker_hand.cards)))
			return sorted_values == list(range(sorted_values[0], sorted_values[0] + 5))
		return False

class PokerHand(object):
	RESULT = ['Loss', 'Tie', 'Win']
	HV_ORDER = [HighCard, Pairs, TwoPairs, ThreeOfAKind, Straight, Flush, FullHouse, FourOfAKind, StraightFlush, RoyalFlush]

	def __init__(self, hand):
		self.cards = tuple((Card(card_str) for card_str in hand.split()))
		self.is_same_color = len(set(self.card_colors)) == 1
		self.hand_value = None
		for hand_value_cls in reversed(self.HV_ORDER):
			if hand_value_cls.is_valid(self):
				self.hand_value = hand_value_cls(self)
				break

	def __str__(self):
		return ' '.join(map(str, self.cards))

	def compare_with(self, other):
		print(self.hand_value.pretty_string)
		print(other.hand_value.pretty_string)
		if self.HV_ORDER.index(type(self.hand_value)) < self.HV_ORDER.index(type(other.hand_value)):
			return 'Loss'
		if self.HV_ORDER.index(type(self.hand_value)) > self.HV_ORDER.index(type(other.hand_value)):
			return 'Win'
		return self.hand_value.compare(other.hand_value)

	@property
	def card_values(self):
		return tuple((card.value for card in self.cards))

	@property
	def card_colors(self):
		return tuple((card.color for card in self.cards))


class PokerHand(object):

	def __init__(self, hand):
		self.hand = hand
		self.lst = ['10' if 'T' in x else x[0].replace('J', '11').replace('Q', '12').replace('K', '13').replace('A', '14') for x in self.hand.split()]

	def straight(self):
		return 0 if not ''.join(sorted(self.lst, key=int)) in '234567891011121314' else max(list(map(int, self.lst)))

	def four(self):
		return 0 if not max([self.lst.count(x) for x in self.lst]) == 4 else [x for x in self.lst if self.lst.count(x) == 4][0]

	def full_house(self):
		return 0 if not len(set(self.lst)) == 2 or self.four() != 0 else [x for x in self.lst if self.lst.count(x) == 3][0]

	def flush(self):
		return 0 if not len({x[-1] for x in self.hand.split()}) == 1 or self.full_house() or self.four() else 6

	def three(self):
		return 0 if not max([self.lst.count(x) for x in self.lst]) == 3 or self.full_house() else [x for x in self.lst if self.lst.count(x) == 3][0]

	def two_pair(self):
		return 0 if not len(set(self.lst)) == 3 or self.three() else max({x for x in self.lst if self.lst.count(x) == 2}, key=int)

	def pair(self):
		return 0 if not len(set(self.lst)) == 4 else max({x for x in self.lst if self.lst.count(x) == 2}, key=int)

	def high(self):
		return sum(map(int, self.lst))

	def score(self):
		out = list(map(int, [min(self.straight(), self.flush()), self.four(), self.full_house(), self.flush(), self.straight(), self.three(), self.two_pair(), self.pair(), self.high()]))
		b = 14
		return out[0] * b ** 8 + out[1] * b ** 7 + out[2] * b ** 6 + out[3] * b ** 5 + out[4] * b ** 4 + out[5] * b ** 3 + out[6] * b ** 2 + out[7] * b ** 1 + out[8]

	def final_check(self, other):
		(one, two) = [sorted(x, key=int, reverse=True) for x in (self.lst, other.lst)]
		for i in range(5):
			if int(one[i]) > int(two[i]):
				return 1
			if int(two[i]) > int(one[i]):
				return -1
		return 0

	def compare_with(self, other):
		RESULT = ['Loss', 'Win']
		if self.score() == other.score() and (not self.final_check(other)):
			return 'Tie'
		if not self.straight() and (not self.flush()) and (not self.four()) and (not self.full_house()) and (not self.flush()) and (not self.straight()) and (not self.three()) and (not self.two_pair()) and (not self.pair()) and (not other.straight()) and (not other.flush()) and (not other.four()) and (not other.full_house()) and (not other.flush()) and (not other.straight()) and (not other.three()) and (not other.two_pair()) and (not other.pair()):
			return RESULT[self.final_check(other) > 0]
		return RESULT[self.score() > other.score()]


from collections import Counter

class PokerHand(object):

	def __init__(self, hand):
		self.hand = ''.join(hand.split())

	def evaluate(self):
		HIERARCHY = {'highcard': 1, 'pair': 2, 'two_pairs': 3, 'three_of_aKind': 4, 'straight': 5, 'flush': 6, 'full_house': 7, 'four_of_aKind': 8, 'straight_flush': 9, 'royal_flush': 10}
		PRECEDENCE = {'1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, 'T': 10, 'J': 11, 'Q': 12, 'K': 13, 'A': 14}
		value = sorted((PRECEDENCE[x] for x in self.hand[::2]))
		shape = self.hand[1::2]
		if len(set(shape)) == 1 and value == [10, 11, 12, 13, 14]:
			return (HIERARCHY['royal_flush'], value, 'royal_flush')
		elif len(set(shape)) == 1 and all((abs(value[i] - value[i + 1]) == 1 for i in range(len(value) - 1))):
			return (HIERARCHY['straight_flush'], value, 'straight_flush')
		elif any((value.count(x) == 4 for x in set(value))):
			return (HIERARCHY['four_of_aKind'], value, 'four_of_aKind')
		elif any((value.count(x) == 3 for x in set(value))) and any((value.count(x) == 2 for x in set(value))):
			return (HIERARCHY['full_house'], value, 'full_house')
		elif len(set(shape)) == 1:
			return (HIERARCHY['flush'], value, 'flush')
		elif all((abs(value[i] - value[i + 1]) == 1 for i in range(len(value) - 1))):
			return (HIERARCHY['straight'], value, 'straight')
		elif any((value.count(x) == 3 for x in set(value))):
			return (HIERARCHY['three_of_aKind'], value, 'three_of_aKind')
		elif Counter(value).most_common(2)[-1][-1] == 2:
			return (HIERARCHY['two_pairs'], value, 'two_pairs')
		elif any((value.count(x) == 2 for x in set(value))):
			return (HIERARCHY['pair'], value, 'pair')
		else:
			return (HIERARCHY['highcard'], value, 'highcard')

	def compare_with(self, other):
		(rank, cards, combo) = self.evaluate()
		(other_rank, other_cards, other_combo) = other.evaluate()
		if rank > other_rank:
			return 'Win'
		elif rank == other_rank:
			if cards == other_cards:
				return 'Tie'
			elif combo == 'straight_flush' or combo == 'straight':
				if cards.pop() > other_cards.pop():
					return 'Win'
				else:
					return 'Loss'
			elif combo == 'four_of_aKind' or combo == 'full_house':
				(c1, c2) = (Counter(cards), Counter(other_cards))
				if c1.most_common()[0][0] > c2.most_common()[0][0]:
					return 'Win'
				elif c1.most_common()[0][0] < c2.most_common()[0][0]:
					return 'Loss'
				elif c1.most_common()[-1][0] > c2.most_common()[-1][0]:
					return 'Win'
				else:
					return 'Loss'
			elif combo == 'flush':
				for i in range(4, -1, -1):
					if cards[i] < other_cards[i]:
						return 'Loss'
					elif cards[i] != other_cards[i]:
						return 'Win'
			elif combo == 'three_of_aKind':
				for i in range(1, -1, -1):
					if cards[i] < other_cards[i]:
						return 'Loss'
					elif cards[i] != other_cards[i]:
						return 'Win'
			elif combo == 'two_pairs' or combo == 'pair':
				(c1, c2) = (Counter(cards), Counter(other_cards))
				sorted_c1 = sorted(c1.most_common(), key=lambda x: (x[1], x))
				sorted_c2 = sorted(c2.most_common(), key=lambda x: (x[1], x))
				for i in range(len(sorted_c1) - 1, -1, -1):
					if sorted_c1[i][0] < sorted_c2[i][0]:
						return 'Loss'
					elif sorted_c1[i][0] != sorted_c2[i][0]:
						return 'Win'
			else:
				for i in range(4, -1, -1):
					if cards[i] < other_cards[i]:
						return 'Loss'
					elif cards[i] != other_cards[i]:
						return 'Win'
		else:
			return 'Loss'


class PokerHand(object):

	def __init__(self, hand):
		self.hand = hand
		pass

	def handProcess(self, handList):
		suit = handList[0][1]
		isHandFlush = True
		seenCards = []
		seenPairs = []
		seenTriple = []
		seenFour = []
		for card in handList:
			if suit not in card:
				isHandFlush = False
			if card[0] == 'T':
				(handList[handList.index(card)], card) = (10, 10)
			elif card[0] == 'J':
				(handList[handList.index(card)], card) = (11, 11)
			elif card[0] == 'Q':
				(handList[handList.index(card)], card) = (12, 12)
			elif card[0] == 'K':
				(handList[handList.index(card)], card) = (13, 13)
			elif card[0] == 'A':
				(handList[handList.index(card)], card) = (14, 14)
			else:
				(handList[handList.index(card)], card) = (int(card[0]), int(card[0]))
			if card in seenCards:
				if card in seenTriple:
					seenFour.append(card)
					del seenTriple[seenTriple.index(card)]
				elif card in seenPairs:
					seenTriple.append(card)
					del seenPairs[seenPairs.index(card)]
				else:
					seenPairs.append(card)
			seenCards.append(card)
		handList = sorted(handList)
		if sum(handList) == handList[-1] * (handList[-1] + 1) / 2 - (handList[0] - 1) * handList[0] / 2:
			isHandStraight = True
		else:
			isHandStraight = False
		highestCard = handList[-1]
		highestValue = 0
		cardsOutsideCombination = []
		handScore = 0
		if highestCard == 14 and isHandStraight and isHandFlush:
			handScore = 9
		elif isHandStraight and isHandFlush:
			handScore = 8
			highestValue = highestCard
		elif len(seenFour) == 1:
			handScore = 7
			highestValue = seenFour[0]
			for card in handList:
				if card not in seenFour:
					cardsOutsideCombination.append(card)
		elif len(seenTriple) == 1 and len(seenPairs) == 1:
			handScore = 6
			highestValue = seenTriple[0]
		elif isHandFlush:
			handScore = 5
		elif isHandStraight:
			handScore = 4
		elif len(seenTriple) == 1:
			handScore = 3
			highestValue = seenTriple[0]
			for card in handList:
				if card not in seenTriple:
					cardsOutsideCombination.append(card)
		elif len(seenPairs) == 2:
			handScore = 2
			highestValue = sorted(seenPairs)[-1]
			for card in handList:
				if card not in seenPairs:
					cardsOutsideCombination.append(card)
		elif len(seenPairs) == 1:
			handScore = 1
			highestValue = seenPairs[0]
			for card in handList:
				if card not in seenPairs:
					cardsOutsideCombination.append(card)
		return (handScore, highestValue, highestCard, cardsOutsideCombination, handList)

	def compare_with(self, other):
		hand1 = self.handProcess(self.hand.split())
		hand2 = self.handProcess(other.hand.split())
		if hand1[0] > hand2[0]:
			return 'Win'
		elif hand1[0] < hand2[0]:
			return 'Loss'
		elif hand1[1] > hand2[1]:
			return 'Win'
		elif hand1[1] < hand2[1]:
			return 'Loss'
		else:
			if hand1[2] > hand2[2]:
				return 'Win'
			elif hand1[2] < hand2[2]:
				return 'Loss'
			for card in range(0, len(hand1[3])):
				if hand1[3][card] > hand2[3][card]:
					return 'Win'
				elif hand1[3][card] < hand2[3][card]:
					return 'Loss'
			for card in range(len(hand1[4]) - 1, -1, -1):
				if hand1[4][card] > hand2[4][card]:
					return 'Win'
				elif hand1[4][card] < hand2[4][card]:
					return 'Loss'
			return 'Tie'


class PokerHand(object):

	def __init__(self, hand):
		self.st = ['2', '3', '4', '5', '6', '7', '8', '9', 'T', 'J', 'Q', 'K', 'A']
		self.h = sorted(hand.split(), key=lambda x: self.st.index(x[0]))
		self.v = lambda i, j: 'Win' if self.st.index(i) > self.st.index(j) else 'Loss'

	def compare_with(self, o):
		o = sorted(o.h, key=lambda x: self.st.index(x[0]))
		if o == self.h:
			return 'Tie'
		(s, s1) = ([i[0] for i in o], [i[0] for i in self.h])
		a = [self.straight_flush, self.four_of_kind, self.full_house, self.flush, self.straight, self.three_of_kind, self.two_pair, self.one_pair]
		b = [0, 1, 2, self.flush_, self.straight_, 5, 6, 7]
		for (u, j) in enumerate(zip(a, b)):
			(k, l) = (j[0], j[1])
			(i, j) = (k(self.h), k(o))
			if i != j:
				return 'Win' if i else 'Loss'
			elif i == j == 1:
				if u in [3, 4]:
					return l(s1, s)
				return self.common(s1, s)
		for (i, j) in zip(s1[::-1], s[::-1]):
			if i != j:
				return self.v(i, j)
		return 'Tie'

	def straight_flush(self, p):
		return len(set([i[1] for i in p])) == 1 and all((abs(self.st.index(p[i][0]) - self.st.index(p[i + 1][0])) == 1 for i in range(len(p) - 1)))

	def four_of_kind(self, p):
		p = [i[0] for i in p]
		return any((p.count(i) == 4 for i in p))

	def full_house(self, p):
		p = [i[0] for i in p]
		return any((p.count(i) == 3 for i in p)) and any((p.count(i) == 2 for i in p))

	def flush(self, p):
		return len(set([i[1] for i in p])) == 1

	def straight(self, p):
		return all((abs(self.st.index(p[i][0]) - self.st.index(p[i + 1][0])) == 1 for i in range(len(p) - 1)))

	def three_of_kind(self, p):
		p = [i[0] for i in p]
		return any((p.count(i) == 3 for i in p))

	def two_pair(self, p):
		p = [i[0] for i in p]
		return [p.count(i) for i in set(p)].count(2) == 2

	def one_pair(self, p):
		p = [i[0] for i in p]
		return [p.count(i) for i in set(p)].count(2) == 1

	def high_card(self, p):
		p = [i[0] for i in p]
		return max(p, key=lambda x: self.st.index(x))

	def straight_flush_(self, i, j):
		return 'Win' if self.v(i[-1], j[-1]) else 'Loss'

	def common(self, i, j):
		findi = sorted([k for k in set(i)], key=lambda x: (-i.count(x), -self.st.index(x)))
		findj = sorted([k for k in set(j)], key=lambda x: (-j.count(x), -self.st.index(x)))
		for (k, l) in zip(findi, findj):
			if k != l:
				return 'Win' if self.st.index(k) > self.st.index(l) else 'Loss'

	def flush_(self, i, j):
		for (k, l) in zip(i[::-1], j[::-1]):
			if k != l:
				return 'Win' if self.st.index(k) > self.st.index(l) else 'Loss'

	def straight_(self, i, j):
		return 'Tie' if self.st.index(i[-1]) == self.st.index(j[-1]) else 'Win' if self.st.index(i[-1]) > self.st.index(j[-1]) else 'Loss'