Project Euler: Sum varying by a significant margin - python

I'm currently trying to solve problem 22 on Project Euler...which is as follows:
**Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-thousand first names, begin by sorting it into alphabetical order. Then working out the alphabetical value for each name, multiply this value by its alphabetical position in the list to obtain a name score.
For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12 + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 = 49714.
What is the total of all the name scores in the file?**
Here's the code that I wrote to solve this problem:
f = open("F:\gnames.txt", "r")
strr = f.read()
w = strr.replace('"', "")
li = w.split(',')
dic = {}
sum = 0
for ee in li:
for e in ee:
if (e == "A"):
sum+=1
elif (e == "B"):
sum+=2
elif (e == "C"):
sum+=3
elif (e == "D"):
sum+=4
elif (e == "E"):
sum+=5
elif (e == "F"):
sum+=6
elif (e == "G"):
sum+=7
elif (e == "H"):
sum+=8
elif (e == "I"):
sum+=9
elif (e == "J"):
sum+=10
elif (e == "K"):
sum+=11
elif (e == "L"):
sum+=12
elif (e == "M"):
sum+=13
elif (e == "N"):
sum+=14
elif (e == "O"):
sum+=15
elif (e == "P"):
sum+=16
elif (e == "Q"):
sum+=17
elif (e == "R"):
sum+=18
elif (e == "S"):
sum+=19
elif (e == "T"):
sum+=20
elif (e == "U"):
sum+=21
elif (e == "V"):
sum+=22
elif (e == "W"):
sum+=23
elif (e == "X"):
sum+=24
elif (e == "Y"):
sum+=25
else:
sum+=26
dic[ee] = sum
sum = 0
x = sorted(dic.items(), key=lambda t: t[1])
main_sum = 0
index = 0
for c in x:
t = c[1]*index
main_sum = main_sum + t
index+=1
print main_sum
The actual answer is 871198282. However, my code gives the answer as 995996966, which is off by 124798684 compared to the actual answer. What seems to be the problem with my code?

I think your issue is in the line x = sorted(dic.items(), key=lambda t: t[1]). This sorts the dictionary items by the scores, not alphabetically by the names. Change t[1] to t[0] in the lambda and I suspect you'll get a better result.
Another possible issue (it's a little ambiguous) is your indexing when you go to add up the scores. You're starting index at zero, but the instructions suggest that the 938th name should be multiplied by 938, not by its zero-based index, which would be 937. You probably need to start with index = 1.

Related

If loop with multiple conditions still executing when one condition is not met

I'm making a roman numeral to integer converter. In the code below, you will see the function math_logic. When I give the input CCC, the program should skip the if statements and elif statements (because of the keyword and) and go right to the else statement since only one of the two conditions are met. The else statement should return a dictionary value using parameter char_0 as the key. However, the program will run the code inside the second elif statement and return TypeError: unsupported operand type(s) for +: 'int' and 'NoneType' as the error.
I'm not sure why this is happening. You can put a debug point at line 38 and step into 4 times to get to the issue I'm having.
Please see code below
romanToIntDictionary = {
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000
}
subtraction_happened = [
4,
9,
40,
90,
400,
900
]
def convert_roman_to_int(string, checker_state):
characters_left = len(string)
character_list = []
total = 0
if checker_state:
print("What you entered is a valid roman numeral.")
for character in string:
character_list.append(character)
while characters_left > 1:
did_i_sub = False
for item in subtraction_happened:
if (not did_i_sub) and (item == math_logic(character_list[0], character_list[1], romanToIntDictionary)): #the order of multiple conditions matters
total = total + math_logic(character_list[0], character_list[1], romanToIntDictionary)
characters_left -= 2
character_list.pop(0)
character_list.pop(0)
did_i_sub = True
if not did_i_sub:
total = total + math_logic(character_list[0], character_list[1], romanToIntDictionary)
characters_left -= 1
character_list.pop(0)
while characters_left == 1:
total = total + romanToIntDictionary[character_list[0]]
characters_left -= 1
character_list.pop(0)
print(total)
if not checker_state:
print("What you entered is not a roman numeral.")
def math_logic(char_0, char_1, r_to_i_dict):
if (char_0 == "I") and (char_1 == "V" or "X"):
if char_1 == "V":
return 4
elif char_1 == "X":
return 9
elif (char_1 == "L" or "C") and (char_0 == "X"):
if char_1 == "L":
return 40
elif char_1 == "C":
return 90
elif (char_1 == "D" or "M") and (char_0 == "C"):
if char_1 == "D":
return 400
elif char_1 == "M":
return 900
else:
return r_to_i_dict[char_0]
def roman_numeral_checker(string):
is_roman_numeral = True
characters_left = len(string)
while is_roman_numeral and characters_left > 0:
for character in string:
if character not in romanToIntDictionary.keys():
is_roman_numeral = False
characters_left -= 1
if not is_roman_numeral:
return False
if is_roman_numeral:
return True
string_from_user = (input("Enter a roman numeral to convert: ")).upper()
convert_roman_to_int(string_from_user, roman_numeral_checker(string_from_user))
The trouble is in your boolean logic:
value = 'c'
print(value == 'X' or 'V')
'V'
This is because 'V' is a "truthy" value:
bool('V')
True
So you are saying if value == 'X' or True: which will always be True. Because of this, there's an else that isn't evaluating:
if value == 'X' or 'V':
if value == 'X':
print('X!')
elif value == 'V':
print('V!')
else:
print('unexpected')
unexpected
The correct syntax is:
if value == 'X' or value == 'V':
Or even more succinctly:
if value in ('X', 'V'):
if value == 'X':
do something
else:
do something
The else ensures that all cases are covered, and they are, because value could only be 'X' or 'V'.
So your whole math logic function would be:
def math_logic(char_0, char_1, r_to_i_dict):
if char_0 == "I" and char_1 in ('V', 'X'):
if char_1 == "V":
return 4
else:
return 9
elif char_1 in ('L', 'C') and char_0 == "X":
if char_1 == "L":
return 40
else:
return 90
elif char_1 in ('D', 'M') and char_0 == "C":
if char_1 == "D":
return 400
else:
return 900
else:
return r_to_i_dict[char_0]

Break function does not work when the elif line is true

start = input('Enter quadratic equation: ')
w = start.split()
while len(w) != 7:
start = input('Enter quadratic equation correctly: ')
w = start.split()
while x < len(w):
if "x" in w[x] and '^2' in w[x]:
a = w[x]
if a == "x^2":
a = 1
else:
a = a.replace('x^2', '')
a = int(a)
if w[x-1] == '-':
a = a * (-1)
else:
a = a
elif 'x' in w[x] and '^' not in w[x]:
b = w[x]
if b == 'x':
b = 1
else:
b = b.replace('x', '')
b = int(b)
if w[x-1] == '-':
b = b * (-1)
else:
b = b
elif w[x].isdigit() and 'x' not in w[x] and w[x] != '0':
c = w[x]
elif w[x] == '-' or '+' or '=':
s = 0
elif not w[x].isdigit() and 'x' not in w[x] and w[x] != '-' or '+' or '=':
print('Mistake')
break #Would not this code here work?
x += 1
I have tried just doing 'else' block, but still it wouldn't work. What I am trying to do is to check whether the input is actually a quadratic equation.
The wrong condition is elif not w[x].isdigit() and 'x' not in w[x] and w[x] != '-' or '+' or '=':, it doesn't do what you want/need
The w[x] != '-' or '+' or '=': part :
is like (w[x]!='-') or ('+') or ('='):
not like w[x] != ('-' or '+' or '='):
What you want is w[x] not in '-+=': and same for the previous one
elif w[x] in '-+=':
s = 0
elif not w[x].isdigit() and 'x' not in w[x] and w[x] not in '-+=':
print('Mistake')
break

Separating out 'While' function

I currently have defined my object (is_matched) that contains a while loop and also the checking of a string. I am trying to pull out the while loop into it's own object but am having trouble completing the coding. I also need the while loop to continue running until a user enters 'q' into the input.
def is_matched():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
stack = Stack()
for i in expr:
if i == '{' or i == '(' or i == '[':
stack.push(i)
elif i == '}':
if len(expr) != 0:
c = stack.top()
if c == '{':
stack.pop()
else:
return "Unbalanced"
elif i == ')':
if len(expr) != 0:
c = stack.top()
if c == '(':
stack.pop()
else:
return "Unbalanced"
elif i == ']':
if len(expr) != 0:
c = stack.top()
if c == '[':
stack.pop()
else:
return "Unbalanced"
else:
return "Unbalanced"
if len(stack) != 0:
return "Unblanced"
return "Balanced"
result = is_matched()
print(result)
I am trying to pull out the while loop from above and enter into its own object as follows:
def main():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
else:
return is_matched()
your is_matched function will take one argument which will be the expression to evaluate.
def is_matched(expr):
stack = Stack()
for i in expr:
if i == '{' or i == '(' or i == '[':
stack.push(i)
elif i == '}':
if len(expr) != 0:
c = stack.top()
if c == '{':
stack.pop()
else:
return "Unbalanced"
elif i == ')':
if len(expr) != 0:
c = stack.top()
if c == '(':
stack.pop()
else:
return "Unbalanced"
elif i == ']':
if len(expr) != 0:
c = stack.top()
if c == '[':
stack.pop()
else:
return "Unbalanced"
else:
return "Unbalanced"
if len(stack) != 0:
return "Unblanced"
return "Balanced"
main function.
def main():
while True:
expr = input("Enter string (q to quit): ")
if expr == "q":
break
else:
print(is_matched(expr))

Use inequality from user input string

Lets say I'm writing a program that checks if input [ one number and equality statement ] compared against a randomly generated number is true, here's my code for reference:
import random
class Checker():
def __init__(self):
self.user_num=[]
self.comp_roll()
self.input_drive()
def comp_roll(self):
self.roll=random.randint(1,6)+random.randint(1,6) #roll 2 d6
def input_drive(self):
self.user_input=input("Input a number and [in]equality to compare against 2 random d6")
user_input=self.user_input
for i in range(len(user_input)):
if user_input[i].isdigit() == True: #if user_input[i] is a num
self.user_num.append(user_input[i]) #Keep track of just number from input in list
else: #if user_input[i] is not a num
if user_input[i] == ">":
self.track_op=">"
elif user_input[i] == "<":
self.track_op="<"
elif user_input[i] == "=":
self.track_op="="
self.user_num=int("".join(self.user_num)) #turn number list into one int
self.logic()
def logic(self):
dif=self.roll-self.user_num
abs_dif=abs(dif)
if self.track_op == ">":
if dif > 0:
win=True
else:
win=False
elif self.track_op == "<":
if dif < 0:
win=True
else:
win=False
elif self.track_op == "=":
if dif == 0:
win=True
else:
win=False
print("{result}\nComputer Guessed %d\nYou Guessed %d\nDifference %d".format(result="Win! :)" if win==True else "Lose :(") % (self.roll,self.user_num,abs_dif))
test=Checker()
So as you should be able to see I'm forced to use a switch statement that individually checks the code to see if any of >, <, = exist.
I then have to save this as a string with the value of the equality sign.
for i in range(len(user_input)):
if user_input[i].isdigit() == True: #if user_input[i] is a num
self.user_num.append(user_input[i]) #Keep track of just number from input in list
else: #if user_input[i] is not a num
if user_input[i] == ">":
self.track_op=">"
elif user_input[i] == "<":
self.track_op="<"
elif user_input[i] == "=":
self.track_op="="
Which I then use in another switch statement to manually check the difference.
dif=self.roll-self.user_num
abs_dif=abs(dif)
if self.track_op == ">":
if dif > 0:
win=True
else:
win=False
elif self.track_op == "<":
if dif < 0:
win=True
else:
win=False
elif self.track_op == "=":
if dif == 0:
win=True
else:
win=False
I would much rather save the [in]equality sign as a dictionary that uses a similar concept to this:
import operator
ops = { "+": operator.add, "-": operator.sub }
I'm sure that there must be an quicker way to do this similar to the code above. I'm just not sure how to do it.
Thank you so much for the help! :)
You rarely need to use Boolean literals. Your switch first reduces to
if self.track_op == ">":
win = dif > 0
elif self.track_op == "<":
win = dif < 0
elif self.track_op == "=":
win = dif == 0
which should make it obvious you can abstract out the comparison operators.
comp_ops = {">": operator.gt, "<": operator.lt, "=": operator.eq}
if self.track_op in comp_ops:
win = comp_ops[self.trac_op](dif, 0)
Is there a reason for avoiding the builtin eval() function? If not you could just do something like this in your checker class
import random
roll=random.randint(1,6)+random.randint(1,6)
print(roll)
test_in = input("please enter your statement")
try:
test_out = eval(f"{test_in}roll")
print(test_out)
except:
print('Invalid Entry')
Results
10
please enter your statement>? 4>
False
And for a true statement
3
please enter your statement4>
True
Edit: I should add that eval() could be dangerous as it can execute arbitrary python commands. It doesn't seem like an issue in your case but I'd feel remiss if I didn't add an addendum

Difficulties with my python tic-tac-toe

I am following Charles Dierbach's book, Introduction to Computer Science using Python.
I am on chapter 5. I am trying to do this exercise on tic-tac-toe automate play.
I am having difficulties creating a function for the pc to select an empty box ([]).
Here is my code
import re
import random
def template():
mylst = list()
for i in range(0, 3):
my_temp = []
for j in range(0, 3):
my_temp.append([])
mylst.append(my_temp)
return mylst
def template_2(alst):
print()
al = ("A", "B", "C")
for a in al:
if a == "A":
print (format(a, ">6"), end="")
if a == "B":
print (format(a, ">5"), end="")
if a == "C":
print (format(a, ">5"), end="")
print()
for j in range(len(alst)):
print(str(j + 1), format( " ", ">1"), end="")
print(alst[j])
print()
def print_template(alst):
print()
al = ("A", "B", "C")
for a in al:
if a == "A":
print (format(a, ">6"), end="")
if a == "B":
print (format(a, ">4"), end="")
if a == "C":
print (format(a, ">3"), end="")
print()
for j in range(len(alst)):
print(str(j + 1), format( " ", ">1"), end="")
print(alst[j])
print()
def first_player(lst):
print()
print ("Your symbol is 'X'. ")
alpha = ("A", "B", "C")
#check it was entered correctly
check = True
temp_lst1 = []
while check:
correct_entry = False
while not correct_entry:
coord = input("Please enter your coordinates ")
player_regex = re.compile(r'(\w)(\d)')
aSearch = player_regex.search(coord)
if aSearch == None:
correct_entry = False
if aSearch.group(1) != "A" or aSearch.group(1) != "B" or aSearch.group(1) != "C" or aSearch.group(2) != 1 or aSearch.group(2) == 2 or aSearch.group(3) != 3:
correct_entry = False
if aSearch.group(1) == "A" or aSearch.group(1) == "B" or aSearch.group(1) == "C" or aSearch.group(2) == 1 or aSearch.group(2) == 2 or aSearch.group(3) == 3:
correct_entry = True
else:
correct_entry = True
blank = False
while not blank:
if lst[(int(coord[-1])) - 1][alpha.index(coord[0])] == []:
lst[(int(coord[-1])) - 1][alpha.index(coord[0])] = "X"
temp_lst1.append((int(coord[-1])-1))
temp_lst1.append((alpha.index(coord[0])))
blank = True
else:
blank = True
correct_entry = False
if blank == True and correct_entry == True:
check = False
return True
def pc_player(lst):
print()
print ("PC symbol is 'O'. ")
alpha = ("A", "B", "C")
num_list = (0, 1, 2)
for i in range(0, len(lst)):
for j in range(0, len(lst[i])):
if lst[i][j] ==[]:
lst[i][j] = "O"
break
break
return True
def check_1st_player(lst):
if lst[0][0] == "X" and lst[0][1] == "X" and lst[0][2] == "X":
return True
elif lst[1][0] == "X" and lst[1][1] == "X" and lst[1][2] == "X":
return True
elif lst[2][0] == "X" and lst[2][1] == "X" and lst[2][2] == "X":
return True
elif lst[0][0] == "X" and lst[1][0] == "X" and lst[2][0] == "X":
return True
elif lst[0][1] == "X" and lst[1][1] == "X" and lst[2][1] == "X":
return True
elif lst[0][2] == "X" and lst[1][2] == "X" and lst[2][2] == "X":
return True
elif lst[0][0] == "X" and lst[1][1] == "X" and lst[2][2] == "X":
return True
elif lst[2][0] == "X" and lst[1][1] == "X" and lst[0][2] == "X":
return True
else:
return False
def check_pc_player(lst):
if lst[0][0] == "O" and lst[0][1] == "O" and lst[0][2] == "O":
return True
elif lst[1][0] == "O" and lst[1][1] == "O" and lst[1][2] == "O":
return True
elif lst[2][0] == "O" and lst[2][1] == "O" and lst[2][2] == "O":
return True
elif lst[0][0] == "O" and lst[1][0] == "O" and lst[2][0] == "O":
return True
elif lst[0][1] == "O" and lst[1][1] == "O" and lst[2][1] == "O":
return True
elif lst[0][2] == "O" and lst[1][2] == "O" and lst[2][2] == "O":
return True
elif lst[0][0] == "O" and lst[1][1] == "O" and lst[2][2] == "O":
return True
elif lst[2][0] == "O" and lst[1][1] == "O" and lst[0][2] == "O":
return True
else:
return False
def play_game():
ask = input("Do you want to play a two player game of Tic-Tac-Toe game? (y/n) ")
if ask in yes_response:
# contruct the template for tic-tac-toe
print()
print("How many rounds do you want to play? " )
print("Please enter only odd integers" )
print("Please enter your coordinates", end="")
print(" using format A1 or B2")
print("New Round")
return True
def play_again():
tell_me = input("Do you want you play a game ? (y/n)")
if tell_me == "Y" or "y":
return True
else:
return False
def is_full(lst):
count = 0
for i in lst:
for j in i:
if j != []:
count += 1
if count == 9:
return True
#
#-- main
print("Welcome to Awesome 2 Player Tic-Tac-Toe Game? ")
print()
answer = False
yes_response =("Y", "y")
no_response = ("N", "n")
while not answer:
print("Enter an even integer to exit")
ask = int(input("How many matches do you want to play? (odd integers only)? " ))
game = play_game()
structure = template()
print_template(structure)
if ask % 2 == 1:
score_player1 = 0
score_pc = 0
count = 0
while count < ask:
pc_lst = []
if count >= 1:
structure = template()
print_template(structure)
while game:
check_pc = True
while check_pc:
pc_player(structure)
template_2(structure)
check_pc = False
check_pc_winner = True
while check_pc_winner:
game_pc = check_pc_player(structure)
check_pc_winner = False
if game_pc == True:
print("Congratulations PC won")
score_pc += 1
game = False
break
check_player1 = True
while check_player1:
first_player(structure)
template_2(structure)
check_player1 = False
check_first_winner = True
while check_first_winner:
game_first = check_1st_player(structure)
check_first_winner = False
if game_first == True:
print("Congratulations Player 1 won")
score_player1 += 1
game = False
break
board_full = False
while not board_full:
check_board = is_full(structure)
board_full = True
if check_board == True:
print("This round was a tie.")
game = False
print("Player 1 : ", score_player1, " PC : ", score_pc)
count += 1
game = True
if score_player1 > score_pc:
print("Player 1 won")
elif score_player1 < score_pc:
print("PC won")
if play_again() == False:
answer = True
else:
answer = False
The problem I have is at def pc_player():
I would like to know how to loop the list and sublists so that AI can select an empty box as its choice to place an "O"
My current for loop does not work. AI only selects the first box.
My current for loop does not work. AI only selects the first box.
I suppose you refer to this part:
def pc_player(lst):
print()
print ("PC symbol is 'O'. ")
alpha = ("A", "B", "C")
num_list = (0, 1, 2)
for i in range(0, len(lst)):
for j in range(0, len(lst[i])):
if lst[i][j] ==[]:
lst[i][j] = "O"
break
break
return True
The break instructions together with the way you initialize the for loops will only attempt to set lst[0][0]. Other cells are not considered.
To make an evenly distributed random choice, it is essential to gather the possibilities first. For this, it is convenient to have all cells in a plain list first:
from itertools import chain
all_cells = list(chain.from_iterable(lst))
Then, you can filter out non-empty cells:
empty_cells = filter(lambda l: len(l) == 0, all_cells)
# empty_cells = filter(lambda l: not l, all_cells)
# empty_cells = [cell for cell in all_cells if not cell]
Based on this you can now trigger your random selection and symbol placement:
import random
cell_to_place = random.choice(empty_cells)
cell_to_place.append('O')
If you need the index of the cell being modified, you can do the following:
import itertools
indices = list(itertools.product(range(3), range(3)))
indexed_cells = zip(indices, map(lambda (i, j): lst[i][j], indices))
indexed_cells = filter(lambda (_, l): not l, indexed_cells) # filter non-empty
(i,j), cell_to_place = random.choice(indexed_cells)
# ...
These code samples do not take into account that there could be no empty cell left. Also, your code has some general design issues. For example:
Why do you use lists as cell items in the first place? You could simply use None, 'X' and 'O' as the elements of the 2-dimensional list.
check_pc_player and check_1st_player can be easily generalized by making the symbol to check for a parameter of the function.
Why is this a while-loop?
while check_first_winner:
game_first = check_1st_player(structure)
check_first_winner = False
Start by finding all empty boxes:
empty= [(i,j) for i in range(len(lst)) for j in range(len(lst[i])) if lst[i][j]==[]]
Then choose a random one:
import random
chosen_i, chosen_j= random.choice(empty)
And finally put an O there:
lst[chosen_i][chosen_j]= 'O'

Categories

Resources