Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elm beginner: trying to write blackjack

I'm doing an independent study on Elm, and I feel like I'm learning to program all over again! As a learn-the-language project, I'm trying to get an easy blackjack up and running, but once I started I realized how much I still don't grasp. I have as far as drawing cards from a deck and adding them to a list:

import Random
import Mouse
import Array

--Build the deck
faces = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
suits = ['H', 'D', 'C', 'S']

allCards faces suits =
  case suits of
    x :: xs -> family faces x ++ allCards faces xs
    _ -> []

family faces suit =
  case faces of
    x :: xs -> (,) x suit :: family xs suit
    _ -> []

deck = allCards faces suits

rand : Signal Int
rand = Random.range 0 (length deck-1) Mouse.clicks 

pickCard n = head <| drop n deck
nextCard = lift pickCard rand

yourHand = foldp (::) [] nextCard

main = lift asText yourHand

My questions are mostly on how to continue. Looking at completed Elm projects helps a little, but many of them are hard for me to parse as a beginner. Any kind of direction helps!

  1. One of the first problems I had was trying to figure out how to remove cards from the deck once they're drawn, using something like dropCard deck card = filter (\card /= nextCard) deck to filter out the drawn card from the list. But my understanding of Elm is that every time a signal changes, the program re-evaluates, meaning that the deck is recreated in full every time a card is drawn. Would I need to foldp the original deck as well?

  2. What's the proper way to remove an element from one list and add it to another in functional programming? Function composition, like toHand . dropCard card?

  3. For adding card faces to determine winning/losing, I'm not sure how to get the integer value out of the list. I tried doing fst (head deck), but I got type errors, probably because deck is itself a signal of some kind. Is there something I'm not seeing?

That said, I've really enjoyed Elm thus far!

like image 330
Tinstar Avatar asked Mar 19 '23 06:03

Tinstar


1 Answers

Questions

  1. For simple programs, the easiest way to think about signals is by thinking about what kinds of things in your program can change. In your case that would be the deck and the hand. Then you take these things and make a datastructure in which to store them. Then you do a foldp over that whole datastructure, so instead of just keeping track of the hand you also keep track of the deck.
  2. You can write a function that takes a list and an index, and returns the item at that index in the list and the list with that item removed. Then you add the item to the other list and you're done.
  3. fst (head deck) should work. Perhaps you forgot to remove lift in the main definition when you tried it?

Example code

-- This first part is your code:
import Random
import Mouse
import Array

--Build the deck
faces = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
suits = ['H', 'D', 'C', 'S']

allCards faces suits =
  case suits of
    x :: xs -> family faces x ++ allCards faces xs
    _ -> []

family faces suit =
  case faces of
    x :: xs -> (,) x suit :: family xs suit
    _ -> []

-- Here come my additions/changes:
-- Naming some types for clarity
type Card = (Int,Char)
type ProgramState = { deck : [Card], hand : [Card] }

getFromList : Int -> [a] -> (a,[a])
getFromList index list =
  let prefix = take index list
      (item :: postfix) = drop index list
  in (item, prefix ++ postfix)

startState : ProgramState
startState = { deck = allCards faces suits, hand = [] }

rand : Signal Float
rand = Random.float Mouse.clicks 

rFloatToInt : Float -> Int -> Int -> Int
rFloatToInt rnd lo hi = round ((rnd + toFloat lo) * toFloat hi)

pickCard : Float -> ProgramState -> ProgramState
pickCard rnd {deck,hand} = 
  let index = rFloatToInt rnd 0 (length deck - 1)
      (item, newDeck) = getFromList index deck
  in { deck = newDeck, hand = item :: hand }

programState : Signal ProgramState
programState = foldp pickCard startState rand

main : Signal Element
main = lift asText programState

If anything is unclear, let me know.

like image 196
Apanatshka Avatar answered Mar 22 '23 23:03

Apanatshka