I wrote a program that read a csv file that contain 100 rows that look like:
1;S****L;SCHOOL
2;*A*G*A*;HANGMAN
then try to guess the letters like in a hangman game. My scope is to count every right and wrong letters and then sum them up. The code works fine, I get around 1670 right + wrong attempts to guess the letters. My approach was to create a dictionary in which I store all the letters from the alphabet and read every words from the file then sum every appearance of a letter and store them in the dictionary. Somethin like
{
"A" : 30,
"B" : 40
}
Then I sort the dict based on every letter occurrence and first try to guess the letter with the most apparace.
My question. Is something that I can improve in order to get a smaller number of attempts?
import csv
INPUT_FILE = "words.csv"
def oppenFile(): # function to read the file
with open(INPUT_FILE, "r", encoding="utf-8") as words:
reader = list(csv.reader(words, delimiter=";"))
return reader
def letterCount(): # function that count every the letter in the file and return a dict: {A : 2}
letters = dict.fromkeys("QWERTYUIOPĂÎASDFGHJKLȘȚÂZXCVBNM", 0)
words = oppenFile()
for w in range(len(words)):
for l in list(words[w][2]):
if l not in list(words[w][1]):
letters[l] += 1
return letters
def checkLetters(word, wholeWord, letters): # function that solve a word return the number of right + wrong attempts
attempts = 0
for letter, key in letters.items():
if letter in wholeWord and letter not in word:
attempts += 1
index = [i for i, lit in enumerate(wholeWord) if lit == letter]
letters[letter] -= len(index)
for j in range(len(index)):
word = word[:index[j]] + letter + word[(index[j] + 1):]
elif '*' not in word:
break
else:
attempts += 1
return attempts
def hangman():
words = oppenFile()
numberOfAttempts = 0
letters = letterCount()
for i in range(len(words)):
letters = dict(sorted(letters.items(), key=lambda x: x[1], reverse=True)) # sort the dict
numberOfAttempts += checkLetters(words[i][1], words[i][2], letters)
print(f"{numberOfAttempts} right + wrong attempts")
if __name__ == "__main__":
hangman()
1 Answer 1
Welcome to Code Review!
PEP-8
In python, it is common (and recommended) to follow the PEP-8 style guide for writing clean, maintainable and consistent code.
Functions and variables should be named in a lower_snake_case
, classes as UpperCamelCase
, and constants as UPPER_SNAKE_CASE
.
Type hinting
With newer python versions, you can make use of type hinting to give a brief overview of the type of variables and function parameters.
Counting letters
Python provides an inbuilt collections.Counter
for you to make use of.
Comments
The comments don't really help here. Also, prefer writing docstring over comments for functions.
Variable names
You open a file, and name its pointer as words
, whereas the function is returning a list of words; called reader
, which in turn is stored in a variable called words
?
Weird conversions
You generate a mapping of letters to their respective counts, as a dictionary (hash-map/table/lookup), then convert it to list of 2-valued tuple, sort that, and convert back to dictionary. Why? dict
has \$ O(1) \$ lookup and sorting makes no sense in your case.
Iteration with index
You use the following loop structure:
for i in range(len(words)):
where, i
in itself is serving no purpose. Every occurrence of usage of i
is of the form words[i]
. You can just iterate over the values of words
list itself:
for word in words: