/*
 * Copyright 2002-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import java.util.Random;
import java.util.Scanner;
import java.util.regex.Pattern;

/**
* じゃんけん
* @author HOU Bin
*/

public class RPS {
	
	private Pattern inputHandPattern = Pattern.compile("[1-3]{1}"); //入力出し手チェック用Pattern
	
	/**
	* じゃんけんの結果
	*/
	public enum RpsResult {
		/**
		* 失敗
		*/
		LOSE,
		/**
		* 引き分け
		*/
		DRAW,
		/**
		* 勝利
		*/
		WIN
	}
	
	/*
	* じゃんけん種類
	* 1: グー、2: チョキ、3: パー
	*/
	private enum Hand {
		ROCK(1, "グー"), //グー
		SCISSORS(2, "チョキ"), //チョキ
		PAPER(3, "パー"); // パー
		
		private int code;
		private String label;
		
		private Hand(int code, String label) {
			this.code = code;
			this.label = label;
		} 

		/**
		* コードを取得する
		* return コード
		*/
		public int getCode() {
			return this.code;
		}
		
		/**
		 * ラベルを取得する
		 * @return ラベル
		 */
		public String getLabel() {
			return this.label;
		}
		
		/**
		* 数字コードを出し手に変換する
		* @param code 1: グー、2: チョキ、3: パー です
		* @return 出し手
		*/
		public static Hand valueOf (int code) {
			for(Hand hand: Hand.values()){
				if(hand.getCode() == code) {
					return hand;
				}
			}
			throw new RuntimeException("Hand Code[" + code + "]は不正です");
		}
		
		@Override
		public String toString() {
			return this.getLabel();
		}
		
		/**
		* 勝負判断
		* return 結果(0: あいこ, 1: 勝, -1: 負)
		*/
		public RpsResult judge (Hand other) {
			if (this == other) {
				return RpsResult.DRAW; //同じである場合, あいこ
			} else if ((this == ROCK && other == SCISSORS) 
						|| (this == SCISSORS && other == PAPER)
				 		|| (this == PAPER && other == ROCK)){
				return RpsResult.WIN; //勝
			} else {
				return RpsResult.LOSE; //負
			}
		}
	}
	
	/**
	* じゃんけんゲーム開始
	*/
	public void play() {
		
		// メセッジを提示する
		System.out.println("じゃんけんをしましょう");
		System.out.println("1: グー、2: チョキ、3: パー です。");
		System.out.println("じゃーんけーん・・");
		
		Scanner keyboard = new Scanner(System.in); 
		
		RpsResult rpsResult = null; //勝負結果
		
		while (RpsResult.WIN != rpsResult && RpsResult.LOSE != rpsResult) { //勝負が出たら、ループ終了
			System.out.print("出す手を入力 => ");
		
			// ユーザーが入力された文字を取得する
			String inputString = keyboard.nextLine();
		
			// 入力チェック
			if (!validInput(inputString)) {
				// 入力エラー, continue
				continue;
			}
		
			// ユーザーの出し手
			Hand userHand = Hand.valueOf(Integer.valueOf(inputString));
		
			// コンピュータの出し手を生成する
			Hand computerHand = generateHand();
			
			//結果を表示する
			if (RpsResult.DRAW != rpsResult) {
				System.out.println("ぽん！");
			} else {
				System.out.println("しょ！");
			}
			System.out.println("あなた：" + userHand + "、コンピュータ：" + computerHand);
			rpsResult = userHand.judge(computerHand);
			switch(rpsResult) {
				case LOSE :
					System.out.println("あなたの負けです!");
					break;
				case DRAW : 
					System.out.println("あいこです!");
					break;
				case WIN :
					System.out.println("あなたの勝ちです!");
					break;
				default: 
					// 発生可能性なし
					throw new RuntimeException("結果[" + userHand.judge(computerHand) + "]は不正です");
			}
		}
	}
	
	/**
	* ランダムでコンピュータが出し手を取得
	*/
	private Hand generateHand() {
		Random random = new Random();
		return Hand.valueOf(random.nextInt(3) + 1);
	}
	
	/**
	* 入力チェック
	* @param v 入力された文字
	* @return 入力チェック結果 true: 入力OK false:　入力エラー
	*/
	private boolean validInput(String v) {
		if (v == null) {
			return false;
		} else {
			return inputHandPattern.matcher(v).matches();
		}
	}
	
	/**
	* Mainメソッド
	*/
	public static void main(String[] args) {
		RPS rps = new RPS();
		rps.play(); //ゲームスタット
	}
}