-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathblokus.sql
588 lines (500 loc) · 15.6 KB
/
blokus.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
--drop table if exists users;
create table if not exists users
(
id int auto_increment primary key,
username varchar(255) not null,
session_id varchar(255) null,
password varchar(255) not null,
score int default 0 not null
);
drop function if exists createUser;
DELIMITER $$
create function createUser(username_param varchar(255), password_param varchar(255)) returns tinyint(1)
begin
if exists(select * from users where username= username_param) then
signal sqlstate '45000' set message_text = 'Username already exists';
else
insert into users(username,password,session_id) values (username_param,password_param,LEFT(UUID(), 8));
return true;
end if;
end;
drop function if exists getUserInfo;
create function getUserInfo(session_id_param varchar(255)) returns longtext
begin
declare id_val int;
declare username_val varchar(255);
declare score_val int;
select id into id_val
from users
where session_id = session_id_param;
if id_val is null then
signal sqlstate '45000' set message_text = 'You need to login first';
end if;
select username, id, score from users where session_id=session_id_param into username_val, id_val, score_val;
return json_object(
'username',username_val,
'id',id_val,
'score',score_val
);
end;
drop function if exists getScoreboard;
create function getScoreboard() returns longtext
begin
return (
select json_arrayagg(
json_object(
'username', username,
'score', score
)
)
from users
order by score desc
);
end;
-- rooms
-- drop table if exists rooms;
create table if not exists rooms (
room_index int auto_increment primary key,
player_a varchar(255),
player_b varchar(255),
player_c varchar(255),
player_d varchar(255),
a_mask bigint default 2097151, -- bitmask for pieces remaining for player a (21 bits set by default)
b_mask bigint default 2097151,
c_mask bigint default 2097151,
d_mask bigint default 2097151,
a_state tinyint default 0, -- 0 playing, 1 blocked, 2 placed all pieces
b_state tinyint default 0,
c_state tinyint default 0,
d_state tinyint default 0,
a_activity TIMESTAMP default NULL,
b_activity TIMESTAMP default NULL,
c_activity TIMESTAMP default NULL,
d_activity TIMESTAMP default NULL,
turn_index int default 0,
password varchar(255), -- optional password for private games (hashed for security)
created_at datetime default current_timestamp
);
-- drop table if exists boards;
create table if not exists boards (
room_id int primary key,
json_data text default '[ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] ]'
);
-- "
drop function if exists createRoom;
create function createRoom(session_id_param varchar(255),
password_param varchar(255))
returns int
begin
declare username_a varchar(255);
declare room_id int;
select username from users where session_id=session_id_param into username_a;
IF username_a IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'No user found for given session ID';
END IF;
insert into rooms (player_a, password, turn_index, created_at)
values (username_a,
case when password_param is not null and password_param != ''
then password(password_param)
else null
end,
1,
current_timestamp);
set room_id = last_insert_id();
insert into boards (room_id) values (room_id);
return room_id;
end;
drop function if exists getRooms;
create function getRooms() returns longtext
begin
return (
select json_arrayagg(
json_object(
'id', room_index,
'status',
case
when player_a is not null
and player_b is not null
and player_c is not null
and player_d is not null then 'full'
else 'not full'
end,
'access',
case
when password is not null then 'private'
else 'public'
end,
"created_at", created_at
)
)
from rooms
);
end$$
DELIMITER ;
DELIMITER $$
drop function if exists joinRoom;
create function joinRoom(room_index_param int, session_id_param varchar(255), password_param varchar(255))
returns varchar(255)
deterministic
begin
declare username_tmp varchar(255);
declare password_tmp varchar(255);
declare player_a_tmp varchar(255);
declare player_b_tmp varchar(255);
declare player_c_tmp varchar(255);
declare player_d_tmp varchar(255);
declare updated_field varchar(255);
select password into password_tmp
from rooms
where room_index = room_index_param limit 1;
if not (password_tmp = password_param)
or not (password_tmp is NULL and password_param = '') then
return "Wrong password";
end if;
select username into username_tmp
from users
where session_id = session_id_param limit 1;
-- get currnt players
select player_a, player_b, player_c, player_d
into player_a_tmp, player_b_tmp, player_c_tmp, player_d_tmp
from rooms
where room_index = room_index_param;
if player_a_tmp = username_tmp or player_b_tmp = username_tmp or player_c_tmp = username_tmp or player_d_tmp = username_tmp then
return "Already joined.";
end if;
-- check for the first empty field and update
if player_a_tmp is null then
update rooms set player_a = username_tmp where room_index = room_index_param limit 1;
set updated_field = 'player_a';
elseif player_b_tmp is null then
update rooms set player_b = username_tmp where room_index = room_index_param limit 1;
set updated_field = 'player_b';
elseif player_c_tmp is null then
update rooms set player_c = username_tmp where room_index = room_index_param limit 1;
set updated_field = 'player_c';
elseif player_d_tmp is null then
update rooms set player_d = username_tmp where room_index = room_index_param limit 1;
set updated_field = 'player_d';
else
set updated_field = 'no empty slots available.';
end if;
return updated_field;
end$$
DELIMITER ;
DELIMITER $$
drop function if exists getState;
create function getState(room_index_param int) returns longtext
begin
return (
select json_arrayagg(
json_object(
-- 'id', room_id,
'board', json_data
)
)
from boards
where room_id = room_index_param
);
end$$
DELIMITER ;
DELIMITER $$
-- 12abcdefghilnptuvwxyz
drop function if exists getBitMask;
create function getBitMask(session_id_param varchar(255), room_id_param int)
returns int
deterministic
begin
declare username_val varchar(255);
declare bitmask int;
select username from users where session_id=session_id_param into username_val;
select
case
when player_a = username_val then a_mask
when player_b = username_val then b_mask
when player_c = username_val then c_mask
when player_d = username_val then d_mask
else null
end
into bitmask
from rooms
where (player_a = username_val
or player_b = username_val
or player_c = username_val
or player_d = username_val)
and room_index = room_id_param
limit 1;
return bitmask;
end$$
DELIMITER ;
DELIMITER $$
drop function if exists getPlayerState;
create function getPlayerState(n int, room_id_param int)
returns int
deterministic
begin
declare state_val int;
select
case
when n = 1 then a_state
when n = 2 then b_state
when n = 3 then c_state
when n = 4 then d_state
else null
end
into state_val
from rooms
where room_index = room_id_param
limit 1;
return state_val;
end$$
DELIMITER ;
DELIMITER $$
-- 12abcdefghilnptuvwxyz
drop function if exists getTurn;
create function getTurn(room_id_param int)
returns varchar(255)
deterministic
begin
-- declare username_val varchar(255);
declare turn_val int;
select turn_index into turn_val from rooms where room_index = room_id_param;
if turn_val = 1 then
return (select player_a from rooms where room_index = room_id_param);
elseif turn_val = 2 then
return (select player_b from rooms where room_index = room_id_param);
elseif turn_val = 3 then
return (select player_c from rooms where room_index = room_id_param);
elseif turn_val = 4 then
return (select player_d from rooms where room_index = room_id_param);
end if;
end$$
DELIMITER ;
DELIMITER $$
drop procedure if exists updateBitMask;
create procedure updateBitMask(
in session_id_param varchar(255),
in room_id_param int,
in new_bitmask int
)
begin
declare username_val varchar(255);
-- retrieve username from session_id
select username
into username_val
from users
where session_id = session_id_param;
-- update the appropriate bitmask column
update rooms
set
a_mask = case when player_a = username_val then new_bitmask else a_mask end,
b_mask = case when player_b = username_val then new_bitmask else b_mask end,
c_mask = case when player_c = username_val then new_bitmask else c_mask end,
d_mask = case when player_d = username_val then new_bitmask else d_mask end
where
room_index = room_id_param
and (player_a = username_val
or player_b = username_val
or player_c = username_val
or player_d = username_val);
end$$
DELIMITER ;
DELIMITER $$
drop procedure if exists updatePlayerState;
create procedure updatePlayerState(
in n int,
in room_id_param int,
in new_state int
)
begin
update rooms
set
a_state = case when n = 1 then new_state else a_state end,
b_state = case when n = 2 then new_state else b_state end,
c_state = case when n = 3 then new_state else c_state end,
d_state = case when n = 4 then new_state else d_state end
where
room_index = room_id_param
and (
(n = 1 and player_a is not null) or
(n = 2 and player_b is not null) or
(n = 3 and player_c is not null) or
(n = 4 and player_d is not null)
);
end$$
DELIMITER ;
DELIMITER $$
drop function if exists getColor;
create function getColor(session_id_param varchar(255), room_id_param int)
returns int
deterministic
begin
declare username_val varchar(255);
declare color int;
select username
into username_val
from users
where session_id = session_id_param;
select
case
when player_a = username_val then 1
when player_b = username_val then 2
when player_c = username_val then 3
when player_d = username_val then 4
else null
end
into color
from rooms
where room_index = room_id_param
and username_val in (player_a, player_b, player_c, player_d);
return color;
end$$
DELIMITER ;
DELIMITER $$
DROP PROCEDURE IF EXISTS updateTurn$$
CREATE PROCEDURE updateTurn(current_turn INT, room_index_param INT)
BEGIN
DECLARE new_turn INT;
DECLARE a_state_val INT;
DECLARE b_state_val INT;
DECLARE c_state_val INT;
DECLARE d_state_val INT;
DECLARE iteration_count INT;
SELECT a_state, b_state, c_state, d_state
INTO a_state_val, b_state_val, c_state_val, d_state_val
FROM rooms
WHERE room_index = room_index_param
LIMIT 1;
SET new_turn = current_turn;
SET iteration_count = 0;
-- Loop until a valid turn is found or the safety limit is reached
REPEAT
SET iteration_count = iteration_count + 1;
SET new_turn = CASE
WHEN new_turn = 4 THEN 1
ELSE new_turn + 1
END;
UNTIL
((new_turn = 1 AND a_state_val = 0) OR
(new_turn = 2 AND b_state_val = 0) OR
(new_turn = 3 AND c_state_val = 0) OR
(new_turn = 4 AND d_state_val = 0))
OR iteration_count > 4
END REPEAT;
-- test
IF iteration_count <= 4 THEN
UPDATE rooms
SET turn_index = new_turn
WHERE room_index = room_index_param
LIMIT 1;
END IF;
END$$
DELIMITER ;
-- DELIMITER $$
--
-- drop procedure if exists updateTurn$$
--
-- create procedure updateTurn(current_turn int, room_index_param int)
-- begin
-- declare new_turn int;
--
-- set new_turn = case
-- when current_turn = 4 then 1
-- else current_turn + 1
-- end;
--
-- update rooms
-- set turn_index = new_turn
-- where room_index = room_index_param limit 1;
-- end$$
--
-- DELIMITER ;
DELIMITER $$
drop function if exists getPlayers $$
create function getPlayers(room_index_param int)
returns json
deterministic
begin
declare result json;
select json_object(
player_a, 1,
player_b, 2,
player_c, 3,
player_d, 4
)
into result
from rooms
where room_index = room_index_param
limit 1;
return result;
end $$
DELIMITER ;
DELIMITER $$
drop function if exists getPosition $$
create function getPosition(room_id_param varchar(255), session_id_param varchar(255))
returns int
deterministic
begin
declare player_position int default 0;
declare username_val varchar(255);
select username into username_val
from users
where session_id = session_id_param;
if username_val is not null then
select case
when player_a = username_val then 1
when player_b = username_val then 2
when player_c = username_val then 3
when player_d = username_val then 4
else 0
end into player_position
from rooms
where room_index = room_id_param;
end if;
return player_position;
end$$
DELIMITER ;
DELIMITER $$
drop procedure if exists updateActivity $$
create procedure updateActivity(session_id_param varchar(255), room_id_param int)
deterministic
begin
declare username_val varchar(255);
-- retrieve username from session_id
select username
into username_val
from users
where session_id = session_id_param;
-- update the appropriate bitmask column
update rooms
set
a_activity = case when player_a = username_val then current_timestamp else a_activity end,
b_activity = case when player_b = username_val then current_timestamp else b_activity end,
c_activity = case when player_c = username_val then current_timestamp else c_activity end,
d_activity = case when player_d = username_val then current_timestamp else d_activity end
where
room_index = room_id_param
and (player_a = username_val
or player_b = username_val
or player_c = username_val
or player_d = username_val);
end$$
DELIMITER ;
DELIMITER $$
drop procedure if exists removePlayer$$
create procedure removeplayer(username_param varchar(255), room_index_param int)
begin
update rooms
set
player_a = case when player_a = username_param then null else player_a end,
player_b = case when player_b = username_param then null else player_b end,
player_c = case when player_c = username_param then null else player_c end,
player_d = case when player_d = username_param then null else player_d end,
a_activity = case when player_a = username_param then null else a_activity end,
b_activity = case when player_b = username_param then null else b_activity end,
c_activity = case when player_c = username_param then null else c_activity end,
d_activity = case when player_d = username_param then null else d_activity end
where
(player_a = username_param or player_b = username_param or player_c = username_param or player_d = username_param)
and room_index = room_index_param;
end$$
DELIMITER ;