-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathLanguageTreeAdventure.hs
More file actions
268 lines (239 loc) · 10.3 KB
/
LanguageTreeAdventure.hs
File metadata and controls
268 lines (239 loc) · 10.3 KB
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
module Main where
import LanguageTree
import Parser
import Cmd
import System.IO
import System.Exit (exitSuccess, exitFailure)
import Data.Char (toLower)
import Text.Read (readMaybe)
import Data.List (find)
main :: IO ()
main = do
putStrLn "Welcome to the Language Learning Adventure!\n"
targetLang <- selectLanguage
let langData = generateLanguageData targetLang
level <- selectLevel (levels langData)
let initialZip = initializeGame level
putStrLn $ "You have chosen " ++ show targetLang ++ ", Level " ++ show (levelNumber level) ++ ". Let's begin!\n"
displayHelp
gameLoop initialProgress initialZip
type Progress = [String]
initialProgress :: Progress
initialProgress = []
updateProgress :: String -> Progress -> Progress
updateProgress item progress = if item `elem` progress then progress else item : progress
viewProgress :: Progress -> IO ()
viewProgress [] = putStrLn "You have not completed any lessons yet."
viewProgress progress = do
putStrLn "\nLessons completed:"
mapM_ putStrLn (reverse progress)
selectLanguage :: IO TargetLanguage
selectLanguage = do
putStrLn "Please choose a target language: Spanish, French, or German."
putStr "> "
hFlush stdout
input <- getLine
case parseLang input of
Just lang -> return lang
Nothing -> putStrLn "Invalid language. Please try again." >> selectLanguage
parseLang :: String -> Maybe TargetLanguage
parseLang input =
case map toLower input of
"spanish" -> Just Spanish
"french" -> Just French
"german" -> Just German
_ -> Nothing
selectLevel :: [Level] -> IO Level
selectLevel availableLevels = do
putStrLn "Please choose a level:"
mapM_ (\lvl -> putStrLn $ "Level " ++ show (levelNumber lvl)) availableLevels
putStr "> "
hFlush stdout
input <- getLine
case readMaybe input :: Maybe Int of
Just num ->
case find (\lvl -> levelNumber lvl == num) availableLevels of
Just lvl -> return lvl
Nothing -> putStrLn "Invalid level number. Please try again." >> selectLevel availableLevels
Nothing -> putStrLn "Invalid input. Please enter a level number." >> selectLevel availableLevels
initializeGame :: Level -> LangZip
initializeGame level =
let (l:ls) = lessons level
(n:ns) = nodes l
lessonCxt = LessonCxt (title l) [] ns
levelCxt = LevelCxt [] ls (Just lessonCxt)
in (InLevel levelCxt, n)
-- Game Loop
gameLoop :: Progress -> LangZip -> IO ()
gameLoop progress z@(cxt, node) = do
putStrLn $ "\nYou are at: " ++ getNodeTitle node
putStrLn "What would you like to do? (Type 'help' for commands)"
putStr "> "
hFlush stdout
input <- getLine
case parseInput input of
Just Next -> case go_next z of
Just z' -> gameLoop progress z'
Nothing -> endOfLesson progress z
Just Back -> case go_back z of
Just z' -> gameLoop progress z'
Nothing -> putStrLn "You are at the beginning." >> gameLoop progress z
Just Learn -> do
putStrLn $ "\n" ++ drawLangNode node ++ "\n"
gameLoop progress z
Just Quiz -> case node of
QuizNode questions -> do
putStrLn "\nStarting Quiz! Type 'exitquiz' or 'eq' to leave the quiz early."
score <- takeQuiz questions 0
putStrLn $ "\nYou scored " ++ show score ++ " out of " ++ show (length questions)
gameLoop progress z
_ -> do
putStrLn "No quiz available here."
gameLoop progress z
Just ExitQuiz -> putStrLn "You are not in a quiz to exit." >> gameLoop progress z
Just Progress -> do
viewProgress progress
gameLoop progress z
Just Quit -> do
putStrLn "Thank you for playing!"
exitSuccess
Just Help -> do
displayHelp
gameLoop progress z
Nothing -> do
putStrLn "Invalid command. Please try again."
gameLoop progress z
getNodeTitle :: LangNode -> String
getNodeTitle (WordNode word _) = "Word: " ++ word
getNodeTitle (GrammarNode rule _) = "Grammar Rule: " ++ rule
getNodeTitle (QuizNode _) = "Quiz Section"
-- Quiz Functionality with Early Exit
takeQuiz :: [QuizQuestion] -> Int -> IO Int
takeQuiz [] score = return score
takeQuiz (q:qs) score = do
putStrLn $ "\nQuestion: " ++ question q
putStr "> "
hFlush stdout
userAnswer <- getLine
case parseInput userAnswer of
Just ExitQuiz -> do
putStrLn "Exiting the quiz."
return score
_ -> if map toLower userAnswer == map toLower (answer q)
then do
putStrLn "Correct!"
takeQuiz qs (score + 1)
else do
putStrLn $ "Incorrect. The correct answer is: " ++ answer q
takeQuiz qs score
-- Navigation Functions
go_next :: LangZip -> Maybe LangZip
go_next (InLevel levelCxt, node) =
case currentLessonCxt levelCxt of
Just lessonCxt ->
case remainingNodes lessonCxt of
(n:ns) ->
let newLessonCxt = lessonCxt { completedNodes = completedNodes lessonCxt ++ [node], remainingNodes = ns }
newLevelCxt = levelCxt { currentLessonCxt = Just newLessonCxt }
in Just (InLevel newLevelCxt, n)
[] ->
-- End of nodes in current lesson
go_to_next_lesson (InLevel levelCxt { completedLessons = completedLessons levelCxt ++ [Lesson (lessonTitle lessonCxt) (completedNodes lessonCxt ++ [node])], currentLessonCxt = Nothing }, node)
Nothing ->
-- No current lesson, attempt to move to next lesson
go_to_next_lesson (InLevel levelCxt, node)
go_to_next_lesson :: LangZip -> Maybe LangZip
go_to_next_lesson (InLevel levelCxt, _) =
case remainingLessons levelCxt of
(l:ls) ->
let (n:ns) = nodes l
newLessonCxt = LessonCxt (title l) [] ns
newLevelCxt = levelCxt { completedLessons = completedLessons levelCxt, remainingLessons = ls, currentLessonCxt = Just newLessonCxt }
in Just (InLevel newLevelCxt, n)
[] ->
-- End of level
Nothing -- Handle end of level in the game loop
go_back :: LangZip -> Maybe LangZip
go_back (InLevel levelCxt, node) =
case currentLessonCxt levelCxt of
Just lessonCxt ->
case completedNodes lessonCxt of
(b:bs) ->
let newLessonCxt = lessonCxt { completedNodes = bs, remainingNodes = node : remainingNodes lessonCxt }
newLevelCxt = levelCxt { currentLessonCxt = Just newLessonCxt }
in Just (InLevel newLevelCxt, b)
[] -> Nothing -- At the beginning of the lesson
Nothing -> Nothing -- No lesson context
-- End of Lesson Handling
endOfLesson :: Progress -> LangZip -> IO ()
endOfLesson progress z@(InLevel levelCxt, node) = do
case currentLessonCxt levelCxt of
Just lessonCxt -> do
let completedLesson = Lesson (lessonTitle lessonCxt) (completedNodes lessonCxt ++ [node])
let updatedLevelCxt = levelCxt {
completedLessons = completedLessons levelCxt ++ [completedLesson],
currentLessonCxt = Nothing
}
case remainingLessons updatedLevelCxt of
(l:ls) -> do
let (n:ns) = nodes l
let newLessonCxt = LessonCxt (title l) [] ns
let newLevelCxt = updatedLevelCxt {
remainingLessons = ls,
currentLessonCxt = Just newLessonCxt
}
putStrLn "\nLesson completed. Moving to the next lesson."
gameLoop progress (InLevel newLevelCxt, n)
[] -> do
putStrLn "\nCongratulations! You have completed this level!"
proceedToNextLevel progress (InLevel updatedLevelCxt, node)
Nothing -> do
putStrLn "Error: No current lesson to end."
exitFailure
proceedToNextLevel :: Progress -> LangZip -> IO ()
proceedToNextLevel progress z@(InLevel levelCxt, _) = do
putStrLn "Do you want to proceed to the next level? (yes/no)"
input <- getLine
case map toLower input of
"yes" -> do
let currentLevelNumber = levelNumberFromContext levelCxt
let nextLevelNumber = currentLevelNumber + 1
let allLevels = getAllLevelsForLanguage (languageFromContext levelCxt)
case find (\lvl -> levelNumber lvl == nextLevelNumber) allLevels of
Just nextLevel -> do
let initialZip = initializeGame nextLevel
gameLoop progress initialZip
Nothing -> do
putStrLn "No more levels available."
exitSuccess
_ -> do
putStrLn "Thank you for playing!"
exitSuccess
-- Helper functions to extract level number and language from context
levelNumberFromContext :: LevelCxt -> Int
levelNumberFromContext levelCxt = levelNumber $ getLevelFromContext levelCxt
getLevelFromContext :: LevelCxt -> Level
getLevelFromContext levelCxt = undefined -- Implement this to retrieve the current level
getAllLevelsForLanguage :: TargetLanguage -> [Level]
getAllLevelsForLanguage lang = levels $ generateLanguageData lang
languageFromContext :: LevelCxt -> TargetLanguage
languageFromContext levelCxt = undefined -- Implement this to retrieve the language
-- Pretty Printing
drawLangNode :: LangNode -> String
drawLangNode (WordNode word translation) =
"Word: " ++ word ++ " - " ++ translation
drawLangNode (GrammarNode rule explanation) =
"Grammar Rule: " ++ rule ++ "\nExplanation: " ++ explanation
drawLangNode (QuizNode _) =
"Quiz Time! Type 'quiz' to start the quiz."
-- Display help commands
displayHelp :: IO ()
displayHelp = do
putStrLn "\nAvailable commands:"
putStrLn "Type 'next' or 'n' to proceed to the next content."
putStrLn "Type 'back' or 'b' to go back."
putStrLn "Type 'learn' or 'l' to see the content."
putStrLn "Type 'quiz' or 'qz' to take a quiz (when available)."
putStrLn "Type 'exitquiz' or 'eq' to exit a quiz early."
putStrLn "Type 'progress' or 'p' to view your progress."
putStrLn "Type 'quit' or 'q' to exit.\n"