Prefer snake-shift instead of a row-by-row shift

Per the assignment's instructions, the `Shift n` operation should treat
the *entire keyboard* like a cycle and shift that. I was erroneously
treating *each row* like a cycle and shifting those one-by-one.

This change fixes that. In addition, it also:
- Updates README.md with expected inputs and outputs
- Updates test suite
- Adds `split` dependency to {default,shell}.nix
This commit is contained in:
William Carroll 2020-08-12 12:03:35 +01:00
parent f11b91c985
commit bba3f16c43
5 changed files with 57 additions and 37 deletions

View file

@ -7,14 +7,31 @@ import Utils ((|>))
import qualified Data.Char as Char import qualified Data.Char as Char
import qualified Utils import qualified Utils
import qualified Data.List.Split as Split
import qualified Keyboard import qualified Keyboard
import qualified Data.HashMap.Strict as HM import qualified Data.HashMap.Strict as HM
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
transform :: Keyboard -> Transform -> Keyboard transform :: Keyboard -> Transform -> Keyboard
transform (Keyboard xs) HorizontalFlip = xs |> fmap reverse |> Keyboard
transform (Keyboard xs) VerticalFlip = xs |> reverse |> Keyboard transform (Keyboard xs) xform =
transform (Keyboard xs) (Shift n) = xs |> fmap (Utils.rotate n) |> Keyboard case xform of
HorizontalFlip ->
xs
|> fmap reverse
|> Keyboard
VerticalFlip ->
xs
|> reverse
|> Keyboard
Shift n ->
xs
|> concat
|> Utils.rotate n
|> Split.chunksOf 10
|> Keyboard
retypePassage :: String -> Keyboard -> Maybe String retypePassage :: String -> Keyboard -> Maybe String
retypePassage passage newKeyboard = retypePassage passage newKeyboard =

View file

@ -57,11 +57,11 @@ Now a working example:
$ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant.' $ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant.'
Typing: "Hello,Brilliant." Typing: "Hello,Brilliant."
On this keyboard: On this keyboard:
[N][M][,][.][/][Z][X][C][V][B] [H][J][K][L][;][Q][W][E][R][T]
[H][J][K][L][;][A][S][D][F][G] [Y][U][I][O][P][1][2][3][4][5]
[Y][U][I][O][P][Q][W][E][R][T] [6][7][8][9][0][Z][X][C][V][B]
[6][7][8][9][0][1][2][3][4][5] [N][M][,][.][/][A][S][D][F][G]
Result: QKRRF30LDRRDY1;4 Result: ZIVV4D/O3VV36APF
``` ```
...and an example with an erroneous input (i.e. `!`): ...and an example with an erroneous input (i.e. `!`):
@ -70,10 +70,10 @@ Result: QKRRF30LDRRDY1;4
$ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant!' $ ./result/transform-keyboard --transforms=HHVS12VHVHS3 --passage='Hello,Brilliant!'
Typing: "Hello,Brilliant!" Typing: "Hello,Brilliant!"
On this keyboard: On this keyboard:
[N][M][,][.][/][Z][X][C][V][B] [H][J][K][L][;][Q][W][E][R][T]
[H][J][K][L][;][A][S][D][F][G] [Y][U][I][O][P][1][2][3][4][5]
[Y][U][I][O][P][Q][W][E][R][T] [6][7][8][9][0][Z][X][C][V][B]
[6][7][8][9][0][1][2][3][4][5] [N][M][,][.][/][A][S][D][F][G]
Looks like at least one of the characters in your input passage doesn't fit on our QWERTY keyboard: Looks like at least one of the characters in your input passage doesn't fit on our QWERTY keyboard:
[1][2][3][4][5][6][7][8][9][0] [1][2][3][4][5][6][7][8][9][0]
[Q][W][E][R][T][Y][U][I][O][P] [Q][W][E][R][T][Y][U][I][O][P]

View file

@ -5,11 +5,12 @@ import Test.Hspec
import Test.QuickCheck import Test.QuickCheck
import Keyboard (Keyboard(..)) import Keyboard (Keyboard(..))
import Transforms (Transform(..)) import Transforms (Transform(..))
import Data.Coerce
import Utils
import qualified App import qualified App
import qualified Keyboard import qualified Keyboard
import qualified Transforms import qualified Transforms
import qualified Utils
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
main :: IO () main :: IO ()
@ -55,12 +56,12 @@ main = hspec $ do
it "shifts any keyboard" $ do it "shifts any keyboard" $ do
property $ \first second third fourth n -> property $ \first second third fourth n ->
App.transform (Keyboard [first, second, third, fourth]) (Shift n) == do App.transform (Keyboard [first, second, third, fourth]) (Shift n)
Keyboard $ [ Utils.rotate n first |> (coerce :: Keyboard -> [[Char]])
, Utils.rotate n second |> concat ==
, Utils.rotate n third [first, second, third, fourth]
, Utils.rotate n fourth |> concat
] |> Utils.rotate n
it "flips a QWERTY keyboard horizontally" $ do it "flips a QWERTY keyboard horizontally" $ do
App.transform Keyboard.qwerty HorizontalFlip == do App.transform Keyboard.qwerty HorizontalFlip == do
@ -72,27 +73,27 @@ main = hspec $ do
it "flips a keyboard vertically" $ do it "flips a keyboard vertically" $ do
App.transform Keyboard.qwerty VerticalFlip == do App.transform Keyboard.qwerty VerticalFlip == do
Keyboard $ [ ['Z','X','C','V','B','N','M',',','.','/'] Keyboard [ ['Z','X','C','V','B','N','M',',','.','/']
, ['A','S','D','F','G','H','J','K','L',';'] , ['A','S','D','F','G','H','J','K','L',';']
, ['Q','W','E','R','T','Y','U','I','O','P'] , ['Q','W','E','R','T','Y','U','I','O','P']
, ['1','2','3','4','5','6','7','8','9','0'] , ['1','2','3','4','5','6','7','8','9','0']
] ]
it "shifts a keyboard left N times" $ do it "shifts a keyboard left N times" $ do
App.transform Keyboard.qwerty (Shift 2) == do App.transform Keyboard.qwerty (Shift 2) == do
Keyboard $ [ ['3','4','5','6','7','8','9','0','1','2'] Keyboard [ ['3','4','5','6','7','8','9','0','Q','W']
, ['E','R','T','Y','U','I','O','P','Q','W'] , ['E','R','T','Y','U','I','O','P','A','S']
, ['D','F','G','H','J','K','L',';','A','S'] , ['D','F','G','H','J','K','L',';','Z','X']
, ['C','V','B','N','M',',','.','/','Z','X'] , ['C','V','B','N','M',',','.','/','1','2']
] ]
it "shifts right negative amounts" $ do it "shifts right negative amounts" $ do
App.transform Keyboard.qwerty (Shift (-3)) == do App.transform Keyboard.qwerty (Shift (-3)) == do
Keyboard $ [ ['8','9','0','1','2','3','4','5','6','7'] Keyboard [ [',','.','/','1','2','3','4','5','6','7']
, ['I','O','P','Q','W','E','R','T','Y','U'] , ['8','9','0','Q','W','E','R','T','Y','U']
, ['K','L',';','A','S','D','F','G','H','J'] , ['I','O','P','A','S','D','F','G','H','J']
, [',','.','/','Z','X','C','V','B','N','M'] , ['K','L',';','Z','X','C','V','B','N','M']
] ]
describe "Transforms.optimize" $ do describe "Transforms.optimize" $ do
it "removes superfluous horizontal transformations" $ do it "removes superfluous horizontal transformations" $ do

View file

@ -5,9 +5,10 @@ let
rev = "afa9ca61924f05aacfe495a7ad0fd84709d236cc"; rev = "afa9ca61924f05aacfe495a7ad0fd84709d236cc";
}) {}; }) {};
ghc = pkgs.haskellPackages.ghcWithPackages (hpkgs: [ ghc = pkgs.haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [
hpkgs.optparse-applicative optparse-applicative
hpkgs.unordered-containers unordered-containers
split
]); ]);
in pkgs.stdenv.mkDerivation { in pkgs.stdenv.mkDerivation {
name = "transform-keyboard"; name = "transform-keyboard";

View file

@ -10,6 +10,7 @@ in pkgs.mkShell {
hspec hspec
optparse-applicative optparse-applicative
unordered-containers unordered-containers
split
])) ]))
]; ];
} }