“This is the 11th day of my participation in the First Challenge 2022. For details: First Challenge 2022”

❤️ Author’s home page: Xiao Xu Zhu

❤️ About the author: Hello everyone, I am Xiao Xu Zhu. Java field quality creator 🏆, CSDN blog expert 🏆, Huawei cloud enjoy expert 🏆, Nuggets of the year popular author 🏆, Ali Cloud expert blogger 🏆

❤️ technology live, the appreciation

❤️ like 👍 collect ⭐ look again, form a habit

preface

Chinese chess is a kind of chess originated in China. It is a kind of two-player antagonistic game and has a long history in China. Because the equipment is simple and interesting, it has become a very popular chess activity.

Chinese chess uses a square checkerboard with a total of 32 round pieces and 16 pieces each in red and black, placed and moved at intersections. The two sides alternate moves, and the one who checkmated the opposing general first wins.

Chinese chess is a puzzle game with strong Chinese characteristics, the new online battle, fun, parties can invite children to challenge together. The wonderful games make you feel the profoundness of Chinese chess.

“Chinese Chess” game is implemented with Java language, using Swing technology for interface processing, design ideas with object-oriented thought. , man-machine chess based on minimax search algorithm.

The main requirements

According to the rules of Chinese chess, to achieve red and black games, there should be AI opponents, players can play against AI, or two players can play by themselves.

The main design

1, look for the board interface and the corresponding chess pictures, program design board interface and function menu

2. Design the movement logic of different pieces

3. When the chess pieces move, there should be sound effects

4. Design the logical algorithm of the opponent AI, which uses Max/min search algorithm and sets different search depth AI(different intelligence).

5, before the start of the game, the two sides of the chess pieces on the board. 6, in the game, by the red side to go first, both sides take turns to take a step. 7. When it is the turn of a player to move a piece from one crossing point to another, or to eat the other’s piece and occupy its crossing point, it counts as a move. The two sides each walk, called a round. 9, take a chess, if their own pieces can go to the position of the other side’s pieces exist, you can eat the other side’s pieces and occupy that position. 10, one side’s pieces attack the opponent’s shuai (general), and the next move to eat it, known as “zhaojiang”, or simply “general”. “Zhao Will” need not declare. The subject must immediately “answer”, that is, use his own method to resolve the situation of the subject. If a checkmate fails to answer, he is checkmated.

Specially designed man-machine game, everyone game, and AI to AI game

Screenshot function

The game start

Game menu Settings

Effect of mobile

Code implementation

Checkerboard design


@Slf4j
public class BoardPanel extends JPanel implements LambdaMouseListener {

    /** * is used to mark checkerboard moves */
    private final transient TraceMarker traceMarker;
    /** * The starting position of the current move corresponds to the piece */
    private transient ChessPiece curFromPiece;
    /** * scenario */
    private transient Situation situation;

    /** * Create the panel. */
    public BoardPanel(a) {
        setBorder(new EmptyBorder(5.5.5.5));
        setLayout(null);
        // Initializes the tag
        traceMarker = new TraceMarker(BoardPanel.this);
        // Add mouse events
        addMouseListener(this);
    }

    /**
     * 更新标记
     */
    public void updateMark(Place from, Place to) {
        // Update the tag
        curFromPiece = null;
        // Change the tag
        traceMarker.endedStep(from, to);
    }

    /** * Initializes all tags */
    public void initMark(a) {
        traceMarker.initMarker();
    }

    /** * Add pieces */
    public void init(Situation situation) {
        this.situation = situation;
        // Remove all components
        this.removeAll();
        // Add pieces
        situation.getPieceList().forEach(it -> add(it.getComp()));
        situation.getSituationRecord().getEatenPieceList().forEach(it -> add(it.getComp()));
        // Initializes the tag
        traceMarker.initMarker();
        repaint();
    }

    / * * *@paramE Mouse press the event object */
    @Override
    public void mouseReleased(MouseEvent e) {
        / / position
        Place pointerPlace = ChessDefined.convertLocationToPlace(e.getPoint());
        if (pointerPlace == null) {
            return;
        }
        if(situation.winner() ! =null) {
            log.warn("Winner already exists: {}, cannot move", situation.winner());
            return;
        }
        // The current move
        @NonNull Part pointerPart = situation.getNextPart();
        // The current focus piece
        ChessPiece pointerPiece = situation.getChessPiece(pointerPlace);
        // Determine whether moves can be made by the current side and position
        // step: form
        if (curFromPiece == null) {
            // The current focus position has a piece and is its own piece
            if(pointerPiece ! =null && pointerPiece.piece.part == pointerPart) {
                // The chess piece is from
                curFromPiece = pointerPiece;
                traceMarker.setMarkFromPlace(pointerPlace);
                / / get toList
                MyList<Place> list = curFromPiece.piece.role.find(new AnalysisBean(situation.generatePieces()), pointerPart, pointerPlace);
                traceMarker.showMarkPlace(list);
                ChessAudio.CLICK_FROM.play();
                log.info("True -> Current focus position has a piece and is its own piece");
                final ListPool listPool = ListPool.localPool();
                listPool.addListToPool(list);
                return;
            }
            log.warn("Warning -> From focus indicator error");
            return;
        }
        if (pointerPlace.equals(curFromPiece.getPlace())) {
            log.warn("false -> from == to");
            return;
        }
        // The current focus position has a piece and is its own piece
        if(pointerPiece ! =null && pointerPiece.piece.part == pointerPart) {
            assert curFromPiece.piece.part == pointerPart : "There's a piece in the current focus position and it's your piece that was pointing to the other piece.";
            / / update the curFromPiece
            curFromPiece = pointerPiece;
            traceMarker.setMarkFromPlace(pointerPlace);
            MyList<Place> list = curFromPiece.piece.role.find(new AnalysisBean(situation.generatePieces()), pointerPart, pointerPlace);
            traceMarker.showMarkPlace(list);
            ChessAudio.CLICK_FROM.play();
            log.info("True -> Update curFromPiece");
            ListPool.localPool().addListToPool(list);
            return;
        }
        final StepBean stepBean = StepBean.of(curFromPiece.getPlace(), pointerPlace);
        // Return if the rule is not met
        final Piece[][] pieces = situation.generatePieces();
        if(! curFromPiece.piece.role.rule.check(pieces, pointerPart, stepBean.from, stepBean.to)) {// If the current pointing to a piece is its own piece
            log.warn("Does not conform to the rules of chess.");
            return;
        }
        // If long block or long block is reached, return
        final StepBean forbidStepBean = situation.getForbidStepBean();
        if(forbidStepBean ! =null && forbidStepBean.from == stepBean.from && forbidStepBean.to == stepBean.to) {
            ChessAudio.MAN_MOV_ERROR.play();
            log.warn("Long stop or long catch.");
            return;
        }
        AnalysisBean analysisBean = new AnalysisBean(pieces);
        // If two bosses face each other after a move, return
        if(! analysisBean.isBossF2FAfterStep(curFromPiece.piece, stepBean.from, stepBean.to)) { ChessAudio.MAN_MOV_ERROR.play(); log.warn("BOSS to BOSS");
            return;
        }
        /* Simulate a move and then calculate if the opponent can take his boss */
        if (analysisBean.simulateOneStep(stepBean, bean -> bean.canEatBossAfterOneAiStep(Part.getOpposite(pointerPart)))) {
            ChessAudio.MAN_MOV_ERROR.play();
            log.warn("BOSS danger");
            if(! Application.config().isActiveWhenBeCheck()) {return; }}// The current checker has no checker or is the opponent's checker and conforms to the rules
        Object[] objects = new Object[]{stepBean.from, stepBean.to, PlayerType.PEOPLE};
        final boolean sendSuccess = Application.context().getCommandExecutor().sendCommandWhenNotRun(CommandExecutor.CommandType.LocationPiece, objects);
        if(! sendSuccess) { log.warn("Command not sent successfully: {} ==> {}", CommandExecutor.CommandType.LocationPiece, Arrays.toString(objects)); }}@Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Image img = ChessImage.CHESS_BOARD.getImage();
        int imgWidth = img.getWidth(this);
        int imgHeight = img.getHeight(this);// Get the width and height of the image
        int fWidth = getWidth();
        int fHeight = getHeight();// Get the window width and height
        int x = (fWidth - imgWidth) / 2;
        int y = (fHeight - imgHeight) / 2;
        // 520 576 514 567
        log.debug(String.format("%s,%s,%s,%s,%s,%s", imgWidth, imgHeight, fWidth, fHeight, x, y));
        g.drawImage(img, 0.0.null); }}Copy the code

Command executor, used to process commands in moves


@Slf4j
public class CommandExecutor {

    /** * asynchronously calls the thread to process the move command */
    private final CtrlLoopThreadComp ctrlLoopThreadComp;
    private final BoardPanel boardPanel;
    /** * Whether to run the flag */ continuously
    private volatile boolean sustain;

    public CommandExecutor(BoardPanel boardPanel) {
        this.boardPanel = boardPanel;
        this.ctrlLoopThreadComp = CtrlLoopThreadComp.ofRunnable(this::loop)
                .setName("CommandExecutor")
                .catchFun(CtrlLoopThreadComp.CATCH_FUNCTION_CONTINUE);
    }

    /** ** Next command */
    private CommandType nextCommand;
    /** * Parameters of the next command */
    private Object nextParamObj;

    private volatile boolean isRun;

    / * * *@paramCommandType commandType */
    public void sendCommand(@NonNull CommandType commandType) {
        sendCommand(commandType, null);
    }

    / * * *@paramCommandType commandType *@paramParamObj Command parameter */
    public synchronized void sendCommand(@NonNull CommandType commandType, Object paramObj) {
        this.nextCommand = commandType;
        this.nextParamObj = paramObj;
        sustain = false;
        this.ctrlLoopThreadComp.startOrWake();
    }

    /** ** Can only be added successfully if the thread is not running@paramCommandType commandType *@paramParamObj Command parameter *@returnWhether the file is successfully added */
    public synchronized boolean sendCommandWhenNotRun(@NonNull CommandType commandType, Object paramObj) {
        if (isRun) {
            return false;
        }
        sendCommand(commandType, paramObj);
        return true;
    }

    private void loop(a) {
        final CommandType command;
        final Object paramObj;
        synchronized (this) {
            command = this.nextCommand;
            paramObj = this.nextParamObj;
            this.nextCommand = null;
            this.nextParamObj = null;
        }
        if(command ! =null) {
            isRun = true;
            try {
                log.debug("Handle event [{}] start", command.getLabel());
                consumerCommand(command, paramObj);
                log.debug("Handle event [{}] end", command.getLabel());
            } catch (Exception e) {
                log.error("Exception occurred when executing command [{}]", command.getLabel(), e);
                newThread(() -> JOptionPane.showMessageDialog(boardPanel, e.getMessage(), e.toString(), JOptionPane.ERROR_MESSAGE)).start(); }}else {
            this.ctrlLoopThreadComp.pause();
            isRun = false; }}/** * run */
    private void consumerCommand(final CommandType commandType, Object paramObj) {
        switch (commandType) {
            case SuspendCallBackOrAiRun:
                break;
            case CallBackOneTime:
                Application.context().rollbackOneStep();
                break;
            case AiRunOneTime:
                if(Application.context().aiRunOneTime() ! =null) {
                    log.debug("The winner has been decided!");
                }
                break;
            case SustainCallBack:
                sustain = true;
                while (sustain) {
                    if(! Application.context().rollbackOneStep()) { sustain =false;
                        break;
                    }
                    Throws.con(Application.config().getComIntervalTime(), Thread::sleep).logThrowable();
                }
                break;
            case SustainAiRun:
                sustain = true;
                while (sustain) {
                    if(Application.context().aiRunOneTime() ! =null) {
                        log.debug("Winner has been determined, AI execution pause!");
                        sustain = false;
                        break;
                    }
                    Throws.con(Application.config().getComIntervalTime(), Thread::sleep).logThrowable();
                }
                break;
            case SustainAiRunIfNextIsAi:
                sustain = true;
                while (sustain) {
                    // If the next player is not AI, pause
                    if(! PlayerType.COM.equals(Application.config().getPlayerType(Application.context().getSituation().getNextPart()))) { sustain =false;
                        log.debug("Next player is not AI, pause!");
                    } else if(Application.context().aiRunOneTime() ! =null) {
                        log.debug("Winner has been determined, AI execution pause!");
                        sustain = false;
                    } else{ Throws.con(Application.config().getComIntervalTime(), Thread::sleep).logThrowable(); }}break;
            case LocationPiece:
                final Object[] params = (Object[]) paramObj;
                Place from = (Place) params[0];
                Place to = (Place) params[1];
                PlayerType type = (PlayerType) params[2];
                Application.context().locatePiece(from, to, type);
                sendCommand(CommandExecutor.CommandType.SustainAiRunIfNextIsAi);
                break;
            default:
                throw new ShouldNotHappenException("Unprocessed command:"+ commandType); }}/** * support enumeration (the following commands should be run on the same thread, with one event finished before another can be run.) * /
    @SuppressWarnings("java:S115")
    public enum CommandType {
        SuspendCallBackOrAiRun("Stop revoked | AI computing"),
        CallBackOneTime("Undo one step"),
        SustainCallBack("Continuous withdrawal"),
        AiRunOneTime("AI calculation in one step"),
        SustainAiRun("AI keeps running"),
        SustainAiRunIfNextIsAi("COM role run"),
        LocationPiece("UI drop sub command");

        @Getter
        private final String label;

        CommandType(String label) {
            this.label = label; }}}Copy the code

The core algorithm



@NoArgsConstructor(access = AccessLevel.PRIVATE)
@Slf4j
public class AlphaBeta {

    private static final int MAX = 100 _000_000;
    /** * ensure that Min + Max = 0, even a slight difference can cause errors */
    private static final int MIN = -MAX;

    /** * Dynamically adjust the search depth according to the number of pieces **@paramPieceNum Number of pieces *@returnAdjust the search depth difference */
    public static int searchDeepSuit(final int pieceNum) {
        // Dynamically adjust the search depth according to the number of pieces
        if (pieceNum > 20) {
            return -2;
        } else if (pieceNum <= 4) {
            return 4;
        } else if (pieceNum <= 8) {
            return 2;
        }
        return 0;
    }

    /** * generates a list of options, which are available below, and sorts the search results if deep > 2. **@paramAnalysisBean Checkerboard analysis object *@paramCurPart The current move *@paramDeep Search depth *@returnThe set of available vacancies */
    private static MyList<StepBean> geneNestStepPlaces(final AnalysisBean analysisBean, final Part curPart, final int deep) {
        final Piece[][] pieces = analysisBean.pieces;
        // Whether to kill chess
        MyList<StepBean> stepBeanList = ListPool.localPool().getAStepBeanList();
        for (int x = 0; x < ChessDefined.RANGE_X; x++) {
            for (int y = 0; y < ChessDefined.RANGE_Y; y++) {
                final Piece fromPiece = pieces[x][y];
                if(fromPiece ! =null && fromPiece.part == curPart) {
                    final Place from = Place.of(x, y);
                    // TO DO consider whether there is room for optimization when calculating the method added TO the collection here.
                    final MyList<Place> list = fromPiece.role.find(analysisBean, curPart, from);
                    if (list.isEmpty()) {
                        ListPool.localPool().addListToPool(list);
                        continue;
                    }
                    final Object[] elementData = list.eleTemplateDate();
                    for (int i = 0, len = list.size(); i < len; i++) { stepBeanList.add(StepBean.of(from, (Place) elementData[i])); } ListPool.localPool().addListToPool(list); }}}If the search depth is greater than 2, the results are sorted
        // The sorted result is easily pruned when entering the minimax search algorithm.
        if (deep > 2) {
            orderStep(analysisBean, stepBeanList, curPart);
        }

        return stepBeanList;
    }

    /** * Sort the vacancy list. The sorted vacancy list is easy to prune when entering the minimax search algorithm. **@paramAnalysisBean Checkerboard analysis object *@paramStepBeanList List of vacancies that can be sublisted *@paramCurPart Current move */
    private static void orderStep(final AnalysisBean analysisBean, final MyList<StepBean> stepBeanList, final Part curPart) {
        final Piece[][] srcPieces = analysisBean.pieces;
        // Count the constants used in the loop before entering the loop
        MyList<DoubleBean<Integer, StepBean>> bestPlace = ListPool.localPool().getADoubleBeanList();
        // Opposing player
        final Part oppositeCurPart = Part.getOpposite(curPart);
        int best = MIN;

        final Object[] objects = stepBeanList.eleTemplateDate();
        for (int i = 0; i < stepBeanList.size(); i++) {
            final StepBean item = (StepBean) objects[i];
            final Place to = item.to;
            / / backup
            final Piece eatenPiece = srcPieces[to.x][to.y];
            int score;
            // Determine victory
            if(eatenPiece ! =null && eatenPiece.role == Role.BOSS) {
                score = MAX;
            } else {
                / / playing chess
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                DebugInfo.incrementAlphaBetaOrderTime();
                / / score
                score = negativeMaximumWithNoCut(analysisBean, oppositeCurPart, -best);
                // Take a step back
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            // Add all the scores here
            bestPlace.add(new DoubleBean<>(score, item));
            if (score > best) { // If you find a better score, delete all the seats saved beforebest = score; }}/* Returns */ after sorting
        // This sort is correct and can effectively reduce the number
        bestPlace.sort((o1, o2) -> o2.getO1() - o1.getO1());

        stepBeanList.clear();
        bestPlace.forEach(dou -> stepBeanList.add(dou.getO2()));

        ListPool.localPool().addListToDoubleBeanListPool(bestPlace);
    }


    /** * Negative maximum search algorithm (without pruning algorithm) **@paramAnalysisBean situation analysis object *@paramCurPart The current move *@returnThe negative maximum search algorithm calculates the score */
    private static int negativeMaximumWithNoCut(AnalysisBean analysisBean, Part curPart, int alphaBeta) {
        // 1. Initialize each variable
        final Piece[][] pieces = analysisBean.pieces;
        int best = MIN;
        // 2. Generate a list to be selected
        MyList<StepBean> stepBeanList = geneNestStepPlaces(analysisBean, curPart, 1);

        final Object[] objects = stepBeanList.eleTemplateDate();
        for (int i = 0, len = stepBeanList.size(); i < len; i++) {
            final StepBean item = (StepBean) objects[i];
            Place from = item.from;
            Place to = item.to;
            / / backup
            Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // Determine victory
            if(eatenPiece ! =null && eatenPiece.role == Role.BOSS) {
                score = MAX;
            } else {
                / / playing chess
                final int invScr = analysisBean.goForward(from, to, eatenPiece);
                DebugInfo.incrementAlphaBetaOrderTime();
                score = analysisBean.getCurPartEvaluateScore(curPart);
                // Take a step back
                analysisBean.backStep(from, to, eatenPiece, invScr);
            }
            if (score > best) { // Find a better score, update the score
                best = score;
            }
            if (score > alphaBeta) { / / alpha pruning
                break;
            }
        }
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return -best;
    }


    /** * The odd-numbered layer is computer (Max layer)thisSide, and the even-numbered layer is human(min layer)otherSide **@paramSrcPieces board *@paramCurPart The current move *@paramDeep Search depth *@paramForbidStep Prohibited step (long catch or long block) *@returnNext position */
    public static Set<StepBean> getEvaluatedPlace(final Piece[][] srcPieces, final Part curPart, final int deep, final StepBean forbidStep) {
        // 1. Initialize each variable
        final AnalysisBean analysisBean = new AnalysisBean(srcPieces);
        // 2. Get the list of available vacancies
        MyList<StepBean> stepBeanList = geneNestStepPlaces(analysisBean, curPart, deep);
        // 3
        stepBeanList.remove(forbidStep);
        // Count the constants used in the loop before entering the loop
        Set<StepBean> bestPlace = new HashSet<>();
        int best = MIN;
        // Opposing player
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // Next depth
        final int nextDeep = deep - 1;
        log.debug("size : {}, content: {}", stepBeanList.size(), stepBeanList);
        final Object[] objects = stepBeanList.eleTemplateDate();
        for (int i = 0, len = stepBeanList.size(); i < len; i++) {
            StepBean item = (StepBean) objects[i];
            final Place to = item.to;
            / / backup
            final Piece eatenPiece = srcPieces[to.x][to.y];
            int score;
            // Determine victory
            if(eatenPiece ! =null && eatenPiece.role == Role.BOSS) {
                // The fewer steps, the higher the score
                score = MAX + deep;
            } else {
                / / playing chess
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                / / score
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best);
                }
                // Take a step back
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            if (score == best) { // Find the same score, add this step
                bestPlace.add(item);
            }
            if (score > best) { // If you find a better score, delete all the seats saved before
                best = score;
                bestPlace.clear();
                bestPlace.add(item);
            }
        }
        ListPool.end();
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return bestPlace;
    }

    /** * The odd-numbered layer is computer (Max layer)thisSide, and the even-numbered layer is human(min layer)otherSide **@paramSrcPieces board *@paramCurPart The current move *@paramDeep Search depth *@paramForbidStep Prohibited step (long catch or long block) *@returnNext position */
    public static Set<StepBean> getEvaluatedPlaceWithParallel(final Piece[][] srcPieces, final Part curPart, final int deep, final StepBean forbidStep) {
        // 1. Initialize each variable
        final AnalysisBean srcAnalysisBean = new AnalysisBean(srcPieces);
        // 2. Get the list of available vacancies
        MyList<StepBean> stepBeanList = geneNestStepPlaces(srcAnalysisBean, curPart, deep);
        // 3
        stepBeanList.remove(forbidStep);
        // Count the constants used in the loop before entering the loop
        final Set<StepBean> bestPlace = new HashSet<>();
        final AtomicInteger best = new AtomicInteger(MIN);
        // Opposing player
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // Next depth
        final int nextDeep = deep - 1;
        log.debug("size : {}, content: {}", stepBeanList.size(), stepBeanList);

        Arrays.stream(stepBeanList.toArray()).parallel().filter(Objects::nonNull).map(StepBean.class::cast).forEach(item -> {
            log.debug("Parallel streams ==> Thread: {}", Thread.currentThread().getId());
            final Piece[][] pieces = ArrayUtils.deepClone(srcPieces);
            final AnalysisBean analysisBean = new AnalysisBean(pieces);

            final Place to = item.to;
            / / backup
            final Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // Determine victory
            if(eatenPiece ! =null && eatenPiece.role == Role.BOSS) {
                // The fewer steps, the higher the score
                score = MAX + deep;
            } else {
                / / playing chess
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                / / score
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best.get());
                }
                // Take a step back
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            if (score == best.get()) { // Find the same score, add this step
                synchronized(bestPlace) { bestPlace.add(item); }}if (score > best.get()) { // If you find a better score, delete all the seats saved before
                best.set(score);
                synchronized (bestPlace) {
                    bestPlace.clear();
                    bestPlace.add(item);
                }
            }
            ListPool.end();
        });
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        ListPool.end();
        return bestPlace;
    }


    /** * Negative maximum search algorithm **@paramAnalysisBean situation analysis object *@paramCurPart The current move *@paramDeep Search depth *@paramAlphaBeta Pruning score *@returnThe negative maximum search algorithm calculates the score */
    private static int negativeMaximum(AnalysisBean analysisBean, Part curPart, int deep, int alphaBeta) {
        // 1. Initialize each variable
        final Piece[][] pieces = analysisBean.pieces;
        int best = MIN;
        // Opposing player
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // Next depth
        final int nextDeep = deep - 1;
        // 2. Generate a list to be selected
        final MyList<StepBean> stepBeanList = geneNestStepPlaces(analysisBean, curPart, deep);

        final Object[] objects = stepBeanList.eleTemplateDate();
        for (int i = 0, len = stepBeanList.size(); i < len; i++) {
            final StepBean item = (StepBean) objects[i];
            Place from = item.from;
            Place to = item.to;
            / / backup
            Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // Determine victory
            if(eatenPiece ! =null && eatenPiece.role == Role.BOSS) {
                // The fewer steps, the higher the score
                score = MAX + deep;
            } else {
                / / playing chess
                final int invScr = analysisBean.goForward(from, to, eatenPiece);
                / / evaluation
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best);
                }
                // Take a step back
                analysisBean.backStep(from, to, eatenPiece, invScr);
            }
            if (score > best) { // Find a better score, update the score
                best = score;
            }
            if (score > alphaBeta) { / / alpha pruning
                break;
            }
        }
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return-best; }}Copy the code

conclusion

Through the implementation of the game “Chinese Chess”, LET me have a further understanding of the relevant knowledge of Swing, the Language of Java has a deeper understanding than before.

Basic Java syntax, such as data types, operators, program flow control, and arrays, is better understood. Java is the core of the core object oriented thought, for this concept, finally realized some.

The source code for

Can pay attention to the blogger, private chat blogger free access