-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #20 from TINF21CS1/docs_new
Docs
- Loading branch information
Showing
31 changed files
with
447 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -51,4 +51,4 @@ l10n/ | |
launch.json | ||
venv | ||
*.db | ||
Client/Data/profiles.json | ||
Client/Data/profiles.json |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,26 @@ | ||
# TicTacToeKojote | ||
# TicTacToeKojote | ||
|
||
This is a simple TicTacToe game written in Python. IT can be played by two players in a GUI. However, it only works on Windows. | ||
|
||
## Installation | ||
- Install Python 3.11 or higher from [python.org](https://www.python.org/downloads/) | ||
- Install the required packages by running `pip install -r requirements.txt` from the root directory of the project | ||
- Run the game by executing `python main.py` from the root directory of the project | ||
|
||
## Features | ||
- Play TicTacToe with a friend online | ||
- Play TicTacToe with a friend offline | ||
- Play TicTacToe against an AI (weak or strong) | ||
- Chat with your opponent during the game | ||
- Create Profiles | ||
- View your game statistics whenever you are connected to a server | ||
|
||
## How to play | ||
- **Manage your player profiles:** View Use Case 1: Manage Player Profiles | ||
- **Play against AI:** View the corresponding [sequence diagram](docs/sequence_diagrams/play_vs_ai.png) | ||
- **Play against another player locally:** View the corresponding [sequence diagram](docs/sequence_diagrams/play_locally.png) | ||
- **Host an online game:** View Use Case 3.1: Host Game | ||
- **Join an online game:** View Use Case 3.2: Join Game | ||
- **Leave an online game:** View Use Case 3.3: Leave Game | ||
- **Send Chat messages:** View Use Case 4: Chat | ||
- **Display the statistics:** View Use Case 5: Display Statistics |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
@startuml AI | ||
!pragma useIntermediatePackages false | ||
|
||
class AI.ai_context.AIContext { | ||
- _strategy: AIStrategy | ||
|
||
+ AIContext(strategy: ai_strategy.AIStrategy) | ||
+ None set_strategy(strategy: ai_strategy.AIStrategy) | ||
+ None run_strategy() | ||
} | ||
class AI.ai_rulebase.AIRulebase { | ||
+ check_win(state: Server.game_state.GameState) | ||
} | ||
abstract class AI.ai_strategy.AIStrategy { | ||
- _strength: str | ||
- _good_luck_message: str | ||
- _good_game_message_lost: str | ||
- _good_game_message_won: str | ||
- _good_game_message_draw: str | ||
- _current_uuid: str | ||
- _rulebase: AI.ai_rulebase.AIRulebase | ||
- _ip: str | ||
- _port: int | ||
|
||
+ AIStrategy() | ||
- post_init() | ||
+ None thread_entry() | ||
+ None run() | ||
+ None join_game() | ||
- _message_handler(message_type: str) | ||
- wish_good_luck() | ||
- say_good_game() | ||
- list[list[int]] get_empty_cells(game_status: list[list[int]]) | ||
+ None do_turn() | ||
} | ||
|
||
class AI.ai_strategy.AdvancedAIStrategy { | ||
- _current_uuid: str | ||
- _strength: str | ||
- _good_luck_message: str | ||
- _good_game_message_lost: str | ||
- _good_game_message_won: str | ||
- _good_game_message_draw: str | ||
- _player: Server.player.Player | ||
|
||
+ AdvancedAIStrategy(uuid: str = 'd90397a5-a255-4101-9864-694b43ce8a6c') | ||
+ None do_turn() | ||
} | ||
|
||
class AI.ai_strategy.WeakAIStrategy { | ||
- _current_uuid: str | ||
- _strength: str | ||
- _good_luck_message: str | ||
- _good_game_message_lost: str | ||
- _good_game_message_won: str | ||
- _good_game_message_draw: str | ||
- _player: Server.player.Player | ||
|
||
+ WeakAIStrategy(uuid: str = '108eaa05-2b0e-4e00-a190-8856edcd56a5') | ||
- check_winning_move(empty_cells: list[list[int]], player:int) | ||
+ None do_turn() | ||
} | ||
|
||
AI.ai_context.AIContext *-- AI.ai_strategy.AIStrategy | ||
AI.ai_strategy.AIStrategy <|-- AI.ai_strategy.AdvancedAIStrategy | ||
AI.ai_strategy.AIStrategy <|-- AI.ai_strategy.WeakAIStrategy | ||
AI.ai_strategy.AIStrategy *-- AI.ai_rulebase.AIRulebase | ||
AI.ai_strategy.AIStrategy --|> Client.client.GameClient | ||
AI.ai_rulebase.AIRulebase --|> Server.rulebase.Rulebase | ||
|
||
AI.ai_strategy.AdvancedAIStrategy *-- Server.player.Player | ||
AI.ai_strategy.WeakAIStrategy *-- Server.player.Player | ||
|
||
@enduml | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
@startuml Client | ||
!pragma useIntermediatePackages false | ||
|
||
class Client.client.GameClient { | ||
- _ip: str | ||
- _port: int | ||
- _player: Player | ||
- _player_number: int | ||
- _symbol: str | ||
- _opponent: Player | ||
- _opponent_number: int | ||
- _starting_player: Player | ||
- _current_player: Player | ||
- _lobby_status: list[str] | ||
- _playfield: list[list[int]] | ||
- _statistics: Server.statistics.Statistics | ||
- _chat_history: list[tuple[Player, str]] | ||
- _winner: Player | ||
- _error_history: list[str] | ||
- _json_schema: Any | ||
|
||
+ None GameClient(ip:str, port:int, player:Player) | ||
- None connect() | ||
+ tuple[GameClient, asyncio.Task, Thread] create_game(player: Player, port:int = 8765) | ||
+ tuple[GameClient, asyncio.Task] join_game(player: Player, ip:str, port:int = 8765) | ||
+ None listen() | ||
+ Player get_player_by_uuid(uuid:str) | ||
- None _preprocess_message(message:str) | ||
- None _message_handler(message_type: str) | ||
+ None join_lobby() | ||
+ None lobby_ready(ready:bool = True) | ||
+ None lobby_kick(player_to_kick_index:int) | ||
+ None game_make_move(x:int, y:int) | ||
+ None chat_message(message:str) | ||
+ None close() | ||
+ None terminate() | ||
} | ||
|
||
class Client.ui_client.GameClientUI { | ||
- _tk_root: tk.Tk | ||
- _in_queue: queue.Queue | ||
- _out_queue: queue.Queue | ||
|
||
+ None GameClientUI(ip:str, port:int, player:Player, tk_root:tk.Tk, out_queue:Queue, in_queue:Queue) | ||
+ tuple[GameClientUI, asyncio.Task, asyncio.Task] join_game(player: Player, ip: str, tk_root:tk.Tk, out_queue:Queue, in_queue:Queue, port: int = 8765) | ||
- None listen() | ||
- None _message_handler(message_type: str) | ||
- None await_commands() | ||
- None send_gamestate_to_ui() | ||
} | ||
|
||
class Client.profile_save.Profile { | ||
+ list[Player] get_profiles() | ||
+ None set_profiles(players:list[Player], selected:int) | ||
+ None delete_all_profiles() | ||
} | ||
|
||
class Server.statistics.Statistics { | ||
} | ||
|
||
Client.client.GameClient <|-- Client.ui_client.GameClientUI | ||
Client.client.GameClient *-- Server.statistics.Statistics | ||
@enduml | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
@startuml Server | ||
!pragma useIntermediatePackages false | ||
|
||
class Server.game.Game { | ||
- _uuid: UUID | ||
- _id: int | ||
+ state: Server.gamestate.GameState | ||
+ players: list[Server.player.Player] | ||
+ rule_base: RuleBase | ||
|
||
+ Game(player1: Player, player2: Player, rule_base: RuleBase = RuleBase()) | ||
+ None move(player: int, new_position: tuple[int, int]) | ||
+ str current_player_uuid() | ||
+ Server.player.Player winner() | ||
} | ||
class Server.gamestate.GameState { | ||
- _playfield: list[list[int]] | ||
- _finished: bool | ||
- _winner: int | ||
- _current_player: int | ||
|
||
+ GameState(playfield_dimensions: tuple[int, int] = (3,3)) | ||
+ None set_player_position(player: int, new_position: tuple[int, int]) | ||
+ None set_winner(winner: int) | ||
+ int winner() | ||
+ bool finished() | ||
+ list[list[int]] playfield() | ||
+ int playfield_value(position: tuple[int, int]) | ||
+ tuple[int, int] playfield_dimensions() | ||
+ int current_player() | ||
} | ||
class Server.player.Player { | ||
+ uuid: UUID | ||
+ display_name: str | ||
+ color: int | ||
+ ready: bool | ||
|
||
+ Player(display_name: str, color: int, uuid: UUID = uuid4(), ready:bool = False) | ||
+ dict[str, Any] as_dict() | ||
+ Player from_dict(data: dict[str, Any]) | ||
} | ||
class Server.rulebase.RuleBase { | ||
- _playfield_dimensions: tuple[int, int] | ||
|
||
+ RuleBase(playfield_dimensions: tuple[int, int] = (3,3)) | ||
+ bool is_move_valid(state: GameState, new_position: tuple[int, int]) | ||
+ None check_win(state: GameState) | ||
+ bool is_game_state_valid(state: GameState) | ||
+ list[list[int]] transpose(matrix: list[list[int]]) | ||
} | ||
class Server.websocket_server.Lobby { | ||
- _players: dict[str, Server.player.Player] | ||
- _game: Server.game.Game | ||
- _inprogress: bool | ||
- _port: int | ||
- _connections: list[websockets.server.WebSocketServerProtocol] | ||
- _stats: Server.statistics.Statistics | ||
- _json_schema: dict[str, Any] | ||
|
||
+ Lobby(admin:Player, port: int = 8765) | ||
+ None handler(websocket: websockets.server.WebSocketServerProtocol) | ||
- None _end_game() | ||
+ None start_server() | ||
+ None run() | ||
} | ||
class Server.statistics.Statistics { | ||
- path: str | ||
- conn: sqlite3.Connection | ||
- cursor: sqlite3.Cursor | ||
|
||
+ Statistics(path: str = os.path.abspath('Server/Data/statistics.db')) | ||
+ list[tuple[str, int]] get_statistics() | ||
+ None increment_emojis(player: Player, message: str) | ||
+ None increment_moves(player: Player) | ||
+ None increment_games(player_list: list[Player], winner: int) | ||
- None _increment_win(player: Player) | ||
- None _increment_loss(player: Player) | ||
- None _increment_draws(player: Player) | ||
- None _check_add_profile(player: Player) | ||
- bool _check_profile(uuid_str: str) | ||
- None _add_profile(player: Player) | ||
} | ||
Server.game.Game *-- Server.rulebase.RuleBase | ||
Server.game.Game *-- Server.gamestate.GameState | ||
Server.game.Game *-- Server.player.Player | ||
Server.websocket_server.Lobby *-- Server.game.Game | ||
Server.websocket_server.Lobby *-- Server.statistics.Statistics | ||
Server.websocket_server.Lobby *-- Server.player.Player | ||
@enduml | ||
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
@startuml Server | ||
!pragma useIntermediatePackages false | ||
|
||
class Server.websocket_server.Lobby { | ||
- _connections: set[WebSocketServerProtocol] | ||
+ handler(websocket: WebSocketServerProtocol) | ||
} | ||
|
||
class websockets.WebSocketServerProtocol { | ||
+ send(message: str) | ||
+ str recv() | ||
} | ||
|
||
note left of Server.websocket_server.Lobby::handler | ||
Whenever a new connection is made, the handler is called. | ||
The handler adds the connection to the set of connections | ||
(_connections) and removes it when the connection is closed. | ||
Whenever a message is received, the handler uses | ||
websockets.broadcast() to send the updated game state to all | ||
connections in _connections. | ||
end note | ||
|
||
note bottom of websockets.WebSocketServerProtocol | ||
The WebSocketServerProtocol is a protocol that is used to | ||
handle the WebSocket connection. It has methods to send and | ||
receive messages, and it also has methods to handle the | ||
opening and closing of the connection. | ||
end note | ||
|
||
Server.websocket_server.Lobby o-- websockets.WebSocketServerProtocol | ||
@enduml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
@startuml | ||
title Create Player Profile | ||
|
||
actor Player | ||
database Client | ||
|
||
Player->Client: Click Profile Button | ||
Client->Player: Show Profile Creation Prompt | ||
Player->Client: Set Name | ||
Player->Client: Set Color | ||
Player->Client: Click Create Profile Button | ||
Client->Client: Save Profile on Disk | ||
Client->Player: Show Profile | ||
|
||
@enduml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@startuml | ||
title Delete Player Profile | ||
|
||
actor Player | ||
database Client | ||
|
||
Player->Client: Click Profile Button | ||
Client->Player: Show Profile | ||
Player->Client: Click Delete Profile Button | ||
Client->Client: Delete Profile from Disk | ||
Client->Player: Show Profile Creation Prompt | ||
|
||
@enduml |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.