榆树初学者:试图写二十一点

时间:2014-10-07 17:55:11

标签: functional-programming frp elm

我正在做一项关于榆树的独立研究,我觉得我正在学习重新编程!作为一个学习语言的项目,我试图让一个简单的二十一点启动和运行,但一旦我开始,我意识到我仍然没有掌握。我从甲板上绘制卡片并将它们添加到列表中:

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

我的问题主要是关于如何继续。看完已完成的榆树项目有点帮助,但其中很多都很难让我作为初学者进行解析。任何方向都有帮助!

  1. 我遇到的第一个问题之一就是试图弄清楚如何从卡片中取出卡片,使用dropCard deck card = filter (\card /= nextCard) deck之类的东西从列表中过滤出卡片。但我对榆树的理解是,每当信号发生变化时,程序就会重新评估,这意味着每次抽取卡片时都会重新创建一副牌。我是否还需要foldp原始套牌?

  2. 从一个列表中删除元素并在函数式编程中将其添加到另一个列表的正确方法是什么?功能组合,如toHand . dropCard card

  3. 为了添加卡片面来确定输赢,我不确定如何从列表中获取整数值。我试过做fst (head deck),但我得到了类型错误,可能是因为deck本身就是某种信号。我有没有看到的东西?

  4. 那就是说,到目前为止,我真的非常喜欢榆树!

1 个答案:

答案 0 :(得分:7)

问题

  1. 对于简单的程序,思考信号的最简单方法是考虑程序中的哪些内容可以改变。在你的情况下,这将是甲板和手。然后你拿走这些东西并建立一个数据结构来存储它们。然后你在整个数据结构上做foldp,所以不仅要跟踪手,还要跟踪平台。
  2. 您可以编写一个获取列表和索引的函数,并返回列表中该索引处的项目以及删除该项目的列表。然后将项目添加到另一个列表中,您就完成了。
  3. fst (head deck)应该有效。也许您在尝试时忘记删除lift定义中的main了?
  4. 示例代码

    -- 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
    

    如果有任何不清楚的地方,请告诉我。