2017-04-04 8 views
1

更新、下記を参照

私は現在Elmを学習しており、これは最初の機能的な言語です。 私のモデルにList ResourceList Converterがあります。 ConverterList Resourceを取り込み、別のList Resourceを出力します。十分な入力がある場合にのみ変換が行われます。私はそれぞれConverterを繰り返して、リソースの数を減らしたり増やしたいと思っています。リストの各繰り返しでモデルを更新

解決策の周りに私の頭を包むことができませんでした。私はList.foldrが私が使用すべきものだと感じているが、わからない。モデルを更新して各反復を更新する方法はありますか?

これは私がこれまで持っているものです。

type alias Resource = 
{ resourcetype : ResourceType 
, quantity: Int 
} 

type ResourceType 
    = Energy 
    | Water 
    | Metal 

type alias Converter = 
    { convertertype : ConverterType 
    , intakes : List (ResourceType, Int) 
    , outputs: List (ResourceType, Int) 
    } 

type ConverterType 
    = SolarCollector 
    | Humidifer 
    | MetalCollector 

type alias Model = 
    { resources : List Resource 
    , converters : List Converter 
    } 

type Msg 
    = Tick Time 

update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
     Tick time -> 
      (updateGame model, Cmd.none) 

convert : List Resource -> Converter -> List Resource 
convert resources converter = 
    let 
     intakes = converter.intakes 
     outputs = converter.outputs 
     -- TODO, remove intakes from resources and add outputs to resources 
    in 
     resources 

updateGame : Model -> Model 
updateGame model = 
    -- TODO, call convert on each converter and update model 
    model 

subscriptions : Model -> Sub Msg 
subscriptions model = 
    Time.every second Tick 

例:

資源枯渇しません。

--Initial converters 
[ SolarCollector [] [Energy 2] 
, MetalCollector [Energy 1] [Metal 1] 
] 
--Initial resources 
[ Energy 10, Metal 0] 

--After 5 ticks 
[ Energy 15, Metal 5] 

リソースが枯渇します:

--Initial converters 
[ MetalCollector [Energy 2] [Metal 1] 
, SolarCollector [] [Energy 1] 
] 
--Initial resources 
[ Energy 4, Metal 0] 

--Tick 1 
[ Energy 3, Metal 1] -- MetalCollector uses 2 Energy to get 1 Metal, SolarCollector will generate 1 Energy 
--Tick 2 
[ Energy 2, Metal 2] -- MC -2E,+1M; SC +1E 
--Tick 3 
[ Energy 1, Metal 3] -- MC -2E,+1M; SC +1E 
--Tick 4 
[ Energy 2, Metal 3] -- SC +1E 
-- Notice how this tick the MetalCollector didn't run because of list order. 
--Tick 5 
[ Energy 1, Metal 4] -- MC -2E,+1M; SC +1E 

更新:

私はそれを稼働させました! Converterの順番は今問題であり、1ダックごとに適切な量のリソースが必要です。最終的な作業コードは、私を助けてくれてありがとう!ここでは、それを試してみることができます:https://ellie-app.com/RB3YsxwbGja1/0

module Main exposing (..) 

import Html exposing (Html, div, text, program, ul, li) 
import Time exposing (Time, second) 

type alias Resources = 
    { energy : Float 
    , water : Float 
    , metal : Float 
    } 

resourcesToList : Resources -> List Float 
resourcesToList resources = 
    [resources.energy, resources.water, resources.metal] 

noResource : Resources 
noResource = Resources 0 0 0 

energyResource : Float -> Resources 
energyResource energy = 
    { noResource | energy = energy } 

waterResource : Float -> Resources 
waterResource water = 
    { noResource | water = water } 

metalResource : Float -> Resources 
metalResource metal = 
    { noResource | metal = metal } 

type alias Converter = 
    { convertertype : ConverterType 
    , quantity : Int 
    , intakes : Resources 
    , outputs: Resources 
    } 

type ConverterType 
    = SolarCollector 
    | Humidifer 
    | MetalCollector 

initialResources : Resources 
initialResources = 
    { noResource | energy = 10} 

initialConverters : List Converter 
initialConverters = 
    [ { convertertype = MetalCollector 
    , quantity = 2 
    , intakes = energyResource 1 
    , outputs = metalResource 1 
    } 
    , { convertertype = SolarCollector 
    , quantity = 2 
    , intakes = noResource 
    , outputs = energyResource 1 
    } 
    , { convertertype = Humidifer 
    , quantity = 1 
    , intakes = energyResource 1 
    , outputs = waterResource 1 
    } 
    ] 

convert : Converter -> Resources -> Resources 
convert converter resources = 
    let 
     activatedQuantity = 
      toFloat (getActiveConverterQuantity converter resources) 

     getActiveConverterQuantity : Converter -> Resources -> Int 
     getActiveConverterQuantity converter resources = 
      let 
       resourcesList = resourcesToList resources 
       intakesList = resourcesToList converter.intakes 

       finalList = 
        List.map2 (,) resourcesList intakesList 
         |> List.filter (\(r,i) -> i > 0) 
         |> List.map (\(r,i) -> floor (r/i)) 
      in 
       case List.maximum finalList of 
        Just q -> 
         min q converter.quantity 
        Nothing -> 
         converter.quantity 

     subtractIntakes : Converter -> Resources -> Resources 
     subtractIntakes converter resources = 
      { resources 
      | energy = resources.energy - activatedQuantity * converter.intakes.energy 
      , water = resources.water - activatedQuantity * converter.intakes.water 
      , metal = resources.metal - activatedQuantity * converter.intakes.metal 
      } 
     addOutputs : Converter -> Resources -> Resources 
     addOutputs converter resources = 
      { resources 
      | energy = resources.energy + activatedQuantity * converter.outputs.energy 
      , water = resources.water + activatedQuantity * converter.outputs.water 
      , metal = resources.metal + activatedQuantity * converter.outputs.metal 
      } 
    in 
     resources 
      |> subtractIntakes converter 
      |> addOutputs converter 
-- MODEL 


type alias Model = 
    { resources : Resources 
    , converters : List Converter 
    } 


init : (Model, Cmd Msg) 
init = 
    ({ resources = initialResources 
    , converters = initialConverters 
    } 
    , Cmd.none 
    ) 



-- MESSAGES 


type Msg 
    = Tick Time 

-- VIEW 


view : Model -> Html Msg 
view model = 
    div [] 
     [ div[] [text (toString model.resources)] 
     , div[] 
      [ model.converters 
       |> List.map 
        (\c -> li [] [text (toString (c.convertertype,c.quantity,c.intakes))]) 
       |> ul [] 
      ] 
     ] 

-- UPDATE 


update : Msg -> Model -> (Model, Cmd Msg) 
update msg model = 
    case msg of 
     Tick time -> 
      (updateGame model, Cmd.none) 

updateGame : Model -> Model 
updateGame model = 
    let 
     newResources = model.converters |> List.foldr convert model.resources 
    in 
     { model | resources = newResources } 


-- SUBSCRIPTIONS 


subscriptions : Model -> Sub Msg 
subscriptions model = 
    Time.every second Tick 

-- MAIN 


main : Program Never Model Msg 
main = 
    program 
     { init = init 
     , view = view 
     , update = update 
     , subscriptions = subscriptions 
     } 
+0

ようにそれを呼び出すあなたは、入力データと所望の出力の例を追加していただけますか? – halfzebra

+0

私はユースケースをカバーするいくつかの例を追加しました。 –

+0

あなたのケースでは、 'List.map'は' List.foldr'よりはるかに役立ちますが、 'List'から' Dict'に切り替える方が良いでしょう。 – daniula

答えて

1

私はあなたのmodel.resourcesは1 ResourceTypeが複数の値を保持する必要がないことを期待したいので、録音が(そのために物事が容易になります - >リソース=を仮定して、[エネルギー2、水1、エネルギー2]意味をなさないだろう)

type alias Resources = 
    { energy : Int 
    , water : Int 
    , metal : Int 
    } 

type alias Model = 
    { resources : Resources 
    , converters : List Converter 
    } 

今、あなたはすべてのコンバータの摂取量を倍と資源に

convert : Converter -> Resources -> Resources 
convert {intakes, outputs} resources = 
    let 
     substractResource : (ResourceType, Int) -> Resources -> Resources 
     substractResource (rType, quantity) res = 
      case rType of 
       Energy -> 
        { res | energy = energy - quantity } 
       -- TODO: same for Water and Metal 

     -- TODO: addResource function 

     hasEnoughResources newRes = 
      case negativeResources newRes of 
       -- TODO: function to check if any value of the new resources Record is negative 
       True -> -- return original resources if converter can not run 
        resources 
       False -> -- add outputs to res and return new recources 
        outputs |> List.foldr addResource newRes 
    in 
     intakes 
      |> List.foldr substractResource resources 
      |> hasEnoughResources 

ボーナス蓄積することができます:櫛をINE追加しsubstract機能をタイプの1つの機能に:(Int -> Int) -> (ResourceType, Int) -> Resources -> ResourcescalcResource << (+)

updateGame : Model -> Model 
updateGame model = 
    let 
     newResources = model.converters |> List.foldr convert model.resources 
    in 
     { model | resources = newResources } 
+0

アイデアありがとう!レコードのこの使用法は、実際に自分のコードを再構築するのに役立ちます。私はコードが実行されないと思うリソースの種類を取り除き、それらを使用したいので。また、foldGでupdateGame関数の一部が私のために働いていません。 –

+0

@GáborFekete私は、私が変更したい機能をリストアップしました。ResourceTypeとConverterの型をそのまま残しました。変換関数の順序をpipeableに更新し、substractResourceの型宣言を修正しました。 (私は今、それをテストすることはできません) – farmio

+0

私は現在の作業コードを元の質問に追加しました。 –

関連する問題