## Euler Problems 54 to 60

```# problem 54

def winner_calc(pointz1, pointz2, value_of_hand1, value_of_hand2, hi_card1, hi_card2):
global winner

if pointz1 < pointz2:
return winner
elif pointz1 > pointz2:
''' compare points '''
winner += 1
return winner
elif pointz1 == pointz2 and value_of_hand1 > value_of_hand2:
winner += 1
return winner
elif value_of_hand1 == value_of_hand2 and hi_card > hi_card2:
winner += 1
return winner
elif value_of_hand1 == value_of_hand2 and hi_card == hi_card2:
return winner
else:
return winner

def values(cards, rank):
'''list of card rank
['A'} -> [14] '''
lst =[]
for item in cards:
lst.append(rank[item])
return lst

def card_values(hand):
''' list of values in hand
['TS'] -> ['T']'''
values = []
for item in hand:
values.append(item[:-1])
return values

def txt_feed():
file = open('poker.txt', 'r')
for line in file:
line = line.strip('\n')
line = line.split()
if not line:
break
yield line

def card_suits(hand):
''' list of suits in hand
['TS', 'TD'] -> ['S', 'D'] '''
suits = []
for item in hand:
suits.append(item[-1])
return suits

def card_count(hand, target):
''' card counter '''
card_count = 0
for card in hand:
if card[-1] == target:
card_count += 1
return card_count

def all_same( items ):
return len(set(items)) == 1

def points_calc(hand, rank, flsh, royal):

global hi_card
global top_card
global reserve
item1 = None

suits = card_suits(hand) # ['C', 'H',.....]
val = card_values(hand)  # ['2', 'K', ..........]
cardvalue = values(val, rank)  # ['2', '14', ......]
suit = all_same(suits)          # check if one suit

#-- Royal Flush --------------

# perm to find if the hand equates to a Royal Flush

chk = False
for L in range(5, len(val)+1):
for subset in itertools.permutations(val, L):
if set(subset) == set(royal):
chk = True

if suit == True and chk == True:
hi_card = 13
top_card = 14
points = 10
return points

#-- Straight Flush -------------------------

# check all cards are of the same suit

chk = False
for L in range(5, len(val)+1):
for subset in itertools.permutations(val, L):
subset = list(subset)
if ''.join(subset) in ''.join(flsh):
chk = True

#  check if cards are consecutive.

if suit and chk:
cardvalue = sorted(cardvalue)
cardvalue = cardvalue[::-1]
hi_card = cardvalue[1]
top_card = cardvalue[0]
points = 9
return points

#-- Four of a kind ----------------------------

# check for cards of the same value, a list of 4 and 1 required.

#-- check for four of the same value
for item in cardvalue:
num = cardvalue.count(item)
if num == 4:
item1 = item
top_card = item1
points = 8
elif num == 1:
hi_card = item
if num == 1 and top_card == item1:
return points

#-- Three of a kind and a pair ----------------

temp = set()

# check for three and two of a kind
for item in cardvalue:
num = cardvalue.count(item)
if num == 3 or num == 2:

if num == 3:
item1 = item
top_card = item1

for x in cardvalue:
if cardvalue.count(x) == 2:
hi_card = x

if temp == {2, 3} or temp == {3, 2}:
points = 7
return points

#-- Flush ----------------------------------

suit_lst = []

# check first item in suit equals the remainder
for item in hand:
suit_lst.append(item[-1])

if suit_lst.count(suit_lst[0]) == 5:
cardvalue = sorted(cardvalue)
cardvalue = cardvalue[::-1]
hi_card = cardvalue[1]
top_card = max(cardvalue)
points = 6

return points

#-- Straight ------------------------------

chk = False

# check all cards are consecutive values
for L in range(5, len(val)+1):
for subset in itertools.permutations(val, L):
if ''.join(subset) in ''.join(flsh):
chk = True
cardvalue = sorted(cardvalue)
cardvalue = cardvalue[::-1]
hi_card = cardvalue[1]
top_card = cardvalue[0]

if chk:
points = 5
return points

#-- Three of a kind -----------------------------

temp = set()

suits = card_values(hand)

# count equal value cards
for item in suits:
num = suits.count(item)
if num == 3:
points = 4

for x in cardvalue:
if cardvalue.count(x) == 3:
top_card = x

temp = set()
for x in cardvalue:
if cardvalue.count(x) == 1:
hi_card = max(temp)

return points

#-- Two pairs -------------------------------------

temp = set()

# check if there are two of each item
for item in cardvalue:
num = cardvalue.count(item)
if num == 2:

if len(temp) == 2:
points = 3
top_card = max(temp)
hi_card = min(temp)
return points

#-- One pair -------------------------------------

temp = set()

for item in cardvalue:
num = cardvalue.count(item)
if num == 2:

top_card = max(temp)
points = 2
y = max(temp)
cardvalue_temp = cardvalue
cardvalue_temp = [x for x in cardvalue_temp if x != y]
hi_card = max(cardvalue_temp)
return points

#-- High card ----------------------------------

b = []
for x in range(0, len(val)):
b.append(card_rank[val[x]])

b = sorted(b)
b = b[::-1]
hi_card = b[1]
top_card = b[0]
reserve = b[2]
points = 1

return points
#==============================================================================

if __name__ == '__main__':

import itertools
winner = 0
valu = 0
top_card = 0
reserve = 0

card_rank ={'A': 14, 'K': 13, 'Q': 12, 'J': 11, 'T': 10, '9': 9, '8': 8,
'7': 7, '6': 6, '5': 5, '4': 4, '3': 3, '2': 2}
flush = ['A', 'K', 'Q', 'J', 'T', '9', '8', '7', '6', '5', '4', '3', '2']

royal_flush = ['T', 'J', 'Q', 'K', 'A']

test = txt_feed()
while True:
try:
while True:
pointz1 = 0  # points awarded for content of hand
pointz2 = 0

# -- evaluate hand1 -----------------------------------------------------------------

reserve1 = reserve
test2 = next(test)  # pulls out line of text
hand = test2[:5]   # splits test2 in half
ans = card_values(hand)  # list of values ['4', '7', '9', '3', 'j'] etc
pointz1 = points_calc(hand, card_rank, flush, royal_flush)  # initial value of hand(1 to 10)
hi_card1 = hi_card

valu = values(ans, card_rank)
value_of_hand1 = top_card

# -- evaluate hand2 -----------------------------------------------------------------------------------

reserve2 = reserve
hand2 = test2[5:]  # second half of list
ans = card_values(hand2)  # # list of values ['4', '7', '9',....
pointz2 = points_calc(hand2, card_rank, flush, royal_flush)  # analyse hand and award points

value_of_hand2 = top_card
hi_card2 = hi_card

# -- check for a winner! ----------

calc = winner_calc(pointz1, pointz2, value_of_hand1, value_of_hand2, hi_card1, hi_card2)

except StopIteration:
break

print('Wins for hand one = ', calc)
```
```# problem 55
count_it = 0
lychrel = 0

for y in range(1, 10000):
while True:
y_reversed = int(str(y)[::-1])
count_it += 1
# if the count goes up to 50 a lychrel number is declared
if count_it == 50:
lychrel += 1
count_it = 0
break
if palindrome:
count_it = 0
break

print('Lychrel numbers under 10000 = ', lychrel)
```
```# problem 56

temp = 0
for a in range(100, 1, -1):
for b in range(100, 1, -1):
natural_num = a ** b

l = str(natural_num)
digital_sum = 0
for i in l:
digital_sum += int(i)
if digital_sum > temp:
temp = digital_sum

```
```#problem 57

'''
It is possible to show that the square root of two can be
expressed as an infinite continued fraction.

v 2 = 1 + 1/(2 + 1/(2 + 1/(2 + ... ))) = 1.414213...

By expanding this for the first four iterations, we get:

1 + 1/2 = 3/2 = 1.5
1 + 1/(2 + 1/2) = 7/5 = 1.4
1 + 1/(2 + 1/(2 + 1/2)) = 17/12 = 1.41666...
1 + 1/(2 + 1/(2 + 1/(2 + 1/2))) = 41/29 = 1.41379...

The next three expansions are 99/70, 239/169, and 577/408,
but the eighth expansion, 1393/985, is the first example where
the number of digits in the numerator exceeds the number of digits in the denominator.

In the first one-thousand expansions, how many fractions contain a
numerator with more digits than denominator?
'''

def root_two(num):
''' int -> int
'''
count = 0
numerator = 3
denominator = 2
while num > 0:
a = denominator * 2 + numerator
b = numerator + denominator
numerator = a
denominator = b
num -= 1
if len(str(numerator)) > len(str(denominator)):
count += 1
return count

ans = root_two(1000)
```
```# problem 58
'''

Starting with 1 and spiralling anticlockwise in the following way,
a square spiral with side length 7 is formed.

37 36 35 34 33 32 31
38 17 16 15 14 13 30
39 18  5  4  3 12 29
40 19  6  1  2 11 28
41 20  7  8  9 10 27
42 21 22 23 24 25 26
43 44 45 46 47 48 49

It is interesting to note that the odd squares lie along the bottom right diagonal,
but what is more interesting is that 8 out of the 13 numbers lying along both
diagonals are prime; that is, a ratio of 8/13 â‰ˆ 62%.

If one complete new layer is wrapped around the spiral above, a square spiral
with side length 9 will be formed. If this process is continued, what is the
side length of the square spiral for which the ratio of primes along both diagonals
first falls below 10%?

'''

def isprime(n):

# make sure n is a positive integer
n = abs(int(n))

# all other even numbers are not primes,
#rejects other even numbers.
if not n & 1:
return False

# range starts with 3 and only needs to go up the squareroot of n
# for all odd numbers
for x in range (3,int (n**0.5)+1, 2):

if n % x == 0:
n = n+ 1
return False

return True

if __name__ == '__main__':

import time
tt = time.time()
prime_count = 0
ans = 1
count = 0
x = 2
total = 0
percent = 1

while True:
total += 1
count += 1

ans += x

if isprime(ans):
prime_count += 1

percent =  prime_count / total

if percent <= 0.1:
print('Answer = ', x + 1)
print(time.time() - tt)
exit()

if count == 4:
x += 2
count = 0

print("done!", x + 1)
```
```#problem 59
from string import ascii_lowercase

class Decoder:
def __init__(self):
self.lst = [i for i in ascii_lowercase]
self.alphalist = self.lst
self.data = None
self.code_lst = None

''' text -> list
Read text and output as a list (data)
'''
with open(text) as file:
self.data = self.data.strip('\n')
self.data = self.data.split(',')
return self.data

def get_code(self):
''' list -> list
Extract a three character code by
applying the alphabet to every third character and
checking for spaces (ascii 32)
'''
alpha = ''
dict1 = {}
key_list = []
temp_list = []
total_e = 0
for a in range(0, 3):
for x in range(0, len(self.alphalist)):
for y in range(a, len(self.data), 3):
if y > len(self.data):
y = len(self.data)
data_y = int(self.data[y])
alpha = self.lst[x]
temp_list.append(int(ord(alpha)) ^ int(data_y))
e_accum = temp_list.count(32)
dict1[alpha] = e_accum
if e_accum > total_e:
total_e = e_accum
temp_list = []
ans = max(dict1, key=dict1.get)
key_list.append(ans)
print(key_list)
total_e = 0
code_lst = [key_list[0], key_list[1], key_list[2]]
return code_lst

def decrypt_text(self):
''' list -> text
Decrypt the list and sum the ascii values
'''

text_out = ''  # decrypted text
y = 0
out_lst = []    # decrypted list
len_data = len(self.data)
index1 = 0
index2 = 3
slice = self.data[index1:index2]
while y != len(self.data):
for x in range(0, len(self.code_lst)):
a = int(slice[x])
b = ord(self.code_lst[x])
ab_sum = a ^ b
out_lst.append(ab_sum)
#print(out)
da = len(out_lst)
if da == len_data:
exit()
y += 1
index1 += 3
index2 += 3
if index2 > len(self.data):
index2 = len(self.data)
slice = self.data[index1:index2]

def get_text(self, txt):
''' number list -> text
convert list of numbers and convert to
characters
'''
for x in range(len(self.lst)):
txt += chr(self.lst[x])
return txt

def main():
my_code = Decoder()