diff --git a/games/README.md b/games/README.md
new file mode 100644
index 0000000..e15f459
--- /dev/null
+++ b/games/README.md
@@ -0,0 +1,4 @@
+# ABANDONED
+
+This app (the `/games` directory) is abandoned.
+It needs to stick around for compatibility reasons, but otherwise do not use this.
diff --git a/games/models.py b/games/models.py
index bf6c321..69cc7df 100644
--- a/games/models.py
+++ b/games/models.py
@@ -25,6 +25,7 @@ class RPSMove(models.Model):
user = models.ForeignKey(ActiveUser, on_delete=models.CASCADE)
choice = models.CharField(max_length=8)
+# Create your models here.
class MinesweeperBoard(models.Model):
class Status(models.IntegerChoices):
IN_PROGRESS = 0
diff --git a/minesweeper/__init__.py b/minesweeper/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/games/admin.py b/minesweeper/admin.py
similarity index 100%
rename from games/admin.py
rename to minesweeper/admin.py
diff --git a/minesweeper/apps.py b/minesweeper/apps.py
new file mode 100644
index 0000000..4b289fb
--- /dev/null
+++ b/minesweeper/apps.py
@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class MinesweeperConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'minesweeper'
diff --git a/minesweeper/consumers.py b/minesweeper/consumers.py
new file mode 100644
index 0000000..6edd37d
--- /dev/null
+++ b/minesweeper/consumers.py
@@ -0,0 +1,212 @@
+import json
+from channels.generic.websocket import WebsocketConsumer
+from asgiref.sync import async_to_sync
+# TODO: rename
+from games.models import MinesweeperBoard, MinesweeperCell
+from common.models import LameUser
+from django.db.models import Q
+import random
+
+class MinesweeperConsumer(WebsocketConsumer):
+ def xy_to_pos(self, x, y):
+ return (y * self.board.width) + x
+ def pos_to_xy(self, pos):
+ return (pos % self.board.width, pos // self.board.height)
+
+ def send_client(self, tpy, msg):
+ self.send(json.dumps({
+ 'type': tpy,
+ 'payload': msg
+ }))
+
+ def hit_bomb(self, sq):
+ self.send_client('change-board', [{
+ 'x': sq.x,
+ 'y': sq.y,
+ 'flagged': sq.flagged,
+ 'bomb': sq.bomb,
+ 'bombs_next': sq.bombs_next
+ }])
+ self.lose()
+
+ def client_selected_square(self, pos):
+ x, y = self.pos_to_xy(pos)
+ reved = self.reveal(x, y, [])
+ print(reved)
+ if len(reved) == 0:
+ self.hit_bomb(self.board.cells.get(x=x, y=y))
+ else:
+ self.send_client('change-board', reved)
+ self.save_revealed(reved)
+
+ def check_win(self):
+ if self.has_won():
+ self.win()
+
+ def has_won(self):
+ shown = list(self.board.cells.filter(shown=True))
+ not_bombs = list(self.board.cells.filter(bomb=False))
+ return shown == not_bombs
+
+ def win(self):
+ self.send_client('message', 'You win!')
+ self.board.status = self.board.Status.WON
+ self.board.save()
+
+ def send_new_board(self):
+ self.send_client('new_board', '')
+ self.send_client('message', 'New board generated!')
+
+ def flag_tile(self, pos):
+ x, y = self.pos_to_xy(pos)
+ cell = MinesweeperCell.objects.get(x=x, y=y, board=self.board)
+ if not cell.flagged:
+ cell.shown = False
+ cell.flagged = not cell.flagged
+ cell.save()
+
+ def send_shown_flagged(self):
+ if (self.board.is_game_over()):
+ self.send_client('change-board', [
+ x.as_full_dict() for x in self.board.cells.all()
+ ])
+ else:
+ shown = [{'x': x.x, 'y': x.y, 'bombs_next': x.bombs_next} for x in list(self.board.cells.filter(shown=True))]
+ flagged = [{'x': x.x, 'y': x.y, 'flagged': True} for x in list(self.board.cells.filter(flagged=True))]
+ self.send_client('change-board', shown + flagged)
+
+ def save_revealed(self, revealed_squares):
+ # edit database so user can come back later
+ for cell in revealed_squares:
+ dbcell = MinesweeperCell.objects.get(x=cell['x'], y=cell['y'], board=self.board)
+ dbcell.shown = True
+ dbcell.flagged = False
+ dbcell.save()
+
+ def valid_pos(self, x, y):
+ return x >= 0 and x < self.board.width and y >= 0 and y < self.board.height
+
+ def reveal(self, x, y, already_revealed):
+ if not self.valid_pos(x, y):
+ return already_revealed
+ # if already checked
+ for rev in already_revealed:
+ if rev['x'] == x and rev['y'] == y:
+ return already_revealed
+
+ tile = self.board.cells.get(x=x, y=y)
+ # if is bomb
+ if tile.bomb:
+ return already_revealed
+ elif tile.bombs_next > 0:
+ already_revealed.append({
+ 'x': x,
+ 'y': y,
+ 'bombs_next': self.cells[y][x]
+ })
+ return already_revealed
+ # if bombs_next is 0
+ already_revealed.append({
+ 'x': x,
+ 'y': y,
+ 'bombs_next': 0
+ })
+
+ for xd in range(-1, 2):
+ for yd in range(-1, 2):
+ nx = x+xd
+ ny = y+yd
+ # jump over middle square
+ if nx == x and ny == y:
+ continue
+ self.reveal(nx, ny, already_revealed)
+ return already_revealed
+
+ def select_board_if_exists(self):
+ # if user has a board already available: use it instead
+ current_board = MinesweeperBoard.objects.filter(user=self.user)
+ if len(current_board) > 0:
+ self.board = current_board[0]
+ self.cells = [[0 for _ in range(self.board.width)] for _ in range(self.board.height)]
+ for cell in self.board.cells.all():
+ self.cells[cell.y][cell.x] = '*' if cell.bomb else cell.bombs_next
+ return True
+ self.board_generator()
+
+ # TODO: make more efficient
+ # TODO: make easier to read
+ # TODO: Move to seperate file
+ def board_generator(self):
+ self.board = MinesweeperBoard.objects.create(user=self.user)
+ self.cells = []
+ for y in range(self.board.height):
+ self.cells.append([])
+ for x in range(self.board.width):
+ self.cells[y].append(0)
+ placed_bombs = 0
+ while placed_bombs < 15:
+ rand = random.randint(0, (self.board.width * self.board.height)-1)
+
+ x = rand % 10
+ y = rand // 10
+ if self.cells[y][x] != '*':
+ self.cells[y][x] = '*'
+ placed_bombs += 1
+ for y in range(self.board.height):
+ for x in range(self.board.width):
+ i = (y*self.board.width) + x
+ if self.cells[y][x] != '*':
+ # This finds the number of bombs within the 8 squares surrounding
+ check_matrix = [
+ (-1, -1),
+ (-1, 0),
+ (-1, 1),
+ (0, -1),
+ (0, 1),
+ (1, -1),
+ (1, 0),
+ (1, 1)
+ ]
+ bombs_around = 0
+ for p,q in check_matrix:
+ if self.valid_pos(p+y, q+x):
+ if self.cells[y+p][x+q] == '*':
+ bombs_around += 1
+ self.cells[y][x] = bombs_around
+ m = MinesweeperCell.objects.create(
+ x=x,
+ y=y,
+ bombs_next=self.cells[y][x] if self.cells[y][x] != '*' else 0,
+ bomb=self.cells[y][x] == '*',
+ board=self.board,
+ shown=False
+ )
+ def lose(self):
+ self.send_client('message', 'You hit a bomb!')
+ self.board.status = self.board.Status.LOST
+ # This will remove all flags; I believe this is the classic behaviour
+ self.board.cells.all().update(flagged=False)
+ self.board.save()
+ self.send_shown_flagged()
+
+ def connect(self):
+ self.accept()
+ self.user = LameUser.objects.get(username=self.scope['user'].username)
+ self.select_board_if_exists()
+ self.send_shown_flagged()
+
+ def disconnect(self, close_code):
+ pass
+
+ def receive(self, text_data):
+ data = json.loads(text_data)
+ if data['type'] == 'generate':
+ self.board.delete()
+ self.send_new_board()
+ self.board_generator()
+ elif data['type'] == 'clicked' and not self.board.is_game_over():
+ self.client_selected_square(data['button_id'])
+ self.check_win()
+ elif data['type'] == 'flagged' and not self.board.is_game_over():
+ self.flag_tile(data['button_id'])
+
diff --git a/minesweeper/migrations/__init__.py b/minesweeper/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/games/tests.py b/minesweeper/tests.py
similarity index 100%
rename from games/tests.py
rename to minesweeper/tests.py
diff --git a/minesweeper/urls.py b/minesweeper/urls.py
new file mode 100644
index 0000000..f928a47
--- /dev/null
+++ b/minesweeper/urls.py
@@ -0,0 +1,6 @@
+from django.urls import path
+from . import views
+
+urlpatterns = [
+ path('minesweeper/', views.minesweeper, name='minesweeper')
+]
diff --git a/minesweeper/views.py b/minesweeper/views.py
new file mode 100644
index 0000000..9ce1d94
--- /dev/null
+++ b/minesweeper/views.py
@@ -0,0 +1,17 @@
+from django.shortcuts import (
+ render, HttpResponse, redirect
+)
+from django.urls import reverse
+# TODO: rename
+from games.models import MinesweeperBoard
+
+def minesweeper(request):
+ board = MinesweeperBoard.objects.filter(user=request.user)
+ if len(board) > 0:
+ board = board[0]
+ else:
+ board = MinesweeperBoard.objects.create(user=request.user)
+ id_board = [[(y*board.width)+x for x in range(board.width)] for y in range(board.height)]
+ return render(request, 'games/minesweeper/minesweeper.html', {
+ 'board': id_board
+ })
diff --git a/rps/__init__.py b/rps/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/rps/admin.py b/rps/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/rps/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/games/apps.py b/rps/apps.py
similarity index 100%
rename from games/apps.py
rename to rps/apps.py
diff --git a/games/consumers.py b/rps/consumers.py
similarity index 99%
rename from games/consumers.py
rename to rps/consumers.py
index 74567a5..5ecdd7e 100644
--- a/games/consumers.py
+++ b/rps/consumers.py
@@ -1,7 +1,7 @@
import json
from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync
-from .models import Room, ActiveUser, RPSMove, MinesweeperBoard, MinesweeperCell
+from games.models import Room, ActiveUser, RPSMove
from common.models import LameUser
from django.db.models import Q
import random
diff --git a/games/static/games/js/minesweeper.js b/rps/static/games/js/minesweeper.js
similarity index 100%
rename from games/static/games/js/minesweeper.js
rename to rps/static/games/js/minesweeper.js
diff --git a/games/static/games/js/rps.js b/rps/static/games/js/rps.js
similarity index 100%
rename from games/static/games/js/rps.js
rename to rps/static/games/js/rps.js
diff --git a/games/templates/games/gamelog.html b/rps/templates/games/gamelog.html
similarity index 92%
rename from games/templates/games/gamelog.html
rename to rps/templates/games/gamelog.html
index 51caa98..df6e8ca 100644
--- a/games/templates/games/gamelog.html
+++ b/rps/templates/games/gamelog.html
@@ -11,7 +11,7 @@
Welcome!
\ No newline at end of file
+
diff --git a/games/templates/games/minesweeper/board.html b/rps/templates/games/minesweeper/board.html
similarity index 100%
rename from games/templates/games/minesweeper/board.html
rename to rps/templates/games/minesweeper/board.html
diff --git a/games/templates/games/minesweeper/minesweeper.html b/rps/templates/games/minesweeper/minesweeper.html
similarity index 94%
rename from games/templates/games/minesweeper/minesweeper.html
rename to rps/templates/games/minesweeper/minesweeper.html
index 3598bb8..09d0457 100644
--- a/games/templates/games/minesweeper/minesweeper.html
+++ b/rps/templates/games/minesweeper/minesweeper.html
@@ -6,4 +6,4 @@
{% include 'games/minesweeper/mobile-buttons.html' %}
{% include 'games/gamelog.html' %}
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/games/templates/games/minesweeper/mobile-buttons.html b/rps/templates/games/minesweeper/mobile-buttons.html
similarity index 100%
rename from games/templates/games/minesweeper/mobile-buttons.html
rename to rps/templates/games/minesweeper/mobile-buttons.html
diff --git a/games/templates/games/rps/rps.html b/rps/templates/games/rps/rps.html
similarity index 100%
rename from games/templates/games/rps/rps.html
rename to rps/templates/games/rps/rps.html
diff --git a/games/templates/games/rps/rps_choose.html b/rps/templates/games/rps/rps_choose.html
similarity index 100%
rename from games/templates/games/rps/rps_choose.html
rename to rps/templates/games/rps/rps_choose.html
diff --git a/games/templates/games/rps/rps_join.html b/rps/templates/games/rps/rps_join.html
similarity index 100%
rename from games/templates/games/rps/rps_join.html
rename to rps/templates/games/rps/rps_join.html
diff --git a/rps/tests.py b/rps/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/rps/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/games/urls.py b/rps/urls.py
similarity index 100%
rename from games/urls.py
rename to rps/urls.py
diff --git a/games/views.py b/rps/views.py
similarity index 93%
rename from games/views.py
rename to rps/views.py
index 7191b4b..b5ea635 100644
--- a/games/views.py
+++ b/rps/views.py
@@ -2,7 +2,7 @@ from django.shortcuts import (
render, HttpResponse, redirect
)
from django.urls import reverse
-from .models import Room, ActiveUser, MinesweeperBoard
+from games.models import Room, ActiveUser, MinesweeperBoard
# Create your views here.
def rps(request):