こんにちは!じゃいごテックのあつしです。
今回はpaiza クラス・構造体メニュー から静的メンバという問題を解説します。
この問題集はクラスの静的メンバ(クラス変数)や継承に関する5個のSTEP問題(C~B級)とFINAL問題(B級)で構成されていて、STEP問題を解いて行けばFINAL問題も解けるはず!となっています。
この問題集はボリュームがありますので前半と後半で記事を分けています。
後半(STEP4, 5, FINAL)は継承やクラス変数・クラスメソッドに関するB級相当の問題です。
STEP問題を解いてみる(後半)
簡単な解説は付けていますが、難しいと感じたら下記の記事も参考にしてみて下さい。
STEP4: クラスの継承 (paizaランク B 相当)
問題
paiza 国の大衆居酒屋で働きながらクラスの勉強をしていたあなたは、お客さんをクラスに見立てることで店内の情報を管理できることに気付きました。
全てのお客さんは、ソフトドリンクと食事を頼むことができます。
paiza 国の法律では、 20 歳以上のお客さんは成人とみなされ、お酒を頼むことができます。
20 歳未満のお客さんは未成年とみなされ、お酒を頼もうとした場合はその注文は取り消されます。
また、お酒を頼んだ場合、以降の全ての食事の注文 が毎回 200 円引きになります.
店内の全てのお客さんの数と注文の回数、各注文をしたお客さんの番号とその内容が与えられるので、各お客さんの会計を求めてください。
ヒント
注文について、20 歳未満のお客さんにできて、 20 歳以上のお客さんにできないことはないので、20歳未満のお客さんのクラスを作成して、それを継承して 20歳以上のお客さんのクラスを作成することで効率よく実装することができます。
入力される値
入力は以下のフォーマットで与えられます。
N K
a_1
...
a_N
n_1 s_1 m_1
...
n_K s_K m_K
- 1 行目では、お客さんの人数 N と注文の回数 K が与えられます。
- 続く N 行のうち i 行目(1 ≦ i ≦ N)では、i 番目のお客さんの年齢が与えられます。
- 続く K 行では、頼んだお客さんの番号 n_i , 注文の種類 s_i , 値段 m_i (1 ≦ i ≦ K) が与えられます。
入力値最終行の末尾に改行が1つ入ります。
期待する出力
sum_1
...
sum_N
- i 番目のお客さんの会計 sum_i を N 人のお客さんについて以上の形式で出力してください。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ N , K ≦ 1000
- 1 ≦ a_i ≦ 100 (1 ≦ i ≦ N)
- 1 ≦ n_i ≦ N (1 ≦ i ≦ K)
- 1 ≦ s_i ≦ N (1 ≦ i ≦ K) は "food" , "softdrink" , "alcohol" のいずれかです。
food , softdrink , alcohol はその注文が食事・ソフトドリンク・お酒であることを表しています。 - 300 ≦ m_i ≦ 5000 (1 ≦ i ≦ K)
解答例
Customerクラス
- インスタンス変数
- 年齢 @age : Integer
- メニュー @menu : Array
- 支払額 @payment: Integer(外部からの参照可)
- initializeメソッド(引数: age)
- @age を age で初期化する
- @menu を ["food", "softdrink"] で初期化する
- @payment を 0 で初期化する
- インスタンスメソッド
- order(引数: item, price):
@menu に item が含まれていれば @payment に price を加算する
※ 未成年でもアルコールを注文する可能性ありますが却下されます。
- order(引数: item, price):
AdultCustomerクラス(Customerクラスを継承)
- 定数
- 値引き額 DISCOUNT = 200
- インスタンス変数
- 値引きフラグ @discount : boolean
- initializeメソッド(引数: age)
- super (引数: ageを渡してCustomerクラスのinitializeメソッドを呼び出す)
- @menu に ["alcohol"] を追加する
- @discount を false で初期化する
- インスタンスメソッド
- order(引数: item, price)
- super (引数: item, priceを渡してCustomerクラスのorderメソッドを呼び出す)
- @discountがtrueでitemがfoodなら@paymentをDISCOUNTで減算する
- @discountがfalseでitemが"alcohol"なら@discountをtrueにする
- order(引数: item, price)
INPUT1 = <<~"EOS" 2 5 59 5 2 food 1223 1 alcohol 4461 1 alcohol 4573 1 alcohol 1438 2 softdrink 1581 EOS OUTPUT1 = <<~"EOS" 10472 2804 EOS INPUT2 = <<~"EOS" 7 7 62 91 29 33 79 15 91 2 food 3134 7 alcohol 2181 6 softdrink 4631 3 softdrink 3120 4 softdrink 4004 6 alcohol 1468 6 alcohol 1245 EOS OUTPUT2 = <<~"EOS" 0 3134 3120 4004 0 4631 2181 EOS class Customer # payment の参照を許可 attr_reader :payment def initialize(age) @age = age @menu = ["food", "softdrink"] @payment = 0 end def order(item, price) @payment += price if @menu.include?(item) end end class AdultCustomer < Customer DISCOUNT = 200 def initialize(age) super # 成人メニュー @menu << "alcohol" # 値引きフラグ @discount = false end def order(item, price) super if @discount # food 注文なら値引き @payment -= DISCOUNT if item == "food" else # アルコール注文で値引き true @discount = true if item == "alcohol" end end end def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.shift(k).map(&:split) # customers をインスタンス化して配列を上書きする customers.map! do |age| if age < 20 # 未成年なら Customer クラスでインスタンス化 Customer.new(age) else # 成人なら AdultCustomer クラスでインスタンス化 AdultCustomer.new(age) end end # 注文の処理 requests.each do |idx, item, price| idx, price = [idx, price].map(&:to_i) # 引数に item, price を与えて order を実行 customers[idx - 1].order(item, price) end # 注文が終わったら customers の先頭から順に payment を参照して配列に格納 result = customers.map { |customer| customer.payment } # 支払い料金を改行で連結し末尾に改行を追加 result.join("\n") << "\n" end puts solve(STDIN.read) # [参考 確認用コード] # p solve(INPUT1) # > "10472\n2804\n" # p solve(INPUT1) == OUTPUT1 # > true # p solve(INPUT2) # > "0\n3134\n3120\n4004\n0\n4631\n2181\n" # p solve(INPUT2) == OUTPUT2 # > true
solveメソッドの処理内容
- 入力データ受け取り
人数n
,注文数k
を整数型で受け取ります。n人分
の年齢を受け取り、整数型に変換して配列customers
に格納します。k件
の注文データ情報を受け取り、半角スペースで分割して配列requests
に格納します。
配列customers
の先頭から順にインスタンス化した配列で上書きします。- 未成年なら
Customerクラス
でインスタンス化 - 成人なら
AdultCusomerクラス
でインスタンス化
- 未成年なら
配列requests
の先頭から順に注文の処理を行います。- 顧客を
idx
で指定して、そのインスタンスにitem, price
を与えてorderメソッド
を実行します。
- 顧客を
配列customers
の先頭から順に@payment
を参照した結果を配列result
に格納します。配列result
を改行で連結して末尾に改行を入れて返します。
STEP5: デフォルト引数 (paizaランク B 相当)
問題
居酒屋で働きながらクラスの勉強をしていたあなたは、お客さんをクラスに見立てることで店内の情報を管理できることに気付きました。
全てのお客さんは、ソフトドリンクと食事を頼むことができます。加えて 20 歳以上のお客さんはお酒を頼むことができます。
20 歳未満のお客さんがお酒を頼もうとした場合はその注文は取り消されます。
また、お酒(ビールを含む)を頼んだ場合、以降の全ての食事の注文 が毎回 200 円引きになります。
今回、この居酒屋でビールフェスをやることになり、ビールの注文が相次いだため、いちいちビールの値段である 500 円を書くのをやめ、伝票に注文の種類と値段を書く代わりに 0 とだけを書くことになりました。
店内の全てのお客さんの数と注文の回数、各注文をしたお客さんの番号とその内容が与えられるので、各お客さんの会計を求めてください。
入力される値
入力は以下のフォーマットで与えられます。
N K
a_1
...
a_N
n_1 o_1
...
n_K o_K
- 1 行目では、お客さんの人数 N と注文の回数 K が与えられます。
- 続く N 行のうち i 行目(1 ≦ i ≦ N)では、i 番目のお客さんの年齢が与えられます。
- 続く K 行では、頼んだお客さんの番号 n_i , 注文を表す文字列 o_i が与えられます。
- o_i では、注文の種類 s_i と 値段 m_i (1 ≦ i ≦ K) を表す文字列 "s_i m_i" または、ビールの注文を表す "0" が与えられます。
入力値最終行の末尾に改行が1つ入ります。
期待する出力
sum_1
...
sum_N
- i 番目のお客さんの会計 sum_i を N 人のお客さんについて以上の形式で出力してください。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ N , K ≦ 1000
- 1 ≦ a_i ≦ 100 (1 ≦ i ≦ N)
- 1 ≦ n_i ≦ N (1 ≦ i ≦ K)
o_i (1 ≦ i ≦ K) は次のうちのいずれかの形式です。
- "s_i m_i"
1 ≦ s_i ≦ N (1 ≦ i ≦ K) は "food" , "softdrink" , "alcohol" のいずれかです。
food , softdrink , alcohol はその注文が食事・ソフトドリンク・お酒であることを表しています。
また、300 ≦ m_i ≦ 5000 です。
- "0"
その注文がビールであることを表す。
解答例
Customerクラス
- インスタンス変数
- 年齢 @age : Integer
- メニュー @menu : Array
- 支払額 @payment: Integer(外部からの参照可)
- initializeメソッド(引数: age)
- @age を age で初期化する
- @menu を ["food", "softdrink"] で初期化する
- @payment を 0 で初期化する
- インスタンスメソッド
- order(引数: item = "alcohol", price = 500):
@menu に item が含まれていれば @payment に price を加算する
※ 未成年でもアルコールを注文する可能性ありますが却下されます。
- order(引数: item = "alcohol", price = 500):
AdultCustomerクラス(Customerクラスを継承)
- 定数
- 値引き額 DISCOUNT = 200
- インスタンス変数
- 値引きフラグ @discount : boolean
- initializeメソッド(引数: age)
- super (引数: ageを渡してCustomerクラスのinitializeメソッドを呼び出す)
- @menu に ["alcohol"] を追加する
- @discount を false で初期化する
- インスタンスメソッド
- order(引数: item = "alcohol", price = 500)
- super (引数: item, priceを渡してCustomerクラスのorderメソッドを呼び出す)
- @discountがtrueでitemがfoodなら@paymentをDISCOUNTで減算する
- @discountがfalseでitemが"alcohol"なら@discountをtrueにする
- order(引数: item = "alcohol", price = 500)
INPUT1 = <<~"EOS" 3 5 19 43 22 2 0 2 food 4333 1 0 2 0 1 food 4606 EOS OUTPUT1 = <<~"EOS" 4606 5133 0 EOS INPUT2 = <<~"EOS" 5 10 1 13 31 74 34 1 food 1088 4 alcohol 3210 1 alcohol 599 2 alcohol 602 2 softdrink 4375 4 food 1752 2 0 5 alcohol 4565 3 0 2 0 EOS OUTPUT2 = <<~"EOS" 1088 4375 500 4762 4565 EOS class Customer attr_reader :payment def initialize(age) @age = age @menu_item = ["food", "softdrink"] @payment = 0 end def order(item = "alcohol", price = 500) @payment += price if @menu_item.include?(item) end end class AdultCustomer < Customer DISCOUNT = 200 def initialize(age) super @menu_item << "alcohol" @discount = false end def order(item = "alcohol", price = 500) super if @discount # food 注文なら値引き @payment -= DISCOUNT if item == "food" else # アルコール注文で値引き true @discount = true if item == "alcohol" end end end def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.map(&:split) # customers をインスタンス化して配列を上書きする customers.map! do |age| if age < 20 # 未成年なら Customer クラスでインスタンス化 Customer.new(age) else # 成人なら AdultCustomer クラスでインスタンス化 AdultCustomer.new(age) end end # 注文の処理 requests.each do |number, item, price| number, price = [number, price].map(&:to_i) if item == "0" # "0" なら引数無しで order を実行 customers[number - 1].order else # 引数に item, price を与えて order を実行 customers[number - 1].order(item, price.to_i) end end # 注文が終わったら customers の先頭から順に payment を参照して配列に格納 result = customers.map { |customer| customer.payment } # 支払い料金を改行で連結し末尾に改行を追加 result.join("\n") << "\n" end puts solve(STDIN.read) # p solve(INPUT1) # > "4606\n5133\n0\n" # p solve(INPUT1) == OUTPUT1 # > true # p solve(INPUT2) # > "1088\n4375\n500\n4762\n4565\n" # p solve(INPUT2) == OUTPUT2 # > true
solveメソッドの処理内容
- 入力データ受け取り
人数n
,注文数k
を整数型で受け取ります。n人分
の年齢を受け取り、整数型に変換して配列customers
に格納します。k件
の注文データ情報を受け取り、半角スペースで分割して配列requests
に格納します。
配列customers
の先頭から順にインスタンス化した配列で上書きします。- 未成年なら
Customerクラス
でインスタンス化 - 成人なら
AdultCusomerクラス
でインスタンス化
- 未成年なら
配列requests
の先頭から順に注文の処理を行います。idx
で対象顧客(インスタンス) を選択します。item
が”0”
なら引数なしでorderメソッド
を実行します。
(ビールを注文します。)item, price
を与えてorderメソッド
を実行します。
配列customers
の先頭から順に@payment
を参照した結果を配列result
に格納します。配列result
を改行で連結して末尾に改行を入れて返します。
静的メンバ (paizaランク B 相当)を解いてみる
※ paizaレベルアップ問題集 クラス・構造体メニューより
問題
居酒屋で働きながらクラスの勉強をしていたあなたは、お客さんをクラスに見立てることで勤務時間中の店内の人数や注文の情報を管理できることに気付きました。
全てのお客さんは、ソフトドリンクと食事を頼むことができます。加えて 20 歳以上のお客さんはお酒を頼むことができます。
20 歳未満のお客さんがお酒を頼もうとした場合はその注文は取り消されます。
また、お酒(ビールを含む)を頼んだ場合、以降の全ての食事の注文 が毎回 200 円引きになります。
今回、この居酒屋でビールフェスをやることになり、ビールの注文が相次いだため、いちいちビールの値段である 500 円を書くのをやめ、注文の種類と値段を書く代わりに 0 とだけを書くことになりました。
勤務時間の初めに店内にいるお客さんの人数と与えられる入力の回数、各注文をしたお客さんの番号とその内容、または退店したお客さんの番号が与えられます。
お客さんが退店する場合はそのお客さんの会計を出力してください。勤務時間中に退店した全てのお客さんの会計を出力したのち、勤務時間中に退店した客の人数を出力してください。
入力される値
入力は以下のフォーマットで与えられます。
N K
a_1
...
a_N
n_1 o_1
...
n_K o_K
- 1 行目では、お客さんの人数 N と入力の回数 K が与えられます。
- 続く N 行のうち i 行目(1 ≦ i ≦ N)では、i 番目のお客さんの年齢が与えられます。
- 続く K 行では、頼んだお客さんの番号 n_i , 注文を表す文字列 o_i が与えられます。
- o_i では、注文の種類 s_i と 値段 m_i (1 ≦ i ≦ K) を表す文字列 "s_i m_i" または、ビールの注文を表す "0" または、そのお客さんが会計を行い帰ることを表す "A" が与えられます。
入力値最終行の末尾に改行が1つ入ります。
期待する出力
sum_1 ... C
お客さんが帰るたびにそのお客さんの会計を出力してください。 1 人の会計ごとに改行を行ってください。
勤務時間中に帰った全てのお客さんの会計を出力したのち、勤務時間中に退店した客の人数 C を出力してください。
条件
すべてのテストケースにおいて、以下の条件をみたします。
- 1 ≦ N , K ≦ 1000
- 1 ≦ a_i ≦ 100 (1 ≦ i ≦ N)
- 1 ≦ n_i ≦ N (1 ≦ i ≦ K)
o_i (1 ≦ i ≦ K) は次のうちのいずれかの形式です。
- "s_i m_i"
1 ≦ s_i ≦ N (1 ≦ i ≦ K) は "food" , "softdrink" , "alcohol" のいずれかです。
food , softdrink , alcohol はその注文が食事・ソフトドリンク・お酒であることを表しています。また、300 ≦ m_i ≦ 5000 です。
- "0"
その注文がビールであることを表す。
- "A"
n_i 番のお客さんが会計をして退店することを表す。
- 入力例1
- 2 3
20
30
1 0
2 0
1 A
- 出力例1
- 500
1
- 入力例2
- 7 12
68
85
57
32
90
74
7
2 0
4 A
3 0
1 A
4 softdrink 3781
6 softdrink 3010
4 0
5 alcohol 1018
1 0
1 softdrink 376
1 softdrink 797
2 alcohol 4284
- 出力例2
- 0
0
2
攻略ポイント
ポイント
- 継承で未成年クラスと成人クラスを実装する
- クラス変数で来店者数(精算した顧客数)を管理する
- クラス変数を参照するクラスメソッドを実装する
問題を解く流れ
入出力例をコピペしてヒアドキュメントで変数に代入し、データを確認します。正しく受け取れていれば確認用コードは削除します。(データが多い時はppメソッド
を使うといい感じに出力してくれます)
INPUT1 = <<~"EOS" 2 3 20 30 1 0 2 0 1 A EOS OUTPUT1 = <<~"EOS" 500 1 EOS INPUT2 = <<~"EOS" 7 12 68 85 57 32 90 74 7 2 0 4 A 3 0 1 A 4 softdrink 3781 6 softdrink 3010 4 0 5 alcohol 1018 1 0 1 softdrink 376 1 softdrink 797 2 alcohol 4284 EOS OUTPUT2 = <<~"EOS" 0 0 2 EOS # 確認用コード pp INPUT1 # > "2 3\n" + "20\n" + "30\n" + "1 0\n" + "2 0\n" + "1 A\n" p OUTPUT1 # > "500\n1\n" pp INPUT2 # > "7 12\n" + # > "68\n" + # > "85\n" + # > "57\n" + # > "32\n" + # > "90\n" + # > "74\n" + # > "7\n" + # > "2 0\n" + # > "4 A\n" + # > "3 0\n" + # > "1 A\n" + # > "4 softdrink 3781\n" + # > "6 softdrink 3010\n" + # > "4 0\n" + # > "5 alcohol 1018\n" + # > "1 0\n" + # > "1 softdrink 376\n" + # > "1 softdrink 797\n" + # > "2 alcohol 4284\n" p OUTPUT2 # > "0\n0\n2\n"
続いてCustomerクラス, AdultCustomerクラス
と問題を解くsolveメソッド
を変数の下に定義します。
まず、クラス
を定義します。
Customerクラス
- クラス変数
- 来店者数 @count : Integer
- クラスメソッド
- Customer.visitor_count : @@count を返す
(self.visitor_countと同じ)
- Customer.visitor_count : @@count を返す
- インスタンス変数
- 年齢 @age : Integer
- メニュー @menu : Array
- 支払額 @payment: Integer(外部からの参照可)
- initializeメソッド(引数: age)
- @age を age で初期化する
- @menu を ["food", "softdrink"] で初期化する
- @payment を 0 で初期化する
- インスタンスメソッド
- order(引数: item = "alcohol", price = 500):
@menu に item が含まれていれば @payment に price を加算する
※ 未成年でもアルコールを注文する可能性ありますが却下されます。 - check_out :
@@countをインクリメントする
@paymentを返す
- order(引数: item = "alcohol", price = 500):
AdultCustomerクラス(Customerクラスを継承)
- 定数
- 値引き額 DISCOUNT = 200
- インスタンス変数
- 値引きフラグ @discount : boolean
- initializeメソッド(引数: age)
- super (引数: ageを渡してCustomerクラスのinitializeメソッドを呼び出す)
- @menu に ["alcohol"] を追加する
- @discount を false で初期化する
- インスタンスメソッド
- order(引数: item = "alcohol", price = 500)
- super (引数: item, priceを渡してCustomerクラスのorderメソッドを呼び出す)
- @discountがtrueでitemがfoodなら@paymentをDISCOUNTで減算する
- @discountがfalseでitemが"alcohol"なら@discountをtrueにする
- order(引数: item = "alcohol", price = 500)
class Customer # 来店者数(清算時にカウントアップ) @@count = 0 # 来店者数を返すクラスメソッド def Customer.visitor_count @@count end def initialize(age) @age = age @menu_item = ["food", "softdrink"] @payment = 0 end def order(item = "alcohol", price = 500) @payment += price if @menu_item.include?(item) end def checkout @@count += 1 @payment end end class AdultCustomer < Customer DISCOUNT = 200 def initialize(age) super @menu_item << "alcohol" @discount = false end def order(item = "alcohol", price = 500) super if @discount # food 注文なら値引き @payment -= DISCOUNT if item == "food" else # アルコール注文で値引き true @discount = true if item == "alcohol" end end end # 確認用コード # Customer確認 kodomo = Customer.new(10) kodomo.order("food", 1000) kodomo.order("softdrink", 500) kodomo.order("alcohol", 800) kodomo.order pp kodomo # > #<Customer:0x00007fafab10e840 # > @age=10, # > @menu_item=["food", "softdrink"], # > @payment=1500> p kodomo.checkout # > 1500 # AdultCustomer確認 otona = AdultCustomer.new(20) otona.order("food", 1000) otona.order("softdrink", 500) otona.order("alcohol", 800) otona.order pp otona # > #<AdultCustomer:0x00007fafaf01ccd0 # > @age = 20, # > @discount = true, # > @menu_item = ["food", "softdrink", "alcohol"], # > @payment = 2800 > otona.order("food", 1000) p otona.checkout # > 3600 # visitor_count確認 p Customer.visitor_count # > 2
クラスの動作が良さそうなら、確認用コードを削除してAdultCustomerクラス
の下にsolveメソッド
を記述していきます。
まず、入力データを受け取る処理を書きます。
def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.map(&:split) # 確認用コード [customers, requests] end # 確認用コード pp solve(INPUT1) # > [[20, 30], [["1", "0"], ["2", "0"], ["1", "A"]]] pp solve(INPUT2) # > [[68, 85, 57, 32, 90, 74, 7], # > [["2", "0"], # > ["4", "A"], # > ["3", "0"], # > ["1", "A"], # > ["4", "softdrink", "3781"], # > ["6", "softdrink", "3010"], # > ["4", "0"], # > ["5", "alcohol", "1018"], # > ["1", "0"], # > ["1", "softdrink", "376"], # > ["1", "softdrink", "797"], # > ["2", "alcohol", "4284"]]]
データが正しく受け取れていれば、solve メソッド
に処理を追加していきます。
配列customers
の先頭から順にインスタンス化した配列で上書きします。- 未成年なら
Customerクラス
でインスタンス化 - 成人なら
AdultCusomerクラス
でインスタンス化
- 未成年なら
- 空の
配列result
を用意してから、配列requests
の先頭から順に注文の処理を行います。idx
で対象顧客(インスタンス) を選択します。item
が”0”
なら引数なしでorderメソッド
を実行します。
(ビールを注文します。)item
が”A”
ならcheckoutメソッド
を実行して戻り値を配列result
にpush
します。- それ以外なら
item, price
を与えてorderメソッド
を実行します。
クラスメソッドCustomer.visitor_count
を実行した結果を配列result
にpush
します。配列result
を返します。
def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.map(&:split) # customers をインスタンス化して配列を上書きする customers.map! do |age| if age < 20 # 未成年なら Customer クラスでインスタンス化 Customer.new(age) else # 成人なら AdultCustomer クラスでインスタンス化 AdultCustomer.new(age) end end # 注文の処理 result = [] requests.each do |number, item, price| number, price = [number, price].map(&:to_i) case item when "0" # "0" なら引数無しで order を実行 customers[number - 1].order when "A" # "A" なら checkout を実行 result << customers[number - 1].checkout else # 引数に item, price を与えて order を実行 customers[number - 1].order(item, price) end end # result に退店した客の人数を push result << Customer.visitor_count # 確認用コード result end # 確認用コード # 注:@@countが連番なので個別に確認 p solve(INPUT1) # > [500, 1] p solve(INPUT1) == OUTPUT1 # > false p solve(INPUT2) # > [0, 0, 2] p solve(INPUT2) == OUTPUT2 # > false
あとは出力形式を整えれば完成です。
p solve(INPUT1) == OUTPUT1 -> true
を確認するために、配列resultの要素を半角スペースで結合し末尾に改行を加えます。
def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.map(&:split) # customers をインスタンス化して配列を上書きする customers.map! do |age| if age < 20 # 未成年なら Customer クラスでインスタンス化 Customer.new(age) else # 成人なら AdultCustomer クラスでインスタンス化 AdultCustomer.new(age) end end # 注文の処理 result = [] requests.each do |number, item, price| number, price = [number, price].map(&:to_i) case item when "0" # "0" なら引数無しで order を実行 customers[number - 1].order when "A" # "A" なら checkout を実行 result << customers[number - 1].checkout else # 引数に item, price を与えて order を実行 customers[number - 1].order(item, price) end end # result に退店した客の人数を push result << Customer.visitor_count # result を改行で連結して末尾に改行を追加 result.join("\n") << "\n" end # 確認用コード # 注:@@countが連番なので個別に確認 # p solve(INPUT1) # > "500\n1\n" # p solve(INPUT1) == OUTPUT1 # > true # p solve(INPUT2) # > "0\n0\n2\n" # p solve(INPUT2) == OUTPUT2 # > true
入出力例での動作確認が出来ましたので、標準入力からのデータ受け取りに変更して、手動で動作確認をしたら提出します。
複数行のデータ受け取りなので STDIN.read
を使います。(入力終了は Ctrl+D
又は Ctrl+Z
)
解答コード
class Customer # 来店者数(清算時にカウントアップ) @@count = 0 # 来店者数を返すクラスメソッド def Customer.visitor_count @@count end def initialize(age) @age = age @menu_item = ["food", "softdrink"] @payment = 0 end def order(item = "alcohol", price = 500) @payment += price if @menu_item.include?(item) end def checkout @@count += 1 @payment end end class AdultCustomer < Customer DISCOUNT = 200 def initialize(age) super @menu_item << "alcohol" @discount = false end def order(item = "alcohol", price = 500) super if @discount # food 注文なら値引き @payment -= DISCOUNT if item == "food" else # アルコール注文で値引き true @discount = true if item == "alcohol" end end end def solve(input_data) # 入力データ受け取り input_data = input_data.split("\n") n, k = input_data.shift.split.map(&:to_i) customers = input_data.shift(n).map(&:to_i) requests = input_data.map(&:split) # customers をインスタンス化して配列を上書きする customers.map! do |age| if age < 20 # 未成年なら Customer クラスでインスタンス化 Customer.new(age) else # 成人なら AdultCustomer クラスでインスタンス化 AdultCustomer.new(age) end end # 注文の処理 result = [] requests.each do |number, item, price| number, price = [number, price].map(&:to_i) case item when "0" # "0" なら引数無しで order を実行 customers[number - 1].order when "A" # "A" なら checkout を実行 result << customers[number - 1].checkout else # 引数に item, price を与えて order を実行 customers[number - 1].order(item, price) end end # result に退店した客の人数を push result << Customer.visitor_count # result を改行で連結して末尾に改行を追加 result.join("\n") << "\n" end puts solve(STDIN.read)
今回のまとめ
後半ではオブジェクト指向での大事な概念である継承を扱いました。
- クラスの継承
- クラス変数の定義
- 特異メソッド(クラスメソッド)の定義と呼び出し
クラスの継承を使えば変更箇所を少なく抑えながら、色々な変更が出来るので便利ですね!