2017-04-04 1 views
1

업데이트, 아래 참조

저는 현재 엘름을 배우고 있으며 이것은 처음으로 기능하는 언어입니다. 내 모델에는 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의 순서는 이제 중요하며 매 틱마다 적절한 양의 리소스가 필요합니다. 여기에 최종 코드가 있습니다. 저를 도와 주셔서 감사합니다! 여기 당신이 그것을 밖으로 시도 할 수 있습니다 : 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 그래서 레코드 (즉, 쉽게 일을 할 것 하나 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 

보너스 축적 것 : 빗 오프라인 추가하고 빼기 기능을 유형 1 개 기능 : (Int -> Int) -> (ResourceType, Int) -> Resources -> Resources을하고 입력 데이터와 원하는 출력의 예를 추가하시기 바랍니다 수 calcResource << (+)

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 유형은 그대로 두었습니다.substractResource의 타입 선언을 수정할 수 있도록 변환 함수의 순서를 업데이트했습니다. (지금 당장은 테스트 할 수 없습니다) – farmio

+0

원래의 질문에 현재 작동중인 코드를 추가했습니다. –