Snapshot permission updates.
This commit is contained in:
1 parent
414380740f
commit
d570b16b60
15 files changed
+540
-502
No files matched your search
+3
-3
@@ -1,3 +1,3 @@
|
||||
*.pyc
|
||||
.venv
|
||||
__pycache__
|
||||
*.pyc
|
||||
.venv
|
||||
__pycache__
|
||||
+24
-24
@@ -1,24 +1,24 @@
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
This is free and unencumbered software released into the public domain.
|
||||
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
distribute this software, either in source code form or as a compiled
|
||||
binary, for any purpose, commercial or non-commercial, and by any
|
||||
means.
|
||||
|
||||
In jurisdictions that recognize copyright laws, the author or authors
|
||||
of this software dedicate any and all copyright interest in the
|
||||
software to the public domain. We make this dedication for the benefit
|
||||
of the public at large and to the detriment of our heirs and
|
||||
successors. We intend this dedication to be an overt act of
|
||||
relinquishment in perpetuity of all present and future rights to this
|
||||
software under copyright law.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
For more information, please refer to <http://unlicense.org>
|
||||
+68
-68
@@ -1,68 +1,68 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import dictionary
|
||||
from game import LetterResult
|
||||
|
||||
|
||||
class Constraints:
|
||||
def __init__(self):
|
||||
# Array of known letters in result with None for unknown.
|
||||
self.correct = [None] * dictionary.WORDLE_LENGTH
|
||||
# Array with per-letter sets of known bad letters.
|
||||
self.incorrect = [set() for _ in range(dictionary.WORDLE_LENGTH)]
|
||||
# Dict of letter -> int with minimum required count of letter in word.
|
||||
self.count = defaultdict(int)
|
||||
# If letter is present in set, value in min is both min and max.
|
||||
self.exact = set()
|
||||
|
||||
# List of LetterResult values.
|
||||
def update_graded(self, guess, grade):
|
||||
guess = guess.lower()
|
||||
|
||||
new_count = defaultdict(int)
|
||||
|
||||
for i, letter in enumerate(guess):
|
||||
match grade[i]:
|
||||
case LetterResult.CORRECT:
|
||||
self.correct[i] = letter
|
||||
new_count[letter] += 1
|
||||
case LetterResult.MOVE:
|
||||
self.incorrect[i].add(letter)
|
||||
new_count[letter] += 1
|
||||
case LetterResult.INCORRECT:
|
||||
self.incorrect[i].add(letter)
|
||||
self.exact.add(letter)
|
||||
new_count[letter] += 0 # Ensure letter is in dict
|
||||
|
||||
for letter, c in new_count.items():
|
||||
self.count[letter] = max(c, self.count[letter])
|
||||
|
||||
def matches(self, guess):
|
||||
counts = defaultdict(int)
|
||||
|
||||
# All known correct letters in place.
|
||||
for i, letter in enumerate(guess):
|
||||
# If we have a known letter, and don't match...
|
||||
if self.correct[i] and self.correct[i] != letter:
|
||||
return False
|
||||
|
||||
# If we have a letter that's known to be incorrect in the current location...
|
||||
if letter in self.incorrect[i]:
|
||||
return False
|
||||
|
||||
counts[letter] += 1
|
||||
|
||||
for letter, c in self.count.items():
|
||||
if letter in self.exact:
|
||||
if counts[letter] != c:
|
||||
return False
|
||||
else:
|
||||
if counts[letter] < c:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def filter_words(self, words=dictionary.words()):
|
||||
return set(filter(lambda w: self.matches(w), words))
|
||||
#!/usr/bin/python
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
import dictionary
|
||||
from game import LetterResult
|
||||
|
||||
|
||||
class Constraints:
|
||||
def __init__(self):
|
||||
# Array of known letters in result with None for unknown.
|
||||
self.correct = [None] * dictionary.WORDLE_LENGTH
|
||||
# Array with per-letter sets of known bad letters.
|
||||
self.incorrect = [set() for _ in range(dictionary.WORDLE_LENGTH)]
|
||||
# Dict of letter -> int with minimum required count of letter in word.
|
||||
self.count = defaultdict(int)
|
||||
# If letter is present in set, value in min is both min and max.
|
||||
self.exact = set()
|
||||
|
||||
# List of LetterResult values.
|
||||
def update_graded(self, guess, grade):
|
||||
guess = guess.lower()
|
||||
|
||||
new_count = defaultdict(int)
|
||||
|
||||
for i, letter in enumerate(guess):
|
||||
match grade[i]:
|
||||
case LetterResult.CORRECT:
|
||||
self.correct[i] = letter
|
||||
new_count[letter] += 1
|
||||
case LetterResult.MOVE:
|
||||
self.incorrect[i].add(letter)
|
||||
new_count[letter] += 1
|
||||
case LetterResult.INCORRECT:
|
||||
self.incorrect[i].add(letter)
|
||||
self.exact.add(letter)
|
||||
new_count[letter] += 0 # Ensure letter is in dict
|
||||
|
||||
for letter, c in new_count.items():
|
||||
self.count[letter] = max(c, self.count[letter])
|
||||
|
||||
def matches(self, guess):
|
||||
counts = defaultdict(int)
|
||||
|
||||
# All known correct letters in place.
|
||||
for i, letter in enumerate(guess):
|
||||
# If we have a known letter, and don't match...
|
||||
if self.correct[i] and self.correct[i] != letter:
|
||||
return False
|
||||
|
||||
# If we have a letter that's known to be incorrect in the current location...
|
||||
if letter in self.incorrect[i]:
|
||||
return False
|
||||
|
||||
counts[letter] += 1
|
||||
|
||||
for letter, c in self.count.items():
|
||||
if letter in self.exact:
|
||||
if counts[letter] != c:
|
||||
return False
|
||||
else:
|
||||
if counts[letter] < c:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def filter_words(self, words=dictionary.words()):
|
||||
return set(filter(lambda w: self.matches(w), words))
|
||||
@@ -1,64 +1,64 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
import dictionary
|
||||
import game
|
||||
|
||||
|
||||
def display_instructions():
|
||||
"""Print out instuctions before starting play."""
|
||||
|
||||
print(
|
||||
f"""Welcome to Wordle!
|
||||
|
||||
Wordle has a hidden word of five letters, and you get to
|
||||
make up to six guesses to find out what it is.
|
||||
|
||||
After each guess, you get feedback on each letter of your guess.
|
||||
* {game.display_result(game.LetterResult.CORRECT, "Correct!")}
|
||||
* {game.display_result(game.LetterResult.MOVE, "Correct, in a different location.")}
|
||||
* {game.display_result(game.LetterResult.INCORRECT, "Not in the word.")}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def read_valid_guess(guess_number):
|
||||
while True:
|
||||
print(f"Guess {guess_number}: ", end="")
|
||||
guess = input()
|
||||
if guess in dictionary.words():
|
||||
return guess
|
||||
|
||||
print(f"{guess} is not a valid Wordle word. Please try again.")
|
||||
|
||||
|
||||
def display_results(guess, results):
|
||||
print(" ", end="")
|
||||
for i in range(dictionary.WORDLE_LENGTH):
|
||||
print(game.display_result(results[i], guess[i]), end="")
|
||||
print("")
|
||||
|
||||
|
||||
def play_game():
|
||||
display_instructions()
|
||||
|
||||
target = game.select_word()
|
||||
|
||||
# To help with debugging
|
||||
# print(f"The target is: {target}")
|
||||
|
||||
for guess_number in range(1, 6):
|
||||
guess = read_valid_guess(guess_number)
|
||||
results = game.grade_word(target, guess)
|
||||
|
||||
if game.success_result(results):
|
||||
print(f"You won! It took {guess_number} guesses.")
|
||||
return
|
||||
|
||||
display_results(guess, results)
|
||||
|
||||
print(f"Sorry, no guesses remaining. The word was: {target}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
play_game()
|
||||
#!/usr/bin/python
|
||||
|
||||
|
||||
import dictionary
|
||||
import game
|
||||
|
||||
|
||||
def display_instructions():
|
||||
"""Print out instuctions before starting play."""
|
||||
|
||||
print(
|
||||
f"""Welcome to Wordle!
|
||||
|
||||
Wordle has a hidden word of five letters, and you get to
|
||||
make up to six guesses to find out what it is.
|
||||
|
||||
After each guess, you get feedback on each letter of your guess.
|
||||
* {game.display_result(game.LetterResult.CORRECT, "Correct!")}
|
||||
* {game.display_result(game.LetterResult.MOVE, "Correct, in a different location.")}
|
||||
* {game.display_result(game.LetterResult.INCORRECT, "Not in the word.")}
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def read_valid_guess(guess_number):
|
||||
while True:
|
||||
print(f"Guess {guess_number}: ", end="")
|
||||
guess = input()
|
||||
if guess in dictionary.words():
|
||||
return guess
|
||||
|
||||
print(f"{guess} is not a valid Wordle word. Please try again.")
|
||||
|
||||
|
||||
def display_results(guess, results):
|
||||
print(" ", end="")
|
||||
for i in range(dictionary.WORDLE_LENGTH):
|
||||
print(game.display_result(results[i], guess[i]), end="")
|
||||
print("")
|
||||
|
||||
|
||||
def play_game():
|
||||
display_instructions()
|
||||
|
||||
target = game.select_word()
|
||||
|
||||
# To help with debugging
|
||||
# print(f"The target is: {target}")
|
||||
|
||||
for guess_number in range(1, 6):
|
||||
guess = read_valid_guess(guess_number)
|
||||
results = game.grade_word(target, guess)
|
||||
|
||||
if game.success_result(results):
|
||||
print(f"You won! It took {guess_number} guesses.")
|
||||
return
|
||||
|
||||
display_results(guess, results)
|
||||
|
||||
print(f"Sorry, no guesses remaining. The word was: {target}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
play_game()
|
||||
@@ -61,10 +61,29 @@ class SimilaritySolver(object):
|
||||
for word in wordle_dictionary:
|
||||
scored_words[word] = self._score_word(position_matches, word_matches, word)
|
||||
|
||||
result = list(wordle_dictionary)
|
||||
result.sort(key=lambda word: scored_words[word], reverse=True)
|
||||
# Return as list of (word, score) sorted by high-score, word.
|
||||
result = sorted(scored_words.items(), key=lambda kv: kv[0])
|
||||
result = sorted(result, key=lambda kv: kv[1], reverse=True)
|
||||
return result
|
||||
|
||||
return [(word, scored_words[word]) for word in result]
|
||||
|
||||
class LimitsSolver(object):
|
||||
def scored_words(self, words=dictionary.words()):
|
||||
# word: score
|
||||
scored_words = dict()
|
||||
|
||||
for word in words:
|
||||
reduced = const.filter_words(words)
|
||||
|
||||
# Our score is how many words did we remove from consideration.
|
||||
score = len(words) - len(reduced)
|
||||
|
||||
scored_words[word] = score
|
||||
|
||||
# Return as list of (word, score) sorted by high-score, word.
|
||||
result = sorted(scored_words.items(), key=lambda kv: kv[0])
|
||||
result = sorted(result, key=lambda kv: kv[1], reverse=True)
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
+26
-26
@@ -1,27 +1,27 @@
|
||||
.navbar {
|
||||
background-color: lightslategray;
|
||||
font-size: 1em;
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||
color: white;
|
||||
padding: 8px 5px 8px 5px;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
font-variant: small-caps;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.body-content {
|
||||
padding: 5px;
|
||||
font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
.navbar {
|
||||
background-color: lightslategray;
|
||||
font-size: 1em;
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||
color: white;
|
||||
padding: 8px 5px 8px 5px;
|
||||
}
|
||||
|
||||
.navbar a {
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.navbar-item {
|
||||
font-variant: small-caps;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.body-content {
|
||||
padding: 5px;
|
||||
font-family:'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
+23
-23
@@ -1,23 +1,23 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
Dictionary
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if page > 0 %}<a href="{{ url_for('dictionary', page=page-1) }}">Prev</a>{% endif %}
|
||||
|
||||
Page {{ page }} / {{ max_pages }}
|
||||
|
||||
{% if page < max_pages %}<a href="{{ url_for('dictionary', page=page+1) }}">Next</a>{% endif %}
|
||||
|
||||
|
||||
<ul>
|
||||
{% for word in words %}
|
||||
<li>{{ word }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
Dictionary
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if page > 0 %}<a href="{{ url_for('dictionary', page=page-1) }}">Prev</a>{% endif %}
|
||||
|
||||
Page {{ page }} / {{ max_pages }}
|
||||
|
||||
{% if page < max_pages %}<a href="{{ url_for('dictionary', page=page+1) }}">Next</a>{% endif %}
|
||||
|
||||
|
||||
<ul>
|
||||
{% for word in words %}
|
||||
<li>{{ word }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
+26
-26
@@ -1,27 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='site.css')}}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<a href="{{ url_for('solver') }}" class="navbar-item">Home</a>
|
||||
<a href="{{ url_for('dictionary') }}" class="navbar-item">Dictionary</a>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
<hr />
|
||||
<footer>
|
||||
This is not associated with the New York Times or the offical version of
|
||||
Wordle in any way.
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='site.css')}}" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="navbar">
|
||||
<a href="{{ url_for('solver') }}" class="navbar-item">Home</a>
|
||||
<a href="{{ url_for('dictionary') }}" class="navbar-item">Dictionary</a>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
<hr />
|
||||
<footer>
|
||||
This is not associated with the New York Times or the offical version of
|
||||
Wordle in any way.
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+29
-29
@@ -1,30 +1,30 @@
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
Solver!
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<ul>
|
||||
{% for guess in guesses %}
|
||||
<li>{{ guess }}
|
||||
|
||||
{% for i in range(5) %}
|
||||
<select name="g{{i}}" id="g{{i}}">
|
||||
<option value="U">Unknown</option>
|
||||
<option value="I">Incorrect</option>
|
||||
<option value="M">Move</option>
|
||||
<option value="C">Correct</option>
|
||||
</select>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
||||
{%if solution %}
|
||||
The proposed solution is <b>{{ solution }}</b>.
|
||||
{% else %}
|
||||
No solution found.
|
||||
{% endif %}
|
||||
{% extends "layout.html" %}
|
||||
|
||||
{% block title %}
|
||||
Solver!
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<ul>
|
||||
{% for guess in guesses %}
|
||||
<li>{{ guess }}
|
||||
|
||||
{% for i in range(5) %}
|
||||
<select name="g{{i}}" id="g{{i}}">
|
||||
<option value="U">Unknown</option>
|
||||
<option value="I">Incorrect</option>
|
||||
<option value="M">Move</option>
|
||||
<option value="C">Correct</option>
|
||||
</select>
|
||||
{% endfor %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
|
||||
{%if solution %}
|
||||
The proposed solution is <b>{{ solution }}</b>.
|
||||
{% else %}
|
||||
No solution found.
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
+81
-81
@@ -1,81 +1,81 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import constraints
|
||||
from game import LetterResult
|
||||
|
||||
|
||||
class TestConstraints(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
consts = constraints.Constraints()
|
||||
self.assertTrue(consts.matches("abcde"))
|
||||
self.assertTrue(consts.matches("bcdef"))
|
||||
|
||||
def test_correct(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"abcde",
|
||||
[
|
||||
LetterResult.CORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("amnop"))
|
||||
self.assertTrue(consts.matches("aaaaa"))
|
||||
|
||||
self.assertFalse(consts.matches("abcde"))
|
||||
self.assertFalse(consts.matches("lmnop"))
|
||||
self.assertFalse(consts.matches("aedcb"))
|
||||
self.assertFalse(consts.matches("amnob"))
|
||||
|
||||
def test_correct_count_limit(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"aazzz",
|
||||
[
|
||||
LetterResult.CORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("abcde"))
|
||||
self.assertTrue(consts.matches("abbbb"))
|
||||
|
||||
self.assertFalse(consts.matches("aabbb"))
|
||||
self.assertFalse(consts.matches("abbba"))
|
||||
self.assertFalse(consts.matches("bbbbb"))
|
||||
self.assertFalse(consts.matches("bbbba"))
|
||||
self.assertFalse(consts.matches("babbb"))
|
||||
|
||||
def test_move(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"abcde",
|
||||
[
|
||||
LetterResult.MOVE,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("zzzza"))
|
||||
self.assertTrue(consts.matches("zzzaa"))
|
||||
self.assertTrue(consts.matches("zaaaa"))
|
||||
|
||||
self.assertFalse(consts.matches("azzzz"))
|
||||
self.assertFalse(consts.matches("zzzzz"))
|
||||
self.assertFalse(consts.matches("zzzba"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import constraints
|
||||
from game import LetterResult
|
||||
|
||||
|
||||
class TestConstraints(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
consts = constraints.Constraints()
|
||||
self.assertTrue(consts.matches("abcde"))
|
||||
self.assertTrue(consts.matches("bcdef"))
|
||||
|
||||
def test_correct(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"abcde",
|
||||
[
|
||||
LetterResult.CORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("amnop"))
|
||||
self.assertTrue(consts.matches("aaaaa"))
|
||||
|
||||
self.assertFalse(consts.matches("abcde"))
|
||||
self.assertFalse(consts.matches("lmnop"))
|
||||
self.assertFalse(consts.matches("aedcb"))
|
||||
self.assertFalse(consts.matches("amnob"))
|
||||
|
||||
def test_correct_count_limit(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"aazzz",
|
||||
[
|
||||
LetterResult.CORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("abcde"))
|
||||
self.assertTrue(consts.matches("abbbb"))
|
||||
|
||||
self.assertFalse(consts.matches("aabbb"))
|
||||
self.assertFalse(consts.matches("abbba"))
|
||||
self.assertFalse(consts.matches("bbbbb"))
|
||||
self.assertFalse(consts.matches("bbbba"))
|
||||
self.assertFalse(consts.matches("babbb"))
|
||||
|
||||
def test_move(self):
|
||||
consts = constraints.Constraints()
|
||||
consts.update_graded(
|
||||
"abcde",
|
||||
[
|
||||
LetterResult.MOVE,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
LetterResult.INCORRECT,
|
||||
],
|
||||
)
|
||||
|
||||
self.assertTrue(consts.matches("zzzza"))
|
||||
self.assertTrue(consts.matches("zzzaa"))
|
||||
self.assertTrue(consts.matches("zaaaa"))
|
||||
|
||||
self.assertFalse(consts.matches("azzzz"))
|
||||
self.assertFalse(consts.matches("zzzzz"))
|
||||
self.assertFalse(consts.matches("zzzba"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+34
-34
@@ -1,34 +1,34 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import dictionary
|
||||
|
||||
|
||||
class TestDictionary(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
"""Verify we can get the default words."""
|
||||
words = dictionary.words()
|
||||
|
||||
def test_expected(self):
|
||||
"""Verify we have a few expected words."""
|
||||
words = dictionary.words()
|
||||
self.assertIn("cares", words)
|
||||
self.assertIn("fudge", words)
|
||||
|
||||
def test_unexpected(self):
|
||||
"""Verify we have a few expected words."""
|
||||
words = dictionary.words()
|
||||
self.assertNotIn("doray", words)
|
||||
self.assertNotIn("xxxxx", words)
|
||||
|
||||
def test_size(self):
|
||||
"""Verify all words are the expected length."""
|
||||
words = dictionary.words()
|
||||
|
||||
for word in words:
|
||||
self.assertEqual(len(word), dictionary.WORDLE_LENGTH)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import dictionary
|
||||
|
||||
|
||||
class TestDictionary(unittest.TestCase):
|
||||
def test_empty(self):
|
||||
"""Verify we can get the default words."""
|
||||
words = dictionary.words()
|
||||
|
||||
def test_expected(self):
|
||||
"""Verify we have a few expected words."""
|
||||
words = dictionary.words()
|
||||
self.assertIn("cares", words)
|
||||
self.assertIn("fudge", words)
|
||||
|
||||
def test_unexpected(self):
|
||||
"""Verify we have a few expected words."""
|
||||
words = dictionary.words()
|
||||
self.assertNotIn("doray", words)
|
||||
self.assertNotIn("xxxxx", words)
|
||||
|
||||
def test_size(self):
|
||||
"""Verify all words are the expected length."""
|
||||
words = dictionary.words()
|
||||
|
||||
for word in words:
|
||||
self.assertEqual(len(word), dictionary.WORDLE_LENGTH)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+79
-79
@@ -1,79 +1,79 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import dictionary
|
||||
import game
|
||||
|
||||
|
||||
class TestGame(unittest.TestCase):
|
||||
test_words = (
|
||||
"aaaaa",
|
||||
"aabbb",
|
||||
"aaccc",
|
||||
"bbbaa",
|
||||
"bbbbb",
|
||||
"ccaaa",
|
||||
"cccaa",
|
||||
"ccccc",
|
||||
"abcde",
|
||||
)
|
||||
|
||||
def test_select_word(self):
|
||||
word = game.select_word(self.test_words)
|
||||
|
||||
self.assertIn(word, self.test_words)
|
||||
|
||||
word = game.select_word()
|
||||
|
||||
self.assertIn(word, dictionary.words())
|
||||
|
||||
def test_grade_word_correct(self):
|
||||
target = "aaaaa"
|
||||
guess = "aaaaa"
|
||||
|
||||
result = game.grade_word(target, guess, self.test_words)
|
||||
|
||||
expected = [
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
]
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
self.assertTrue(game.success_result(result))
|
||||
|
||||
def test_grade_word_mixed(self):
|
||||
C = game.LetterResult.CORRECT
|
||||
M = game.LetterResult.MOVE
|
||||
I = game.LetterResult.INCORRECT
|
||||
|
||||
test_cases = (
|
||||
("aabbb", "aabbb", [C, C, C, C, C]),
|
||||
("aabbb", "aaccc", [C, C, I, I, I]),
|
||||
("bbbaa", "cccaa", [I, I, I, C, C]),
|
||||
("aabbb", "cccaa", [I, I, I, M, M]),
|
||||
("aabbb", "bbbaa", [M, M, C, M, M]),
|
||||
("aabbb", "ccaaa", [I, I, M, M, I]),
|
||||
("aabbb", "abcde", [C, M, I, I, I]),
|
||||
("aabbb", "ccccc", [I, I, I, I, I]),
|
||||
)
|
||||
|
||||
for target, guess, expected in test_cases:
|
||||
result = game.grade_word(target, guess, self.test_words)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_grade_word_invalid(self):
|
||||
target = "aaaaa"
|
||||
guess = "inval"
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
game.grade_word(target, guess, self.test_words)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import dictionary
|
||||
import game
|
||||
|
||||
|
||||
class TestGame(unittest.TestCase):
|
||||
test_words = (
|
||||
"aaaaa",
|
||||
"aabbb",
|
||||
"aaccc",
|
||||
"bbbaa",
|
||||
"bbbbb",
|
||||
"ccaaa",
|
||||
"cccaa",
|
||||
"ccccc",
|
||||
"abcde",
|
||||
)
|
||||
|
||||
def test_select_word(self):
|
||||
word = game.select_word(self.test_words)
|
||||
|
||||
self.assertIn(word, self.test_words)
|
||||
|
||||
word = game.select_word()
|
||||
|
||||
self.assertIn(word, dictionary.words())
|
||||
|
||||
def test_grade_word_correct(self):
|
||||
target = "aaaaa"
|
||||
guess = "aaaaa"
|
||||
|
||||
result = game.grade_word(target, guess, self.test_words)
|
||||
|
||||
expected = [
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
game.LetterResult.CORRECT,
|
||||
]
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
self.assertTrue(game.success_result(result))
|
||||
|
||||
def test_grade_word_mixed(self):
|
||||
C = game.LetterResult.CORRECT
|
||||
M = game.LetterResult.MOVE
|
||||
I = game.LetterResult.INCORRECT
|
||||
|
||||
test_cases = (
|
||||
("aabbb", "aabbb", [C, C, C, C, C]),
|
||||
("aabbb", "aaccc", [C, C, I, I, I]),
|
||||
("bbbaa", "cccaa", [I, I, I, C, C]),
|
||||
("aabbb", "cccaa", [I, I, I, M, M]),
|
||||
("aabbb", "bbbaa", [M, M, C, M, M]),
|
||||
("aabbb", "ccaaa", [I, I, M, M, I]),
|
||||
("aabbb", "abcde", [C, M, I, I, I]),
|
||||
("aabbb", "ccccc", [I, I, I, I, I]),
|
||||
)
|
||||
|
||||
for target, guess, expected in test_cases:
|
||||
result = game.grade_word(target, guess, self.test_words)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_grade_word_invalid(self):
|
||||
target = "aaaaa"
|
||||
guess = "inval"
|
||||
|
||||
with self.assertRaises(Exception):
|
||||
game.grade_word(target, guess, self.test_words)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+14
-14
@@ -1,14 +1,14 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import play
|
||||
|
||||
|
||||
class TestPlay(unittest.TestCase):
|
||||
def test_noop(self):
|
||||
"""Currently no tests for this code."""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import play
|
||||
|
||||
|
||||
class TestPlay(unittest.TestCase):
|
||||
def test_noop(self):
|
||||
"""Currently no tests for this code."""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
+46
-27
@@ -1,27 +1,46 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import solver
|
||||
|
||||
|
||||
class TestSolver(unittest.TestCase):
|
||||
def test_SimilaritySolver(self):
|
||||
"""Minimal end to end test."""
|
||||
|
||||
solve = solver.SimilaritySolver()
|
||||
result = solve.scored_words()
|
||||
|
||||
expected = [
|
||||
("cares", 139631),
|
||||
("sanes", 139129),
|
||||
("tares", 138755),
|
||||
("bares", 138375),
|
||||
("sales", 137491),
|
||||
]
|
||||
|
||||
self.assertListEqual(result[:5], expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
#!/usr/bin/python
|
||||
|
||||
import unittest
|
||||
|
||||
import dictionary
|
||||
import solver
|
||||
|
||||
test_dictionary = dictionary.words()
|
||||
|
||||
|
||||
class TestSolver(unittest.TestCase):
|
||||
def test_SimilaritySolver(self):
|
||||
"""Minimal end to end test."""
|
||||
|
||||
solve = solver.SimilaritySolver()
|
||||
result = solve.scored_words(test_dictionary)
|
||||
|
||||
expected = [
|
||||
("cares", 139631),
|
||||
("sanes", 139129),
|
||||
("tares", 138755),
|
||||
("bares", 138375),
|
||||
("sales", 137491),
|
||||
]
|
||||
|
||||
self.assertListEqual(result[:5], expected)
|
||||
|
||||
def test_LimitsSolver(self):
|
||||
"""Minimal end to end test."""
|
||||
|
||||
solve = solver.LimitsSolver()
|
||||
result = solve.scored_words(test_dictionary)
|
||||
|
||||
expected = [
|
||||
("aahed", 5),
|
||||
("aalii", 5),
|
||||
("aargh", 5),
|
||||
("aaron", 5),
|
||||
("abaca", 5),
|
||||
]
|
||||
|
||||
self.assertListEqual(result[:5], expected)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -9,7 +9,7 @@
|
||||
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": true
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
},
|
||||
"python.formatting.provider": "none",
|
||||
|
||||
Reference in new issue
Block a user