Antichess oyna!


19

https://en.wikipedia.org/wiki/Losing_chess

Bu temelde Satranç Turnuvasıdır , ancak alçaklık için;)

Antichess, icat edilmiş birçok satranç çeşidinden biridir . Amaç tüm parçalarınızı kaybetmektir (bu biraz garip görünebilir, ancak bir sebepten dolayı antijenlik denir).

Kurallar

Anticess kuralları standart satranca çok benzer - ancak birkaç küçük farkla. Yukarıda bahsettiğim gibi amaç tüm taşlarınızı kaybetmektir. Bunu gerçekleştirmek için rakibinizin taşlarınızdan birini yakalama fırsatı varsa, yapabileceği tek hareket budur. Ona bir turda birden fazla şans verirseniz, diğer oyuncu sırası seçebilir. Değişen bir başka şey de, kralın özel güçleri olmamasıdır - içinde olduğu gibi rakibinizi kontrol edemezsiniz ve onu kontrol etmeye zorlayamazsınız.

Standart oyunda aşağıdaki değişiklikler de geçerli olacaktır (oyunu basitleştirmeye yardımcı olurlar):

  • Yolcu yok sayılır.
  • Rolling mümkün değil.
  • Elli hamle kuralı otomatik olarak (berabere oyun biter anlamında) geçerlidir.
  • Piyonlar neye teşvik ettiklerini seçebilecekler.
  • Bir oyuncunun taşınması için 2 saniyeden daha uzun sürmesi gerekiyorsa oyunu kaybeder.
  • Geçersiz bir hamle geri dönmek oyunu kaybetmenize neden olur.
  • Kazanmak için rakiplerinizin tüm taşlarını yakalaması gerekir .
  • Beyaz oyuna başlar.
  • Beyaz alanın "altına" (y = 0), siyah ise üstüne (y = 7) yerleştirilir.
  • Botunuzdan (internet, dosyalar, diğer botlar, ...) başka kaynaklara erişmek yasaktır.

puanlama

  • Kazanan size 3 puan, 1 beraberlik ve 0 puan kaybeder.
  • Her sunum birbiriyle 10 kez oynar (5 kez beyaz, 5 siyah).

Botunuzu yazma

Denetleyici kodu burada: https://github.com/JJ-Atkinson/SimpleAntichessKOTH

Botunuzu Java veya Groovy ile yazabilirsiniz. Bir bot yazmak için Playersınıfı genişletmelisiniz . Oyuncu sınıfının bir soyut yöntemi vardır Move getMove(Board board, Player enemy, Set<Move> validMoves).

İşte yararlı yöntemler hakkında hızlı bir özet:

Player:

  • List<Piece> getPieces(Board board): Tahtadaki tüm parçalarınızı iade edin.
  • PieceUpgradeType pieceUpgradeType: Piyonlarınızdan biri tahtanın sonuna ulaştığında / ulaştığında, bunu yükseltmek istediğiniz parça türüne göre tanımlamanız gerekir. Sen seçimi var ROOK, KNIGHT, QUEEN, BISHOP, ve KING.

Board:

  • Field getFieldAtLoc(Location loc): Konumuna geri dönün Field. Bu uygun bir getAtyöntem vardır, böylece groovy kullanıyorsanız yazabilirsiniz board[loc].
  • Field getFieldAtLoc(int x, int y): Konumuna geri dönün Field. Bu uygun bir getAtyöntem vardır, böylece groovy kullanıyorsanız yazabilirsiniz board[x, y].
  • Board movePiece(Player player, Move move): Tahtada nasıl hareket edeceğini görebilmek için bir hamle yap. Yeni kartı döndürür.

Rakiplerinizin parçalarını görmek istiyorsanız, yazın enemy.getPieces(board). Botunuzu dizilişe eklemek için şu satırı ekleyin PlayerFactory:

put(YourBot.class, { new YourBot() } )

Botunuzda hata ayıklama:

Botlarınızın hata ayıklamasına yardımcı olacak birkaç araç ekledim. Oyununuzun canlı oynandığını görmek için Game#DEBUGbayrağı true olarak ayarlayabilirsiniz . Bunun gibi bir çıktı alırsınız:

Game started. Players: [OnePlayBot(WHITE), SacrificeBot(BLACK)]
...
BLACKs turn.
validMoves: [Move(Piece(BLACK, PAWN, Loc(0, 6)), Loc(0, 5)), ...]
board:
RKBQIBKR
PPPPPPPP
--------
--------
--------
p-------
-ppppppp
rkbqibkr

captureless turns: 1
chosen move: Move(Piece(BLACK, PAWN, Loc(7, 6)), Loc(7, 4))
Game over? false

==============================

WHITEs turn.
validMoves: [Move(Piece(WHITE, ROOK, Loc(0, 0)), Loc(0, 1)), ...]
board:
RKBQIBKR
PPPPPPP-
--------
-------P
--------
p-------
-ppppppp
rkbqibkr

...

(Beyaz büyük harf, kral ile gösterilir i)

Konsolunuz utf-8 özel karakterlerini destekliyorsa, tahtayı satranç karakterleriyle aşağıdakileri kullanarak da gösterebilirsiniz Board#USE_UTF8_TO_STRING:

♜♞♝♛♚♝—♜
♟—♟♟♟♟♟♟
————————
—♟——————
————————
♙———————
—♙♙♙♙♔♙♙
♖♘♗♕—♗♘♖

(tek aralıklı yazı tipiyle daha iyi görünür)

İstenmeyen çıktıların taşmasını önlemek için Main#mainişlevi aşağıdaki gibi bir şeye değiştirmelisiniz :

new Game(new MyBot(), new SacrificeBot()).run()

Beyaz olarak oynamak için botunuzu sola, siyah olarak oynamak için sağa koyun.

Kontrolörün oluşturulması:

Denetleyici harika yazılmıştır, bu nedenle java ve groovy yüklü olmalıdır. Harika yüklemek istemiyorsanız, denetleyiciyle birlikte gelen kepçe oluşturma dosyasını kullanabilirsiniz (bu test edilmemiştir). Groovy veya gradle kullanmak istemiyorsanız en son sürüm kavanozunu kullanabilirsiniz ( https://github.com/JJ-Atkinson/SimpleAntichessKOTH/releases ). Bunu yaparsanız, kendi mainyönteminizi yapmanız ve botunuzu manuel olarak oyuncu fabrikasına eklemeniz gerekir. Misal:

PlayerFactory.players.put(YourBot.class, { new YourBot() } )
new Runner().runGames();

(Yine de hata ayıklama bayraklarını ve öğelerini ayarlayabileceğinizi unutmayın)

Herhangi bir hata bulma takdir edilmektedir!

Skorlar:

SearchBot -> 101
SacrificeBot -> 81
MeasureBot -> 37
RandomBot -> 28
OnePlayBot -> 24

Her zaman yeni gönderimler yapmaya hazır olduğumu lütfen unutmayın!


Eğer groovy ve IntelliJ'i seviyorsanız ... Kotlin
TheNumberOne'a

Kotlin'i daha önce görmüştüm, ama ona hiç bakmadım. Bu bir scala / groovy mashup gibi görünüyor (ama Tamam - groovy ve scala benim en sevdiğim diller;)
J Atkin

Daha önce hiç scala kullanmadım ... ama Kotlin kodunu java'dan aramak java'dan goovy kodunu aramaktan çok daha kolay.
TheNumberOne

1
Bir krala yükseltebilir misin?!? Kesinlikle hayır ...
wizzwizz4

1
@ wizzwizz4 Antichess'te yapabilirsiniz.
ProgramFOX

Yanıtlar:


6

SearchBot

Şimdiye kadar en yavaş bot, ancak hareket başına 2 saniyeden daha hızlı ve şu anda yayınlanan tüm botları yeniyor. Geçerli hamlelerin herhangi birinden sonra ne olduğuna ve bu hamlelerden sonra herhangi bir hamleden sonra ne olabileceğine bakar ve en iyi sonucun ne olacağına karar verir. Ne yazık ki daha derin arama yapamıyor çünkü o zaman 2 saniyeden fazla sürecek.

package com.ppcgse.koth.antichess.player

import com.ppcgse.koth.antichess.controller.Board
import com.ppcgse.koth.antichess.controller.Color
import com.ppcgse.koth.antichess.controller.Location
import com.ppcgse.koth.antichess.controller.Move
import com.ppcgse.koth.antichess.controller.Piece
import com.ppcgse.koth.antichess.controller.PieceType
import com.ppcgse.koth.antichess.controller.PieceUpgradeType
import com.ppcgse.koth.antichess.controller.Player

import groovy.lang.Tuple

/**
 * Created by ProgramFOX on 12/22/15.
 */

 class SearchBot extends Player {
    {pieceUpgradeType = PieceUpgradeType.KING}

    @Override
    Move getMove(Board board, Player opponent, Set<Move> validMoves) {
        return getMoveInternal(board, this, opponent, validMoves, 2)[0]
    }

    Tuple getMoveInternal(Board board, Player whoseTurn, Player opponent, Set<Move> validMoves, Integer depth) {
        def bestScore = null
        def currentlyChosenMove = null
        validMoves.each { m ->
            def opponentPiecesValueBefore = opponent.getPieces(board).sum { getPieceValue(it.getType()) }
            def newBoard = board.movePiece(whoseTurn, m)
            def opponentPiecesValueAfter = opponent.getPieces(newBoard).sum { getPieceValue(it.getType()) }
            if (opponentPiecesValueAfter == null) {
                opponentPiecesValueAfter = 0
            }
            def score = opponentPiecesValueAfter - opponentPiecesValueBefore
            if (whoseTurn.getTeam() == Color.BLACK) {
                score = -score
            }
            if (depth > 1) {
                def validMovesNow = genValidMoves(opponent, whoseTurn, newBoard)
                def goDeeper = true
                if (validMovesNow == null || validMovesNow.size() == 0) {
                    def toAdd = -999
                    if (whoseTurn.getTeam() == Color.BLACK) {
                        toAdd = -toAdd
                    }
                    score += toAdd
                    goDeeper = false
                }
                if (goDeeper) {
                    score += getMoveInternal(newBoard, opponent, whoseTurn, validMovesNow, depth - 1)[1]
                }
            }
            if (bestScore == null) {
                bestScore = score
                currentlyChosenMove = m
            }
            if ((whoseTurn.getTeam() == Color.WHITE && score > bestScore) || (whoseTurn.getTeam() == Color.BLACK && score < bestScore))  {
                bestScore = score
                currentlyChosenMove = m
            }
        }
        return new Tuple(currentlyChosenMove, bestScore)
    }

    Double getPieceValue(PieceType pieceType) {
        switch (pieceType) {
            case PieceType.KING:
                return 1
            case PieceType.PAWN:
                return 1.5
            case PieceType.KNIGHT:
                return 2.5
            case PieceType.BISHOP:
                return 3
            case PieceType.ROOK:
                return 5
            case PieceType.QUEEN:
                return 9
            default:
                return 0
        }
    }

    // Copied from Game.groovy and a bit modified.
    // I actually need this.
    Set<Move> genValidMoves(Player player, Player enemy, Board board) {
        def allMoves = player.getPieces(board).collect { [it, it.getValidDestinationSet(board)] }
        def attackMoves = allMoves
                .collect { pair ->
            def piece = pair[0]
            def dests = pair[1]
            [piece, dests.findAll { board.getFieldAtLoc(it as Location)?.piece?.team == enemy.team }]
        }.findAll { it[1] }

        if (attackMoves.isEmpty())
            return allMoves.collect {
                Piece piece = it[0] as Piece
                return it[1].collect { loc -> new Move(piece, loc as Location) }
            }.flatten() as Set<Move>
        else
            return attackMoves.collect {
                Piece piece = it[0] as Piece
                return it[1].collect { loc -> new Move(piece, loc as Location) }
            }.flatten() as Set<Move>
    }
 }

4

SacrificeBot

Bu bot, diğer oyuncunun sahip olduğu tüm hareketleri kontrol eder ve herhangi birinin kesişip kesişmediğini kontrol eder (yani parça öldürülecek). (Bu beklediğimden çok daha iyi bir heck yapar;)

package com.ppcgse.koth.antichess.player

import com.ppcgse.koth.antichess.controller.Board
import com.ppcgse.koth.antichess.controller.Color
import com.ppcgse.koth.antichess.controller.Location
import com.ppcgse.koth.antichess.controller.Move
import com.ppcgse.koth.antichess.controller.Piece
import com.ppcgse.koth.antichess.controller.PieceType
import com.ppcgse.koth.antichess.controller.PieceUpgradeType
import com.ppcgse.koth.antichess.controller.Player

import java.util.concurrent.ThreadLocalRandom

/**
 * Created by Jarrett on 12/19/15.
 */
class SacrificeBot extends Player {

    {pieceUpgradeType = PieceUpgradeType.ROOK}

    @Override
    Move getMove(Board board, Player enemy, Set<Move> validMoves) {
        def enemyPieces = enemy.getPieces(board)
        def pawnMoves = getPawnsMoves(board, enemyPieces)
        def enemyPlayerValidMoves = (enemyPieces
                                        .collect { it.getValidDestinationSet(realBoard) }
                                        .flatten() as List<Location>)
        enemyPlayerValidMoves += pawnMoves

        def sacrificeMove = validMoves
                                .find {enemyPlayerValidMoves.contains(it.destination)}

        if (sacrificeMove)
            return sacrificeMove
        else
            return randomMove(validMoves)
    }

    def randomMove(Set<Move> validMoves) {
        return validMoves[ThreadLocalRandom.current().nextInt(validMoves.size())];
    }

    def getPawnsMoves(Board board, List<Piece> allPieces) {
        def direction = getTeam() == Color.BLACK ? 1 : -1;
        def pawns = allPieces.findAll {it.type == PieceType.PAWN}
        def pawnAttacks = (pawns.collect {
                                    [it.loc.plus(-1, direction), it.loc.plus(1, direction)]
                                }.flatten()
                                ).findAll {
                                    ((Location) it).isValid()
                                }
        return pawnAttacks as List<Location>
    }
}

3

OnePlayBot

Sadece bir oyun ile ölü basit bot. Bir kaleye yükselecek.

package com.ppcgse.koth.antichess.player

import com.ppcgse.koth.antichess.controller.Move
import com.ppcgse.koth.antichess.controller.PieceUpgradeType
import com.ppcgse.koth.antichess.controller.Player
import com.ppcgse.koth.antichess.controller.ReadOnlyBoard

public class OnePlayBot extends Player {

    {pieceUpgradeType = PieceUpgradeType.ROOK}

    @Override
    public Move getMove(ReadOnlyBoard board, Player enemy, Set<Move> moves) {
        return new ArrayList<Move>(moves).get(0);
    }

}

3

RandomBot

Bu zorlayıcı rastgele bot. Her zaman bir kaleye yükseltilir.

package com.ppcgse.koth.antichess.player

import com.ppcgse.koth.antichess.controller.PieceUpgradeType
import com.ppcgse.koth.antichess.controller.Player
import com.ppcgse.koth.antichess.controller.Move
import com.ppcgse.koth.antichess.controller.ReadOnlyBoard

import java.util.concurrent.ThreadLocalRandom;

public class TestBot extends Player {

    {pieceUpgradeType = PieceUpgradeType.ROOK}

    @Override
    public Move getMove(ReadOnlyBoard board, Player enemy, Set<Move> moves) {
        return moves[ThreadLocalRandom.current().nextInt(moves.size())];
    }

}

3

MeasureBot

Bu benim başladığım bot; Genişletmek için çalışıyordum ama sonra derin klon böceği ile karşılaştım ve sonra "iyi, bu botu zaten gönderelim, RandomBot ve OnePlayBot'tan daha iyi performans gösterebilirim ve daha sonra her zaman yeni bir bot gönderebilirim" diye düşündüm. , işte burada:

package com.ppcgse.koth.antichess.player

import com.ppcgse.koth.antichess.controller.Board
import com.ppcgse.koth.antichess.controller.Move
import com.ppcgse.koth.antichess.controller.Piece
import com.ppcgse.koth.antichess.controller.PieceType
import com.ppcgse.koth.antichess.controller.PieceUpgradeType
import com.ppcgse.koth.antichess.controller.Player

import java.util.concurrent.ThreadLocalRandom

/**
 * Created by ProgramFOX on 12/21/15.
 */

 class MeasureBot extends Player {
    {pieceUpgradeType = PieceUpgradeType.KING}

    @Override
    Move getMove(Board board, Player opponent, Set<Move> validMoves) {
        def opponentPieces = opponent.getPieces(board)
        def mustCapture = opponentPieces.find { it.loc == validMoves[0].destination } != null
        def chosen = null
        if (mustCapture) {
            def piecesThatCanBeTaken = opponentPieces.findAll { validMoves.collect { it.getDestination() }.contains(it.loc) }
            def lowestAmount = getPieceValue(piecesThatCanBeTaken.sort { getPieceValue(it.getType()) }[0].getType())
            def piecesWithLowestValue = piecesThatCanBeTaken.findAll { getPieceValue(it.getType()) == lowestAmount }
            def chosenOnes = validMoves.findAll { m -> piecesWithLowestValue.find { it.loc ==  m.destination } != null }
            chosen = chosenOnes.sort { getPieceValue(it.piece.getType()) }.reverse()[0]
        } else {
            chosen = randomMove(validMoves);
        }
        return chosen
    }

    Double getPieceValue(PieceType pieceType) {
        switch (pieceType) {
            case PieceType.KING:
                return 1
            case PieceType.PAWN:
                return 1.5
            case PieceType.KNIGHT:
                return 2.5
            case PieceType.BISHOP:
                return 3
            case PieceType.ROOK:
                return 5
            case PieceType.QUEEN:
                return 9
            default:
                return 0
        }
    }

    def randomMove(Set<Move> validMoves) {
        return validMoves[ThreadLocalRandom.current().nextInt(validMoves.size())];
    }
 }

MeasureBot bir şey yakalaması gerekip gerekmediğine bakar: eğer yapmazsa, sadece rastgele bir hareket yapar. Eğer öyleyse, hangi parçayı alacağına karar verecektir: daha düşük bir parça değerine sahip olanı seçecektir, çünkü bunlar kendi parçalarından daha azını yakalayabilir. Ve mümkün olan en düşük değere sahip bir parçayı almanın birden fazla yolu varsa, onu mümkün olan en yüksek değere sahip parça ile yakalar: eğer bunu yaparsa, yakalama parçasını diğer parçalara ( en azından daha düşük değerli bir parçayı kaybetmeyi tercih edersiniz.

Bu, kullandığım parça değerlerinin bir listesidir:

  • Kral: 1
  • Piyon: 1.5
  • Şövalye: 2.5
  • Piskopos: 3
  • Kale: 5
  • Kraliçe: 9

Bir piyon teşvik ettiğinde, her zaman bir krala terfi eder, çünkü en düşük değerli parça.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.