-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathtetris-clean.hs
executable file
·129 lines (113 loc) · 2.75 KB
/
tetris-clean.hs
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/env -S stack script --resolver=lts-20.13 --package ansi-terminal-game
import Import
type Line = Int
type Piece = [[Line]]
type Well = [Line]
type State =
( Piece
, Well
)
main :: IO ()
main = playGame $ Game 8 (head pieces, emptyWell) logic draw (\_->False)
where
emptyWell = replicate 20 0
pieces :: [Piece]
pieces = [ i, t, l, j, s, z, o ]
where
i =
[[0b00011_11000
]
,[0b00001_00000
,0b00001_00000
,0b00001_00000
,0b00001_00000
]
]
t =
[[0b00001_00000
,0b00011_10000
]
,[0b00001_00000
,0b00001_10000
,0b00001_00000
]
,[0b00011_10000
,0b00001_00000
]
,[0b00001_00000
,0b00011_00000
,0b00001_00000
]
]
l =
[[0b00000_10000
,0b00011_10000
]
,[0b00001_00000
,0b00001_00000
,0b00001_10000
]
,[0b00011_10000
,0b00010_00000
]
,[0b00001_10000
,0b00000_10000
,0b00000_10000
]
]
j = reverse . mirror $ l
s =
[[0b00001_10000
,0b00011_00000
]
,[0b00001_00000
,0b00001_10000
,0b00000_10000
]
]
z = mirror s
o =
[[0b00001_10000
,0b00001_10000
]
]
mirror = map reverse
withWalls :: Well -> Well
withWalls = overlay $ replicate 19 sideWalls ++ [bottomWall]
where
sideWalls = 0b1_00000_00000_1
bottomWall = 0b1_11111_11111_1
overlay :: [Line] -> Well -> Well
overlay = zipWith (.|.)
draw :: GEnv -> State -> Plane
draw _ s = stringPlane $ render (withWalls $ add s)
render :: Well -> String
render = unlines . map renderLine
where
renderLine line = concatMap (renderBlock line) [0..14]
renderBlock line i = if indent line `testBit` i then "▇▉" else " "
indent line = line `shiftL` 3
add :: State -> Well
add (pieces, well) = overlay (head pieces ++ repeat 0) well
logic :: GEnv -> State -> Event -> State
logic _ s (KeyPress k)
| k == 'k', let s' = rot s, isValid s' = s'
| k == 'j', let s' = move (`div`2) s, isValid s' = s'
| k == 'l', let s' = move (*2) s, isValid s' = s'
logic _ s _
| let s' = fall s, isValid s' = s'
| otherwise = glue s
rot :: State -> State
rot (piece, well) = (tail . cycle $ piece, well)
move :: (Line -> Line) -> State -> State
move x (piece, well) = (map (map x) piece, well)
fall :: State -> State
fall (piece, well) = (map (0:) piece, well)
isValid :: State -> Bool
isValid (piece, well) = all (== 0) $ zipWith (.&.) (head piece) (withWalls well)
glue :: State -> State
glue s = (newPiece, map (\ _ -> 0) erase ++ keep)
where
newPiece = pieces!!(sum well' `mod` 7)
well' = add s
(keep, erase) = partition (<2046) well'