// コンピュータによるn人ジャンケン(270行) by 片山博文MZ
// 2017年4月11日
// License: CC BY
// 手を表す列挙型。
enum Hand {
グー,
チョキ,
パー,
無効な手
}
// メインクラス。
public class Main {
// サブクラスComputerNJanken。
static protected class ComputerNJanken {
// 人数の最小値、最大値(定数)。
public static final int MIN_PLAYERS = 2;
public static final int MAX_PLAYERS = 10;
// メンバー変数(ComputerNJankenのインスタンスから使える)。
protected int numOfCpu; // CPUの人数。
protected Hand[] hands; // 手。
protected String[] playerNames
; // プレイヤーの名前。 protected boolean[] survival; // 生き残りを表す。
protected java.
util.
Random rand
; // 乱数生成。 protected java.util.Scanner scanner; // 入力スキャナー。
protected int[] handCounters; // 手の個数。
// コンストラクタ
public ComputerNJanken(java.util.Scanner scanner) {
this(scanner, -1);
}
public ComputerNJanken(java.util.Scanner scanner, int numOfCpu) {
this.
rand = new java.
util.
Random(); this.scanner = scanner;
this.numOfCpu = numOfCpu;
}
// ゲームを行う。
public boolean play() {
// ゲーム開始。
if (!start()) {
println("ゲームを開始できませんでした。");
return false; // 失敗。
}
// ゲームループ。
for (;;) {
// 生き残りの人数を数える。
if (getSurvivorCount() <= 1) {
// 生き残りが1人以下。
int iPlayer = getSurvivor();
if (iPlayer == -1) {
println("勝者なし。");
} else {
println("勝者は" + playerNames[iPlayer] + "です。");
}
return true; // 成功。
}
for (;;) {
// 手を出す。
takeHands();
// 判定。
if (judge()) {
break;
}
println("あいこです。");
// 生き残りを出力する。
printSurvivors();
}
}
}
// 勝った方の手を返す。
public Hand getWinnersHand(Hand hand1, Hand hand2) {
int value1 = hand1.ordinal(), value2 = hand2.ordinal();
if (value1 == value2) {
return Hand.無効な手; // あいこ。
}
// 剰余(割り算の余り)の性質を利用した判定。
if ((value2 - value1 + 3) % 3 == 1) {
return hand1;
}
return hand2;
}
//
// 入出力。
//
return scanner.nextLine().trim();
}
public void print
(String str
) { }
public void println
(String str
) { }
public void printSurvivors() {
print("この時点で残っているのは ");
if (survival[0]) {
print(playerNames[0]);
}
for (int i = 1; i < numOfCpu; ++i) {
if (survival[i]) {
print(" と " + playerNames[i]);
}
}
println("です。");
}
// 人数の入力。
protected void inputPlayerCount() {
numOfCpu = -1;
for (;;) {
print("対戦人数を入力して下さい(" + MIN_PLAYERS +
"人以上" + MAX_PLAYERS + "人以内): ");
try {
String line
= scanner.
nextLine().
trim(); if (!(MIN_PLAYERS <= numOfCpu && numOfCpu <= MAX_PLAYERS))
break;
System.
out.
println("無効な値です。入力をやり直して下さい。"); }
}
}
// ゲームスタート。
protected boolean start() {
println("コンピュータ同士でジャンケンをします。");
if (numOfCpu == -1) {
inputPlayerCount();
}
if (numOfCpu == -1) {
return false; // 失敗。
}
// メンバー変数の初期化。
hands = new Hand[numOfCpu];
playerNames
= new String[numOfCpu
]; survival = new boolean[numOfCpu];
for (int i = 0; i < numOfCpu; ++i) {
playerNames[i] = "CPU#" + i;
survival[i] = true;
}
handCounters = new int[3];
return true; // 成功。
}
// 手を出す。
protected void takeHands() {
for (int i = 0; i < numOfCpu; i++) {
if (survival[i]) {
hands[i] = Hand.values()[rand.nextInt(3)];
}
}
}
// 手をその種類で数える。
protected void countHands() {
// ゼロで初期化。
for (int i = 0; i < 3; i++) {
handCounters[i] = 0;
}
// 生き残りの手の種類を調べて、種類ごとに数える。
for (int i = 0; i < numOfCpu; i++) {
if (survival[i]) {
handCounters[hands[i].ordinal()] += 1;
}
}
}
// プレイヤーの手を表示する。
protected void printHands() {
for (int i = 0; i < 3; ++i) {
Hand hand = Hand.values()[i];
str += hand.toString() + " は ";
str += handCounters[i];
str += " 人、";
}
str += " です。";
println(str);
}
// 判定。
protected boolean judge() {
countHands(); // 手を数える。
printHands(); // 手を表示する。
// 手のばらつきを調べる。
int x = 0;
if (handCounters[0] > 0) ++x;
if (handCounters[1] > 0) ++x;
if (handCounters[2] > 0) ++x;
if (x == 1 || x == 3) {
return false; // あいこ。
}
Hand y = Hand.無効な手;
Hand z = Hand.無効な手;
for (int i = 0; i < numOfCpu; i++) {
if (survival[i]) {
if (handCounters[hands[i].ordinal()] > 0) {
if (hands[i] == y) {
;
} else if (y == Hand.無効な手) {
y = hands[i];
} else {
z = hands[i];
break;
}
}
}
}
if (false) {
println(y.toString());
println(z.toString());
}
// 勝者と敗者を出力。
Hand winnersHand = getWinnersHand(y, z);
println("勝ったのは " + winnersHand.toString() + " です。");
for (int i = 0; i < numOfCpu; i++) {
if (survival[i]) {
if (hands[i] != winnersHand) {
// 負け。
println(playerNames[i] + "が負けました。");
survival[i] = false; // ここでプレイヤーが死ぬ。
}
}
}
return true; // 勝敗あり。
}
// 生き残りの人数を数える。
protected int getSurvivorCount() {
int num = 0;
for (int i = 0; i < numOfCpu; ++i) {
if (survival[i]) {
++num;
}
}
return num;
}
// 生き残りのプレイヤーインデックスを取得する。
// 失敗の場合-1を返す。
protected int getSurvivor() {
for (int i = 0; i < numOfCpu; ++i) {
if (survival[i]) {
return i;
}
}
return -1;
}
}
// メイン関数。
public static void main
(String[] args
) { java.
util.
Scanner scanner
= new java.
util.
Scanner(System.
in); ComputerNJanken janken = new Main.ComputerNJanken(scanner);
janken.play();
}
}