Water Balloon Wars


12

Questo gioco king-of-the-hill è un gioco di strategia in cui devi lanciare un pallone d'acqua ed evitare di essere schizzato dall'acqua. L'obiettivo è ottenere il maggior numero di punti. Ti verrà data una mappa del campo e la posizione del pallone d'acqua. Puoi restituire che vuoi colpire il pallone d'acqua (se sei abbastanza vicino) in una certa direzione o che vuoi muoverti in una determinata direzione.

In particolare: il pallone ad acqua inizierà a (0, 0)30 unità di altezza e scenderà. Se la mongolfiera colpisce il terreno, un giocatore verrà scelto casualmente per perdere 4 punti, con più peso dato a coloro che sono più vicini alla mongolfiera. Inoltre, il giocatore che ha colpito per ultimo il pallone guadagna 3 punti. Pertanto, se colpisci il palloncino verso il basso, molto probabilmente perderai 1 punto.

Scriverai una classe che si estende Player. È necessario implementare il costruttore. Il costruttore sarà simile a:

public Player1() {
    super(/* Some numbers */ 3, 3, 4)
}

Questi numeri sono doubles. Il primo numero rappresenta la velocità del giocatore, il secondo rappresenta la forza e il terzo rappresenta la fortuna. I numeri devono aggiungere fino a 10 o meno e nessun numero può essere inferiore o uguale a zero.

In secondo luogo, è necessario implementare il movemetodo. Questo è un movemetodo di esempio :

@Override
protected Action move(Map<Player, Point2D> map, Balloon b) {
    // Get my own location
    Point2D myself = map.get(this);
    // If I'm close enough to the balloon
    // then hit the balloon
    if (myself.distanceSq(b.getLocation()) <= 16) {
        double d = (r.nextDouble() - 0.5) * 3;
        // Random y direction, z direction is what's left 
        return new Hit(0, d, Math.sqrt(9 - d*d));
    } else {
        double diffX = b.getLocation().getX() - myself.getX(),
                diffY = b.getLocation().getY() - myself.getY();
        // Move towards the balloon
        return new Movement(Math.signum(diffX)*3/Math.sqrt(2), Math.signum(diffY)*3/Math.sqrt(2));
    }
}

Ci sono un certo numero di cose importanti qui. Innanzitutto, nota che il campo è passato come a Map<Player, Point2D>. Il campo è infinito - non c'è limite a quanto lontano puoi andare. Non è un array bidimensionale o qualcosa del genere. Inoltre, questo significa che avrai coordinate non intere come posizione. Questo va perfettamente bene.

Un'altra conseguenza è che i giocatori e il pallone possono sovrapporsi. In effetti, due giocatori possono trovarsi esattamente nella stessa posizione!

Il palloncino ha una certa velocità e direzione. In generale, cadrà ad una velocità di 3 unità / passo. Si muove anche in una xdirezione e ydirezione. Quando ritorni a Hit, passi le direzioni x, ye z che stai spingendo il palloncino. Non si può colpire un palloncino cui altezza è maggiore di 10 o la cui distanza da voi (solo su due dimensioni) è maggiore di 4. Inoltre, se è vero che x^2 + y^2 + z^2 > s^2dove sè la vostra forza, e x, ye zsono le direzioni che ti ha colpito , la tua azione viene scartata. La forza del tuo colpo è amplificata da un numero casuale compreso tra 0e luck(il che significa che potrebbe diminuire se la fortuna è bassa).

Allo stesso modo, puoi restituire a Movementcon le coordinate xe yche stai spostando (nota che non puoi saltare in aria). Se x^2 + y^2 > s^2dov'è la stua velocità, la tua azione viene scartata.

Se la mongolfiera colpisce il terreno, viene scelto un giocatore a caso, con più peso dato a quelli più vicini, ma meno peso a quelli che hanno più fortuna. Il giocatore scelto perde 4 punti.

Controller: https://github.com/prakol16/water-balloon-wars/tree/master

Il gioco dura 1000 passi. Alla fine, ci sarà un file chiamato log.out. Copia e incolla i dati in questo violino per visualizzare il gioco: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

O ancora meglio, visualizzalo in 3D: http://www.brianmacintosh.com/waterballoonwars (grazie a BMac)

Vince il giocatore con il maggior numero di punteggi dopo 100 (può essere maggiore, ma non inferiore).

Se si desidera inviare una soluzione, è possibile leggere i dettagli specifici su https://github.com/prakol16/water-balloon-wars/tree/master .

Modifica 3/8 :

Questi sono i punteggi finali per ora (1000 iterazioni, senza includere i giocatori 1 e 2). Se modifichi il tuo post, puoi commentare e rifarò i punteggi:

{
    class players.BackAndForth=-75.343,
    class players.Hydrophobe=-0.800,
    class players.KeepAway=-53.064,
    class players.Weakling=39.432,
    class players.Repeller=21.238,
    class players.LuckyLoser=-30.055,
    class players.AngryPenguin=-49.310
}

Il vincitore è stato Weaklingcon una media di 39 punti. Il 2 ° posto è stato Repellercon 21 punti.


1
Cosa succede quando si colpisce il pallone? Come si muove? Cosa succede se più persone lo colpiscono?
Keith Randall,

L'animazione con jsfiddle è davvero bella!
Common Acquista il

A proposito, dovresti rendere definitivi i metodi nella classe Player, altrimenti gli invii possono annullarli.
CommonGuy

2
Hai invertito speede strengthnel costruttore Player.
Thrax,

@KeithRandall The dirX, dirYe dirZ(amplificati dalla tua fortuna) vengono semplicemente aggiunti alle velocità del pallone. Se più persone lo colpiscono (un po 'improbabile), il giocatore che potrebbe ottenere tre punti viene deciso per fortuna (vedi dettagli specifici)
soktinpk,

Risposte:


7

Simulatore

Spero che vada bene, dato che in realtà non è una voce. Mi è piaciuta molto l'idea del simulatore visivo e volevo crearne una mia che rendesse un po 'più facile vedere tutto in una volta (3D completo).

28/02 9:06 PST : aggiornamento con follow follow, colori

3/4 8:47 AM PST : aggiornamento con un cursore per la velocità di simulazione, e fatto iniziare un nuovo gioco effettivamente funzionare senza aggiornare la pagina (utilizzare Ctrl-F5 per ricaricare lo script nella cache)

Visualizzatore ThreeJS online

inserisci qui la descrizione dell'immagine


3
+1000 È fantastico. Grazie
soktinpk,

Non intendi Ctrl + F5, non Maiusc + F5?
Timtech,

Sembra che entrambi funzionino in Chrome.
BMac,

7

Avanti e indietro

Questo robot cerca di avvicinarsi e colpire il palloncino fino a quando la sua altezza è troppo bassa e cerca di scappare.

package players;

import java.awt.geom.Point2D;
import java.util.Map;

import balloon.Action;
import balloon.Balloon;
import balloon.Player;
import balloon.Action.Hit;
import balloon.Action.Movement;

public class BackAndForth extends Player {

    static int round = 0;
    static int speed = 3;
    static int strength = 1;
    static boolean hit = false;
    static double previousHeight = 30.0;

    public BackAndForth() {
        super(speed, strength, 10 - speed - strength);
    }

    @Override
    protected Action move(Map<Player, Point2D> map, Balloon b) {

        round++;

        Point2D me = map.get(this);
        Point2D balloon = b.getLocation();

        double distanceX = balloon.getX() - me.getX();
        double distanceY = balloon.getY() - me.getY();
        double distance = Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));

        double maxX = speed * distanceX / distance;
        double maxY = speed * distanceY / distance;

        if (previousHeight < b.getHeight())
            hit = false;

        if (hit || b.getHeight() < 3) {
            previousHeight = b.getHeight();
            return new Movement(-maxX, -maxY);
        } else {
            if (distance < 4 && b.getHeight() < 10) {
                hit = true;
                return new Hit(0, 0, strength);
            } else {
                if (Math.pow(distance, 2) <= Math.pow(speed, 2)) {
                    return new Movement(distanceX, distanceY);
                } else {
                    return new Movement(maxX, maxY);
                }
            }
        }

    }

}

sembra che il tuo bot esegua mosse illegali e quindi non faccia nulla quando lo fa.
Moogie,

@soktinpk Ho corretto la mia richiesta, ora dovrebbe fare di meglio. Grazie anche a Moogie!
Thrax,

Sto ancora scoprendo che il tuo robot sta chiedendo movimento oltre ciò che è possibile. Ho inserito una modifica del tuo post per la revisione. Fondamentalmente stavi usando la posizione del palloncino come movimento.
Moogie,

@Moogie Bene, grazie mille!
Thrax,

Felice di aiutare. Il tuo bot è abbastanza bravo a ottenere punteggi positivi. molto bene!
Moogie,

5

AngryPenguin

Questo pinguino è arrabbiato perché non riesce a volare verso il pallone, quindi cerca di colpirlo in faccia alle persone che gli stanno attorno.

package players;

import java.awt.geom.Point2D;
import java.util.Map;
import java.util.Map.Entry;

import balloon.Action;
import balloon.Action.Hit;
import balloon.Action.Movement;
import balloon.Balloon;
import balloon.Player;

public class AngryPenguin extends Player {
    private static final double HIT_Z = 3;
    public AngryPenguin() {
        super(4, 4, 2);
    }

    @Override
    protected Action move(Map<Player, Point2D> map, Balloon balloon) {
        Point2D myself = map.get(this);

        double distanceX = balloon.getLocation().getX() - myself.getX();
        double distanceY = balloon.getLocation().getY() - myself.getY();
        double distance = Math.sqrt(Math.pow(distanceX, 2) + Math.pow(distanceY, 2));

        if (balloon.getHeight() < 2) {
            double[] xy = shrink(distanceX, distanceY, Math.pow(getSpeed(),2));
            return new Movement(-xy[0], -xy[1]);
        } else if (distance <= 4 && balloon.getHeight() <= 10) {
            double lowestDistance = Double.MAX_VALUE;
            Point2D nearestPlayerLoc = null;
            for (Entry<Player, Point2D> e : map.entrySet()) {
                if (e.getKey() != this) {
                    double d = e.getValue().distanceSq(myself);
                    if (d < lowestDistance) {
                        lowestDistance = d;
                        nearestPlayerLoc = e.getValue();
                    }
                }
            }
            double dX = nearestPlayerLoc.getX() - myself.getX();
            double dY = nearestPlayerLoc.getY() - myself.getY();
            double d = Math.pow(getStrength() - HIT_Z, 2);
            double[] xy = shrink(dX, dY, d);
            return new Hit(xy[0], xy[1], -HIT_Z);
        } else {
            double[] xy = shrink(distanceX, distanceY, Math.pow(Math.min(getSpeed(), distance), 2));
            return new Movement(xy[0], xy[1]);          
        }
    }

    private double[] shrink(double x, double y, double totalPow) {
        double[] xy = new double[2];
        double ratio = y == 0 ? 0 : 
                       x == 0 ? 1 : Math.abs(x) / Math.abs(y);
        if (ratio > 1)
            ratio = 1/ratio;
        xy[1] = totalPow * ratio;
        xy[0] = totalPow - xy[1];
        xy[0] = x < 0 ? -Math.sqrt(xy[0]) : Math.sqrt(xy[0]);
        xy[1] = y < 0 ? -Math.sqrt(xy[1]) : Math.sqrt(xy[1]);
        return xy;
    }

}

Questo è quello da battere.
Kevin Workman,

5

mingherlino

Questo robot può solo toccare il pallone in quanto è così debole, invece si basa solo sulla sua grande fortuna. Si comporta quindi in modo simile a LuckyLoser (da cui questo bot è ispirato).

Sembra che esegua tutti i robot attuali, incluso Repeller.

package players;
import java.awt.geom.Point2D;
import java.util.Map;
import balloon.Action;
import balloon.Balloon;
import balloon.Player;
import balloon.Action.Hit;
import balloon.Action.Movement;

public class Weakling extends Player {

    static final private double STRENGTH = Double.MIN_VALUE;
    static final private double SPEED = 1.5;
    static final private double LUCK = 8.5;
    public Weakling() {
        super(SPEED,STRENGTH,LUCK);
    }

    protected Action move(Map<Player, Point2D> map, Balloon b) {
        Point2D start = map.get(this);
        Point2D balloon = b.getLocation();
        double distance = start.distance(balloon)+Double.MIN_VALUE;
        if(distance<=4 && b.getHeight()<=10){

            // just touch it :P
            return new Hit(0,0,0);
        }
        double x = start.getX()-balloon.getX();
        double y = start.getY()-balloon.getY();
        x /= distance;
        y /= distance;

        // move to directly underneath balloon
        x*=Math.min(SPEED, distance);
        y*=Math.min(SPEED, distance);
        return new Movement(-x, -y);
    }
}

EDIT: velocità ridotta a favore della fortuna


3

idrofobo

Questo è uno dei bot più semplici possibili ma, dato che è competitivo, lo pubblicherò.

Strategia: beh ... questo robot odia l'acqua, quindi scompare.

Poiché il bot verrà schizzato molto raramente, segnerà in media un po 'meno di 0 punti. La somma dei punteggi di tutti i robot è -1 * [palloncino che colpisce il terreno], quindi Hydrophobe segnerà probabilmente un punteggio superiore alla media.

package players;
import java.awt.geom.Point2D;
import java.util.Map;
import balloon.*;

public class Hydrophobe extends Player {
    public Hydrophobe() {super(8, 1, 1);}
    @Override
    protected Action move(Map<Player, Point2D> map, Balloon balloon) {
        return new Action.Movement(5.65,5.65);
    }
}

3

Tenere lontano

Questo giocatore insegue il pallone finché la sua altezza è> 2. Non appena può colpire il pallone, colpisce il pallone lontano dal giocatore più vicino. Quando l'altezza del pallone è <2, questo giocatore scappa.

package players;

import java.awt.geom.Point2D;
import java.util.Map;

import balloon.Action;
import balloon.Balloon;
import balloon.Player;
import balloon.Action.Hit;
import balloon.Action.Movement;

public class KeepAway extends Player{

    public KeepAway() {
        super(5, 3, 2);
    }

    @Override
    protected Action move(Map<Player, Point2D> map, Balloon b) {

        Point2D myself = map.get(this);

        //if balloon is high up, run towards it
        if(b.getHeight() > 2){
            Point2D closest = getClosestPlayer(map);

            boolean canHit = b.getHeight() <= 10 && myself.distance(b.getLocation()) <= 4;

            //hit it when you can
            if(canHit){

                Point2D normHit = normalize(new Point2D.Double(myself.getX() - closest.getX(), myself.getY() - closest.getY()));
                Point2D forceHit = new Point2D.Double(normHit.getX() * getStrength(), normHit.getY() * getStrength());

                return new Hit(forceHit.getX(), forceHit.getY(), 0);
            }
            //if you can't hit it, keep running towards it
            else {

                Point2D normRun = normalize(new Point2D.Double(myself.getX() - b.getLocation().getX(), myself.getY() - b.getLocation().getY()));
                Point2D forceRun = new Point2D.Double(-normRun.getX() * getSpeed(), -normRun.getY() * getSpeed());
                return new Movement(forceRun.getX(), forceRun.getY());
            }
        }
        //if the balloon is low, run away
        else{
            Point2D normRun = normalize(new Point2D.Double(myself.getX() - b.getLocation().getX(), myself.getY() - b.getLocation().getY()));
            Point2D forceRun = new Point2D.Double(normRun.getX() * getSpeed(), normRun.getY() * getSpeed());
            return new Movement(forceRun.getX(), forceRun.getY());
        }

    }

    private Point2D getClosestPlayer(Map<Player, Point2D> map){

        double minDistance = Double.MAX_VALUE;
        Point2D closestPoint = null;
        Point2D myPoint = map.get(this);

        for(Player p : map.keySet()){
            if(this != p){

                if(myPoint.distance(map.get(p)) < minDistance){
                    minDistance = myPoint.distance(map.get(p));
                    closestPoint = map.get(p);
                }
            }
        }

        return closestPoint;
    }

    private Point2D normalize(Point2D p){
        double d = p.distance(0, 0);

        if(d == 0){
            return new Point2D.Double(0, 0);
        }

        return new Point2D.Double(p.getX()/d, p.getY()/d);
    }

}

Modifica: stavo giocando con Player1 e Player2 inclusi. Questo giocatore vince in quel caso, ma perde quando li tiro fuori. Booooo.


3

Perdente fortunato

Questo bot si basa sul suo punteggio di fortuna elevato. Se non è vicino al pallone, corre verso il pallone. Una volta vicino al pallone, se ci sono almeno altri 2 giocatori nel raggio di azione del pallone, lo spingerà a terra. Altrimenti, lo farà cadere.

package players;
import java.awt.geom.Point2D;
import java.util.Map;

import balloon.Action;
import balloon.Balloon;
import balloon.Player;
import balloon.Action.Hit;
import balloon.Action.Movement;

public class LuckyLoser extends Player {
    public LuckyLoser() {
        super(1,1,8);
    }

    protected Action move(Map<Player, Point2D> map, Balloon b) {
        Point2D start = map.get(this);
        Point2D bLocation = b.getLocation();
        double distance = start.distance(bLocation);
        if(distance<=4){
            boolean foundMe = false;
            int numPlayersInRange=0;
            for(Point2D point:map.values()){
                if( !foundMe && point.equals(start))
                {
                    foundMe=true;
                    continue;
                }
                if(point.distance(bLocation)<=4)
                    numPlayersInRange++;                
            }
            if(numPlayersInRange>1)
                return new Hit(0,0,-1);
            else
                return new Hit(0,0,1);
        }
        double x = start.getX()-bLocation.getX();
        double y = start.getY()-bLocation.getY();
        x /= distance;
        y /= distance;
        return new Movement(-x, -y);
    }
}

EDIT: corretto bug di movimento che in realtà mi faceva scappare non verso il pallone> _ <Ora corro dritto verso il pallone se non riesco a colpirlo.


3

Repeller

Questo robot fa affidamento su una sola mossa reale, ovvero continuare a spingere il palloncino lontano da se stesso. cioè respinge il pallone.

Sembra funzionare bene contro l'attuale raccolto di robot (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) quasi sempre vincenti. Tuttavia Hydrophobe, per inerzia, è sempre pronto a vincere se tutti gli altri robot riescono a ottenere un punteggio negativo: P

package players;
import java.awt.geom.Point2D;
import java.util.Map;

import balloon.Action;
import balloon.Balloon;
import balloon.Player;
import balloon.Action.Hit;
import balloon.Action.Movement;

public class Repeller extends Player {

    static final private double STRENGTH = 3.5;
    static final private double SPEED = 2.5;
    static final private double LUCK = 4;
    public Repeller() {
        super(SPEED,STRENGTH,LUCK);
    }

    protected Action move(Map<Player, Point2D> map, Balloon b) {
        Point2D start = map.get(this);
        Point2D balloon = b.getLocation();
        double distance = start.distance(balloon)+Double.MIN_VALUE;
        if(distance<=4 && b.getHeight()<=10){
            double x = start.getX()-balloon.getX();
            double y = start.getY()-balloon.getY();
            x /= distance;
            y /= distance;
            x*=STRENGTH;
            y*=STRENGTH;

            // push the balloon away with all our strength
            return new Hit(-x,-y,0);
        }
        double x = start.getX()-balloon.getX();
        double y = start.getY()-balloon.getY();
        x /= distance;
        y /= distance;

        // if we are directly underneath then move away from balloon
        distance=distance<1?-1:distance;

        // if we are just off of directly underneath then stay put
        distance=distance<2?0:distance;

        // move to the desired location
        x*=Math.min(SPEED, distance);
        y*=Math.min(SPEED, distance);
        return new Movement(-x, -y);
    }
}
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.