diff --git a/src/main/java/controls/AbstractGameState.java b/src/main/java/controls/AbstractGameState.java new file mode 100644 index 0000000..fd0fac6 --- /dev/null +++ b/src/main/java/controls/AbstractGameState.java @@ -0,0 +1,55 @@ +package controls; + +import resources.Algo; + +import java.util.List; +import java.util.Map; + +public abstract class AbstractGameState { + Algo algo; + static boolean isATurn; + boolean isSucceedLatestAttack; + public AbstractGameState(Algo algo){ + this.algo = algo; + isATurn=algo.isATurn(); + } + + public abstract void attack(int guess, int attacker, int target); + public List> getMyHands() { + return algo.getHandsA(); + } + + public List> getOpponentHands() { + return algo.getHandsB(); + } + + public Map.Entry getTopCard() { + if (isDeckLess()) return null; + return algo.getDeck().get(0); + } + public void updateTurn() { + algo.updateTurn(); + isATurn= algo.isATurn(); + } + public boolean isATurn() { + return isATurn; + } + public boolean isDeckLess() { + return algo.getDeck().size() == 0; + } + public boolean isSucceedLatestAttack() { + return isSucceedLatestAttack; + } + + public int getDeckNumber() { + return algo.getDeck().size(); + } + + public boolean isALose() { + return algo.getLoseA(); + } + + public boolean isBLose() { + return algo.getLoseB(); + } +} diff --git a/src/main/java/controls/BotIntelligence.java b/src/main/java/controls/BotIntelligence.java index d2d1588..dd0d493 100644 --- a/src/main/java/controls/BotIntelligence.java +++ b/src/main/java/controls/BotIntelligence.java @@ -9,21 +9,21 @@ import static views.Constants.DECK_COUNT; public class BotIntelligence implements IBotBehavior { - - public BotIntelligence() { - + TurnBot turnBot; + public BotIntelligence(TurnBot turnBot) { + this.turnBot = turnBot; } /** * 未確定の数字を列挙する */ - List calculateCandidate(IAttack iAttack) { + List calculateCandidate() { //候補の初期化 var candidates = new ArrayList(); for (int i = 0; i < DECK_COUNT; i++) candidates.add(i); - candidates.removeAll(iAttack.getOpponentHands().stream().map(x -> x.getKey()).collect(Collectors.toList())); - candidates.removeAll(iAttack.getMyHands().stream().filter(x -> x.getValue()).map(x -> x.getKey()).collect(Collectors.toList())); + candidates.removeAll(turnBot.getOpponentHands().stream().map(x -> x.getKey()).collect(Collectors.toList())); + candidates.removeAll(turnBot.getMyHands().stream().filter(x -> x.getValue()).map(x -> x.getKey()).collect(Collectors.toList())); return candidates; } @@ -31,16 +31,15 @@ /** * 相手の手札に対して、候補となる数字を割り当てる * - * @param iAttack * @return 候補のリスト */ - List assignCandidateNumberEachHand(IAttack iAttack) { - var myHands = iAttack.getMyHands(); + List assignCandidateNumberEachHand() { + var myHands = turnBot.getMyHands(); var result = new ArrayList(); for (var card : myHands) {//ユーザーの手札を左から見ていく var index = myHands.indexOf(card);//左からindex番目に - var candidateList = calculateCandidate(iAttack);//確認するカード + var candidateList = calculateCandidate();//確認するカード if (card.getValue()) { @@ -82,8 +81,8 @@ //公開されていないカードのインデックスを選ぶ(カードにかかれている番号ではない) @Override - public int selectAttacker(IAttack iAttack) { - var botHands = iAttack.getOpponentHands(); + public int selectAttacker() { + var botHands = turnBot.getOpponentHands(); for (var i : botHands) {//小さいものから選択 if (!i.getValue()) return botHands.indexOf(i); @@ -92,8 +91,8 @@ } @Override - public int selectTarget(IAttack iAttack) { - var candidate = assignCandidateNumberEachHand(iAttack); + public int selectTarget() { + var candidate = assignCandidateNumberEachHand(); int result = 0; int min = DECK_COUNT; for (var i : candidate) { @@ -106,8 +105,8 @@ } @Override - public int declareNumber(IAttack iAttack, int target) { - var array = assignCandidateNumberEachHand(iAttack).get(target); + public int declareNumber(int target) { + var array = assignCandidateNumberEachHand().get(target); return array[new Random().nextInt(array.length)]; } diff --git a/src/main/java/controls/PhaseController.java b/src/main/java/controls/PhaseController.java new file mode 100644 index 0000000..8a1cabb --- /dev/null +++ b/src/main/java/controls/PhaseController.java @@ -0,0 +1,127 @@ +package controls; + +import interfaces.IGameView; +import resources.Algo; + +public class PhaseController { + IGameView iGameView; + Phase currentPhase; + int guess; + boolean isDecidedAttacker; + int attacker; + int target; + Algo algo; + public 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; + } + public void bindGameView(IGameView iGameView){ + this.iGameView = iGameView; + } + public void startGame(){ + changePhase(Phase.StartPlayerTurn); + } + public void setSelection(int attacker){ + changePhase(Phase.Selection, attacker); + } + public void setTarget(int target){ + changePhase(Phase.Target, target); + + } + 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 botAttack(int guess, int attacker, int target){ + changePhase(Phase.BotAttack,guess,attacker,target); + + + } + boolean judgeGameOver(){ + + if(algo.getLoseA()){ + iGameView.onFinishedGame(abstractGameState, true); + return true; + }else if(algo.getLoseB()){ + iGameView.onFinishedGame(abstractGameState,false); + return true; + } + return false; + } + + enum Phase{ + StartPlayerTurn, + Selection, + Target, + Declaration, + StartBotTurn, + BotAttack + } +} diff --git a/src/main/java/controls/TurnBot.java b/src/main/java/controls/TurnBot.java new file mode 100644 index 0000000..ba6d508 --- /dev/null +++ b/src/main/java/controls/TurnBot.java @@ -0,0 +1,20 @@ +package controls; + +import resources.Algo; + +public class TurnBot extends AbstractGameState{ + public TurnBot(Algo algo) { + super(algo); + } + + @Override + public void attack(int guess, int attacker, int target) { + if (isDeckLess()) { + algo.inputSelectB(guess, attacker, target); + isSucceedLatestAttack = algo.getSucceedSelectB().getKey(); + } else { + algo.inputDrawB(guess, target); + isSucceedLatestAttack = algo.getSucceedDrawB().getKey(); + } + } +} diff --git a/src/main/java/controls/TurnPlayer.java b/src/main/java/controls/TurnPlayer.java new file mode 100644 index 0000000..a7d6bff --- /dev/null +++ b/src/main/java/controls/TurnPlayer.java @@ -0,0 +1,20 @@ +package controls; + +import resources.Algo; + +public class TurnPlayer extends AbstractGameState{ + public TurnPlayer(Algo algo) { + super(algo); + } + + @Override + public void attack(int guess, int attacker, int target) { + if (isDeckLess()) { + algo.inputSelectA(guess, attacker, target); + isSucceedLatestAttack = algo.getSucceedSelectA().getKey(); + } else { + algo.inputDrawA(guess, target); + isSucceedLatestAttack = algo.getSucceedDrawA().getKey(); + } + } +} diff --git a/src/main/java/interfaces/IBotBehavior.java b/src/main/java/interfaces/IBotBehavior.java index d5e2afa..f4e096a 100644 --- a/src/main/java/interfaces/IBotBehavior.java +++ b/src/main/java/interfaces/IBotBehavior.java @@ -1,9 +1,9 @@ package interfaces; public interface IBotBehavior { - int selectAttacker(IAttack iAttack); + int selectAttacker(); - int selectTarget(IAttack iAttack); + int selectTarget(); - int declareNumber(IAttack iAttack, int target); + int declareNumber(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/resources/Algo.java b/src/main/java/resources/Algo.java index 4b7c627..85919fc 100644 --- a/src/main/java/resources/Algo.java +++ b/src/main/java/resources/Algo.java @@ -15,7 +15,7 @@ private SucceedSelectA succeedSelectA; private SucceedSelectB succeedSelectB; int turnCount = 0; - + boolean isATurn; public Algo() { ///モデル生成分 loseB = new LoseB(); @@ -28,6 +28,7 @@ succeedSelectA = new SucceedSelectA(handsB, handsA); succeedSelectB = new SucceedSelectB(handsA, handsB); //追加分 + isATurn = true; deck.reset(DECK_COUNT); for (int i = 0; i < 2; i++) { handsA.getValue().add(deck.head()); @@ -92,4 +93,10 @@ public Map.Entry getSucceedDrawA() { return succeedDrawA.getValue(); } + + //追加分 + public boolean isATurn() { + return isATurn; + } + public void updateTurn(){isATurn= isATurn? false : true;} } \ No newline at end of file diff --git a/src/main/java/views/CardButton.java b/src/main/java/views/CardButton.java index 10b5b49..1eadaf1 100644 --- a/src/main/java/views/CardButton.java +++ b/src/main/java/views/CardButton.java @@ -29,6 +29,10 @@ } } + public Status getStatus() { + return status; + } + public void setStatus(Status status) { switch (status) { case OPEN: @@ -45,6 +49,7 @@ this.setForeground(OPEN_COLOR); break; } + this.status = status; } @Override diff --git a/src/main/java/views/HandButtons.java b/src/main/java/views/HandButtons.java new file mode 100644 index 0000000..d0b86a5 --- /dev/null +++ b/src/main/java/views/HandButtons.java @@ -0,0 +1,28 @@ +package views; + +import java.awt.event.ActionListener; +import java.util.ArrayList; + +/** + * 手札の情報をボタンで扱うためのクラス + */ +class HandButtons extends ArrayList { + public void addListeners(ActionListener al){ + for (var hb : this){ + hb.addActionListener(al); + } + } + public void setEnableButtons(boolean enableButtons){ + for (var hb : this){ + hb.setEnabled(enableButtons); + } + } + public void removeButtonListeners(){ + for(var my:this) { + for( ActionListener al : my.getActionListeners() ) { + my.removeActionListener( al ); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/views/MainFrame.java b/src/main/java/views/MainFrame.java index d1f9c47..f69bab9 100644 --- a/src/main/java/views/MainFrame.java +++ b/src/main/java/views/MainFrame.java @@ -1,6 +1,7 @@ package views; -import controls.StepScheduler; +import controls.PhaseController; +import resources.Algo; import javax.swing.*; import java.awt.*; @@ -8,21 +9,25 @@ import java.awt.event.WindowListener; public class MainFrame extends JFrame { - StepScheduler stepScheduler; public MainFrame() { super("Algolike"); - stepScheduler = new StepScheduler(); - var mainPanel = new MainPanel(stepScheduler); - 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(stepScheduler); + phaseController.startGame(); } @Override @@ -47,7 +52,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 c075c5a..2cc785d 100644 --- a/src/main/java/views/MainPanel.java +++ b/src/main/java/views/MainPanel.java @@ -1,50 +1,32 @@ package views; -import controls.BotIntelligence; -import controls.StepScheduler; -import interfaces.IAttack; +import controls.*; +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 { - private List myHandButtons; - - private List opponentHandButtons; - - private List selectableMyHandKeys; - private List selectableOpponentHandKeys; - Constants.Step currentStep; +public class MainPanel extends JPanel implements IGameView { JPanel myHandButtonsPanel; JPanel myHandAttackerPanel; JPanel myPanel; JPanel opponentButtonsPanel; JPanel opponentAttackerPanel; JPanel opponentPanel; - /** - * アタックで使用するカードが既に決定しているか - */ - boolean isDecidedAttacker; - int guess; - int attacker; - int target; - int indexForMyHands = 0; - int indexForOpponent = 0; + PhaseController phaseController; + private HandButtons myHandButtons; + private HandButtons opponentHandButtons; private JPanel deckButtonPanel; - - public MainPanel(StepScheduler stepScheduler) { + public MainPanel(Algo algo) { super(new BorderLayout()); - myHandButtons = new ArrayList<>(); - opponentHandButtons = new ArrayList<>(); - selectableOpponentHandKeys = new ArrayList<>(); - currentStep = Step.SelectMyHands; + myHandButtons = new HandButtons(); + opponentHandButtons = new HandButtons(); deckButtonPanel = new JPanel(); myHandButtonsPanel = new JPanel(); @@ -52,111 +34,215 @@ myHandAttackerPanel = new JPanel(); myPanel = new JPanel(); + opponentAttackerPanel = new JPanel(); opponentPanel = new JPanel(); + phaseController = new PhaseController(algo); + myPanel.add(myHandAttackerPanel); myPanel.add(myHandButtonsPanel); opponentPanel.add(opponentAttackerPanel); opponentPanel.add(opponentButtonsPanel); - if (!stepScheduler.isDeckLess()) { //デッキが存在する場合 - var cardButton = new JButton("deck"); - cardButton.setPreferredSize(new Dimension(CARD_HEIGHT, CARD_WIDTH)); - deckButtonPanel.add(cardButton); - } - repaintField(stepScheduler); - /** - * setButton末尾にあった処理をコンストラクタ内へ。 - * - */ 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()); + var isOpened = sourceButton.getStatus()== CardButton.Status.OPEN; + if(isOpened){ + JOptionPane.showMessageDialog(null, "裏のカードを選んでください. ", "Warn", + JOptionPane.WARNING_MESSAGE); + return; + } - void botBehave(IAttack iAttack) { - iAttack.updateTurn(); - var bot = new BotIntelligence(); + for (var my : MainPanel.this.myHandButtons) my.setEnabledSelection(false); + sourceButton.setEnabledSelection(true); + var option = JOptionPane.showConfirmDialog(null, "このカードを使ってアタックをしますか?", "confirmation", 2); + if (option == JOptionPane.YES_OPTION) { + int attacker = myHandButtons.indexOf(sourceButton); + phaseController.setSelection(attacker); + } else { + sourceButton.setEnabledSelection(false); + } + + } + }); + } + + 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()) { //デッキが存在する場合にデッキトップのカードを表示する処理 + var cardButton = new CardButton(deckTopCard.getKey().toString()); + cardButton.setBounds(0, 100, CARD_WIDTH, CARD_HEIGHT); + if (abstractGameState.isATurn()) { + myHandAttackerPanel.add(cardButton); + } else { + cardButton.setText(CLOSED_SYMBOL); + opponentAttackerPanel.add(cardButton); + } + if (abstractGameState.getDeckNumber() == 1) { + deckButtonPanel.removeAll(); + } + }else{ + updateMyHandButtons(); + } + + validate(); + repaint(); + } + @Override + 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 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( + null, + "このカードの数字を宣言してください。", + "Declare Number", + JOptionPane.QUESTION_MESSAGE, + null, + optionsToChoose, + optionsToChoose[0]); + + if (getDeclaredNumber != null) { //数字を宣言して、承認したとき + var g = parseInt(getDeclaredNumber); + phaseController.setDeclaration(g); + } else { + 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 (!iAttack.isDeckLess()) { //デッキにカードが存在するとき - paintDrawCard(iAttack);//デッキから引いたカードを描画する + if (!turnBot.isDeckLess()) { //デッキにカードが存在するとき + paintDrawCard(turnBot);//デッキから引いたカードを描画する selectText = "Botはカードをドローしました。"; } else { - atk = bot.selectAttacker(iAttack); + atk = bot.selectAttacker(); opponentHandButtons.get(atk).setEnabledSelection(true); selectText = "Botはアタックに使用するカードを選びました。"; } JOptionPane.showMessageDialog(null, selectText); var targetText = ""; - var tar = bot.selectTarget(iAttack); + var tar = bot.selectTarget(); myHandButtons.get(tar).setEnabledSelection(true); JOptionPane.showMessageDialog(null, "Botはこのカードを対象にしました。"); - var dec = bot.declareNumber(iAttack, tar); + var dec = bot.declareNumber(tar); JOptionPane.showMessageDialog(null, "Botは\"" + dec + "\"を宣言しました。"); - iAttack.attack(dec, atk, tar); - boolean isSucceed = iAttack.isSucceedLatestAttack(); + 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(); + } - String resultMessage = "Botのアタックは "; + @Override + public void onFinishedBotAttack(int guess, boolean isSucceed) { + String resultMessage = "Botのアタックは"; resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; + resultMessage += "(宣言した値:" + guess + ")"; JOptionPane.showMessageDialog(null, resultMessage); - myHandButtons.get(tar).setEnabledSelection(false); - repaintField(iAttack); - if (isGameOver(iAttack)) { - finishGame(iAttack); - return; - } - iAttack.updateTurn(); - playerBehave(iAttack); } - - void paintDrawCard(IAttack iAttack) { - var deckTopCard = iAttack.getTopCard(); - - if (!iAttack.isDeckLess()) { //デッキが存在する場合にデッキトップのカードを表示する処理 - var cardButton = new CardButton(deckTopCard.getKey().toString()); - cardButton.setBounds(0, 100, CARD_WIDTH, CARD_HEIGHT); - if (iAttack.isATurn()) { - myHandAttackerPanel.add(cardButton); - isDecidedAttacker = true; - } else { - cardButton.setText(CLOSED_SYMBOL); - opponentAttackerPanel.add(cardButton); - } - if (iAttack.getDeckNumber() == 1) { - deckButtonPanel.removeAll(); - } - } - - validate(); - repaint(); - } - - void repaintField(IAttack iAttack) { - - var myHands = iAttack.getMyHands(); - var opponentHands = iAttack.getOpponentHands(); + @Override + public void repaintBoard(AbstractGameState abstractGameState) { + var myHands = abstractGameState.getMyHands(); + var opponentHands = abstractGameState.getOpponentHands(); /** * 初期化処理(する必要があるのかどうかは知らない) */ - isDecidedAttacker = false; + deckButtonPanel.removeAll(); myHandButtonsPanel.removeAll();// myHandButtons.clear(); myHandAttackerPanel.removeAll(); @@ -164,199 +250,44 @@ opponentButtonsPanel.removeAll();// opponentHandButtons.clear(); - /** - * 自分の手札に関する処理 - */ - indexForMyHands = 0; + if (!abstractGameState.isDeckLess()) { //デッキが存在する場合 + var cardButton = new JButton("deck"); + cardButton.setPreferredSize(new Dimension(CARD_HEIGHT, CARD_WIDTH)); + deckButtonPanel.add(cardButton); + } 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, BorderLayout.WEST); myHandButtonsPanel.add(cardButton); - final var a = indexForMyHands;//actionPerformedの中に書くと、クリックされて初めて、回しきったindexForMyHandsを参照してしまうため、ここで一時変数に格納する - cardButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - if (!iAttack.isDeckLess()) return;//デッキがあるときは何も反応しないように - for (var my : myHandButtons) my.setEnabledSelection(false); - cardButton.setEnabledSelection(true); - var option = JOptionPane.showConfirmDialog(null, "このカードを使ってアタックをしますか?", "confirmation", 2); - - - if (option == JOptionPane.YES_OPTION) { - attacker = a; - isDecidedAttacker = true; - } else { - cardButton.setEnabledSelection(false); - } - } - }); - indexForMyHands++; } //ここまでが自分のカードに関する処理 /** *相手のカードに関する処理 */ - indexForOpponent = 0; - 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()); - cardButton.addActionListener(new ActionListener() { - final int index = indexForOpponent; - - public void actionPerformed(ActionEvent e) { - if (!iAttack.isDeckLess()) isDecidedAttacker = true; - if (!isDecidedAttacker) { - JOptionPane.showMessageDialog(null, "あなたの手札からアタックに使用するカードを選んでください. ", "Warn", - JOptionPane.WARNING_MESSAGE); - return; - } - - cardButton.setEnabledSelection(true); - - //相手のカードを選択したときに確認用ダイアログを出す - var option = JOptionPane.showConfirmDialog(null, "このカードを選びますか?", "confirmation", 2); - if (option == JOptionPane.YES_OPTION) { - target = opponentHands.size() - index;//画面上,相手の手札も自分の手札と同じように左から右へ並べられているため,それを補正するために反転させている - var t = index; - opponentHandButtons.stream().filter(x -> x.getText().equals(CLOSED_SYMBOL)).forEach(x -> { - x.setEnabled(false); - }); - String[] optionsToChoose = new String[DECK_COUNT]; - for (var i = 0; i < optionsToChoose.length; i++) optionsToChoose[i] = String.valueOf(i); - var getDeclaredNumber = (String) JOptionPane.showInputDialog( - null, - "このカードの数字を宣言してください。", - "Declare Number", - JOptionPane.QUESTION_MESSAGE, - null, - optionsToChoose, - optionsToChoose[0]); - if (getDeclaredNumber != null) { //数字を宣言して、承認したとき - guess = Integer.parseInt(getDeclaredNumber); - var g = Integer.parseInt(getDeclaredNumber); - iAttack.attack(g, attacker, t); - - boolean isSucceed = iAttack.isSucceedLatestAttack(); - - String resultMessage = "あなたのアタックは"; - resultMessage += isSucceed ? "成功しました。" : "失敗しました。"; - JOptionPane.showMessageDialog(null, resultMessage); - } else { - opponentHandButtons.stream().filter(x -> x.getText().equals(CLOSED_SYMBOL)).forEach(x -> { - x.setEnabled(true); - }); - return; - } - - } else { - cardButton.setEnabledSelection(false); - return; - } - for (var my : myHandButtons) my.setEnabledSelection(false); - cardButton.setEnabledSelection(false); - repaintField(iAttack); - if (isGameOver(iAttack)) { - finishGame(iAttack); - return; - } - botBehave(iAttack); - } - }); - opponentHandButtons.add(cardButton); - opponentButtonsPanel.add(cardButton, 0);//見た目の順序が逆になるように,0番目に挿入 - indexForOpponent++; - } - //ここまでが相手のカードに関する処理 - validate(); - repaint(); - } - - public void playerBehave(IAttack iAttack) { - isDecidedAttacker = false; - JOptionPane.showMessageDialog(null, "あなたのターンです。"); - var selectText = ""; - var atk = 0; - if (!iAttack.isDeckLess()) { //デッキにカードが存在するとき - selectText = "あなたは数字\"" + iAttack.getTopCard().getKey() + "\"のカードをドローしました。"; - } else { - selectText = "アタックに使用するカードを手札から選んでください。"; - } - paintDrawCard(iAttack); - - JOptionPane.showMessageDialog(null, selectText); - - if (!iAttack.isDeckLess()) JOptionPane.showMessageDialog(null, "アタックする対象を相手の手札から選んでください。"); - - } - - /** - * ゲームが終了しているか - * - * @param iAttack - */ - boolean isGameOver(IAttack iAttack) { - - if (iAttack.isALose()) { - return true; - } else if (iAttack.isBLose()) { - return true; - } - - return false; - } - - void finishGame(IAttack iAttack) { - var myHands = iAttack.getMyHands(); - var opponentHands = iAttack.getOpponentHands(); - - /** - * 初期化処理(する必要があるのかどうかは知らない) - */ - isDecidedAttacker = false; - myHandButtonsPanel.removeAll();// - myHandButtons.clear(); - opponentButtonsPanel.removeAll();// - opponentHandButtons.clear(); - /** - * 自分の手札に関する処理 - */ - indexForMyHands = 0; - 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, BorderLayout.WEST); - - final var a = indexForMyHands;//actionPerformedの中に書くと、クリックされて初めて、回しきったindexForMyHandsを参照してしまうため、ここで一時変数に格納する - indexForMyHands++; - } - //ここまでが自分のカードに関する処理 - - /** - *相手のカードに関する処理 - */ - indexForOpponent = 0; 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番目に挿入 - indexForOpponent++; } + + updateOpponentHandButtons(); //ここまでが相手のカードに関する処理 validate(); repaint(); - if (iAttack.isALose()) { + } + @Override + public void onFinishedGame(AbstractGameState abstractGameState, boolean isLoseA) { + this.repaintBoard(abstractGameState); + myHandButtons.setEnableButtons(false); + opponentHandButtons.setEnableButtons(false); + if (isLoseA) { JOptionPane.showMessageDialog(null, "Botが勝利しました。"); - } else if (iAttack.isBLose()) { + } else { JOptionPane.showMessageDialog(null, "あなたが勝利しました。"); } - } } diff --git a/src/test/java/controls/BotIntelligenceTest.java b/src/test/java/controls/BotIntelligenceTest.java index 44e99ba..aa18c35 100644 --- a/src/test/java/controls/BotIntelligenceTest.java +++ b/src/test/java/controls/BotIntelligenceTest.java @@ -11,10 +11,11 @@ @Test void 正しく未確定数字を計算ができる() { StepScheduler stepScheduler=new StepScheduler(); - BotIntelligence botIntelligence=new BotIntelligence(); + var algo = stepScheduler.algo; + BotIntelligence botIntelligence=new BotIntelligence(new TurnBot(algo)); stepScheduler.isATurn = false; - var candidate=botIntelligence.calculateCandidate(stepScheduler); + var candidate=botIntelligence.calculateCandidate(); printAlgoState(algo); var s= "["; for (var i : candidate)s+=i+" "; @@ -24,9 +25,9 @@ @Test void 各手札のカードに対して候補を算出できる(){ StepScheduler stepScheduler=new StepScheduler(); - BotIntelligence botIntelligence=new BotIntelligence(); - var algo = stepScheduler.algo; + var algo = stepScheduler.algo; + BotIntelligence botIntelligence=new BotIntelligence(new TurnBot(algo)); var iniHandsANum = algo.getHandsA().size(); var initDeckNum=algo.getDeck().size(); //正解のカードを選択させるための変数 @@ -38,6 +39,6 @@ stepScheduler.isATurn = false; printAlgoState(algo); - botIntelligence.assignCandidateNumberEachHand(stepScheduler); + botIntelligence.assignCandidateNumberEachHand(); } } \ No newline at end of file