कोथ: गोमोकू (एक पंक्ति में पांच)


10

गोमोकू या फाइव एक पंक्ति में ग्रिड पर दो खिलाड़ियों द्वारा काले और सफेद पत्थरों के साथ खेला जाने वाला एक बोर्ड गेम है । जो भी 5 पत्थरों को एक पंक्ति में रखने में सक्षम है (क्षैतिज, ऊर्ध्वाधर या विकर्ण) खेल जीतता है।15×155

नियम

इस KoTH में हम Swap2 नियम खेलेंगे, जिसका अर्थ है कि एक खेल में दो चरण होते हैं: प्रारंभिक चरण में दो खिलाड़ी यह निर्धारित करते हैं कि कौन पहले जाता है / कौन काला खेलता है, इसके बाद वे खिलाड़ी के साथ शुरू होने वाले प्रत्येक राउंड में एक पत्थर रखेंगे। जिसने काला उठाया।

पहला भाग

खिलाड़ियों को एंड बी और खेल खोलने देंगे:

  • बोर्ड पर दो काले और एक सफेद पत्थर के एक स्थान
  • B निम्नलिखित तीन में से एक चाल चुन सकता है:
    • खिलाड़ी बी ने काला खेलने का फैसला किया: प्रारंभिक चरण खत्म हो गया है
    • खिलाड़ी बी एक सफेद पत्थर रखने का फैसला करता है और सफेद खेलता है: प्रारंभिक चरण खत्म हो गया है
    • खिलाड़ी बी एक काला और एक सफेद पत्थर खेलने का फैसला करता है: रंग लेने के लिए जाता है

खेल का चरण

प्रत्येक खिलाड़ी अपने रंग का एक पत्थर बोर्ड पर रखता है, जो उस खिलाड़ी के साथ शुरू होता है जो काला खेलता है, यह तब तक चलता है जब तक कि खेलने के लिए अधिक खाली स्थान नहीं हैं (जिस स्थिति में यह टाई है) या एक खिलाड़ी पत्थरों को खेलने के लिए प्रबंधित करता है पंक्ति (जिस स्थिति में खिलाड़ी जीतता है)।5

एक पंक्ति का अर्थ है क्षैतिज, ऊर्ध्वाधर या विकर्ण। एक जीत एक जीत है - इससे कोई फर्क नहीं पड़ता कि खिलाड़ी एक पंक्ति से अधिक स्कोर करने में कामयाब रहा या नहीं।

KoTH खेल के नियम

  • प्रत्येक खिलाड़ी दो बार एक दूसरे खिलाड़ी के खिलाफ खेलता है:
    • शुरू में यह बेतरतीब ढंग से तय किया जाएगा कि कौन पहले जाता है
    • अगले गेम में अंतिम बार खेलने वाला खिलाड़ी पहले जाता है
  • एक जीत 2 अंक, एक टाई 1 और नुकसान 0 के बराबर है
  • लक्ष्य संभव के रूप में कई अंक स्कोर करने के लिए है

आपका बॉट

इस चुनौती को अधिक से अधिक भाषाओं तक पहुंचाने के लिए संभव इनपुट / आउटपुट स्टड / स्टडआउट (लाइन-आधारित) के माध्यम से होगा । जज प्रोग्राम आपके बॉट के स्टडिन को एक लाइन प्रिंट करके आपके प्रोग्राम को प्रॉम्प्ट करेगा और आपका बॉट स्टडआउट को एक लाइन प्रिंट करेगा ।

एक बार जब आप एक EXITसंदेश प्राप्त करते हैं, तो आपको जज को मारने से पहले फाइलों को लिखने के लिए आधा सेकंड दिया जाएगा।

अनियमितता

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

तर्क

बॉट को दो कमांड लाइन तर्क मिले:

  1. प्रतिद्वंद्वी का नाम
  2. यादृच्छिकता के लिए बीज

उपयोगकर्ता स्थिति

क्योंकि आपका प्रोग्राम हमेशा प्रत्येक गेम के लिए नया शुरू किया जाएगा, जिसे आप किसी भी जानकारी को बनाए रखने के लिए फ़ाइलों का उपयोग करने की आवश्यकता होगी। आपको अपनी वर्तमान निर्देशिका में किसी भी फाइल को पढ़ने / लिखने या उप-फ़ोल्डर्स बनाने / निकालने की अनुमति है। आपको किसी भी मूल-निर्देशिका में किसी भी फ़ाइल तक पहुँचने की अनुमति नहीं है!

इनपुट / आउटपुट प्रारूप

BOARD((X,Y),COLOR)XY[0,15)COLOR"B""W"

SPXY(X,Y)[0,15)|

प्रारंभिक चरण में तीन विभिन्न प्रकार के संदेश हैं:

Prompt (judge) -> Answer (bot)
"A" SP "[]"  -> XY XY XY
"B" SP BOARD -> "B" | "W" SP XY | XY XY
"C" SP BOARD -> "B" | "W"
  • पहला संदेश तीन टुपल्स के लिए पूछता है, पहले दो काले पत्थरों की स्थिति और तीसरा एक सफेद के लिए स्थिति होगी।
  • दूसरा संदेश या तो पूछता है:
    • "B" -> काला उठाओ
    • "W" SP XY -> सफेद चुनें और सफेद पत्थर रखें XY
    • XY XY -> दो पत्थर रखें (पहला एक काला और दूसरा एक सफेद)
  • आखिरी वाला बस पूछता है कि आप किस रंग से खेलना चाहते हैं

उसके बाद नियमित खेल शुरू हो जाएगा और संदेश बहुत सरल हो जाएंगे

N BOARD -> XY

N0XY


एक अतिरिक्त संदेश है जो उत्तर की उम्मीद नहीं करता है

"EXIT" SP NAME | "EXIT TIE"

NAMEबॉट का नाम कहां है जो जीता। दूसरा संदेश भेजा जाएगा यदि गेम किसी के जीतने के कारण समाप्त नहीं होता है और पत्थरों को रखने के लिए अधिक खाली स्थान नहीं है (इसका मतलब है कि आपके बॉट का नाम नहीं लिया जा सकता है TIE)।

का प्रारूपण

चूंकि बॉट के संदेशों को बिना किसी रिक्त स्थान के डिकोड किया जा सकता है, सभी रिक्त स्थान को अनदेखा किया जाएगा (उदाहरण के (0 , 0) (0,12)लिए उसी के रूप में व्यवहार किया जाता है (0,0)(0,12))। जज के संदेशों में केवल अलग-अलग वर्गों (यानी जैसा कि ऊपर उल्लेखित है SP) को अलग करने के लिए एक स्थान होता है , जिससे आप रिक्त स्थान पर रेखा को विभाजित कर सकते हैं।

किसी भी अवैध प्रतिक्रिया के परिणामस्वरूप उस दौर का नुकसान होगा (आप अभी भी एक EXITसंदेश प्राप्त करेंगे ), नियम देखें।

उदाहरण

यहां वास्तविक संदेशों के कुछ उदाहरण दिए गए हैं:

A []
B [((0,0),"B"),((0,1),"W"),((14,14),"B")]
1 [((0,0),"B"),((0,1),"W"),((1,0),"B"),((1,1),"W"),((14,14),"B")]

न्यायाधीश

आप यहां जज प्रोग्राम पा सकते हैं : बॉट को इसमें जोड़ने के लिए केवल फ़ोल्डर में एक नया फ़ोल्डर बनाएं bots, अपनी फ़ाइलों को वहां रखें और एक फ़ाइल जोड़ें metaजिसमें नाम , कमांड , तर्क और एक ध्वज 0/1 (अक्षम / सक्षम स्टादर ) प्रत्येक एक अलग लाइन पर।

एक टूर्नामेंट चलाने के लिए ./gomokuऔर एक एकल बॉट रन को डिबग करने के लिए ./gomoku -d BOT

नोट: आप Github रिपॉजिटरी में जज को सेटअप करने और उसका उपयोग करने के बारे में अधिक जानकारी पा सकते हैं। तीन उदाहरण बॉट ( हास्केल , पायथन और जावास्क्रिप्ट ) भी हैं।

नियम

  • बॉट के प्रत्येक परिवर्तन पर * टूर्नामेंट फिर से शुरू होगा और सबसे अधिक अंक जीतने वाला खिलाड़ी (टाई-ब्रेकर पहले जमा करेगा)
  • जब तक वे एक आम रणनीति नहीं निभाते हैं तब तक आप एक से अधिक बॉट जमा कर सकते हैं
  • आपको अपनी निर्देशिका के बाहर फ़ाइलों को छूने की अनुमति नहीं है (उदाहरण के लिए अन्य खिलाड़ी की फ़ाइलों में हेरफेर)
  • यदि आपका बॉट क्रैश हो जाता है या एक अवैध प्रतिक्रिया भेजता है, तो वर्तमान गेम समाप्त हो जाता है और आप उस दौर को खो देते हैं
  • जबकि जज (वर्तमान में) प्रति दौर की समय-सीमा को लागू नहीं करता है, आपको सलाह दी जाती है कि समय कम रखने के लिए क्योंकि यह सभी प्रस्तुतियाँ का परीक्षण करने के लिए संभव हो सकता है **
  • जज प्रोग्राम में गालियां देना खामियों के रूप में गिना जाता है

* आपको अपने बॉट को सीधे botsनिर्देशिका में प्रस्तुत करने के लिए (और संभावित रूप से संशोधित util.sh) गितुब का उपयोग करने के लिए प्रोत्साहित किया जाता है !

** यदि यह एक समस्या बन जाती है तो आपको सूचित किया जाएगा, मैं 500ms से नीचे कुछ भी कहूंगा (यह बहुत है!) अभी के लिए ठीक होना चाहिए।

चैट

यदि आपके कोई प्रश्न हैं या इस KoTH के बारे में बात करना चाहते हैं, तो चैट में शामिल होने के लिए स्वतंत्र महसूस करें !



आपके उदाहरणों में रिक्त स्थान का मेटा स्पेस चरित्र होना मेरे दिमाग को उड़ा रहा है। कुछ और उदाहरण अच्छे होंगे।
Veskah

@Veskah: तीन उदाहरण बॉट जुड़े हुए हैं, मैं संदेशों के लिए कुछ उदाहरण जोड़ूंगा।
ბიმო

@Veskah: कुछ उदाहरण जोड़े। Btw। आप एक उदाहरण बॉट को डिबग करने का भी प्रयास कर सकते हैं कि वे किस प्रारूप में होंगे और परीक्षण करेंगे कि एक वैध प्रतिक्रिया क्या है।
ბიმო

आपने पुश अनुमतियाँ नहीं
काइटो किड

जवाबों:


3

KaitoBot

यह मिनीमैक्स सिद्धांतों के बहुत क्रूड कार्यान्वयन का उपयोग करता है। खोज की गहराई भी बहुत कम है, क्योंकि अन्यथा यह बहुत लंबा रास्ता तय करती है।

बाद में सुधार करने के लिए संपादित कर सकते हैं।

यदि संभव हो तो यह ब्लैक खेलने की भी कोशिश करता है, क्योंकि विकिपीडिया को लगता है कि ब्लैक का एक फायदा है।

मैंने खुद कभी गोमोकू नहीं खेला है, इसलिए मैंने पहले तीन पत्थरों को एक बेहतर विचार की कमी के लिए बेतरतीब ढंग से स्थापित किया।

const readline = require('readline');
const readLine = readline.createInterface({ input: process.stdin });

var debug = true;
var myColor = '';
var opponentColor = '';
var board = [];
var seed = parseInt(process.argv[3]);

function random(min, max) {
    changeSeed();
    var x = Math.sin(seed) * 10000;
    var decimal = x - Math.floor(x);
    var chosen = Math.floor(min + (decimal * (max - min)));
    return chosen;
}

function changeSeed() {
    var x = Math.sin(seed++) * 10000;
    var decimal = x - Math.floor(x);
    seed = Math.floor(100 + (decimal * 9000000));
}

function KaitoBot(ln) {
    var ws = ln.split(' ');

    if (ws[0] === 'A') {
        // Let's play randomly, we don't care.
        var nums = [];
        nums[0] = [ random(0, 15), random(0, 15) ];
        nums[1] = [ random(0, 15), random(0, 15) ];
        nums[2] = [ random(0, 15), random(0, 15) ];
        while (nums[1][0] == nums[0][0] && nums[1][1] == nums[0][1])
        {
            nums[1] = [ random(0, 15), random(0, 15) ];
        }
        while ((nums[2][0] == nums[0][0] && nums[2][1] == nums[0][1]) || (nums[2][0] == nums[1][0] && nums[2][1] == nums[1][1]))
        {
            nums[2] = [ random(0, 15), random(0, 15) ];
        }
        console.log('(' + nums[0][0] + ',' + nums[0][1] + ') (' + nums[1][0] + ',' + nums[1][1] + ') (' + nums[2][0] + ',' + nums[2][1] + ')');
    }
    else if (ws[0] === 'B') {
        // we're second to play, let's just pick black
        myColor = 'B';
        opponentColor = 'W';
        console.log('B');
    }
    else if (ws[0] === 'C') {
        // the other player chose to play 2 stones more, we need to pick..
        // I would prefer playing Black
        myColor = 'B';
        opponentColor = 'W';
        console.log('B');
    }
    else if (ws[0] === 'EXIT') {
        process.exit();
    }
    else {
        board = [];
        var json = JSON.parse(ws[1].replace(/\(\(/g,'{"xy":[')
                .replace(/"\)/g,'"}')
                .replace(/\),/g,'],"colour":'));
        // loop over all XYs and make a board object I can use
        for (var x = 0; x < 15; x++) {
            var newRow = []
            for (var y = 0; y < 15; y++) {
                var contains = false;
                json.forEach(j => {
                    if (j.xy[0] == x && j.xy[1] == y) {
                        contains = true;
                        newRow[newRow.length] = j.colour;
                    }
                });
                if (!contains) {
                    newRow[newRow.length] = ' ';
                }
            }
            board[board.length] = newRow;
        }
        // If we never picked Black, I assume we're White
        if (myColor == '') {
            myColor = 'W';
            opponentColor = 'B';
        }
        var bestMoves = ChooseMove(board, myColor, opponentColor);
        var chosenMove = bestMoves[random(0, bestMoves.length)];
        console.log('(' + chosenMove.X + ',' + chosenMove.Y + ')');
    }
}

function IsSquareRelevant(board, x, y) {
    return (board[x][y] == ' ' && 
        ((x > 0 && board[x - 1][y] != ' ') 
        || (x < 14 && board[x + 1][y] != ' ') 
        || (y > 0 && board[x][y - 1] != ' ') 
        || (y < 14 && board[x][y + 1] != ' ')
        || (x > 0 && y > 0 && board[x - 1][y - 1] != ' ') 
        || (x < 14 && y < 14 && board[x + 1][y + 1] != ' ') 
        || (y > 0 && x < 14 && board[x + 1][y - 1] != ' ') 
        || (y < 14 && x > 0 && board[x - 1][y + 1] != ' ')));
}

function ChooseMove(board, colorMe, colorOpponent) {
    var possibleMoves = [];
    for (var x = 0; x < 15; x++) {
        for (var y = 0; y < 15; y++) {
            if (IsSquareRelevant(board, x, y)) {
                possibleMoves[possibleMoves.length] = {X:x, Y:y};
            }
        }
    }
    var bestValue = -9999;
    var bestMoves = [possibleMoves[0]];
    for (var k in possibleMoves) {
        var changedBoard = JSON.parse(JSON.stringify(board));
        changedBoard[possibleMoves[k].X][possibleMoves[k].Y] = colorMe;
        var value = analyseBoard(changedBoard, colorMe, colorOpponent, colorOpponent, 2);
        if (value > bestValue) {
            bestValue = value;
            bestMoves = [possibleMoves[k]];
        } else if (value == bestValue) {
            bestMoves[bestMoves.length] = possibleMoves[k];
        }
    }
    return bestMoves;
}

function analyseBoard(board, color, opponent, nextToPlay, depth) {
    var tBoard = board[0].map((x,i) => board.map(x => x[i]));
    var score = 0.0;
    for (var x = 0; x < board.length; x++) {
        var inARow = 0;
        var tInARow = 0;
        var opponentInARow = 0;
        var tOpponentInARow = 0;
        var inADiago1 = 0;
        var opponentInADiago1 = 0;
        var inADiago2 = 0;
        var opponentInADiago2 = 0;

        for (var y = 0; y < board.length; y++) {
            if (board[x][y] == color) {
                inARow++;
                score += Math.pow(2, inARow);
            } else {
                inARow = 0;
            }
            if (board[x][y] == opponent) {
                opponentInARow++;
                score -= Math.pow(2, opponentInARow);
            } else {
                opponentInARow = 0;
            }
            if (tBoard[x][y] == color) {
                tInARow++;
                score += Math.pow(2, tInARow);
            } else {
                tInARow = 0;
            }
            if (tBoard[x][y] == opponent) {
                tOpponentInARow++;
                score -= Math.pow(2, tOpponentInARow);
            } else {
                tOpponentInARow = 0;
            }

            var xy = (y + x) % 15;
            var xy2 = (x - y + 15) % 15;
            if (xy == 0) {
                inADiago1 = 0;
                opponentInADiago1 = 0;
            }
            if (xy2 == 0) {
                inADiago2 = 0;
                opponentInADiago2 = 0;
            }

            if (board[xy][y] == color) {
                inADiago1++;
                score += Math.pow(2, inADiago1);
            } else {
                inADiago1 = 0;
            }
            if (board[xy][y] == opponent) {
                opponentInADiago1++;
                score -= Math.pow(2, opponentInADiago1);
            } else {
                opponentInADiago1 = 0;
            }
            if (board[xy2][y] == color) {
                inADiago2++;
                score += Math.pow(2, inADiago2);
            } else {
                inADiago2 = 0;
            }
            if (board[xy2][y] == opponent) {
                opponentInADiago2++;
                score -= Math.pow(2, opponentInADiago2);
            } else {
                opponentInADiago2 = 0;
            }


            if (inARow == 5 || tInARow == 5) {
                return 999999999.0;
            } else if (opponentInARow == 5 || tOpponentInARow == 5) {
                return -99999999.0;
            }
            if (inADiago1 == 5 || inADiago2 == 5) {
                return 999999999.0;
            } else if (opponentInADiago1 == 5 || opponentInADiago2 == 5) {
                return -99999999.0;
            }
        }
    }

    if (depth > 0) {
        var bestMoveValue = 999999999;
        var nextNextToPlay = color;
        if (nextToPlay == color) {
            nextNextToPlay = opponent;
            bestMoveValue = -999999999;
        }
        for (var x = 0; x < board.length; x++) {
            for (var y = 0; y < board.length; y++) {
                if (IsSquareRelevant(board, x, y)) {
                    var changedBoard = JSON.parse(JSON.stringify(board));
                    changedBoard[x][y] = nextToPlay;
                    var NextMoveValue = (analyseBoard(changedBoard, color, opponent, nextNextToPlay, depth - 1) * 0.1);

                    if (nextToPlay == color) {
                        if (NextMoveValue > bestMoveValue) {
                            bestMoveValue = NextMoveValue;
                        }
                    } else {
                        if (NextMoveValue < bestMoveValue) {
                            bestMoveValue = NextMoveValue;
                        }
                    }
                }
            }
        }
        score += bestMoveValue * 0.1;
    }
    return score;
}

readLine.on('line', (ln) => {

    KaitoBot(ln);

});

EDITS: बीज को गतिशील रूप से बदल दिया क्योंकि अन्यथा जब बीज 2 ^ 52 से अधिक हो जाते हैं तो जावास्क्रिप्ट सही ढंग से वृद्धि को नहीं संभाल सकता है

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