こんにちは!じゃいごテックのあつしです。
今回は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)
今回のまとめ
後半ではオブジェクト指向での大事な概念である継承を扱いました。
- クラスの継承
- クラス変数の定義
- 特異メソッド(クラスメソッド)の定義と呼び出し

クラスの継承を使えば変更箇所を少なく抑えながら、色々な変更が出来るので便利ですね!