ราชาแห่งกำแพง


10

แจ้งให้ทราบ

ความท้าทายนี้สิ้นสุดลงแล้วและจะไม่ถูกตัดสินอีกครั้ง แต่สามารถโพสต์คำตอบและทดสอบโปรแกรมของคุณกับผู้อื่นด้วยโปรแกรมควบคุม!

เป้าหมายของความท้าทายนี้คือการทำให้ AI ชนะการต่อสู้กับ AI อื่นโดยการวางกำแพงบนตาราง 25x25 เพื่อป้องกันคู่ต่อสู้

อินพุต

25 บรรทัดคั่นด้วยและลงท้ายด้วย;อาร์กิวเมนต์บรรทัดคำสั่ง ซึ่งจะรวมถึง:

  • ช่องว่าง .
  • กำแพง #
  • ผู้เล่น1และ2(ฝ่ายตรงข้ามอยู่เสมอ2)

ตัวอย่าง

###############..........;..............#..........;..............#..........;..............#..........;..............#..........;...........1###..........;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;.........................;...................###...;...................#.##..;2..................#..#..;#..................##.#..;#...................#.###;....................#####;

ซึ่งแสดงถึงแผนที่ดังต่อไปนี้:

###############..........
..............#..........
..............#..........
..............#..........
..............#..........
...........1###..........
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
...................###...
...................#.##..
2..................#..#..
#..................##.#..
#...................#.###
....................#####

เอาท์พุต

สตริงที่เขียนไปยังคอนโซลโดยเริ่มต้นด้วยอักขระที่แสดงถึงทิศทางที่ AI ประสงค์จะเปลี่ยน นี่คือกรณีที่ละเอียดอ่อน!

  • ทางทิศเหนือ N
  • ตะวันออก E
  • ภาคใต้ S
  • ตะวันตก W
  • ยอมแพ้ (สิ่งอื่นใด)

ตัวอย่าง

W

กฎของเกม

  • ในขณะที่ AIs เคลื่อนที่พวกเขาจะทิ้งกำแพงทึบไว้ข้างหลังพวกเขา
  • ผู้เล่นเริ่มต้นที่มุมซ้ายบนและล่างขวา
  • เกมนี้ใช้งานได้นานจนกว่า AI ใด ๆ จะชนกำแพงหรือ AIs ชนเข้าด้วยกัน
    • AI จะชนะถ้าฝ่ายตรงข้ามล้มเหลวก่อน
    • นอกจากนี้ไม่มีผู้ชนะหรือผู้แพ้ถ้าเอไอเอสทั้งการสูญเสียในเวลาเดียวกัน
  • หาก AI ดับลงที่ขอบด้านหนึ่งของตารางพวกเขาจะดำเนินการต่อในทิศทางเดียวกันจากอีกด้าน

การจัดอันดับ

อันดับที่ 1 - FloodBot (Java, 12 ชนะ)

อันดับที่ 2 - FluidBot (Python, 9 ชัยชนะ)

อันดับที่ 3 - FillUpBot (C ++, 8 ชนะ)

อันดับที่ 4 - AwayBot (Ruby, 5 ชัยชนะ)

อันดับที่ 5 - ArcBot (Python, 4 wins)

อันดับที่ 6 - BlindSnake (แบทช์, 2 ชนะ)

อันดับที่ 6 - RandomBot (C #, 2 ชนะ)

โปรแกรมควบคุม (ทดสอบสำหรับ Python 3.3.3)

โปรแกรมรันด้วยอาร์กิวเมนต์ของทั้งสองคำสั่งและอาร์กิวเมนต์เดียว ( ""ถ้าไม่จำเป็น) สำหรับ AIs เช่น Control.py "ruby" "AwayBot.rb" "FillUpBot.exe" "". ก็สามารถดาวน์โหลดได้ที่นี่

import sys, subprocess

Program1, Argument1, Program2, Argument2, Player1, Player2, Grid = sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4], [0, 0], [24, 24], [['.' for y in range(25)] for x in range(25)]
while True:
    Str  = ''
    for x in range(25):
        for y in range(25):
            if Grid[x][y] == '1' or Grid[x][y] == '2':
                Grid[x][y] = '#'
    Grid[Player1[0]][Player1[1]] = '1'
    Grid[Player2[0]][Player2[1]] = '2'
    for y in range(25):
        for x in range(25):
            Str += Grid[x][y]
        Str += ';'
    if Argument1 == '':
        move = subprocess.Popen([Program1, Str], stdout=subprocess.PIPE).stdout.read().decode('ASCII')[0]
    else:
        move = subprocess.Popen([Program1, Argument1, Str], stdout=subprocess.PIPE).stdout.read().decode('ASCII')[0]
    Lose1 = False
    if move == 'N':
        if Player1[1] > 0:
            Player1[1] -= 1
        else:
            Player1[1] = 24
    elif move == 'E':
        if Player1[0] < 24:
            Player1[0] += 1
        else:
            Player1[0] = 0
    elif move == 'S':
        if Player1[1] < 24:
            Player1[1] += 1
        else:
            Player1[1] = 0
    elif move == 'W':
        if Player1[0] > 0:
            Player1[0] -= 1
        else:
            Player1[0] = 24
    else:
        Lose1 = True
    if Grid[Player1[0]][Player1[1]] == '#' or Grid[Player1[0]][Player1[1]] == '2':
        Lose1 = True
    print('Player 1:', move)
    if Argument2 == '':
        move = subprocess.Popen([Program2, Str.replace('2','3').replace('1','2').replace('3','1')], stdout=subprocess.PIPE).stdout.read().decode('ASCII')[0]
    else:
        move = subprocess.Popen([Program2, Argument2, Str.replace('2','3').replace('1','2').replace('3','1')], stdout=subprocess.PIPE).stdout.read().decode('ASCII')[0]
    Lose2 = False
    if move == 'N':
        if Player2[1] > 0:
            Player2[1] -= 1
        else:
            Player2[1] = 24
    elif move == 'E':
        if Player2[0] < 24:
            Player2[0] += 1
        else:
            Player2[0] = 0
    elif move == 'S':
        if Player2[1] < 24:
            Player2[1] += 1
        else:
            Player2[1] = 0
    elif move == 'W':
        if Player2[0] > 0:
            Player2[0] -= 1
        else:
            Player2[0] = 24
    elif Lose1:
        Lose2 = True
    else:
        Lose2 = True
    print('Player 2:', move)
    print(Str.replace(';', '\n'))
    if Grid[Player2[0]][Player2[1]] == '#':
        Lose2 = True
    if Lose1 and Lose2:
        print('Draw!')
        break
    elif Lose1:
        print('Player 2 wins!')
        break
    elif Lose2:
        print('Player 1 wins!')
        break

5
คุณต้องเพิ่ม API และโปรแกรมทดสอบทันที! เราจะเขียนโค้ดเพื่อเชื่อมต่อกับมันได้อย่างไร การตั้งค่าสถานะไม่ชัดเจน
AJMansfield

3
ดูเหมือนจะเป็นความท้าทายที่ดี แต่ใช่มั้ย .. นั่นคือ 'โปรแกรมทดสอบ' (เป็นโปรแกรมควบคุมใช่ไหม) มันเป็นภาษาอะไรและฉันต้องรวบรวมมัน? โปรดบอกวิธีการใช้
Herjan

3
ดูเหมือนจะเป็นความท้าทายที่น่าสนใจที่ฉันจะไม่แข่งขันเนื่องจาก (A) ข้อ จำกัด ของระบบปฏิบัติการ (ผู้ใช้ Linux เท่านั้น) และ (B) ข้อ จำกัด ทางภาษา (ส่วนใหญ่ Fortran แต่ทำงานเกี่ยวกับการเรียนรู้ Lua)
Kyle Kanos

2
@Doorknob ฉันกำลังติดตั้ง Ruby ตอนนี้และกำลังคิดที่จะเรียนรู้การใช้งาน
kitcar2000

2
@ kitcar2000 อาฉันเห็นว่ามันยุติธรรมพอ หรือคุณสามารถระบุผ่าน stdin แต่ใช้บรรทัดเดียวเนื่องจากอาร์กิวเมนต์เป็นเกมที่ยุติธรรม ดังที่กล่าวไว้เนื่องจากแผนที่ของคุณมีขนาดคงที่คุณไม่จำเป็นต้องมีตัวคั่นใด ๆ เลย
Martin Ender

คำตอบ:


8

Floodbot

ชวา

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

นอกจากนี้เขายังคิดว่าศัตรูไม่สามารถคาดการณ์ได้ดังนั้นเขาจึงปฏิบัติต่อแต่ละสี่เหลี่ยมล้อมรอบพวกเขาทันทีว่าเป็นกำแพงแล้ว หากสิ่งนั้นนำไปสู่ทิศทางที่เป็นไปไม่ได้เขาจะกลับไปที่แผนที่ "จริง"

public class Floodbot {

    boolean[][] walkable;
    boolean[][] actual;
    boolean[][] map;
    int px;
    int py;

    void run(String[] input){
        int direction = 0;
        if(read(input))
            direction = bestPath(findPaths(false), true);
        System.out.print(directions[direction]);
    }

    int bestPath(int[] paths, boolean first){
        if(!first)
            paths = findPaths(true);
        int bestDir = 0;
        int best = 0;
        for(int i=0;i<paths.length;i++)
            if(paths[i] > best){
                best = paths[i];
                bestDir = i;
            }
        if(best==0 && first)
            return bestPath(paths, false);
        return bestDir;
    }

    static int floodCount;
    void flood(boolean[][] visited, int x, int y){
        if(visited[x][y] || !map[x][y])
            return;
        floodCount++;
        visited[x][y] = true;
        for(int dir=0;dir<4;dir++){
            int nx = dir%2==1 ? wrap(x+dir-2) : x;
            int ny = dir%2==0 ? wrap(y+dir-1) : y;
            flood(visited, nx, ny);
        }       
    }

    int[] findPaths(boolean useActual){             
        int[] paths = new int[4];
        map = useActual ? actual : walkable;
        for(int i=0;i<4;i++){
            floodCount = 0;
            int nx = i%2==1 ? wrap(px+i-2) : px;
            int ny = i%2==0 ? wrap(py+i-1) : py;
            flood(new boolean[size][size], nx, ny);
            paths[i] = floodCount;
        }
        return paths;
    }

    boolean read(String[] input){
        if(input.length < 1 || input[0].length() < size*size)
            return false;
        String[] lines = input[0].split(";");
        if(lines.length < size)
            return false;
        walkable = new boolean[size][size];
        actual = new boolean[size][size];
        for(int x=0;x<size;x++)
            for(int y=0;y<size;y++){
                walkable[x][y] = true;
                actual[x][y] = true;
            }
        for(int y=0;y<size;y++)
            for(int x=0;x<size;x++){
                char pos = lines[y].charAt(x);
                switch(pos){
                case '.':
                    break;
                case '2':
                    actual[x][y] = false;
                    walkable[x][y] = false;
                    walkable[wrap(x+1)][y] = false;
                    walkable[wrap(x-1)][y] = false;
                    walkable[x][wrap(y+1)] = false;
                    walkable[x][wrap(y-1)] = false;
                    break;
                case '1':
                    px = x; py = y;
                case '#':
                default:
                    walkable[x][y] = false;
                    actual[x][y] = false;
                }
            }

        return true;
    }

    public static void main(String[] input){new Floodbot().run(input);}
    static int wrap(int c){return (size+c)%size;}   
    static final String[] directions = {"N","W","S","E"};
    static final int size = 25;
}

ฉันคิดว่าคุณมีสิ่งนี้ในกระเป๋า
cjfaure

@Trimsty โอ้ ฉันยังไม่ได้ทดสอบกับการแข่งขันทั้งหมดดังนั้นฉันจึงไม่แน่ใจว่ามันจะต่อสู้กับพวกเขาสองคนได้อย่างไร เป็นการดีที่จะทราบ :)
Geobits

ยินดีด้วยที่ชนะ! :)
tomsmeding

4

BlindSnake

ชุด

บอทนี้แค่เฝ้าดูสภาพแวดล้อมที่ใกล้เคียง หากไม่มีกำแพงมันจะเคลื่อนที่ไปที่นั่น

@echo off
setlocal enableextensions enabledelayedexpansion
set map=%1

REM find position
set I=0
set L=-1
:l
if "!map:~%I%,1!"=="" goto ld
if "!map:~%I%,1!"=="1" set L=%I%
set /a I+=1
goto l
:ld
set /a pos = %L%
set /a row = %pos% / 26
set /a col = %pos% %% 26

REM find surroundings
If %row%==0 (
    set /a northPos = 24 * 26 + %col%
) else (
    set /a rowDown = %row% - 1
    set /a northPos=!rowDown! * 26 + !col!
)
If %row%==24 (
    set /a southPos = %col%
) else (
    set /a rowDown = %row%+1
    set /a southPos=!rowDown!*26+!col!
)
If %col%==0 (
    set /a westPos = %row% * 26 + 24
) else (
    set /a westPos = %pos% - 1
)
If %col%==24 (
    set /a eastPos = %row% * 26
) else (
    set /a eastPos = %pos% + 1
)

REM choose move
if "!map:~%northPos%,1!" neq "#" (
    echo N
    goto end
)
if "!map:~%eastPos%,1!" neq "#" (
    echo E
    goto end
)
if "!map:~%southPos%,1!" neq "#" (
    echo S
    goto end
)
if "!map:~%westPos%,1!" neq "#" (
    echo W
    goto end
)
echo N
:end

ฉันแค่ต้องการสร้างบอทในแบทช์ ... และจะไม่ทำมันอีกเลย


4

FluidBot

Python 3

ใช้เส้นทางที่มีแนวต้านน้อยที่สุดและพยายามทำนายคู่ต่อสู้

import sys, math

def mvs(j,x,y,d,*args):
    score = sum([
                    ((j[y-1][x]=='.') * ((j[rgpos[1][1]+1][rgpos[1][0]]=='#')/3+1)) /
                        ([j[y-1][x+1], j[y-1][x-1]].count('#')+1)
                        * (d != 'S'),
                    ((j[y+1][x]=='.')*((j[rgpos[1][1]-1][rgpos[1][0]]=='#')/3+1)) /
                        ([j[y+1][x+1], j[y+1][x-1]].count('#')+1)
                        *(d != 'N'),
                    ((j[y][x-1]=='.')*((j[rgpos[1][1]][rgpos[1][0]+1]=='#')/3+1)) /
                        ([j[y+1][x-1], j[y-1][x-1]].count('#')+1)
                        *(d != 'W'),
                    ((j[y][x+1]=='.')*((j[rgpos[1][1]][rgpos[1][0]-1]=='#')/3+1)) /
                        ([j[y-1][x+1], j[y+1][x+1]].count('#')+1)
                        *(d != 'E')
                ]) * (j[y][x]=='.')
    if len(args):
        if args[0] > 0:
            mvx = {'N': [x, y-1], 'S': [x, y+1], 'E': [x+1, y], 'W': [x-1, y]}
            nscr = score * (args[0] + mvs(j,mvx[d][0],mvx[d][1],d,args[0]-1))
            return(nscr)
        else:
            return(score)
    else:
        return(score*mvs(j,x,y,d,[len(g),len(g[0])][d in ['E','W']]-1))

g = sys.argv[1].split(';')[:-1]
fg = sys.argv[1].replace(';', '')

pos = [fg.index('1'), fg.index('2')]
pos = [
        [pos[0]%len(g[0]), math.floor(pos[0]/len(g[0]))],
        [pos[1]%len(g[0]), math.floor(pos[1]/len(g[0]))]
    ]
rg = ';'.join(g).replace('1', '#').replace('2', '#').split(';')
mg = [c+c+g[i]+c+c for i,c in enumerate(rg)]
rg = [i*5 for i in rg]

rg = rg + rg + mg + rg + rg
rgpos = [
        [pos[0][0]+len(g[0]), pos[0][1]+len(g)],
        [pos[1][0]+len(g[0]), pos[1][1]+len(g)]
    ]
relpos = [
            rgpos[1][0]-rgpos[0][0],
            rgpos[1][1]-rgpos[0][1]
        ]

moves = {
        'N': ((relpos[1]>0)/3+1)*mvs(rg, rgpos[0][0], rgpos[0][1]-1, 'N'),
        'S': ((relpos[1]<0)/3+1)*mvs(rg, rgpos[0][0], rgpos[0][1]+1, 'S'),
        'E': ((relpos[0]<0)/3+1)*mvs(rg, rgpos[0][0]+1, rgpos[0][1], 'E'),
        'W': ((relpos[0]>0)/3+1)*mvs(rg, rgpos[0][0]-1, rgpos[0][1], 'W')
        }

sys.stdout.write(sorted(moves, key=lambda x:-moves[x])[0])

ทำงานเกี่ยวกับเรื่องนี้ประมาณหนึ่งชั่วโมง ._

ทดสอบกับ AwayBot:

Player 1: E
Player 2: W
#.....#####.......##.....
#.....###1.........##...#
....................#####
.........................
.........................
.........................
......######.............
......#....####..........
......#.......##.........
......#........###.......
.....##..........#.......
.....#...........#.......
.....#...........#.......
....##......##...#.......
....###.....##...#.......
......#...#####..#.......
....###...#...#..#.......
....#..####...##.##......
....#..#.......#..##.....
....##2#.......#...##....
.......#.......##...##...
.......#........#....##..
.......#........#.....##.
.......##.......##.....##
........###......##.....#

Player 1 wins!

FillUpBot:

Player 1: W
Player 2: E
#......................#2
#......................##
......................##.
......................#..
.....................##..
....................##...
....................#....
...................##....
..................##.....
..................#......
.......1###########......
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
.........................
#########################
.......................##

Player 1 wins!

แก้ไข 5 : อนาคตที่ใส่ใจมากขึ้น; พยายามหลีกเลี่ยงการปิดพื้นที่ (เว้นแต่แน่นอนว่าคู่ต่อสู้อยู่ในนั้น)

แก้ไข 4 : ล้างรหัส

แก้ไข 3 : ทำงานได้ดีขึ้นสำหรับพื้นที่เล่นรูปสี่เหลี่ยมผืนผ้า

แก้ไข 2 : โค้ดที่สะอาดกว่าอัลกอริทึมมีเหตุผลมากกว่าและคาดการณ์การเคลื่อนไหวบางอย่างในอนาคต

แก้ไข : อัลกอริทึมการป้องกันเพิ่มเติมไม่นับผีตัวเองเป็นพื้นที่ว่าง


3

AwayBot

เขียนในทับทิม (1.9)

AwayBot ตั้งชื่ออย่างถูกต้องว่าพยายามหลบสิ่งกีดขวางใด ๆ มันค้นหาสี่เหลี่ยมจัตุรัสรอบตัว 15x15 น้ำหนักทิศทางนั้นและเลือกทิศทางที่มีสิ่งกีดขวางน้อยที่สุด (นี่ก็หมายความว่ามันหลีกเลี่ยงขอบซึ่งก็ดีดังนั้นมันจึงไม่ติดกับพวกมัน)

นอกจากนี้ยังพิจารณากำแพงที่อยู่ใกล้ ๆ ว่าเป็นอันตรายมากกว่า กำแพงที่อยู่ติดกับมันมีน้ำหนักมากกว่าผนังที่อยู่ไกลออกไป

Sสำหรับการป้อนข้อมูลตัวอย่างของคุณมันจะออกผลลัพธ์ น้ำหนักสำหรับแต่ละทิศทางของอินพุตตัวอย่างคือ[["N", 212], ["E", 140], ["S", 0], ["W", 84]]น้ำหนักสำหรับแต่ละทิศทางของการป้อนข้อมูลตัวอย่าง

คำอุทาน: ฉันเพิ่งสังเกตเห็นว่าเวทีล้อมรอบ ถ้าอย่างนั้นเทคนิคการหลีกเลี่ยงขอบของฉันก็ไร้ประโยชน์แล้ว บางทีฉันจะแก้ไขในภายหลัง

arena = ARGF.argv[0]

# we're considering the enemy a wall, for simplicity.
# no need to weight him any more than the other walls because he will
# always be surrounded by walls anyway.
arena = arena.sub(?2, ?#).split(?;)

# pad the arena with extra walls (edges of the arena)
searchRadius = 7
arenaSize = arena.first.size

verticalEdgeWalls = [?# * arenaSize] * searchRadius
arena = verticalEdgeWalls + arena + verticalEdgeWalls

horizontalEdgeWalls = ?# * searchRadius
arena.map! {|row| (horizontalEdgeWalls + row + horizontalEdgeWalls).split('') }

# now get the area around the bot
botRow = arena.index{|row| row.index ?1 }
botCol = arena[botRow].index ?1

searchZone = arena.slice(botRow-searchRadius..botRow+searchRadius)
searchZone.map! {|row| row.slice(botCol-searchRadius..botCol+searchRadius) }

# second to last step: assign values to each square depending on how far away they are
# from the player (Manhattan distance)
# this is so that the player avoids running directly into a wall; higher value means closer tile
# 0123210
# 1234321
# 2345432
# 1234321
# 0123210
centerSquare = searchRadius
searchZone = searchZone.each_with_index.map {|row, rowIndex| row.each_with_index.map{|tile, tileIndex|
    [tile, searchRadius*2 - ((rowIndex - centerSquare).abs + (tileIndex - centerSquare).abs)]
} }
puts searchZone.map{|x|x.map{|y|y[1].to_s.rjust(2, ?0)}.join ' '} * "\n"

# finally, assign weights to each direction
# first, create a map of directions. each direction has an array, the first element being
# what rows to slice and the second being what column.
sBeg = 0
sMdl = searchRadius
sEnd = searchRadius*2
directions = {
    ?N => [sBeg..sMdl-1, sBeg..sEnd],
    ?E => [sBeg..sEnd, sMdl+1..sEnd],
    ?S => [sMdl+1..sEnd, sBeg..sEnd],
    ?W => [sBeg..sEnd, sBeg..sMdl-1]
}
# then, create another hash of weights
weights = directions.map{|dir, arr|
    section = searchZone.slice(arr[0]).map{|x| x.slice(arr[1]) }.flatten(1)
    [dir, (section.select{|tile| tile[0] == ?# }.map{|tile| tile[1] }.reduce(:+) || 0)] # return the sum of the values of the walls in the area
}
# yay! we have our weights! now just find the smallest one...
dirToGo = weights.min_by{|_, walls| walls }
# and output!
print dirToGo[0]

นี่ก็หมายความว่ามันหลีกเลี่ยงขอบซึ่งก็ดีดังนั้นมันจึงไม่ติดกับพวกมัน " - ขอบไม่ห่อหรือไม่
Hovercouch

1
@ โฮ่เอ่อใช่คุณไม่ได้อ่านย่อหน้าสุดท้ายเหรอ? ;-)
Doorknob

@ Doorknob ให้แน่ใจว่าคุณได้รับข้อมูลของคุณผ่านทางบรรทัดคำสั่งดังนั้นARGF.argv[0].chompแทนที่จะเป็นgets.chompในบรรทัดแรก!
tomsmeding

@Doorknob คุณควรระบุรุ่น Ruby ของคุณ ฉันคิดว่านี่ใช้คุณสมบัติบางอย่างที่ไม่เป็นสากล
ไม่ใช่ Charles

@tomsmeding อ่าไม่ได้ตระหนักถึงเรื่องนั้น ขอขอบคุณการแก้ไข
Doorknob

3

FillUpBot

เขียนใน C ++

อย่าคิดว่าฉันจะชนะ แต่นี่คือสิ่งที่ฉันทำได้:

#include <iostream>
#include <cassert>
#include <cmath>
#include <cstdlib>

#define SIZE 25

using namespace std;

class Board{
public:
    unsigned long long walls[SIZE]; //each int is a bitmap with the LSbit being the left side
    int p1x,p1y,p2x,p2y;
    void read(const char *arg){
        int map,i,j;
        for(i=0;i<SIZE;i++){
            for(map=1,j=0;j<SIZE;map<<=1,j++){
                if(arg[(SIZE+1)*i+j]=='1'){
                    p1x=j;
                    p1y=i;
                } else if(arg[(SIZE+1)*i+j]=='2'){
                    p2x=j;
                    p2y=i;
                }
                walls[i]=(walls[i]&~map)|(map*(arg[(SIZE+1)*i+j]=='#'));
            }
        }
    }
    bool operator==(const Board &other){
        int i;
        for(i=0;i<SIZE;i++)if(walls[i]!=other.walls[i])return false;
        if(p1x!=other.p1x||p1y!=other.p1y||p2x!=other.p2x||p2y!=other.p2y)return false;
        return true;
    }
};

inline int mod(int a,int b){return (a+b)%b;}
inline int min(int a,int b){return a<b?a:b;}

int main(int argc,char **argv){
    assert(argc==2);
    Board B;
    B.read(argv[1]);
    //cerr<<"KOTW: read"<<endl;
    if(hypot(B.p2x-B.p1x,B.p2y-B.p1y)<=3||hypot(mod(B.p2x+SIZE/2,SIZE)-mod(B.p1x+SIZE/2,SIZE),mod(B.p2y+SIZE/2,SIZE)-mod(B.p1y+SIZE/2,SIZE))<=3){
        double maxdist=-1,d;
        int maxat=-1; //0=E, 1=N, 2=W, 3=S
        //cerr<<B.walls[B.p1y]<<endl;
        if(!(B.walls[B.p1y]&(1<<mod(B.p1x+1,SIZE)))){
            d=min(hypot(mod(B.p2x-(B.p1x+1),SIZE),mod(B.p2y-B.p1y,SIZE)),hypot(mod(B.p1x+1-B.p2x,SIZE),mod(B.p1y-B.p2y,SIZE)));
            //cerr<<"E: "<<d<<endl;
            if(d>maxdist){
                maxdist=d;
                maxat=0; //E
            }
        }
        //cerr<<B.walls[mod(B.p1y-1,SIZE)]<<endl;
        if(!(B.walls[mod(B.p1y-1,SIZE)]&(1<<B.p1x))){
            d=min(hypot(mod(B.p2x-B.p1x,SIZE),mod(B.p2y-(B.p1y-1),SIZE)),hypot(mod(B.p1x-B.p2x,SIZE),mod(B.p1y-1-B.p2y,SIZE)));
            //cerr<<"N: "<<d<<endl;
            if(d>maxdist){
                maxdist=d;
                maxat=1; //N
            }
        }
        //cerr<<B.walls[B.p1y]<<endl;
        if(!(B.walls[B.p1y]&(1<<mod(B.p1x-1,SIZE)))){
            d=min(hypot(mod(B.p2x-(B.p1x-1),SIZE),mod(B.p2y-B.p1y,SIZE)),hypot(mod(B.p1x-1-B.p2x,SIZE),mod(B.p1y-B.p2y,SIZE)));
            //cerr<<"W: "<<d<<endl;
            if(d>maxdist){
                maxdist=d;
                maxat=2; //W
            }
        }
        //cerr<<B.walls[mod(B.p1y+1,SIZE)]<<endl;
        if(!(B.walls[mod(B.p1y+1,SIZE)]&(1<<B.p1x))){
            d=min(hypot(mod(B.p2x-B.p1x,SIZE),mod(B.p2y-(B.p1y+1),SIZE)),hypot(mod(B.p1x-B.p2x,SIZE),mod(B.p1y+1-B.p2y,SIZE)));
            //cerr<<"S: "<<d<<endl;
            if(d>maxdist){
                maxdist=d;
                maxat=3; //S
            }
        }
        if(maxat==-1){ //help we're stuck!
            cout<<"ENWS"[(int)((double)rand()/RAND_MAX*4)]<<endl;
            return 0;
        }
        cout<<"ENWS"[maxat]<<endl;
        return 0;
    }
    //cerr<<"KOTW: <=3 checked"<<endl;
    //cerr<<B.p1x<<","<<B.p1y<<endl;
    if(!(B.walls[B.p1y]&(1<<mod(B.p1x+1,SIZE))))cout<<'E'<<endl;
    else if(!(B.walls[mod(B.p1y+1,SIZE)]&(1<<B.p1x)))cout<<'S'<<endl;
    else if(!(B.walls[mod(B.p1y-1,SIZE)]&(1<<B.p1x)))cout<<'N'<<endl;
    else if(!(B.walls[B.p1y]&(1<<mod(B.p1x-1,SIZE))))cout<<'W'<<endl;
    else cout<<"ENWS"[(int)((double)rand()/RAND_MAX*4)]<<endl; //help we're stuck!
    //cerr<<"KOTW: done"<<endl;
    return 0;
}

คอมไพเลอร์ C ++ มาตรฐานของคุณควรจะสามารถจัดการกับสิ่งนี้ได้


ดูเหมือนจะไม่สามารถรวบรวม GCC 4.8.1, Windows 7 แสดงข้อผิดพลาดเกี่ยวกับ rand และ RAND_MAX ที่ไม่ได้ถูกกำหนด
cjfaure

@Trimsty #include <cstdlib>ช่วยได้ไหม? (เพียงแค่ใส่ไว้ที่ด้านบนเป็นเส้นใหม่)
tomsmeding

แน่นอน! มันรวบรวมตอนนี้ ขอบคุณ
cjfaure

วิ่งตาม FluidBot ล้มเหลวในการสร้างผลลัพธ์ในการย้ายครั้งนี้: pastie.org/private/azmwkybqrxqlfvpwidlpw (FluidBot เป็นผู้เล่น 1)
cjfaure

@Trimsty อืม ... gist.github.com/tomsmeding/96060c7db3f1c3483668 (1 และ 2 สลับถ้าผมไม่สลับพวกเขาจะช่วยให้การส่งออกเดียวกัน)
tomsmeding

3

Arcbot

Python 3

เล่นกับอัลกอริธึมที่อิงกับความก้าวร้าวในฐานะศัตรูและตอบโต้อย่างดุเดือดด้วยอิทธิพล

อัลกอริทึมนี้เป็น 'อารมณ์ตาม' ฉันเดา ในการพัฒนาสิ่งนี้ฉันตระหนักว่า FluidBot สามารถเอาชนะได้เกือบทุกครั้ง Arcbot ไม่ใช่อัลกอริทึมที่เร็วที่สุดหรือดีที่สุด แต่ก็มีจุดแข็ง

มันไม่ผิดพลาดเข้าไปในกำแพง ไม่รู้ว่าทำไม

FLUIDBOT นั้นดีกว่า

#   Arcbot
#   
#   This is a more dynamic bot than the earlier Fluidbot.
#   I'm also commenting on the code to make my algorithm
#   more clear.

#** Some intial definitions **#

import math, sys # math for the 'arc' part

class edgeWrapList: # yay, such efficient
    def __init__(self, l):
        self.l = list(l)
    def __getitem__(self, i):
        it = i%len(self.l)
        if it == i: # no wrapping, include players
            return(self.l[i])
        else: # wrapping, replace players with walls
            if not isinstance(self.l[it], str):
                return(self.l[it])
            else:
                return(self.l[it].replace('1', '#').replace('2', '#'))
    def __len__(self):
        return(len(self.l))
    def __str__(self):
        return(''.join(str(i) for i in self.l))
    def __setitem__(self, i, v):
        self.l[i%len(self.l)] = v

grid = edgeWrapList([edgeWrapList([j for j in i]) for i in sys.argv[1].split(';')[:-1]]) # a 2D edgeWrapList. Access via grid[y][x]

attackStr = 1 # distance to attack from
attackEnd = 12 # distance to avoid again

predictTurns = 6 # how many turns to play as the opponent as well. Keep low for performance.

#** Arcbot's main class **#

class arcbot:
    def __init__(self, g, astr, aend):
        self.g = g # g is a 2D edgeWrapList
        self.p1p = str(g).index('1')
        self.p1p = [self.p1p%len(g[0]), math.floor(self.p1p/len(g[0]))] # x, y of player 1
        self.p2p = str(g).index('2')
        self.p2p = [self.p2p%len(g[0]), math.floor(self.p2p/len(g[0]))] # x, y of player 2
        self.astr = astr
        self.aend = aend
    def getAggr(self, d):
        if self.astr < d < self.aend:
            return(0)
        else:
            return(math.cos((d-self.astr)*(math.pi*2/self.aend))) # sort-of bell curve between -1 and 1
    def getMove(self, p): # p is either 1 or 2
        scrg = edgeWrapList(self.scoreGridGen(p)) # get dem position scores
        pos = self.p1p if p==1 else self.p2p
        dir = {
            'N': scrg[pos[1]-1][pos[0]], 
            'S': scrg[pos[1]+1][pos[0]],
            'E': scrg[pos[1]][pos[0]+1],
            'W': scrg[pos[1]][pos[0]-1]
            }
        o = sorted(dir, key=lambda x:-dir[x])[0]
        return([o, dir[o]]) # return direction with highest scoring position and it's score
    def getScore(self, x, y, p, d='*'):
        epos = self.p2p if p == 1 else self.p1p
        dist = math.sqrt((y - epos[1])**2 + (x - epos[0])**2)
        return((sum([
                (self.g[y][x-1] == '.') * (((self.g[y][x+1] == '.')+1) * ((self.g[y][x-2] == '.')*4+1)),
                (self.g[y][x+1] == '.') * (((self.g[y][x-1] == '.')+1) * ((self.g[y][x+2] == '.')*4+1)),
                (self.g[y-1][x] == '.') * (((self.g[y+1][x] == '.')+1) * ((self.g[y-2][x] == '.')*4+1)),
                (self.g[y+1][x] == '.') * (((self.g[y-1][x] == '.')+1) * ((self.g[y+2][x] == '.')*4+1))
            ]) * 2 + 1) * (self.getAggr(dist) / 10 + 1) * (self.g[y][x] == '.'))
    def scoreGridGen(self, p): # turn .s into numbers, higher numbers are better to move to
        o = []
        for y,r in enumerate(self.g.l): # y, row
            o.append(edgeWrapList(
                    self.getScore(x, y, p) for x,v in enumerate(r.l) # x, value
                )
            )
        return(o)
    def play(self, turns, movestr): # movestr is [p1moves, p2moves]
        p2move = self.getMove(2)
        movestr[1] += [p2move[0]]
        p1move = self.getMove(1)
        if len(movestr[0]) == turns:
            return([p1move[1], p1move[0]]) # Score for final block
        scores = {}
        for i in 'N S E W'.split():
            movestr[0] += [i]
            og = self.simMoves(movestr)
            if og == 'LOSE:2':
                scores[i] = 1000000 # we win!
            elif og == 'LOSE:1':
                scores[i] = -1000000 # we lose!
            else:
                scores[i] = og[1] * ((i == p1move[0]) / 1.2 + 1) * (turns-len(movestr[0])) * (self.play(turns, movestr)[0]+1)
            movestr[0] = movestr[0][:-1]
        hst = sorted(scores, key=lambda x:-scores[x])[0]
        return([scores[hst], hst]) # highest scoring turn in total and it's score
    def simMove(self, p, d): # move player p in direction d
        pos = self.p1p if p == 1 else self.p2p
        target = {
            'N': [pos[0], pos[1]-1],
            'S': [pos[0], pos[1]+1],
            'E': [pos[0]+1, pos[1]],
            'W': [pos[0]-1, pos[1]]
            }[d]
        v = self.g[target[1]][target[0]] # contents of target block
        if v == '.': # yay let's move here
            self.g[target[1]][target[0]] = str(p)
            self.g[pos[1]][pos[0]] = '#'
            if p == 1:
                self.p1p = [target[0], target[1]]
            else:
                self.p2p = [target[0], target[1]]
        else: # nuu crash
            raise(ValueError) # doesn't matter, caught later
    def simMoves(self, mvl): # return simmed copy
        op = [self.p1p, self.p2p]
        og = self.g
        finalScore = 0
        for i in range(len(mvl[0])):
            try:
                if i == len(mvl[0])-2:
                    finalScore = {
                        'N': self.getScore(self.p1p[0], self.p1p[1]-1, 'N'),
                        'S': self.getScore(self.p1p[0], self.p1p[1]+1, 'S'),
                        'E': self.getScore(self.p1p[0]+1, self.p1p[1], 'E'),
                        'W': self.getScore(self.p1p[0]-1, self.p1p[1], 'W')
                        }[mvl[0][i]]
                self.simMove(1, mvl[0][i])
            except:
                return('LOSE:1')
            try:
                self.simMove(2, mvl[1][i])
            except:
                return('LOSE:2')
        o = self.g
        self.g = og
        self.p1p, self.p2p = op
        return([o, finalScore])

arcbotMove = arcbot(grid, attackStr, attackEnd)
sys.stdout.write(arcbotMove.play(predictTurns, [[], []])[1])

แก้ไข : ปรับตัวเลขและสูตรตอนนี้เล่นได้ดีขึ้น แต่ก็ยังแพ้ Fluidbot

แก้ไข 2 : อ๊ะลืมเปลี่ยนรหัส


1

RandomBot

ค#

RandomBot สุ่มเลือกทิศทางจนกว่าเส้นทางจะว่าง หากไม่มีทิศทางที่ปลอดภัยก็เพียงแค่พิมพ์*และเสีย

using System;

class AI
{
    static void Main(string[] args)
    {
        char[,] grid = new char[25, 25];
        char[] directions = { 'N', 'E', 'S', 'W' };
        string map = args[0];
        Random rand = new Random();
        int[] pos = new int[2];
        for (var x = 0; x < 25; x++)
        {
            for (var y = 0; y < 25; y++)
            {
                grid[x, y] = map.Split(';')[y][x];
                if (grid[x,y] == '1') {
                    pos[0] = x;
                    pos[1] = y;
                }
            }
        }
        if (grid[(pos[0] + 1) % 25, pos[1]] != '.' && grid[pos[0], (pos[1] + 1) % 25] != '.' && grid[(pos[0] + 24) % 25, pos[1]] != '.' && grid[pos[0], (pos[1] + 24) % 25] != '.')
        {
            if (grid[pos[0], (pos[1] + 24) % 25] == '2')
            {
                Console.Write("N");
            }
            else if (grid[(pos[0] + 1) % 25, pos[1]] == '2')
            {
                Console.Write("E");
            }
            else if (grid[pos[0], (pos[1] + 1) % 25] == '2')
            {
                Console.Write("S");
            }
            else if (grid[(pos[0] + 24) % 25, pos[1]] == '2')
            {
                Console.Write("W");
            }
            else
            {
                Console.Write("*");
            }
        }
        else
        {
            while (true)
            {
                char direction = directions[Convert.ToInt32(rand.Next(4))];
                if (direction == 'N' && grid[pos[0], (pos[1] + 24) % 25] == '.')
                {
                    Console.Write("N");
                    break;
                }
                else if (direction == 'E' && grid[(pos[0] + 1) % 25, pos[1]] == '.')
                {
                    Console.Write("E");
                    break;
                }
                else if (direction == 'S' && grid[pos[0], (pos[1] + 1) % 25] == '.')
                {
                    Console.Write("S");
                    break;
                }
                else if (direction == 'W' && grid[(pos[0] + 24) % 25, pos[1]] == '.')
                {
                    Console.Write("W");
                    break;
                }
            }
        }
    }
}

นี่เป็นเพียงตัวอย่างเท่านั้น - มันไม่ได้ถูกออกแบบมาเพื่อชนะ!


-1

Fill Up Bot (หมุน 90 องศาทวนเข็มนาฬิกาเมื่อเผชิญหน้ากับสิ่งกีดขวาง

C ++

ในรหัสของฉันผู้เล่นสองคน (1 และ 2) พยายามท่วม ความหมายเมื่อใดก็ตามที่พวกเขาเผชิญกับอุปสรรคพวกเขาหันทวนเข็มนาฬิกา
โปรดจำไว้ว่าบรรทัดในอินพุตนั้นคั่นด้วยspaceหรือnewlineไม่;

#include<iostream>
#include<conio.h>
#include<windows.h>
char draw(char plot[][25],char dir,char num)
{
    int a=1,i,j;
    for(i=0;i<25;i++)
    {
        for(j=0;j<25;j++)
        {
            if(plot[i][j]==num&&a)
            {
                a--;
                switch(dir)
                {
                    case 'S':{
                        if(i==24||plot[i+1][j]=='#')
                        {
                            dir='E';
                            plot[i][j]='#';
                            plot[i][j+1]=num;
                        }
                        else if(i<24||plot[i+1][j]=='.')
                        {
                            plot[i][j]='#';
                            plot[i+1][j]=num;
                        }
                        break;
                    }
                    case 'E':{
                        if(j==24||plot[i][j+1]=='#')
                        {
                            dir='N';
                            plot[i][j]='#';
                            plot[i-1][j]=num;
                        }
                        else if(j<24||plot[i][j+1]=='.')
                        {
                            plot[i][j]='#';
                            plot[i][j+1]=num;
                        }
                        break;
                    }
                    case 'N':{
                        if(i==0||plot[i-1][j]=='#')
                        {
                            dir='W';
                            plot[i][j]='#';
                            plot[i][j-1]=num;
                        }
                        else if(i>0||plot[i-1][j]=='.')
                        {
                            plot[i][j]='#';
                            plot[i-1][j]=num;
                        }
                        break;
                    }
                    case 'W':{
                        if(j==0||plot[i][j-1]=='#')
                        {
                            dir='S';
                            plot[i][j]='#';
                            plot[i+1][j]=num;
                        }
                        else if(j>0||plot[i][j-1]=='.')
                        {
                            plot[i][j]='#';
                            plot[i][j-1]=num;
                        } 
                        break;
                    }
                }
            }
        }
    }
    return dir;
}
void run()
{
    int i,j,crash=1,count,k,a;
    char plot[25][25],dir1='S',dir2='N';
    for(i=0;i<25;i++)
        std::cin>>plot[i];
    plot[0][0]='1';
    plot[24][24]='2';
    while(crash)
    {
        system("cls");
        dir1=draw(plot,dir1,'1');
        dir2=draw(plot,dir2,'2');
        count=0;
        for(i=0;i<25;i++)
            for(j=0;j<25;j++)
                if(plot[i][j]=='.')count++;
        if(count==1)
        {
            crash--;
            plot[12][12]='*';
            plot[11][12]='#';
            plot[13][12]='#';
        }
        for(i=0;i<25;i++)
        {
            for(j=0;j<25;j++)
                std::cout<<plot[i][j];
            std::cout<<'\n';
        }
        Sleep(25);
    }
}
int main()
{
    run();
    getch();
    return 0;
}

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