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
|
module Chelleport.KeySequence where
import Chelleport.Types (KeyGrid, KeySequence)
import Chelleport.Utils (findWithIndex, uniq)
import Control.Monad (guard)
import Data.List (elemIndex, isPrefixOf)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe, isJust)
import qualified SDL
nextChars :: KeySequence -> KeyGrid -> Maybe [Char]
nextChars keySequence cells =
case matches of
[] -> Nothing
_ -> Just nextCharactersInSequence
where
matches = concatMap (filter $ isPrefixOf keySequence) cells
nextCharactersInSequence = uniq $ concatMap (take 1 . drop (length keySequence)) matches
findMatchPosition :: KeySequence -> KeyGrid -> Maybe (Int, Int)
findMatchPosition keySequence = findWithIndex searchRows 0
where
searchRows = fmap fst . findWithIndex searchInRow 0
searchInRow = guard . (== keySequence)
isValidKey :: SDL.Keycode -> Bool
isValidKey = (`Map.member` keycodeCharMapping)
-- Linear Congruential Generator
lcg :: Int -> Int
lcg seed = (a * seed + c) `mod` fromIntegral m
where
a = 1664525
c = 1013904223
m = (2 :: Integer) ^ (32 :: Integer)
getIndexRounded :: Int -> [a] -> a
getIndexRounded i ls = ls !! (i `mod` length ls)
generateGrid :: Int -> (Int, Int) -> KeySequence -> Maybe KeyGrid
generateGrid seed (rows, columns) hintKeys
| rows * columns > length hintKeys * length hintKeys = Nothing
| otherwise = Just $ (\row -> getKeySeq row <$> [0 .. columns - 1]) <$> [0 .. rows - 1]
where
allKeySeq = take numPairs . uniq $ generatePairs
numPairs = rows * columns
getKeySeq row col = allKeySeq !! (row * columns + col)
randomNumbers = iterate lcg seed
generatePairs =
[ [getIndexRounded i hintKeys, getIndexRounded j hintKeys]
| (i, j) <- zip randomNumbers (drop numPairs randomNumbers)
]
toKeyChar :: SDL.Keycode -> Maybe Char
toKeyChar = (`Map.lookup` keycodeCharMapping)
keycodeCharMapping :: Map.Map SDL.Keycode Char
keycodeCharMapping =
Map.fromList
[ (SDL.KeycodeA, 'A'),
(SDL.KeycodeB, 'B'),
(SDL.KeycodeC, 'C'),
(SDL.KeycodeD, 'D'),
(SDL.KeycodeE, 'E'),
(SDL.KeycodeF, 'F'),
(SDL.KeycodeG, 'G'),
(SDL.KeycodeH, 'H'),
(SDL.KeycodeI, 'I'),
(SDL.KeycodeJ, 'J'),
(SDL.KeycodeK, 'K'),
(SDL.KeycodeL, 'L'),
(SDL.KeycodeM, 'M'),
(SDL.KeycodeN, 'N'),
(SDL.KeycodeO, 'O'),
(SDL.KeycodeP, 'P'),
(SDL.KeycodeQ, 'Q'),
(SDL.KeycodeR, 'R'),
(SDL.KeycodeS, 'S'),
(SDL.KeycodeT, 'T'),
(SDL.KeycodeU, 'U'),
(SDL.KeycodeV, 'V'),
(SDL.KeycodeW, 'W'),
(SDL.KeycodeX, 'X'),
(SDL.KeycodeY, 'Y'),
(SDL.KeycodeZ, 'Z')
]
keycodeToInt :: SDL.Keycode -> Maybe Int
keycodeToInt = (`elemIndex` digitKeycodes)
isKeycodeDigit :: SDL.Keycode -> Bool
isKeycodeDigit = isJust . keycodeToInt
digitKeycodes :: [SDL.Keycode]
digitKeycodes =
[ SDL.Keycode0,
SDL.Keycode1,
SDL.Keycode2,
SDL.Keycode3,
SDL.Keycode4,
SDL.Keycode5,
SDL.Keycode6,
SDL.Keycode7,
SDL.Keycode8,
SDL.Keycode9
]
|