Skip to content

Commit 6b007dc

Browse files
committed
Merge branch 'leynier' into main
2 parents 02e20a5 + 3bebde4 commit 6b007dc

File tree

5 files changed

+242
-38
lines changed

5 files changed

+242
-38
lines changed

app/Main.hs

Lines changed: 75 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,84 @@
11
module Main where
22

3-
import System.Random
43

5-
import Structures
64
import Algorithms
5+
import Console
6+
import Structures
7+
import System.IO
8+
import System.Random
9+
10+
11+
main = do
12+
putStrLn "Welcome to Hidato!!! Type 'help' to see the list of available commands."
13+
hFlush stdout
14+
console
15+
16+
17+
console :: IO ()
18+
console = do
19+
Console.start cmds
720

21+
cmds :: [Command]
22+
cmds = [commandGenerate, commandSolve]
823

9-
main = do
10-
let rand = randomIO :: IO Int
11-
seed <- rand
24+
25+
generateFunction :: [Char] -> [Char] -> [Char] -> [Char] -> FilePath -> [Char] -> IO ()
26+
generateFunction rs cs ra di path to = do
27+
seed <- randomIO :: IO Int
1228
let gen = mkStdGen seed
1329
let seeds = randoms gen :: [Int]
1430

15-
print "Introduzca la cantidad de filas:"
16-
rowsString <- getLine
17-
let rows = read rowsString :: Int
18-
print "Introduzca la cantidad de columnas:"
19-
columnsString <- getLine
20-
let columns = read columnsString :: Int
21-
print "Introduzca el radio de obstaculos:"
22-
ratioString <- getLine
23-
let ratio = read ratioString :: Float
24-
print "Introduzca la dificultad:"
25-
dificultyString <- getLine
26-
let dificulty = read dificultyString :: Dificulty
27-
m <- generateGame rows columns ratio dificulty
28-
print m
29-
let sol = solve m seeds
30-
print sol
31+
let rows = read rs :: Int
32+
let columns = read cs :: Int
33+
let ratio = read ra :: Float
34+
let difficulty = read di :: Difficulty
35+
let tout = read to :: Int
36+
37+
(ok, m) <- generateGame rows columns ratio difficulty tout
38+
39+
if ok then do
40+
writeFile path (show m)
41+
print m
42+
else do
43+
putStrLn "The generator could not generate a hidato with the indicated arguments and the indicated time."
44+
45+
46+
commandGenerate :: Command
47+
commandGenerate =
48+
Command
49+
{
50+
cmdName = "generate",
51+
cmdDescription = "Command to generate a hidato. The board is save to a file.\nDifficulty: [Easy, Normal, Hard]\nDefault timeout: 60000000 microseconds = 1 minute",
52+
cmdArgs = ["ROWS", "COLUMNS", "RATIO", "DIFFICULTY", "FILEPATH", "TIMEOUT (OPTIONAL)"],
53+
cmdIO = \args -> do
54+
case args of
55+
[rs, cs, ra, di, path] -> generateFunction rs cs ra di path "60000000"
56+
[rs, cs, ra, di, path, to] -> generateFunction rs cs ra di path to
57+
otherwise -> print "The number of arguments is not correct"
58+
return 0
59+
}
60+
61+
62+
commandSolve :: Command
63+
commandSolve =
64+
Command
65+
{
66+
cmdName = "solve",
67+
cmdDescription = "Command to solve a hidato. The board is obtained from a file.",
68+
cmdArgs = ["FILEPATH"],
69+
cmdIO = \args -> do
70+
case args of
71+
[filePath] -> do
72+
text <- readFile filePath
73+
let table = read text :: Matrix
74+
seed <- randomIO :: IO Int
75+
let gen = mkStdGen seed
76+
let seeds = randoms gen :: [Int]
77+
let solves = solveAll table seeds
78+
if null solves then do
79+
print "Solve not found"
80+
else do
81+
print $ head solves
82+
otherwise -> print "The number of arguments is not correct"
83+
return 0
84+
}

hidato.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ cabal-version: 1.12
44
--
55
-- see: https://github.com/sol/hpack
66
--
7-
-- hash: 8990a2fc1a1f4fa5cf6bcf0dc27fc8585348d19663dd6d611e9d1f7fb613dc4c
7+
-- hash: be00057decf180595c875f0852db5de4a7bb552ba6b5d44ec64fabd77e70bd53
88

99
name: hidato
1010
version: 0.1.0.0
@@ -27,6 +27,7 @@ source-repository head
2727
library
2828
exposed-modules:
2929
Algorithms
30+
Console
3031
Structures
3132
other-modules:
3233
Paths_hidato

src/Algorithms.hs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module Algorithms
2-
( Dificulty(..)
2+
( Difficulty(..)
33
, generate
44
, solve
55
, solveAll
@@ -8,22 +8,25 @@ module Algorithms
88
, validateTemplate
99
) where
1010

11-
import System.Random
12-
import Structures
11+
12+
import Data.Map (Map)
13+
import qualified Data.Map as Map
14+
import Data.Maybe
1315
import Data.Set (Set, lookupMin, lookupMax)
1416
import qualified Data.Set as Set
1517
import Debug.Trace
16-
import Data.Map (Map)
17-
import qualified Data.Map as Map
18+
import Structures
19+
import System.Random
1820
import System.Timeout
19-
import Data.Maybe
21+
2022

2123
genRCell :: Int -> Int -> Int -> IO Cell
2224
genRCell rn cn val = do
2325
r <- randomRIO (1, rn)
2426
c <- randomRIO (1, cn)
2527
return $ Cell r c val
2628

29+
2730
genRCellFromSet :: Set Cell -> IO [Cell]
2831
genRCellFromSet set = if Set.null set
2932
then do
@@ -36,6 +39,7 @@ genRCellFromSet set = if Set.null set
3639
sets <- genRCellFromSet newSet
3740
return $ e : sets
3841

42+
3943
generateRandom :: Int -> Int -> Float -> IO Matrix
4044
generateRandom rn cn ratio = do
4145
let obs_ratio = if ratio < 0 || ratio > 1 then 0.33 else ratio
@@ -52,13 +56,16 @@ generateRandom rn cn ratio = do
5256
result <- generateRandom rn cn ratio
5357
return result
5458

55-
data Dificulty = Easy | Normal | Hard deriving (Ord, Eq, Show, Read)
5659

57-
emptyRatio :: Dificulty -> Float
60+
data Difficulty = Easy | Normal | Hard deriving (Ord, Eq, Show, Read)
61+
62+
63+
emptyRatio :: Difficulty -> Float
5864
emptyRatio Easy = 50/100
5965
emptyRatio Normal = 60/100
6066
emptyRatio Hard = 70/100
6167

68+
6269
generateRandomGame :: Int -> Int -> Float -> IO Matrix
6370
generateRandomGame rn cn ratio = do
6471
maybeTemplate <- timeout 1000000 $ generateRandom rn cn ratio
@@ -77,6 +84,7 @@ generateRandomGame rn cn ratio = do
7784
else do
7885
return $ head solutions
7986

87+
8088
removeCells :: Matrix -> [Cell] -> Int -> Int -> [Int] -> Matrix
8189
removeCells sol@(Matrix rn cn cs) cells ite n seeds =
8290
if null cells || ite >= n then
@@ -94,11 +102,12 @@ removeCells sol@(Matrix rn cn cs) cells ite n seeds =
94102
else
95103
removeCells sol tailCells (ite + 1) n seeds
96104

97-
generateGame :: Int -> Int -> Float -> Dificulty -> IO Matrix
98-
generateGame rn cn ratio dif = do
99-
maybeMatrix <- timeout 60000000 $ generateRandomGame rn cn ratio
105+
106+
generateGame :: Int -> Int -> Float -> Difficulty -> Int -> IO (Bool, Matrix)
107+
generateGame rn cn ratio dif to = do
108+
maybeMatrix <- timeout to $ generateRandomGame rn cn ratio
100109
if isNothing maybeMatrix then do
101-
return $ error "Game not found"
110+
return (False, blankMatrix 1 1)
102111
else do
103112
let solution = maybe (blankMatrix rn cn) (\x -> x) maybeMatrix
104113
let setForRemove = Set.filter (\x -> let v = value x in v > 1 && v < rn * cn) (matrix solution) :: Set Cell
@@ -109,11 +118,13 @@ generateGame rn cn ratio dif = do
109118
let gen = mkStdGen seed
110119
let seeds = randoms gen :: [Int]
111120
let game = removeCells solution randomCells 0 cant_empty seeds
112-
return game
121+
return (True, game)
122+
113123

114124
generate :: Matrix
115125
generate = read "{. x x x x x x x x \n . 8 x x x x x x x \n . . 11 x x x x x x \n 29 . 10 . x x x x x \n 30 . . . . x x x x \n . 31 1 38 . . x x x \n . 32 . . 39 41 . x x \n . . . 22 . . 42 . x \n . . . . . . . 44 45}" :: Matrix
116126

127+
117128
stepMatrix :: Int -> Matrix -> Cell -> Map Int Cell -> [Int] -> [(Matrix, Cell)]
118129
stepMatrix step m@(Matrix rs cs ma) prevCell map seeds = if Map.notMember step map
119130
then [
@@ -125,9 +136,11 @@ stepMatrix step m@(Matrix rs cs ma) prevCell map seeds = if Map.notMember step m
125136
else let actCell = map Map.! step
126137
in [newMatrix | isAdjacent actCell prevCell || value actCell == 1, let newMatrix = (m, actCell)]
127138

139+
128140
buildMap :: Matrix -> Map Int Cell
129141
buildMap ma@(Matrix r c m) = Set.foldl (\acc cell -> Map.insert (value cell) cell acc) Map.empty m
130142

143+
131144
validateTemplate :: Matrix -> Bool
132145
validateTemplate (Matrix rn cn cells)
133146
| sum [ 1 | degree <- degrees, degree == 0 ] > 0 = False
@@ -137,15 +150,18 @@ validateTemplate (Matrix rn cn cells)
137150
let adjacents = [ adjR | adj <- getAdjacents cell rn cn 0 [1..],
138151
let Just adjR = Set.lookupGE adj cells, adjR /= cell, value adjR == 0]]
139152

153+
140154
solveRecursiveDFS :: Matrix -> Int -> Cell -> Int -> Map Int Cell -> [Int] -> [Matrix]
141155
solveRecursiveDFS actualMatrix step prevCell obs map seeds
142156
| step == obs + 1 = [actualMatrix]
143157
| otherwise = let toAdd = stepMatrix step actualMatrix prevCell map seeds
144158
in concat [ solveRecursiveDFS matrix (step + 1) prevCell obs map (tail seeds) | (matrix, prevCell) <- toAdd ]
145159

160+
146161
solveAll :: Matrix -> [Int] -> [Matrix]
147162
solveAll m = solveRecursiveDFS m 1 (Cell 0 0 0) (rows m * columns m - countObstacles m) (buildMap m)
148163

164+
149165
solve :: Matrix -> [Int] -> Matrix
150166
solve m seeds = let solves = solveAll m seeds
151167
in case solves of [] -> error "Solve not found"

src/Console.hs

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{-# LANGUAGE BlockArguments #-}
2+
3+
module Console
4+
( start
5+
, commandHelp
6+
, consoleLoop
7+
, commandExit
8+
, Command (..),
9+
) where
10+
11+
12+
import Control.Monad (when)
13+
import Data.List (find)
14+
import Debug.Trace
15+
import System.IO
16+
17+
18+
start :: [Command] -> IO ()
19+
start cmds = do
20+
let cmdList = cmds ++ [commandExit]
21+
let cmdListWithHelp = commandHelp (createHelp : cmdList) : cmdList
22+
consoleLoop cmdListWithHelp
23+
where
24+
createHelp = commandHelp []
25+
26+
27+
consoleLoop :: [Command] -> IO ()
28+
consoleLoop cmds = do
29+
putStr "> "
30+
hFlush stdout
31+
input <- getLine
32+
let command = words input
33+
when (null command) do
34+
-- empty case, just enter
35+
start cmds
36+
let r = find (\a -> head command == cmdName a) cmds
37+
case r of
38+
Just c -> do
39+
ret <- cmdIO c $ tail command
40+
case ret of
41+
0 -> consoleLoop cmds
42+
1 -> return ()
43+
Nothing -> do
44+
putStrLn $ "Command \"" ++ head command ++ "\" not found. Try \"help\" to find all avalidable commands."
45+
consoleLoop cmds
46+
47+
48+
data Command = Command
49+
{ cmdName :: String,
50+
cmdDescription :: String,
51+
cmdArgs :: [String],
52+
cmdIO :: [String] -> IO Int
53+
}
54+
55+
56+
-- Help Commands
57+
commandHelp :: [Command] -> Command
58+
commandHelp cmds =
59+
Command
60+
{ cmdName = "help",
61+
cmdDescription = "The Help command will help you in all your needs",
62+
cmdArgs = ["COMMAND"],
63+
cmdIO = \args -> do
64+
case args of
65+
[] -> do
66+
putStrLn "Avalidable Commands: "
67+
putStr $ unlines $ map printCmd cmds
68+
putStrLn ""
69+
[command] -> do
70+
let r = find (\a -> command == cmdName a) cmds
71+
case r of
72+
Just c ->
73+
putStr $
74+
unlines
75+
[ cmdName c ++ " - " ++ cmdDescription c,
76+
"Usage: " ++ cmdName c ++ " " ++ printArgs (cmdArgs c),
77+
""
78+
]
79+
Nothing -> putStrLn $ "Command \"" ++ command ++ "\" not found. Try \"help\" to find all avalidable commands."
80+
return 0
81+
}
82+
where
83+
printArgs args = foldl (\a b -> a ++ "[" ++ b ++ "] ") "" args
84+
printCmd c = unwords ["\t", cmdName c, "\t\t", printArgs (cmdArgs c)]
85+
86+
87+
commandExit :: Command
88+
commandExit =
89+
Command
90+
{ cmdName = "exit",
91+
cmdDescription = "Exit the console",
92+
cmdArgs = [],
93+
cmdIO = \_ -> do
94+
putStrLn "Are you sure? y/n"
95+
answer <- getLine
96+
return case answer of
97+
"y" -> 1
98+
"n" -> 0
99+
}

0 commit comments

Comments
 (0)