From 7361289f325ffd05db83f4c304b6df17b6e04f3a Mon Sep 17 00:00:00 2001 From: siers Date: Sat, 16 Sep 2023 01:09:10 +0300 Subject: [PATCH] Add counterclockwise rotation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The default rotation is now clockwise¹. In the help widget, it now says: RotateR with k/↑, RotateL with g. 1 - both tetris.com and [tetris.fandom.com/wiki/Tetris_Guideline](https://tetris.fandom.com/wiki/Tetris_Guideline) use cw rotation for up --- src/Tetris.hs | 32 ++++++++++++++++++-------------- src/UI/Game.hs | 8 +++++--- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/Tetris.hs b/src/Tetris.hs index cc04ee9..a513d46 100644 --- a/src/Tetris.hs +++ b/src/Tetris.hs @@ -21,6 +21,7 @@ module Tetris , Block(..) , Coord , Direction(..) + , RotationalDirection(..) , Game(..) , Tetrimino(..) , Tetris @@ -65,6 +66,9 @@ makeLenses ''Block data Direction = Left | Right | Down deriving (Eq, Show) +data RotationalDirection = Clockwise | Counterclockwise + deriving (Eq, Show) + -- | Board -- -- If coordinate not present in map, yet in bounds, then it is empty, @@ -132,19 +136,20 @@ boardHeight = 20 startOrigin :: Coord startOrigin = V2 6 22 --- | Rotate block counter clockwise about origin +-- | Rotate the block clockwise (or counter-) around origin -- *Note*: Strict unsafe rotation not respecting boundaries -- Safety can only be assured within Game context -rotateRaw :: Block -> Block -rotateRaw b@(Block s o@(V2 xo yo) cs) +rotateRaw :: RotationalDirection -> Block -> Block +rotateRaw rd b@(Block s o@(V2 xo yo) cs) | -- O doesn't need rotation s == O = b | -- I only has two orientations - s == I && V2 xo (yo + 1) `elem` cs = rotateWith clockwise - | otherwise = rotateWith counterclockwise + s == I && V2 xo (yo + 1) `elem` cs = rotateWith (direction Counterclockwise) + | s == I = rotateWith (direction Clockwise) + | otherwise = rotateWith (direction rd) where - clockwise = (+ o) . cwperp . subtract o - counterclockwise = (+ o) . LV.perp . subtract o + direction Clockwise = (+ o) . cwperp . subtract o + direction Counterclockwise = (+ o) . LV.perp . subtract o rotateWith dir = b & extra %~ fmap dir cwperp (V2 x y) = V2 y (-x) @@ -238,19 +243,18 @@ updateScore = do latestOrZero Empty = 0 latestOrZero (_ :|> n) = n --- | Handle counterclockwise block rotation (if possible) --- Allows wallkicks: http://tetris.wikia.com/wiki/TGM_rotation -rotate :: Tetris () -rotate = do +-- | Allows wallkicks: http://tetris.wikia.com/wiki/TGM_rotation +rotate :: RotationalDirection -> Tetris () +rotate rd = do blk <- use block brd <- use board let mblk = foldr (<|>) Nothing $ mfilter (isValidBlockPosition brd) . pure . ($ blk) - <$> [ rotateRaw - , rotateRaw . translate Left - , rotateRaw . translate Right + <$> [ rotateRaw rd + , rotateRaw rd . translate Left + , rotateRaw rd . translate Right ] forM_ mblk $ assign block diff --git a/src/UI/Game.hs b/src/UI/Game.hs index c4c5214..c836fe6 100644 --- a/src/UI/Game.hs +++ b/src/UI/Game.hs @@ -89,8 +89,9 @@ handleEvent (VtyEvent (V.EvKey V.KDown [])) = exec (shift Down) handleEvent (VtyEvent (V.EvKey (V.KChar 'l') [])) = exec (shift Right) handleEvent (VtyEvent (V.EvKey (V.KChar 'h') [])) = exec (shift Left) handleEvent (VtyEvent (V.EvKey (V.KChar 'j') [])) = exec (shift Down) -handleEvent (VtyEvent (V.EvKey V.KUp [])) = exec rotate -handleEvent (VtyEvent (V.EvKey (V.KChar 'k') [])) = exec rotate +handleEvent (VtyEvent (V.EvKey V.KUp [])) = exec (rotate Clockwise) +handleEvent (VtyEvent (V.EvKey (V.KChar 'k') [])) = exec (rotate Clockwise) +handleEvent (VtyEvent (V.EvKey (V.KChar 'g') [])) = exec (rotate Counterclockwise) handleEvent (VtyEvent (V.EvKey (V.KChar ' ') [])) = guarded (not . view paused) @@ -262,7 +263,8 @@ drawHelp = [ ("Left" , "h, ←") , ("Right" , "l, →") , ("Down" , "j, ↓") - , ("Rotate" , "k, ↑") + , ("RotateR", "k, ↑") + , ("RotateL", "g") , ("Drop" , "space") , ("Restart", "r") , ("Pause" , "p")