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)))
コードの全体像
提出コード
(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にクローズされました