diff --git a/src/main/java/controls/PhaseController.java b/src/main/java/controls/PhaseController.java index 929c670..5a30228 100644 --- a/src/main/java/controls/PhaseController.java +++ b/src/main/java/controls/PhaseController.java @@ -1,44 +1,151 @@ package controls; -import interfaces.ICardButtonEnabler; +import interfaces.IGameView; +import resources.Algo; -public class PhaseController extends Thread{ - ICardButtonEnabler iCardButtonEnabler; +public class PhaseController { + IGameView iGameView; Phase currentPhase; int guess; + boolean isDecidedAttacker; int attacker; + boolean isDecidedTarget; int target; - public PhaseController(ICardButtonEnabler iCardButtonEnabler){ - this.iCardButtonEnabler=iCardButtonEnabler; + Algo algo; + AbstractGameState abstractGameState; + TurnPlayer turnPlayer; + TurnBot turnBot; + public PhaseController(Algo algo){ + this.algo = algo; + isDecidedAttacker = false; + turnPlayer = new TurnPlayer(algo); + turnBot = new TurnBot(algo); + abstractGameState = turnPlayer; currentPhase=Phase.Selection; + //iGameView.onFinishedEachAttack(abstractGameState); + // iGameView.onStartPlayerTurn(abstractGameState); + } + public void bindGameView(IGameView iGameView){ + this.iGameView = iGameView; } public void setSelection(int attacker){ - this.attacker = attacker; - iCardButtonEnabler.setEnableSelection(attacker); + changePhase(Phase.Selection, attacker); +// switch (currentPhase){ +// case Selection: +// if(abstractGameState.isDeckLess()){ +// currentPhase = Phase.Target; +// }else{ +// this.attacker = attacker; +// isDecidedAttacker = true; +// currentPhase = Phase.Target; +// iGameView.onDecidedSelection(attacker); +// } +// break; +// case Target: +// this.attacker = attacker; +// isDecidedAttacker = true; +// currentPhase = Phase.Target; +// iGameView.onDecidedSelection(attacker); +// break; +// } + } - public void setTarget(int target){ - this.target = target; - iCardButtonEnabler.setEnableTarget(target); + public void setTarget(int target){ + changePhase(Phase.Target, target); + } - @Override - public void run(){ - switch (currentPhase){ + public boolean isDecidedAttacker(){ + return isDecidedAttacker; + } + /** + * + * @param phase 遷移先の状態 + * @param params 遷移先に遷移するために必要な引数 + */ + private void changePhase(Phase phase, int... params) { + + switch (phase){ + case StartPlayerTurn: + abstractGameState=turnPlayer; + isDecidedAttacker = !abstractGameState.isDeckLess(); + iGameView.repaintBoard(abstractGameState); + iGameView.onStartPlayerTurn(abstractGameState); + break; case Selection: + + this.attacker = params[0]; + isDecidedAttacker = true; + currentPhase = Phase.Target; + iGameView.onDecidedSelection(attacker); + + break; case Target: + this.target = params[0]; + currentPhase = phase; + iGameView.onDecidedTarget(target); + currentPhase = Phase.Declaration; + + break; case Declaration: + this.guess = params[0]; + abstractGameState.attack(this.guess,this.attacker,this.target); + currentPhase = Phase.StartBotTurn; + var isSucceed = abstractGameState.isSucceedLatestAttack(); + iGameView.repaintBoard(abstractGameState); + iGameView.onFinishedPlayerAttack(guess, isSucceed); + if(judgeGameOver())return; + changePhase(Phase.StartBotTurn, 0); + break; + case StartBotTurn: + + currentPhase = Phase.StartBotTurn; + abstractGameState = turnBot; + abstractGameState.updateTurn(); + iGameView.onStartBotAttack(turnBot); + + break; + case BotAttack: + abstractGameState.updateTurn(); + abstractGameState.attack(params[0],params[1],params[2]); + iGameView.onFinishedBotAttack(params[0], abstractGameState.isSucceedLatestAttack()); + if(judgeGameOver())return; + changePhase(Phase.StartPlayerTurn); + break; + } + } + + public void setDeclaration(int guess) { + changePhase(Phase.Declaration, guess); + } + + public void startBotTurn(){ + changePhase(Phase.StartBotTurn, 0); + } + public void botAttack(int guess, int attacker, int target){ + changePhase(Phase.BotAttack,guess,attacker,target); + } - public void playerAttack(){ + boolean judgeGameOver(){ + if(algo.getLoseA()){ + iGameView.onFinishedGame(abstractGameState, true); + return true; + }else if(algo.getLoseB()){ + iGameView.onFinishedGame(abstractGameState,false); + return true; + } + return false; } - public void botAttack(){ - } enum Phase{ + StartPlayerTurn, Selection, Target, - Declaration + Declaration, + StartBotTurn, + BotAttack } } diff --git a/src/main/java/interfaces/ICardButtonEnabler.java b/src/main/java/interfaces/ICardButtonEnabler.java deleted file mode 100644 index 7ad2fa4..0000000 --- a/src/main/java/interfaces/ICardButtonEnabler.java +++ /dev/null @@ -1,6 +0,0 @@ -package interfaces; - -public interface ICardButtonEnabler { - void setEnableSelection(int selection); - void setEnableTarget(int target); -} diff --git a/src/main/java/interfaces/IGameView.java b/src/main/java/interfaces/IGameView.java new file mode 100644 index 0000000..34cfaae --- /dev/null +++ b/src/main/java/interfaces/IGameView.java @@ -0,0 +1,51 @@ +package interfaces; + +import controls.AbstractGameState; +import controls.TurnBot; + +public interface IGameView { + void onStartPlayerTurn(AbstractGameState abstractGameState); + /** + * アタックに使用するカードが決定した際に実行 + * @param selection + */ + void onDecidedSelection(int selection); + /** + * アタックの対象が決定した際に実行 + * @param target + */ + void onDecidedTarget(int target); + + /** + * プレイヤーのアタックが終了した際に実行 + * @param guess 宣言した数 + * @param isSucceed アタックの成否の結果 + */ + void onFinishedPlayerAttack(int guess, boolean isSucceed); + + /** + * ボットのアタックが開始した際に実行 + * + * @param turnBot ボットの思考結果を出力するためのAI + */ + void onStartBotAttack(TurnBot turnBot); + + /** + * ボットのアタックが終了した際に実行 + * + * @param guess + * @param isSucceed アタックの成否の結果 + */ + void onFinishedBotAttack(int guess, boolean isSucceed); + + /** + * ゲームが終了した際に実行 + */ + void onFinishedGame(AbstractGameState abstractGameState, boolean isLoseA); + + /** + * 盤面を再描画する + * @param abstractGameState + */ + void repaintBoard(AbstractGameState abstractGameState); +} diff --git a/src/main/java/views/MainFrame.java b/src/main/java/views/MainFrame.java index 5e66a31..1cb97a4 100644 --- a/src/main/java/views/MainFrame.java +++ b/src/main/java/views/MainFrame.java @@ -1,6 +1,6 @@ package views; -import controls.StepScheduler; +import controls.PhaseController; import resources.Algo; import javax.swing.*; @@ -9,21 +9,26 @@ import java.awt.event.WindowListener; public class MainFrame extends JFrame { - StepScheduler stepScheduler; public MainFrame() { super("Algolike"); - var mainPanel = new MainPanel(new Algo()); - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + var algo = new Algo(); + var mainPanel = new MainPanel(algo); + var phaseController = new PhaseController(algo); + mainPanel.bindPhaseController(phaseController); + phaseController.bindGameView(mainPanel); + this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); mainPanel.setVisible(true); + this.add(mainPanel, BorderLayout.CENTER); this.pack(); this.addWindowListener(new WindowListener() { @Override public void windowOpened(WindowEvent e) { - mainPanel.playerBehave(); + mainPanel.repaintBoard(mainPanel.abstractGameState); + mainPanel.onStartPlayerTurn(mainPanel.abstractGameState); } @Override @@ -48,7 +53,6 @@ @Override public void windowActivated(WindowEvent e) { - } @Override diff --git a/src/main/java/views/MainPanel.java b/src/main/java/views/MainPanel.java index ae78392..18b6ca7 100644 --- a/src/main/java/views/MainPanel.java +++ b/src/main/java/views/MainPanel.java @@ -1,26 +1,18 @@ package views; import controls.*; -import interfaces.ICardButtonEnabler; +import interfaces.IGameView; import resources.Algo; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; -import java.util.List; import static java.lang.Integer.parseInt; import static views.Constants.*; -public class MainPanel extends JPanel implements ICardButtonEnabler { - private HandButtons myHandButtons; - - private HandButtons opponentHandButtons; - - private List selectableMyHandKeys; - private List selectableOpponentHandKeys; +public class MainPanel extends JPanel implements IGameView { Constants.Step currentStep; JPanel myHandButtonsPanel; JPanel myHandAttackerPanel; @@ -40,14 +32,15 @@ int target; int indexForMyHands = 0; int indexForOpponent = 0; - private JPanel deckButtonPanel; PhaseController phaseController; + private HandButtons myHandButtons; + private HandButtons opponentHandButtons; + private JPanel deckButtonPanel; public MainPanel(Algo algo) { super(new BorderLayout()); myHandButtons = new HandButtons(); opponentHandButtons = new HandButtons(); - selectableOpponentHandKeys = new ArrayList<>(); currentStep = Step.SelectMyHands; deckButtonPanel = new JPanel(); @@ -59,42 +52,92 @@ opponentAttackerPanel = new JPanel(); opponentPanel = new JPanel(); + phaseController = new PhaseController(algo); + myPanel.add(myHandAttackerPanel); myPanel.add(myHandButtonsPanel); opponentPanel.add(opponentAttackerPanel); opponentPanel.add(opponentButtonsPanel); - turnPlayer = new TurnPlayer(algo); turnBot = new TurnBot(algo); - abstractGameState= turnPlayer; + abstractGameState = turnPlayer; if (!abstractGameState.isDeckLess()) { //デッキが存在する場合 var cardButton = new JButton("deck"); cardButton.setPreferredSize(new Dimension(CARD_HEIGHT, CARD_WIDTH)); deckButtonPanel.add(cardButton); + }else{ + } - repaintField(); - /** - * setButton末尾にあった処理をコンストラクタ内へ。 - * - */ + //repaintField(); add(deckButtonPanel, BorderLayout.WEST); - //add(myHandButtonsPanel, BorderLayout.SOUTH); add(myPanel, BorderLayout.SOUTH); - - //add(opponentButtonsPanel, BorderLayout.NORTH); add(opponentPanel, BorderLayout.NORTH); opponentHandButtons.stream().filter(x -> x.getText().equals(CLOSED_SYMBOL)).forEach(x -> { x.setEnabled(true); }); + updateOpponentHandButtons(); repaint(); } + public void bindPhaseController(PhaseController phaseController){ + this.phaseController = phaseController; + } + void updateMyHandButtons() { + /** + * 自分の手札のボタンにリスナーを追加する処理 + */ + myHandButtons.removeButtonListeners(); + myHandButtons.setEnableButtons(true); + myHandButtons.addListeners(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + var sourceButton = ((CardButton) e.getSource()); + for (var my : MainPanel.this.myHandButtons) my.setEnabledSelection(false); + sourceButton.setEnabledSelection(true); + var option = JOptionPane.showConfirmDialog(null, "このカードを使ってアタックをしますか?", "confirmation", 2); + if (option == JOptionPane.YES_OPTION) { + attacker = myHandButtons.indexOf(sourceButton); + isDecidedAttacker = true; + phaseController.setSelection(attacker); + } else { + sourceButton.setEnabledSelection(false); + } + } + }); + } - void paintDrawCard() { + void updateOpponentHandButtons() { + /** + * 相手の手札を選択する処理をリスナーに追加する + */ + opponentHandButtons.removeButtonListeners(); + opponentHandButtons.addListeners(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if(!phaseController.isDecidedAttacker()){ + JOptionPane.showMessageDialog(null, "あなたの手札からアタックに使用するカードを選んでください. ", "Warn", + JOptionPane.WARNING_MESSAGE); + return; + } + var sourceButton = ((CardButton) e.getSource()); + var index = opponentHandButtons.indexOf(sourceButton); + sourceButton.setEnabledSelection(true); + //相手のカードを選択したときに確認用ダイアログを出す + var option = JOptionPane.showConfirmDialog(null, "このカードを選びますか?", "confirmation", 2); + if (option == JOptionPane.YES_OPTION) { + phaseController.setTarget(index); + } else { + sourceButton.setEnabledSelection(false); + } + } + }); + } + + void paintDrawCard(AbstractGameState abstractGameState) { var deckTopCard = abstractGameState.getTopCard(); if (!abstractGameState.isDeckLess()) { //デッキが存在する場合にデッキトップのカードを表示する処理 @@ -110,6 +153,8 @@ if (abstractGameState.getDeckNumber() == 1) { deckButtonPanel.removeAll(); } + }else{ + updateMyHandButtons(); } validate(); @@ -222,12 +267,11 @@ abstractGameState = turnPlayer; isDecidedAttacker = false; - var phaseController = new PhaseController(this); JOptionPane.showMessageDialog(null, "あなたのターンです。"); var selectText = !abstractGameState.isDeckLess() - ?"あなたは数字\"" + abstractGameState.getTopCard().getKey() + "\"のカードをドローしました。" - :"アタックに使用するカードを手札から選んでください。"; + ? "あなたは数字\"" + abstractGameState.getTopCard().getKey() + "\"のカードをドローしました。" + : "アタックに使用するカードを手札から選んでください。"; /** * デッキにカードが存在しないとき、 * 自分の手札を選択してから、相手のカードを選ぶようにする @@ -241,7 +285,7 @@ myHandButtons.addListeners(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - var sourceButton = ((CardButton)e.getSource()); + var sourceButton = ((CardButton) e.getSource()); for (var my : MainPanel.this.myHandButtons) my.setEnabledSelection(false); sourceButton.setEnabledSelection(true); var option = JOptionPane.showConfirmDialog(null, "このカードを使ってアタックをしますか?", "confirmation", 2); @@ -293,10 +337,10 @@ } - paintDrawCard(); + //paintDrawCard(); JOptionPane.showMessageDialog(null, selectText); - if (!abstractGameState.isDeckLess()){ + if (!abstractGameState.isDeckLess()) { JOptionPane.showMessageDialog(null, "アタックする対象を相手の手札から選んでください。"); } /** @@ -306,7 +350,7 @@ opponentHandButtons.addListeners(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - var sourceButton = ((CardButton)e.getSource()); + var sourceButton = ((CardButton) e.getSource()); var index = opponentHandButtons.indexOf(sourceButton); sourceButton.setEnabledSelection(true); //相手のカードを選択したときに確認用ダイアログを出す @@ -327,7 +371,7 @@ opponentHandButtons.addListeners(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - var sourceButton = (CardButton)e.getSource(); + var sourceButton = (CardButton) e.getSource(); var index = opponentHandButtons.indexOf(e.getSource()); sourceButton.setEnabledSelection(true); @@ -419,10 +463,11 @@ // indexForOpponent++; // } - abstractGameState.attack(guess,attacker,target); + // abstractGameState.attack(guess, attacker, target); phaseController.setSelection(0); } + void botBehave() { abstractGameState = turnBot; abstractGameState.updateTurn(); @@ -433,7 +478,7 @@ var selectText = ""; var atk = 0; if (!abstractGameState.isDeckLess()) { //デッキにカードが存在するとき - paintDrawCard();//デッキから引いたカードを描画する + //paintDrawCard();//デッキから引いたカードを描画する selectText = "Botはカードをドローしました。"; } else { atk = bot.selectAttacker(); @@ -451,7 +496,7 @@ var dec = bot.declareNumber(tar); JOptionPane.showMessageDialog(null, "Botは\"" + dec + "\"を宣言しました。"); - abstractGameState.attack(dec, atk, tar); + boolean isSucceed = abstractGameState.isSucceedLatestAttack(); String resultMessage = "Botのアタックは "; @@ -459,18 +504,17 @@ JOptionPane.showMessageDialog(null, resultMessage); myHandButtons.get(tar).setEnabledSelection(false); - repaintField(); if (isGameOver()) { finishGame(); return; } abstractGameState.updateTurn(); - playerBehave(); + } + /** * ゲームが終了しているか - * - * */ + */ boolean isGameOver() { if (abstractGameState.isALose()) { @@ -533,13 +577,31 @@ } @Override - public void setEnableSelection(int attacker) { + public void onStartPlayerTurn(AbstractGameState abstractGameState) { + JOptionPane.showMessageDialog(null, "あなたのターンです。"); + var selectText = !abstractGameState.isDeckLess() + ? "あなたは数字\"" + abstractGameState.getTopCard().getKey() + "\"のカードをドローしました。" + : "アタックに使用するカードを手札から選んでください。"; + + paintDrawCard(abstractGameState); + if (!abstractGameState.isDeckLess()) { + selectText ="あなたは数字\"" + abstractGameState.getTopCard().getKey() + "\"のカードをドローしました。"; + phaseController.setSelection(0); + }else { + selectText = "アタックに使用するカードを手札から選んでください。"; + } + JOptionPane.showMessageDialog(null, selectText); + + } + + @Override + public void onDecidedSelection(int attacker) { } @Override - public void setEnableTarget(int target) { + public void onDecidedTarget(int target) { String[] optionsToChoose = new String[DECK_COUNT]; for (var i = 0; i < optionsToChoose.length; i++) optionsToChoose[i] = String.valueOf(i); var getDeclaredNumber = (String) JOptionPane.showInputDialog( @@ -550,21 +612,124 @@ null, optionsToChoose, optionsToChoose[0]); + if (getDeclaredNumber != null) { //数字を宣言して、承認したとき - guess = parseInt(getDeclaredNumber); var g = parseInt(getDeclaredNumber); - abstractGameState.attack(g, attacker, target); - - boolean isSucceed = abstractGameState.isSucceedLatestAttack(); - - String resultMessage = "あなたのアタックは"; - resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; - JOptionPane.showMessageDialog(null, resultMessage); + phaseController.setDeclaration(g); } else { - opponentHandButtons.stream().filter(x -> x.getText().equals(CLOSED_SYMBOL)).forEach(x -> { - x.setEnabled(true); - }); - return; + opponentHandButtons.get(target).setEnabledSelection(false); + } + } + + @Override + public void onFinishedPlayerAttack(int guess, boolean isSucceed) { + + String resultMessage = "あなたのアタックは"; + resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; + resultMessage += "(宣言した値:" + guess + ")"; + JOptionPane.showMessageDialog(null, resultMessage); + + + } + + @Override + public void onStartBotAttack(TurnBot turnBot) { + var bot = new BotIntelligence(turnBot); + JOptionPane.showMessageDialog(null, "Botのターンです。"); + var selectText = ""; + var atk = 0; + if (!turnBot.isDeckLess()) { //デッキにカードが存在するとき + paintDrawCard(turnBot);//デッキから引いたカードを描画する + selectText = "Botはカードをドローしました。"; + } else { + atk = bot.selectAttacker(); + opponentHandButtons.get(atk).setEnabledSelection(true); + selectText = "Botはアタックに使用するカードを選びました。"; + } + JOptionPane.showMessageDialog(null, selectText); + + var targetText = ""; + var tar = bot.selectTarget(); + myHandButtons.get(tar).setEnabledSelection(true); + JOptionPane.showMessageDialog(null, "Botはこのカードを対象にしました。"); + + + var dec = bot.declareNumber(tar); + JOptionPane.showMessageDialog(null, "Botは\"" + dec + "\"を宣言しました。"); + + phaseController.botAttack(dec, atk, tar); +// boolean isSucceed = abstractGameState.isSucceedLatestAttack(); +// +// String resultMessage = "Botのアタックは "; +// resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; +// JOptionPane.showMessageDialog(null, resultMessage); +// +// myHandButtons.get(tar).setEnabledSelection(false); +// repaintField(); +// if (isGameOver()) { +// finishGame(); +// return; +// } +// abstractGameState.updateTurn(); + } + + @Override + public void onFinishedBotAttack(int guess, boolean isSucceed) { + String resultMessage = "Botのアタックは"; + resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; + resultMessage += "(宣言した値:" + guess + ")"; + JOptionPane.showMessageDialog(null, resultMessage); + + } + @Override + public void repaintBoard(AbstractGameState abstractGameState) { + var myHands = abstractGameState.getMyHands(); + var opponentHands = abstractGameState.getOpponentHands(); + + /** + * 初期化処理(する必要があるのかどうかは知らない) + */ + isDecidedAttacker = false; + myHandButtonsPanel.removeAll();// + myHandButtons.clear(); + myHandAttackerPanel.removeAll(); + opponentAttackerPanel.removeAll(); + opponentButtonsPanel.removeAll();// + opponentHandButtons.clear(); + + for (var i : myHands) { + var cardButton = new CardButton(i.getKey().toString()); + cardButton.setStatus(i.getValue() ? CardButton.Status.OPEN : CardButton.Status.MY_CLOSED); + myHandButtons.add(cardButton); + myHandButtonsPanel.add(cardButton); + } + //ここまでが自分のカードに関する処理 + + /** + *相手のカードに関する処理 + */ + for (var i : opponentHands) { + var cardButton = new CardButton(i.getValue() ? i.getKey().toString() : CLOSED_SYMBOL); + cardButton.setStatus(i.getValue() ? CardButton.Status.OPEN : CardButton.Status.CLOSED); + cardButton.setEnabled(!i.getValue()); + opponentHandButtons.add(cardButton); + opponentButtonsPanel.add(cardButton, 0);//見た目の順序が逆になるように,0番目に挿入 + } + //updateMyHandButtons(); + updateOpponentHandButtons(); + //ここまでが相手のカードに関する処理 + validate(); + repaint(); + } + + + @Override + public void onFinishedGame(AbstractGameState abstractGameState, boolean isLoseA) { + this.repaintBoard(abstractGameState); + if (isLoseA) { + JOptionPane.showMessageDialog(null, "Botが勝利しました。"); + } else { + JOptionPane.showMessageDialog(null, "あなたが勝利しました。"); } } }