Il re delle mura


10

Avviso

Questa sfida è terminata e non verrà valutata nuovamente, ma sentiti libero di pubblicare risposte e testare il tuo programma contro gli altri con il Programma di controllo!

Lo scopo di questa sfida è fare in modo che un'intelligenza artificiale vinca una lotta contro un'altra intelligenza artificiale disegnando strategicamente un muro su una griglia 25x25 per bloccare l'avversario.

Ingresso

25 righe separate da e che terminano con ;come argomento della riga di comando. Ciò includerà:

  • Spazi vuoti .
  • Walls #
  • Giocatori 1e 2(l'avversario è sempre 2)

Esempio

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

che rappresenta la seguente mappa:

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

Produzione

Una stringa scritta sulla console che inizia con il carattere che rappresenta la direzione in cui l'IA desidera girare. Questo è case sensitive!

  • Nord N
  • est E
  • Sud S
  • ovest W
  • Rinuncia (qualsiasi altra cosa)

Esempio

W

Regole del gioco

  • Mentre gli AI si muovono, lasceranno dietro di sé una solida scia di muri.
  • I giocatori iniziano negli angoli in alto a sinistra e in basso a destra
  • Il gioco dura fino a quando un'intelligenza artificiale non colpisce un muro o l'IA si schianta l'uno contro l'altro.
    • Un'intelligenza artificiale vince se il loro avversario si schianta per primo
    • Non vi è alcun vincitore o perdente se gli IA perdono entrambi contemporaneamente.
  • Se un'intelligenza artificiale esce da un bordo della griglia, continua nella stessa direzione dall'altro lato.

Classifica

1 ° posto - FloodBot (Java, 12 vittorie)

2 ° posto - FluidBot (Python, 9 vittorie)

3 ° posto - FillUpBot (C ++, 8 vittorie)

4 ° posto - AwayBot (Ruby, 5 vittorie)

5 ° posto - ArcBot (Python, 4 vittorie)

6 ° posto - BlindSnake (Lotto, 2 vittorie)

6 ° posto - RandomBot (C #, 2 vittorie)

Programma di controllo (testato per Python 3.3.3)

Il programma viene eseguito con argomenti dei due comandi e un singolo argomento ( ""se non richiesto) per gli AI. Control.py "ruby" "AwayBot.rb" "FillUpBot.exe" "". Può essere scaricato qui .

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
È necessario aggiungere un'API e un programma di prova ORA! In quale altro modo saremo in grado di scrivere codice per interfacciarci con esso? Contrassegnando come poco chiaro.
AJMansfield,

3
Sembra una bella sfida, ma eh, quel "programma di test" (è il programma del controller giusto?), Che lingua è e devo compilarlo? Per favore, dicci come usarlo.
Herjan,

3
Sembra una sfida interessante che non competerò a causa delle restrizioni (A) del sistema operativo (utente solo Linux) e (B) del linguaggio (principalmente Fortran ma che lavora per imparare Lua)
Kyle Kanos

2
@Doorknob Sto installando Ruby ora e sto pensando di imparare ad usarlo comunque.
kitcar2000,

2
@ kitcar2000 ah vedo che è abbastanza giusto. in alternativa potresti fornirlo tramite stdin, ma usare una singola riga come argomento è un gioco equo. Detto questo, poiché la tua mappa è di dimensioni fisse, non hai bisogno di alcun delimitatore.
Martin Ender,

Risposte:


8

Floodbot

Giava

Questo ragazzo è tutto per evitare. Non gli interessa provare a intrappolare l'avversario, vuole solo vivere. Per fare ciò, riempie tutte le direzioni per vedere quale strada porterà alla più grande area aperta.

Pensa anche che il nemico sia imprevedibile, quindi tratta ogni quadrato immediatamente circostante come se fosse già un muro. Se ciò non conduce a nessuna direzione possibile, ricade sulla mappa "reale".

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

Penso che tu abbia questo nella borsa.
cjfaure,

@Trimsty Oh? Non ho ancora testato contro tutta la concorrenza, quindi non ero sicuro di come andasse contro un paio di loro. Buono a sapersi :)
Geobits

Complimenti per aver vinto! :)
tomsmeding

4

BlindSnake

Lotto

Questo bot osserva solo i suoi dintorni. Se non c'è un muro, si sposta lì.

@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

Volevo solo creare un bot in batch ... E non lo farò mai più


4

FluidBot

Python 3

Prende il percorso di minor resistenza e tenta di prevedere l'avversario

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

Ci ho lavorato per circa un'ora. ._.

Testato contro 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 : più attento al futuro; cerca di evitare di chiudere le aree (a meno che, ovviamente, non ci sia l'avversario).

EDIT 4 : codice pulito.

EDIT 3 : funziona meglio per le aree di gioco rettangolari.

EDIT 2 : codice più pulito, l'algoritmo è più logico e prevede alcune mosse nel futuro

EDIT : algoritmo più difensivo, non considera il sé fantasma come spazio vuoto.


3

AwayBot

scritto in Ruby (1.9)

Appropriatamente chiamato, AwayBot cerca di allontanarsi da qualsiasi ostacolo. Cerca un quadrato di 15x15 attorno a sé, pondera le direzioni di conseguenza e sceglie la direzione con il minor numero di ostacoli. (Ciò significa anche che evita i bordi, il che è buono in modo che non rimanga intrappolato in essi.)

Considera anche i muri più vicini per essere più di un pericolo. Le pareti proprio accanto ad essa sono pesate molto più delle pareti lontane.

Per l'input di esempio, viene emesso S. I pesi per ciascuna direzione dell'ingresso campione sono [["N", 212], ["E", 140], ["S", 0], ["W", 84]].

Interiezione: ho appena notato che l'arena si chiude. Bene, ora la mia tecnica per evitare i bordi è un po 'inutile, ma meh. Forse lo aggiusterò più tardi.

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]

"Questo significa anche che evita i bordi, il che è buono in modo che non rimanga intrappolato in essi." - I bordi non si avvolgono?
Hovercouch,

1
@Hover Umm, sì, non hai letto l'ultimo paragrafo? ;-)
Maniglia della porta

@Doorknob Assicurati di ricevere i tuoi input dalla riga di comando, quindi ARGF.argv[0].chompinvece che gets.chompnella prima riga!
tomsmeding,

@Doorknob dovresti probabilmente specificare la tua versione di Ruby. Penso che questo usi alcune caratteristiche che non sono universali
Non che Charles

@tomsmeding Ah, non me ne sono reso conto. Grazie, editing
Doorknob

3

FillUpBot

scritto in C ++

Non pensare che vincerò, ma ecco il mio tentativo comunque:

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

Il compilatore C ++ standard dovrebbe essere in grado di gestirlo.


Non riesco a compilare. GCC 4.8.1, Windows 7. Genera errori su rand e RAND_MAX non definiti.
cjfaure,

@Trimsty Fa un #include <cstdlib>aiuto? (Basta inserirlo in cima come una nuova riga)
tomsmeding

Infatti! Si compila ora. Grazie.
cjfaure,

L'ho combattuto contro FluidBot, non è riuscito a produrre output in questa mossa: pastie.org/private/azmwkybqrxqlfvpwidlpw (FluidBot è il giocatore 1)
cjfaure,

@Trimsty Um ... gist.github.com/tomsmeding/96060c7db3f1c3483668 (1 e 2 scambiati; se non li scambio dà lo stesso risultato)
tomsmeding

3

Arcbot

Python 3

Gioca con un algoritmo basato sull'aggressività mentre il nemico e le forze brute rispondono con influenza

Questo algoritmo è un po '"basato sulle emozioni", immagino. Nello sviluppo di questo, mi sono reso conto che FluidBot lo ha battuto quasi ogni volta. Arcbot non è l'algoritmo più veloce né il migliore, ma ha i suoi punti di forza.

Si fa sbattere contro le pareti. Non ho idea del perché.

FLUIDBOT È MEGLIO

#   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 : modificati i numeri e la formula, ora gioca meglio ma perde ancora con Fluidbot.

EDIT 2 : Whoops, ho dimenticato di cambiare un po 'di codice.


1

RandomBot

C #

RandomBot seleziona casualmente una direzione fino a quando il suo percorso è libero. Se non esiste una direzione sicura, digita *e perde semplicemente .

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

Questo è solo un esempio di AI - non è progettato per vincere!


-1

Fill Up Bot (ruota di 90 gradi in senso antiorario, quando affronta un ostacolo

C ++

Nel mio codice, i due giocatori (1 e 2) provano a inondare. Significa che ogni volta che affrontano un ostacolo, girano in senso antiorario.
Ricorda, le righe in input sono separate da un spaceo newlinenon da;

#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
Non sarò in grado di testare questo programma perché non è conforme ad alcune specifiche essenziali e non può essere utilizzato dal programma di controllo.
kitcar2000,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.