From 7de24964de5bd613958796154cca3d456c53160d Mon Sep 17 00:00:00 2001 From: KylerO Date: Fri, 18 Apr 2025 11:21:17 -0600 Subject: [PATCH 01/11] Started UI --- library.py | 1 + main.py | 15 +++++++++++++++ ui.py | 10 ++++++++++ 3 files changed, 26 insertions(+) create mode 100644 main.py create mode 100644 ui.py diff --git a/library.py b/library.py index 38daec0..a7c682c 100644 --- a/library.py +++ b/library.py @@ -30,6 +30,7 @@ class Library: def serve_forever(self): try: + print(f"Starting server at {self.__host}:{self.__port}") with self.__socket as s: s.bind((self.__host, self.__port)) s.listen(1) diff --git a/main.py b/main.py new file mode 100644 index 0000000..24ae844 --- /dev/null +++ b/main.py @@ -0,0 +1,15 @@ +import argparse + +def server(host: str='', port: int=7788): + from library import Library + lib = Library(host, port) + lib.serve_forever() + +def client(playername: str, host: str='localhost', port: int=7788): + pass + +def main(): + pass + +if __name__ == "__main__": + main() diff --git a/ui.py b/ui.py new file mode 100644 index 0000000..2db18cc --- /dev/null +++ b/ui.py @@ -0,0 +1,10 @@ + +from client import Player + +class UI: + + __player: Player + + def __init__(self, playername: str, host: str='localhost', port: int=7788): + self.__player = Player(playername) + self.__player.join_game() From f53e358410b9cfbf46f8fe314a62b79cfdd59914 Mon Sep 17 00:00:00 2001 From: KylerO Date: Mon, 21 Apr 2025 11:34:06 -0600 Subject: [PATCH 02/11] Got first part of UI working. --- .gitignore | 1 + client.py | 22 +++++++++++----- library.py | 9 ++++++- main.py | 6 +++-- server.py | 10 ++++++++ ui.py | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c18dd8d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/client.py b/client.py index cd19349..44df3e9 100644 --- a/client.py +++ b/client.py @@ -3,10 +3,14 @@ # Apr 2025 from __future__ import annotations +from typing import TYPE_CHECKING import socket import select import network_utilities +if TYPE_CHECKING: + from ui import UI + class Game: @@ -66,12 +70,14 @@ class Player: __verse: str __score: int __game: Game | None + __ui: UI - def __init__(self, name: str): + def __init__(self, name: str, ui: UI): self.__name = name self.__verse = "" self.__score = 0 self.__game = None + self.__ui = ui @property def name(self) -> str: return self.__name @@ -108,27 +114,29 @@ class Player: def player_joined(self, name: str): if self.__game is not None: - pass + self.__ui.player_joined(name) def new_verse(self, text: str): if self.__game is not None: - pass + self.__verse = text + self.__ui.new_verse(text) def guess_incorrect(self): if self.__game is not None: - pass + self.__ui.guess_incorrect() def guess_correct(self): if self.__game is not None: - pass + self.__ui.guess_correct() def verse_guessed(self, points: int, url: str, player: str): if self.__game is not None: - pass + self.__score += points + self.__ui.verse_guessed(points, url, player) def game_over(self, players: list[str], scores: list[int]): if self.__game is not None: - pass + self.__ui.game_over(players, scores) def update(self): if self.__game is not None: diff --git a/library.py b/library.py index a7c682c..e9a0666 100644 --- a/library.py +++ b/library.py @@ -9,6 +9,7 @@ import socket import select import network_utilities from server import Game +from time import sleep class Library: @@ -41,11 +42,13 @@ class Library: if not game.finished: game.update() else: self.__games.remove(game) if ready_to_read: - conn, _ = s.accept() + conn, addr = s.accept() conn.setblocking(False) if network_utilities.unpack_varint(conn) == 1: name = network_utilities.unpack_string(conn) + print(f"<< (1) join_game({name}, {addr})") self.join_game(name, conn) + sleep(0.1) except KeyboardInterrupt: print("KeyboardInterrupt\nExiting...") return @@ -110,3 +113,7 @@ class Library: return difficulty_verses + +if __name__ == '__main__': + lib = Library() + lib.serve_forever() diff --git a/main.py b/main.py index 24ae844..84aee3c 100644 --- a/main.py +++ b/main.py @@ -6,10 +6,12 @@ def server(host: str='', port: int=7788): lib.serve_forever() def client(playername: str, host: str='localhost', port: int=7788): - pass + from ui import UI + ui = UI(playername, host, port) + ui.loop() def main(): - pass + client("TestPlayer") if __name__ == "__main__": main() diff --git a/server.py b/server.py index 1223251..4cbb530 100644 --- a/server.py +++ b/server.py @@ -105,24 +105,29 @@ class Player: def name(self) -> str: return self.__name def player_joined(self, name: str): + print(f">> (1) player_joined({name})") data = network_utilities.pack_varint(1) data += network_utilities.pack_string(name) self.__client.send(data) def new_verse(self, text: str): + print(f">> (2) new_verse({text})") data = network_utilities.pack_varint(2) data += network_utilities.pack_string(text) self.__client.send(data) def guess_incorrect(self): + print(">> (3) guess_incorrect()") data = network_utilities.pack_varint(3) self.__client.send(data) def guess_correct(self): + print(">> (4) guess_correct()") data = network_utilities.pack_varint(4) self.__client.send(data) def verse_guessed(self, points: int, url: str, player: str): + print(f">> (5) verse_guessed({points}, {url})") data = network_utilities.pack_varint(5) data += network_utilities.pack_varint(points) data += network_utilities.pack_string(url) @@ -130,6 +135,7 @@ class Player: self.__client.send(data) def game_over(self, players: list[str], scores: list[int]): + print(f">> (6) game_over({len(players)}, {len(scores)})") data = network_utilities.pack_varint(6) data += network_utilities.pack_string_array(players) data += network_utilities.pack_varint_array(scores) @@ -141,13 +147,17 @@ class Player: if ready_to_read: packet_id = network_utilities.unpack_varint(self.__client) if packet_id == 2: + print("<< (2) start_game()") self.__game.start_game() elif packet_id == 3: difficulty = network_utilities.unpack_varint(self.__client) + print(f"<< (3) start_round({difficulty})") self.__game.start_round(difficulty) elif packet_id == 4: url = network_utilities.unpack_string(self.__client) + print(f"<< (4) guess_reference({url}, {self.name})") self.__game.guess_reference(url, self) elif packet_id == 5: + print("<< (5) end_game()") self.__game.end_game() diff --git a/ui.py b/ui.py index 2db18cc..9f230a7 100644 --- a/ui.py +++ b/ui.py @@ -1,10 +1,81 @@ from client import Player +from time import sleep +from blessed import Terminal + class UI: __player: Player + __verse: str + __in_game: bool + __game_over: bool + __term: Terminal + __buffer: str def __init__(self, playername: str, host: str='localhost', port: int=7788): - self.__player = Player(playername) - self.__player.join_game() + self.__player = Player(playername, self) + self.__player.join_game(host, port) + self.__verse = "" + self.__in_game = False + self.__game_over = False + self.__term = Terminal() + self.__buffer = "" + + def get_line(self): + with self.__term.cbreak(): + val = self.__term.inkey(timeout=0) + if not val: + return None + if val.is_sequence: + if val.name == 'KEY_ENTER': + line = self.__buffer + self.__buffer = "" + print() + return line + elif val.name == 'KEY_BACKSPACE': + self.__buffer = self.__buffer[:-1] + print(f'\r{self.__term.clear_eol}{self.__buffer}', end='', flush=True) + else: + self.__buffer += val + print(val, end='', flush=True) + return None + + def loop(self): + while not self.__game_over: + self.__player.update() + if text := self.get_line(): + if self.__in_game: + self.__player.guess_reference(text) + elif text == 'Start Game': + self.__player.start_game() + self.__player.new_round(1) + sleep(0.1) + + def player_joined(self, name: str): + print(f"{name} Joined the Game") + + def new_verse(self, text: str): + self.__in_game = True + self.__verse = text + print(self.__verse) + + def guess_incorrect(self): + print("That guess was incorrect.") + print(self.__verse) + + def guess_correct(self): + print("That guess was correct!") + + def verse_guessed(self, points: int, url: str, player: str): + print(f"The verse has been guessed. It is {url}.") + print(f"You have been awarded {points} points for your guess.") + + def game_over(self, players: list[str], scores: list[int]): + self.__game_over = True + print("--- THANKS FOR PLAYING! ---") + for player, score in players, scores: + if player == self.__player.name: + print(f" * {player}: {score} *") + else: + print(f" {player}: {score}") From f0dd002101ade7cbaebe2946abbde48bc4fef3f6 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 21:15:35 -0600 Subject: [PATCH 03/11] Added reference to url conversions --- library.py | 1 + reference.py | 160 +++++++++++++++++++++++++++++++++++++++++++++++++++ ui.py | 47 ++++++++++++--- 3 files changed, 201 insertions(+), 7 deletions(-) create mode 100644 reference.py diff --git a/library.py b/library.py index e9a0666..877b711 100644 --- a/library.py +++ b/library.py @@ -65,6 +65,7 @@ class Library: def get_verse(self, difficulty: int, game: Game): url = self.__select_verse(difficulty) + print(f"Verse Selected: {url}") text = self.__get_verse_text(url) game.new_verse(url, text) diff --git a/reference.py b/reference.py new file mode 100644 index 0000000..1079731 --- /dev/null +++ b/reference.py @@ -0,0 +1,160 @@ +# Kyler Olsen +# Mar 2024 +import re + +__LINKS = { + '/ot/gen': ("Gen.", "Genesis", ), + '/ot/ex': ("Ex.", "Exodus", ), + '/ot/lev': ("Lev.", "Leviticus", ), + '/ot/num': ("Num.", "Numbers", ), + '/ot/deut': ("Deut.", "Deuteronomy", ), + '/ot/josh': ("Josh.", "Joshua", ), + '/ot/judg': ("Judg.", "Judges", ), + '/ot/ruth': ("Ruth", ), + '/ot/1-sam': ("1 Sam.", "1 Samuel", ), + '/ot/2-sam': ("2 Sam.", "2 Samuel", ), + '/ot/1-kgs': ("1 Kgs.", "1 Kings", ), + '/ot/2-kgs': ("2 Kgs.", "2 Kings", ), + '/ot/1-chr': ("1 Chr.", "1 Chronic, es", ), + '/ot/2-chr': ("2 Chr.", "2 Chronicles", ), + '/ot/ezra': ("Ezra", ), + '/ot/neh': ("Neh.", "Nehemiah", ), + '/ot/esth': ("Esth.", "Esther", ), + '/ot/job': ("Job", ), + '/ot/ps': ("Ps.", "Psalms", "Psalm", ), + '/ot/prov': ("Prov.", "Proverbs", ), + '/ot/eccl': ("Eccl.", "Ecclesiastes", ), + '/ot/song': ("Song", "Song of Solomon", ), + '/ot/isa': ("Isa.", "Isaiah", ), + '/ot/jer': ("Jer.", "Jeremiah", ), + '/ot/lam': ("Lam.", "Lamentations", ), + '/ot/ezek': ("Ezek.", "Ezekiel", ), + '/ot/dan': ("Dan.", "Daniel", ), + '/ot/hosea': ("Hosea", ), + '/ot/joel': ("Joel", ), + '/ot/amos': ("Amos", ), + '/ot/obad': ("Obad.", "Obadiah", ), + '/ot/jonah': ("Jonah", ), + '/ot/micah': ("Micah", ), + '/ot/nahum': ("Nahum", ), + '/ot/hab': ("Hab.", "Habakkuk", ), + '/ot/zeph': ("Zeph.", "Zephaniah", ), + '/ot/hag': ("Hag.", "Haggai", ), + '/ot/zech': ("Zech.", "Zechariah", ), + '/ot/mal': ("Mal.", "Malachi", ), + '/nt/matt': ("Matt.", "Matthew", ), + '/nt/mark': ("Mark", ), + '/nt/luke': ("Luke", ), + '/nt/john': ("John", ), + '/nt/acts': ("Acts", ), + '/nt/rom': ("Rom.", "Romans", ), + '/nt/1-cor': ("1 Cor.", "1 Corinthians", ), + '/nt/2-cor': ("2 Cor.", "2 Corinthians", ), + '/nt/gal': ("Gal.", "Galatians", ), + '/nt/eph': ("Eph.", "Ephesians", ), + '/nt/philip': ("Philip.", "Philippians", ), + '/nt/col': ("Col.", "Colossians", ), + '/nt/1-thes': ("1 Thes.", "1 Thessalonians", ), + '/nt/2-thes': ("2 Thes.", "2 Thessalonians", ), + '/nt/1-tim': ("1 Tim.", "1 Timothy", ), + '/nt/2-tim': ("2 Tim.", "2 Timothy", ), + '/nt/titus': ("Titus", ), + '/nt/philem': ("Philem.", "Philemon", ), + '/nt/heb': ("Heb.", "Hebrews", ), + '/nt/james': ("James", ), + '/nt/1-pet': ("1 Pet.", "1 Peter", ), + '/nt/2-pet': ("2 Pet.", "2 Peter", ), + '/nt/1-jn': ("1 Jn.", "1 John", ), + '/nt/2-jn': ("2 Jn.", "2 John", ), + '/nt/3-jn': ("3 Jn.", "3 John", ), + '/nt/jude': ("Jude", ), + '/nt/rev': ("Rev.", "Revelation", ), + '/bofm/1-ne': ("1 Ne.", "1 Nephi", ), + '/bofm/2-ne': ("2 Ne.", "2 Nephi", ), + '/bofm/jacob': ("Jacob", ), + '/bofm/enos': ("Enos", ), + '/bofm/jarom': ("Jarom", ), + '/bofm/omni': ("Omni", ), + '/bofm/w-of-m': ("W of M", "Words of Mormon", ), + '/bofm/mosiah': ("Mosiah", ), + '/bofm/alma': ("Alma", ), + '/bofm/hel': ("Hel.", "Helaman", ), + '/bofm/3-ne': ("3 Ne.", "3 Nephi", ), + '/bofm/4-ne': ("4 Ne.", "4 Nephi", ), + '/bofm/morm': ("Morm.", "Mormon", ), + '/bofm/ether': ("Ether", ), + '/bofm/moro': ("Moro.", "Moroni", ), + '/dc-testament/dc': ("D&C", "Doctrine and Covenants", ), + '/dc-testament/od': ("OD", "Official Declaration", ), + '/pgp/moses': ("Moses", ), + '/pgp/abr': ("Abr.", "Abraham", ), + '/pgp/js-m': ("JS—M", "Joseph Smith—Matthew", "JS-M", "Joseph Smith-Matthew", ), + '/pgp/js-h': ("JS—H", "Joseph Smith—History", "JS-H", "Joseph Smith-History", ), + '/pgp/a-of-f': ("A of F", "Articles of Faith", ), + '/ot': ("OT", "Old Testament", "The Old Testament", ), + '/nt': ("NT", "New Testament", "The New Testament", ), + '/bofm': ("BofM", "Book of Mormon", "The Book of Mormon", ), + '/pgp': ("PGP", "PofGP", "Pearl of Great Price", "The Pearl of Great Price", ), +} + +def __find_book(book: str) -> tuple[str, list[str]]: + matches: dict[str, str] = {} + for key, values in __LINKS.items(): + if book.lower().replace('.', '') in [i.lower().replace('.', '') for i in values]: + return (key, []) + else: + for value in values: + if value.lower().startswith(book.lower().replace('.', '')): + matches[key] = values[-1] + if len(matches) == 1: + return (list(matches.keys())[0], []) + else: + return ("", list(matches.values())) + +def convert_reference(ref: str) -> tuple[str, list[str]]: + pattern = re.findall(r'^.*\w\.?\s\d', ref) + if pattern: + i = len(pattern[-1])-1 + book, cv = ref[:i-1], \ + ref[i:].replace(' ', '').replace('–', '-').replace(':', '/') + link, possible = __find_book(book) + if link: + return (f"{link}/{cv}", []) + else: + return ("", possible) + else: + return __find_book(ref) + +def convert_url(url: str) -> str: + parts = url.strip('/').split('/') + + if not parts: + raise ValueError("Empty URL") + + book_key = f"/{'/'.join(parts[:2]) if len(parts) >= 2 else parts[0]}" + remainder = parts[2:] if len(parts) > 2 else [] + + if book_key not in __LINKS: + raise ValueError(f"Book key not found: {book_key}") + + book_name = __LINKS[book_key][-1] + + if not remainder: + return book_name + elif len(remainder) == 1: + return f"{book_name} {remainder[0]}" + elif len(remainder) == 2: + return f"{book_name} {remainder[0]}:{remainder[1]}" + else: + raise ValueError(f"Unexpected format in URL: {url}") + +if __name__ == '__main__': + # import json + # with open('refs.json', 'w', encoding='utf-8') as file: + # json.dump(__LINKS, file, indent=4) + with open('refs.txt', encoding='utf-8') as file: + # for i in file.readlines(): + for i in file.readlines()[::50]: + ref = convert_reference(i[:-1])[0] + if ref: + print(convert_url(ref)) diff --git a/ui.py b/ui.py index 9f230a7..5bbe1d5 100644 --- a/ui.py +++ b/ui.py @@ -1,5 +1,6 @@ from client import Player +from reference import convert_reference, convert_url from time import sleep from blessed import Terminal @@ -45,13 +46,40 @@ class UI: while not self.__game_over: self.__player.update() if text := self.get_line(): - if self.__in_game: - self.__player.guess_reference(text) - elif text == 'Start Game': - self.__player.start_game() - self.__player.new_round(1) + if self.__in_game: self.__guess_ref(text) + elif text == 'Start Game': self.__start_game() sleep(0.1) + def __guess_ref(self, text: str): + try: + url, possible = convert_reference(text) + except Exception: + print( + "An Unknown Error Occurred.\n" + "Please Check Your Reference and Try Again." + ) + else: + if url: + self.__player.guess_reference(url) + return + elif possible: + print( + "Sorry, that reference could not be found.\n" + "Did you mean one of these:" + ) + for i in possible: + print(i) + else: + print( + "Sorry, that reference could not be found.\n" + "Please Check Your Reference and Try Again." + ) + print(self.__verse) + + def __start_game(self, difficulty: int = 1): + self.__player.start_game() + self.__player.new_round(difficulty) + def player_joined(self, name: str): print(f"{name} Joined the Game") @@ -68,8 +96,13 @@ class UI: print("That guess was correct!") def verse_guessed(self, points: int, url: str, player: str): - print(f"The verse has been guessed. It is {url}.") - print(f"You have been awarded {points} points for your guess.") + try: ref = convert_url(url) + except Exception: ref = url.upper().replace('/','.').strip('.') + print( + f"The verse has been guessed by {player}.\n" + f"The reference is {ref}.\n" + f"You have been awarded {points} points for your guess." + ) def game_over(self, players: list[str], scores: list[int]): self.__game_over = True From b3c6ec9e48d48aeb77985e0e2ecde38a19bff6bf Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 21:33:21 -0600 Subject: [PATCH 04/11] Added partial correct and points --- client.py | 7 +++++++ server.py | 19 ++++++++++++++++++- ui.py | 14 ++++++++++++-- 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/client.py b/client.py index 44df3e9..a95173c 100644 --- a/client.py +++ b/client.py @@ -51,6 +51,9 @@ class Game: self.__player.new_verse(text) elif packet_id == 3: self.__player.guess_incorrect() + elif packet_id == 7: + url = network_utilities.unpack_string(self.__server) + self.__player.guess_partial_correct(url) elif packet_id == 4: self.__player.guess_correct() elif packet_id == 5: @@ -125,6 +128,10 @@ class Player: if self.__game is not None: self.__ui.guess_incorrect() + def guess_partial_correct(self, url): + if self.__game is not None: + self.__ui.guess_partial_correct(url) + def guess_correct(self): if self.__game is not None: self.__ui.guess_correct() diff --git a/server.py b/server.py index 4cbb530..733f6a8 100644 --- a/server.py +++ b/server.py @@ -17,6 +17,7 @@ class Game: __library: Library __current_url: str + __current_url_parts: list[str] __clients: list[Player] __round_points: list[int] __total_scores: list[int] @@ -27,6 +28,7 @@ class Game: def __init__(self, library: Library): self.__library = library self.__current_url = "" + self.__current_url_parts = [] self.__clients = [] self.__round_points = [] self.__total_scores = [] @@ -58,18 +60,27 @@ class Game: def new_verse(self, url: str, text: str): for player in self.__clients: self.__current_url = url + self.__current_url_parts = url.strip('/').split('/') player.new_verse(text) def guess_reference(self, url: str, player: Player): if self.__active and not self.__finished: if url == self.__current_url: player.guess_correct() + self.__round_points[self.__clients.index(player)] = 4 for i, points in enumerate(self.__round_points): self.__total_scores[i] += points self.__clients[i].verse_guessed( points, self.__current_url, player.name) else: - player.guess_incorrect() + partially_correct = [] + for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts): + if player_url == current_url: + partially_correct.append(current_url) + if partially_correct: + player.guess_partial_correct(f"/{'/'.join(partially_correct)}") + self.__round_points[self.__clients.index(player)] = len(partially_correct) + else: player.guess_incorrect() def end_game(self): self.__finished = True @@ -121,6 +132,12 @@ class Player: data = network_utilities.pack_varint(3) self.__client.send(data) + def guess_partial_correct(self, url): + print(f">> (7) guess_partial_correct({url})") + data = network_utilities.pack_varint(7) + data += network_utilities.pack_string(url) + self.__client.send(data) + def guess_correct(self): print(">> (4) guess_correct()") data = network_utilities.pack_varint(4) diff --git a/ui.py b/ui.py index 5bbe1d5..23779c1 100644 --- a/ui.py +++ b/ui.py @@ -42,6 +42,10 @@ class UI: print(val, end='', flush=True) return None + def __reset(self): + self.__buffer = "" + print() + def loop(self): while not self.__game_over: self.__player.update() @@ -84,6 +88,7 @@ class UI: print(f"{name} Joined the Game") def new_verse(self, text: str): + self.__reset() self.__in_game = True self.__verse = text print(self.__verse) @@ -92,6 +97,11 @@ class UI: print("That guess was incorrect.") print(self.__verse) + def guess_partial_correct(self, url): + try: ref = convert_url(url) + except Exception: ref = url.upper().replace('/','.').strip('.') + print(f"That guess was partially correct: {ref}") + def guess_correct(self): print("That guess was correct!") @@ -99,14 +109,14 @@ class UI: try: ref = convert_url(url) except Exception: ref = url.upper().replace('/','.').strip('.') print( - f"The verse has been guessed by {player}.\n" + f"\nThe verse has been guessed by {player}.\n" f"The reference is {ref}.\n" f"You have been awarded {points} points for your guess." ) def game_over(self, players: list[str], scores: list[int]): self.__game_over = True - print("--- THANKS FOR PLAYING! ---") + print("\n--- THANKS FOR PLAYING! ---") for player, score in players, scores: if player == self.__player.name: print(f" * {player}: {score} *") From 109efe66c590f70474e163390684ead2b638c020 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 22:08:33 -0600 Subject: [PATCH 05/11] Implement name generation for players and enhance UI feedback on player actions --- main.py | 46 +++++++++++++++++++++++++++++++++++++++++-- server.py | 58 +++++++++++++++++++++++++++++++------------------------ ui.py | 9 +++++++-- 3 files changed, 84 insertions(+), 29 deletions(-) diff --git a/main.py b/main.py index 84aee3c..10fbcf6 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,46 @@ -import argparse + +import random + +def name_gen(): + adjectives = [ + "able", "active", "adaptable", "adventurous", "agreeable", "alert", + "amazing", "amiable", "ample", "artistic", "attractive", "balanced", + "beautiful", "blissful", "bold", "brave", "bright", "brilliant", + "bubbly", "calm", "capable", "careful", "charming", "cheerful", "clean", + "clear", "clever", "colorful", "comfortable", "compassionate", + "confident", "considerate", "cool", "cooperative", "courageous", + "creative", "cultured", "cute", "daring", "decent", "delightful", + "detailed", "determined", "dignified", "disciplined", "dynamic", + "eager", "easygoing", "elegant", "energetic", "engaging", + "enthusiastic", "excellent", "exciting", "expressive", "fair", + "faithful", "fancy", "fascinating", "flexible", "focused", "friendly", + "fun", "funny", "generous", "gentle", "genuine", "gifted", "glad", + "gleaming", "good", "graceful", "gracious", "great", "handsome", + "happy", "harmonious", "helpful", "honest", "hopeful", "humble", + "imaginative", "impressive", "independent", "innocent", "inspiring", + "intelligent", "interesting", "intuitive", "jolly", "jovial", "joyful", + "kind", "lively", "logical", "lovely", "loyal", "lucky", "mature", + "mindful", "modest", + ] + nouns = [ + "Cello", "Badger", "Fish", "Apple", "Mountain", "River", "Teacher", + "Book", "Car", "Tree", "Dog", "House", "Chair", "Phone", "Computer", + "City", "Ocean", "Guitar", "Desk", "Flower", "Star", "Sky", "Window", + "Road", "Train", "Plane", "School", "Garden", "Table", "Bottle", + "Shirt", "Door", "Bridge", "Watch", "Camera", "Bag", "Pencil", "Cup", + "Hat", "Wall", "Cloud", "Island", "Forest", "Room", "Engine", "Shoe", + "Candle", "Bed", "Lamp", "Mirror", "Clock", "Keyboard", "Mouse", + "Blanket", "Pillow", "Soap", "Towel", "Toothbrush", "Backpack", + "Basket", "Fan", "Television", "Magazine", "Newspaper", "Statue", + "Painting", "Ladder", "Fence", "Rope", "Ball", "Drum", "Violin", + "Microphone", "Box", "Shelf", "Ring", "Necklace", "Coin", "Wallet", + "Purse", "Ticket", "Key", "Lock", "Brush", "Comb", "Notebook", + "Envelope", "Stamp", "Hammer", "Screwdriver", "Nail", "Saw", "Plank", + "Brick", "Tile", "Carpet", "Curtain", "Apron", "Oven", "Refrigerator", + "Blender", "Pot", "Pan", + ] + + return random.choice(adjectives).capitalize() + random.choice(nouns) def server(host: str='', port: int=7788): from library import Library @@ -11,7 +53,7 @@ def client(playername: str, host: str='localhost', port: int=7788): ui.loop() def main(): - client("TestPlayer") + client(name_gen()) if __name__ == "__main__": main() diff --git a/server.py b/server.py index 733f6a8..f576ddb 100644 --- a/server.py +++ b/server.py @@ -44,7 +44,10 @@ class Game: def add_player(self, name: str, conn: socket): if not self.__active: - self.__clients.append(Player(name, self, conn)) + new_player = Player(name, self, conn) + for player in self.__clients: + new_player.player_joined(player.name) + self.__clients.append(new_player) self.__total_scores.append(0) for player in self.__clients: player.player_joined(name) @@ -72,6 +75,7 @@ class Game: self.__total_scores[i] += points self.__clients[i].verse_guessed( points, self.__current_url, player.name) + self.end_game() else: partially_correct = [] for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts): @@ -106,45 +110,47 @@ class Player: __name: str __game: Game __client: socket + __connected: bool def __init__(self, name: str, game: Game, conn: socket): self.__name = name self.__game = game self.__client = conn + self.__connected = True @property def name(self) -> str: return self.__name def player_joined(self, name: str): - print(f">> (1) player_joined({name})") + print(f">> (1, {self.name}) player_joined({name})") data = network_utilities.pack_varint(1) data += network_utilities.pack_string(name) self.__client.send(data) def new_verse(self, text: str): - print(f">> (2) new_verse({text})") + print(f">> (2, {self.name}) new_verse({text})") data = network_utilities.pack_varint(2) data += network_utilities.pack_string(text) self.__client.send(data) def guess_incorrect(self): - print(">> (3) guess_incorrect()") + print(f">> (3, {self.name}) guess_incorrect()") data = network_utilities.pack_varint(3) self.__client.send(data) def guess_partial_correct(self, url): - print(f">> (7) guess_partial_correct({url})") + print(f">> (7, {self.name}) guess_partial_correct({url})") data = network_utilities.pack_varint(7) data += network_utilities.pack_string(url) self.__client.send(data) def guess_correct(self): - print(">> (4) guess_correct()") + print(">> (4, {self.name}) guess_correct()") data = network_utilities.pack_varint(4) self.__client.send(data) def verse_guessed(self, points: int, url: str, player: str): - print(f">> (5) verse_guessed({points}, {url})") + print(f">> (5, {self.name}) verse_guessed({points}, {url})") data = network_utilities.pack_varint(5) data += network_utilities.pack_varint(points) data += network_utilities.pack_string(url) @@ -152,29 +158,31 @@ class Player: self.__client.send(data) def game_over(self, players: list[str], scores: list[int]): - print(f">> (6) game_over({len(players)}, {len(scores)})") + print(f">> (6, {self.name}) game_over({len(players)}, {len(scores)})") data = network_utilities.pack_varint(6) data += network_utilities.pack_string_array(players) data += network_utilities.pack_varint_array(scores) self.__client.send(data) self.__client.close() + self.__connected = False def update(self): - ready_to_read, _, _ = select.select([self.__client], [], [], 0) - if ready_to_read: - packet_id = network_utilities.unpack_varint(self.__client) - if packet_id == 2: - print("<< (2) start_game()") - self.__game.start_game() - elif packet_id == 3: - difficulty = network_utilities.unpack_varint(self.__client) - print(f"<< (3) start_round({difficulty})") - self.__game.start_round(difficulty) - elif packet_id == 4: - url = network_utilities.unpack_string(self.__client) - print(f"<< (4) guess_reference({url}, {self.name})") - self.__game.guess_reference(url, self) - elif packet_id == 5: - print("<< (5) end_game()") - self.__game.end_game() + if self.__connected: + ready_to_read, _, _ = select.select([self.__client], [], [], 0) + if ready_to_read: + packet_id = network_utilities.unpack_varint(self.__client) + if packet_id == 2: + print(f"<< (2, {self.name}) start_game()") + self.__game.start_game() + elif packet_id == 3: + difficulty = network_utilities.unpack_varint(self.__client) + print(f"<< (3, {self.name}) start_round({difficulty})") + self.__game.start_round(difficulty) + elif packet_id == 4: + url = network_utilities.unpack_string(self.__client) + print(f"<< (4, {self.name}) guess_reference({url}, {self.name})") + self.__game.guess_reference(url, self) + elif packet_id == 5: + print(f"<< (5, {self.name}) end_game()") + self.__game.end_game() diff --git a/ui.py b/ui.py index 23779c1..223f970 100644 --- a/ui.py +++ b/ui.py @@ -64,6 +64,9 @@ class UI: ) else: if url: + try: ref = convert_url(url) + except Exception: ref = url.upper().replace('/','.').strip('.') + print(f"Your input was interpreted as: {ref}") self.__player.guess_reference(url) return elif possible: @@ -85,7 +88,8 @@ class UI: self.__player.new_round(difficulty) def player_joined(self, name: str): - print(f"{name} Joined the Game") + if name == self.__player.name: print(f"* {name} Joined the Game *") + else: print(f"{name} Joined the Game") def new_verse(self, text: str): self.__reset() @@ -101,6 +105,7 @@ class UI: try: ref = convert_url(url) except Exception: ref = url.upper().replace('/','.').strip('.') print(f"That guess was partially correct: {ref}") + print(self.__verse) def guess_correct(self): print("That guess was correct!") @@ -117,7 +122,7 @@ class UI: def game_over(self, players: list[str], scores: list[int]): self.__game_over = True print("\n--- THANKS FOR PLAYING! ---") - for player, score in players, scores: + for player, score in zip(players, scores): if player == self.__player.name: print(f" * {player}: {score} *") else: From dacb3b893b194d8e62b62f7dc7644e3abf5373b8 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 22:58:56 -0600 Subject: [PATCH 06/11] Improved string encoding for network --- network_utilities.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/network_utilities.py b/network_utilities.py index ff95aae..6fd02e1 100644 --- a/network_utilities.py +++ b/network_utilities.py @@ -32,8 +32,9 @@ def unpack_varint(conn: socket) -> int: return data def pack_string(text: str) -> bytes: - data = pack_varint(len(text)) - data += text.encode('utf-8') + utf = text.encode('utf-8') + data = pack_varint(len(utf)) + data += utf return data def unpack_string(conn: socket) -> str: From 0635ab50f9db6ab9816c190f01f75fdf9398e64c Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 22:59:27 -0600 Subject: [PATCH 07/11] Improved default player naming alg --- main.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 10fbcf6..c28dba5 100644 --- a/main.py +++ b/main.py @@ -22,25 +22,26 @@ def name_gen(): "kind", "lively", "logical", "lovely", "loyal", "lucky", "mature", "mindful", "modest", ] - nouns = [ - "Cello", "Badger", "Fish", "Apple", "Mountain", "River", "Teacher", - "Book", "Car", "Tree", "Dog", "House", "Chair", "Phone", "Computer", - "City", "Ocean", "Guitar", "Desk", "Flower", "Star", "Sky", "Window", - "Road", "Train", "Plane", "School", "Garden", "Table", "Bottle", - "Shirt", "Door", "Bridge", "Watch", "Camera", "Bag", "Pencil", "Cup", - "Hat", "Wall", "Cloud", "Island", "Forest", "Room", "Engine", "Shoe", - "Candle", "Bed", "Lamp", "Mirror", "Clock", "Keyboard", "Mouse", - "Blanket", "Pillow", "Soap", "Towel", "Toothbrush", "Backpack", - "Basket", "Fan", "Television", "Magazine", "Newspaper", "Statue", - "Painting", "Ladder", "Fence", "Rope", "Ball", "Drum", "Violin", - "Microphone", "Box", "Shelf", "Ring", "Necklace", "Coin", "Wallet", - "Purse", "Ticket", "Key", "Lock", "Brush", "Comb", "Notebook", - "Envelope", "Stamp", "Hammer", "Screwdriver", "Nail", "Saw", "Plank", - "Brick", "Tile", "Carpet", "Curtain", "Apron", "Oven", "Refrigerator", - "Blender", "Pot", "Pan", + animals = [ + "aardvark", "albatross", "alligator", "alpaca", "ant", "anteater", + "antelope", "ape", "armadillo", "baboon", "badger", "barracuda", "bat", + "bear", "beaver", "bee", "beetle", "bison", "boar", + "bobcat", "buffalo", "butterfly", "camel", "canary", "capybara", + "caracal", "caribou", "cassowary", "cat", "caterpillar", "cattle", + "chameleon", "cheetah", "chicken", "chimpanzee", "chinchilla", "cobra", + "cockatoo", "cougar", "cow", "coyote", "crab", "crane", "crocodile", + "crow", "deer", "dingo", "dog", "dolphin", "donkey", "dove", + "dragonfly", "duck", "eagle", "echidna", "eel", "elephant", "elk", + "emu", "falcon", "ferret", "finch", "firefly", "fish", "flamingo", + "fly", "fox", "frog", "gazelle", "gecko", "giraffe", "goat", "goldfish", + "goose", "gorilla", "grasshopper", "pig", "gull", "hamster", + "hare", "hawk", "hedgehog", "hippopotamus", "horse", + "hummingbird", "hyena", "iguana", "jackal", "jaguar", + "jellyfish", "kangaroo", "kingfisher", "koala", "lemur", + "leopard", "lion", "lizard", "llama", ] - return random.choice(adjectives).capitalize() + random.choice(nouns) + return random.choice(adjectives).capitalize() + random.choice(animals).capitalize() def server(host: str='', port: int=7788): from library import Library From f6888d63374ea6c3ff6af5733bc2515df8807779 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 23:00:43 -0600 Subject: [PATCH 08/11] Improved ui with game host controls --- client.py | 13 ++++++++++--- server.py | 55 ++++++++++++++++++++++++++++++++++++++++--------------- ui.py | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 84 insertions(+), 24 deletions(-) diff --git a/client.py b/client.py index a95173c..aa1d945 100644 --- a/client.py +++ b/client.py @@ -45,7 +45,8 @@ class Game: packet_id = network_utilities.unpack_varint(self.__server) if packet_id == 1: name = network_utilities.unpack_string(self.__server) - self.__player.player_joined(name) + admin = bool(network_utilities.unpack_varint(self.__server)) + self.__player.player_joined(name, admin) elif packet_id == 2: text = network_utilities.unpack_string(self.__server) self.__player.new_verse(text) @@ -74,6 +75,7 @@ class Player: __score: int __game: Game | None __ui: UI + __admin: bool def __init__(self, name: str, ui: UI): self.__name = name @@ -81,6 +83,7 @@ class Player: self.__score = 0 self.__game = None self.__ui = ui + self.__admin = False @property def name(self) -> str: return self.__name @@ -91,6 +94,9 @@ class Player: @property def score(self) -> int: return self.__score + @property + def admin(self) -> bool: return self.__admin + def join_game(self, host: str = 'localhost', port: int = 7788): conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) conn.connect((host, port)) @@ -115,9 +121,10 @@ class Player: if self.__game is not None: self.__game.end_game() - def player_joined(self, name: str): + def player_joined(self, name: str, admin: bool): if self.__game is not None: - self.__ui.player_joined(name) + if name == self.name: self.__admin = admin or self.__admin + self.__ui.player_joined(name, admin) def new_verse(self, text: str): if self.__game is not None: diff --git a/server.py b/server.py index f576ddb..2cdba89 100644 --- a/server.py +++ b/server.py @@ -3,7 +3,7 @@ # Apr 2025 from __future__ import annotations -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, ClassVar import select import datetime import network_utilities @@ -15,6 +15,8 @@ if TYPE_CHECKING: class Game: + FINAL_SCORE_LIST: ClassVar[int] = 50 + __library: Library __current_url: str __current_url_parts: list[str] @@ -24,6 +26,7 @@ class Game: __active: bool __finished: bool __created: datetime.datetime + __difficulty: int def __init__(self, library: Library): self.__library = library @@ -35,6 +38,7 @@ class Game: self.__active = False self.__finished = False self.__created = datetime.datetime.now() + self.__difficulty = 0 @property def active(self) -> bool: return self.__active @@ -45,18 +49,24 @@ class Game: def add_player(self, name: str, conn: socket): if not self.__active: new_player = Player(name, self, conn) - for player in self.__clients: - new_player.player_joined(player.name) - self.__clients.append(new_player) - self.__total_scores.append(0) - for player in self.__clients: - player.player_joined(name) + if self.__clients: + for player in self.__clients: + new_player.player_joined(player.name, False) + self.__clients.append(new_player) + self.__total_scores.append(0) + for player in self.__clients: + player.player_joined(name, False) + else: + new_player.player_joined(new_player.name, True) + self.__clients.append(new_player) + self.__total_scores.append(0) def start_game(self): self.__active = True def start_round(self, difficulty: int): if self.__active and not self.__finished: + self.__difficulty = difficulty self.__round_points = [0] * len(self.__clients) self.__library.get_verse(difficulty, self) @@ -70,12 +80,11 @@ class Game: if self.__active and not self.__finished: if url == self.__current_url: player.guess_correct() - self.__round_points[self.__clients.index(player)] = 4 + self.__round_points[self.__clients.index(player)] = 4 + self.__difficulty for i, points in enumerate(self.__round_points): self.__total_scores[i] += points self.__clients[i].verse_guessed( points, self.__current_url, player.name) - self.end_game() else: partially_correct = [] for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts): @@ -88,9 +97,24 @@ class Game: def end_game(self): self.__finished = True + items = sorted( + [(i.name, j) for i, j in zip(self.__clients, self.__total_scores)], + reverse=True, + key=lambda o: o[1] + ) + players = [i for i, _ in items] + scores = [i for _, i in items] for player in self.__clients: - player.game_over( - [i.name for i in self.__clients], self.__total_scores) + if player.name in players[:Game.FINAL_SCORE_LIST]: + player.game_over( + players[:Game.FINAL_SCORE_LIST], + scores[:Game.FINAL_SCORE_LIST] + ) + else: + player.game_over( + players[:Game.FINAL_SCORE_LIST] + [player.name], + scores[:Game.FINAL_SCORE_LIST] + [scores[players.index(player.name)]] + ) def update(self): if not self.__active and ( @@ -121,10 +145,11 @@ class Player: @property def name(self) -> str: return self.__name - def player_joined(self, name: str): - print(f">> (1, {self.name}) player_joined({name})") + def player_joined(self, name: str, admin: bool): + print(f">> (1, {self.name}) player_joined({name}, {admin})") data = network_utilities.pack_varint(1) data += network_utilities.pack_string(name) + data += network_utilities.pack_varint(admin) self.__client.send(data) def new_verse(self, text: str): @@ -145,7 +170,7 @@ class Player: self.__client.send(data) def guess_correct(self): - print(">> (4, {self.name}) guess_correct()") + print(f">> (4, {self.name}) guess_correct()") data = network_utilities.pack_varint(4) self.__client.send(data) @@ -180,7 +205,7 @@ class Player: self.__game.start_round(difficulty) elif packet_id == 4: url = network_utilities.unpack_string(self.__client) - print(f"<< (4, {self.name}) guess_reference({url}, {self.name})") + print(f"<< (4, {self.name}) guess_reference({url})") self.__game.guess_reference(url, self) elif packet_id == 5: print(f"<< (5, {self.name}) end_game()") diff --git a/ui.py b/ui.py index 223f970..5ef4b6e 100644 --- a/ui.py +++ b/ui.py @@ -10,6 +10,7 @@ class UI: __player: Player __verse: str __in_game: bool + __in_between_rounds: bool __game_over: bool __term: Terminal __buffer: str @@ -19,6 +20,7 @@ class UI: self.__player.join_game(host, port) self.__verse = "" self.__in_game = False + self.__in_between_rounds = False self.__game_over = False self.__term = Terminal() self.__buffer = "" @@ -50,10 +52,25 @@ class UI: while not self.__game_over: self.__player.update() if text := self.get_line(): - if self.__in_game: self.__guess_ref(text) - elif text == 'Start Game': self.__start_game() + if self.__in_between_rounds and self.__player.admin: + self.__next_round(text) + elif self.__in_between_rounds: + print("Waiting for the next round to start...") + elif self.__in_game: self.__guess_ref(text) + elif self.__player.admin: self.__start_game(text) + else: + print("Waiting for the game to start...") sleep(0.1) + def __next_round(self, text: str): + if text.isdigit() and 0 <= int(text) <= 10: + print(f"Starting round with difficulty: {text}") + self.__player.new_round(int(text)) + elif text.lower() == 'e': + self.__player.end_game() + else: + print("Invalid input!\nPlease enter a difficulty level between 1 and 10.") + def __guess_ref(self, text: str): try: url, possible = convert_reference(text) @@ -83,17 +100,25 @@ class UI: ) print(self.__verse) - def __start_game(self, difficulty: int = 1): + def __start_game(self, text: str = "1"): + print("Starting game...") + self.__in_between_rounds = True self.__player.start_game() - self.__player.new_round(difficulty) + self.__next_round(text) - def player_joined(self, name: str): - if name == self.__player.name: print(f"* {name} Joined the Game *") + def player_joined(self, name: str, admin: bool): + if name == self.__player.name: + if admin: + print("You are the game host.") + print("Please enter the difficulty for the first round to start the game.") + print("(Difficulty Range: 1 Easy - 10 Hard)") + print(f"* {name} Joined the Game *") else: print(f"{name} Joined the Game") def new_verse(self, text: str): self.__reset() self.__in_game = True + self.__in_between_rounds = False self.__verse = text print(self.__verse) @@ -118,6 +143,9 @@ class UI: f"The reference is {ref}.\n" f"You have been awarded {points} points for your guess." ) + self.__in_between_rounds = True + if self.__player.admin: + print("Please enter the difficulty for the next round (1-10) or 'e' to end the game.") def game_over(self, players: list[str], scores: list[int]): self.__game_over = True From 2f710acba0d028895be80961558813ad5a4c2505 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 23:23:18 -0600 Subject: [PATCH 09/11] Fixed error in partially correct references --- server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server.py b/server.py index 2cdba89..c67ba8f 100644 --- a/server.py +++ b/server.py @@ -90,6 +90,8 @@ class Game: for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts): if player_url == current_url: partially_correct.append(current_url) + else: + break if partially_correct: player.guess_partial_correct(f"/{'/'.join(partially_correct)}") self.__round_points[self.__clients.index(player)] = len(partially_correct) From e2dc2a0e5ed1f580d62e8ceafa843d52a9680250 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 23:23:47 -0600 Subject: [PATCH 10/11] Improved references handling --- reference.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/reference.py b/reference.py index 1079731..7c4d357 100644 --- a/reference.py +++ b/reference.py @@ -15,13 +15,13 @@ __LINKS = { '/ot/2-sam': ("2 Sam.", "2 Samuel", ), '/ot/1-kgs': ("1 Kgs.", "1 Kings", ), '/ot/2-kgs': ("2 Kgs.", "2 Kings", ), - '/ot/1-chr': ("1 Chr.", "1 Chronic, es", ), + '/ot/1-chr': ("1 Chr.", "1 Chronicles", ), '/ot/2-chr': ("2 Chr.", "2 Chronicles", ), '/ot/ezra': ("Ezra", ), '/ot/neh': ("Neh.", "Nehemiah", ), '/ot/esth': ("Esth.", "Esther", ), '/ot/job': ("Job", ), - '/ot/ps': ("Ps.", "Psalms", "Psalm", ), + '/ot/ps': ("Ps.", "Psalm", "Psalms", ), '/ot/prov': ("Prov.", "Proverbs", ), '/ot/eccl': ("Eccl.", "Ecclesiastes", ), '/ot/song': ("Song", "Song of Solomon", ), @@ -75,7 +75,7 @@ __LINKS = { '/bofm/enos': ("Enos", ), '/bofm/jarom': ("Jarom", ), '/bofm/omni': ("Omni", ), - '/bofm/w-of-m': ("W of M", "Words of Mormon", ), + '/bofm/w-of-m': ("WofM", "W of M", "Words of Mormon", ), '/bofm/mosiah': ("Mosiah", ), '/bofm/alma': ("Alma", ), '/bofm/hel': ("Hel.", "Helaman", ), @@ -84,13 +84,13 @@ __LINKS = { '/bofm/morm': ("Morm.", "Mormon", ), '/bofm/ether': ("Ether", ), '/bofm/moro': ("Moro.", "Moroni", ), - '/dc-testament/dc': ("D&C", "Doctrine and Covenants", ), + '/dc-testament/dc': ("D&C", "D & C", "DandC", "D and C", "D+C", "D + C", "Doctrine and Covenants", ), '/dc-testament/od': ("OD", "Official Declaration", ), '/pgp/moses': ("Moses", ), '/pgp/abr': ("Abr.", "Abraham", ), - '/pgp/js-m': ("JS—M", "Joseph Smith—Matthew", "JS-M", "Joseph Smith-Matthew", ), - '/pgp/js-h': ("JS—H", "Joseph Smith—History", "JS-H", "Joseph Smith-History", ), - '/pgp/a-of-f': ("A of F", "Articles of Faith", ), + '/pgp/js-m': ("JS—M", "Joseph Smith—Matthew", "JS-M", "JSM", "Joseph Smith-Matthew", ), + '/pgp/js-h': ("JS—H", "Joseph Smith—History", "JS-H", "JSH", "Joseph Smith-History", ), + '/pgp/a-of-f': ("A of F", "AofF", "Articles of Faith", ), '/ot': ("OT", "Old Testament", "The Old Testament", ), '/nt': ("NT", "New Testament", "The New Testament", ), '/bofm': ("BofM", "Book of Mormon", "The Book of Mormon", ), From 20fc64654b8f66a900fa6e4021ab14bdc8014126 Mon Sep 17 00:00:00 2001 From: Kyler Date: Thu, 24 Apr 2025 23:26:52 -0600 Subject: [PATCH 11/11] Added a bible only mode --- library.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/library.py b/library.py index 877b711..ded1329 100644 --- a/library.py +++ b/library.py @@ -19,8 +19,9 @@ class Library: __host: str __port: int __socket: socket.socket + __bible_only: bool - def __init__(self, host: str = '', port: int = 7788): + def __init__(self, host: str = '', port: int = 7788, *, bible_only: bool = False): with open("data/scripture-frequencies.json", encoding='utf-8') as file: self.__verses = json.load(file) self.__games = [] @@ -29,6 +30,8 @@ class Library: self.__port = port self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.__bible_only = bible_only + def serve_forever(self): try: print(f"Starting server at {self.__host}:{self.__port}") @@ -108,13 +111,17 @@ class Library: difficulty_verses = [] for key, value in self.__verses.items(): + if self.__bible_only and not (key.startswith('/ot') or key.startswith('/nt')): + continue for i, diff in enumerate(value): if real_difficulty_lower <= diff <= real_difficulty_upper: difficulty_verses.append(f"{key}/{i+1}") + if not difficulty_verses: difficulty_verses.append('/pgp/js-h/1/17') + return difficulty_verses if __name__ == '__main__': - lib = Library() + lib = Library(bible_only=False) lib.serve_forever()