master
Tait Hoyem 4 years ago
parent a3956e3bad
commit e7a414bcc4

@ -0,0 +1,44 @@
# Generated by Django 3.1 on 2020-09-10 16:21
import django.contrib.auth.models
import django.contrib.auth.validators
from django.db import migrations, models
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]
operations = [
migrations.CreateModel(
name='LameUser',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]

@ -0,0 +1,38 @@
# Generated by Django 3.1 on 2020-09-10 16:21
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('games', '0006_auto_20200908_1344'),
]
operations = [
migrations.CreateModel(
name='Card',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('suit', models.IntegerField(choices=[(0, 'None'), (1, 'Diamond'), (2, 'Spade'), (3, 'Heart'), (4, 'Club')])),
('value', models.IntegerField(choices=[(0, 'Joker'), (1, 'One'), (2, 'Two'), (3, 'Three'), (4, 'Four'), (5, 'Five'), (6, 'Six'), (7, 'Seven'), (8, 'Eight'), (9, 'Nine'), (10, 'Ten'), (11, 'Jack'), (12, 'Queen'), (13, 'King')])),
],
),
migrations.CreateModel(
name='MinesweeperCell',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('shown', models.BooleanField(default=False)),
('bomb', models.BooleanField()),
('bombs_next', models.SmallIntegerField()),
],
),
migrations.CreateModel(
name='MinesweeperBoard',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('cells', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='board', to='games.minesweepercell')),
],
),
]

@ -0,0 +1,25 @@
# Generated by Django 3.1 on 2020-09-10 16:35
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('games', '0007_card_minesweeperboard_minesweepercell'),
]
operations = [
migrations.DeleteModel(
name='Card',
),
migrations.AddField(
model_name='minesweeperboard',
name='user',
field=models.OneToOneField(default=None, on_delete=django.db.models.deletion.CASCADE, to='common.lameuser'),
preserve_default=False,
),
]

@ -0,0 +1,27 @@
# Generated by Django 3.1 on 2020-09-10 16:37
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('games', '0008_auto_20200910_1635'),
]
operations = [
migrations.AddField(
model_name='activeuser',
name='user',
field=models.OneToOneField(default=0, on_delete=django.db.models.deletion.CASCADE, to='common.lameuser'),
preserve_default=False,
),
migrations.AlterField(
model_name='minesweeperboard',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='games.activeuser'),
),
]

@ -0,0 +1,21 @@
# Generated by Django 3.1 on 2020-09-10 18:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('games', '0009_auto_20200910_1637'),
]
operations = [
migrations.AlterField(
model_name='minesweeperboard',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
),
]

@ -0,0 +1,24 @@
# Generated by Django 3.1 on 2020-09-10 18:12
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('games', '0010_auto_20200910_1809'),
]
operations = [
migrations.RemoveField(
model_name='minesweeperboard',
name='cells',
),
migrations.AddField(
model_name='minesweepercell',
name='board',
field=models.ForeignKey(default=0, on_delete=django.db.models.deletion.CASCADE, to='games.minesweeperboard'),
preserve_default=False,
),
]

@ -0,0 +1,31 @@
# Generated by Django 3.1 on 2020-09-10 18:23
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('games', '0011_auto_20200910_1812'),
]
operations = [
migrations.AddField(
model_name='minesweepercell',
name='x',
field=models.SmallIntegerField(default=0),
preserve_default=False,
),
migrations.AddField(
model_name='minesweepercell',
name='y',
field=models.SmallIntegerField(default=0),
preserve_default=False,
),
migrations.AlterField(
model_name='minesweepercell',
name='board',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='cells', to='games.minesweeperboard'),
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-09-10 21:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0012_auto_20200910_1823'),
]
operations = [
migrations.AddField(
model_name='minesweepercell',
name='flagged',
field=models.BooleanField(default=False),
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-09-10 22:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0013_minesweepercell_flagged'),
]
operations = [
migrations.AddField(
model_name='minesweepercell',
name='game_over',
field=models.BooleanField(default=False),
),
]

@ -0,0 +1,22 @@
# Generated by Django 3.1 on 2020-09-10 22:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0014_minesweepercell_game_over'),
]
operations = [
migrations.RemoveField(
model_name='minesweepercell',
name='game_over',
),
migrations.AddField(
model_name='minesweeperboard',
name='game_over',
field=models.BooleanField(default=False),
),
]

@ -0,0 +1,18 @@
# Generated by Django 3.1 on 2020-09-10 23:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0015_auto_20200910_2215'),
]
operations = [
migrations.AddField(
model_name='minesweeperboard',
name='win_lose',
field=models.BooleanField(default=None),
),
]

@ -0,0 +1,27 @@
# Generated by Django 3.1 on 2020-09-10 23:46
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0016_minesweeperboard_win_lose'),
]
operations = [
migrations.RemoveField(
model_name='minesweeperboard',
name='game_over',
),
migrations.RemoveField(
model_name='minesweeperboard',
name='win_lose',
),
migrations.AddField(
model_name='minesweeperboard',
name='status',
field=models.IntegerField(choices=[(0, 'In Progress'), (1, 'Lost'), (2, 'Won')], default=0),
preserve_default=False,
),
]

@ -0,0 +1,22 @@
# Generated by Django 3.1 on 2020-09-11 00:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('games', '0017_auto_20200910_2346'),
]
operations = [
migrations.RemoveField(
model_name='activeuser',
name='username',
),
migrations.AlterField(
model_name='minesweeperboard',
name='status',
field=models.IntegerField(choices=[(0, 'In Progress'), (1, 'Lost'), (2, 'Won')], default=0),
),
]

@ -0,0 +1,181 @@
const WSProtocol = window.location.protocol === "https:" ? "wss" : "ws";
const MSSocket = new WebSocket(
WSProtocol
+ '://'
+ window.location.host
+ '/minesweeper/'
+ "1"
);
const RED_FLAG_UNICODE = '🚩';
/* TODO: remove global variable */
let LATEST_BUTTON;
const help_menu = () => {
write_message("h: Help menu")
write_message("n: New game");
write_message("f: Toggle flag on current tile");
write_message("Space/Enter: Expose current tile");
write_message("w/a/s/d: up/left/down/right");
};
const send_click = (e, event_type) => {
LATEST_BUTTON = e.target;
bid = Number(LATEST_BUTTON.id.split('-').pop());
if (event_type === 'flagged')
{
// if is number, meaning: already shown
if (/[0-9]/.test(LATEST_BUTTON.innerHTML))
{
write_message("<i>You cannot flag a square that is already showing</i>");
} else {
if (LATEST_BUTTON.innerHTML !== RED_FLAG_UNICODE)
{
LATEST_BUTTON.innerHTML = RED_FLAG_UNICODE;
write_message("Flagged " + (bid % 10) + "," + Math.floor(bid / 10));
} else {
LATEST_BUTTON.innerHTML = '';
write_message("Unflagged " + (bid % 10) + "," + Math.floor(bid / 10));
}
}
} else if (event_type === 'clicked') {
// if flagged
if (LATEST_BUTTON.innerHTML === RED_FLAG_UNICODE)
{
write_message('<i>You cannot click on a flagged element!</i>')
return;
}
if (/[0-9]/.test(LATEST_BUTTON.innerHTML))
{
write_message('<i>You have already exposed this peice!</i>');
return;
}
}
MSSocket.send(JSON.stringify(
{
'type': event_type,
'button_id': bid
}
));
};
const moving_key_handler = (e) => {
/* if no last button: do not change */
if (!LATEST_BUTTON)
{
return;
}
old_id = Number(LATEST_BUTTON.id.split('-').pop());
console.log("OID: " + old_id);
/* TODO: remove hardcoded values */
if (e.key === 'w') {
new_id = old_id -= 10;
} else if (e.key === 'a') {
new_id = old_id -= 1;
} else if (e.key === 's') {
new_id = old_id += 10;
} else if (e.key === 'd') {
new_id = old_id += 1;
}
/* if new ID over/under limit: stop */
/* TODO: remove hardcoded values */
if (new_id > 99 || new_id < 0)
{
return;
}
console.log("NID: " + new_id);
/* focus on new button ID */
document.getElementById("mscell-" + new_id).focus();
};
const gen_new_board = () => {
write_message("<i>Generating new board...</i>")
MSSocket.send(JSON.stringify({
'type': 'generate'
}));
};
const global_key_handler = (e) => {
console.log(e.key);
if (e.key === 'n') {
gen_new_board();
} else if (e.key === 'h') {
help_menu();
}
};
MSSocket.onmessage = (e) => {
console.log(e.data);
console.log(JSON.parse(e.data));
data = JSON.parse(e.data);
if (data.type === 'display') {
let shown_tiles = 0;
for (cell of data.partial_board)
{
i = (cell.y*10) + cell.x;
btn = document.getElementById("mscell-" + i);
btn.innerHTML = cell.bombs_next;
shown_tiles++;
}
if (data.flagged)
{
for (cell of data.flagged)
{
i = (cell.y*10) + cell.x;
btn = document.getElementById("mscell-" + i);
btn.innerHTML = '&#x1F6A9;';
}
}
write_message("You have exposed " + shown_tiles + " tiles");
} else if (data.type === 'display_full') {
for (cell of data.full_board)
{
i = (cell.y*10) + cell.x;
btn = document.getElementById("mscell-" + i);
if (cell.bomb) {
btn.innerHTML = '&#x1F4A3;';
} else {
btn.innerHTML = cell.bombs_next;
}
}
} else if (data.type === 'game_over') {
MSSocket.send(JSON.stringify({
'type': 'full_board'
}));
} else if (data.type === 'new_board') {
for (btn of document.getElementsByClassName("cell"))
{
btn.innerHTML = '';
}
} else if (data.type === 'message') {
write_message(data.message);
}
};
/* TODO: remove hardcoded "clicked"/"flagged" Low-Priority */
for (cell of document.getElementsByClassName("cell")) {
cell.addEventListener('keydown', (e) => {
if (e.key === 'f') {
send_click(e, 'flagged');
}
});
cell.addEventListener('keydown', moving_key_handler);
cell.addEventListener('click', (e) => {
send_click(e, 'clicked');
});
cell.addEventListener('contextmenu', (e) => {
send_click(e, 'flagged');
});
cell.addEventListener('focus', (e) => {
LATEST_BUTTON = e.target;
});
}
document.addEventListener('keypress', global_key_handler);
help_menu();

@ -0,0 +1,10 @@
<div id="minesweeper-board">
{% for row in board %}
<div class="row">
{% for cell in row %}
<label hidden for="mscell-{{ cell.id }}">{{ cell.x }},{{ cell.y }}</label>
<button class="cell" id="mscell-{{ cell.id }}"></button>
{% endfor %}
</div>
{% endfor %}
</div>

@ -0,0 +1,8 @@
{% extends 'common/master.html' %}
{% load static %}
{% block body %}
{% include 'games/minesweeper/board.html' %}
{% include 'games/gamelog.html' %}
<script src="{% static 'games/js/minesweeper.js' %}"></script>
{% endblock %}
Loading…
Cancel
Save