Compare commits
20 Commits
b75e03cd3e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b3e2cd0d3 | ||
|
|
d4a7b41d70 | ||
|
|
ce5b660350 | ||
|
|
eecc9becbc | ||
|
|
752061f92f | ||
|
|
e786d42e98 | ||
|
|
ab13de5bc3 | ||
|
|
a9d6476b75 | ||
|
|
b269656833 | ||
|
|
d48ff10b2f | ||
|
|
8c0d13d096 | ||
|
|
1bc950d97b | ||
|
|
890faab9fc | ||
|
|
ded7da8e73 | ||
|
|
694ccc14a4 | ||
|
|
6ee7a435e0 | ||
|
|
1d5b449d6d | ||
|
|
e0af5c2d33 | ||
|
|
78ed9e1daf | ||
|
|
1a81ae7f43 |
137
app.py
137
app.py
@@ -15,12 +15,11 @@ from typing import Any
|
|||||||
from libs.slow import (
|
from libs.slow import (
|
||||||
JSONAPI,
|
JSONAPI,
|
||||||
App,
|
App,
|
||||||
HTTPResponse,
|
|
||||||
JSONResponse,
|
|
||||||
Request,
|
Request,
|
||||||
redirect,
|
redirect,
|
||||||
render,
|
render,
|
||||||
)
|
)
|
||||||
|
from libs.slow.responses import HTTPResponse, JSONResponse
|
||||||
|
|
||||||
|
|
||||||
class Coord:
|
class Coord:
|
||||||
@@ -165,6 +164,32 @@ class Board:
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "\n".join([" ".join([p.value for p in self.grid[i]]) for i in range(8)])
|
return "\n".join([" ".join([p.value for p in self.grid[i]]) for i in range(8)])
|
||||||
|
|
||||||
|
def make_move(self, src: str, dst: str):
|
||||||
|
sx, sy = pos_to_coord(src)
|
||||||
|
dx, dy = pos_to_coord(dst)
|
||||||
|
self.grid[dy][dx] = self.index(src)
|
||||||
|
piece_kind = self.grid[sy][sx].value.lower()
|
||||||
|
is_white = self.grid[sy][sx].value.isupper()
|
||||||
|
|
||||||
|
if piece_kind == "p" and (dy == 7 or dy == 0):
|
||||||
|
self.grid[dy][dx] = Piece.WHITE_QUEEN if is_white else Piece.BLACK_QUEEN
|
||||||
|
|
||||||
|
if (
|
||||||
|
is_white and dst == "e1" and piece_kind == "k" and dst == "g1"
|
||||||
|
): # Castling (White)
|
||||||
|
castle_from = pos_to_coord("h1")
|
||||||
|
castle_to = pos_to_coord("f1")
|
||||||
|
self.grid[castle_from.y][castle_from.x] = Piece.EMPTY
|
||||||
|
self.grid[castle_to.y][castle_to.x] = Piece.WHITE_CASTLE
|
||||||
|
if (
|
||||||
|
not is_white and src == "e8" and piece_kind == "k" and dst == "g8"
|
||||||
|
): # Castling (Black)
|
||||||
|
castle_from = pos_to_coord("h8")
|
||||||
|
castle_to = pos_to_coord("f8")
|
||||||
|
self.grid[castle_from.y][castle_from.x] = Piece.EMPTY
|
||||||
|
self.grid[castle_to.y][castle_to.x] = Piece.BLACK_CASTLE
|
||||||
|
self.grid[sy][sx] = Piece.EMPTY
|
||||||
|
|
||||||
|
|
||||||
class Room:
|
class Room:
|
||||||
board: Board
|
board: Board
|
||||||
@@ -210,12 +235,12 @@ favicon_update = Path("favicon_update.ico").read_bytes()
|
|||||||
|
|
||||||
@app.GET("/favicon.ico")
|
@app.GET("/favicon.ico")
|
||||||
async def favicon_s(request):
|
async def favicon_s(request):
|
||||||
return HTTPResponse(request, favicon, content_type="image/x-icon")
|
return HTTPResponse(favicon, content_type="image/x-icon")
|
||||||
|
|
||||||
|
|
||||||
@app.GET("/favicon_update.ico")
|
@app.GET("/favicon_update.ico")
|
||||||
async def favicon_update_s(request):
|
async def favicon_update_s(request):
|
||||||
return HTTPResponse(request, favicon_update, content_type="image/x-icon")
|
return HTTPResponse(favicon_update, content_type="image/x-icon")
|
||||||
|
|
||||||
|
|
||||||
letters = string.ascii_lowercase + string.digits
|
letters = string.ascii_lowercase + string.digits
|
||||||
@@ -231,25 +256,25 @@ def room_key():
|
|||||||
@app.POST("/create_room")
|
@app.POST("/create_room")
|
||||||
async def new_room(request):
|
async def new_room(request):
|
||||||
if len(rooms) == len(letters) ** 4:
|
if len(rooms) == len(letters) ** 4:
|
||||||
return HTTPResponse(request, "Out of service", status=501)
|
return HTTPResponse("Out of service", status=501)
|
||||||
key = room_key()
|
key = room_key()
|
||||||
rooms[key] = Room()
|
rooms[key] = Room()
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
request,
|
|
||||||
{
|
{
|
||||||
"id": key,
|
"id": key,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
quick_queue: deque[str]
|
quick_queue: deque[str] = deque()
|
||||||
quick_map: dict[str, Room]
|
quick_map: dict[str, Room] = {}
|
||||||
|
quick_last_map: dict[str, datetime] = {}
|
||||||
lock = asyncio.Lock()
|
lock = asyncio.Lock()
|
||||||
|
|
||||||
|
|
||||||
@app.POST("/quick")
|
@app.POST("/quick")
|
||||||
async def quick_match(request: Request):
|
async def quick_match(request: Request):
|
||||||
global quick_queue, quick_map
|
global quick_queue, quick_map, quick_last_map
|
||||||
data = parse(request.body)
|
data = parse(request.body)
|
||||||
async with lock:
|
async with lock:
|
||||||
if (
|
if (
|
||||||
@@ -262,6 +287,13 @@ async def quick_match(request: Request):
|
|||||||
second = None
|
second = None
|
||||||
position: int = 0
|
position: int = 0
|
||||||
# UPDATE LOGIC
|
# UPDATE LOGIC
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
for q, t in quick_last_map.items():
|
||||||
|
if t - now >= timedelta(seconds=3):
|
||||||
|
quick_queue.remove(q)
|
||||||
|
del quick_map[q]
|
||||||
|
del quick_last_map[q]
|
||||||
|
|
||||||
while position < len(quick_queue):
|
while position < len(quick_queue):
|
||||||
if quick_queue[position] not in quick_map:
|
if quick_queue[position] not in quick_map:
|
||||||
if not first:
|
if not first:
|
||||||
@@ -274,26 +306,33 @@ async def quick_match(request: Request):
|
|||||||
room = Room()
|
room = Room()
|
||||||
k = room_key()
|
k = room_key()
|
||||||
rooms[k] = room
|
rooms[k] = room
|
||||||
quick_map[first] = room
|
quick_map[first] = k
|
||||||
quick_map[second] = room
|
quick_map[second] = k
|
||||||
|
|
||||||
qid = data["queue_id"]
|
qid = data["queue_id"]
|
||||||
|
quick_last_map[qid] = datetime.now(timezone.utc)
|
||||||
if qid in quick_map:
|
if qid in quick_map:
|
||||||
return JSONResponse(request, {"room_id": quick_map[qid]})
|
return JSONResponse({"room_id": quick_map[qid]})
|
||||||
else:
|
else:
|
||||||
return JSONResponse(
|
return JSONResponse({}) # Client handles empty as continue to wait
|
||||||
request, {}
|
elif (
|
||||||
) # Client handles empty as continue to wait
|
data
|
||||||
|
and len(data) == 2
|
||||||
|
and "queue_id" in data
|
||||||
|
and data["queue_id"] in quick_queue
|
||||||
|
and "leave" in data
|
||||||
|
):
|
||||||
|
quick_queue.remove(data["queue_id"])
|
||||||
else:
|
else:
|
||||||
qid = str(uuid.uuid4())
|
qid = str(uuid.uuid4())
|
||||||
quick_queue.append(qid)
|
quick_queue.append(qid)
|
||||||
return JSONResponse(request, {"queue_id": qid})
|
quick_last_map[qid] = datetime.now(timezone.utc)
|
||||||
|
return JSONResponse({"queue_id": qid})
|
||||||
|
|
||||||
|
|
||||||
@app.GET("/")
|
@app.GET("/")
|
||||||
async def home(request):
|
async def home(request):
|
||||||
return render(request, "home.html")
|
return render("home.html")
|
||||||
|
|
||||||
|
|
||||||
@app.GET("/<id>")
|
@app.GET("/<id>")
|
||||||
@@ -302,18 +341,17 @@ async def game(request, id):
|
|||||||
return redirect("/")
|
return redirect("/")
|
||||||
if id not in rooms:
|
if id not in rooms:
|
||||||
return redirect("/")
|
return redirect("/")
|
||||||
return render(request, "game.html")
|
return render("game.html")
|
||||||
|
|
||||||
|
|
||||||
@app.POST("/join/<room_id>")
|
@app.POST("/join/<room_id>")
|
||||||
async def join(request, room_id):
|
async def join(request, room_id):
|
||||||
if room_id not in rooms:
|
if room_id not in rooms:
|
||||||
return JSONResponse(request, {"code": "NOGO", "error": "Room not found."}, 404)
|
return JSONResponse({"code": "NOGO", "error": "Room not found."}, 404)
|
||||||
room: Room = rooms[room_id]
|
room: Room = rooms[room_id]
|
||||||
player = room.add_player()
|
player = room.add_player()
|
||||||
if player:
|
if player:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
request,
|
|
||||||
{
|
{
|
||||||
"code": "JOIN",
|
"code": "JOIN",
|
||||||
"id": player[0],
|
"id": player[0],
|
||||||
@@ -329,7 +367,6 @@ async def join(request, room_id):
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
request,
|
|
||||||
{
|
{
|
||||||
"code": "FULL",
|
"code": "FULL",
|
||||||
"error": "Room Full",
|
"error": "Room Full",
|
||||||
@@ -361,14 +398,12 @@ def get_piece_moves(piece_kind, board: Board, is_white, src: str) -> list[Coord]
|
|||||||
if (y == 1 or y == 6) and board.index_xy(x, y + 2 * dir) == Piece.EMPTY:
|
if (y == 1 or y == 6) and board.index_xy(x, y + 2 * dir) == Piece.EMPTY:
|
||||||
valids.append(Coord(x=x, y=y + 2 * dir))
|
valids.append(Coord(x=x, y=y + 2 * dir))
|
||||||
if (
|
if (
|
||||||
board.index_xy(x + 1, y + dir)
|
board.index_xy(x + 1, y + dir) not in [Piece.EMPTY, Piece.NONE]
|
||||||
not in [Piece.EMPTY, Piece.NONE, Piece.BLACK_KING, Piece.WHITE_KING]
|
|
||||||
and board.index_xy(x + 1, y + dir).value.isupper() != is_white
|
and board.index_xy(x + 1, y + dir).value.isupper() != is_white
|
||||||
):
|
):
|
||||||
valids.append(Coord(x=x + 1, y=y + dir))
|
valids.append(Coord(x=x + 1, y=y + dir))
|
||||||
if (
|
if (
|
||||||
board.index_xy(x - 1, y + dir)
|
board.index_xy(x - 1, y + dir) not in [Piece.EMPTY, Piece.NONE]
|
||||||
not in [Piece.EMPTY, Piece.NONE, Piece.BLACK_KING, Piece.WHITE_KING]
|
|
||||||
and board.index_xy(x - 1, y + dir).value.isupper() != is_white
|
and board.index_xy(x - 1, y + dir).value.isupper() != is_white
|
||||||
):
|
):
|
||||||
valids.append(Coord(x=x - 1, y=y + dir))
|
valids.append(Coord(x=x - 1, y=y + dir))
|
||||||
@@ -425,6 +460,20 @@ def get_piece_moves(piece_kind, board: Board, is_white, src: str) -> list[Coord]
|
|||||||
elif piece_kind == "k":
|
elif piece_kind == "k":
|
||||||
x, y = pos_to_coord(src)
|
x, y = pos_to_coord(src)
|
||||||
comb = product([-1, 0, 1], repeat=2)
|
comb = product([-1, 0, 1], repeat=2)
|
||||||
|
if (
|
||||||
|
src == "e1"
|
||||||
|
and is_white
|
||||||
|
and board.index("f1") == Piece.EMPTY
|
||||||
|
and board.index("g1") == Piece.EMPTY
|
||||||
|
): # Castle (White)
|
||||||
|
valids.append(pos_to_coord("g1"))
|
||||||
|
if (
|
||||||
|
src == "e8"
|
||||||
|
and is_white
|
||||||
|
and board.index("f8") == Piece.EMPTY
|
||||||
|
and board.index("g8") == Piece.EMPTY
|
||||||
|
): # Castling (Black)
|
||||||
|
valids.append(pos_to_coord("g8"))
|
||||||
for dir in comb:
|
for dir in comb:
|
||||||
if dir[0] ** 2 + dir[1] ** 2 == 0:
|
if dir[0] ** 2 + dir[1] ** 2 == 0:
|
||||||
continue # x=0 y=0 cannot move => invalid
|
continue # x=0 y=0 cannot move => invalid
|
||||||
@@ -465,33 +514,19 @@ def generate_valid_moves(
|
|||||||
):
|
):
|
||||||
king = Coord(j, i)
|
king = Coord(j, i)
|
||||||
break
|
break
|
||||||
|
|
||||||
for m in possible_moves:
|
for m in possible_moves:
|
||||||
fake_board = board.copy()
|
fake_board = board.copy()
|
||||||
fake_board.grid[m.y][m.x] = fake_board.index(src)
|
fake_board.make_move(src, coord_to_pos_safe(m))
|
||||||
sx, sy = pos_to_coord(src)
|
|
||||||
fake_board.grid[sy][sx] = Piece.EMPTY
|
|
||||||
king_safe = True
|
king_safe = True
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
for j in range(8):
|
for j in range(8):
|
||||||
p = board.grid[i][j]
|
p = board.index_xy(j, i)
|
||||||
if p != Piece.EMPTY and p.value.isupper() != is_white:
|
if p != Piece.EMPTY and p.value.isupper() != is_white:
|
||||||
# Enemy
|
|
||||||
enemy_moves = get_piece_moves(
|
|
||||||
p.value.lower(), board, not is_white, xy_to_pos_safe(j, i)
|
|
||||||
)
|
|
||||||
if king not in enemy_moves:
|
|
||||||
continue
|
|
||||||
ni = i
|
|
||||||
nj = j
|
|
||||||
if j == sx and i == sy:
|
|
||||||
ni = m.y
|
|
||||||
nj = m.x
|
|
||||||
new_enemy_moves = get_piece_moves(
|
new_enemy_moves = get_piece_moves(
|
||||||
p.value.lower(),
|
p.value.lower(),
|
||||||
fake_board,
|
fake_board,
|
||||||
not is_white,
|
not is_white,
|
||||||
xy_to_pos_safe(nj, ni),
|
xy_to_pos_safe(j, i),
|
||||||
)
|
)
|
||||||
if king in new_enemy_moves:
|
if king in new_enemy_moves:
|
||||||
king_safe = False
|
king_safe = False
|
||||||
@@ -554,12 +589,8 @@ async def move(request: Request, room_id):
|
|||||||
):
|
):
|
||||||
return 400, {"code": "HTME", "error": "Cannot move to your own piece"}
|
return 400, {"code": "HTME", "error": "Cannot move to your own piece"}
|
||||||
valid_moves = generate_valid_moves(piece_kind, board, is_white, src)
|
valid_moves = generate_valid_moves(piece_kind, board, is_white, src)
|
||||||
if (c := pos_to_coord(dst)) in valid_moves:
|
if pos_to_coord(dst) in valid_moves:
|
||||||
board.grid[c.y][c.x] = srcp
|
board.make_move(src, dst)
|
||||||
sx, sy = pos_to_coord(src)
|
|
||||||
board.grid[sy][sx] = Piece.EMPTY
|
|
||||||
if (c.y == 0 or c.y == 7) and piece_kind == "p":
|
|
||||||
board.grid[c.y][c.x] = Piece.WHITE_QUEEN if is_white else Piece.BLACK_QUEEN
|
|
||||||
room.turn = Color.BLACK if color == Color.WHITE else Color.WHITE
|
room.turn = Color.BLACK if color == Color.WHITE else Color.WHITE
|
||||||
room.last_move = datetime.now(timezone.utc)
|
room.last_move = datetime.now(timezone.utc)
|
||||||
opp_checkmate = True
|
opp_checkmate = True
|
||||||
@@ -576,7 +607,7 @@ async def move(request: Request, room_id):
|
|||||||
if not opp_checkmate:
|
if not opp_checkmate:
|
||||||
break
|
break
|
||||||
if opp_checkmate:
|
if opp_checkmate:
|
||||||
room.state = State.BLACK_WIN if is_white else State.WHITE_WIN
|
room.state = State.WHITE_WIN if is_white else State.BLACK_WIN
|
||||||
return {
|
return {
|
||||||
"code": "MOVD",
|
"code": "MOVD",
|
||||||
"color": color.value,
|
"color": color.value,
|
||||||
@@ -664,11 +695,9 @@ async def static(request, fn):
|
|||||||
try:
|
try:
|
||||||
path = sanitize_filename(fn, Path("static/").resolve())
|
path = sanitize_filename(fn, Path("static/").resolve())
|
||||||
|
|
||||||
return HTTPResponse(
|
return HTTPResponse(path.read_bytes(), content_type="application/octet-stream")
|
||||||
request, path.read_bytes(), content_type="application/octet-stream"
|
|
||||||
)
|
|
||||||
except Exception:
|
except Exception:
|
||||||
return HTTPResponse(request, "404 File Not Found", status=404)
|
return HTTPResponse("404 File Not Found", status=404)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
15
game.html
15
game.html
@@ -141,11 +141,12 @@
|
|||||||
const textures = {};
|
const textures = {};
|
||||||
|
|
||||||
const piecemoveSound = new Audio("/static/piecemove.mp3");
|
const piecemoveSound = new Audio("/static/piecemove.mp3");
|
||||||
//const endgameSound = new Audio("/static/endgame.mp3");
|
const endgameSound = new Audio("/static/endgame.mp3");
|
||||||
|
|
||||||
let color = 0;
|
let color = 0;
|
||||||
let turn = 0;
|
let turn = 0;
|
||||||
let state = -1;
|
let state = -1;
|
||||||
|
let oldState = -1;
|
||||||
let start_time = undefined;
|
let start_time = undefined;
|
||||||
let ready = false;
|
let ready = false;
|
||||||
let letterMap = ' ';
|
let letterMap = ' ';
|
||||||
@@ -187,14 +188,18 @@
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("Playback failed:", error);
|
console.error("Playback failed:", error);
|
||||||
});
|
});
|
||||||
|
if (oldState !== state && state >= 1) {
|
||||||
|
endgameSound.play();
|
||||||
|
}
|
||||||
oldBoard = structuredClone(board);
|
oldBoard = structuredClone(board);
|
||||||
|
oldState = state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setUI() {
|
function setUI() {
|
||||||
if (ready) {
|
if (ready) {
|
||||||
if (state == -1) {
|
if (state == -1) {
|
||||||
document.getElementById('stats').textCotnent = "";
|
document.getElementById('stats').innerText = "";
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const differenceMs = 30 * 60 * 1000 - Math.abs(start_time.getTime() - now.getTime());
|
const differenceMs = 30 * 60 * 1000 - Math.abs(start_time.getTime() - now.getTime());
|
||||||
const totalSeconds = Math.floor(differenceMs / 1000);
|
const totalSeconds = Math.floor(differenceMs / 1000);
|
||||||
@@ -210,7 +215,7 @@
|
|||||||
if (UID === undefined || turn != color) {
|
if (UID === undefined || turn != color) {
|
||||||
if (turn == 0) {
|
if (turn == 0) {
|
||||||
document.getElementById('turn').innerText = "White's Turn";
|
document.getElementById('turn').innerText = "White's Turn";
|
||||||
} else if (turn == 0) {
|
} else if (turn == 1) {
|
||||||
document.getElementById('turn').innerText = "Black's Turn";
|
document.getElementById('turn').innerText = "Black's Turn";
|
||||||
}
|
}
|
||||||
} else if (turn == color) {
|
} else if (turn == color) {
|
||||||
@@ -240,7 +245,7 @@
|
|||||||
mouse = [x, y];
|
mouse = [x, y];
|
||||||
i = Math.floor((x / width) * 8);
|
i = Math.floor((x / width) * 8);
|
||||||
j = Math.floor((y / height) * 8);
|
j = Math.floor((y / height) * 8);
|
||||||
if (ready && state == -1) {
|
if (ready && state == -1 && UID !== undefined) {
|
||||||
canvas.style.cursor = 'default';
|
canvas.style.cursor = 'default';
|
||||||
if (board) {
|
if (board) {
|
||||||
if (color == 0) {
|
if (color == 0) {
|
||||||
@@ -326,9 +331,9 @@
|
|||||||
ready = data.ready;
|
ready = data.ready;
|
||||||
turn = data.turn;
|
turn = data.turn;
|
||||||
board = data.board.grid;
|
board = data.board.grid;
|
||||||
boardOnChange();
|
|
||||||
state = data.state;
|
state = data.state;
|
||||||
start_time = new Date(data.start_time);
|
start_time = new Date(data.start_time);
|
||||||
|
boardOnChange();
|
||||||
|
|
||||||
setUI();
|
setUI();
|
||||||
})
|
})
|
||||||
|
|||||||
76
home.html
76
home.html
@@ -70,7 +70,6 @@
|
|||||||
.code {
|
.code {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-bottom: 2px solid rgba(92, 92, 92, 0.664);
|
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
letter-spacing: 8px;
|
letter-spacing: 8px;
|
||||||
@@ -94,19 +93,18 @@
|
|||||||
|
|
||||||
.group {
|
.group {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 60px;
|
height: 48px;
|
||||||
gap: 4px;
|
gap: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.group * {
|
.group * {
|
||||||
height: 60px;
|
height: 48px;
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.vs {
|
.vs {
|
||||||
height: calc(100% - 8px);
|
height: calc(100% - 8px);
|
||||||
width: 2px;
|
width: 2px;
|
||||||
margin: 4px;
|
|
||||||
background: rgba(92, 92, 92, 0.664);
|
background: rgba(92, 92, 92, 0.664);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,6 +124,13 @@
|
|||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#quick_match_info {
|
||||||
|
margin: 14px 0;
|
||||||
|
font-size: 18px;
|
||||||
|
user-select: none;
|
||||||
|
color: rgba(92, 92, 92, 0.664);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
<link rel="icon" href="/favicon.ico" type="image/x-icon">
|
||||||
</head>
|
</head>
|
||||||
@@ -145,19 +150,74 @@
|
|||||||
<button id="join" class="button">join</button>
|
<button id="join" class="button">join</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="or"></div>
|
<div class="or"></div>
|
||||||
Public games not added yet.
|
<div id="quick_match_info" style="visibility: hidden;">Searching for a game</div>
|
||||||
|
<button class="button" id="quick_match">quick match</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|
||||||
|
let dots = 0;
|
||||||
|
|
||||||
|
setInterval(() => {
|
||||||
|
let text = "Searching for a game";
|
||||||
|
for (let i = 0; i < dots; i++) {
|
||||||
|
text += ".";
|
||||||
|
}
|
||||||
|
document.getElementById("quick_match_info").innerText = text;
|
||||||
|
dots += 1;
|
||||||
|
if (dots == 4) {
|
||||||
|
dots = 0;
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
const code = document.getElementById("code");
|
const code = document.getElementById("code");
|
||||||
const pat = new RegExp("^[a-z0-9]{4}$")
|
const pat = new RegExp("^[a-z0-9]{4}$")
|
||||||
document.getElementById("join").addEventListener("click", () => {
|
document.getElementById("join").addEventListener("click", () => {
|
||||||
if (!reg.test(code.value)) {
|
if (!pat.test(code.value.toLowerCase())) {
|
||||||
alert("Invalid ID");
|
alert("Invalid ID");
|
||||||
} else {
|
} else {
|
||||||
window.location.href = window.location.origin + "/" + code.value;
|
window.location.href = window.location.origin + "/" + code.value.toLowerCase();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const qm = document.getElementById("quick_match");
|
||||||
|
let matchmaking = -1;
|
||||||
|
let qid = -1;
|
||||||
|
qm.addEventListener("click", () => {
|
||||||
|
if (qm.innerText.toLowerCase() === "cancel") {
|
||||||
|
qm.innerText = "quick match";
|
||||||
|
document.getElementById("quick_match_info").style.visibility = "hidden";
|
||||||
|
clearInterval(-1);
|
||||||
|
} else if (qm.innerText.toLowerCase() === "quick match") {
|
||||||
|
qm.innerText = "cancel";
|
||||||
|
document.getElementById("quick_match_info").style.visibility = "visible";
|
||||||
|
fetch("/quick", {
|
||||||
|
method: 'POST',
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
qid = data.queue_id;
|
||||||
|
matchmaking = setInterval(() => {
|
||||||
|
fetch("/quick", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ "queue_id": qid }),
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.room_id) {
|
||||||
|
clearInterval(matchmaking);
|
||||||
|
window.location.href = window.location.origin + "/" + data.room_id;
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
})
|
||||||
|
}, 1500);
|
||||||
|
}).catch((error) => {
|
||||||
|
console.error(error);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
document.getElementById("create").addEventListener("click", () => {
|
document.getElementById("create").addEventListener("click", () => {
|
||||||
|
|||||||
2
libs
2
libs
Submodule libs updated: 24334d1def...c455adea07
Reference in New Issue
Block a user