Initial commit

This commit is contained in:
2022-05-24 12:19:51 +02:00
commit f475b78da6
6 changed files with 332 additions and 0 deletions

160
.gitignore vendored Normal file
View File

@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

10
exceptions.py Normal file
View File

@ -0,0 +1,10 @@
class WordleGameOver(Exception):
...
class WordleInvalidGuess(Exception):
...
class WordleUnknownWord(Exception):
...

12
util.py Normal file
View File

@ -0,0 +1,12 @@
from wordle import CORRECT, IN_WORD, NOT_IN_WORD
def green(string):
return f"\033[42;30m{string}\033[0m"
def yellow(string):
return f"\033[43;30m{string}\033[0m"
def grey(string):
return f"\033[100;30m{string}\033[0m"
empty_guess = (" ", [NOT_IN_WORD for i in range(5)])

75
wordle-cli.py Normal file
View File

@ -0,0 +1,75 @@
from exceptions import WordleInvalidGuess, WordleUnknownWord
from wordle import Wordle
from wordle import CORRECT, IN_WORD, NOT_IN_WORD
from util import green, yellow, grey, empty_guess
def print_guess(guess, result):
string = ""
guess = guess.upper()
for c, r in zip(guess, result):
if r == CORRECT:
string += green(f" {c} ") + " "
elif r == IN_WORD:
string += yellow(f" {c} ") + " "
elif r == NOT_IN_WORD:
string += grey(f" {c} ") + " "
print(string, end="")
def print_character_state(game, characters):
string = ""
states = game.get_characters()
for c in characters:
if states[c] == CORRECT:
string += green(f" {c} ") + " "
elif states[c] == IN_WORD:
string += yellow(f" {c} ") + " "
elif states[c] == NOT_IN_WORD:
string += grey(f" {c} ") + " "
elif states[c] == None:
string += f" {c} "
print(string, end="")
def print_state(game):
guesses = game.guesses + [empty_guess for j in range(game.max_guesses - len(game.guesses)) ]
# keyboard layout
keyboard = ("qwertzuiop", "asdfghjkl", "yxcvbnm")
# guesses
for index, g in enumerate(guesses):
guess, result = g
print_guess(guess, result)
# print keyboard
print(" ", end="")
if index < 3:
print_character_state(game, keyboard[index])
print()
if __name__ == "__main__":
game = Wordle()
print("Game has started:")
while not game.has_ended():
print_state(game)
while True:
guess = input("Please enter your guess: ")
try:
result = game.guess(guess)
break
except WordleInvalidGuess:
print("Invalid guess.", end=" ")
except WordleUnknownWord:
print("Unknown word.", end=" ")
print_state(game)
if game.has_won():
print("You win!")
else:
print(f"You lost. The word was {game._word.upper()} ...")

73
wordle.py Normal file
View File

@ -0,0 +1,73 @@
import random
from exceptions import WordleGameOver, WordleInvalidGuess, WordleUnknownWord
CORRECT = 0
IN_WORD = 1
NOT_IN_WORD = 2
with open("words.txt", "r") as words_file:
words = words_file.readline().strip().split(",")
guesses = words_file.readline().strip().split(",")
class Wordle:
def __init__(self, max_guesses = 6):
self.max_guesses = max_guesses
self.guesses = []
self._word = random.choice(words).lower()
self._ended = False
self._won = False
def has_ended(self):
return self._ended
def has_won(self):
return self._won
def get_characters(self):
characters = { c : None for c in "abcdefghijklmnopqrstuvwxyz"}
for guess, result in self.guesses:
for c, r in zip(guess, result):
characters[c] = r
return characters
def guess(self, word):
# Check if guess is valid
if len(word) != 5:
raise WordleInvalidGuess("Guess must have length 5")
word = word.lower()
if word not in words and word not in guesses:
raise WordleUnknownWord(f"Unknown word '{word}'")
if self.has_ended():
raise WordleGameOver("Game is already over.")
result = []
correct = True
for index, c in enumerate(word):
if c not in self._word:
result.append(NOT_IN_WORD)
correct = False
elif word[index] == self._word[index]:
result.append(CORRECT)
correct = correct and True
else:
result.append(IN_WORD)
correct = False
self.guesses.append((word, result))
if correct or len(self.guesses) == self.max_guesses:
self._ended = True
self._won = correct
return result
def reset(self):
self.guesses = []
self._ended = False
self._won = False
def reroll(self):
self._word = random.choice(words)
self.reset()

2
words.txt Normal file

File diff suppressed because one or more lines are too long