Closed5

paizaでClojureの勉強 - 【シミュレーション 3】燃費 (paizaランク B 相当)

むらむーむらむー

入力値の読み込み

入力値が多いので、まずは入力値の読み込み処理を作る

(defn read-input []
  (let [x (read-int-value-line)
        [starting running] (read-int-values-line)
        [total_distance] (read-int-values-line)
        stop_points (read-int-values-line)]
    {:economy {:change_distance x
               :starting starting
               :running running}
     :total_distance total_distance
     :stop_points stop_points}))

テストコード

(deftest read-input-test
  (with-in-str "10\n7 3\n100 1\n50\n"
    (is (= (read-input)
           {:economy {:change_distance 10
                      :starting 7
                      :running 3}
            :total_distance 100
            :stop_points [50]})))
  (with-in-str "50\n5 4\n100 2\n30 60\n"
    (is (= (read-input)
           {:economy {:change_distance 50
                      :starting 5
                      :running 4}
            :total_distance 100
            :stop_points [30 60]}))))

with-in-strがこういう入力値のテストに便利

むらむーむらむー

全体の処理の流れ

(defn calc-total-fuel [input]
  ; 総移動距離と停止地点リストから、移動距離リストを作成する
  (let [moving_distances (create-moving-distances (:total_distance input) (:stop_points input))]
    ; reduceと移動距離から必要燃料量を計算する関数を使って、合計の必要な燃料量を求める
    (reduce (fn [total-fuel moving_distance]
              (+ total-fuel (calc-fuel (:economy input) moving_distance)))
            0 moving_distances)))
むらむーむらむー

総移動距離と停止地点リストから、移動距離リストを作成する

"停止地点リストの最後尾にtotal_distanceを追加したリスト"と"停止地点リストの先頭に0を追加したリスト"とを使って、同じインデックスの要素を引いて、移動距離リストを作成する

イメージ
[30 60 100]
[0 30 60]

[30 30 40]

(defn create-moving-distances [total_distance stop_points]
  (vec (map #(- %1 %2) (conj stop_points total_distance) (cons 0 stop_points))))

テスト

(deftest create-moving-distances-test
  (is (= (create-moving-distances 100 [50]) [50 50]))
  (is (= (create-moving-distances 100 [30 60]) [30 30 40]))
  (is (= (create-moving-distances 200 [10 20 30 40 50]) [10 10 10 10 10 150])))
むらむーむらむー
(defn calc-fuel [economy, moving_distance]
  (if (<= moving_distance (:change_distance economy))
    ; 消費燃料の切り替え距離を超えていない場合
    (* moving_distance (:starting economy))
    ; 消費燃料の切り替え距離を超えた場合
    (let [starting-fuel (* (:change_distance economy) (:starting economy))
          running-fuel (* (- moving_distance (:change_distance economy)) (:running economy))]
      (+ starting-fuel running-fuel))))

テストコード

(deftest calc-fuel-test
  (is (= (calc-fuel {:change_distance 10 :starting 7 :running 3} 50) 190))
  (is (= (calc-fuel {:change_distance 50 :starting 5 :running 4} 30) 150)))
むらむーむらむー

コードの全体像

https://github.com/eno314/clojure-practice/pull/7

提出コード

(ns clojure-practice.paiza.libs
  (:require [clojure.string :as string]))

(defn split-line-by-space [line]
  (string/split line #" "))

(defn read-int-value-line []
  (Integer/parseInt (read-line)))

(defn read-int-values-line []
  (vec (map #(Integer/parseInt %) (split-line-by-space (read-line)))))

(defn read-input []
  (let [x (read-int-value-line)
        [starting running] (read-int-values-line)
        [total_distance] (read-int-values-line)
        stop_points (read-int-values-line)]
    {:economy {:change_distance x
               :starting starting
               :running running}
     :total_distance total_distance
     :stop_points stop_points}))

(defn create-moving-distances [total_distance stop_points]
  ; "停止地点リストの最後尾にtotal_distanceを追加したリスト"と"停止地点リストの先頭に0を追加したリスト"のお互いの要素を引いたリストを作成する
  ; [30 60 100]
  ; [0 30 60]
  ; ↓
  ; [30 30 40]
  (vec (map #(- %1 %2) (conj stop_points total_distance) (cons 0 stop_points))))

(defn calc-fuel [economy, moving_distance]
  (if (<= moving_distance (:change_distance economy))
    ; 消費燃料の切り替え距離を超えていない場合
    (* moving_distance (:starting economy))
    ; 消費燃料の切り替え距離を超えた場合
    (let [starting-fuel (* (:change_distance economy) (:starting economy))
          running-fuel (* (- moving_distance (:change_distance economy)) (:running economy))]
      (+ starting-fuel running-fuel))))

(defn calc-total-fuel [input]
  ; 総移動距離と停止地点リストから、移動距離リストを作成する
  (let [moving_distances (create-moving-distances (:total_distance input) (:stop_points input))]
    ; reduceと移動距離から必要燃料量を計算する関数を使って、合計の必要な燃料量を求める
    (reduce (fn [total-fuel moving_distance]
              (+ total-fuel (calc-fuel (:economy input) moving_distance)))
            0 moving_distances)))

(defn main []
  (println (calc-total-fuel (read-input))))

(main)
このスクラップは2023/07/08にクローズされました