Vua của các bức tường


10

Để ý

Thử thách này đã kết thúc và sẽ không được đánh giá lại, nhưng hãy đăng câu trả lời và kiểm tra chương trình của bạn với những người khác bằng Chương trình Kiểm soát!

Mục đích của thử thách này là tạo ra một AI để giành chiến thắng trong cuộc chiến chống lại một AI khác bằng cách chiến lược vẽ một bức tường trên lưới 25x25 để chặn đối thủ.

Đầu vào

25 dòng được phân tách bằng và kết thúc bằng ;một đối số dòng lệnh. Điều này sẽ bao gồm:

  • Những khoảng trống .
  • Tường #
  • Người chơi 12(Đối thủ luôn luôn 2)

Thí dụ

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

đại diện cho bản đồ sau:

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

Đầu ra

Một chuỗi được ghi vào bảng điều khiển bắt đầu bằng ký tự đại diện cho hướng mà AI muốn rẽ. Đây trường hợp nhạy cảm!

  • Bắc N
  • phía đông E
  • miền Nam S
  • hướng Tây W
  • Từ bỏ (Bất cứ điều gì khác)

Thí dụ

W

Luật chơi

  • Khi các AI di chuyển, chúng sẽ để lại một vệt tường vững chắc phía sau chúng.
  • Người chơi bắt đầu ở góc trên bên trái và dưới cùng bên phải
  • Trò chơi kéo dài cho đến khi bất kỳ AI nào va vào tường hoặc các AI đâm vào nhau.
    • Một AI chiến thắng nếu đối thủ của họ gặp sự cố trước
    • Không người chiến thắng hay kẻ thua cuộc nếu cả hai AI đều thua cùng một lúc.
  • Nếu một AI đi ra khỏi một cạnh của lưới, chúng sẽ tiếp tục đi theo hướng tương tự từ phía bên kia.

Xếp hạng

Vị trí số 1 - FloodBot (Java, 12 trận thắng)

Vị trí thứ 2 - FluidBot (Python, 9 trận thắng)

Vị trí thứ 3 - FillUpBot (C ++, 8 trận thắng)

Vị trí thứ 4 - AwayBot (Ruby, 5 trận thắng)

Vị trí thứ 5 - ArcBot (Python, 4 chiến thắng)

Vị trí thứ 6 - BlindSnake (Batch, 2 trận thắng)

Vị trí thứ 6 - RandomBot (C #, 2 trận thắng)

Chương trình điều khiển (Đã kiểm tra Python 3.3.3)

Chương trình được chạy với các đối số của hai lệnh và một đối số duy nhất ( ""nếu không bắt buộc) cho các AI, ví dụ. Control.py "ruby" "AwayBot.rb" "FillUpBot.exe" "". Nó có thể được tải xuống ở đây .

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
Bạn cần thêm API và chương trình thử NGAY BÂY GIỜ! Làm thế nào khác chúng ta sẽ có thể viết mã để giao diện với nó? Cờ như không rõ ràng.
AJMansfield

3
Có vẻ như là một thử thách thú vị, nhưng eh .., đó là 'chương trình thử nghiệm' (đó là chương trình điều khiển phải không?), Đó là ngôn ngữ gì và tôi có phải biên dịch nó không? Xin vui lòng cho chúng tôi biết làm thế nào để sử dụng nó.
Herjan

3
Có vẻ như một thách thức thú vị mà tôi sẽ không cạnh tranh do (A) hạn chế hệ điều hành (người dùng chỉ dành cho Linux) và (B) hạn chế ngôn ngữ (chủ yếu là Fortran nhưng làm việc trong việc học Lua)
Kyle Kanos

2
@Doorknob Bây giờ tôi đang cài đặt Ruby và đang suy nghĩ về việc học cách sử dụng nó.
kitcar2000

2
@ kitcar2000 ah Tôi thấy thế là đủ công bằng. cách khác, bạn có thể cung cấp nó thông qua stdin, nhưng sử dụng một dòng duy nhất làm đối số là trò chơi công bằng. Điều đó đang được nói, vì bản đồ của bạn có kích thước cố định, bạn không cần bất kỳ dấu phân cách nào cả.
Martin Ender

Câu trả lời:


8

Lũ quét

Java

Anh chàng này là tất cả về tránh. Anh ta không quan tâm đến việc cố gắng gài bẫy đối thủ, anh ta chỉ muốn sống. Để làm điều đó, anh ta lấp đầy mỗi hướng để xem con đường nào sẽ dẫn đến khu vực mở lớn nhất.

Anh ta cũng nghĩ rằng kẻ thù là không thể đoán trước, vì vậy anh ta đối xử với từng ô vuông ngay lập tức xung quanh họ như đã là một bức tường. Nếu điều đó dẫn đến không thể có hướng, anh ta sẽ rơi trở lại bản đồ "thực tế".

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;
}

Tôi nghĩ rằng bạn đã có cái này trong túi.
cjfaure

@Trimsty ơi? Tôi chưa thử nghiệm với tất cả các đối thủ cạnh tranh, vì vậy tôi không chắc nó đã chống lại một vài người trong số họ như thế nào. Những điều cần biết :)
Geobits

Chúc mừng chiến thắng! :)
tomsmeding

4

BlindSnake

Lô hàng

Bot này chỉ xem môi trường xung quanh của nó. Nếu không có một bức tường, nó sẽ di chuyển đến đó.

@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

Tôi chỉ muốn tạo một bot theo đợt ... Và sẽ không bao giờ làm lại


4

Chất lỏng

Con trăn 3

Có đường đi ít kháng cự nhất và cố gắng dự đoán đối thủ

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])

Làm việc trên này trong khoảng một giờ. ._.

Đã thử nghiệm với AwayBot:

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

Player 1 wins!

FillUpBot:

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

Player 1 wins!

EDIT 5 : Ý thức tương lai hơn; cố gắng tránh đóng cửa các khu vực (tất nhiên trừ khi đối thủ ở trong đó).

EDIT 4 : Làm sạch mã.

EDIT 3 : Hoạt động tốt hơn cho các khu vực chơi hình chữ nhật.

EDIT 2 : Mã sạch hơn, thuật toán hợp lý hơn và dự đoán một số bước đi trong tương lai

EDIT : Thuật toán phòng thủ nhiều hơn, không tính ma tự là không gian trống.


3

AwayBot

được viết bằng Ruby (1.9)

Có tên Aptly, AwayBot cố gắng tránh xa mọi trở ngại. Nó tìm kiếm một hình vuông 15x15 xung quanh chính nó, cân các hướng tương ứng và chọn hướng có ít chướng ngại vật nhất. (Điều này cũng có nghĩa là nó tránh được các cạnh, điều này là tốt để nó không bị mắc kẹt trong đó.)

Nó cũng coi các bức tường gần hơn là nguy hiểm hơn. Những bức tường ngay bên cạnh nó có trọng lượng lớn hơn nhiều so với những bức tường ở xa.

Đối với đầu vào mẫu của bạn, nó đầu ra S. Các trọng số cho mỗi hướng của đầu vào mẫu là [["N", 212], ["E", 140], ["S", 0], ["W", 84]].

Thán từ: Tôi chỉ nhận thấy rằng đấu trường kết thúc tốt đẹp. Vậy thì, kỹ thuật tránh cạnh của tôi bây giờ có phần vô nghĩa, nhưng meh. Có lẽ tôi sẽ sửa nó sau.

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]

"Điều này cũng có nghĩa là nó tránh được các cạnh, điều này là tốt để nó không bị mắc kẹt trong chúng." - Đừng bao bọc các cạnh?
Hovercouch

1
@Hover Umm, vâng, bạn đã không đọc đoạn cuối phải không? ;-)
Doorknob

@Doorknob Hãy chắc chắn rằng bạn nhận được thông tin đầu vào của bạn thông qua dòng lệnh, do đó ARGF.argv[0].chompthay vì gets.chomptrong dòng đầu tiên!
tomsmeding

@Doorknob có lẽ bạn nên chỉ định phiên bản Ruby của mình. Tôi nghĩ rằng điều này sử dụng một số tính năng không phổ biến
Không phải Charles

@tomsmeding Ah, không nhận ra điều đó. Cảm ơn, chỉnh sửa
Doorknob

3

FillUpBot

được viết bằng C ++

Đừng nghĩ rằng tôi sẽ giành chiến thắng, nhưng dù sao thì tôi cũng sẽ làm điều đó:

#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;
}

Trình biên dịch C ++ tiêu chuẩn của bạn sẽ có thể xử lý việc này.


Dường như không thể biên dịch. GCC 4.8.1, Windows 7. Ném lỗi về rand và RAND_MAX không được xác định.
cjfaure

@Trimsty Có #include <cstdlib>giúp được không? (Chỉ cần chèn nó ở trên cùng như một dòng mới)
tomsmeding

Thật! Nó biên dịch ngay bây giờ. Cảm ơn.
cjfaure

Chạy nó chống lại FluidBot, không thể tạo ra kết quả đầu ra cho di chuyển này: pastie.org/private/azmwkybqrxqlfvpwidlpw (FluidBot là người chơi 1)
cjfaure

@Trimsty Um ... gist.github.com/tomsmeding/96060c7db3f1c3483668 (1 và 2 đã hoán đổi; nếu tôi không trao đổi chúng, nó sẽ cho cùng một đầu ra)
tomsmeding

3

Arcbot

Con trăn 3

Chơi với thuật toán dựa trên xâm lược khi kẻ thù và bruteforces trả lời có ảnh hưởng

Thuật toán này là loại 'dựa trên cảm xúc', tôi đoán vậy. Khi phát triển điều này, tôi nhận ra rằng FluidBot đã đánh bại nó gần như mọi lúc. Arcbot không phải là thuật toán nhanh nhất cũng không phải là thuật toán tốt nhất, nhưng nó có điểm mạnh.

không đâm vào tường. Không biết tại sao.

FLUIDBOT LÀ TỐT HƠN

#   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])

EDIT : Điều chỉnh các con số và công thức, hiện tại nó chơi tốt hơn nhưng vẫn thua Fluidbot.

EDIT 2 : Rất tiếc, quên thay đổi một số mã.


1

RandomBot

C #

RandomBot chọn ngẫu nhiên một hướng cho đến khi tuyến đường đó miễn phí. Nếu không có hướng an toàn, nó chỉ đơn giản là loại *và mất.

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;
                }
            }
        }
    }
}

Đây chỉ là một ví dụ AI - nó không được thiết kế để giành chiến thắng!


-1

Lấp đầy Bot (quay 90 độ ngược chiều kim đồng hồ, khi gặp chướng ngại vật

C ++

Trong mã của tôi, hai người chơi (1 và 2) cố gắng vượt qua. Có nghĩa là bất cứ khi nào họ phải đối mặt với một chướng ngại vật, họ quay ngược chiều kim đồng hồ.
Hãy nhớ rằng, các dòng trong đầu vào được phân tách bằng một spacehoặc newlinekhông bởi;

#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
Tôi sẽ không thể kiểm tra chương trình này vì nó không tuân thủ một số thông số kỹ thuật thiết yếu và không thể được chương trình điều khiển sử dụng.
kitcar2000
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.