如何为井字游戏创造简单,中等和难度级别?

问题描述 投票:1回答:3

目前我正在Android中创建tic-tac-toe-game

我成功创造了游戏,但面临一些问题

这是我到目前为止尝试过的代码

这是我的BoardView

public class BoardView extends View implements GestureDetector.OnGestureListener, ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {
    private static final int STROKE_WIDTH = 10;
    private static final int SWEEPER_WIDTH = 20;

    private float[] gridLinePoints;
    private Paint gridPaint;

    private PointF[][] centerPoints;
    private Paint signPaint;

    private List<SignData> signDataList;

    private @Constants.WinLinePosition int winLinePosition;
    private Paint winLinePaint;

    private GestureDetector clickDetector;
    private OnBoardInteractionListener onBoardInteractionListener;

    private ValueAnimator clickAnimator;
    private ValueAnimator winLineAnimator;
    private ValueAnimator resetAnimator;

    private float signRadius;
    private float winLineLength;
    private float sweeperStartPosition;

    private Paint sweeperPaint;
    private int[] sweeperColors;
    private float[] sweeperStops;

    public BoardView(Context context) {
        super(context);
        init();
    }

    public BoardView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public BoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @TargetApi(Build.VERSION_CODES.M)
    private void init() {
        gridLinePoints = new float[16];

        centerPoints = new PointF[3][3];
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                centerPoints[i][j] = new PointF();
            }
        }

        signDataList = new ArrayList<>();

        winLinePosition = Constants.NONE;

        gridPaint = new Paint();
        gridPaint.setColor(getContext().getResources().getColor(R.color.holo_green_dark, null));
        gridPaint.setAntiAlias(true);
        gridPaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
        gridPaint.setStrokeCap(Paint.Cap.ROUND);

        signPaint = new Paint();
        signPaint.setColor(getContext().getResources().getColor(R.color.holo_orange_dark, null));
        signPaint.setAntiAlias(true);
        signPaint.setStyle(Paint.Style.STROKE);
        signPaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
        signPaint.setStrokeCap(Paint.Cap.ROUND);

        winLinePaint = new Paint();
        winLinePaint.setColor(getContext().getResources().getColor(R.color.holo_red_dark, null));
        winLinePaint.setAntiAlias(true);
        winLinePaint.setStrokeWidth(dpToPx(STROKE_WIDTH));
        winLinePaint.setStrokeCap(Paint.Cap.ROUND);

        clickDetector = new GestureDetector(getContext(), this);

        clickAnimator = new ValueAnimator();
        clickAnimator.setDuration(150);
        clickAnimator.setInterpolator(new DecelerateInterpolator());
        clickAnimator.addUpdateListener(this);
        clickAnimator.addListener(this);

        winLineAnimator = new ValueAnimator();
        winLineAnimator.setDuration(150);
        winLineAnimator.setInterpolator(new DecelerateInterpolator());
        winLineAnimator.addUpdateListener(this);
        winLineAnimator.addListener(this);

        resetAnimator = new ValueAnimator();
        resetAnimator.setDuration(500);
        resetAnimator.setInterpolator(new AccelerateInterpolator());
        resetAnimator.addUpdateListener(this);
        resetAnimator.addListener(this);

        sweeperPaint = new Paint();
        sweeperPaint.setAntiAlias(true);
        sweeperPaint.setStyle(Paint.Style.FILL);

        sweeperColors = new int[3];
        sweeperColors[0] = Color.parseColor("#0000DDFF");
        sweeperColors[1] = Color.parseColor("#FF00DDFF");
        sweeperColors[2] = Color.parseColor("#0000DDFF");

        sweeperStops = new float[3];
        sweeperStops[0] = 0;
        sweeperStops[1] = 0.5f;
        sweeperStops[2] = 1;

        setLayerType(LAYER_TYPE_SOFTWARE, sweeperPaint);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        getLayoutParams().height = getMeasuredWidth();

        setGridLinePoints();
        setCenterPoints();
        setAnimationValues();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawGrid(canvas);
        super.onDraw(canvas);

        if (resetAnimator.isRunning()) {
            canvas.clipRect(0, sweeperStartPosition, getMeasuredWidth(), getMeasuredWidth());

            setSweeperGradient();
            canvas.drawRect(0, sweeperStartPosition, getMeasuredWidth(), sweeperStartPosition + dpToPx(SWEEPER_WIDTH), sweeperPaint);
        }

        drawSigns(canvas);
        drawWinLine(canvas);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if ((!isEnabled()) || (clickAnimator.isRunning()) || (isAnimationFlagSet())) {
            return super.onTouchEvent(event);
        } else {
            return clickDetector.onTouchEvent(event);
        }
    }

    private boolean isAnimationFlagSet() {
        for (SignData signData : signDataList) {
            if (signData.isAnimationFlag()) {
                return true;
            }
        }
        return false;
    }

    private void setGridLinePoints() {
        int side = getMeasuredWidth();
        float padding = dpToPx(STROKE_WIDTH / 2f);

        gridLinePoints[0] = gridLinePoints[4] = gridLinePoints[9] = gridLinePoints[13] = padding;
        gridLinePoints[1] = gridLinePoints[3] = gridLinePoints[8] = gridLinePoints[10] = side / 3f;
        gridLinePoints[2] = gridLinePoints[6] = gridLinePoints[11] = gridLinePoints[15] = side - padding;
        gridLinePoints[5] = gridLinePoints[7] = gridLinePoints[12] = gridLinePoints[14] = (2 * side) / 3f;
    }

    private void setCenterPoints() {
        float a = getMeasuredWidth() / 6f;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                centerPoints[i][j].x = a + (j * (2 * a));
                centerPoints[i][j].y = a + (i * (2 * a));
            }
        }
    }

    private void setAnimationValues() {
        clickAnimator.setFloatValues(0, (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH));
        winLineAnimator.setFloatValues(0, getMeasuredWidth());
        resetAnimator.setFloatValues(-dpToPx(SWEEPER_WIDTH), getMeasuredWidth());
    }

    private void setSweeperGradient() {
        float axis = sweeperStartPosition + (dpToPx(SWEEPER_WIDTH / 2f));

        LinearGradient horizontalGradient = new LinearGradient(0, axis, getMeasuredWidth(), axis,
                sweeperColors, sweeperStops, Shader.TileMode.CLAMP);

        LinearGradient verticalGradient = new LinearGradient(getMeasuredWidth() / 2f, sweeperStartPosition,
                getMeasuredWidth() / 2f, sweeperStartPosition + dpToPx(SWEEPER_WIDTH), sweeperColors, sweeperStops,
                Shader.TileMode.CLAMP);

        ComposeShader shader = new ComposeShader(horizontalGradient, verticalGradient, PorterDuff.Mode.MULTIPLY);

        sweeperPaint.setShader(shader);
    }

    private void drawGrid(Canvas canvas) {
        canvas.drawLines(gridLinePoints, gridPaint);
    }

    private void drawSigns(Canvas canvas) {
        for (int i = 0; i < signDataList.size(); i++) {
            SignData signData = signDataList.get(i);

            switch (signData.getSign()) {
                case Constants.CIRCLE:
                    drawCircle(canvas, centerPoints[signData.getRow()][signData.getColumn()], signData.isAnimationFlag());
                    break;
                case Constants.CROSS:
                    drawCross(canvas, centerPoints[signData.getRow()][signData.getColumn()], signData.isAnimationFlag());
                    break;
                case Constants.EMPTY:
                    break;
            }
        }
    }

    private void drawCircle(Canvas canvas, PointF center, boolean animationFlag) {
        float radius = animationFlag ? signRadius : (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH);

        canvas.drawCircle(center.x, center.y, radius, signPaint);
    }

    private void drawCross(Canvas canvas, PointF center, boolean animationFlag) {
        float radius = animationFlag ? signRadius : (getMeasuredWidth() / 6f) - dpToPx(2 * STROKE_WIDTH);

        canvas.drawLine(center.x - radius, center.y - radius, center.x + radius, center.y + radius, signPaint);
        canvas.drawLine(center.x - radius, center.y + radius, center.x + radius, center.y - radius, signPaint);
    }

    private void drawWinLine(Canvas canvas) {
        float length = winLineLength;

        float a = getMeasuredWidth() / 6f;

        float padding = dpToPx(STROKE_WIDTH);

        switch (winLinePosition) {
            case Constants.NONE:
                break;
            case Constants.ROW_1:
                canvas.drawLine(padding, a, length - padding, a, winLinePaint);
                break;
            case Constants.ROW_2:
                canvas.drawLine(padding, a + (2 * a), length - padding, a + (2 * a), winLinePaint);
                break;
            case Constants.ROW_3:
                canvas.drawLine(padding, a + (4 * a), length - padding, a + (4 * a), winLinePaint);
                break;
            case Constants.COLUMN_1:
                canvas.drawLine(a, padding, a, length - padding, winLinePaint);
                break;
            case Constants.COLUMN_2:
                canvas.drawLine(a + (2 * a), padding, a + (2 * a), length - padding, winLinePaint);
                break;
            case Constants.COLUMN_3:
                canvas.drawLine(a + (4 * a), padding, a + (4 * a), length - padding, winLinePaint);
                break;
            case Constants.DIAGONAL_1:
                canvas.drawLine(padding, padding, length - padding, length - padding, winLinePaint);
                break;
            case Constants.DIAGONAL_2:
                canvas.drawLine(getMeasuredWidth() - padding, padding, padding + getMeasuredWidth()
                        - length, length - padding, winLinePaint);
                break;
        }
    }

    void addSignToBoard(@Constants.Sign int sign, int row, int column) {
        SignData signData = new SignData();
        signData.setSign(sign);
        signData.setRow(row);
        signData.setColumn(column);
        signData.setAnimationFlag(true);

        if (clickAnimator.isRunning()) {
            clickAnimator.end();
        }

        signDataList.add(signData);
        clickAnimator.start();
    }

    void showWinLine(@Constants.WinLinePosition int winLinePosition) {
        this.winLinePosition = winLinePosition;

        winLineAnimator.start();
    }

    void resetBoard() {
        if (!resetAnimator.isRunning()) {
            resetAnimator.start();
        }
    }

    boolean isAlreadyAdded(int row, int column) {
        for (int i = 0; i < signDataList.size(); i++) {
            SignData signData = signDataList.get(i);

            if ((signData.getRow() == row) && (signData.getColumn() == column)) {
                return true;
            }
        }

        return false;
    }

    private float dpToPx(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getContext().getResources().getDisplayMetrics());
    }

    @Override
    public boolean onDown(MotionEvent e) {
        return true;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        float x = e.getX();
        float y = e.getY();

        int row = detectIndexOfPartition(y);
        int column = detectIndexOfPartition(x);

        if ((row != -1) && (column != -1)) {
            onBoardInteractionListener.onBoardClick(BoardView.this, row, column);
        }

        return true;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }

    private int detectIndexOfPartition(float value) {
        float maxValue = getMeasuredWidth();
        float totalNumberOfPartitions = 3;

        float lengthOfSinglePartition = maxValue / totalNumberOfPartitions;

        return (int) (value / lengthOfSinglePartition);
    }

    public void setOnBoardInteractionListener(OnBoardInteractionListener onBoardInteractionListener) {
        this.onBoardInteractionListener = onBoardInteractionListener;
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        if (animation == clickAnimator) {
            signRadius = (float) animation.getAnimatedValue();
        } else if (animation == winLineAnimator) {
            winLineLength = (float) animation.getAnimatedValue();
        } else if (animation == resetAnimator) {
            sweeperStartPosition = (float) animation.getAnimatedValue();
        }
        invalidate();
    }

    @Override
    public void onAnimationStart(Animator animation) {

    }

    @Override
    public void onAnimationEnd(Animator animation) {
        if (animation == clickAnimator) {
            SignData signData = signDataList.get(signDataList.size() - 1);
            signData.setAnimationFlag(false);
            onBoardInteractionListener.onSignAdded(signData.getSign(), signData.getRow(), signData.getColumn());
            signRadius = 0;
        } else if (animation == resetAnimator) {
            signDataList.clear();
            winLinePosition = Constants.NONE;
            onBoardInteractionListener.onBoardReset();
        }
    }

    @Override
    public void onAnimationCancel(Animator animation) {

    }

    @Override
    public void onAnimationRepeat(Animator animation) {

    }

    interface OnBoardInteractionListener {

        void onBoardClick(BoardView board, int row, int column);

        void onSignAdded(@Constants.Sign int sign, int row, int column);

        void onBoardReset();
    }

    private class SignData {
        private @Constants.Sign int sign;
        private int row;
        private int column;
        private boolean animationFlag;

        @Constants.Sign int getSign() {
            return sign;
        }

        void setSign(@Constants.Sign int sign) {
            this.sign = sign;
        }

        int getRow() {
            return row;
        }

        void setRow(int row) {
            this.row = row;
        }

        int getColumn() {
            return column;
        }

        void setColumn(int column) {
            this.column = column;
        }

        boolean isAnimationFlag() {
            return animationFlag;
        }

        void setAnimationFlag(boolean animationFlag) {
            this.animationFlag = animationFlag;
        }
    }
}

我的大脑课

class Brain {
    private static Brain INSTANCE;

    private @Constants.Sign
    int[][] board = new int[3][3];

    private int rowOfResult;
    private int columnOfResult;

    private int depth;

    private @Constants.Sign
    int computerSign;
    private @Constants.Sign
    int playerSign;

    private OnProcessCompleteListener onProcessCompleteListener;

    private static final int HORIZONTAL = 0;
    private static final int VERTICAL = 1;
    private static final int DIAGONAL = 2;

    @IntDef({HORIZONTAL, VERTICAL, DIAGONAL})
    @interface DirectionOfWinLine {

    }

    // References used by isWin function.
    private int[] winSequence = new int[3];
    private int[] row = new int[3];
    private int[] column = new int[3];
    private int[] diagonal1 = new int[3];
    private int[] diagonal2 = new int[3];

    private Brain() {
    }

    static Brain getInstance() {
        if (INSTANCE == null) {
            INSTANCE = new Brain();
        }
        return INSTANCE;
    }

    void play() {
        if (onProcessCompleteListener == null) {
            return;
        }
        calculateNextMove(computerSign, depth);

        onProcessCompleteListener.onNextMoveCalculated(rowOfResult, columnOfResult);
    }

    private int calculateNextMove(@Constants.Sign int sign, int depth) {

        if (isWin(computerSign, false)) {
            return 10 - depth;
        } else if (isWin(playerSign, false)) {
            return depth - 10;
        }

        if (depth >= 9) {
            return 0;
        }

        List<Integer> scores = new ArrayList<>(), rowIndices = new ArrayList<>(), columnIndices = new ArrayList<>();

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (board[i][j] == Constants.EMPTY) {
                    board[i][j] = sign;
                    scores.add(calculateNextMove(getOppositeSign(sign), depth + 1));
                    rowIndices.add(i);
                    columnIndices.add(j);
                    board[i][j] = Constants.EMPTY;
                }
            }
        }

        if (sign == computerSign) {
            int maxScore = -100;
            for (int i = 0; i < scores.size(); i++) {
                if (scores.get(i) > maxScore) {
                    maxScore = scores.get(i);
                }
            }
            return randomizeScore(maxScore, scores, rowIndices, columnIndices);

        } else {
            int minScore = 100;
            for (int i = 0; i < scores.size(); i++) {
                if (scores.get(i) < minScore) {
                    minScore = scores.get(i);
                }
            }
            return randomizeScore(minScore, scores, rowIndices, columnIndices);
        }
    }

    private int randomizeScore(int score, List<Integer> scores, List<Integer> rowIndices, List<Integer> columnIndices) {
        List<Integer> equalScoreIndices = new ArrayList<>();

        for (int i = 0; i < scores.size(); i++) {
            if (scores.get(i) == score) {
                equalScoreIndices.add(i);
            }
        }

        Random rand = new Random();
        int randomIndex = equalScoreIndices.get(rand.nextInt(equalScoreIndices.size()));

        rowOfResult = rowIndices.get(randomIndex);
        columnOfResult = columnIndices.get(randomIndex);

        return score;
    }

    private boolean isWin(@Constants.Sign int sign, boolean notifyWinEnabled) {
        for (int i = 0; i < 3; i++) {
            winSequence[i] = sign;
        }

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {

                if (i == j) {
                    diagonal1[i] = board[i][j];
                }
                if ((i + j) == 2) {
                    diagonal2[i] = board[i][j];
                }

                row[j] = board[i][j];
                column[j] = board[j][i];
            }

            if (isEqual(row, winSequence)) {
                if (notifyWinEnabled) {
                    notifyWin(sign, HORIZONTAL, i + 1);
                }
                return true;
            } else if (isEqual(column, winSequence)) {
                if (notifyWinEnabled) {
                    notifyWin(sign, VERTICAL, i + 1);
                }
                return true;
            }
        }

        if (isEqual(diagonal1, winSequence)) {
            if (notifyWinEnabled) {
                notifyWin(sign, DIAGONAL, 1);
            }
            return true;
        } else if (isEqual(diagonal2, winSequence)) {
            if (notifyWinEnabled) {
                notifyWin(sign, DIAGONAL, 2);
            }
            return true;
        }

        return false;
    }

    private boolean isEqual(int[] x, int[] y) {
        for (int i = 0; i < 3; i++) {
            if (x[i] != y[i]) {
                return false;
            }
        }
        return true;
    }

    void analyzeBoard() {
        if (onProcessCompleteListener == null) {
            return;
        }

        if ((!isWin(Constants.CIRCLE, true)) && (!isWin(Constants.CROSS, true)) && (depth >= 9)) {
            onProcessCompleteListener.onGameDraw();
        }
    }

    private void notifyWin(@Constants.Sign int sign, @DirectionOfWinLine int direction, int index) {
        if (onProcessCompleteListener == null) {
            return;
        }

        @Constants.WinLinePosition int winLinePosition = Constants.NONE;

        switch (direction) {
            case HORIZONTAL:
                switch (index) {
                    case 1:
                        winLinePosition = Constants.ROW_1;
                        break;
                    case 2:
                        winLinePosition = Constants.ROW_2;
                        break;
                    case 3:
                        winLinePosition = Constants.ROW_3;
                        break;
                }
                break;
            case VERTICAL:
                switch (index) {
                    case 1:
                        winLinePosition = Constants.COLUMN_1;
                        break;
                    case 2:
                        winLinePosition = Constants.COLUMN_2;
                        break;
                    case 3:
                        winLinePosition = Constants.COLUMN_3;
                        break;
                }
                break;
            case DIAGONAL:
                switch (index) {
                    case 1:
                        winLinePosition = Constants.DIAGONAL_1;
                        break;
                    case 2:
                        winLinePosition = Constants.DIAGONAL_2;
                        break;
                }
                break;
        }

        onProcessCompleteListener.onGameWin(sign, winLinePosition);
    }

    void reset() {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                board[i][j] = Constants.EMPTY;
            }
        }
        depth = 0;
    }

    void setComputerSign(int computerSign) {
        this.computerSign = computerSign;
        playerSign = getOppositeSign(computerSign);
    }

    void updateBoard(@Constants.Sign int sign, int row, int column) {
        board[row][column] = sign;
        depth++;
    }

    private @Constants.Sign
    int getOppositeSign(@Constants.Sign int sign) {
        return sign == Constants.CIRCLE ? Constants.CROSS : Constants.CIRCLE;
    }

    void setOnProcessCompleteListener(OnProcessCompleteListener onProcessCompleteListener) {
        this.onProcessCompleteListener = onProcessCompleteListener;
    }

    interface OnProcessCompleteListener {

        void onNextMoveCalculated(int row, int column);

        void onGameWin(@Constants.Sign int sign, @Constants.WinLinePosition int winLinePosition);

        void onGameDraw();
    }

    void destroy() {
        INSTANCE = null;
    }
}

我已经为这里提供的所有代码创建了github repo

https://github.com/SuperSaiyanGoku3/MyGame

我在上面的代码中遇到了一些问题

  1. 上面的代码只支持硬级(Impossible),我怎样才能在上面的游戏算法中再创建简单的中等硬度计算机(CPU)。
  2. 如何设置自定义图标而不是O和X.
  3. 如何在上面的代码中随机设置所有三种游戏模式,如同简单的中等和硬级别,所以当用户启动游戏时,cpu将随机出现,枯萎或中等或难度。

以下是我迄今为止尝试过的一些链接,但无法理解如何创建简单的中等和硬级别

如果需要更多信息,请告诉我。提前致谢。您的努力将不胜感激。

java android tic-tac-toe
3个回答
4
投票
  1. 实施难度:为了支持轻松和中等难度,我建议你只使用随机。你已经实现了HARD难度,所以你只需要制作“错误”的较难的逻辑,这个错误可以随机实现。 private void calculateNextMoveRandom() { Random rand = new Random(); int randomRow; int randomColumn; while (true) { randomRow = rand.nextInt(3); randomColumn = rand.nextInt(3); if (Constants.EMPTY == board[randomRow][randomColumn]) { rowOfResult = randomRow; columnOfResult = randomColumn; return; } } }

2.位图标记:您可以使用BitmapFactory.decodeResource()在屏幕上绘制位图。

    private void drawCircle(Canvas canvas, PointF center, boolean animationFlag) {
        int iconSize = (int) LayoutUtil.getPixelFromDp(MARKER_SIZE, getContext());
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.android);
        Bitmap scaled = Bitmap.createScaledBitmap(bitmap, iconSize, iconSize, true);
        canvas.drawBitmap(scaled, center.x - (iconSize >> 1), center.y - (iconSize >> 1), signPaint);
    }

3.随机难度:只需使用随机设置难度。

    brain.setDifficulty(new Random().nextInt(3));

这是我的拉动请求: https://github.com/SuperSaiyanGoku3/MyGame/pull/1

enter image description here


0
投票

如果你使用minimax策略来玩tic-tac-toe,你可以拥有多个与游戏中不同难度级别相对应的开关案例。最简单的方法是在minimax树中设置不同的深度阈值。例如,您可以扩展minimax游戏树,直到只有深度2(假设为3 * 3井字游戏)为简单级别并且说到搜索树的末端为最高难度级别。您可以根据电路板尺寸和预期的难度级别设置此阈值。

实现难度级别的另一种方法是通过实现不同的启发式函数来计算董事会得分(对董事会当前状态的良好度量)。您可以使用您的启发式函数,根据您在该行/列/对角线中占用的单元格数量来评估单个行/列/对角线得分。例如,如果占用的单元数是1,则得分= x(x可以是任意数字)。如果占用的细胞数是2,则得分= x ^ 2,如果是3,则得分= x ^ 3。然后将所有单独的线路分数相乘,以获得每个行,列或对角线的良好度量(或者您可以将其视为获胜概率)。您可以为对手计算一个类似的分数,然后取一个差异来获得一个委员会得分。因此,该想法是通过为每个难度级别设计启发式函数的不同变化来实现评估当前板状态的不同方式。一个糟糕的启发式功能可以作为一个简单的级别,因为它将失去很多游戏,而一个设计合理的启发式将有一个不丢失的政策(它将最终赢得或绘制游戏)。

为了在每次游戏运行中随机选择难度级别,您可以使用随机数生成器来选择难度级别。您可以将“0”指定为“简单”,将“1”指定为“中”,将“2”指定为“硬”。您可以使用以下java函数生成0到(n-1)之间的整数

int random = Random.nextInt(n)


0
投票

Complete Tic Tac Toe with "n x n matrix"

基本思路是我们只需要检查列/行/对角元素是否相同。用C#编写的代码,带有基本单元测试。

© www.soinside.com 2019 - 2024. All rights reserved.