-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGameFlow.hs
133 lines (121 loc) · 7.64 KB
/
GameFlow.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
module GameFlow where
import Env
import EnvChanges
import Agents
import Data.Data
import Data.Matrix
--Start Simulation
--An environment can be provided or one can be generated
--simTime: max time to keep on simulation
startSimulation :: Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> Int -> [Element] -> Bool -> IO ()
startSimulation rows cols obsts robots babys dirt robotTypes randomVariationTime simTime board generateBoard = do
let
initialEnv = if generateBoard
then initializeEnv rows cols obsts robots babys dirt
else board
in gameCicle rows cols robotTypes randomVariationTime simTime 0 initialEnv [] [] False 0
--Main cicle of the game. Call for environment random changes and for the robots response.
gameCicle :: Int -> Int -> Int -> Int -> Int-> Int -> [Element] -> [Element] -> [Element] -> Bool -> Int -> IO ()
gameCicle rows cols robotTypes randomVariationTime simTime currentTime env babiesEnv dirtEnv True fLegend= printStadistics env dirtEnv currentTime rows cols fLegend
gameCicle rows cols robotTypes randomVariationTime simTime currentTime env babiesEnv dirtEnv False fLegend = do
printState env dirtEnv currentTime rows cols
let babiesEnv = moveBabies rows cols env
dirtEnv = if ((mod currentTime randomVariationTime) == 0 )
then createDirt rows cols env babiesEnv
else babiesEnv
(envChangedByRobot, finalEnv) = moveRobots rows cols dirtEnv robotTypes
envChanged = envChangedByRobot
gameOver = isGameOver rows cols finalEnv
tLimitExceed = simTime == currentTime
fLegend = if tLimitExceed
then 0
else
if gameOver
then 1
else 2
finishSim = tLimitExceed || gameOver || not envChanged in gameCicle rows cols robotTypes randomVariationTime simTime (currentTime+1) finalEnv babiesEnv dirtEnv finishSim fLegend
--Translate the env to a matrix
getEnvAsMatrix :: [Element] -> Int -> Int -> Matrix [Char]
getEnvAsMatrix env rows cols = fmatrix
where
bmatrix = matrix rows cols $ \(i, j)-> " "
fmatrix = fillMatrix env bmatrix
--Populate the matrix with the simulation state
fillMatrix :: [Element] -> Matrix [Char] -> Matrix [Char]
fillMatrix [] board = board
fillMatrix (e:rest) board = fillMatrix rest newBoard
where
x = row e
y = column e
elementName = show $ toConstr (e)
wc = if (elementName == "Baby" || elementName == "Robot") then wcompany e else False
oldString = board ! (x,y)
mRepr = getStringForMatrix oldString elementName wc
newBoard = setElem mRepr (x, y) board
--Get the corresponding string for a tile in the matrix representing the board
getStringForMatrix :: String -> String -> Bool -> String
getStringForMatrix oldString elementName wc = newString
where
elementRepresentation = elementLegend elementName wc
initialChar = oldString !! 0
finalChar = oldString !! 4
newString = if elementName == "Obstacle" || elementName == "Playpen"
then
elementRepresentation
else
if (oldString !! 2) /= ' '--there was already 1 element in the tile
then
if (oldString !! 1) /= ' '
then "-----"--there was already 3 elements in the tile
else [initialChar] ++ [oldString !! 2] ++ " " ++ elementRepresentation ++ [finalChar]
else
if (oldString !! 1) /= ' ' && (oldString !! 3) /= ' '--two elements in the tile
then [initialChar] ++ [oldString !! 1] ++ elementRepresentation ++ [oldString !! 3] ++ [finalChar]
else [initialChar] ++ " " ++ elementRepresentation ++ " " ++ [finalChar]--first element found in that tile
--Works like a dictionary from every element in the simulation to their corresponding representation
elementLegend :: String -> Bool -> String
elementLegend elementName wc = case elementName of
"Dirt" -> "D"
"Obstacle"-> " /// "
"Playpen" -> "| |"
"Baby" -> if wc then "B" else "b"
"Robot" -> if wc then "R" else "r"
--Print stadistics about the simulation
printStadistics :: [Element] -> [Element] -> Int -> Int -> Int -> Int -> IO ()
printStadistics finalEnv dirtEnv time rows cols fLegend = do
printState finalEnv dirtEnv time rows cols
putStrLn "Simulation Stopped"
let reasonOfCulmmination = if fLegend == 0
then "Time Limit exceed"
else
if fLegend == 1
then "Dirt Amount exceed 40 %"
else "No more moves available for robots"
putStrLn reasonOfCulmmination
putStrLn "Stadistics:"
putStrLn "Board dimensions: "
putStrLn ("Rows: "++ show rows)
putStrLn ("Columns: "++ show cols)
putStrLn ("Simulation time: "++ show time ++ " s")
let dirtTiles = takeDirt finalEnv finalEnv
let dirtPercentange = (length dirtTiles) * 100 `div` (rows * cols)
putStrLn ("Dirt tiles: "++ show dirtPercentange ++ "%")
let babiesFree = takeBabies finalEnv finalEnv
putStrLn ("Unreached babies: " ++ show (length babiesFree))
--Print simulation state in a nice and easy way to undestand
printState :: [Element] -> [Element] -> Int -> Int -> Int -> IO ()
printState finalEnv dirtEnv t rows cols = do
putStrLn ("Simulation time: " ++ show t)
putStrLn "Environment's random variation:"
let dirtMatrix = getEnvAsMatrix dirtEnv rows cols
putStrLn (show dirtMatrix)
putStrLn "Robot's response:"
let finalMatrix = getEnvAsMatrix finalEnv rows cols
putStrLn (show finalMatrix)
--Returns True is the amount of dirt in the env represents more than 40 percent of total tiles
isGameOver :: Int -> Int -> [Element] -> Bool
isGameOver rows cols env = amountOfDirt > fortyPercent
where
dirtyElements = takeDirt env env
amountOfDirt = length dirtyElements
fortyPercent = (rows * cols * 40 ) `div` 100