5
\$\begingroup\$

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()
\$\endgroup\$
5
\$\begingroup\$

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:
\$\endgroup\$

This site is temporarily in read only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .