การแข่งขันหมากรุก


24

นี่คือหมากรุก KOTH ที่มีกฎง่าย ๆ (เนื่องจากหมากรุกเองมีความซับซ้อนอยู่แล้วการเล่นผ่านโปรแกรมอย่างง่ายไม่ทำให้ง่ายขึ้น) ในขณะนี้มันถูก จำกัด จาวา (เวอร์ชัน 8) แต่การสร้างคลาส wrapper นั้นไม่ใช่เรื่องยาก (ในกรณีที่มีคนต้องการทำสิ่งนี้)

กระดานหมากรุก

กระดานหมากรุกในโปรแกรมควบคุมใช้รุ่นแก้ไขของสัญกรณ์ ICCF ตัวเลข มันเป็น zero-based ความหมายข้อมูลด้านล่างซ้ายเป็นตำแหน่งในขณะที่ข้อมูลบนขวาเป็นตำแหน่ง0,07,7

แก้ไขกฎ

  • En passantจะถูกละเว้น
  • การขว้างเป็นไปไม่ได้
  • กฎห้าสิบย้ายนำไปใช้โดยอัตโนมัติ (หมายถึงเกมสิ้นสุดในการวาด)
  • การส่งเสริมการจำนำเป็นราชินีเกิดขึ้นโดยอัตโนมัติเมื่อถึงจุดสิ้นสุดของกระดาน
  • หากผู้เล่นต้องการความเคลื่อนไหวนานกว่า 2 วินาทีเขาจะแพ้ในเกม
  • การคืนการย้ายที่ไม่ถูกต้องจะส่งผลให้สูญเสียเกม
  • จะชนะคุณต้องจับศัตรูกษัตริย์ มันไม่เพียงพอที่จะรุกฆาตศัตรู
  • นอกจากนี้ยังช่วยให้คุณย้ายราชาของคุณไปยังทุ่งที่ศัตรูสามารถจับคุณได้
  • ขาวเริ่มเกม
  • สีขาวถูกวางไว้ "ที่ด้านล่าง" ของฟิลด์ (y = 0) สีดำจะอยู่ที่ด้านบน (y = 7)
  • การเข้าถึงทรัพยากรอื่นนอกเหนือจากบอทของคุณ (อินเทอร์เน็ต, ไฟล์, บอตอื่น ๆ , ... ) เป็นสิ่งต้องห้าม

เกณฑ์การให้คะแนน

  • ผู้ชนะจะได้รับ 3 คะแนนเสมอ 1 คะแนนและเสีย 0 คะแนน
  • การส่งแต่ละครั้งจะเล่นกับการส่งอื่น ๆ 10 ครั้ง (สีขาว 5 ครั้ง, 5 สีดำ)

ตัวควบคุม

คุณสามารถค้นหาโปรแกรมควบคุมบน GitHub
ในการเข้าร่วมคุณจะต้องสร้างชั้นภายในเป็นplayerแพคเกจและมันจะต้องมี subclass Playerของ ตัวอย่างเช่นดูที่ TestPlayer (ซึ่งจะรวมอยู่ในการให้คะแนนด้วย)

ในแต่ละเกมผู้ควบคุมจะสร้างตัวอย่างใหม่ให้ผู้เล่นของคุณ จากนั้นในแต่ละเทิร์นคุณจะต้องกลับมาเคลื่อนไหว ควบคุมให้คุณมีสำเนาที่คณะกรรมการซึ่งมีอาร์เรย์ 8x8 ของทุ่ง ฟิลด์จะมีข้อมูลเกี่ยวกับสีตำแหน่งและชิ้นส่วนของมันหากมี
ควบคุมยังให้คุณมีข้อมูลเกี่ยวกับผู้เล่นศัตรูเช่นและisCheck getPieces()การเรียกgetMove()ศัตรูจะทำให้คุณถูกตัดสิทธิ์

ป้ายบอกคะแนน

01) AlphaBetaPV: 229
02) AlphaBeta: 218
03) ตัวรับสัญญาณ: 173
04) ชีส: 115
05) ThreeMoveMonte: 114
06) StretchPlayer: 93
07) DontThinkAhead: 81
08) SimplePlayer: 27
09) TestPlayer: 13

การประกวดนั้น จำกัด อยู่ที่จาวาเพราะจะทำให้การสร้างคำตอบง่ายขึ้นเนื่องจากคุณสามารถทำกำไรจากวิธีการที่ผู้ควบคุมจัดเตรียมไว้ให้ อย่างไรก็ตามหากมีคนสร้างเสื้อคลุมฉันจะรวมภาษาอื่น ๆ


2
นอกจากนี้ยังเปลี่ยนทางตันให้กลายเป็นความสูญเสีย :(
Geobits

2
you can profit from the methods provided by the controller: นี่ไม่ใช่ความจริงทั้งหมด วิธีการที่เป็นประโยชน์ส่วนใหญ่เป็นแพคเกจส่วนตัวดังนั้นจึงไม่สามารถใช้งานได้ คุณอาจคิดว่าจะเพิ่มsimulateMoveวิธีการในBoardชั้นเรียนซึ่งส่งกลับสำเนาลึกของคณะกรรมการที่มีการย้ายไปใช้? ด้วยวิธีนี้เราไม่ต้องเขียนเอง (หรือคัดลอกโค้ดทั้งหมดของคุณ ^^)
ทิม

4
กฎข้อที่สองนั้นยอดเยี่ยมมาก แทนที่จะเป็นบอตหมากรุกที่ดีที่สุดยาก ๆ ความท้าทายก็เหมือน: สร้างบอทหมากรุกที่ดีที่สุดที่ไม่ฉลาด
Mark Gabriel

2
@Geobits ฉันอัพเดทตัวควบคุม วิธีการที่เป็นประโยชน์ส่วนใหญ่publicตอนนี้;)
ทั่วไปซื้อ

3
ฉันเกือบจะอยากเขียนบอทที่ขว้างThrowableหรือแม้กระทั่งErrorเพราะมันจะหลีกเลี่ยงการสูญเสีย ฉันเรียกมันว่า BoardTipper
Ingo Bürk

คำตอบ:


4

AlphaBetaPV

AlphaBetaPV ย่อมาจาก Alpha Beta พร้อมการเปลี่ยนแปลงหลัก (ไม่ใช่การค้นหาความแปรปรวนหลัก) มีเพียงไม่กี่บรรทัดที่ถักทอเป็นรหัสของ AlphaBeta.java มันจะเต้น AlphaBeta.java และอีกครั้งขออภัยสำหรับการ morphing และการรวมรหัสจากแหล่งอินเทอร์เน็ตอื่น ๆ ลงในรหัส JAVA นี้เท่านั้น

  • รูปแบบหลักถูกจัดเก็บและใช้สำหรับการย้ายที่ง่ายที่สุดเพื่อเร่งการตัดอัลฟาเบต้า:
    • ในขณะที่ซ้ำลึกและ
    • สำหรับการย้ายครั้งต่อไป
  • ประเมินตำแหน่งง่าย ๆ :
    • จำนวนการเคลื่อนไหวของแต่ละฝ่ายมี (ระดับความเป็นอิสระ) เพื่อรองรับการเปิด
    • โปรโมชั่นจำนำเพื่อสนับสนุนเกมจบ
  • ยังไม่มีการค้นหาความเงียบ

ยังคงเล่นที่น่าเบื่อ

package player;

import java.util.Random;
import controller.*;

public class AlphaBetaPV extends Player {
    private static final int INFINITY = Integer.MAX_VALUE;
    private static final int MAXTIME = 1800; // max time for evaluation
    private static final Random random=new Random();
    private static int seed=1;

    private long time; // time taken this turn
    private int iterativeDepth;
    private Player myOpponent;
    private int commitedDepth;

    private static Piece[] pieces = new Piece[20000];
    private static Point[] points = new Point[20000];
    private static int[] freedom = new int[20];

    private static class PV {
        Move move;
        PV next;
    }       
    private PV pv= new PV();

    @Override
    public Move getMove(Board root, Player min) {
        time=System.currentTimeMillis();
        seed++; myOpponent=min;
        // use last PV for an estimate of this move
        if (pv.next!=null) pv=pv.next;
        if (pv.next!=null) pv=pv.next;
        iterative_deepening(root);
        return pv.move;
    }

    private void iterative_deepening(Board root) {
        try {
            for (iterativeDepth = (commitedDepth=Math.max(2, commitedDepth-2));; iterativeDepth++) {
                alphaBeta(root, -INFINITY, +INFINITY, iterativeDepth, this, myOpponent, 0, 0, pv, pv);
                commitedDepth=iterativeDepth;
            }
        } catch (InterruptedException e) {}
    }

    //http://chessprogramming.wikispaces.com/Alpha-Beta
    private int alphaBeta(Board root, int alpha, int beta, int d, Player max, Player min, int begin, int level, PV pv, PV pline) throws InterruptedException {
        if (d==0 || root.getKing(max) == null) return evaluate(root, d, level);
        int end = allMoves(root, max, begin, level, pv);
        PV line= new PV();
        for (int m=begin; m<end; m++) {
            Board board = root.copy();
            board.movePiece(new Move(pieces[m].copy(), points[m]));
            int score = -alphaBeta(board, -beta, -alpha, d - 1, min, max, end, level+1, pline==null?null:pline.next, line);
            if (score >= beta)
                return beta; // fail hard beta-cutoff
            if (score > alpha) {
                pline.move=new Move(pieces[m].copy(), points[m]); // store as principal variation
                pline.next=line; line=new PV();
                alpha = score; // alpha acts like max in MiniMax
            }
        }
        return alpha;
    }

    private int evaluate(Board board, int d, int level) throws InterruptedException {
        if ((System.currentTimeMillis() - time) > MAXTIME)  throw new InterruptedException();
        int minmax=2*((iterativeDepth-d)&1)-1;
        int king = 0, value=(level>1)?minmax*(freedom[level-1]-freedom[level-2]):0;
        Field[][] field = board.getFields();
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                Piece piece = field[x][y].getPiece();
                if (piece==null) continue;

                int sign=(piece.getTeam()==getTeam())?-minmax:minmax;
                switch (piece.getType()) {
                case PAWN:      value += (  1000+2*(piece.getTeam()==Color.WHITE?y:7-y))*sign; break;
                case KNIGHT:    value +=    3000*sign; break;
                case BISHOP:    value +=    3000*sign; break;
                case ROOK:      value +=    5000*sign; break;
                case QUEEN:     value +=    9000*sign; break;
                case KING:      king  += (100000-(iterativeDepth-d))*sign; break;
                default: // value += 0;
                }
            }
        }
        return king==0?value:king;
    }

    private int allMoves(Board board, Player player, int begin, int level, PV pv) {
        random.setSeed(seed);
        int m=0;
        for (Piece piece : player.getPieces(board)) {
            for (Point point: piece.getValidDestinationSet(board)) {
                // shuffle and store
                int r=begin+random.nextInt(++m);
                points[begin+m-1]=points[r];    pieces[begin+m-1]=pieces[r];
                points[r]=point;                pieces[r]=piece;
            }
        }
        freedom[level]=m;
        if (pv!=null && pv.move!=null)  { // push PV to front
            for (int i = 0; i < m; i++) {
                if (pv.move.getPiece().equals(pieces[begin+i]) && pv.move.getDestination().equals(points[begin+i])) {
                    Point point = points[begin];    Piece piece = pieces[begin];
                    points[begin]=points[begin+i];  pieces[begin]=pieces[begin+i];
                    points[begin+i]=point;          pieces[begin+i]=piece;  
                    break;
                }
            }
        }
        return begin+m;
    }
}

11

PieceTaker

รหัสเป็นระเบียบเล็กน้อย แต่ใช้งานได้ ตอนนี้มันชนะกับผู้เล่นคนอื่น ๆ แม้ว่าจะได้รับเพียง 400ms แทนที่จะเป็น 2000ms ที่อนุญาต

ฉันกำลังใช้การตัดแต่งกิ่งเบต้าด้วยอัลฟาลึกซ้ำเพื่อให้แน่ใจว่า AI จะไม่เกินเวลาที่กำหนด ฮิวริสติกปัจจุบันนั้นง่ายมาก (มีเพียงชิ้นส่วนที่สูญหาย / นำไปพิจารณาเท่านั้นไม่ใช่ตำแหน่งบนกระดาน ฯลฯ )

ในอนาคตฉันอาจเพิ่มฮิวริสติกของนักฆ่าและจัดเรียงการเคลื่อนไหวก่อนที่จะตรวจสอบพวกเขา

package player;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import controller.*;

public class PieceTaker extends Player {

    private boolean DEBUG = false;
    private Player pieceTaker;
    private static final int MAXINT = Integer.MAX_VALUE / 2;
    private static final int MININT = Integer.MIN_VALUE / 2;
    private static final boolean ITERATIVE_DEEPENING = true;
    private static final int MAX_DEPTH = 6; // max depth if not using iterative
                                            // deepening
    private static int MAXTIME = 400; // max time for evaluation (if using
                                        // iterativeDeepening). We still need to
                                        // evaluate moves, so save time for
                                        // that.
    private long time; // time taken this turn

    @Override
    public Move getMove(Board board, Player enemy) {
        pieceTaker = this;
        // generate all possible moves
        List<Move> possibleMoves = new ArrayList<>();
        List<Piece> pieces = this.getPieces(board);
        for (Piece piece : pieces) {
            Point[] destinations = piece.getValidDestinations(board);
            for (Point point : destinations) {
                possibleMoves.add(new Move(piece, point));
            }
        }

        // rate moves
        Move best = getNextMove(board, possibleMoves, enemy);
        return best;
    }

    private Move getNextMove(Board board, List<Move> possibleMoves, Player enemy) {
        time = System.currentTimeMillis();

        // wrap moves in node class and apply move
        List<Node> children = new ArrayList<>();
        for (Move move : possibleMoves) {
            Node newNode = new Node(move, board, this, enemy, 0);
            newNode.applyAndRateMove();
            children.add(newNode);
        }

        if (ITERATIVE_DEEPENING) {
            for (int depth = 1;; depth++) {
                List<Node> copy = new ArrayList<>();
                // copy nodes (so that in case time is over we still have a valid set)
                for (Node node : children) {
                    copy.add(node.copy());
                }
                // rate copy
                rateMoves(copy, depth);
                if ((System.currentTimeMillis() - time) > MAXTIME) {
                    break;
                }
                // copy rated nodes back
                children = new ArrayList<>();
                for (Node node : copy) {
                    children.add(node.copy());
                }
            }
        } else {
            rateMoves(children, MAX_DEPTH);
        }

        return getBestMove(children);
    }

    // returns node with the highest score
    private Move getBestMove(List<Node> nodes) {
        if (DEBUG) {
            System.out.println("\n");
            for (Node node : nodes) {
                System.out.println(node.toString());
            }
        }

        Collections.sort(nodes, new ComparatorNode());

        // get all nodes with top rating
        List<Node> best = new ArrayList<>();
        int bestValue = nodes.get(0).getRating();
        for (Node node : nodes) {
            if (node.getRating() == bestValue) {
                best.add(node);
            }
        }

        Random random = new Random();
        Node bestNode = best.get(random.nextInt(best.size()));
        if (DEBUG) {
            System.out.println("using: " + bestNode.toString());
        }
        return bestNode.getMove();
    }

    private void rateMoves(List<Node> nodes, int depth) {
        if (nodes.size() == 1) {
            // nothing to rate. one possible move, take it.
            return;
        }

        for (Node node : nodes) {
            int alphaBeta = alphaBeta(node, depth, MININT, MAXINT);
            node.setRating(alphaBeta);
        }
    }

    protected int alphaBeta(Node node, int depth, int alpha, int beta) {
        Player currentPlayer = node.getCurrentPlayer();
        Player otherPlayer = node.getOtherPlayer();
        // game over
        if (node.getBoard().getKing(currentPlayer) == null) {
            if (currentPlayer == this) {
                return node.getRating() - 999;
            } else {
                return node.getRating() + 999;
            }
        } else {
            // TODO check for draw and rate draw (might be good to take it)
        }
        if (depth <= 0) {
            return node.getRating(); // the rating in the move is always as seen
                                        // for player, not current player
        }

        List<Node> children = getPossibleMoves(node);
        if (otherPlayer == this) {
            for (Node child : children) {
                if ((System.currentTimeMillis() - time) > MAXTIME) {
                    break; // time over.
                }
                alpha = Math.max(alpha,
                        alphaBeta(child, depth - 1, alpha, beta));
                if (beta <= alpha) {
                    break; // cutoff
                }
            }
            return alpha;
        } else {
            for (Node child : children) {
                if ((System.currentTimeMillis() - time) > MAXTIME) {
                    break; // time over.
                }
                beta = Math.min(beta, alphaBeta(child, depth - 1, alpha, beta));
                if (beta <= alpha) {
                    break; // cutoff
                }
            }
            return beta;
        }
    }

    private List<Node> getPossibleMoves(Node node) {
        List<Node> possibleMoves = new ArrayList<>();
        List<Piece> pieces = node.getOtherPlayer().getPieces(node.getBoard());
        for (Piece piece : pieces) {
            Point[] destinations = piece.getValidDestinations(node.getBoard());
            for (Point point : destinations) {
                Node newNode = new Node(new Move(piece, point),
                        node.getBoard(), node.getOtherPlayer(),
                        node.getCurrentPlayer(), node.getRating());
                if (newNode.applyAndRateMove()) {
                    possibleMoves.clear();
                    possibleMoves.add(newNode);
                    return possibleMoves; // we won, return wining move
                }
                possibleMoves.add(newNode);
            }
        }
        return possibleMoves;
    }

    private class Node {
        private Move move;
        private Move originalMove;
        private Board board;
        private Player currentPlayer;
        private Player otherPlayer;
        private int rating;

        public Node(Move move, Board board, Player currentPlayer,
                Player otherPlayer, int rating) {
            super();
            this.move = new Move(move.getPiece().copy(), move.getDestination()
                    .copy());
            this.originalMove = new Move(move.getPiece().copy(), move
                    .getDestination().copy());
            // copy board so changes only affect this node
            this.board = board.copy();
            this.currentPlayer = currentPlayer;
            this.otherPlayer = otherPlayer;
            this.rating = rating;
        }

        @Override
        public String toString() {
            return " [" + originalMove.toString() + " (r: " + rating + ")] ";
        }

        public Node copy() {
            Node copy = new Node(new Move(originalMove.getPiece().copy(),
                    originalMove.getDestination().copy()), board.copy(),
                    currentPlayer, otherPlayer, rating);
            return copy;
        }

        public boolean applyAndRateMove() {
            // call rate before apply as it needs the unchanged board
            rateMove();
            board.movePiece(move);
            if (getBoard().getKing(currentPlayer) == null) {
                return true;
            } else {
                return false;
            }
        }

        private void rateMove() {
            Point dest = move.getDestination();
            Field destField = board.getFields()[dest.getX()][dest.getY()];

            int value = 0;
            if (destField.hasPiece()) {
                PieceType type = destField.getPiece().getType();
                switch (type) {
                case PAWN:
                    value = 1;
                    break;
                case KNIGHT:
                    value = 3;
                    break;
                case BISHOP:
                    value = 3;
                    break;
                case ROOK:
                    value = 5;
                    break;
                case QUEEN:
                    value = 9;
                    break;
                case KING:
                    value = 111;
                    break;
                default:
                    value = 0;
                }
            }

            if (currentPlayer == pieceTaker) {
                this.rating += value;
            } else {
                this.rating -= value;
            }
        }

        public Player getOtherPlayer() {
            return otherPlayer;
        }

        public Player getCurrentPlayer() {
            return currentPlayer;
        }

        public Board getBoard() {
            return board;
        }

        public int getRating() {
            return rating;
        }

        public void setRating(int r) {
            this.rating = r;
        }

        public Move getMove() {
            return originalMove;
        }
    }

    private class ComparatorNode implements Comparator<Node> {
        @Override
        public int compare(Node t, Node t1) {
            return t1.getRating() - t.getRating();
        }
    }
}

บอทตัวนี้เหนียวมาก!
Mark Gabriel

@ MarkGabriel ขอบคุณ :) โดยสุจริตฉันไม่ได้มีความสุขกับมันในตอนแรก สามารถคิดล่วงหน้าได้ 2-4 ครั้งเท่านั้นซึ่งไม่เพียงพอในหลายสถานการณ์ ฉันมีรุ่นที่ปรับปรุงแล้วฉันไม่ได้คัดลอกฟิลด์ แต่เลิกทำการย้ายซึ่งเร็วกว่ามาก แต่มันเป็นบั๊กซีและฉันไม่สามารถแก้ไขได้ :(
ทิม

11

StretchPlayer

บอทนี้เล่นเหมือนฉัน!

โดยวิธีการที่ฉันกลัวหมากรุก

ความคิดเห็นอธิบายสิ่งที่มันกำลังทำจริง มันเหมือนกับกระบวนการคิดของฉันมาก

ในฐานะโบนัสที่เพิ่มเข้ามาจะทำให้บ็อตอื่น ๆ ทั้งหมดมีส่วนต่างมาก (จนถึงตอนนี้)

แก้ไข: ตอนนี้ทำนายคู่ต่อสู้ด้วยการวิ่งเป็นศัตรู!

แก้ไข 2: โปรแกรมทำผิดพลาดจากการไม่ฆ่าราชาจริง ๆ เมื่อเปิดกว้าง มันถูกตำหนิตาม

import java.util.List;
import java.util.Set;

import controller.*;

public class StretchPlayer extends Player{

    boolean avoidStackOverflow = false;
    @Override
    public Move getMove(Board board, Player enemy) {
        List<Piece> pieces = this.getPieces(board);
        for(Piece piece:pieces){
            //first order of business: kill the enemy king if possible
            if(piece.getValidDestinationSet(board).contains(board.getKing(enemy).getPos())){
                return new Move(piece,board.getKing(enemy).getPos());
                }
        }
        //I suppose I should protect my king.
        for(Piece ePiece:enemy.getPieces(board)){
            if(ePiece.getValidDestinationSet(board).contains(board.getKing(this).getPos())){
                //ideally I would move my king.
                for(Point p:board.getKing(this).getValidDestinationSet(board)){
                    //but I don't want it to move into a spot where the enemy can get to. That would be suicide.
                    boolean moveHere=true;
                    for(Piece enemyPiece:enemy.getPieces(board)){
                        if(enemyPiece.getValidDestinationSet(board).contains(p)){
                            moveHere=false;
                        }
                    }
                    if(moveHere){
                        return new Move(board.getKing(this),p);
                    }
                }
                //so the king can't move. But I can fix this. There has to be a way!
                for(Piece myPiece:pieces){
                    for(Point possMove:myPiece.getValidDestinationSet(board)){
                        Board newBoard = board.copy();
                        newBoard.movePiece(new Move(myPiece,possMove));
                        if(!newBoard.isCheck(this, enemy)){
                            //Aha! found it!
                            return new Move(myPiece,possMove);
                        }
                    }

                }
                //uh-oh. Better just go with the flow. I'll lose anyway.
            }
        }
        for(Piece piece:pieces){
            Set<Point> moves = piece.getValidDestinationSet(board);
            for(Piece opponentPiece:enemy.getPieces(board)){
                if(moves.contains(opponentPiece.getPos())){
                    Point futurePosition = null;
                    //search for this illusive move (no indexOf(...)?)
                    for(Point p:moves){
                        if(p.getX()==opponentPiece.getPos().getX()&&p.getY()==opponentPiece.getPos().getY()){
                            futurePosition = p;
                        }
                    }
                    //it can now kill the enemies piece. But first, it should probably check if it is going to get killed if it moves there.
                    boolean safe = true;
                    for(Piece nextMoveOpponent:enemy.getPieces(board)){
                        if(nextMoveOpponent.getValidDestinationSet(board).contains(futurePosition)&&piece.getType()!=PieceType.PAWN){
                            safe = false;
                        }
                        //it would also be beneficial if the enemy didn't kill my king next round.
                        if(nextMoveOpponent.getValidDestinationSet(board).contains(board.getKing(this).getPos())){
                            safe = false;
                        }
                    }
                    if(safe){
                        return new Move(piece, futurePosition);
                    }

                }
            }
        }
        //ok, so I couldn't kill anything. I'll just put the enemy king in check!
        for(Piece piece:pieces){
            for(Point p:piece.getValidDestinationSet(board)){
                Piece simulatedMove = piece.copy();
                simulatedMove.setPos(p);
                if(simulatedMove.getValidDestinationSet(board).contains(board.getKing(enemy).getPos())){
                    return new Move(piece,p);
                }
            }
        }
        //hmmmm... What would I do if I was the enemy?
        if(!avoidStackOverflow){
            avoidStackOverflow = true;
            Board copy = board.copy();
            Move thinkingLikeTheEnemy = this.getMove(copy, this);
            avoidStackOverflow = false;
            Board newBoard = copy;
            //I wonder what piece it's targeting...
            Piece targeted =null;
            for(Piece p:pieces){
                if(p.getPos().getX()==thinkingLikeTheEnemy.getDestination().getX()&&p.getPos().getY()==thinkingLikeTheEnemy.getDestination().getY()){
                    targeted=p;
                }
            }
            //better move that piece out of the way, if it doesn't hurt my king
            if(targeted!=null){
                for(Point p:targeted.getValidDestinations(newBoard)){
                    newBoard = board.copy();
                    newBoard.movePiece(new Move(targeted,p));
                    for(Piece enemy2:enemy.getPieces(newBoard)){
                        if(!enemy2.getValidDestinationSet(newBoard).contains(p) && !newBoard.isCheck(this, enemy)){
                            return new Move(targeted,p);
                        }
                    }
                }
                newBoard.movePiece(new Move(targeted,thinkingLikeTheEnemy.getPiece().getPos()));
                if(!newBoard.isCheck(this, enemy)){
                    return new Move(targeted,thinkingLikeTheEnemy.getPiece().getPos());
                }
            }
        }

        //well, I guess this means I couldn't kill anything. Or put the enemy in check. And the enemy didn't have anything interesting to do
        //I guess I should just push a pawn or something
        for(Piece piece:pieces){
            if(piece.getType()==PieceType.PAWN){
                if(piece.getValidDestinationSet(board).size()>0){
                    return new Move(piece,piece.getValidDestinations(board)[0]);
                }
            }
        }
        //What!?!? No Pawns? guess I'll just move the first thing that comes to mind.
        for(Piece piece:pieces){
            if(piece.getValidDestinations(board).length>0){
                //providing that doesn't put my king in danger
                Board newBoard = board.copy();
                newBoard.movePiece(new Move(piece,piece.getValidDestinations(board)[0]));
                if(!newBoard.isCheck(this, enemy)){
                    return new Move(piece,piece.getValidDestinations(board)[0]);
                }
            }
        }
        //Oh no! I can make no moves that can save me from imminent death. Better hope for a miracle!
        for(Piece p:pieces){
            if(p.getValidDestinations(board).length>0){
                return new Move(p,p.getValidDestinations(board)[0]);
            }
        }
        //a miracle happened! (if it made it here)
        return null;
    }

}

การวิ่งเป็นศัตรูช่วยทำคะแนนหรือไม่?
ภูมิใจ haskeller

ไม่จริง แต่ดูดี! มันไม่เปลี่ยนคะแนนมากนัก แต่นั่นอาจเป็นเพราะการขาดความคล้ายคลึงกับบอทอื่น ๆ ของฉัน
ยืด Maniac

8

Three Move Monte

ผู้ชายคนนี้ดูการเคลื่อนไหวสามครั้งถัดไป (ของฉันคุณของฉัน) และเลือกการเคลื่อนไหวที่ให้คะแนนสูงสุด หากมีมากกว่า 60 ท่าเคลื่อนไหวก็จะเลือกสุ่ม 60 ในแต่ละขั้นตอน แน่นอนถ้าการย้ายครั้งเดียว (จากทั้งหมดนั้นไม่ใช่ 60 ที่เลือก) จะจบเกมฉันจะรับทันที

เพื่อให้คะแนนกระดานฉันให้ค่าพื้นฐานแต่ละชิ้น มันถูกดัดแปลงโดยความคล่องตัวของชิ้นส่วนจำนวนชิ้นส่วนที่คุกคามและจำนวนชิ้นส่วนที่คุกคาม

แน่นอนว่าราชามือถือไม่จำเป็นต้องดีในช่วงต้นเกมดังนั้นฉันจึงคิดค่าเล็กน้อยสำหรับพวกเขา

การดำเนินการนี้ค่อนข้างเร็วและสามารถจบเกมด้วยการครอบตัดปัจจุบันใน 3-4 วินาที ดูเหมือนว่ามีช่องว่างที่จะชนสองสามอย่างถ้าจำเป็น

อัปเดต:

  • เพิ่มคะแนนสำหรับ "ควบคุมศูนย์" ในเกมแรก
  • กรณีคะแนนกษัตริย์พิเศษ
  • แก้ไขข้อผิดพลาดสองคะแนนในการจำลองการย้าย
package player;

import java.util.*;
import pieces.*;
import controller.*;

public class ThreeMoveMonte extends Player{
    final static int TOSSES = 60;
    Random rand = new Random();

    @Override
    public Move getMove(Board board, Player them){
        List<Move> moves = getMoves(board, getTeam(), 0);
        for(Move move : moves)
            if(gameOver(apply(board, move)))
                return move;

        moves = getMoves(board, getTeam(), TOSSES);
        int highest = Integer.MIN_VALUE;
        Move best = moves.get(0);
        for(Move move : moves){
            Board applied = apply(board, move);
            Move oBest = getBestMove(applied, getOpponent(getTeam()), 0);
            applied = apply(applied, oBest);
            if(!gameOver(applied)){
                Move lBest = getBestMove(applied, getTeam(), TOSSES);
                Board lApplied = apply(applied, lBest);
                int score = eval(lApplied, getTeam());
                if(score > highest){
                    best = move;
                    highest = score;
                }
            }
        }
        return best;
    }

    boolean gameOver(Board board){
        Field[][] fields = board.getFields();
        int kings = 0;
        for(int x=0;x<fields.length;x++)
            for(int y=0;y<fields[x].length;y++){
                Piece p = fields[x][y].getPiece();
                if(p!=null&&p.getType().equals(PieceType.KING))
                    kings++;
            }
        return kings==2?false:true;
    }

    Move getBestMove(Board board, Color color, int breadth){
        int highest = Integer.MIN_VALUE;
        Move best = null;
        List<Move> moves = getMoves(board, color, breadth);
        for(Move move : moves){
            Board applied = apply(board, move);
            int score = eval(applied, color);
            if(score > highest){
                best = move;
                highest = score;
            }
        }
        return best;
    }

    List<Move> getMoves(Board board, Color color, int breadth){
        List<Move> moves = new ArrayList<Move>();
        Set<Piece> pieces = getPiecesOfColor(board, color);
        for(Piece piece : pieces){
            Set<Point> points = piece.getValidDestinationSet(board);
            for(Point point : points){
                moves.add(new Move(piece, point));
            }
        }
        Collections.shuffle(moves);
        if(breadth > 0)
            while(moves.size()>breadth)
                moves.remove(moves.size()-1);
        return moves;
    }

    Board apply(Board board, Move move){
        Board copy = board.copy();
        Piece piece = move.getPiece().copy();
        Point src = piece.getPos(); 
        Point dest = move.getDestination();
        if(piece.getType().equals(PieceType.PAWN)){
            if(piece.getTeam().equals(Color.WHITE)&&dest.getY()==7 || 
                    piece.getTeam().equals(Color.BLACK)&&dest.getY()==0)
                piece = new Queen(piece.getTeam(), piece.getPos());
        }
        piece.setPos(dest);
        copy.getFields()[src.getX()][src.getY()].setPiece(null);
        copy.getFields()[dest.getX()][dest.getY()].setPiece(piece);
        return copy;
    }

    int eval(Board board, Color color){
        int score = 0;
        List<Piece> mine = getPieces(board);
        Field[][] fields = board.getFields();
        for(Piece piece : mine){
            int value = getValueModified(board, piece);

            Set<Point> moves = piece.getValidDestinationSet(board);
            for(Point move : moves){
                int x = move.getX(),y=move.getY();
                if(fields[x][y].hasPiece()){
                    Piece other = fields[x][y].getPiece();
                    if(!other.getTeam().equals(getTeam()))
                        value += getValue(other) / (other.getType()==PieceType.KING ? 1 : 30); 
                }
                if(mine.size()>10)
                    value += (int)(8 - (Math.abs(3.5-x) + Math.abs(3.5-y)));
            }

            int attackerCount = getAttackers(board, piece, false).size();
            if(piece.getType()==PieceType.KING){
                if(attackerCount > 0)
                    value = -value;
            } else {
                for(int i=0;i<attackerCount;i++)
                    value = (value * 90) / 100;
            }
            score += value;
        }

        return score;
    }

    Set<Piece> getPiecesOfColor(Board board, Color color){
        Field[][] fields = board.getFields();
        Set<Piece> out = new HashSet<Piece>();
        for(int x=0;x<fields.length;x++){
            for(int y=0;y<fields[x].length;y++){
                Piece p = fields[x][y].getPiece();
                if(p!=null&&p.getTeam().equals(color))
                        out.add(p);
            }
        }
        return out;
    }

    Set<Piece> getAttackers(Board board, Piece piece, boolean all){
        Set<Piece> out = new HashSet<Piece>();
        Color color = piece.getTeam();
        Set<Piece> others = getPiecesOfColor(board, getOpponent(color));
        if(all)
            others.addAll(getPiecesOfColor(board, color));
        for(Piece other : others){
            if(other.getValidDestinationSet(board).contains(piece.getPos()))
                out.add(other);
        }
        return out;
    }

    Color getOpponent(Color color){
        return color.equals(Color.BLACK)?Color.WHITE:Color.BLACK;
    }

    int[] pieceValues = {100, 500, 300, 320, 880, 1500};
    int getValue(Piece piece){
        return pieceValues[piece.getType().ordinal()];
    }

    int[] maxMoves = {3, 14, 8, 13, 27, 8};
    int getValueModified(Board board, Piece piece){
        int moves = piece.getValidDestinationSet(board).size();
        double value = getValue(piece)*.9;
        double mod = getValue(piece)*.1*((double)moves/maxMoves[piece.getType().ordinal()]);
        if(piece.getType()==PieceType.KING)
            if(getPieces(board).size()>10)
                mod = -mod;

        return (int)(value + mod);
    }
}

เย็น! คุณสามารถใช้color.opposite()แทนgetOpponent();)
CommonGuy

@Manu ไม่ได้สังเกตวิธีการที่จะซื่อสัตย์ ฉันเขียนส่วนใหญ่เมื่อวานนี้ก่อนที่ตัวควบคุมจะได้รับการอัปเดตดังนั้นอาจมีวิธีการช่วยเหลืออื่น ๆ ที่ฉันสามารถใช้ได้แทนที่จะพยายามหลีกเลี่ยงการมองเห็นในขณะนี้: p
Geobits

@Manu Updated ควรจะกลับมาอยู่ด้านบนอีกครั้งสำหรับตอนนี้ :)
Geobits

5

AlphaBeta

ขออภัยที่มีรหัส morphed และ fused จากแหล่งอินเทอร์เน็ตอื่นในรหัส JAVA นี้ แต่มันก็ชนะคู่แข่งอื่น ๆ ทั้งหมด (รวมถึง PieceMaker) ... จนถึงตอนนี้

  • ไม่มีการย้ายคำสั่ง
  • ไม่มีการค้นหาความเงียบ
  • ไม่มีการประเมินตำแหน่ง
  • กำลังดุร้ายกำลังดิบของการค้นหาอัลฟาเบต้า
  • ใช้การวนซ้ำลึกลงเพื่อการบริหารเวลาเท่านั้น

และขออภัยในการเล่นเพื่อให้เครื่องน่าเบื่อ

package player;

import java.util.Random;
import controller.*;

public class AlphaBeta extends Player {
    private static final int INFINITY = Integer.MAX_VALUE;
    private static final int MAXTIME = 1800; // max time for evaluation
    private static final Random random=new Random();
    private static int seed=1;

    private long time; // time taken this turn
    private int iterativeDepth;
    private Player myOpponent;
    private int best, candidate;

    @Override
    public Move getMove(Board root, Player min) {
        time=System.currentTimeMillis();
        seed++; myOpponent=min; best=0;
        iterative_deepening(root);
        return allMoves(root, this)[best];
    }

    private void iterative_deepening(Board root) {
        try {
            for (iterativeDepth = 2;; iterativeDepth++) {
                alphaBeta(root, -INFINITY, +INFINITY, iterativeDepth, this, myOpponent);
                best=candidate;
            }
        } catch (InterruptedException e) {}
    }

    //http://chessprogramming.wikispaces.com/Alpha-Beta
    private int alphaBeta(Board root, int alpha, int beta, int d, Player max, Player min) throws InterruptedException {
        if ((System.currentTimeMillis() - time) > MAXTIME)  throw new InterruptedException();
        if (d==0 || root.getKing(max) == null) return evaluate(root, d);
        Move[] allMoves = allMoves(root, max);
        Move move;
        for (int m=0; (move = allMoves[m])!=null; m++) {
            Board board = root.copy();
            board.movePiece(move);
            int score = -alphaBeta(board, -beta, -alpha, d - 1, min, max);
            if (score >= beta)
                return beta; // fail hard beta-cutoff
            if (score > alpha) {
                alpha = score; // alpha acts like max in MiniMax
                if (d == iterativeDepth) candidate = m;
            }
        }
        return alpha;
    }

    private int evaluate(Board board, int d) {
        int minmax=2*((iterativeDepth-d)&1)-1;
        int value = 0, king=0;
        Field[][] field = board.getFields();
        for (int x = 0; x < 8; x++) {
            for (int y = 0; y < 8; y++) {
                Piece piece = field[x][y].getPiece();
                if (piece==null) continue;

                int sign=(piece.getTeam()==getTeam())?-minmax:minmax;
                switch (piece.getType()) {
                case PAWN:      value += 1*sign; break;
                case KNIGHT:    value += 3*sign; break;
                case BISHOP:    value += 3*sign; break;
                case ROOK:      value += 5*sign; break;
                case QUEEN:     value += 9*sign; break;
                case KING:      king  += (100-(iterativeDepth-d))*sign; break;
                default: // value += 0;
                }
            }
        }
        return king==0?value:king;
    }

    private Move[] allMoves(Board board, Player player) {
        random.setSeed(seed);
        Move[] move = new Move[200];
        int m=0;
        for (Piece piece : player.getPieces(board)) {
            for (Point point: piece.getValidDestinationSet(board)) {
                // shuffle
                int r=random.nextInt(++m);
                move[m-1]=move[r];
                move[r]=new Move(piece.copy(), point);
            }
        }
        return move;
    }       
}

5

ไม่ใช่คำตอบ แต่เป็นการจำลองสถานการณ์เพื่อช่วย

ฉันเพิ่มคลาสใหม่: GamePanel และแก้ไขเกมและคอนโทรลเลอร์

มันยังไม่สวยมาก ... คุณรู้หรือไม่ว่า Unicode มีตัวละครหมากรุก!?!? (สุดยอดไปเลย!)
อย่างไรก็ตามคุณต้องมี UTF-8 เพื่อให้ตัวละครเหล่านี้แสดง มันใช้งานได้สำหรับฉัน แต่ไม่แน่ใจว่าจะทำงานกับระบบปฏิบัติการอื่นได้อย่างไร

แก้ไขข้อบกพร่องในตอนท้ายของเกม (ขอบคุณ tim สำหรับการชี้ให้เห็น)

GamePanel:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.ArrayList;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GamePanel extends JPanel{
    private static final long serialVersionUID = 1L;
    JFrame container;
    Board currentBoard;
    Game currentGame;
    ArrayList<Game> games;
    public GamePanel(ArrayList<Game> Games){
        games = Games;
        currentGame = games.get(0);
        currentBoard = currentGame.allBoards.get(0);
        container = new JFrame();
        container.setSize(new Dimension(500,500));
        container.setMinimumSize(new Dimension(150,150));
        this.setMinimumSize(new Dimension(150,150));
        JButton skipButton = new JButton("skip game");
        skipButton.addMouseListener(new MouseListener(){
            @Override
            public void mouseClicked(MouseEvent arg0) {
                nextGame();
            }
            @Override
            public void mouseEntered(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mouseExited(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mousePressed(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mouseReleased(MouseEvent arg0) {
                // TODO Auto-generated method stub

            }

        });
        JButton undoButton = new JButton("go back");
        undoButton.addMouseListener(new MouseListener(){
            @Override
            public void mouseClicked(MouseEvent e) {
                unStep();
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mouseExited(MouseEvent e) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mousePressed(MouseEvent e) {
                // TODO Auto-generated method stub

            }
            @Override
            public void mouseReleased(MouseEvent e) {
                // TODO Auto-generated method stub

            }

        });
        JButton continueButton = new JButton("continue");
        undoButton.setSize(40,40);
        skipButton.setSize(40,40);
        continueButton.setSize(40,40);
        continueButton.addMouseListener(new MouseListener(){
            @Override
            public void mouseClicked(MouseEvent arg0) {
                step();
            }
            @Override
            public void mouseEntered(MouseEvent arg0) { 
            }
            @Override
            public void mouseExited(MouseEvent arg0) {  
            }
            @Override
            public void mousePressed(MouseEvent arg0) {     
            }
            @Override
            public void mouseReleased(MouseEvent arg0) {    
            }
        });
        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout());
        buttonPanel.add(continueButton);
        buttonPanel.add(undoButton);
        buttonPanel.add(skipButton);
        container.setLayout(new BorderLayout());
        container.getContentPane().add(this,BorderLayout.CENTER);
        container.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        container.getContentPane().add(buttonPanel,BorderLayout.NORTH);
        container.setTitle("White: " + currentGame.players[0].getClass().getSimpleName() 
                + " vs "+ "Black: " + currentGame.players[1].getClass().getSimpleName());
        container.setVisible(true);
        container.invalidate();
        container.repaint();
    }
    private void unStep(){
        if(currentBoard!=currentGame.allBoards.get(0)){
            currentBoard=currentGame.allBoards.get(currentGame.allBoards.indexOf(currentBoard)-1);
        }
        container.invalidate();
        container.repaint();
    }
    private void unGame(){
        if(currentGame != games.get(0)){
            currentGame = games.get(games.indexOf(currentGame)-1);
            currentBoard = currentGame.allBoards.get(0);
        }
        container.invalidate();
        container.repaint();
    }
    private void step(){
        if(currentGame.allBoards.indexOf(currentBoard)==currentGame.allBoards.size()-1){
            nextGame();
        }
        else{
            currentBoard = currentGame.allBoards.get(currentGame.allBoards.indexOf(currentBoard)+1);
        }
        container.invalidate();
        container.repaint();
    }
    private void nextGame(){
        container.setTitle("White: " + currentGame.players[0].getClass().getSimpleName() 
                + " vs "+ "Black: " + currentGame.players[1].getClass().getSimpleName());
        if(currentGame != games.get(games.size()-1)){
            currentGame = games.get(games.indexOf(currentGame)+1);
        }
        else{
            //games complete
            container.dispose();
        }
        currentBoard = currentGame.allBoards.get(0);
        container.invalidate();
        container.repaint();
    }
    @Override
    public void paintComponent(Graphics g){
        if(getWidth()>150 && getHeight() > 150){
        int leftBounds,topBounds,width,height;
        topBounds = 50;
        leftBounds = 50;
        if(getWidth() > getHeight()){
            width = (int) (getHeight()-100);
            height = (int) (getHeight()-100);
        }
        else{
            width = (int) (getWidth()-100);
            height = (int) (getWidth()-100);
        }
        //draw grid
        java.awt.Color dark = new java.awt.Color(128, 78, 41);
        java.awt.Color light = new java.awt.Color(250, 223, 173);
        Field[][] feilds = currentBoard.getFields();
        for(int x = leftBounds; x < leftBounds+width-width/8; x+=width/8){
            for(int y = topBounds; y < topBounds+height-height/8; y+=height/8){
                int xPos = (int)Math.round(((double)(x-leftBounds)/(double)width)*8);
                int yPos = (int)Math.round(((double)(y-topBounds)/(double)height)*8);
                String piece = "";
                java.awt.Color stringColor = java.awt.Color.black;
                if(feilds[xPos][yPos].hasPiece()){
                    piece = getPiece(feilds[xPos][yPos].getPiece());
                    if(feilds[xPos][yPos].getPiece().getTeam()==Color.WHITE){stringColor = java.awt.Color.WHITE;}
                }
                if(yPos % 2 == 1){
                    if(xPos % 2 == 1){
                        g.setColor(dark);
                        g.fillRect(x, y, width/8, height/8);
                    }
                    else{
                        g.setColor(light);
                        g.fillRect(x, y, width/8, height/8);
                    }
                }
                else{
                    if(xPos % 2 == 1){
                        g.setColor(light);
                        g.fillRect(x, y, width/8, height/8);
                    }
                    else{
                        g.setColor(dark);
                        g.fillRect(x, y, width/8, height/8);
                    }
                }
                g.setColor(java.awt.Color.black);
                g.setFont(new Font(Font.SANS_SERIF, Font.BOLD, width/8));
                g.drawString(piece, x, y+width/8);
            }
        }
        }

    }
    public String getPiece(Piece p){
        if(p.getTeam() == Color.WHITE){
            if(p.getType() == PieceType.BISHOP){return "\u2657";}
            if(p.getType() == PieceType.PAWN){return "\u2659";}
            if(p.getType() == PieceType.KING){return "\u2654";}
            if(p.getType() == PieceType.QUEEN){return "\u2655";}
            if(p.getType() == PieceType.ROOK){return "\u2656";}
            if(p.getType() == PieceType.KNIGHT){return "\u2658";}
        }
        else{
            if(p.getType() == PieceType.BISHOP){return "\u265D";}
            if(p.getType() == PieceType.PAWN){return "\u265F";}
            if(p.getType() == PieceType.KING){return "\u265A";}
            if(p.getType() == PieceType.QUEEN){return "\u265B";}
            if(p.getType() == PieceType.ROOK){return "\u265C";}
            if(p.getType() == PieceType.KNIGHT){return "\u265E";}
        }
        return p.toString();
    }

}

เกม:

import java.util.ArrayList;

public class Game {
    private static final int MAX_TURNS_WITHOUT_CAPTURES = 100; //=50, counts for both teams
    private static final int MAX_MILLISECONDS = 2000;
    private Board board;
    Player[] players = new Player[2];
    private int turnsWithoutCaptures = 0;
    private boolean draw = false;
    ArrayList<Board> allBoards = new ArrayList<Board>();

    public Game(Player player1, Player player2) {
        board = new Board();
        board.initialize();
        players[0] = player1;
        players[0].setTeam(Color.WHITE);
        players[1] = player2;
        players[1].setTeam(Color.BLACK);
        allBoards.add(board.copy());
    }
    int run() {
        int i = 0;
        while (!gameOver()) {
            if (!turnAvailable(players[i])) {
                draw = true;
            } else {
                makeTurn(players[i], players[(i+1) % 2]);
                i = (i + 1) % 2;
            }
        }
        if (loses(players[0]) && !loses(players[1])) {
            return Controller.LOSE_POINTS;
        } else if (loses(players[1]) && !loses(players[0])) {
            return Controller.WIN_POINTS;
        } else {
            return Controller.DRAW_POINTS;
        }
    }

    private boolean loses(Player player) {
        if (player.isDisqualified() || board.getKing(player) == null) {
            return true;
        }
        return false;
    }

    // player can make a turn
    private boolean turnAvailable(Player player) {
        for (Piece piece : player.getPieces(board)) {
            if (piece.getValidDestinationSet(board).size() > 0) {
                return true;
            }
        }
        return false;
    }

    private void makeTurn(Player player, Player enemy) {
        player.setCheck(board.isCheck(player, enemy));
        enemy.setCheck(board.isCheck(enemy, player));
        try {
            long start = System.currentTimeMillis();

            Move move = player.getMove(board.copy(), enemy);
            if ((System.currentTimeMillis() - start) > MAX_MILLISECONDS) {
                player.setDisqualified();
            }
            if (move.isValid(board, player)) {
                if (board.movePiece(move) || move.getPiece().getType() == PieceType.PAWN) {
                    turnsWithoutCaptures = 0;
                } else {
                    turnsWithoutCaptures++;
                }
            } else {
                player.setDisqualified(); //invalid move
            }
        } catch (Exception e) {
            player.setDisqualified();
            e.printStackTrace();
            System.out.println("Exception while moving " + player);
        }
        allBoards.add(board.copy());
    }
    public boolean gameOver() {
        for (Player player : players) {
            if (player.isDisqualified() || board.getKing(player) == null
                    || turnsWithoutCaptures >= MAX_TURNS_WITHOUT_CAPTURES || draw) {
                return true;
            }
        }
        return false;
    }
}

ควบคุม:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import players.*;

public class Controller {
    public static final int WIN_POINTS = 3;
    public static final int DRAW_POINTS = 1;
    public static final int LOSE_POINTS = 0;
    private static final int GAMES_PER_PAIR = 10;
    private final Class[] classes = {StretchPlayer.class,TestPlayer.class};
    private final Map<Class<? extends Player>, Integer> scores = new HashMap<Class<? extends Player>, Integer>();

    public static void main(String... args) {
        new Controller().generateResult();
    }

    public Controller() {
        for (Class player : classes) {
            scores.put(player, 0);
        }
    }
    ArrayList<Game> games = new ArrayList<Game>();
    private void generateResult() {

        for (int i = 0; i < classes.length - 1; i++) {
            for (int j = i + 1; j < classes.length; j++) {
                for (int k = 0; k < GAMES_PER_PAIR; k++) {
                    runGame(classes[i], classes[j], k>=GAMES_PER_PAIR);
                }
            }
        }
        GamePanel panel = new GamePanel(games);
        printScores();
    }

    private void runGame(Class class1, Class class2, boolean switchSides) {
        if (switchSides) { //switch sides
            Class tempClass = class2;
            class2 = class1;
            class1 = tempClass;
        }
        try {
            Player player1 = (Player) class1.newInstance();
            Player player2 = (Player) class2.newInstance();
            Game game = new Game(player1, player2);
            games.add(game);
            int result = game.run();
            addResult(class1, result, false);
            addResult(class2, result, true);
        } catch (Exception e) {
            System.out.println("Error in game between " + class1 + " and " + class2);
        }
    }

    private void addResult(Class player, int result, boolean reverse) {
        if (reverse) {
            if (result == WIN_POINTS) {
                result = LOSE_POINTS;
            } else if (result == LOSE_POINTS) {
                result = WIN_POINTS;
            }
        }
        int newScore = scores.get(player) + result;
        scores.put(player, newScore);
    }

    private void printScores() {
        int bestScore = 0;
        Class currPlayer = null;
        int place = 1;

        while (scores.size() > 0) {
            bestScore = 0;
            currPlayer = null;
            for (Class player : scores.keySet()) {
                int playerScore = scores.get(player);
                if (scores.get(player) >= bestScore) {
                    bestScore = playerScore;
                    currPlayer = player;
                }
            }
            System.out.println(String.format("%02d", place++) + ") " + currPlayer + ": " + bestScore);
            scores.remove(currPlayer);
        }
    }
}

ขอบคุณนี่มันเรียบร้อยดี แค่สองคนคิดว่า: คุณลืมที่จะลบSimulationListenerและถ้าไม่มีเกมอีกข้อยกเว้นจะถูกโยน และฉันจะได้ใส่สีขาวที่ด้านล่าง แต่ผมคิดว่าผลงานในแบบของคุณได้เป็นอย่างดี :)
ทิม

4

DontThinkAhead

'AI' นี้ไม่ชอบคิดล่วงหน้า หากเห็นว่าสามารถจับชิ้นส่วนศัตรูมันจะทำทันที หากไม่สามารถทำได้ก็จะย้ายชิ้นโดยการสุ่ม

มันดีกว่าSimplePlayerและTestPlayerฉันเขียนไว้เพื่อทำความเข้าใจกับโค้ดคอนโทรลเลอร์และมีบางอย่างที่ต้องทดสอบ

package player;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Random;

import controller.*;
/**
 * Thinking ahead is hard, so lets not do it.
 */
public class DontThinkAhead extends Player {

    @Override
    public Move getMove(Board board, Player enemy) {
        List<Move> moves = new ArrayList<>();
        List<Piece> pieces = this.getPieces(board);
        for (Piece piece : pieces) {
            Point[] destinations = piece.getValidDestinations(board);
            for (Point point : destinations) {
                moves.add(new Move(piece, point));
            }
        }

        List<Node> ratedMoves = new ArrayList<>();
        for (Move move : moves) {
            Point dest = move.getDestination();
            Field destField = board.getFields()[dest.getX()][dest.getY()];

            if (destField.hasPiece()) {
                int rating = 0;
                PieceType type = destField.getPiece().getType();
                switch (type) {
                case PAWN:
                    rating = 1;
                    break;
                case KNIGHT:
                    rating = 3;
                    break;
                case BISHOP:
                    rating = 3;
                    break;
                case ROOK:
                    rating = 5;
                    break;
                case QUEEN:
                    rating = 9;
                    break;
                case KING:
                    rating = 9999;
                    break;
                default:
                    rating = 0;
                }
                ratedMoves.add(new Node(move, rating));
            }           
        }

        if (!ratedMoves.isEmpty()) {
            Collections.sort(ratedMoves, new ComparatorNode());
            return ratedMoves.get(0).getMove();
        } else {
            // no good move possible, return random move
            return moves.get(new Random().nextInt(moves.size()));
        }
    }

    private class Node {
        private Move move;
        private int rating;

        public Node(Move move, int rating) {
            this.move = move;
            this.rating = rating;
        }

        public int getRating() {
            return rating;
        }

        public Move getMove() {
            return move;
        }
    }

    private class ComparatorNode implements Comparator<Node> {

        @Override
        public int compare(Node t, Node t1) {
            return t1.getRating() - t.getRating();
        }
    }
}

2

ชีส

ใช่คุณอ่านถูกต้อง บล็อกของชีสเล่นหมากรุก

ขั้นตอนวิธี

ชีสจะตรวจสอบการเคลื่อนไหวที่เป็นไปได้ทั้งหมดและให้คะแนนตามนั้น เขา (ชีสและใช่มันเป็นชาย) ใช้แนวทางต่อไปนี้เพื่อให้คะแนนตัวเลือกของเขา:

การรับประทานอาหาร

  • King = มากกว่า 9000 !!!!!!!!!!
  • Queen = 18
  • โกง = 10
  • บิชอป = 6
  • อัศวิน = 6
  • จำนำ = 2

เสี่ยงต่อการรับประทาน

  • King = ต่ำกว่า -9000 !!!!!!!!!!!
  • Queen = -16
  • โกง = -8
  • บิชอป = -5
  • อัศวิน = -5
  • จำนำ = 0

มีโอกาสกินครั้งต่อไป

  • King = 5
  • Queen = 3
  • โกง = 2
  • บิชอป = 1
  • อัศวิน = 1
  • จำนำ = 0

รอการปรับปรุง

  • ไม่เพียงพอ SWAG (จะตรวจสอบความเป็นไปได้นี้เร็ว ๆ นี้)
  • ฉันตรวจสอบเวลาแล้วและดูเหมือนว่าฉันทำงานใน 0-1 มิลลิวินาที ฉันคิดว่าฉันสามารถก้าวร้าวมากขึ้นด้วยอัลกอริทึมของฉัน

แก้ไขบั๊กแล้ว

  • เมื่อตรวจสอบคะแนนสำหรับเป้าหมายที่เป็นไปได้ที่จะกินฉันนับหน่วยของตัวเอง ตอนนี้ผมก็แค่คะแนนถ้าฉันสามารถกินชิ้นศัตรู
package player;

import pieces.Queen;
import controller.*;

public class Cheese extends Player {
    private final int[] eatingPriorities = { 9999, 18, 10, 6, 6, 2, 0 };
    private final int[] gettingEatenPriorities = { -9000, -16, -8, -5, -5, 0, 0 };
    private final int[] chanceToEatPriorities = {5,3,2,1,1,0,0};

    @Override
    public Move getMove(Board board, Player enemy) {
        int maxScore = -10000;
        Move bestMove = null;

        int score = 0;

        Field[][] field = board.getFields();
        Field fieldDest;

        // get best move
        for (Piece myPiece : this.getPieces(board)) {
            for (Point possibleDest : myPiece.getValidDestinationSet(board)) {
                score=0;
                fieldDest = field[possibleDest.getX()][possibleDest.getY()];

                //if you're eating an enemy piece, SCORE!
                if(fieldDest.hasPiece() && fieldDest.getPiece().getTeam()!=this.getTeam()){
                    score += eatingPriorities[getPriorityIndex(fieldDest.getPiece().getType())];
                }
                score+=getAftermoveRisk(board, enemy, new Move(myPiece, possibleDest));
                if (maxScore < score) {
                    maxScore = score;
                    bestMove = new Move(myPiece,possibleDest);
                }
            }
        }

        return bestMove;
    }

    private int getAftermoveRisk(Board board, Player enemy, Move move){
        int gettingEatenRisk=0, chanceToEatScore=0;
        Field[][] simField;
        Field field;
        Board simBoard = board.copy();

        simField = simBoard.getFields();
        this.simulateMovePiece(simField, move);

        //gettingEaten risk
        for (Piece enemyPiece : enemy.getPieces(simBoard)) {
            for (Point possibleDest : enemyPiece.getValidDestinationSet(simBoard)) {
                field = simField[possibleDest.getX()][possibleDest.getY()];

                //if it's my piece that's in the line of fire, increase gettingEatenRisk
                if(field.hasPiece() && field.getPiece().getTeam()==this.getTeam()){
                    gettingEatenRisk += gettingEatenPriorities[getPriorityIndex(field.getPiece().getType())];
                }
            }
        }

        //chanceToEat score
        for (Piece myPiece : this.getPieces(simBoard)) {
            for (Point possibleDest : myPiece.getValidDestinationSet(simBoard)) {
                field = simField[possibleDest.getX()][possibleDest.getY()];

                //if it's their piece that's in the line of fire, increase chanceToEatScore
                if(field.hasPiece() && field.getPiece().getTeam()!=this.getTeam()){
                    chanceToEatScore += chanceToEatPriorities[getPriorityIndex(field.getPiece().getType())];
                }
            }
        }

        return gettingEatenRisk + chanceToEatScore;
    }

    // Copied and edited from Board.movePiece
    public void simulateMovePiece(Field[][] fields, Move move) {
        Piece piece = move.getPiece();
        Point dest = move.getDestination();
        if (!dest.isOutside()) {
            // upgrade pawn
            if (piece.getType() == PieceType.PAWN && (dest.getY() == 0 || dest.getY() == 7)) {
                fields[dest.getX()][dest.getY()].setPiece(new Queen(piece.getTeam(), dest));
            } else {
                fields[dest.getX()][dest.getY()].setPiece(piece);
            }
            //remove piece on old field
            fields[piece.getPos().getX()][piece.getPos().getY()].setPiece(null);
        }
    }

    private int getPriorityIndex(PieceType type) {
        int index = 0;
        switch (type) {
        case KING:
            index = 0;
            break;
        case QUEEN:
            index = 1;
            break;
        case ROOK:
            index = 2;
            break;
        case BISHOP:
            index = 3;
            break;
        case KNIGHT:
            index = 4;
            break;
        case PAWN:
            index = 5;
            break;
        default:
            index = 6;
        }
        return index;
    }

}

ด้วยรหัสนี้ดูเหมือนว่าคุณจะสูญเสียราชินีอย่างยินดีที่จะรับจำนำ ดูเหมือนจะไม่ถูกต้องนัก
overactor

ใช่ฉันยังคงปรับเปลี่ยนค่าลำดับความสำคัญ ขอบคุณที่นำสิ่งนั้นขึ้น :)
Mark Gabriel

2

SimplePlayer

ผู้เล่นนี้ทำให้แน่ใจว่าเขาใช้ท่าที่ถูกต้อง แต่อย่างอื่นนั้นค่อนข้างโง่

package player;

import java.util.List;
import controller.*;

public class SimplePlayer extends Player {

    @Override
    public Move getMove(Board board, Player enemy) {
        //get all pieces of this player
        List<Piece> pieces = this.getPieces(board);
        for (Piece piece : pieces) {
            Point[] destinations = piece.getValidDestinations(board);
            if (destinations.length > 0) {
                return new Move(piece, destinations[0]);
            }
        }

        //should never happen, because the game is over then
        return null;
    }

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.