python hangman solver

Oct 08 2020

Napisałem program, który czyta plik csv zawierający 100 wierszy, które wyglądają następująco:

1;S****L;SCHOOL
2;*A*G*A*;HANGMAN

następnie spróbuj odgadnąć litery jak w grze w kata. Moim celem jest policzenie wszystkich dobrych i złych liter, a następnie podsumowanie ich. Kod działa dobrze, mam około 1670 dobrze + złe próby odgadnięcia liter. Moje podejście polegało na stworzeniu słownika, w którym przechowuję wszystkie litery z alfabetu i czytam wszystkie słowa z pliku, a następnie sumuję każdy wygląd litery i przechowuję je w słowniku. Coś jak

{
   "A" : 30,
   "B" : 40
}

Następnie sortuję dyktando na podstawie każdego wystąpienia litery i najpierw staram się odgadnąć, która litera ma największy wyraz.

Moje pytanie. Czy mogę coś poprawić, aby uzyskać mniejszą liczbę prób?

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()

Odpowiedzi

5 hjpotter92 Oct 08 2020 at 04:07

Witamy w przeglądzie kodu!

PEP-8

W Pythonie powszechne (i zalecane) jest przestrzeganie przewodnika stylistycznego PEP-8 dotyczącego pisania czystego, łatwego w utrzymaniu i spójnego kodu.

Funkcje i zmienne powinny być nazywane w a lower_snake_case, klasy jako UpperCamelCase, a stałe jako UPPER_SNAKE_CASE.

Wpisz podpowiedź

W nowszych wersjach języka Python można skorzystać z podpowiedzi typu, aby uzyskać krótki przegląd typów zmiennych i parametrów funkcji.

Liczenie liter

Python zapewnia wbudowany plik collections.Counter.

Komentarze

Komentarze tutaj nie pomagają. Preferuj także pisanie docstringów zamiast komentarzy dla funkcji.

Nazwy zmiennych

Otwierasz plik i nazywasz jego wskaźnik jako words, podczas gdy funkcja zwraca listę słów; wywoływana reader, która z kolei jest przechowywana w zmiennej o nazwie words?

Dziwne konwersje

Generujesz mapowanie liter do ich odpowiednich liczb, jako słownik (hash-map / table / lookup), a następnie konwertujesz je na listę krotek o dwóch wartościach, sortujesz to i konwertujesz z powrotem do słownika. Czemu? dictma \$ O(1) \$ wyszukiwanie i sortowanie nie ma sensu w Twoim przypadku.

Iteracja z indeksem

Używasz następującej struktury pętli:

for i in range(len(words)):

gdzie isamo w sobie nie służy żadnemu celowi. Każde użycie ima postać words[i]. Możesz po prostu iterować po wartościach wordssamej listy:

for word in words: