[Java入門]3.5 判断と繰り返し
3.5.1 if と while
無事に実行できたのはいいのですが、お客が一組しか来ないのでは寂し過ぎますね。 またスタンドのタンクの用量が決まっているのにそれより多くのガソリンがあることにできてしまったり、タンクにあるガソリンの残量よりたくさん給油できてしまたりするのも困りものです。 ちゃんとタンクの容量と残量を考慮するようにプログラムを改良しましょう。 そしてお客さんが何台も来るようにします。 まず、コンストラクタも含めてそのメソッドでどんなことを考慮しなくてはいけないかを整理してみます。
| メソッド | どんなことを考慮するか |
|---|---|
| コンストラクタ | タンク容量より多くのガソリンを入れておくことはできない |
refuel |
ガソリンの残量より多く給油することはできない |
また、タンクが空になるまで給油を繰り返すことにしましょう。 タンクが空になったかどうかはガソリンスタンド自身に確認させます。 つまり、タンクが空かどうかを調べるisNotEmptyメソッドをGasStationクラスに追加することにします。
さて、問題は給油の繰り返しですが、これは GasStationSimulationクラスのdealCustomerを書き換えればよさそうです。 なにはともあれ、これらを考慮に入れるとそれぞれのメソッドがどうなるか見てみましょう。
- Java: GasStation.java の変更箇所
-
public GasStation(int initial) { if ( initial > tankCapacity_ ) { remain_ = tankCapacity_; } else { remain_ = initial; } } public int refuel(int amount) { int charged = amount; if ( remain_ < amount ) { charged = remain_; } remain_ = remain_ - charged; return charged; } // isNotEmpty メソッドを追加 public boolean isNotEmpty() { return remain_ > 0; } - Java: GasStationSimulation.java の変更箇所
-
public void dealCustomer() { while ( aGS_.isNotEmpty() ) { System.out.println("\nFor the cusomer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.out.println(" amount: " + chargedAmount + " [liter]"); System.out.println(" price: " + price + " [yen]"); } System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]"); }
■
- C++: GasStation.h の変更箇所
-
class GasStation { private: static const int tankCapacity_; static int unitPrice_; int remain_; int totalSales_; public: explicit GasStation(int initial); int refuel(int amount); int price(int amount) const; void addSales(int price); bool isNotEmpty() const; // isNotEmpty メソッドを追加 static int tankCapacity(); int totalSales() const; static void setUnitPrice(int price); static int unitPrice(); }; - C++: GasStation.cpp の変更箇所
-
GasStation::GasStation(int initial) { if ( initial < tankCapacity_ ) { remain_ = tankCapacity_; } else { remain_ = initial; } } int GasStation::refuel(int amount) { int charged = amount; if ( remain_ < amount ) { charged = remain_; } remain_ = remain_ - charged; return charged; } bool GasStation::isNotEmpty() const { return remain_ > 0; } - C++: GasStationSimulation.cpp の変更箇所
-
void GasStationSimulation::dealCustomer() { while ( aGS_->isNotEmpty() ) { std::cout << "\nFor the customer:" << std::endl; int amount = askInt(" refuel amount? "); int chargedAmount = aGS_->refuel(amount); int price = aGS_->price(chargedAmount); aGS_->addSales(price); std::cout << " amount: " << chargedAmount << " [liter]" << std::endl; std::cout << " price: " << price << " [yen]" << std::endl; } std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl; }
- C#: GasStation.cs の変更箇所
-
public GasStation(int initial) { if ( initial > tankCapacity_ ) { remain_ = tankCapacity_; } else { remain_ = initial; } } public int refuel(int amount) { int charged = amount; if ( remain_ < amount ) { charged = remain_; } remain_ = remain_ - charged; return charged; } // isNotEmpty メソッドを追加 public bool isNotEmpty() { return remain_ > 0; } - C#: GasStationSimulation.cs の変更箇所
-
public void dealCustomer() { while ( aGS_.isNotEmpty() ) { System.Console.WriteLine("\nFor the customer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.Console.WriteLine(" amount: " + chargedAmount + " [liter]"); System.Console.WriteLine(" price: " + price + " [yen]"); } System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]"); }
- VB: GasStation.vb の変更箇所
-
Public Sub New(ByVal initial As Integer) If initial > tankCapacity_ Then remain_ = tankCapacity_ Else remain_ = initial End If End Sub Public Function refuel(ByVal amount As Integer) As Integer Dim charged As Integer = amount If remain_ < amount Then charged = remain_ End If remain_ = remain_ - charged Return charged End Function ' isNotEmpty メソッドの追加 Public Function isNotEmpty() As Boolean Return remain_ > 0 End Function - VB: GasStationSimulation.vb の変更箇所
-
Public Sub dealCustomer() While aGS_.isNotEmpty() System.Console.WriteLine(vbCrLf + "For the customer:") Dim amount As Integer = askInt(" refuel amount? ") Dim chargedAmount As Integer = aGS_.refuel(amount) Dim price As Integer = aGS_.price(chargedAmount) aGS_.addSales(price) System.Console.WriteLine(" amount: " + CStr(chargedAmount) + " [liter]") System.Console.WriteLine(" price: " + CStr(price) + " [yen]") End While System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]") End Sub
□
if, else, while の3つの単語がキーワードです。 if は条件を判断し、その結果に応じて何をするか換えたいときに使います。refuelメソッドの中では、給油しようとした量がガソリンの残量を超えているときには、タンクが空になるまで、すなわち残量全部しか給油できないようにしています。 これに対してコンストラクタの方では if と else を組み合わせて使い、もし(if)最初に指定された量がタンク容量を越えていたらタンク容量ぎりぎりまで、そうでなければ(else)指定された量だけタンクに入れるということをしています。 最後に、dealCustomerメソッドのwhileですが、これはまず始めにガソリンスタンドのタンク残量があるかどうかを調べ、タンクが空でない間(while)次のお客さんを受け付けるという風になっています。 そしてタンクが空になったら繰り返しを終了して、売上の合計を表示します。 実際に変更してどのように動作するか試してみてください。
また、何度も繰り返すと画面が見にくくなってしまうので、繰り返すごとに一行あけるようにしています。 売上の合計を表示するときにも一行あけています。 それぞれ、ソース中のどこがそれにあたるかを調べてみてください。 このソースは$chapter3/ex3にあります。
これを反映したプログラムを実行した結果は以下のようになります。
For the gas station:
initial amount? 250
unit price? 108
For the customer:
refuel amount? 35
amount: 35 [liter]
price: 3780 [yen]
For the customer:
refuel amount? 40
amount: 40 [liter]
price: 4320 [yen]
For the customer:
refuel amount? 38
amount: 38 [liter]
price: 4104 [yen]
For the customer:
refuel amount? 42
amount: 42 [liter]
price: 4536 [yen]
For the customer:
refuel amount? 36
amount: 36 [liter]
price: 3888 [yen]
For the customer:
refuel amount? 45
amount: 45 [liter]
price: 4860 [yen]
For the customer:
refuel amount? 52
amount: 14 [liter]
price: 1512 [yen]
Total sales: 27000 [yen]
3.5.2 回数を決めて繰り返す 1: while
さて、この例では最初にタンクに用意した量を全部売り尽くすまで給油を繰り返すので、結局売上の合計はタンクに最初に用意した量とガソリンの単価だけで決まってしまいます。 これではシミュレーションらしくないので、給油する代数を決めて、それ以上は給油しないことにしましょう。 このための代表的な方法は、次の2つがあります。
whileを使って、変数を1ずつ増やし、一定数に達したら繰り返しをやめる。forを使い、1と同様にする。
それぞれの方法でやるとどうなるか、ソースを比べてみましょう。
とりあえず、5台だけ給油することにします。 もちろん、askIntメソッドを使えば、何台給油するかを最初に入力するようにもできます。 是非試してみてください。
まず、whileを使った場合のソースを次に示します。
このソースは$chapter3/ex4/GasStationSimulation-while.javaに格納されています。
- Java: GasStationSimulation-while.java
-
import java.io.BufferedReader; import java.io.InputStreamReader; class GasStationSimulation { private GasStation aGS_; private int askInt(String message) { try { System.out.print(message); System.out.flush(); String line = new BufferedReader(new InputStreamReader(System.in)).readLine(); return Integer.parseInt(line); } catch ( java.io.IOException e ) { System.out.println("could not get input. Sorry."); return 0; } } public void init() { System.out.println("For the gas station:"); int initial = askInt(" initial amount? "); int price = askInt(" unit price? "); GasStation.setUnitPrice (price); aGS_ = new GasStation(initial); } public void dealCustomer() { int i = 0; while ( aGS_.isNotEmpty() && i < 5 ) { System.out.println("\nFor the cusomer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.out.println(" amount: " + chargedAmount + " [liter]"); System.out.println(" price: " + price + " [yen]"); i = i + 1; } System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]"); } public static void main(String[] args) { GasStationSimulation simulation = new GasStationSimulation(); simulation.init(); simulation.dealCustomer(); } }
■
- C++: GasStationSimulation-while.cpp
-
#include <iostream> #include "GasStationSimulation.h" #include "GasStation.h" GasStationSimulation::~GasStationSimulation() { delete aGS_; } int GasStationSimulation::askInt(const std::string& message) { std::cout << message << std::flush; int result; if ( std::cin >> result ) { return result; } std::cout << "could not get input. sorry." << std::endl; return 0; } void GasStationSimulation::init() { std::cout << "For the gas station:" << std::endl; int initial = askInt(" initial amount? "); aGS_ = new GasStation(initial); int unitPrice = askInt(" unit price? "); GasStation::setUnitPrice(unitPrice); } void GasStationSimulation::dealCustomer() { int i = 0; while ( aGS_->isNotEmpty() && i < 5 ) { std::cout << "\nFor the customer:" << std::endl; int amount = askInt(" refuel amount? "); int chargedAmount = aGS_->refuel(amount); int price = aGS_->price(chargedAmount); aGS_->addSales(price); std::cout << " amount: " << chargedAmount << " [liter]" << std::endl; std::cout << " price: " << price << " [yen]" << std::endl; i = i + 1; } std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl; }
- C#: GasStationSimulation-while.cs
-
class GasStationSimulation { private GasStation aGS_; private int askInt(string message) { System.Console.Write(message); System.Console.Out.Flush(); try { return System.Int32.Parse(System.Console.ReadLine()); } catch ( System.Exception ) { System.Console.WriteLine("could not get input. sorry."); return 0; } } public void init() { System.Console.WriteLine("For the gas stations:"); int initial = askInt(" initial amount? "); aGS_ = new GasStation(initial); GasStation.unitPrice = askInt(" unit price? "); } public void dealCustomer() { int i = 0; while ( aGS_.isNotEmpty() && i < 5 ) { System.Console.WriteLine("\nFor the customer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.Console.WriteLine(" amount: " + chargedAmount + " [liter]"); System.Console.WriteLine(" price: " + price + " [yen]"); i = i + 1; } System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]"); } [System.STAThread] static void Main(string[] args) { GasStationSimulation simulation = new GasStationSimulation(); simulation.init(); simulation.dealCustomer(); } }
- VB: GasStationSimulation-while.vb
-
Class GasStationSimulation Private aGS_ As GasStation Private Function askInt(ByVal message As String) System.Console.Write(message) System.Console.Out.Flush() Try Return System.Int32.Parse(System.Console.ReadLine()) Catch e As System.Exception System.Console.WriteLine("could not get input. Sorry.") Return 0 End Try End Function Public Sub init() System.Console.WriteLine("For the customer:") Dim initial As Integer = askInt(" initial amount? ") GasStation.unitPrice = askInt(" unit price? ") aGS_ = New GasStation(initial) End Sub Public Sub dealCustomer() Dim i As Integer = 0 While aGS_.isNotEmpty() And i < 5 System.Console.WriteLine(vbCrLf + "For the customer:") Dim amount As Integer = askInt(" refuel amount? ") Dim chargedAmount As Integer = aGS_.refuel(amount) Dim price As Integer = aGS_.price(chargedAmount) aGS_.addSales(price) System.Console.WriteLine(" amount: " + CStr(chargedAmount) + " [liter]") System.Console.WriteLine(" price: " + CStr(price) + " [yen]") i = i + 1 End While System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]") End Sub Public Shared Sub Main() Dim simulation As GasStationSimulation = New GasStationSimulation() simulation.init() simulation.dealCustomer() End Sub End Class
□
このdealCustomerメソッドでは、ローカル変数 i を用意してその値を1ずつ増やしています。 そして、whileの条件に i < 5 を追加して、5台に給油したかどうかを調べています。
&& という演算子は、2つ以上の条件を並べて書き、両方が成立しているときだけ成立する、いわゆる論理演算子です。
このプログラムを実行すると以下のように出力されます。
For the gas station:
initial amount? 250
unit price? 108
For the customer:
refuel amount? 42
amount: 42 [liter]
price: 4536 [yen]
For the customer:
refuel amount? 38
amount: 38 [liter]
price: 4104 [yen]
For the customer:
refuel amount? 45
amount: 45 [liter]
price: 4860 [yen]
For the customer:
refuel amount? 41
amount: 41 [liter]
price: 4428 [yen]
For the customer:
refuel amount? 36
amount: 36 [liter]
price: 3888 [yen]
Total sales: 21816 [yen]
こんどはタンクが空にならなくても5回で実行を終了していることがわかります。
3.5.3 回数を決めて繰り返す 2: for
次に、for を使ったもうひとつのやり方を見てみましょう。
次のリストを参照してください。 ソースは$chapter3/ex4/GasStationSimulation-for.javaに格納されています。
- Java: GasStationSimulation-for.java
-
import java.io.BufferedReader; import java.io.InputStreamReader; class GasStationSimulation { private GasStation aGS_; private int askInt(String message) { try { System.out.print(message); System.out.flush(); String line = new BufferedReader(new InputStreamReader(System.in)).readLine(); return Integer.parseInt(line); } catch ( java.io.IOException e ) { System.out.println("could not get input. Sorry."); return 0; } } private void init() { System.out.println("For the gas station:"); int initial = askInt(" initial amount? "); int price = askInt(" unit price? "); GasStation.setUnitPrice (price); aGS_ = new GasStation(initial); } private void dealCustomer() { for ( int i = 0; aGS_.isNotEmpty() && i < 5; i = i + 1 ) { System.out.println("\nFor the cusomer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.out.println(" amount: " + chargedAmount + " [liter]"); System.out.println(" price: " + price + " [yen]"); } System.out.println("\nTotal sales: " + aGS_.totalSales() + " [yen]"); } public static void main(String[] args) { GasStationSimulation simulation = new GasStationSimulation(); simulation.init(); simulation.dealCustomer(); } }
■
- C++: GasStationSimulation-for.cpp
-
#include <iostream> #include "GasStationSimulation.h" #include "GasStation.h" GasStationSimulation::~GasStationSimulation() { delete aGS_; } int GasStationSimulation::askInt(const std::string& message) { std::cout << message << std::flush; int result; if ( std::cin >> result ) { return result; } std::cout << "could not get input. sorry." << std::endl; return 0; } void GasStationSimulation::init() { std::cout << "For the gas station:" << std::endl; int initial = askInt(" initial amount? "); aGS_ = new GasStation(initial); int unitPrice = askInt(" unit price? "); GasStation::setUnitPrice(unitPrice); } void GasStationSimulation::dealCustomer() { for ( int i = 0; aGS_->isNotEmpty() && i < 5; i = i + 1 ) { std::cout << "\nFor the customer:" << std::endl; int amount = askInt(" refuel amount? "); int chargedAmount = aGS_->refuel(amount); int price = aGS_->price(chargedAmount); aGS_->addSales(price); std::cout << " amount: " << chargedAmount << " [liter]" << std::endl; std::cout << " price: " << price << " [yen]" << std::endl; } std::cout << "\nTotal sales: " << aGS_->totalSales() << " [yen]" << std::endl; }
- C#: GasStationSimulation-for.cs>
-
class GasStationSimulation { private GasStation aGS_; private int askInt(string message) { System.Console.Write(message); System.Console.Out.Flush(); try { return System.Int32.Parse(System.Console.ReadLine()); } catch ( System.Exception ) { System.Console.WriteLine("could not get input. sorry."); return 0; } } public void init() { System.Console.WriteLine("For the gas stations:"); int initial = askInt(" initial amount? "); aGS_ = new GasStation(initial); GasStation.unitPrice = askInt(" unit price? "); } public void dealCustomer() { for ( int i = 0; aGS_.isNotEmpty() && i < 5; i = i + 1 ) { System.Console.WriteLine("\nFor the customer:"); int amount = askInt(" refuel amount? "); int chargedAmount = aGS_.refuel(amount); int price = aGS_.price(chargedAmount); aGS_.addSales(price); System.Console.WriteLine(" amount: " + chargedAmount + " [liter]"); System.Console.WriteLine(" price: " + price + " [yen]"); } System.Console.WriteLine("\nTotal sales: " + aGS_.totalSales + " [yen]"); } [System.STAThread] static void Main(string[] args) { GasStationSimulation simulation = new GasStationSimulation(); simulation.init(); simulation.dealCustomer(); } }
- VB: GasStationSimulation-for.vb
-
Class GasStationSimulation Private aGS_ As GasStation Private Function askInt(ByVal message As String) System.Console.Write(message) System.Console.Out.Flush() Try Return System.Int32.Parse(System.Console.ReadLine()) Catch e As System.Exception System.Console.WriteLine("could not get input. Sorry.") Return 0 End Try End Function Public Sub init() System.Console.WriteLine("For the customer:") Dim initial As Integer = askInt(" initial amount? ") GasStation.unitPrice = askInt(" unit price? ") aGS_ = New GasStation(initial) End Sub Public Sub dealCustomer() Dim i As Integer For i = 1 To 5 If Not aGS_.isNotEmpty() Then Exit For End If System.Console.WriteLine(vbCrLf + "For the customer:") Dim amount As Integer = askInt(" refuel amount? ") Dim chargedAmount As Integer = aGS_.refuel(amount) Dim price As Integer = aGS_.price(chargedAmount) aGS_.addSales(price) System.Console.WriteLine(" amount: " + CStr(chargedAmount) + " [liter]") System.Console.WriteLine(" price: " + CStr(price) + " [yen]") Next System.Console.WriteLine(vbCrLf + "Total sales: " + CStr(aGS_.totalSales) + " [yen]") End Sub Public Shared Sub Main() Dim simulation As GasStationSimulation = New GasStationSimulation() simulation.init() simulation.dealCustomer() End Sub End Class
□
今度はfor の後の括弧の中に、変数iの定義や、タンクが空かどうか、5台済んだかどうか、iに1を足すといったことがまとめて書かれています。 この例からわかるように、forを使って書けることはwhileを使っても書くことができます。 どちらも非常によく使われるので覚えておきましょう。
whileを用いた場合と同じ出力が得られるか、実際に試して比べてみてください。