欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java實(shí)現(xiàn)中國(guó)象棋的示例代碼

 更新時(shí)間:2022年02月07日 10:41:17   作者:小虛竹and掘金  
中國(guó)象棋是起源于中國(guó)的一種棋,屬于二人對(duì)抗性游戲的一種,在中國(guó)有著悠久的歷史。由于用具簡(jiǎn)單,趣味性強(qiáng),成為流行極為廣泛的棋藝活動(dòng)。本文將利用Java實(shí)現(xiàn)這一經(jīng)典游戲,需要的可以參考一下

前言

中國(guó)象棋是起源于中國(guó)的一種棋,屬于二人對(duì)抗性游戲的一種,在中國(guó)有著悠久的歷史。由于用具簡(jiǎn)單,趣味性強(qiáng),成為流行極為廣泛的棋藝活動(dòng)。

中國(guó)象棋使用方形格狀棋盤,圓形棋子共有32個(gè),紅黑二色各有16個(gè)棋子,擺放和活動(dòng)在交叉點(diǎn)上。雙方交替行棋,先把對(duì)方的將(帥)“將死”的一方獲勝。

中國(guó)象棋是一款具有濃郁中國(guó)特色的益智游戲,新增的聯(lián)網(wǎng)對(duì)戰(zhàn),趣味多多,聚會(huì)可以約小朋友一起來挑戰(zhàn)。精彩的對(duì)弈讓你感受中國(guó)象棋的博大精深。

《中國(guó)象棋》游戲是用java語言實(shí)現(xiàn),采用了swing技術(shù)進(jìn)行了界面化處理,設(shè)計(jì)思路用了面向?qū)ο笏枷搿? 人機(jī)對(duì)弈基于極大極小值搜索算法。

主要需求

按照中國(guó)象棋的規(guī)則,實(shí)現(xiàn)紅黑棋對(duì)戰(zhàn),要有AI對(duì)手,可以玩家跟AI的對(duì)弈,也可以兩個(gè)玩家自己玩。

主要設(shè)計(jì)

1、尋找棋盤界面和對(duì)應(yīng)的棋子圖片,程序設(shè)計(jì)棋盤界面和功能菜單

2、設(shè)計(jì)不同的棋子的移動(dòng)邏輯

3、棋子移動(dòng)時(shí),要有音效

4、設(shè)計(jì)對(duì)手AI的邏輯算法,這里運(yùn)用了極大極小值搜索算法,設(shè)置不同的搜索深度AI(智能不同)

5、對(duì)局開始前,雙方棋子在棋盤上的擺法。

6、對(duì)局時(shí),由執(zhí)紅棋的一方先走,雙方輪流走一步。

7、輪到走棋的一方,將某個(gè)棋子從一個(gè)交叉點(diǎn)走到另一個(gè)交叉點(diǎn),或者吃掉對(duì)方的棋子而占領(lǐng)其交叉點(diǎn),都算走了一著。

8、雙方各走一著,稱為一個(gè)回合。

9、走一著棋時(shí),如果己方棋子能夠走到的位置有對(duì)方棋子存在,就可以把對(duì)方棋子吃掉而占領(lǐng)那個(gè)位置。

10、一方的棋子攻擊對(duì)方的帥(將),并在下一著要把它吃掉,稱為“照將”,或簡(jiǎn)稱“將”。“照將”不必聲明。被“照將”的一方必須立即“應(yīng)將”,即用自己的著法去化解被“將”的狀態(tài)。如果被“照將”而無法“應(yīng)將”,就算被“將死”。

11、特別設(shè)計(jì)了人機(jī)對(duì)弈,人人對(duì)弈,還有AI對(duì)AI對(duì)弈

功能截圖

游戲開始

游戲菜單設(shè)置

移動(dòng)效果

代碼實(shí)現(xiàn)

棋盤面板設(shè)計(jì)

@Slf4j
public class BoardPanel extends JPanel implements LambdaMouseListener {

    /**
     * 用于標(biāo)記棋盤走棋痕跡
     */
    private final transient TraceMarker traceMarker;
    /**
     * 當(dāng)前走棋開始坐標(biāo)位置對(duì)應(yīng)棋子
     */
    private transient ChessPiece curFromPiece;
    /**
     * 場(chǎng)景
     */
    private transient Situation situation;

    /**
     * Create the panel.
     */
    public BoardPanel() {
        setBorder(new EmptyBorder(5, 5, 5, 5));
        setLayout(null);
        // 初始化標(biāo)記符
        traceMarker = new TraceMarker(BoardPanel.this);
        // 添加鼠標(biāo)事件
        addMouseListener(this);
    }

    /**
     * 更新標(biāo)記
     */
    public void updateMark(Place from, Place to) {
        // 更新標(biāo)記
        curFromPiece = null;
        // 更改標(biāo)記
        traceMarker.endedStep(from, to);
    }

    /**
     * 初始化所有標(biāo)記
     */
    public void initMark() {
        traceMarker.initMarker();
    }

    /**
     * 添加棋子
     */
    public void init(Situation situation) {
        this.situation = situation;
        // 移除所有組件
        this.removeAll();
        // 添加棋子
        situation.getPieceList().forEach(it -> add(it.getComp()));
        situation.getSituationRecord().getEatenPieceList().forEach(it -> add(it.getComp()));
        // 初始化標(biāo)記符
        traceMarker.initMarker();
        repaint();
    }

    /**
     * @param e 鼠標(biāo)按壓事件對(duì)象
     */
    @Override
    public void mouseReleased(MouseEvent e) {
        // 位置
        Place pointerPlace = ChessDefined.convertLocationToPlace(e.getPoint());
        if (pointerPlace == null) {
            return;
        }
        if (situation.winner() != null) {
            log.warn("已經(jīng)存在勝利者: {}, 無法走棋", situation.winner());
            return;
        }
        // 當(dāng)前走棋方
        @NonNull Part pointerPart = situation.getNextPart();
        // 當(dāng)前焦點(diǎn)棋子
        ChessPiece pointerPiece = situation.getChessPiece(pointerPlace);
        // 通過當(dāng)前方和當(dāng)前位置判斷是否可以走棋
        // step: form
        if (curFromPiece == null) {
            // 當(dāng)前焦點(diǎn)位置有棋子且是本方棋子
            if (pointerPiece != null && pointerPiece.piece.part == pointerPart) {
                // 本方棋子, 同時(shí)是from指向
                curFromPiece = pointerPiece;
                traceMarker.setMarkFromPlace(pointerPlace);
                // 獲取toList
                MyList<Place> list = curFromPiece.piece.role.find(new AnalysisBean(situation.generatePieces()), pointerPart, pointerPlace);
                traceMarker.showMarkPlace(list);
                ChessAudio.CLICK_FROM.play();
                log.info("true -> 當(dāng)前焦點(diǎn)位置有棋子且是本方棋子");
                final ListPool listPool = ListPool.localPool();
                listPool.addListToPool(list);
                return;
            }
            log.warn("warning -> from 焦點(diǎn)指示錯(cuò)誤");
            return;
        }
        if (pointerPlace.equals(curFromPiece.getPlace())) {
            log.warn("false -> from == to");
            return;
        }
        // 當(dāng)前焦點(diǎn)位置有棋子且是本方棋子
        if (pointerPiece != null && pointerPiece.piece.part == pointerPart) {
            assert curFromPiece.piece.part == pointerPart : "當(dāng)前焦點(diǎn)位置有棋子且是本方棋子 之前指向了對(duì)方棋子";
            // 更新 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 -> 更新 curFromPiece");
            ListPool.localPool().addListToPool(list);
            return;
        }
        final StepBean stepBean = StepBean.of(curFromPiece.getPlace(), pointerPlace);
        // 如果不符合規(guī)則則直接返回
        final Piece[][] pieces = situation.generatePieces();
        if (!curFromPiece.piece.role.rule.check(pieces, pointerPart, stepBean.from, stepBean.to)) {
            // 如果當(dāng)前指向棋子是本方棋子
            log.warn("不符合走棋規(guī)則");
            return;
        }
        // 如果達(dá)成長(zhǎng)攔或者長(zhǎng)捉, 則返回
        final StepBean forbidStepBean = situation.getForbidStepBean();
        if (forbidStepBean != null && forbidStepBean.from == stepBean.from && forbidStepBean.to == stepBean.to) {
            ChessAudio.MAN_MOV_ERROR.play();
            log.warn("長(zhǎng)攔或長(zhǎng)捉");
            return;
        }
        AnalysisBean analysisBean = new AnalysisBean(pieces);
        // 如果走棋后, 導(dǎo)致兩個(gè) BOSS 對(duì)面, 則返回
        if (!analysisBean.isBossF2FAfterStep(curFromPiece.piece, stepBean.from, stepBean.to)) {
            ChessAudio.MAN_MOV_ERROR.play();
            log.warn("BOSS面對(duì)面");
            return;
        }
        /* 模擬走一步棋, 之后再計(jì)算對(duì)方再走一步是否能夠吃掉本方的 boss */
        if (analysisBean.simulateOneStep(stepBean, bean -> bean.canEatBossAfterOneAiStep(Part.getOpposite(pointerPart)))) {
            ChessAudio.MAN_MOV_ERROR.play();
            log.warn("BOSS 危險(xiǎn)");
            if (!Application.config().isActiveWhenBeCheck()) {
                return;
            }
        }
        // 當(dāng)前棋子無棋子或者為對(duì)方棋子, 且符合規(guī)則, 可以走棋
        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("命令未發(fā)送成功: {} ==> {}", 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);// 獲得圖片的寬度與高度
        int fWidth = getWidth();
        int fHeight = getHeight();// 獲得窗口的寬度與高度
        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);
    }

}

命令執(zhí)行器, 用于處理走棋中的命令

@Slf4j
public class CommandExecutor {

    /**
     * 異步調(diào)用線程, 來處理走棋命令
     */
    private final CtrlLoopThreadComp ctrlLoopThreadComp;
    private final BoardPanel boardPanel;
    /**
     * 是否持續(xù)運(yùn)行標(biāo)記
     */
    private volatile boolean sustain;

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

    /**
     * 下一步驟命令
     */
    private CommandType nextCommand;
    /**
     * 下一步驟命令的參數(shù)
     */
    private Object nextParamObj;

    private volatile boolean isRun;

    /**
     * @param commandType 命令類型
     */
    public void sendCommand(@NonNull CommandType commandType) {
        sendCommand(commandType, null);
    }

    /**
     * @param commandType 命令類型
     * @param paramObj    命令參數(shù)
     */
    public synchronized void sendCommand(@NonNull CommandType commandType, Object paramObj) {
        this.nextCommand = commandType;
        this.nextParamObj = paramObj;
        sustain = false;
        this.ctrlLoopThreadComp.startOrWake();
    }

    /**
     * 只有在 線程沒有運(yùn)行的情況下, 才能添加成功
     *
     * @param commandType 命令類型
     * @param paramObj    命令參數(shù)
     * @return 是否添加成功
     */
    public synchronized boolean sendCommandWhenNotRun(@NonNull CommandType commandType, Object paramObj) {
        if (isRun) {
            return false;
        }
        sendCommand(commandType, paramObj);
        return true;
    }

    private void loop() {
        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("處理事件[{}] start", command.getLabel());
                consumerCommand(command, paramObj);
                log.debug("處理事件[{}] end ", command.getLabel());
            } catch (Exception e) {
                log.error("執(zhí)行命令[{}]發(fā)生異常", command.getLabel(), e);
                new Thread(() -> JOptionPane.showMessageDialog(boardPanel, e.getMessage(), e.toString(), JOptionPane.ERROR_MESSAGE)).start();
            }
        } else {
            this.ctrlLoopThreadComp.pause();
            isRun = false;
        }
    }

    /**
     * 運(yùn)行
     */
    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("已經(jīng)決出勝方!");
                }
                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("已經(jīng)決出勝方, AI執(zhí)行暫停!");
                        sustain = false;
                        break;
                    }
                    Throws.con(Application.config().getComIntervalTime(), Thread::sleep).logThrowable();
                }
                break;
            case SustainAiRunIfNextIsAi:
                sustain = true;
                while (sustain) {
                    // 如果下一步棋手不是 AI, 則暫停
                    if (!PlayerType.COM.equals(Application.config().getPlayerType(Application.context().getSituation().getNextPart()))) {
                        sustain = false;
                        log.debug("下一步棋手不是 AI, 暫停!");
                    } else if (Application.context().aiRunOneTime() != null) {
                        log.debug("已經(jīng)決出勝方, AI執(zhí)行暫停!");
                        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("未處理的命令: " + commandType);
        }
    }

    /**
     * 命令支持枚舉(以下命令應(yīng)當(dāng)使用同一個(gè)線程運(yùn)行, 一個(gè)事件結(jié)束之后, 另一個(gè)事件才能開始運(yùn)行.)
     */
    @SuppressWarnings("java:S115")
    public enum CommandType {
        SuspendCallBackOrAiRun("停止撤銷|AI計(jì)算"),
        CallBackOneTime("撤銷一步"),
        SustainCallBack("持續(xù)撤銷"),
        AiRunOneTime("AI計(jì)算一步"),
        SustainAiRun("AI持續(xù)運(yùn)行"),
        SustainAiRunIfNextIsAi("COM角色運(yùn)行"),
        LocationPiece("ui落子命令");

        @Getter
        private final String label;

        CommandType(String label) {
            this.label = label;
        }
    }

}

核心算法


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

    private static final int MAX = 100_000_000;
    /**
     * 這里要保證 Min + Max = 0, 哪怕是微不足道的差距都可能導(dǎo)致發(fā)生錯(cuò)誤
     */
    private static final int MIN = -MAX;

    /**
     * 根據(jù)棋子數(shù)量, 動(dòng)態(tài)調(diào)整搜索深度
     *
     * @param pieceNum 棋子數(shù)量
     * @return 調(diào)整搜索深度差值
     */
    public static int searchDeepSuit(final int pieceNum) {
        // 根據(jù)棋子數(shù)量, 動(dòng)態(tài)調(diào)整搜索深度
        if (pieceNum > 20) {
            return -2;
        } else if (pieceNum <= 4) {
            return 4;
        } else if (pieceNum <= 8) {
            return 2;
        }
        return 0;
    }

    /**
     * 生成待選的列表,就是可以下子的空位, 如果 deep > 2 則對(duì)搜索結(jié)果進(jìn)行排序.
     *
     * @param analysisBean 棋盤分析對(duì)象
     * @param curPart      當(dāng)前走棋方
     * @param deep         搜索深度
     * @return 可以下子的空位集合
     */
    private static MyList<StepBean> geneNestStepPlaces(final AnalysisBean analysisBean, final Part curPart, final int deep) {
        final Piece[][] pieces = analysisBean.pieces;
        // 是否殺棋
        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 考慮下此處添加至集合的做法 在計(jì)算時(shí) 是否有優(yōu)化空間.
                    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);
                }
            }
        }
        // 是否排序, 如果搜索深度大于2, 則對(duì)結(jié)果進(jìn)行排序
        // 排序后的結(jié)果, 進(jìn)入極大極小值搜索算法時(shí), 容易被剪枝.
        if (deep > 2) {
            orderStep(analysisBean, stepBeanList, curPart);
        }

        return stepBeanList;
    }

    /**
     * 對(duì) 空位列表 進(jìn)行排序, 排序后的空位列表, 進(jìn)入極大極小值搜索算法時(shí), 容易被剪枝.
     *
     * @param analysisBean 棋盤分析對(duì)象
     * @param stepBeanList 可以下子的空位列表
     * @param curPart      當(dāng)前走棋方
     */
    private static void orderStep(final AnalysisBean analysisBean, final MyList<StepBean> stepBeanList, final Part curPart) {
        final Piece[][] srcPieces = analysisBean.pieces;
        // 進(jìn)入循環(huán)之前計(jì)算好循環(huán)內(nèi)使用常量
        MyList<DoubleBean<Integer, StepBean>> bestPlace = ListPool.localPool().getADoubleBeanList();
        // 對(duì)方棋手
        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;
            // 備份
            final Piece eatenPiece = srcPieces[to.x][to.y];
            int score;
            // 判斷是否勝利
            if (eatenPiece != null && eatenPiece.role == Role.BOSS) {
                score = MAX;
            } else {
                // 走棋
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                DebugInfo.incrementAlphaBetaOrderTime();
                // 評(píng)分
                score = negativeMaximumWithNoCut(analysisBean, oppositeCurPart, -best);
                // 退回上一步
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            // 這里添加進(jìn)所有的分?jǐn)?shù)
            bestPlace.add(new DoubleBean<>(score, item));
            if (score > best) { // 找到一個(gè)更好的分,就把以前存的位子全部清除
                best = score;
            }
        }
        /* 排序后返回 */
        // 這樣排序是正確的, 可以有效消減數(shù)量
        bestPlace.sort((o1, o2) -> o2.getO1() - o1.getO1());

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

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


    /**
     * 負(fù)極大值搜索算法(不帶剪枝算法)
     *
     * @param analysisBean 局勢(shì)分析對(duì)象
     * @param curPart      當(dāng)前走棋方
     * @return 負(fù)極大值搜索算法計(jì)算分值
     */
    private static int negativeMaximumWithNoCut(AnalysisBean analysisBean, Part curPart, int alphaBeta) {
        // 1. 初始化各個(gè)變量
        final Piece[][] pieces = analysisBean.pieces;
        int best = MIN;
        // 2. 生成待選的列表,就是可以下子的列表
        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;
            // 備份
            Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // 判斷是否勝利
            if (eatenPiece != null && eatenPiece.role == Role.BOSS) {
                score = MAX;
            } else {
                // 走棋
                final int invScr = analysisBean.goForward(from, to, eatenPiece);
                DebugInfo.incrementAlphaBetaOrderTime();
                score = analysisBean.getCurPartEvaluateScore(curPart);
                // 退回上一步
                analysisBean.backStep(from, to, eatenPiece, invScr);
            }
            if (score > best) { // 找到一個(gè)更好的分,就更新分?jǐn)?shù)
                best = score;
            }
            if (score > alphaBeta) { // alpha剪枝
                break;
            }
        }
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return -best;
    }


    /**
     * 奇數(shù)層是電腦(max層)thisSide, 偶數(shù)層是human(min層)otherSide
     *
     * @param srcPieces 棋盤
     * @param curPart   當(dāng)前走棋方
     * @param deep      搜索深度
     * @param forbidStep 禁止的步驟(長(zhǎng)捉或長(zhǎng)攔)
     * @return 下一步的位置
     */
    public static Set<StepBean> getEvaluatedPlace(final Piece[][] srcPieces, final Part curPart, final int deep, final StepBean forbidStep) {
        // 1. 初始化各個(gè)變量
        final AnalysisBean analysisBean = new AnalysisBean(srcPieces);
        // 2. 獲取可以下子的空位列表
        MyList<StepBean> stepBeanList = geneNestStepPlaces(analysisBean, curPart, deep);
        // 3. 移除不該下的子
        stepBeanList.remove(forbidStep);
        // 進(jìn)入循環(huán)之前計(jì)算好循環(huán)內(nèi)使用常量
        Set<StepBean> bestPlace = new HashSet<>();
        int best = MIN;
        // 對(duì)方棋手
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // 下一深度
        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;
            // 備份
            final Piece eatenPiece = srcPieces[to.x][to.y];
            int score;
            // 判斷是否勝利
            if (eatenPiece != null && eatenPiece.role == Role.BOSS) {
                // 步數(shù)越少, 分值越大
                score = MAX + deep;
            } else {
                // 走棋
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                // 評(píng)分
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best);
                }
                // 退回上一步
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            if (score == best) { // 找到相同的分?jǐn)?shù), 就添加這一步
                bestPlace.add(item);
            }
            if (score > best) { // 找到一個(gè)更好的分,就把以前存的位子全部清除
                best = score;
                bestPlace.clear();
                bestPlace.add(item);
            }
        }
        ListPool.end();
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return bestPlace;
    }

    /**
     * 奇數(shù)層是電腦(max層)thisSide, 偶數(shù)層是human(min層)otherSide
     *
     * @param srcPieces 棋盤
     * @param curPart   當(dāng)前走棋方
     * @param deep      搜索深度
     * @param forbidStep 禁止的步驟(長(zhǎng)捉或長(zhǎng)攔)
     * @return 下一步的位置
     */
    public static Set<StepBean> getEvaluatedPlaceWithParallel(final Piece[][] srcPieces, final Part curPart, final int deep, final StepBean forbidStep) {
        // 1. 初始化各個(gè)變量
        final AnalysisBean srcAnalysisBean = new AnalysisBean(srcPieces);
        // 2. 獲取可以下子的空位列表
        MyList<StepBean> stepBeanList = geneNestStepPlaces(srcAnalysisBean, curPart, deep);
        // 3. 移除不該下的子
        stepBeanList.remove(forbidStep);
        // 進(jìn)入循環(huán)之前計(jì)算好循環(huán)內(nèi)使用常量
        final Set<StepBean> bestPlace = new HashSet<>();
        final AtomicInteger best = new AtomicInteger(MIN);
        // 對(duì)方棋手
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // 下一深度
        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("并行流 ==> Thread : {}", Thread.currentThread().getId());
            final Piece[][] pieces = ArrayUtils.deepClone(srcPieces);
            final AnalysisBean analysisBean = new AnalysisBean(pieces);

            final Place to = item.to;
            // 備份
            final Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // 判斷是否勝利
            if (eatenPiece != null && eatenPiece.role == Role.BOSS) {
                // 步數(shù)越少, 分值越大
                score = MAX + deep;
            } else {
                // 走棋
                final int invScr = analysisBean.goForward(item.from, to, eatenPiece);
                // 評(píng)分
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best.get());
                }
                // 退回上一步
                analysisBean.backStep(item.from, to, eatenPiece, invScr);
            }
            if (score == best.get()) { // 找到相同的分?jǐn)?shù), 就添加這一步
                synchronized (bestPlace) {
                    bestPlace.add(item);
                }
            }
            if (score > best.get()) { // 找到一個(gè)更好的分,就把以前存的位子全部清除
                best.set(score);
                synchronized (bestPlace) {
                    bestPlace.clear();
                    bestPlace.add(item);
                }
            }
            ListPool.end();
        });
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        ListPool.end();
        return bestPlace;
    }


    /**
     * 負(fù)極大值搜索算法
     *
     * @param analysisBean 局勢(shì)分析對(duì)象
     * @param curPart      當(dāng)前走棋方
     * @param deep         搜索深度
     * @param alphaBeta    alphaBeta 剪枝分值
     * @return 負(fù)極大值搜索算法計(jì)算分值
     */
    private static int negativeMaximum(AnalysisBean analysisBean, Part curPart, int deep, int alphaBeta) {
        // 1. 初始化各個(gè)變量
        final Piece[][] pieces = analysisBean.pieces;
        int best = MIN;
        // 對(duì)方棋手
        final Part oppositeCurPart = Part.getOpposite(curPart);
        // 下一深度
        final int nextDeep = deep - 1;
        // 2. 生成待選的列表,就是可以下子的列表
        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;
            // 備份
            Piece eatenPiece = pieces[to.x][to.y];
            int score;
            // 判斷是否勝利
            if (eatenPiece != null && eatenPiece.role == Role.BOSS) {
                // 步數(shù)越少, 分值越大
                score = MAX + deep;
            } else {
                // 走棋
                final int invScr = analysisBean.goForward(from, to, eatenPiece);
                // 評(píng)估
                if (deep <= 1) {
                    score = analysisBean.getCurPartEvaluateScore(curPart);
                } else {
                    score = negativeMaximum(analysisBean, oppositeCurPart, nextDeep, -best);
                }
                // 退回上一步
                analysisBean.backStep(from, to, eatenPiece, invScr);
            }
            if (score > best) { // 找到一個(gè)更好的分,就更新分?jǐn)?shù)
                best = score;
            }
            if (score > alphaBeta) { // alpha剪枝
                break;
            }
        }
        ListPool.localPool().addListToStepBeanListPool(stepBeanList);
        return -best;
    }

}

總結(jié)

通過此次的《中國(guó)象棋》游戲?qū)崿F(xiàn),讓我對(duì)swing的相關(guān)知識(shí)有了進(jìn)一步的了解,對(duì)java這門語言也有了比以前更深刻的認(rèn)識(shí)。

java的一些基本語法,比如數(shù)據(jù)類型、運(yùn)算符、程序流程控制和數(shù)組等,理解更加透徹。java最核心的核心就是面向?qū)ο笏枷耄瑢?duì)于這一個(gè)概念,終于悟到了一些。

到此這篇關(guān)于Java實(shí)現(xiàn)中國(guó)象棋的示例代碼的文章就介紹到這了,更多相關(guān)Java中國(guó)象棋內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springcloud安裝rabbitmq并配置延遲隊(duì)列插件的過程詳解

    springcloud安裝rabbitmq并配置延遲隊(duì)列插件的過程詳解

    本期主要講解如何利用docker快速安裝rabbitmq并且配置延遲隊(duì)列插件,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • Java詳細(xì)分析講解HashMap

    Java詳細(xì)分析講解HashMap

    在java開發(fā)中,HashMap是最常用、最常見的集合容器類之一,下面一起溫故一下,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 詳解MyBatis工作原理

    詳解MyBatis工作原理

    近來想寫一個(gè)mybatis的分頁(yè)插件,但是在寫插件之前肯定要了解一下mybatis具體的工作原理吧,本文就詳細(xì)總結(jié)了MyBatis工作原理,,需要的朋友可以參考下
    2021-05-05
  • springboot中EasyPoi實(shí)現(xiàn)自動(dòng)新增序號(hào)的方法

    springboot中EasyPoi實(shí)現(xiàn)自動(dòng)新增序號(hào)的方法

    本文主要介紹了EasyPoi實(shí)現(xiàn)自動(dòng)新增序號(hào),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Java隨機(jī)數(shù)的5種獲得方法(非常詳細(xì)!)

    Java隨機(jī)數(shù)的5種獲得方法(非常詳細(xì)!)

    這篇文章主要給大家介紹了關(guān)于Java隨機(jī)數(shù)的5種獲得方法,在實(shí)際開發(fā)中產(chǎn)生隨機(jī)數(shù)的使用是很普遍的,所以在程序中進(jìn)行產(chǎn)生隨機(jī)數(shù)操作很重要,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-10-10
  • C++ 虛函數(shù)與純虛函數(shù)代碼詳解

    C++ 虛函數(shù)與純虛函數(shù)代碼詳解

    本文主要介紹了C++ 虛函數(shù)與純虛函數(shù)的使用與區(qū)別,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Gradle 創(chuàng)建Task的多種方法

    Gradle 創(chuàng)建Task的多種方法

    本文主要介紹了Gradle 創(chuàng)建Task的多種方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 全面解析SpringBoot配置文件

    全面解析SpringBoot配置文件

    這篇文章主要為大家全面的解析SpringBoot-配置文件,文中附含詳細(xì)的圖文示例代碼,以便同學(xué)們能更好的理解,有需要的同學(xué)可以借鑒參考下
    2021-09-09
  • SpringMvc框架的簡(jiǎn)介與執(zhí)行流程詳解

    SpringMvc框架的簡(jiǎn)介與執(zhí)行流程詳解

    MVC是一種軟件設(shè)計(jì)典范,用一種業(yè)務(wù)邏輯、數(shù)據(jù)、界面顯示分離的方法組織代碼,將業(yè)務(wù)邏輯聚集到一個(gè)組件里面,在改進(jìn)和個(gè)性化定制界面及用戶交互的同時(shí),不需要重新編寫業(yè)務(wù)邏輯,MVC分層有助于管理和架構(gòu)復(fù)雜的應(yīng)用程序
    2021-06-06
  • SpringBoot讀取Resource下文件的4種方法

    SpringBoot讀取Resource下文件的4種方法

    這篇文章主要介紹了SpringBoot讀取Resource下文件的4種方法小結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-07-07

最新評(píng)論