Java:if文が多すぎるコードを改善したい
解決済
回答 3
投稿
- 評価
- クリップ 0
- VIEW 7,505
以下のコードだと、一応思うようには動作するのですが、if文が多すぎるコードになってしまって綺麗ではないな..と思っています。
もう少し綺麗な式に直す方法があれば教えていただけませんか?
やりたいこと:
少ない文字で同時にいくつかの値を返すゲームを作りたい。
2人のプレイヤーが4つのアクションボタンをそれぞれ持っており、結果は(0-3)の配列から算出する。
メソッド引数'one'と'two'で受け取った数値から勝敗を判断し、戻り値として 0=両者の負け、1=プレイヤー1の勝ち、2=プレイヤー2の勝ち、3=両者の勝ち、のどれかを返すというものです。
public int fightMath(int one, int two) {
if(one == 0 && two == 0) { result = 0; }
else if(one == 0 && two == 1) { result = 0; }
else if(one == 0 && two == 2) { result = 1; }
else if(one == 0 && two == 3) { result = 2; }
else if(one == 1 && two == 0) { result = 0; }
else if(one == 1 && two == 1) { result = 0; }
else if(one == 1 && two == 2) { result = 2; }
else if(one == 1 && two == 3) { result = 1; }
else if(one == 2 && two == 0) { result = 2; }
else if(one == 2 && two == 1) { result = 1; }
else if(one == 2 && two == 2) { result = 3; }
else if(one == 2 && two == 3) { result = 3; }
else if(one == 3 && two == 0) { result = 1; }
else if(one == 3 && two == 1) { result = 2; }
else if(one == 3 && two == 2) { result = 3; }
else if(one == 3 && two == 3) { result = 3; }
return result;
}
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+2
最悪 16 回の比較、平均で 8 回
です。
最初の回答にあるように勝敗決定表を用意して、その表を引くことで、計算量を常に一定にできます。
しかし
もっとケース分けが膨大な量 (100 * 100) になる、
決定表に未使用のセルが大量に発生する、
ような場合は、勝敗決定を ある程度 プログラムロジックで書く必要がでてきます。
質問のゲームの場合だと、 プレーヤーの手は何らかの物理的な操作に結びついて
いるとおもわれるので、その物理的な挙動にそったロジックを書けばよいです。
もしかすると、計算式1つで、勝敗の計算ができることもあるかもしれません。
(ここでの質問では、ゲームの手の物理的なモデルが不明なので、その例を私が示すことはできませんが)
そこで、以下に、なるべく 計算量がすくなくなるように少し工夫した例をしめします。
質問文では、プレーヤの手は [1,2,3,4] ですが、それを [-2, -1, 1, 2] に変更しています。
そうすると、このゲームでは 勝敗結果が 0, 3 の場合のチェックが簡単にできるからです。
もっとうまい値や判定方法をみつければ、勝敗結果が 1, 2 の場合についても もっと単純にできそうな気がしますが、今はここまでで...
Sample.java
public class Sample {
public static void main(String[] args) {
int[] hands = {-2, -1, 1, 2};
for( int one : hands) {
for( int two : hands) {
System.out.printf("[%d, %d] => %d\n", one, two, fightMath(one, two));
}
System.out.printf("¥n");
}
}
// val の符号を調べる。
// @retrun -1: 負の値, 1: 正の値
static int sign(int val) {
return val < 0 ? -1 : 1;
}
// @param x player one の手 (-2, -1, 1, 2)
// @param y player two の手 (-2, -1, 1, 2)
// @return: (ビット2: y の勝ち負け、ビット1: x の勝ち負け) とした整数を返す。
static int fightMath(int x, int y) {
assert(x != 0);
assert(y != 0);
int win_x = 0; // 0: 負け, 1: 勝ち
int win_y = 0; // 0: 負け, 1: 勝ち
int val = x * y;
if (val > 0) {
win_x = win_y = (sign(val) == sign(x)) ? 1 : 0;
} else if (val == -2) {
win_x = (x < 0) ? 1 : 0;
win_y = 1 - win_x;
} else {
win_x = (x > 0) ? 1 : 0;
win_y = 1 - win_x;
}
return win_x + win_y * 2;
}
}
このプログラムを走らせると次の様な出力になります。
$ javac Sample.java
$ java -ea Sample
[-2, -2] => 0
[-2, -1] => 0
[-2, 1] => 1
[-2, 2] => 2
[-1, -2] => 0
[-1, -1] => 0
[-1, 1] => 2
[-1, 2] => 1
[1, -2] => 2
[1, -1] => 1
[1, 1] => 3
[1, 2] => 3
[2, -2] => 1
[2, -1] => 2
[2, 1] => 3
[2, 2] => 3
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+2
final int[][] result = new int[][] {
{ 0, 0, 1, 2 },
{ 0, 0, 2, 1 },
{ 2, 1, 3, 3 },
{ 1, 2, 3, 3 }
};
return result[one][two];
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
- 0を返す時:両者とも0か1
- 1を返す時:{0,2},{1,3},{2,1},{3,0}
- 2を返す時:{0,3},{1,2},{2,0},{3,1}
- 3を返す時:両者とも2か3
public int fightMath(int one, int two) {
if((one == 0 || one == 1) && (two == 0 || two == 1)) return 0;
else if((one == 2 || one == 3) && (two == 2 || two == 3)) return 3;
else return evaluate(one, two);
}
public int evaluate(int one, int two) {
switch(one) {
case 0:
if(two == 2) return 1;
else if(two == 3) return 2;
break;
case 1:
if(two == 2) return 2;
else if(two == 3) return 1;
break;
case 2:
if(two == 0) return 2;
else if(two == 1) return 1;
break;
case 3:
if(two == 0) return 1;
else if(two == 1) return 2;
break;
}
}
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.19%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2014/08/27 10:41