Compare commits
3 Commits
109efe66c5
...
f6888d6337
| Author | SHA1 | Date |
|---|---|---|
|
|
f6888d6337 | |
|
|
0635ab50f9 | |
|
|
dacb3b893b |
13
client.py
13
client.py
|
|
@ -45,7 +45,8 @@ class Game:
|
||||||
packet_id = network_utilities.unpack_varint(self.__server)
|
packet_id = network_utilities.unpack_varint(self.__server)
|
||||||
if packet_id == 1:
|
if packet_id == 1:
|
||||||
name = network_utilities.unpack_string(self.__server)
|
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:
|
elif packet_id == 2:
|
||||||
text = network_utilities.unpack_string(self.__server)
|
text = network_utilities.unpack_string(self.__server)
|
||||||
self.__player.new_verse(text)
|
self.__player.new_verse(text)
|
||||||
|
|
@ -74,6 +75,7 @@ class Player:
|
||||||
__score: int
|
__score: int
|
||||||
__game: Game | None
|
__game: Game | None
|
||||||
__ui: UI
|
__ui: UI
|
||||||
|
__admin: bool
|
||||||
|
|
||||||
def __init__(self, name: str, ui: UI):
|
def __init__(self, name: str, ui: UI):
|
||||||
self.__name = name
|
self.__name = name
|
||||||
|
|
@ -81,6 +83,7 @@ class Player:
|
||||||
self.__score = 0
|
self.__score = 0
|
||||||
self.__game = None
|
self.__game = None
|
||||||
self.__ui = ui
|
self.__ui = ui
|
||||||
|
self.__admin = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str: return self.__name
|
def name(self) -> str: return self.__name
|
||||||
|
|
@ -91,6 +94,9 @@ class Player:
|
||||||
@property
|
@property
|
||||||
def score(self) -> int: return self.__score
|
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):
|
def join_game(self, host: str = 'localhost', port: int = 7788):
|
||||||
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
conn.connect((host, port))
|
conn.connect((host, port))
|
||||||
|
|
@ -115,9 +121,10 @@ class Player:
|
||||||
if self.__game is not None:
|
if self.__game is not None:
|
||||||
self.__game.end_game()
|
self.__game.end_game()
|
||||||
|
|
||||||
def player_joined(self, name: str):
|
def player_joined(self, name: str, admin: bool):
|
||||||
if self.__game is not None:
|
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):
|
def new_verse(self, text: str):
|
||||||
if self.__game is not None:
|
if self.__game is not None:
|
||||||
|
|
|
||||||
35
main.py
35
main.py
|
|
@ -22,25 +22,26 @@ def name_gen():
|
||||||
"kind", "lively", "logical", "lovely", "loyal", "lucky", "mature",
|
"kind", "lively", "logical", "lovely", "loyal", "lucky", "mature",
|
||||||
"mindful", "modest",
|
"mindful", "modest",
|
||||||
]
|
]
|
||||||
nouns = [
|
animals = [
|
||||||
"Cello", "Badger", "Fish", "Apple", "Mountain", "River", "Teacher",
|
"aardvark", "albatross", "alligator", "alpaca", "ant", "anteater",
|
||||||
"Book", "Car", "Tree", "Dog", "House", "Chair", "Phone", "Computer",
|
"antelope", "ape", "armadillo", "baboon", "badger", "barracuda", "bat",
|
||||||
"City", "Ocean", "Guitar", "Desk", "Flower", "Star", "Sky", "Window",
|
"bear", "beaver", "bee", "beetle", "bison", "boar",
|
||||||
"Road", "Train", "Plane", "School", "Garden", "Table", "Bottle",
|
"bobcat", "buffalo", "butterfly", "camel", "canary", "capybara",
|
||||||
"Shirt", "Door", "Bridge", "Watch", "Camera", "Bag", "Pencil", "Cup",
|
"caracal", "caribou", "cassowary", "cat", "caterpillar", "cattle",
|
||||||
"Hat", "Wall", "Cloud", "Island", "Forest", "Room", "Engine", "Shoe",
|
"chameleon", "cheetah", "chicken", "chimpanzee", "chinchilla", "cobra",
|
||||||
"Candle", "Bed", "Lamp", "Mirror", "Clock", "Keyboard", "Mouse",
|
"cockatoo", "cougar", "cow", "coyote", "crab", "crane", "crocodile",
|
||||||
"Blanket", "Pillow", "Soap", "Towel", "Toothbrush", "Backpack",
|
"crow", "deer", "dingo", "dog", "dolphin", "donkey", "dove",
|
||||||
"Basket", "Fan", "Television", "Magazine", "Newspaper", "Statue",
|
"dragonfly", "duck", "eagle", "echidna", "eel", "elephant", "elk",
|
||||||
"Painting", "Ladder", "Fence", "Rope", "Ball", "Drum", "Violin",
|
"emu", "falcon", "ferret", "finch", "firefly", "fish", "flamingo",
|
||||||
"Microphone", "Box", "Shelf", "Ring", "Necklace", "Coin", "Wallet",
|
"fly", "fox", "frog", "gazelle", "gecko", "giraffe", "goat", "goldfish",
|
||||||
"Purse", "Ticket", "Key", "Lock", "Brush", "Comb", "Notebook",
|
"goose", "gorilla", "grasshopper", "pig", "gull", "hamster",
|
||||||
"Envelope", "Stamp", "Hammer", "Screwdriver", "Nail", "Saw", "Plank",
|
"hare", "hawk", "hedgehog", "hippopotamus", "horse",
|
||||||
"Brick", "Tile", "Carpet", "Curtain", "Apron", "Oven", "Refrigerator",
|
"hummingbird", "hyena", "iguana", "jackal", "jaguar",
|
||||||
"Blender", "Pot", "Pan",
|
"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):
|
def server(host: str='', port: int=7788):
|
||||||
from library import Library
|
from library import Library
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,9 @@ def unpack_varint(conn: socket) -> int:
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def pack_string(text: str) -> bytes:
|
def pack_string(text: str) -> bytes:
|
||||||
data = pack_varint(len(text))
|
utf = text.encode('utf-8')
|
||||||
data += text.encode('utf-8')
|
data = pack_varint(len(utf))
|
||||||
|
data += utf
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def unpack_string(conn: socket) -> str:
|
def unpack_string(conn: socket) -> str:
|
||||||
|
|
|
||||||
55
server.py
55
server.py
|
|
@ -3,7 +3,7 @@
|
||||||
# Apr 2025
|
# Apr 2025
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
from typing import TYPE_CHECKING
|
from typing import TYPE_CHECKING, ClassVar
|
||||||
import select
|
import select
|
||||||
import datetime
|
import datetime
|
||||||
import network_utilities
|
import network_utilities
|
||||||
|
|
@ -15,6 +15,8 @@ if TYPE_CHECKING:
|
||||||
|
|
||||||
class Game:
|
class Game:
|
||||||
|
|
||||||
|
FINAL_SCORE_LIST: ClassVar[int] = 50
|
||||||
|
|
||||||
__library: Library
|
__library: Library
|
||||||
__current_url: str
|
__current_url: str
|
||||||
__current_url_parts: list[str]
|
__current_url_parts: list[str]
|
||||||
|
|
@ -24,6 +26,7 @@ class Game:
|
||||||
__active: bool
|
__active: bool
|
||||||
__finished: bool
|
__finished: bool
|
||||||
__created: datetime.datetime
|
__created: datetime.datetime
|
||||||
|
__difficulty: int
|
||||||
|
|
||||||
def __init__(self, library: Library):
|
def __init__(self, library: Library):
|
||||||
self.__library = library
|
self.__library = library
|
||||||
|
|
@ -35,6 +38,7 @@ class Game:
|
||||||
self.__active = False
|
self.__active = False
|
||||||
self.__finished = False
|
self.__finished = False
|
||||||
self.__created = datetime.datetime.now()
|
self.__created = datetime.datetime.now()
|
||||||
|
self.__difficulty = 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def active(self) -> bool: return self.__active
|
def active(self) -> bool: return self.__active
|
||||||
|
|
@ -45,18 +49,24 @@ class Game:
|
||||||
def add_player(self, name: str, conn: socket):
|
def add_player(self, name: str, conn: socket):
|
||||||
if not self.__active:
|
if not self.__active:
|
||||||
new_player = Player(name, self, conn)
|
new_player = Player(name, self, conn)
|
||||||
for player in self.__clients:
|
if self.__clients:
|
||||||
new_player.player_joined(player.name)
|
for player in self.__clients:
|
||||||
self.__clients.append(new_player)
|
new_player.player_joined(player.name, False)
|
||||||
self.__total_scores.append(0)
|
self.__clients.append(new_player)
|
||||||
for player in self.__clients:
|
self.__total_scores.append(0)
|
||||||
player.player_joined(name)
|
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):
|
def start_game(self):
|
||||||
self.__active = True
|
self.__active = True
|
||||||
|
|
||||||
def start_round(self, difficulty: int):
|
def start_round(self, difficulty: int):
|
||||||
if self.__active and not self.__finished:
|
if self.__active and not self.__finished:
|
||||||
|
self.__difficulty = difficulty
|
||||||
self.__round_points = [0] * len(self.__clients)
|
self.__round_points = [0] * len(self.__clients)
|
||||||
self.__library.get_verse(difficulty, self)
|
self.__library.get_verse(difficulty, self)
|
||||||
|
|
||||||
|
|
@ -70,12 +80,11 @@ class Game:
|
||||||
if self.__active and not self.__finished:
|
if self.__active and not self.__finished:
|
||||||
if url == self.__current_url:
|
if url == self.__current_url:
|
||||||
player.guess_correct()
|
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):
|
for i, points in enumerate(self.__round_points):
|
||||||
self.__total_scores[i] += points
|
self.__total_scores[i] += points
|
||||||
self.__clients[i].verse_guessed(
|
self.__clients[i].verse_guessed(
|
||||||
points, self.__current_url, player.name)
|
points, self.__current_url, player.name)
|
||||||
self.end_game()
|
|
||||||
else:
|
else:
|
||||||
partially_correct = []
|
partially_correct = []
|
||||||
for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts):
|
for player_url, current_url in zip(url.strip('/').split('/'), self.__current_url_parts):
|
||||||
|
|
@ -88,9 +97,24 @@ class Game:
|
||||||
|
|
||||||
def end_game(self):
|
def end_game(self):
|
||||||
self.__finished = True
|
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:
|
for player in self.__clients:
|
||||||
player.game_over(
|
if player.name in players[:Game.FINAL_SCORE_LIST]:
|
||||||
[i.name for i in self.__clients], self.__total_scores)
|
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):
|
def update(self):
|
||||||
if not self.__active and (
|
if not self.__active and (
|
||||||
|
|
@ -121,10 +145,11 @@ class Player:
|
||||||
@property
|
@property
|
||||||
def name(self) -> str: return self.__name
|
def name(self) -> str: return self.__name
|
||||||
|
|
||||||
def player_joined(self, name: str):
|
def player_joined(self, name: str, admin: bool):
|
||||||
print(f">> (1, {self.name}) player_joined({name})")
|
print(f">> (1, {self.name}) player_joined({name}, {admin})")
|
||||||
data = network_utilities.pack_varint(1)
|
data = network_utilities.pack_varint(1)
|
||||||
data += network_utilities.pack_string(name)
|
data += network_utilities.pack_string(name)
|
||||||
|
data += network_utilities.pack_varint(admin)
|
||||||
self.__client.send(data)
|
self.__client.send(data)
|
||||||
|
|
||||||
def new_verse(self, text: str):
|
def new_verse(self, text: str):
|
||||||
|
|
@ -145,7 +170,7 @@ class Player:
|
||||||
self.__client.send(data)
|
self.__client.send(data)
|
||||||
|
|
||||||
def guess_correct(self):
|
def guess_correct(self):
|
||||||
print(">> (4, {self.name}) guess_correct()")
|
print(f">> (4, {self.name}) guess_correct()")
|
||||||
data = network_utilities.pack_varint(4)
|
data = network_utilities.pack_varint(4)
|
||||||
self.__client.send(data)
|
self.__client.send(data)
|
||||||
|
|
||||||
|
|
@ -180,7 +205,7 @@ class Player:
|
||||||
self.__game.start_round(difficulty)
|
self.__game.start_round(difficulty)
|
||||||
elif packet_id == 4:
|
elif packet_id == 4:
|
||||||
url = network_utilities.unpack_string(self.__client)
|
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)
|
self.__game.guess_reference(url, self)
|
||||||
elif packet_id == 5:
|
elif packet_id == 5:
|
||||||
print(f"<< (5, {self.name}) end_game()")
|
print(f"<< (5, {self.name}) end_game()")
|
||||||
|
|
|
||||||
40
ui.py
40
ui.py
|
|
@ -10,6 +10,7 @@ class UI:
|
||||||
__player: Player
|
__player: Player
|
||||||
__verse: str
|
__verse: str
|
||||||
__in_game: bool
|
__in_game: bool
|
||||||
|
__in_between_rounds: bool
|
||||||
__game_over: bool
|
__game_over: bool
|
||||||
__term: Terminal
|
__term: Terminal
|
||||||
__buffer: str
|
__buffer: str
|
||||||
|
|
@ -19,6 +20,7 @@ class UI:
|
||||||
self.__player.join_game(host, port)
|
self.__player.join_game(host, port)
|
||||||
self.__verse = ""
|
self.__verse = ""
|
||||||
self.__in_game = False
|
self.__in_game = False
|
||||||
|
self.__in_between_rounds = False
|
||||||
self.__game_over = False
|
self.__game_over = False
|
||||||
self.__term = Terminal()
|
self.__term = Terminal()
|
||||||
self.__buffer = ""
|
self.__buffer = ""
|
||||||
|
|
@ -50,10 +52,25 @@ class UI:
|
||||||
while not self.__game_over:
|
while not self.__game_over:
|
||||||
self.__player.update()
|
self.__player.update()
|
||||||
if text := self.get_line():
|
if text := self.get_line():
|
||||||
if self.__in_game: self.__guess_ref(text)
|
if self.__in_between_rounds and self.__player.admin:
|
||||||
elif text == 'Start Game': self.__start_game()
|
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)
|
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):
|
def __guess_ref(self, text: str):
|
||||||
try:
|
try:
|
||||||
url, possible = convert_reference(text)
|
url, possible = convert_reference(text)
|
||||||
|
|
@ -83,17 +100,25 @@ class UI:
|
||||||
)
|
)
|
||||||
print(self.__verse)
|
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.start_game()
|
||||||
self.__player.new_round(difficulty)
|
self.__next_round(text)
|
||||||
|
|
||||||
def player_joined(self, name: str):
|
def player_joined(self, name: str, admin: bool):
|
||||||
if name == self.__player.name: print(f"* {name} Joined the Game *")
|
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")
|
else: print(f"{name} Joined the Game")
|
||||||
|
|
||||||
def new_verse(self, text: str):
|
def new_verse(self, text: str):
|
||||||
self.__reset()
|
self.__reset()
|
||||||
self.__in_game = True
|
self.__in_game = True
|
||||||
|
self.__in_between_rounds = False
|
||||||
self.__verse = text
|
self.__verse = text
|
||||||
print(self.__verse)
|
print(self.__verse)
|
||||||
|
|
||||||
|
|
@ -118,6 +143,9 @@ class UI:
|
||||||
f"The reference is {ref}.\n"
|
f"The reference is {ref}.\n"
|
||||||
f"You have been awarded {points} points for your guess."
|
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]):
|
def game_over(self, players: list[str], scores: list[int]):
|
||||||
self.__game_over = True
|
self.__game_over = True
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue