aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaran Jayachandra <karan.jayachandra@nxp.com>2024-10-11 16:59:45 +0200
committerKaran Jayachandra <karan.jayachandra@nxp.com>2024-10-11 16:59:45 +0200
commit0db0ff2f1c712273ac48cb859c24253b1efa8384 (patch)
treeb92c4bd847ca94ad5cdf5a0b85576328484ff061
parent39a01979a470e836da1128503e4587cb76eeae33 (diff)
First working version with court selection
-rw-r--r--app.py45
-rw-r--r--model.py129
-rw-r--r--templates/court.j21
-rw-r--r--templates/courts.j210
-rw-r--r--templates/games.j22
-rw-r--r--templates/index.j218
6 files changed, 150 insertions, 55 deletions
diff --git a/app.py b/app.py
index 16659ec..9f4caed 100644
--- a/app.py
+++ b/app.py
@@ -1,5 +1,5 @@
from os import getenv
-from model import PlayerList, GameList
+from model import CourtList, PlayerList, GameList
from flask import Flask, abort, render_template, request
from dotenv import load_dotenv
@@ -8,7 +8,8 @@ load_dotenv()
print("Importing player list...\n")
PLAYER_LIST = PlayerList(location="test_data.csv")
-GAME_GENERATOR = GameList()
+COURT_LIST = CourtList(12)
+GAME_GENERATOR = GameList(COURT_LIST)
print("List of player:\n")
print(PLAYER_LIST)
@@ -22,21 +23,9 @@ def home():
return render_template("index.j2")
-# @app.route("/courts", methods=["POST"])
-# def set_courts():
-# print(request)
-# print(request.data)
-# print(request.json)
-# print(request.args)
-# return render_template(
-# "courts.j2",
-# courts=GAME_GENERATOR.courts,
-# )
-
-
@app.route("/new-games", methods=["POST"])
def get_new_games():
- GAME_GENERATOR.create_games(PLAYER_LIST.get_active_players())
+ GAME_GENERATOR.create_games(COURT_LIST, PLAYER_LIST)
return render_template(
"games.j2",
games=GAME_GENERATOR.games,
@@ -70,3 +59,29 @@ def get_list_of_players():
"players.j2",
players=PLAYER_LIST.players,
)
+
+
+@app.route("/court-toggle/<court_number>", methods=["POST"])
+def toggle_court(court_number):
+ court_number = int(court_number)
+ selection = COURT_LIST.get_court(court_number)
+ print(len(selection))
+ print(selection)
+ if len(selection) != 1:
+ abort(404, f"Multiple courts requested: {len(selection)}")
+ print(COURT_LIST.courts)
+ COURT_LIST.toggle_court(court_number)
+ print(COURT_LIST.courts)
+ selection = COURT_LIST.get_court(court_number)
+ return render_template(
+ "court.j2",
+ court=selection[0],
+ )
+
+
+@app.route("/court-list", methods=["GET"])
+def get_list_of_courts():
+ return render_template(
+ "courts.j2",
+ courts=COURT_LIST.courts,
+ )
diff --git a/model.py b/model.py
index 4a25400..1d6217b 100644
--- a/model.py
+++ b/model.py
@@ -2,26 +2,47 @@ from math import floor
from csv import reader
from pathlib import Path
from random import sample
+from operator import attrgetter
from dataclasses import dataclass
@dataclass
-class Player:
- name: str
- skill: int
+class Court:
+ number: int
status: bool
@dataclass
-class Team:
- player1: Player
- player2: Player
+class CourtList:
+ total: int
+
+ def __post_init__(self):
+ self.courts = [Court(i + 1, True) for i in range(self.total)]
+ self.active = self.total
+
+ def get_court(self, court_number: int):
+ return [court for court in self.courts if court.number == court_number]
+
+ def toggle_court(self, court_number: int):
+ self.courts = [
+ (
+ Court(
+ number=court_number,
+ status=not court.status,
+ )
+ if court_number == court.number
+ else court
+ )
+ for court in self.courts
+ ]
+ self.active = sum([court.status for court in self.courts])
@dataclass
-class Game:
- team1: Team
- team2: Team
+class Player:
+ name: str
+ skill: int = 0
+ status: bool = True
class PlayerList:
@@ -68,33 +89,81 @@ class PlayerList:
return display_string
-TOTAL_PLAYERS_PER_COURT = 4
-DUMMY_PLAYER = Player(name="-", skill=0, status=True)
+@dataclass
+class Team:
+ player1: Player
+ player2: Player
+
+
+@dataclass
+class Game:
+ court: Court
+ team1: Team
+ team2: Team
+
+
+DUMMY_PLAYER = Player(name="-")
DUMMY_TEAM = Team(player1=DUMMY_PLAYER, player2=DUMMY_PLAYER)
-DUMMY_GAME = Game(DUMMY_TEAM, DUMMY_TEAM)
+
+
+def create_dummy_games(courts: list[Court]):
+ return [Game(court, DUMMY_TEAM, DUMMY_TEAM) for court in courts]
+
+
+RESERVED_PLAYER = Player(name="Reserved")
+RESERVED_TEAM = Team(player1=RESERVED_PLAYER, player2=RESERVED_PLAYER)
+
+
+def create_reserved_games(courts: list[Court]):
+ return [Game(court, RESERVED_TEAM, RESERVED_TEAM) for court in courts]
+
+
+PLAYER_PER_COURT = 4
+
+
+def create_single_game(court: Court, players: list[Player]):
+ team1 = Team(player1=players[0], player2=players[1])
+ team2 = Team(player1=players[2], player2=players[3])
+ return Game(court, team1, team2)
+
+
+def create_possible_games(court_list: list[Court], players: list[Player]):
+ current_players = sample(players, len(court_list) * PLAYER_PER_COURT)
+ clumped_players = [
+ current_players[i : i + PLAYER_PER_COURT]
+ for i in range(0, len(current_players), PLAYER_PER_COURT)
+ ]
+ games = [
+ create_single_game(court, clump)
+ for court, clump in zip(court_list, clumped_players)
+ ]
+ return games
@dataclass
class GameList:
- courts: int = 8
+ court_list: CourtList
def __post_init__(self):
- self.games = [DUMMY_GAME for _ in range(self.courts)]
+ courts = self.court_list.courts
+ active_courts = [court for court in courts if court.status]
+ inactive_courts = [court for court in courts if not court.status]
+ dummy_games = create_dummy_games(active_courts)
+ reserved_games = create_reserved_games(inactive_courts)
+ games = dummy_games + reserved_games
+ games.sort(key=attrgetter("court.number"))
+ self.games = games
- def create_games(self, players: list[Player]):
- possible_games = floor(len(players) / TOTAL_PLAYERS_PER_COURT)
- chosen_players = sample(players, possible_games * TOTAL_PLAYERS_PER_COURT)
- clumped_players = [
- chosen_players[i : i + TOTAL_PLAYERS_PER_COURT]
- for i in range(0, len(chosen_players), TOTAL_PLAYERS_PER_COURT)
- ]
- games = []
- for clump in clumped_players:
- team1 = Team(player1=clump[0], player2=clump[1])
- team2 = Team(player1=clump[2], player2=clump[3])
- game = Game(team1, team2)
- games.append(game)
- empty_courts = (
- self.courts - possible_games if self.courts > possible_games else 0
+ def create_games(self, court_list: CourtList, player_list: PlayerList):
+ active_players = player_list.get_active_players()
+ active_courts = [court for court in court_list.courts if court.status]
+ inactive_courts = [court for court in court_list.courts if not court.status]
+ possible_games = floor(len(active_players) / PLAYER_PER_COURT)
+ active_games = create_possible_games(
+ active_courts[:possible_games], active_players
)
- self.games = games + [DUMMY_GAME for _ in range(empty_courts)]
+ dummy_games = create_dummy_games(active_courts[possible_games:])
+ reserved_games = create_reserved_games(inactive_courts)
+ games = active_games + dummy_games + reserved_games
+ games.sort(key=attrgetter("court.number"))
+ self.games = games
diff --git a/templates/court.j2 b/templates/court.j2
new file mode 100644
index 0000000..6ae4d91
--- /dev/null
+++ b/templates/court.j2
@@ -0,0 +1 @@
+<button class={% if court.status %} "active" {% else %} "dormant" {% endif %} hx-post="{{ "/court-toggle/" ~ court.number}}" hx-trigger="click" hx-swap="outerHTML">{{ court.number }}</button> \ No newline at end of file
diff --git a/templates/courts.j2 b/templates/courts.j2
index a7893a7..3134aca 100644
--- a/templates/courts.j2
+++ b/templates/courts.j2
@@ -1,3 +1,7 @@
-<form hx-post="/courts" hx-trigger="change" hx-swap="outerHTML">
- <input type="number" disabled id="courts" min="1" max="15" name="courts" value="{{ courts }}">
-</form> \ No newline at end of file
+<div class="grid-container">
+{% for court in courts %}
+ <div class="grid-item">
+ <button class={% if court.status %} "active" {% else %} "dormant" {% endif %} hx-post="{{ "/court-toggle/" ~ court.number}}" hx-trigger="click" hx-swap="outerHTML">{{ court.number }}</button>
+ </div>
+{% endfor %}
+</div> \ No newline at end of file
diff --git a/templates/games.j2 b/templates/games.j2
index 22ea936..83fff7f 100644
--- a/templates/games.j2
+++ b/templates/games.j2
@@ -7,7 +7,7 @@
</tr>
{% for game in games %}
<tr>
- <th>{{ loop.index }}</th>
+ <th>{{ game.court.number }}</th>
<td>{{ game.team1.player1.name }}</th>
<td>{{ game.team1.player2.name }}</th>
<td>{{ game.team2.player1.name }}</th>
diff --git a/templates/index.j2 b/templates/index.j2
index be92207..a9c451f 100644
--- a/templates/index.j2
+++ b/templates/index.j2
@@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🏸Match Up!</title>
- <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
- <script src="https://unpkg.com/htmx.org@1.9.11"></script>
+ <link rel="stylesheet" href="https://unpkg.com/sakura.css/css/sakura.css" type="text/css">
+ <script src="https://unpkg.com/htmx.org@2.0.0/dist/htmx.min.js"></script>
<style>
button {
height: 50px;
@@ -23,25 +23,31 @@
row-gap: 20px;
column-gap: 20px;
}
- .tagline {
- text-align: center;
+ hr {
+ margin-top: 1cm;
}
</style>
</head>
<body>
<header>
- <h1>🏸The Smashing Fellows </h1>
- <h4> Total Courts: 8</h4>
+ <h4>🏸The Smashing Fellows </h4>
</header>
+ <hr>
<div>
<h2>Games</h2>
<div class="games" hx-get="/game-list" hx-swap="outerHTML" hx-trigger="revealed"></div>
</div>
<button hx-post="/new-games" hx-trigger="click" hx-target=".games" hx-swap="outerHTML"> New Games </button>
<div class="players">
+ <h2>Courts</h2>
+ <div hx-get="/court-list" hx-swap="outerHTML" hx-trigger="revealed"></div>
+ </div>
+ <hr>
+ <div class="players">
<h2>Players</h2>
<div hx-get="/player-list" hx-swap="outerHTML" hx-trigger="revealed"></div>
</div>
+ <hr>
<footer>
Made by <a href="https://karanjayachandra.com/">K. Jayachandra</a> using <a href="https://htmx.org/">HTMX</a> and <a href="https://flask.palletsprojects.com">Flask</a>
</footer>