What my program does? Take input from user, it needs to be between 0-99.
Program ends when user guesses the number "guess" which is 45 or after taking 10 tries.
The problem is that I cant figure out the second part of this game.
guess = 45
game = do
putStrLn ("Give a number between 0 and 99")
a <- getLine
let x = read a
if x == guess then print ("You got it!") else game
You can make a helper function where you use a parameter with the number of guesses. Each time you make a recursive call where you decrement the number of guesses, if the variable is less than or equal to zero, we can stop the recursion:
guess :: Int
guess = 45
tries :: Int
tries = 10
main :: IO ()
main = game tries
game :: Int -> IO ()
game n
| n <= 0 = putStrLn "end of the game"
| otherwise = do
putStrLn "Give a number between 0 and 99"
a <- readLn
if a == guess then putStrLn "You got it!" else game (n-1)
Thank you Willem! Had to rearrange some things in the code but you gave me the idea. Thats how now it looks like:
guess = 45
tries = 10
main = zad5 tries
zad5 y = do
putStrLn ("Give a number between 0 and 99")
a <- getLine
let x = read a
if y==1 || x == guess then print ("end of the game") else zad5 (y-1)
Related
I want to write a simple game "guess number" - with n attempts. I want to add some conditions and hits. Is it possible to use guards inside do block ?
Here is my code:
game = return()
game n = do putStrLn "guess number: 0-99"
number<-getLine
let y = read number
let x =20
| y>x = putStrLn "your number is greater than x"
| y<x = putStrLn "your number is less than x"
| y==x putStrLn "U win!!"
| otherwise = game (n-1)
already got error
error: parse error on input ‘|’
Is it fixable with some white space, or just impossible to do?
A do expression [Haskell-report] only consists out of exp, pat <- exp, and let … statements, and the compiler will desugar these. Hence without some language extensions, you can not write guards in a do block. Furthermore it is likely not a good idea to enable that anyway. What if you for example would want to use two "guard blocks" next to each other? Then the two would "merge" and thus the guards of the first block would already eleminate (nearly) all cases.
You can use another let clause here:
game :: IO ()
game 0 = return ()
game n = do
putStrLn "guess number: 0-99"
number <- getLine
let y = read number
let x = 20
let action | y > x = putStrLn "your number is greater than x" >> game (n-1)
| y < x = putStrLn "your number is less than x" >> game (n-1)
| otherwise = putStrLn "U win!!"
action
Note that the otherwise in the original question will never get triggered, since a value is less than, greater than, or equal to another value.
Lots of problems there.
First, you can't say game = something and game n = something, so remove the game = return () line. (You may have been trying to write a type signature, but that's not one.)
Second, you can't drop into guard syntax in arbitrary places. The closest valid thing to what you wrote are multi-way if-expressions, which would let you write this:
{-# LANGUAGE MultiWayIf #-}
game n = do putStrLn "guess number: 0-99"
number<-getLine
let y = read number
let x =20
if
| y>x -> putStrLn "your number is greater than x"
| y<x -> putStrLn "your number is less than x"
| y==x-> putStrLn "U win!!"
| otherwise -> game (n-1)
Third, the Ord typeclass is supposed to be for types with a total order, so unless you're using unlawful things like NaN, you'll always have one of y>x, y<x, or y==x, so the otherwise will never be entered.
Fourth, comparing with <, ==, and > is unidiomatic and slow, since it has to keep repeating the comparison. Instead of doing that, do something like this:
case y `compare` x of
GT -> _
LT -> _
EQ -> _
You could also just use case or LambdaCase.
{-# LANGUAGE LambdaCase #-}
game :: Int -> IO ()
game n = case n of
0 -> putStrLn "used all attempts"
n ->
putStrLn "guess a number: 0 - 99" >>
(`compare` 20) . read <$> getLine >>=
\case
EQ -> putStrLn "U win"
GT -> putStrLn "your number is greater than x" >>
game (n - 1)
LT -> putStrLn "your number is less than x" >>
game (n - 1)
The other answers are very informative. Reading those led me to see that you can also call a function to solve this, e.g.
game = do putStrLn "guess number: 0-99"
number <- getLine
let y = read number
let x = 20
action y x
where
action y x
| y>x = putStrLn "your number is greater than x" >> game
| y<x = putStrLn "your number is less than x" >> game
| otherwise = putStrLn "U win!!"
I have the following simple number guess program
import System.Random
turn :: Int -> Int -> Int -> IO ()
turn number attempt attempts =
do
if attempts == 0
then putStrLn "You lose"
else if attempt==number
then putStrLn "You got it!"
else if attempt==0
then guess number attempt attempts
else if attempt < number
then do
putStrLn "The number is greater"
guess number attempt attempts
else
do
putStrLn "The number is lesser"
guess number attempt attempts
guess :: Int -> Int -> Int -> IO ()
guess number attempt attempts =
do
putStr "Try and guess number "
g <- getLine
let number' = read g :: Int
let check = (number'==number)
let attempts' = if check then attempts else attempts - 1
turn number number' attempts'
numberGuess :: IO ()
numberGuess = do
let attempts = 5
number <- randomRIO (0, 10) :: IO Int
turn number 0 attempts
How can I clean up the ugly if else or what techniques are available in haskell?
Your outermost do in turn doesn't actually do anything. So you should nix it. Next, use pattern matching and guards to begin to clean things up.
turn _number _attempt 0 = putStrLn "You lose"
turn number attempt attempts
| attempt == number = putStrLn "You got it!"
| attempt == 0 = guess number attempt attempts
| attempt < number = do
putStrLn "The number is greater"
guess number attempt attempts
| otherwise = do
putStrLn "The number is lesser"
guess number attempt attempts
The final step to clean up turn will be factoring out the pattern "Do something, then call guess". I'll let you try that on your own. I used a pattern match for the first case to demonstrate that technique, which is very often the right one. In this particular case you might be better off just using guards.
For guess, the easy bit is just to combine some expressions.
guess :: Int -> Int -> Int -> IO ()
guess number attempt attempts = do
putStr "Try and guess number "
g <- getLine
let attempts' = if read g == number
then attempts
else attempts - 1
turn number number' attempts'
Note, however, that read generally shouldn't be used to process user input, as it will crash your program on bad input. Import Text.Read and use readMaybe, perhaps.
I am totally new to Haskell. I am writing code to accept a series of values.
eg.
1 2
3 4
0 0
The last condition in when the input stops and I should display the values 1 2 3 4.
I have done the following, but it doesn't work. I need some help.
main = myLoop
myLoop = do inp <- getLine
if (inp == "0 0") then
putStrLn "END"
else do putStrLn(inp)
myLoop
First of all, make sure you are not using tabs in your source. In order to get your example to work I had to line up the putStrLn and the myLoop like this:
myLoop = do inp <- getLine
if (inp == "0 0") then
putStrLn "END"
else do putStrLn(inp)
myLoop
-- ^ note putStrLn and myLoop are at the same column
Secondly, I'll answer the question assuming you want to read in a list of numbers / words.
readNums :: IO [String]
readNums = do
x <- getLine
if x == "0 0"
then return []
else do xs <- readNums
return (words x ++ xs)
Example usage:
main = do nums <- readNums
print nums
I am doing a number guessing game in Haskell and I have 3 difficulties.
I made a menu where the user selects what difficulty but once I implemented it, it started giving me an error and I can't figure out what it is.
The error:
finalename.hs:5:10:
Parse error in pattern: putStrLn
Possibly caused by a missing 'do'?
Also how would I go about implementing a count where it counts how many times it takes for the user to guess?
import System.Random (randomRIO)
main :: IO ()
main = do
putStrLn "Do you want to play 1) Easy, 2) Medium or 3) Hard"
putStrLn "Select your difficulty by entering a number 1, 2 or 3"
choice <- readLn
| choice == 1 = "You selected easy" >> easy
| choice == 2 = "You selected medium" >> medium
| choice == 3 = "You selected hard" >> hard
| otherwiose = "You did not selected a valid choice" >> main
easy :: IO ()
easy = do
putStrLn "Guess a number between 1 and 13: "
rNumber <- randomRIO (1, 10) :: IO Int
loop rNumber
medium :: IO ()
medium = do
putStrLn "Guess a number between 1 and 25: "
rNumber <- randomRIO (1, 25) :: IO Int
loop rNumber
hard :: IO ()
hard = do
putStrLn "Guess a number between 1 and 50: "
rNumber <- randomRIO (1, 50) :: IO Int
loop rNumber
loop :: Int -> IO ()
loop rNumber = do
userInput <- readLn
case compare rNumber userInput of
EQ -> putStrLn "Correct!" >> main
LT -> putStrLn "Guess is too low, try again please" >> loop rNumber
GT -> putStrLn "Guess is too high, try again please" >> loop rNumber
You need to change your loop function to keep track of both the number to guess and the number of guesses:
loop :: Int -> Int -> IO ()
loop rNumber guesses = do
putStrLn $ "You have made " ++ show guesses ++ " guesses so far."
...
putStrLn "Too low, guess again"
loop rNumber (guesses+1)
...
putStrLn "To high, guess again"
loop rNumber (guesses+1)
Note how when you call loop recursively you change the guess count by passing in the old guess count + 1.
I am using guards inside a function but not immediately after the function signature. The guards are under a do statement inside the body of the function. I get this error:
parse error on input `|'
I thought maybe the error comes from the indentation but i have tried many indentation but still i get the errors. Am asking is it because the guards are not immedaitely after the function signature that is why am getting the errors?
thanks
UPDATE 1
CODE:
The user is suppose to guess a number , and the number will be compared with the random number if they are the same. If it is not correct then the user will guess till the "guess" variable in the function is zero. in every interation that value(guess) is decreased by one.
for instance : puzz 12 5. the user can guess for five times, the random number will be picked between 1 and 12. that is how the function is suppose to do, but it is not working.
puzz :: Int -> Int -> IO ()
puzz boundary guess = do
putStr "Guess"
-- putStr -- I have to print (1 .. guess) here in each iteration
putStr ":"
x <- randomRIO (1, boundary :: Int)
n <- getLine
let
nTo = read n::Int
in print x
| guess == 0 = putStr "You couldn't guess right,the correct answer is" ++ x
| nTo > x = putStr "lower"
| nTo < x = putStr "higer"
| nTo == x = putStr "Congrat, You guess right."
| otherwise raad boundary (guess - 1)
the ouput must be like this:
Main> puzz 50 6
Guess a number betwee 1 en 50.
Guess 1: 49
lower
Guess 2: 25
lower
Guess 3: 12
higher
Guess 4: 18
higher
Guess 5: 21
higher
Guess 6: 23
lower
You couldn't guess correct, the answer was: 22.
thanks for your help
You’re using guards incorrectly. From the report:
Top level patterns in case expressions and the set of top level patterns in function or pattern bindings may have zero or more associated guards.
So they’re only for cases and function bindings. If you just want to concisely introduce a series of true-false tests, while inside a do-notation, perhaps the case () of () trick would work:
main = do
putStrLn "hello world"
n <- getLine
let nTo = read n :: Int
case ()
of () | cond -> putStrLn "foo"
| cond' -> putStrLn "bar"
| otherwise -> putStrLn "baz"
It should be noted that there are several things that are a bit off with your code, in addition to using guards wrong. By default output is buffered in haskell so if you want Guess to be on the same line as input you have to either say that stdOut should not be buffered (hSetBuffering stdOut NoBuffering), or you have to flush output with hFlush. It's not necessary to write boundary :: Int, the compiler knows it is an Int. Here is a bit more complete example, I'm sure it could be done better but atleast it works:
import Control.Monad(liftM,unless)
import System.IO(hFlush,stdout)
import System.Random(randomRIO)
guessMyNumber upper guesses = do
putStrLn $ "Guess a number between 1 and " ++ show upper ++ "!"
randomRIO (1, upper) >>= puzz guesses
puzz 0 number = do
putStrLn $ "Sorry, no more guesses, the number was "
++ show number ++ "."
puzz guesses number = do
putStr "Guess:" >> hFlush stdout
guess <- liftM read getLine
printMessage guess number guesses
printMessage guess number guesses
| number > guess = putStrLn "higer" >> puzz (guesses-1) number
| number < guess = putStrLn "lower" >> puzz (guesses-1) number
| number == guess = putStrLn "Congratulations! You guessed right!"