A. Is there an SQLite query to find the length of the last run of heads for a particular player?
You could write a query, although it would be quite complex if catering for a large range of Android API's/versions.
For example the following query will return the last run and is suitable for most Android versions :-
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
Additionally, do you know if there are SQLite queries that solve B and C.?
When you understand the above, the you could move on to solving B and C.
You may wish to refer to https://sqlite.org/lang_with.html
The following code was used for testing the above :-
DROP TABLE IF EXISTS outcome;
CREATE TABLE IF NOT EXISTS outcome (player TEXT, toss TEXT, auto_timestamp);
INSERT INTO outcome VALUES
('Alice','H',10),
('Bob','H',9),
('Alice','T',8),
('Alice','T',7),
('Bob','H',6),
('Bob','H',5),
('Bob','T',4),
('Alice','T',3),
('Bob','T',2),
('Bob','H',1);
WITH
/* CTE for the player - so only need to replce/bind once */
cte_player(p) AS (
SELECT 'Bob' /*<<<<<<<<<< change as necessary */
),
cte_toss(t) AS (
SELECT 'H' /*<<<<<<<<<< change as/if necessary */
),
/* get the base outcome to start from i.e. the latest row for the player */
cte_base_outcome AS (
SELECT auto_timestamp, toss,player
FROM outcome
WHERE player = (SELECT p FROM cte_player)
AND toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp DESC
LIMIT 1
),
/* The recursive CTE */
cte1(auto_timestamp,toss,player) AS (
SELECT auto_timestamp,toss, player
FROM cte_base_outcome
UNION ALL SELECT
(
SELECT auto_timestamp
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
AND outcome.toss = (SELECT t FROM cte_toss)
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT toss
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp
DESC LIMIT 1
),
(
SELECT player
FROM outcome
WHERE outcome.player = (SELECT p FROM cte_player)
AND outcome.auto_timestamp < cte1.auto_timestamp
ORDER BY auto_timestamp DESC
LIMIT 1
)
FROM cte1 WHERE toss = (SELECT t FROM cte_toss) LIMIT 10
)
SELECT count() AS result
FROM cte1
WHERE toss = (SELECT t FROM cte_toss);
/* Cleanup the Testing Environment */
DROP TABLE IF EXISTS outcome;
With Bob and H then the result is :-

With Alice and H the result is :-

With Bob and T the result is :-

And finally with Alice and T :-

To utilise in Room then the SQL would be placed into an @Query and you would specify a function/method return type of Int/int or Long/long (no need for a POJO/Entity class for single column return values).
e.g. :-
@Query("WITH " +
"/* CTE for the player - so only need to replace/bind once */ " +
" cte_player(p) AS ( SELECT :player)," +
" cte_toss(t) AS (SELECT :toss)," +
"/* get the base outcome to start from i.e. the latest row for the player */" +
" cte_base_outcome AS (" +
" SELECT auto_timestamp, toss,player " +
" FROM outcome " +
" WHERE player = (SELECT p FROM cte_player) " +
" AND toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
")," +
"/* The recursive CTE */" +
" cte1(auto_timestamp,toss,player) AS (" +
" SELECT auto_timestamp,toss, player FROM cte_base_outcome " +
" UNION ALL SELECT(SELECT auto_timestamp " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" AND outcome.toss = (SELECT t FROM cte_toss) " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT toss " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" )," +
" (" +
" SELECT player " +
" FROM outcome " +
" WHERE outcome.player = (SELECT p FROM cte_player) " +
" AND outcome.auto_timestamp < cte1.auto_timestamp " +
" ORDER BY auto_timestamp DESC " +
" LIMIT 1" +
" ) " +
" FROM cte1 " +
" WHERE toss = (SELECT t FROM cte_toss) " +
" LIMIT 10" +
") " +
"SELECT count() AS result " +
"FROM cte1 " +
"WHERE toss = (SELECT t FROM cte_toss);")
abstract fun getLastRun(player: String, toss: String): Long
- Note
LIMIT 10
should not be required but is a failsafe obviously you may wish to increase this to a suitable value or exclude it. It limits the number of recursions. However, where LIMIT 1
has been coded, this is required to only get the 1 respective row.