Newer
Older
Algolike / src / main / java / controls / BotIntelligence.java
package controls;

import interfaces.IBotBehavior;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.stream.Collectors;

import static views.Constants.DECK_COUNT;

public class BotIntelligence implements IBotBehavior {
    TurnBot turnBot;

    public BotIntelligence(TurnBot turnBot) {
        this.turnBot = turnBot;
    }

    /**
     * 未確定の数字を列挙する
     */
    List<Integer> calculateCandidate() {
        //候補の初期化
        List<Integer> candidates = new ArrayList<Integer>();
        for (int i = 0; i < DECK_COUNT; i++) candidates.add(i);

        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;
    }

    /**
     * 相手の手札に対して、候補となる数字を割り当てる
     *
     * @return 候補のリスト
     */
    List<int[]> assignCandidateNumberEachHand() {
        List<Map.Entry<Integer, Boolean>> myHands = turnBot.getMyHands();
        List<int[]> result = new ArrayList<int[]>();

        for (Map.Entry<Integer, Boolean> card : myHands) {//ユーザーの手札を左から見ていく
            int index = myHands.indexOf(card);//左からindex番目に
            List<Integer> candidateList = calculateCandidate();//確認するカード


            if (card.getValue()) {
                candidateList.clear();
            } else {                  //裏の場合

                //そのカードから右隣のカードを確認していく
                for (int i = 0; i < myHands.size() - index - 1; i++) {
                    //今確認していっているカード
                    Map.Entry<Integer, Boolean> currentCard = myHands.get(i + index + 1);
                    if (currentCard.getValue()) {//確認しているカードが表なら、(YES)
                        candidateList.removeIf(x -> x > currentCard.getKey());//その確認したカードの数字より大きい数字を除外する。
                        for (int j = 1; j < i; j++) {//そして、その確認したカードよりjだけ小さいそのカードからj番目の数字を除外する。
                            candidateList.remove(candidateList.size() - 1);
                        }
                        break;
                    }
                }

                //そのカードから左隣のカードを確認していく
                for (int i = 1; i <= index; i++) {
                    //今確認していっているカード
                    Map.Entry<Integer, Boolean> currentCard = myHands.get(index - i);
                    if (currentCard.getValue()) {//表があれば、それより小さい数字を候補から削除する
                        candidateList.removeIf(x -> x < currentCard.getKey());
                    }
                }


            }
            String s = (card.getValue() ? "+" : "-") + card.getKey() + ":[";
            for (int i : candidateList) s += i + " ";
            s += "]\n";
            System.out.println(s);
            result.add(candidateList.stream().mapToInt(x -> x).toArray());
        }
        return result;
    }

    //公開されていないカードのインデックスを選ぶ(カードにかかれている番号ではない)
    @Override
    public int selectAttacker() {
        List<Map.Entry<Integer, Boolean>> botHands = turnBot.getOpponentHands();

        for (Map.Entry<Integer, Boolean> i : botHands) {//小さいものから選択
            if (!i.getValue()) return botHands.indexOf(i);
        }
        return 0;
    }

    @Override
    public int selectTarget() {
        List<int[]> candidate = assignCandidateNumberEachHand();
        int result = 0;
        int min = DECK_COUNT;
        for (int[] i : candidate) {
            if (i.length < min && i.length != 0) {
                result = candidate.indexOf(i);
                min = i.length;
            }
        }
        return result;
    }

    @Override
    public int declareNumber(int target) {
        int[] array = assignCandidateNumberEachHand().get(target);
        return array[new Random().nextInt(array.length)];
    }


}