How would one return a random value for a data type like below?
datatype rank = Jack | Queen | King | Ace | Num of int
I am working on a function generate a list of random cards for input to another function, so there is also the need for a similar function for suit.
The output should either be a symbol like Jack, King, etc, or an int from 2 to 9.
The code below is incorrect:
fun pick_rank() =
case Random.randRange(2,13) of 13 => Ace
| 12 => King
| 11 => Queen
| 10 => Jacl
| Int v => v
How would one return a random value for a data type like below?
datatype rank = Jack | Queen | King | Ace | Num of int
I have two answers: Either you generate each value uniquely, or you generate all possible values, shuffle them and pick one. If you just want a random variable in isolation, the former is easiest. But if you want to simulate a card game in which drawing the same card twice is not possible, then you probably want the shuffle.
You can see how I made a command-line blackjack game. I'll repeat both approaches here:
(* There are 13 card ranks, 4 suits *)
datatype rank
= Ace | Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen | King
datatype suit = Hearts | Clubs | Diamonds | Spades
datatype card = Card of suit * rank
fun concatMap f xs = List.concat (List.map f xs)
fun product xs ys = concatMap (fn x => map (fn y => (x,y)) ys) xs
val allCards = map Card
(product
[Hearts,Clubs,Diamonds,Spades]
[Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King])
(* Create a new pseudo-random number generator, prng *)
val prng = Random.newgen ()
(* rlist determines a random index in [0 ; length xs[. *)
fun rlist xs = Random.range (0, length xs) prng
(* remove removes the n'th element of a list *)
fun remove (_, []) = raise Domain
| remove (0, card::library) = library
| remove (n, card::library) = card::remove (n-1, library);
(* randomtake removes and returns the i'th (random) element of a list *)
fun randomtake library =
let val i = rlist library
val card = List.nth (library, i)
val rest = remove (i, library)
in
(card, rest)
end
(* Shuffling is done by removing random cards until there are no cards left *)
fun shuffle [] = []
| shuffle cards =
let val (c,r) = randomtake cards
in
c :: shuffle r
end
Using these functions, you could pick a single random card by doing randomtake allCards, or you could pick any amount of random cards without picking the same card by first shuffle allCards and pick the top elements.
Note that these are not efficient methods. As an exercise, you could implement the Fisher-Yates shuffle.
This is the code I have so far:
data Suit = Diamond | Club | Heart | Spade
deriving (Read, Enum, Eq, Bounded)
data Rank = Two | Three | Four
| Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King | Ace
deriving (Read, Enum, Eq, Ord, Bounded)
and I am trying to map each value, either Rank or Suit to a unique prime number.
primeMapper :: Either Rank Suit -> Int
should be the final function and I want to iterate over each Suit and set it to the first four primes:
primeMapper [Diamond .. Spade] = [2,3,5,7]
and each Rank equal to the rest of the primes up until the 17th:
primeMapper [Two .. Ace] = drop 4 . take 17 $ primes
assuming I have a generating function called primes.
This code, however throws errors obviously because it generates a list from a list. How can I achieve what I am trying to do? Let me know if I can explain it better.
The ultimate goal is to have a hash table that gives unique IDs to each cards based on prime factors, and then generate prime factorization and use modulo to quickly compare poker hands.
Ultimately I solved what I am trying to do by hand as so:
primeMapper :: Either Suit Rank -> Int
primeMapper x = case x of
Left Diamond -> 2
Left Club -> 3
Left Heart -> 5
Left Spade -> 7
Right Two -> 11
Right Three -> 13
Right Four -> 17
Right Five -> 19
Right Six -> 23
Right Seven -> 29
Right Eight -> 31
Right Nine -> 37
Right Ten -> 41
Right Jack -> 43
Right Queen -> 47
Right King -> 53
Right Ace -> 59
... was there a more concise way to do this rather than write each case out by hand?
Your solution using pattern matching is best, though I would prefer
primeMapper :: Either Suit Rank -> Int
primeMapper (Left Diamond) = 2
primeMapper (Left Club) = 3
...
rather than your long case expression.
However you could also use lookup :: Eq a => a -> [(a, b)] -> Maybe b
import Data.Maybe (fromJust)
primeMapper :: Either Suit Rank -> Int
primeMapper = fromJust . flip lookup zippedPrimes
where
zippedPrimes = zip suitranks primes
suitranks = fmap Left suits ++ fmap Right ranks :: [Either Suit Rank]
suits = fromEnum minBound
ranks = fromEnum minBound
Depending on what you plan to use this for, you may not need to use primes or prime factorizations at all; you can get fast conversion to and from plain numbers just by picking one or the other of the suit or rank for a base conversion. Here I'll pick suit -- there are four suits, so take the first digit in base 4 as the suit and the remaining digits as the rank.
encode :: (Suit, Rank) -> Int
encode (s, r) = fromEnum s + 4 * fromEnum r
decode :: Int -> (Suit, Rank)
decode n = (toEnum s, toEnum r) where (r, s) = n `quotRem` 4
You can verify in ghci that this gives a unique number to each card:
> [encode (s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
[0,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]
And that they decode appropriately:
> map decode [0..51] == [(s, r) | r <- [minBound .. maxBound], s <- [minBound .. maxBound]]
True
You can adapt some of this I hope.
no2s3s5s = \n -> take n $ scanl (\b a -> a+b) 11 $ cycle [2,4,2,4,6,2,6,4]
rnk = filter (/=49) $ no2s3s5s 14
stv = [2,3,5,7]
_deck = [ b*v | b <- stv, v <- rnk]
_Dia = take 13.drop (0*13) $ _deck
_Clb = take 13.drop (1*13) $ _deck
_Hrt = take 13.drop (2*13) $ _deck
_Spd = take 13.drop (3*13) $ _deck
_Dia
[22,26,34,38,46,58,62,74,82,86,94,106,118]
_Clb
[33,39,51,57,69,87,93,111,123,129,141,159,177]
_Hrt
[55,65,85,95,115,145,155,185,205,215,235,265,295]
_Spd
[77,91,119,133,161,203,217,259,287,301,329,371,413]
_deck
[22,26,34,38,46,58,62,74,82,86,94,106,118,33,39,51,57,69,87,93,111,123,129,141,159,177,55,65,85,95,115,145,155,185,205,215,235,265,295,77,91,119,133,161,203,217,259,287,301,329,371,413]
length _deck
52
Your multiples (_deck) are all unique.
I normally use no2s3s5s with a computed (limited) factor list and the mod function to generate a long prime list.
the type is defined as follows:
gap :: (Eq a) => a -> a -> [a] -> Maybe Int
I have been stuck on this problem for more than an hour and have no idea how to approach the problem. I am aware that it requires the use of fold and am familiar with that topic.
Please take into consideration that either foldl or foldr must be used.
The output when called ought to look like this
gap 3 8 [1..10]
=Just 5
gap 8 3 [1..10]
=Nothing
gap 'h' 'l' "hello"
=Just 2
gap 'h' 'z' "hello"
=Nothing
You might dropWhile the list until you find the starting element and then fold from the right, starting with Nothing, replacing that with Just 1 once you hit the end element, and fmaping +1 to the accumulator. In code:
gap :: Eq a => a -> a -> [a] -> Maybe Int
gap from to xs = case dropWhile (/= from) xs of
[] -> Nothing
(_:rest) -> gap' to rest
gap' :: Eq a => a -> [a] -> Maybe Int
gap' to = foldr f Nothing
where f x acc | x == to = Just 1
| otherwise = (+1) <$> acc
The nice thing is that it works correctly if you have several occurences of the elements in your sequence:
*Main> gap 3 8 $ [1..10] ++ [1..10]
Just 5
*Main> gap 3 8 [1, 2, 3, 3, 3, 8]
Just 3
Maybe my solution isn't nice, but it works
import Control.Monad
import Data.Function
import Data.Foldable
(...) = (.) . (.)
gap x y = liftA2 ((guard . (> 0) =<<) ... liftA2 (subtract `on` fst))
(find ((==x) . snd)) (find((==y) . snd)) . zip [0..]
I want to return a sequence of Cards in a game in Haskell. For example:
[(SIX,D),(SEVEN,D),(EIGHT,S)] ~> [(SIX,D),(SEVEN,D)]
[(SIX,D),(SEVEN,S)] ~> []
[(SIX,D),(SEVEN,D)] ~> [(SIX,D),(SEVEN,D)]
Until now, I have this function:
findSeq :: [Card] -> [Card]
findSeq [] = []
findSeq (h:t)
| null t = [h]
| Just h == (pCard (head t) pack) = h:findSeq t
| otherwise = [h]
Which returns even the first card: i.e, unsuitable for example 2 above. How can I return a sequence, or nothing else if there is no sequence of consecutive elements in there?
I also tried filtering them, but I received 'too many arguments exception'. Any help?
This is how I would do it:
import Data.List (groupBy)
import Data.Function (on)
data Suit = Clubs | Diamonds | Hearts | Spades deriving Eq
data Face = Ace | Two | Three | Four | Five | Six | Seven | Eight | Nine | Ten
| Jack | Queen | King deriving Enum
type Card = (Face, Suit)
findSequences :: [Card] -> [[Card]]
findSequences = [sequence | sequence <- groupBy ((==) `on` snd),
contiguous (map fst sequence),
length sequence > 1]
contiguous :: Enum a => [a] -> Bool
contiguous (x:xs) = map fromEnum xs == take (length xs) [fromEnum x + 1 ..]
The findSequences function finds all the sequences in the deck (except single card sequences).
Well, mathematically it actually makes perfect sense to consider a single card a sequence of one card. So it's a good idea to not change that behaviour as such... just extend the definition so you can obtain the real desired result from that.
The real problem is not that you get single cards as single-element sequences, but that you don't get anything behind them. To fix that, you need to first obtain not merely the first, but all sequences in the list:
findSeqs :: [Card] -> [[Card]]
findSeqs [] = []
findSeqs [h] = [[h]]
findSeqs (h:t#(h':_)) -- avoid `head` and `null`... pattern matching FTW!
| Just h == (pCard h' pack) = h ^: findSeqs t
| otherwise = [h] : findSeqs t
I've used the helper
(^:) :: a -> [[a]] -> [[a]]
h ^: (hl:ls) = (h:hl) : ls
_ ^: [] = []
Once you have findSeqs, you merely need to skim the result for the first non-degenerate sequence.
I am new to Haskell and having problems using recursion to make a deck of cards.
I have all these definitions:
data Suit = Club | Diamond | Heart | Spade
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen
| King | Ace
type Card = (Suit, Value)
type Deck = [Card]
instance Show Suit where
show Club = "Club"
show Diamond = "Diamond"
show Heart = "Heart"
show Spade = "Spade"
instance Show Value where
show Two = "Two"
show Three = "Three"
show Four = "Four"
show Five = "Five"
show Six = "Six"
show Seven = "Seven"
show Eight = "Eight"
show Nine = "Nine"
show Ten = "Ten"
show Jack = "Jack"
show Queen = "Queen"
show King = "King"
show Ace = "Ace"
I am trying to write a function
makeDeck :: Deck
which returns a list of cards in the order the Data is given, so (Club, Two - Ace), (Diamond, Two-Ace), etc.
I want to do this using recursion, which is why I am having so much difficulty.
Any help would be greatly appreciated.
Thank you!
This doesn't use recursion, but a more canonical way of doing this is:
Add deriving Enum to the definition of Suit and Value, then:
makeDeck :: Deck
makeDeck = [(suit, value) | suit <- [Club..Spade], value <- [Two..Ace]]
Alternatively, provide fully defined lists of all suits and values rather than using Enum.
Given:
data Suit = Club | Diamond | Heart | Spade deriving (Show, Enum)
data Value = Two | Three | Four | Five | Six | Seven
| Eight | Nine | Ten | Jack | Queen
| King | Ace deriving (Show, Enum)
type Card = (Suit, Value)
type Deck = [Card]
makeDeck :: Deck
there are lots of ways to calculate a Cartesian Product -- the product of sets.
All of the functions used in these examples can be looked up on Hoogle:
Monads
Using do notation:
makeDeck = do
suit <- [Club ..]
value <- [Two ..]
return (suit, value)
The unsugared form of the above, which uses >>=:
makeDeck = [Club ..] >>= \suit ->
[Two ..] >>= \value ->
return (suit, value)
Lifting:
makeDeck = liftM2 (,) [Club ..] [Two ..]
Function application within monads:
makeDeck = return (,) `ap` [Club ..] `ap` [Two ..]
Applicatives
Lifting:
makeDeck = liftA2 (,) [Club ..] [Two ..]
Function application within applicatives:
makeDeck = pure (,) <*> [Club ..] <*> [Two ..]
Which is the same as:
makeDeck = (,) <$> [Club ..] <*> [Two ..]
List comprehensions
See #ivanm's answers.
Without any type classes
makeDeck = concatMap (\suit -> map ((,) suit) [Two ..]) [Club ..]
If you need to use recursion explicitly, you can replace concatMap with its definition, and so on until you get to foldr, where the real recursive action happens.
Firstly, are you aware of list comprehensions and all the awesome things you can do with them? The makeDeck function could be written as a fairly simple list comprehension (as ivanm pointed out in his answer), especially given the order you'd like the deck to be in.
However, if you'd still like to use recursion, there are a few ways to go about it. First, figure out what variables you'll need to keep track of during the whole operation. You'll need to keep the current list of cards, and a record of which suit and value you're at. So the type signature might look something like makeDeck :: Suit -> Value -> Deck. Then you'd want to use pattern matching to handle the several possible cases during the computation, such as
makeDeck suit Ace deck = (suit,Ace):(makeDeck (succ suit) Two)
[...]
As you can see, this might turn out to be a fairly long and unwieldy definition. The list comprehension method would yield a much more short, elegant, and canonical solution. Regardless of which you choose, you'll need to add deriving Enum to the end of your datatype declarations. Read up on the deriving keyword here or elsewhere online if you're not familiar with it.
Others have pointed you towards list comprehensions, but if you would like to write it recursively, read on.
This sounds like homework, so I'll just try and give you tips that point you in the right direction (as opposed to writing it for you).
Thing to realize #1:
If you derive the Enum typeclass for your algebraic data types, you can create enumerations like so:
*Main> [Club .. Spade]
[Club,Diamond,Heart,Spade]
Thing to realize #2:
You can create lists of tuples like that, by using maps. You'll end up with [[Suit]], so you should use the concat function to join them into a Deck.
*Main> concat $ map (\x -> map (\y -> (x, y)) ['a'..'c']) [1..3]
[(1,'a'),(1,'b'),(1,'c'),(2,'a'),(2,'b'),(2,'c'),(3,'a'),(3,'b'),(3,'c')]
Thing to realize #3:
You can implement map recursively. Here's the definition from the Prelude:
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
So you could write the (map . map) as one big recursive function. Good luck!