-
Notifications
You must be signed in to change notification settings - Fork 89
/
Copy pathCodeWorldMain.hs
134 lines (110 loc) · 4.21 KB
/
CodeWorldMain.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
130
131
132
133
134
-- By Chris Smith
{-# LANGUAGE NoImplicitPrelude #-}
module MyDrawing where
import Prelude
import FFI
import CodeWorld
main = playInCanvas initial step event draw
data World = World {
stars :: [(Double, Double, Double)],
asts :: [(Point, Vector)],
ship :: (Point, Vector),
direction :: Double,
left :: Double,
right :: Double,
thrust :: Double,
energy :: Double,
score :: Double,
lastScore :: Double,
maxScore :: Double,
savedGen :: StdGen
}
initial g = initialWith 0 0 g
initialWith m l g0 =
case splitR g0 of
(genStars, g1) -> case splitR g1 of
(genAsts, g2) ->
World {
stars = take 40 (makeStars genStars),
asts = take 20 (makeAsts genAsts),
ship = ((0,0), (0,0)),
direction = 0,
left = 0,
right = 0,
thrust = 0,
energy = 1,
score = 0,
maxScore = m,
lastScore = l,
savedGen = g2
}
makeStars g0 = case randomR (-250, 250) g0 of
(x, g1) -> case randomR (-250, 250) g1 of
(y, g2) -> case randomR ( 1, 3) g2 of
(r, g3) -> (x,y,r) : makeStars g3
makeAsts g0 = case randomR (-250, 250) g0 of
(x, g1) -> case randomR (-250, 250) g1 of
(y, g2) -> case randomR ( -30, 30) g2 of
(vx, g3) -> case randomR ( -30, 30) g3 of
(vy, g4) -> ((x,y), (vx, vy)) : makeAsts g4
effective w x | energy w > 0 = x w
| otherwise = 0
lost w = any (collision (ship w)) (asts w)
where collision ((x1,y1),_) ((x2,y2),_) = (((x2-x1)^2::Double) + ((y2-y1)^2::Double)) < 1764
step dt w = if lost w
then initialWith (maxScore w) (if score w < 1 then lastScore w else score w) (savedGen w)
else w {
asts = map (stepBody dt) (asts w),
ship = stepThrust dt (stepBody dt (ship w)) (effective w thrust) (direction w),
direction = stepDir dt (direction w) (left w) (right w),
energy = fence 0 1 (energy w + dt * (0.5 * (1 - thrust w) - 1.0 * thrust w)),
score = score w + dt,
maxScore = max (maxScore w) (score w)
}
fence lo hi v = max 0 (min hi v)
stepThrust dt ((x,y), (sx,sy)) th dir = ((x,y), (sx', sy'))
where sx' = sx + th * (-30) * sin (dir * pi / 180) * dt
sy' = sy + th * 30 * cos (dir * pi / 180) * dt
stepDir dt dir l r = dir + l * 90 * dt - r * 90 * dt
stepBody dt ((x,y),(sx,sy)) = ((wrap (x + sx * dt), wrap (y + sy * dt)), (sx, sy))
where wrap k | k <= (-300) = k + 600
| k >= 300 = k - 600
| otherwise = k
draw w = pictures [
rectangleSolid 500 500,
drawStars (stars w),
drawAsts (asts w),
drawShip (ship w) (direction w) (effective w thrust),
drawEnergyBar (energy w),
drawScoreBar (score w) (lastScore w) (maxScore w)
]
drawStars ss = pictures [
color (gray 0.5) (translate x y (circleSolid r ))
| (x,y,r) <- ss
]
drawAsts as = pictures [
color (light red) (translate x y (circleSolid 30))
| ((x,y),_) <- as
]
drawShip ((x,y),_) dir th = translate x y (rotate dir (pictures [
color (gray 0.2) (circle 12),
color cyan (polygon [(-9, -8), (9, -8), ( 0, 12) ]),
if th > 0 then color orange (polygon [( -8, -8), (-10, -11), (10, -11), (8, -8)])
else blank
]))
drawEnergyBar e = color yellow $ translate 0 (-230) $ rectangleSolid (400 * e) 15
drawScoreBar s l m = pictures [
color blue $ translate 0 230 $ rectangleSolid 500 15,
color white $ translate (-200) 225 $ scale 0.2 0.15 $ text $ "Score: " ++ fmtScore s,
color white $ translate ( -25) 225 $ scale 0.2 0.15 $ text $ "Last: " ++ fmtScore l,
color white $ translate ( 150) 225 $ scale 0.2 0.15 $ text $ "Max: " ++ fmtScore m
]
fmtScore :: Double -> String
fmtScore s = show (floor (10 * s))
event (KeyPressEvent "Up") w = w { thrust = 1 }
event (KeyReleaseEvent "Up") w = w { thrust = 0 }
event (KeyPressEvent "Left") w = w { left = 1 }
event (KeyReleaseEvent "Left") w = w { left = 0 }
event (KeyPressEvent "Right") w = w { right = 1 }
event (KeyReleaseEvent "Right") w = w { right = 0 }
event _ w = w