Skip to content

Commit 9d2dad0

Browse files
pre-commit-ci[bot]amcsz
authored andcommitted
[pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
1 parent 45e9a22 commit 9d2dad0

10 files changed

Lines changed: 98 additions & 78 deletions

File tree

othello/apps/games/admin.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from django.contrib import admin
22

3-
from .models import Game, GameError, Submission, Match
3+
from .models import Game, GameError, Match, Submission
44

55

66
class GameErrorAdmin(admin.TabularInline):
@@ -17,6 +17,7 @@ class GameAdmin(admin.ModelAdmin):
1717
class SubmissionAdmin(admin.ModelAdmin):
1818
readonly_fields = ("id",)
1919

20+
2021
class MatchAdmin(admin.ModelAdmin):
2122
readonly_fields = ("id",)
2223

othello/apps/games/consumers.py

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ def connect(self) -> None:
3535
self.game.channels_group_name, self.channel_name
3636
)
3737

38-
# Send initial game state
3938
self.update_game()
4039

4140
def disconnect(self, code: int) -> None:
@@ -87,9 +86,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
8786
def connect(self) -> None:
8887
self.connected = True
8988
self.accept()
90-
async_to_sync(self.channel_layer.group_add)(
91-
"matches", self.channel_name
92-
)
89+
async_to_sync(self.channel_layer.group_add)("matches", self.channel_name)
9390

9491
def disconnect(self, code: int) -> None:
9592
self.connected = False
@@ -101,19 +98,21 @@ def send_match_update(self, object_id: int) -> None:
10198
if self.connected:
10299
match = Match.objects.get(id=object_id)
103100
score = "-"
104-
if match.status == 'completed':
101+
if match.status == "completed":
105102
score = f"{match.player1_wins}-{match.ties}-{match.player2_wins}"
106-
self.send_json({
107-
'type': 'match_update',
108-
'match_id': match.id,
109-
'status': match.status,
110-
'player1': match.player1.get_game_name(),
111-
'player2': match.player2.get_game_name(),
112-
'num_games': match.num_games,
113-
'score': score,
114-
'created_at': match.created_at.isoformat(),
115-
})
116-
103+
self.send_json(
104+
{
105+
"type": "match_update",
106+
"match_id": match.id,
107+
"status": match.status,
108+
"player1": match.player1.get_game_name(),
109+
"player2": match.player2.get_game_name(),
110+
"num_games": match.num_games,
111+
"score": score,
112+
"created_at": match.created_at.isoformat(),
113+
}
114+
)
115+
117116

118117
class GamePlayingConsumer(GameConsumer):
119118
def connect(self) -> None:

othello/apps/games/forms.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from django.core.exceptions import ValidationError
88

99
from ...sandboxing import import_strategy_sandboxed
10-
from .models import Match, Submission
10+
from .models import Submission
1111

1212

1313
class SubmissionForm(forms.ModelForm):
@@ -77,12 +77,12 @@ class Meta:
7777

7878
class MatchForm(forms.Form):
7979
opponent = forms.ModelChoiceField(label="Opponent:", queryset=Submission.objects.none())
80-
num_games = forms.IntegerField(
81-
label="Number of Games:", initial=3, min_value=1, max_value=10
82-
)
80+
num_games = forms.IntegerField(label="Number of Games:", initial=3, min_value=1, max_value=10)
8381

8482
def __init__(self, user, *args: Any, **kwargs: Any) -> None:
8583
super().__init__(*args, **kwargs)
86-
opponents = Submission.objects.latest().exclude(user=user).exclude(user__username="Yourself")
84+
opponents = (
85+
Submission.objects.latest().exclude(user=user).exclude(user__username="Yourself")
86+
)
8787
self.fields["opponent"].queryset = opponents
88-
self.fields["opponent"].label_from_instance = Submission.get_game_name
88+
self.fields["opponent"].label_from_instance = Submission.get_game_name

othello/apps/games/models.py

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ def latest(self, onesub=False, **kwargs: Any) -> "models.query.QuerySet[Submissi
3737
.distinct("user")
3838
.order_by("user", "-tournament_win_year", "-created_at")
3939
)
40-
40+
41+
4142
class Submission(models.Model):
4243
objects: Any = SubmissionQuerySet.as_manager()
4344

@@ -58,7 +59,7 @@ class Meta:
5859
check=models.Q(user__isnull=False) | models.Q(name__isnull=False),
5960
)
6061
]
61-
get_latest_by = 'created_at'
62+
get_latest_by = "created_at"
6263

6364
def get_user_name(self) -> str:
6465
return self.user.short_name
@@ -98,31 +99,39 @@ def wins_for_user(self, submission: Submission) -> int:
9899
)
99100
.count()
100101
)
101-
102+
103+
102104
class MatchQuerySet(models.QuerySet):
103105
def running(self) -> "models.query.QuerySet[Match]":
104-
return self.filter(status='running')
105-
106+
return self.filter(status="running")
106107

107108

108109
class Match(models.Model):
109110
STATUS_CHOICES = (
110-
('pending', 'Pending'),
111-
('running', 'Running'),
112-
('completed', 'Completed'),
111+
("pending", "Pending"),
112+
("running", "Running"),
113+
("completed", "Completed"),
113114
)
114115

115116
objects: Any = MatchQuerySet.as_manager()
116117

117-
player1 = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name='matches_as_player1')
118-
player2 = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name='matches_as_player2')
118+
player1 = models.ForeignKey(
119+
Submission, on_delete=models.CASCADE, related_name="matches_as_player1"
120+
)
121+
player2 = models.ForeignKey(
122+
Submission, on_delete=models.CASCADE, related_name="matches_as_player2"
123+
)
119124
num_games = models.IntegerField(default=5)
120-
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
125+
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
121126
created_at = models.DateTimeField(auto_now_add=True)
122127

123128
# Results
124-
winner = models.ForeignKey(Submission, null=True, blank=True, on_delete=models.CASCADE, related_name='won_matches')
125-
loser = models.ForeignKey(Submission, null=True, blank=True, on_delete=models.CASCADE, related_name='lost_matches')
129+
winner = models.ForeignKey(
130+
Submission, null=True, blank=True, on_delete=models.CASCADE, related_name="won_matches"
131+
)
132+
loser = models.ForeignKey(
133+
Submission, null=True, blank=True, on_delete=models.CASCADE, related_name="lost_matches"
134+
)
126135
is_tie = models.BooleanField(default=False)
127136
player1_wins = models.IntegerField(default=0)
128137
player2_wins = models.IntegerField(default=0)
@@ -169,7 +178,9 @@ def calculate_results(self) -> None:
169178
self.winner = None
170179
self.loser = None
171180

172-
self.save(update_fields=['player1_wins', 'player2_wins', 'ties', 'winner', 'loser', 'is_tie'])
181+
self.save(
182+
update_fields=["player1_wins", "player2_wins", "ties", "winner", "loser", "is_tie"]
183+
)
173184

174185
def __str__(self) -> str:
175186
return f"{self.player1.get_game_name()} vs {self.player2.get_game_name()} ({self.num_games} games)"
@@ -187,7 +198,9 @@ class Game(models.Model):
187198

188199
black = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name="black")
189200
white = models.ForeignKey(Submission, on_delete=models.CASCADE, related_name="white")
190-
match = models.ForeignKey(Match, null=True, blank=True, on_delete=models.CASCADE, related_name="games")
201+
match = models.ForeignKey(
202+
Match, null=True, blank=True, on_delete=models.CASCADE, related_name="games"
203+
)
191204
time_limit = models.IntegerField(default=5, validators=[validate_game_time_limit])
192205
runoff = models.BooleanField(default=False)
193206

@@ -250,4 +263,4 @@ class GameError(GameObject):
250263

251264
class GameLog(GameObject):
252265
game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="logs")
253-
message = models.TextField(default="")
266+
message = models.TextField(default="")

othello/apps/games/tasks.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def delete_game(game: Game) -> None:
3737
game.delete()
3838

3939

40-
@shared_task(queue='game_queue')
40+
@shared_task(queue="game_queue")
4141
def run_game(game_id: int) -> str | None:
4242
try:
4343
game = Game.objects.get(id=game_id)
@@ -189,7 +189,7 @@ def run_game(game_id: int) -> str | None:
189189

190190
if game.match and not game.match.games.filter(playing=True).exists():
191191
task_logger.info(f"MATCH {game.match.id} OVER")
192-
game.match.status = 'completed'
192+
game.match.status = "completed"
193193
game.match.save(update_fields=["status"])
194194
game.match.calculate_results()
195195
async_to_sync(get_channel_layer().group_send)(
@@ -217,8 +217,8 @@ def run_match(match_id: int) -> str | None:
217217
logger.error(f"Trying to run nonexistent match ({match_id})")
218218
return "match not found"
219219

220-
match.status = 'running'
221-
match.save(update_fields=['status'])
220+
match.status = "running"
221+
match.save(update_fields=["status"])
222222
send_through_match_channel(match, "match.update", match_id)
223223

224224
games = []
@@ -244,4 +244,4 @@ def send_through_match_channel(match: Match, event_type: str, object_id: int) ->
244244
task_logger.debug(f"sending {event_type}")
245245
async_to_sync(get_channel_layer().group_send)(
246246
match.channels_group_name, {"type": event_type, "object_id": object_id}
247-
)
247+
)

othello/apps/games/views.py

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
from .forms import DownloadSubmissionForm, GameForm, MatchForm, SubmissionForm
1313
from .models import Game, Match, Submission
14-
from .utils import serialize_game_info
1514
from .tasks import run_match
15+
from .utils import serialize_game_info
1616

1717
logger = logging.getLogger("othello")
1818

@@ -111,6 +111,7 @@ def play(request: HttpRequest) -> HttpResponse:
111111
initial = json.loads(request.session.get("form-data", "{}"))
112112
return render(request, "games/design.html", {"form": GameForm(initial=initial)})
113113

114+
114115
@login_required
115116
def request_match(request: HttpRequest) -> HttpResponse:
116117
if request.method == "POST":
@@ -119,23 +120,32 @@ def request_match(request: HttpRequest) -> HttpResponse:
119120
cd = form.cleaned_data
120121

121122
one_hour_ago = timezone.now() - timezone.timedelta(hours=1)
122-
recent_games = Match.objects.filter(
123-
models.Q(player1__user=request.user) | models.Q(player2__user=request.user),
124-
created_at__gte=one_hour_ago
125-
).aggregate(total_games=models.Sum('num_games'))['total_games'] or 0
126-
if recent_games + cd['num_games'] > 100:
127-
messages.error(request, "You have exceeded the limit of 100 games per hour.", extra_tags="danger")
123+
recent_games = (
124+
Match.objects.filter(
125+
models.Q(player1__user=request.user) | models.Q(player2__user=request.user),
126+
created_at__gte=one_hour_ago,
127+
).aggregate(total_games=models.Sum("num_games"))["total_games"]
128+
or 0
129+
)
130+
if recent_games + cd["num_games"] > 100:
131+
messages.error(
132+
request,
133+
"You have exceeded the limit of 100 games per hour.",
134+
extra_tags="danger",
135+
)
128136
return redirect("games:request_match")
129137

130138
user_submission = Submission.objects.filter(user=request.user).latest(onesub=True)
131139
if not user_submission:
132-
messages.error(request, f"Could not request match because you do not have a submission")
140+
messages.error(
141+
request, "Could not request match because you do not have a submission"
142+
)
133143
return redirect("games:queue")
134-
144+
135145
match = Match.objects.create(
136146
player1=user_submission,
137-
player2=cd['opponent'],
138-
num_games=cd['num_games'],
147+
player2=cd["opponent"],
148+
num_games=cd["num_games"],
139149
)
140150
run_match.delay(match.id)
141151
messages.success(request, f"Match requested against {cd['opponent'].get_game_name()}.")
@@ -151,12 +161,13 @@ def request_match(request: HttpRequest) -> HttpResponse:
151161

152162
@login_required
153163
def queue(request: HttpRequest) -> HttpResponse:
154-
matches = Match.objects.all().order_by('-created_at')
164+
matches = Match.objects.all().order_by("-created_at")
155165
paginator = Paginator(matches, 10) # 10 per page
156-
page_number = request.GET.get('page')
166+
page_number = request.GET.get("page")
157167
page_obj = paginator.get_page(page_number)
158168
return render(request, "games/queue.html", {"page_obj": page_obj})
159169

170+
160171
def watch(request: HttpRequest, game_id: int | None = None) -> HttpResponse:
161172
if game_id is not None:
162173
return render(
@@ -177,23 +188,27 @@ def replay(request: HttpRequest) -> HttpResponse:
177188
@login_required
178189
def match_replay(request: HttpRequest, match_id: int) -> HttpResponse:
179190
match = get_object_or_404(Match, id=match_id)
180-
games = list(match.games.order_by('created_at'))
181-
selected_game_id = request.GET.get('game_id')
191+
games = list(match.games.order_by("created_at"))
192+
selected_game_id = request.GET.get("game_id")
182193
if selected_game_id:
183194
selected_game = get_object_or_404(Game, id=selected_game_id, match=match)
184195
elif games:
185196
selected_game = games[0]
186197
else:
187198
selected_game = None
188-
199+
189200
game_data = serialize_game_info(selected_game) if selected_game else None
190-
191-
return render(request, 'games/match_replay.html', {
192-
'match': match,
193-
'games': games,
194-
'selected_game': selected_game,
195-
'game_data': game_data,
196-
})
201+
202+
return render(
203+
request,
204+
"games/match_replay.html",
205+
{
206+
"match": match,
207+
"games": games,
208+
"selected_game": selected_game,
209+
"game_data": game_data,
210+
},
211+
)
197212

198213

199214
def about(request: HttpRequest) -> HttpResponse:

othello/settings/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"default": {
2121
"BACKEND": "channels_redis.core.RedisChannelLayer",
2222
"CONFIG": {
23-
"hosts": [("othello_redis", 6379)],
23+
"hosts": [("localhost", 6379)],
2424
"capacity": 1500,
2525
"expiry": 2,
2626
},
@@ -144,7 +144,7 @@
144144

145145
# Celery
146146
CELERY_RESULT_BACKEND = "django-db"
147-
CELERY_BROKER_URL = "redis://othello_redis:6379/1"
147+
CELERY_BROKER_URL = "redis://localhost:6379/1"
148148
CELERY_TIMEZONE = "America/New_York"
149149
CELERY_BEAT_SCHEDULE = {
150150
"delete-old-games": {

othello/static/js/games/match_replay.js

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ function clearErrors(){
2020
$("pre.err_log").remove();
2121
}
2222

23-
// Convert Django game data to replay format
2423
function convertGameDataToReplay(gameData) {
2524
if (!gameData || !gameData.moves) {
2625
return null;
@@ -32,11 +31,6 @@ function convertGameDataToReplay(gameData) {
3231
game: []
3332
};
3433

35-
// Standard Othello initial board
36-
const initialBoard = '...........................ox......xo...........................';
37-
let blackCount = (initialBoard.match(/x/g) || []).length;
38-
let whiteCount = (initialBoard.match(/o/g) || []).length;
39-
4034
for (let i = gameData.moves.length - 1; i >= 0; i--) {
4135
let move = gameData.moves[i];
4236
let board = move.board;
@@ -115,6 +109,5 @@ window.onload = function () {
115109

116110
$(document).on('mousemove', mouseOver);
117111

118-
// Start the match replay
119112
startMatchReplay();
120113
};

0 commit comments

Comments
 (0)