I'm new with OCaml and I am trying to define a type to make a deck of cards, what I have now is:
type palo = Espada | Basto | Oro | Copa
type valor = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12
type carta = Carta of palo*valor
what I want to know if there is a way in which I can define a deck as a list of carta with every combination palo - valor available and then "shuffle" it.
Thank you very much in advance.
Edit:
I should probably clarify that this is a Spanish deck and that is why there is no Jack, Queen, King or Ace
Well, you could, certainly, a good way to do it is a Fisher-Yates/Knuth shuffle
So, you would create an array of length 12 * 4 = 48 cards and then shuffle it (you can find this shuffle code in this page) and then use Array.to_list if you want to keep a list of cards and not an array.
[EDIT]
I took the liberty of rewriting your types :
type palo = Espada | Basto | Oro | Copa
type valor = Uno | Dos | Tres | Quatro | Cinco | Seis | Siete |
Ocho | Nueve | Diez | Once | Doce
type carta = palo * valor
You don't need to say that carta is a Carta of palo * valor since you have only one constructor ;-) carta will be an alias for the couple palo * valor.
But, actually, an easiest way to do would be to have the types :
type palo = Espada | Basto | Oro | Copa
type valor = int
type carta = palo * valor
and to ensure that your valor can't be greater than 12, for example. It would make the card creation much easier. (For example, doing so :
let cards = Array.init 48 (fun i ->
let palo =
if i < 12 then Espada
else if i < 24 then Basto
else if i < 36 then Oro
else Copa
in palo, i mod 12 + 1
)
)
[SECOND EDIT]
If you really want to have your valor types, this is one way to do :
type palo = Espada | Basto | Oro | Copa
type valor = Uno | Dos | Tres | Quatro | Cinco | Seis | Siete |
Ocho | Nueve | Diez | Once | Doce
type carta = palo * valor
let lv = [Uno; Dos; Tres; Quatro; Cinco; Seis; Siete;
Ocho; Nueve; Diez; Once; Doce]
let cards =
let new_list p = List.map (fun v -> p, v) lv in
let l1 = new_list Espada in
let l2 = new_list Basto in
let l3 = new_list Oro in
let l4 = new_list Copa in
List.rev_append l1 (List.rev_append l2 (List.rev_append l3 l4))
As you can see, I created a list of valors and for each palo I add the palo to each element of this list (since lists are persistent data structures, it gives me a new list, it does not modify the previous one) and then I concatenate the four lists.
And an even better way to do :
let lp = [Espada; Basto; Oro; Copa]
let cardsb =
let new_list p = List.map (fun v -> p, v) lv in
List.fold_left (fun acc p ->
List.rev_append (new_list p) acc) [] lp
Which uses iterators which is beautiful, so wow, so charming !
The problem os these last methods is that you can't be sure that you put all your constructors in the list and the typing system won't warn you about it. :-(
Related
I want to create the following data structure, the first is an algebraic data type OneToTen and the second I want to be a list that holds all the values that OneToTen can be for future mappings I do in my program.
data OneToTen = I | II | III | IV | V | VI | VII | VIII | IX | X
???? SetOneToTen = [I, II, III, IV, V, VI, VII, VIII, IX, X]
Is this somehow possible in haskell, or should i just use a function that returns a list like the one above and work with that?
Update: My haskelly way of doing it:
data OneToTen = I | II | III | IV | V | VI | VII | VIII | IX | X
deriving (Enum, Show)
setOneToTen :: [OneToTen]
setOneToTen = [I .. X]
and then just call this function when you want the list :)
just remove the ???? and rename SetOneToTen to setOneToTen:
data OneToTen = I | II | III | IV | V | VI | VII | VIII | IX | X
setOneToTen = [I, II, III, IV, V, VI, VII, VIII, IX, X]
Now setOneToTen is a list of OneToTens.
If the data type contains only data constructors with no parameters, you can easily make these an instance of Bounded and Enum, in that case you can use [minBound ..] to construct the list of possible values:
data OneToTen = I | II | III | IV | V | VI | VII | VIII | IX | X deriving (Bounded, Eq, Enum)
setOneToTen = [minBound ..]
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.
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.
So im in the early stages of learning how to use functional programming and I ran into this problem when I tried to compare a string with a string in a list, so that I could get the matching patterns.
Here is my code:
F# Code
type name = string;;
type number = string;;
type sex = string;;
type year = int;;
type interest = string list;;
type criteria = (sex * year * interest) list;;
type Register = (name * number * criteria) list;;
let reg = [("Lars","28551086",("male",1992,["soccer";"golf"])); ("Hanne","28598653",("female",1989,["cooking";"jewelry"]));
("Viktor","26587297",("male",1973,["clothes";"soccer"])); ("Henrik","22157864",("male",1985,["internet";"facebook"]));
("Lotte","23589462",("female",1997,["bombing";"internet"])); ("Susanne","25896742",("female",1923,["soccer";"cooking"]));
("Marie","22658943",("female",1975,["clothes";"jewelry"])) ];;
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| (name,_,(_,n',_)) when n = n' -> name
| (name,_,(_,n',_))::tail when n <> n' -> findYear(tail);;
What im trying to do, is to retrieve all the people in the reg that has the same name as the one im searching for.
So a F# Interactive call could be:
findYear 1992;;
And then it should give me the details of the persons with that year. Im not sure how to search through my reg
I think you just forgot the n (and the tail of a list) here:
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| (name,_,(_,n',_)) when n = n' -> name // forgot tail
| (name,_,(_,n',_))::tail when n <> n' -> findYear(tail) // forgot n here
(should have gotten an error
try this:
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| ((name,_,(_,n',_))::_) when n = n' -> name
| ((_,_,(_,n',_))::tail) when n <> n' -> findYear n tail
making this a bit better
you don't need to check again
you don't need to recheck the year if the second pattern did not match:
let rec findYear n = function
| [] -> failwith("No person with that year is registrered")
| ((name,_,(_,n',_))::_) when n = n' -> name
| (_::tail) -> findYear n tail
option is better than an exception
The way you handle the case where you don't find a person with this year tells us that your function is "partial" (does not return for every input) - so just make it total again by using option:
let rec findYear n = function
| [] -> None
| ((name,_,(_,n',_))::_) when n = n' -> Some name
| (_::tail) -> findYear n tail
This will not throw and tell the user: "hey I might fail so better handle this!"
use records / ADTs
While your tuples are fine they are not really readable (hard to check if your pattern is ok for example) - why not use records and algebraic-data-types:
type Name = string
type Number = string
type Gender = Male | Female // add more if you need
type Year = int
type Interests = string list
type Criteria = { gender : Gender; year : Year; interests : Interests }
type Register = { name : Name; number : Number; criteria : Criteria }
let reg =
[ { name = "Lars"
; number = "28551086"
; criteria = { gender = Male; year = 1992; interests = ["soccer";"golf"] }
}
// ...
]
and use this:
let rec findYear n =
function
| [] -> None
| (reg::_) when reg.criteria.year = n'
-> Some reg
| (_::regs)
-> findYear n regs
use the List module
What you do here is a very common pattern and it's already implemented (List.tryFind) - so why not use it?
let findYear n =
let hasYear (reg : Register) = reg.criteria.year = n
List.tryFind hasYear
of course you can add the missing parameter if you don't really understand partial application yet:
let findYear n regs =
let hasYear (reg : Register) = reg.criteria.year = n
List.tryFind hasYear regs
finally let's give this a better name
this is of course just me not liking findYear if you really find a registration
// rest is the same
type Registration = { name : Name; number : Number; criteria : Criteria }
let firstRegistrationWithYear year =
let hasYear (reg : Register) = reg.criteria.year = year
List.tryFind hasYear
finding all registrations for one year
let filterRegistrationWithYear year =
let hasYear (reg : Register) = reg.criteria.year = year
List.filter hasYear
or if you want a (tail-recursive) implementation using continuation-passing style (the other answer has the accumulator aproach):
let filterYear n regs =
let rec filter regs cont =
match regs with
| [] -> cont []
| (reg::regs) when reg.criteria.year = n'
-> filter regs (fun res -> reg::res |> cont)
| (_::regs)
-> filter regs cont
filter regs id
remark:
I would not advise implementing this kind of stuff yourself - it's better to use the provided stuff from List (it's for example more performant as this, because I tried to show you how to do it CPS-style)
If you want to use recursion, you can add additional parameter (accumulator), to collect results:
let rec findYear n acc = function
| [] -> acc
| ((name,_,(_,n',_)) as h)::tail when n = n' -> findYear n (h::acc) tail
| h::tail -> findYear n acc tail
And call it this way:
findYear 1973 [] reg
Or you could use the 'filter' function from the List library functions:
let findYear' n lst =
lst |> List.filter (fun (name,_,(_,n',_)) -> n = n')
And call it this way:
findYear' 1973 reg
I want to transefer something like this:
[0,1,2,3,4,5,6,7]
into
[6,1,4,3,2,5,0,7]
Here's a draft, that reverses the elements at even positions (which is what I assume you meant by your question). This is probably far from optimal (e.g. you should make split and join tail-recursive):
let rec split = function
| [] -> [],[]
| h::[] -> [h],[]
| x::y::t -> let a,b = split t in x::a, y::b;;
let rec join a b = match a,b with
| [],_ -> b
| _,[] -> a
| ha::ta,hb::tb -> ha::hb::(join ta tb);;
let doit l = let a,b = split l in join a (List.rev b);;