Created
February 22, 2015 00:24
-
-
Save schinckel/24b66c5a088c7776ca9f to your computer and use it in GitHub Desktop.
Ten pin bowling score calculation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Game 1 | |
INSERT INTO bowling.frame VALUES | |
(1, 1, 1, 7, 2, NULL), | |
(1, 1, 2, 3, 7, NULL), | |
(1, 1, 3, 6, 4, NULL), | |
(1, 1, 4, 10, NULL, NULL), | |
(1, 1, 5, 10, NULL, NULL), | |
(1, 1, 6, 10, NULL, NULL), | |
(1, 1, 7, 9, 1, NULL), | |
(1, 1, 8, 10, NULL, NULL), | |
(1, 1, 9, 8, 1, NULL), | |
(1, 1, 10, 6, 3, NULL); | |
-- Game 2 | |
INSERT INTO bowling.frame VALUES | |
(2, 1, 1, 10, NULL, NULL), | |
(2, 1, 2, 3, 7, NULL), | |
(2, 1, 3, 10, NULL, NULL), | |
(2, 1, 4, 6, 4, NULL), | |
(2, 1, 5, 10, NULL, NULL), | |
(2, 1, 6, 9, 1, NULL), | |
(2, 1, 7, 10, NULL, NULL), | |
(2, 1, 8, 8, 2, NULL), | |
(2, 1, 9, 10, NULL, NULL), | |
(2, 1, 10, 7, 3, 10); | |
-- Game 3 | |
INSERT INTO bowling.frame VALUES | |
(3, 1, 1, 10, NULL, NULL), | |
(3, 1, 2, 10, NULL, NULL), | |
(3, 1, 3, 10, NULL, NULL), | |
(3, 1, 4, 10, NULL, NULL), | |
(3, 1, 5, 10, NULL, NULL), | |
(3, 1, 6, 10, NULL, NULL), | |
(3, 1, 7, 10, NULL, NULL), | |
(3, 1, 8, 10, NULL, NULL), | |
(3, 1, 9, 10, NULL, NULL), | |
(3, 1, 10, 10, 10, 10); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE VIEW pretty_print AS ( | |
WITH symbols AS ( | |
SELECT | |
game_id, player_id, frame, | |
CASE WHEN ball1 = 10 THEN 'X' ELSE ball1::text END as ball1, | |
CASE WHEN ball2 IS NULL THEN ' ' | |
WHEN ball1 + ball2 = 10 THEN '/' | |
WHEN ball1 = 10 AND ball2 = 10 THEN 'X' | |
ELSE ball2::text | |
END as ball2, | |
CASE WHEN ball3 IS NULL THEN ' ' | |
WHEN ball3 = 10 THEN 'X' | |
WHEN ball3 + ball2 = 10 THEN '/' | |
ELSE ball3::text | |
END as ball3, | |
lpad(total::text, 5, ' ') as total | |
FROM | |
frame_score | |
ORDER BY game_id, player_id, frame | |
), grouped_data AS ( | |
SELECT | |
game_id, | |
player_id, | |
array_agg(ball1) ball1, | |
array_agg(ball2) ball2, | |
array_agg(ball3) ball3, | |
array_agg(total) total | |
FROM | |
symbols | |
GROUP BY | |
game_id, player_id | |
) | |
SELECT | |
game_id, | |
player_id, | |
ball1[1] || ' | ' || ball2[1] || ' ' || chr(10) || total[1] AS "1", | |
ball1[2] || ' | ' || ball2[2] || ' ' || chr(10) || total[2] AS "2", | |
ball1[3] || ' | ' || ball2[3] || ' ' || chr(10) || total[3] AS "3", | |
ball1[4] || ' | ' || ball2[4] || ' ' || chr(10) || total[4] AS "4", | |
ball1[5] || ' | ' || ball2[5] || ' ' || chr(10) || total[5] AS "5", | |
ball1[6] || ' | ' || ball2[6] || ' ' || chr(10) || total[6] AS "6", | |
ball1[7] || ' | ' || ball2[7] || ' ' || chr(10) || total[7] AS "7", | |
ball1[8] || ' | ' || ball2[8] || ' ' || chr(10) || total[8] AS "8", | |
ball1[9] || ' | ' || ball2[9] || ' ' || chr(10) || total[9] AS "9", | |
ball1[10] || ' | ' || ball2[10] || ' | ' || ball3[10] || ' ' || chr(10) || lpad(total[10], 9, ' ') AS "10" | |
FROM grouped_data | |
); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
DROP SCHEMA bowling CASCADE; | |
BEGIN; | |
CREATE SCHEMA bowling; | |
SET search_path TO bowling; | |
CREATE DOMAIN bowling.frame_number AS integer | |
CHECK ('[1,10]'::int4range @> VALUE) | |
NOT NULL; | |
CREATE DOMAIN bowling.ball AS integer | |
CHECK ('[0,10]'::int4range @> VALUE); | |
CREATE TABLE bowling.frame | |
( | |
game_id INTEGER NOT NULL, | |
player_id INTEGER NOT NULL, | |
frame bowling.frame_number NOT NULL, | |
ball1 bowling.ball NOT NULL, | |
ball2 bowling.ball NULL, | |
ball3 bowling.ball NULL, | |
PRIMARY KEY (game_id, player_id, frame) | |
); | |
ALTER TABLE bowling.frame | |
ADD CONSTRAINT max_spare_unless_frame_10_strike CHECK | |
( | |
ball1 + ball2 <= 10 OR (frame = 10 AND ball1 = 10) | |
); | |
ALTER TABLE bowling.frame | |
ADD CONSTRAINT ball_2_never_bowled_after_strike CHECK | |
( | |
ball2 IS NULL OR ball1 < 10 OR frame = 10 | |
); | |
ALTER TABLE bowling.frame | |
ADD CONSTRAINT ball_3_only_in_frame_10 CHECK | |
( | |
ball3 IS NULL OR frame = 10 | |
); | |
ALTER TABLE bowling.frame | |
ADD CONSTRAINT ball3_only_if_eligible CHECK | |
( | |
ball3 IS NULL OR (ball2 IS NOT NULL AND ball1 + ball2 >= 10) | |
); | |
ALTER TABLE bowling.frame | |
ADD CONSTRAINT ball3_max_spare_or_strike CHECK | |
( | |
ball2 + ball3 <= 10 | |
OR | |
ball1 + ball2 = 20 | |
OR | |
ball1 + ball2 = 10 | |
); | |
CREATE OR REPLACE VIEW bowling.frame_score AS ( | |
WITH pin_counts AS ( | |
SELECT | |
game_id, | |
player_id, | |
frame, | |
ball1, ball2, ball3, | |
LEAD(ball1, 1) OVER ( | |
PARTITION BY game_id, player_id | |
ORDER BY frame | |
) AS next_ball_1, | |
LEAD(ball2, 1) OVER ( | |
PARTITION BY game_id, player_id | |
ORDER BY frame | |
) AS next_ball_2, | |
LEAD(ball1, 2) OVER ( | |
PARTITION BY game_id, player_id | |
ORDER BY frame | |
) AS next_next_ball_1 | |
FROM bowling.frame | |
), | |
frame_counts AS ( | |
SELECT | |
game_id, | |
player_id, | |
frame, | |
ball1, ball2, ball3, | |
CASE WHEN frame = 10 AND ball1 + ball2 >= 10 THEN | |
ball1 + ball2 + ball3 | |
WHEN ball1 = 10 THEN | |
ball1 + next_ball_1 + ( | |
CASE WHEN next_ball_1 = 10 AND frame < 9 THEN | |
next_next_ball_1 | |
ELSE | |
next_ball_2 | |
END | |
) | |
WHEN ball1 + ball2 = 10 THEN | |
ball1 + ball2 + next_ball_1 | |
ELSE | |
ball1 + ball2 | |
END AS score | |
FROM pin_counts | |
) | |
SELECT *, | |
CASE WHEN score IS NOT NULL THEN | |
SUM(score) OVER ( | |
PARTITION BY game_id, player_id | |
ORDER BY frame | |
ROWS UNBOUNDED PRECEDING | |
) | |
ELSE NULL END AS total | |
FROM frame_counts | |
); | |
COMMIT; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
INSERT INTO bowling.frame VALUES(1, 2, 0, 9, NULL, NULL); | |
INSERT INTO bowling.frame VALUES(1, 2, 1, 11, NULL, NULL); | |
INSERT INTO bowling.frame VALUES(1, 2, 1, -1, NULL, NULL); | |
INSERT INTO bowling.frame VALUES(1, 2, 1, 8, 3, NULL); | |
INSERT INTO bowling.frame VALUES(1, 2, 1, 8, 1, 1); | |
INSERT INTO bowling.frame VALUES(1, 2, 1, 8, 2, 1); | |
INSERT INTO bowling.frame VALUES(1, 2, 10, 8, 3, 1); | |
INSERT INTO bowling.frame VALUES(1, 2, 10, 8, 2, 11); | |
INSERT INTO bowling.frame VALUES(1, 2, 10, 10, NULL, 10); | |
INSERT INTO bowling.frame VALUES(1, 2, 5, 10, 0, NULL); | |
INSERT INTO bowling.frame VALUES(1, 2, 10, 10, 2, 9); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment