Implement valid position checking and improve nextShape
This commit is contained in:
		
							parent
							
								
									a098278778
								
							
						
					
					
						commit
						d5f9c5146b
					
				
					 1 changed files with 42 additions and 24 deletions
				
			
		| 
						 | 
					@ -116,21 +116,26 @@ blockCoords b = b ^. origin : b ^. extra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- Higher level functions on game and board
 | 
					-- Higher level functions on game and board
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bagFourTetriminoEach :: IO (Seq.Seq Tetrimino)
 | 
					-- | Facilitates cycling through at least 4 occurences of each shape
 | 
				
			||||||
bagFourTetriminoEach =
 | 
					-- before next bag (random permutation of 4*each tetrimino) is created. If input is empty,
 | 
				
			||||||
  shuffle $ Seq.cycleTaking 28 $ Seq.fromList [(I)..]
 | 
					-- generates new bag, otherwise just unshifts the first value and returns pair.
 | 
				
			||||||
 | 
					bagFourTetriminoEach :: Seq.Seq Tetrimino -> IO (Tetrimino, Seq.Seq Tetrimino)
 | 
				
			||||||
 | 
					bagFourTetriminoEach = go . Seq.viewl
 | 
				
			||||||
 | 
					  where
 | 
				
			||||||
 | 
					    go (t :< ts) = return (t, ts)
 | 
				
			||||||
 | 
					    go EmptyL = freshList >>= bagFourTetriminoEach
 | 
				
			||||||
 | 
					    freshList = shuffle $ Seq.cycleTaking 28 $ Seq.fromList [(I)..]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Initialize a game with a given level
 | 
					-- | Initialize a game with a given level
 | 
				
			||||||
initGame :: Int ->  IO Game
 | 
					initGame :: Int ->  IO Game
 | 
				
			||||||
initGame lvl = do
 | 
					initGame lvl = do
 | 
				
			||||||
  initBag <- bagFourTetriminoEach
 | 
					  (s1, bag1) <- bagFourTetriminoEach Seq.empty
 | 
				
			||||||
  let (fstShape :< fstBag) = Seq.viewl initBag
 | 
					  (s2, bag2) <- bagFourTetriminoEach bag1
 | 
				
			||||||
      (sndShape :< sndBag) = Seq.viewl fstBag
 | 
					  return $
 | 
				
			||||||
  return
 | 
					 | 
				
			||||||
    Game { _level = lvl
 | 
					    Game { _level = lvl
 | 
				
			||||||
         , _currBlock = initBlock fstShape
 | 
					         , _currBlock = initBlock s1
 | 
				
			||||||
         , _nextShape = sndShape
 | 
					         , _nextShape = s2
 | 
				
			||||||
         , _nextShapeBag = sndBag
 | 
					         , _nextShapeBag = bag2
 | 
				
			||||||
         , _score = 0
 | 
					         , _score = 0
 | 
				
			||||||
         , _board = mempty }
 | 
					         , _board = mempty }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -147,16 +152,28 @@ clearFullRows g = g & board %~ clearBoard
 | 
				
			||||||
           in (x, y - offset)
 | 
					           in (x, y - offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Handle counterclockwise block rotation (if possible)
 | 
					-- | Handle counterclockwise block rotation (if possible)
 | 
				
			||||||
 | 
					-- TODO wallkicks http://tetris.wikia.com/wiki/TGM_rotation
 | 
				
			||||||
rotate :: Game -> Game
 | 
					rotate :: Game -> Game
 | 
				
			||||||
rotate = undefined
 | 
					rotate = undefined
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Check if a block on a board is stopped from further gravitation
 | 
					-- | Check if a block on a board is stopped from further gravitation
 | 
				
			||||||
isStopped :: Board -> Block -> Bool
 | 
					isStopped :: Board -> Block -> Bool
 | 
				
			||||||
isStopped = undefined
 | 
					isStopped b = any (`M.member` b) . map (translate Down) . blockCoords
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | If stopped, freeze current block to board and get next block
 | 
					-- | Freeze current block
 | 
				
			||||||
cycleNextBlock :: Game -> IO Game
 | 
					freezeBlock :: Game -> Game
 | 
				
			||||||
cycleNextBlock = undefined
 | 
					freezeBlock g = g & board %~ (M.union blkMap)
 | 
				
			||||||
 | 
					  where blk    = g ^. currBlock
 | 
				
			||||||
 | 
					        blkMap = M.fromList $ zip (blk ^. to blockCoords) (repeat $ blk ^. shape)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-- | Replace currBlock with next block
 | 
				
			||||||
 | 
					nextBlock :: Game -> IO Game
 | 
				
			||||||
 | 
					nextBlock g = do
 | 
				
			||||||
 | 
					  (t, ts) <- bagFourTetriminoEach (g ^. nextShapeBag)
 | 
				
			||||||
 | 
					  return $
 | 
				
			||||||
 | 
					    g & currBlock    .~ initBlock (g ^. nextShape)
 | 
				
			||||||
 | 
					      & nextShape    .~ t
 | 
				
			||||||
 | 
					      & nextShapeBag .~ ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Try to shift current block; if shifting not possible, leave block where it is
 | 
					-- | Try to shift current block; if shifting not possible, leave block where it is
 | 
				
			||||||
shift :: Direction -> Game -> Game
 | 
					shift :: Direction -> Game -> Game
 | 
				
			||||||
| 
						 | 
					@ -165,23 +182,24 @@ shift d g = g & currBlock %~ shiftBlock
 | 
				
			||||||
                          then translate d b
 | 
					                          then translate d b
 | 
				
			||||||
                          else b
 | 
					                          else b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Check if coordinate is already occupied in board
 | 
					-- | Check if coordinate is already occupied or free in board
 | 
				
			||||||
isOccupied :: Board -> Coord -> Bool
 | 
					isFree, isOccupied :: Board -> Coord -> Bool
 | 
				
			||||||
isOccupied = undefined
 | 
					isFree     = flip M.notMember
 | 
				
			||||||
 | 
					isOccupied = flip M.member
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Check if coordinate is out of bounds
 | 
					-- | Check if coordinate is in or out of bounds
 | 
				
			||||||
isOutOfBounds :: Coord -> Bool
 | 
					isInBounds, isOutOfBounds :: Coord -> Bool
 | 
				
			||||||
isOutOfBounds (x,y) = x `elem` [1..boardWidth] && y `elem` [1..boardHeight]
 | 
					isInBounds (x,y) = x `elem` [1..boardWidth] && y `elem` [1..boardHeight]
 | 
				
			||||||
 | 
					isOutOfBounds = not . isInBounds
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Gravitate current block, i.e. shift down
 | 
					-- | Gravitate current block, i.e. shift down
 | 
				
			||||||
gravitate :: Game -> Game
 | 
					gravitate :: Game -> Game
 | 
				
			||||||
gravitate = shift Down
 | 
					gravitate = shift Down
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Checks if block's potential new origin is valid
 | 
					-- | Checks if block's potential new location is valid
 | 
				
			||||||
isValidBlockPosition :: Block -> Board -> Bool
 | 
					isValidBlockPosition :: Block -> Board -> Bool
 | 
				
			||||||
isValidBlockPosition = undefined
 | 
					isValidBlockPosition blk brd = all validCoord $ blk ^. to blockCoords
 | 
				
			||||||
 | 
					  where validCoord = (&&) <$> isFree brd <*> isInBounds
 | 
				
			||||||
-- TODO wallkicks http://tetris.wikia.com/wiki/TGM_rotation
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
-- | Shuffle a sequence (random permutation)
 | 
					-- | Shuffle a sequence (random permutation)
 | 
				
			||||||
shuffle :: Seq.Seq a -> IO (Seq.Seq a)
 | 
					shuffle :: Seq.Seq a -> IO (Seq.Seq a)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue