Antichess खेलें!


19

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

यह मूल रूप से शतरंज टूर्नामेंट है , लेकिन पुरातन के लिए;)

Antichess कई शतरंज वेरिएंट में से एक है जिसका आविष्कार किया गया है। लक्ष्य अपने सभी टुकड़ों को खोना है (यह थोड़ा अजीब लग सकता है, लेकिन इसे एक कारण के लिए एंटीचेस कहा जाता है)।

नियम

पुरातनता के नियम मानक शतरंज के समान हैं - लेकिन कुछ काफी मामूली अंतरों के साथ। जैसा कि मैंने ऊपर बताया लक्ष्य आपके सभी टुकड़ों को खोना है। ऐसा करने के लिए, यदि आपके प्रतिद्वंद्वी के पास आपके किसी एक टुकड़े को पकड़ने का अवसर है, तो वह एकमात्र चाल है जो वह कर सकता है। यदि आप उसे एक बारी में कई मौके देते हैं, तो दूसरा खिलाड़ी अपनी बारी चुन सकता है। एक और बात जो बदली है वह यह है कि राजा के पास कोई विशेष शक्तियां नहीं हैं - जैसे कि आप अपने प्रतिद्वंद्वी की जांच नहीं कर सकते हैं, और आप उसे जांच में शामिल नहीं कर सकते।

मानक खेल में निम्नलिखित परिवर्तन भी लागू होंगे (वे खेल को सरल बनाने में मदद करते हैं):

  • एन पास करने वाले की अनदेखी की जाएगी।
  • Castling संभव नहीं है।
  • पचास-चाल नियम स्वचालित रूप से (एक ड्रॉ में खेल समाप्त होता है जिसका अर्थ है) लागू होता है।
  • प्यादे यह चुनने में सक्षम होंगे कि वे किस चीज को बढ़ावा देते हैं।
  • यदि किसी खिलाड़ी को स्थानांतरित होने के लिए 2 सेकंड से अधिक की आवश्यकता होती है, तो वह खेल खो देगा।
  • अमान्य कदम वापस करने से खेल को खोना पड़ेगा।
  • जीतने के लिए, आपके विरोधियों को आपके सभी टुकड़ों पर कब्जा करना चाहिए
  • सफेद खेल शुरू होता है।
  • सफेद को क्षेत्र के "नीचे" (y = 0) पर रखा गया है, काला शीर्ष पर स्थित है (y = 7)।
  • आपके बॉट (इंटरनेट, फाइलें, अन्य बॉट्स, ...) की तुलना में अन्य संसाधनों तक पहुंच निषिद्ध है।

स्कोरिंग

  • आपको 3 अंक जीतना, 1 अंक ड्रा करना और 0 अंक गंवाना।
  • प्रत्येक प्रस्तुत एक दूसरे के खिलाफ 10 बार प्रस्तुत करेगा (5 बार सफेद के रूप में, 5 काले के रूप में)।

अपना बॉट लिखना

कंट्रोलर कोड यहाँ है: https://github.com/JJ-Atkinson/SimpleAntichessKOTH

आप अपने बॉट को जावा या ग्रूवी में लिख सकते हैं। बॉट लिखने के लिए आपको Playerकक्षा का विस्तार करना चाहिए । खिलाड़ी वर्ग में एक सार पद्धति है Move getMove(Board board, Player enemy, Set<Move> validMoves)

यहाँ उपयोगी तरीकों पर एक त्वरित ठहरनेवाला है:

Player:

  • List<Piece> getPieces(Board board): अपने सभी टुकड़ों को लौटाएं जो बोर्ड पर हैं।
  • PieceUpgradeType pieceUpgradeType: यदि / जब आपका एक पाव बोर्ड के अंत तक पहुंचता है, तो आपको इसे उस प्रकार को परिभाषित करना होगा, जिसे आप अपग्रेड करना चाहते हैं। आप का विकल्प है ROOK, KNIGHT, QUEEN, BISHOP, और KING

Board:

  • Field getFieldAtLoc(Location loc): Fieldस्थान पर लौटें । इसकी एक मिलान getAtविधि है ताकि यदि आप groovy का उपयोग कर रहे हैं तो आप लिख सकते हैं board[loc]
  • Field getFieldAtLoc(int x, int y): Fieldस्थान पर लौटें । इसकी एक मिलान getAtविधि है ताकि यदि आप groovy का उपयोग कर रहे हैं तो आप लिख सकते हैं board[x, y]
  • Board movePiece(Player player, Move move): बोर्ड पर एक कदम रखें ताकि आप देख सकें कि यह कैसे खेलता है। यह नया बोर्ड लौटाता है।

यदि आप अपने विरोधियों के टुकड़े देखना चाहते हैं, तो बस लिखें enemy.getPieces(board)। अपने बॉट को लाइनअप में जोड़ने के लिए निम्न लाइन को इसमें जोड़ें PlayerFactory:

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

अपने बॉट को डिबग करना:

मैंने आपके बॉट्स को डिबग करने में सहायता के लिए कुछ उपकरणों को शामिल किया है। अपने खेल को लाइव देखने के लिए आप Game#DEBUGध्वज को सही पर सेट कर सकते हैं । आपको कुछ इस तरह का आउटपुट मिलेगा:

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

...

(सफेद ऊपरी मामला है, राजा के साथ दिखाया गया है i)

यदि आपका कंसोल utf-8 विशेष वर्णों का समर्थन करता है, तो आप बोर्ड का उपयोग करके शतरंज वर्णों के साथ दिखा सकते हैं Board#USE_UTF8_TO_STRING:

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

(यह मोनो स्पेसल फ़ॉन्ट के साथ बेहतर दिखता है)

अवांछित आउटपुट की बाढ़ को रोकने के लिए, आपको Main#mainफ़ंक्शन को कुछ इस तरह बदलना चाहिए :

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

अपने बॉट को सफेद के रूप में खेलने के लिए बाईं ओर रखें, इसे ब्लैक के रूप में खेलने के लिए दाईं ओर रखें।

नियंत्रक का निर्माण:

नियंत्रक ग्रूवी में लिखा गया है, इसलिए आपके पास जावा और ग्रूवी स्थापित होना चाहिए। यदि आप ग्रूवी स्थापित नहीं करना चाहते हैं तो आप नियंत्रक के साथ आने वाली ग्रेडल बिल्ड फ़ाइल का उपयोग कर सकते हैं (यह परीक्षण नहीं किया गया है)। यदि आप groovy या gradle का उपयोग नहीं करना चाहते हैं तो आप नवीनतम रिलीज़ जार ( https://github.com/JJ-Atkinson/SimpleAntichessKOTH/releases ) का उपयोग कर सकते हैं । यदि आप ऐसा करते हैं, तो आपको अपना खुद का mainतरीका बनाने और अपने बॉट को प्लेयर फैक्ट्री में जोड़ने की आवश्यकता है । उदाहरण:

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

(ध्यान दें कि आप अभी भी डिबग फ़्लैग और सामान सेट कर सकते हैं)

किसी भी और सभी बग खोज की सराहना की है!

स्कोर:

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

कृपया ध्यान दें कि मैं हमेशा नई प्रस्तुतियाँ करने को तैयार हूँ!


आप ग्रूवी और इंटेलीजे की तरह ... आप पर एक नज़र रखना चाहिए तो Kotlin
TheNumberOne

मैंने पहले भी कोटलिन को देखा है, लेकिन कभी भी इसे अच्छी तरह से नहीं देखा। यह थोड़े scala / groovy मैशप की तरह दिखता है (लेकिन यह ठीक है - groovy और scala मेरी पसंदीदा भाषाएं हैं;)
J Atkin

मैंने पहले कभी स्केला का उपयोग नहीं किया है ... लेकिन जावा से कोटलिन कोड को कॉल करना बहुत आसान है, क्योंकि यह जावा से गोवी कोड को कॉल करना है।
TheNumberOne

1
आप एक राजा के लिए उन्नयन कर सकते हैं?!? निश्चित रूप से नहीं ...
wizzwizz4

1
@ wizzwizz4 प्राचीन काल में, आप कर सकते हैं।
प्रोग्राम फॉक्स

जवाबों:


6

Searchbot

अब तक की सबसे धीमी बॉट, लेकिन अभी भी प्रति सेकंड 2 सेकंड से अधिक तेज है और यह वर्तमान में पोस्ट किए गए सभी बॉट को हरा देती है। यह देखता है कि किसी भी वैध चाल के बाद क्या होता है और उन चालों के बाद किसी भी चाल के बाद क्या हो सकता है और यह तय करता है कि सबसे अच्छा परिणाम क्या होगा। दुर्भाग्य से यह गहरी खोज नहीं कर सकता क्योंकि इसमें 2 सेकंड से अधिक समय लगेगा।

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

यह बॉट उन सभी चालों की जाँच करेगा जो दूसरे खिलाड़ी के पास है और यह देखने के लिए जाँच करेगा कि उनमें से कोई भी अंतरजाल (यानी टुकड़ा मारा जाएगा)। (यह मैंने कभी भी उम्मीद से बेहतर की एक बिल्ली है;)

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

केवल एक नाटक के साथ मृत सरल बॉट। यह एक किश्ती में अपग्रेड होगा।

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

यह अनिवार्य यादृच्छिक बॉट है। यह हमेशा एक बदमाश को अपग्रेड करेगा।

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

यह वह बॉट है जिसे मैंने शुरू किया था; मैं इसे विस्तारित करने पर काम कर रहा था, लेकिन फिर मैं गहरे-क्लोन वाले बग पर आया, और फिर मैंने सोचा "अच्छा है, चलो इस बॉट को पहले से ही सबमिट कर दें, यह रैंडमबॉट और वनप्लसबॉट से बेहतर प्रदर्शन करता है, और मैं हमेशा एक नया बॉट प्रस्तुत कर सकता हूं" , तो यहाँ यह है:

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())];
    }
 }

मेजबोट दिखता है कि क्या उसे किसी चीज़ पर कब्जा करने की ज़रूरत है: यदि ऐसा नहीं होता है, तो यह बस एक यादृच्छिक चाल बनाता है। यदि ऐसा होता है, तो यह तय करेगा कि किस टुकड़े को लेना है: यह एक कम टुकड़े के मूल्य के साथ एक का चयन करेगा क्योंकि वे अपने स्वयं के टुकड़ों में से कम पर कब्जा कर सकते हैं। और अगर सबसे कम संभव मान के साथ एक टुकड़ा लेने के कई तरीके हैं, तो वह इसे उच्चतम संभव मूल्य के साथ टुकड़े पर कब्जा कर लेगा: यदि यह ऐसा करता है, तो यह कैप्चरिंग टुकड़े को अन्य टुकड़ों के करीब लाएगा (शुरुआत में) खेल, कम से कम) और आप कम-मूल्यवान वाले की तुलना में एक उच्च-मूल्यवान टुकड़ा खो देंगे।

यह मेरे द्वारा उपयोग किए गए टुकड़े के मूल्यों की एक सूची है:

  • राजा: १
  • प्यादा: १.५
  • नाइट: 2.5
  • बिशप: 3
  • Rook: 5
  • रानी: ९

जब एक मोहरा बढ़ावा देता है, तो यह हमेशा एक राजा को बढ़ावा देगा, क्योंकि यह सबसे कम मूल्य का टुकड़ा है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.