Wasserballon Kriege

12

Dieses King-of-the-Hill-Spiel ist ein Strategiespiel, bei dem Sie einen Wasserballon umrunden und vermeiden müssen, von Wasser bespritzt zu werden. Das Ziel ist es, die meisten Punkte zu erzielen. Sie erhalten eine Karte des Feldes und den Standort des Wasserballons. Sie können entweder zurückgeben, dass Sie den Wasserballon treffen möchten (wenn Sie nahe genug sind), oder dass Sie sich in eine bestimmte Richtung bewegen möchten.

Insbesondere: Der Wasserballon startet bei (0, 0)30 Einheiten und fällt ab. Wenn der Wasserballon auf dem Boden aufschlägt, wird ein Spieler nach dem Zufallsprinzip ausgewählt, um 4 Punkte zu verlieren, wobei denjenigen, die sich näher am Ballon befinden, mehr Gewicht verliehen wird. Zusätzlich erhält der Spieler, der zuletzt den Ballon geschlagen hat, 3 Punkte. Wenn Sie also den Ballon gerade treffen, verlieren Sie höchstwahrscheinlich 1 Punkt.

Sie werden eine Klasse schreiben, die erweitert wird Player. Sie müssen den Konstruktor implementieren. Der Konstruktor sieht folgendermaßen aus:

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

Diese Zahlen sind doubles. Die erste Zahl steht für die Geschwindigkeit des Spielers, die zweite für die Stärke und die dritte für das Glück. Die Zahlen müssen 10 oder weniger ergeben und keine Zahl darf kleiner oder gleich Null sein.

Zweitens müssen Sie die moveMethode implementieren . Dies ist eine Beispielmethode move:

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

Hier gibt es eine Reihe wichtiger Dinge. Beachten Sie zunächst, dass das Feld als übergeben wird Map<Player, Point2D>. Das Feld ist unendlich - es gibt keine Begrenzung, wie weit Sie gehen können. Es ist kein zweidimensionales Array oder ähnliches. Dies bedeutet außerdem, dass Sie als Standort nicht ganzzahlige Koordinaten verwenden. Das ist vollkommen in Ordnung.

Eine weitere Folge ist, dass sich Spieler und Ballon überlappen können. Tatsächlich können sich zwei Spieler genau am selben Ort befinden!

Der Ballon hat eine bestimmte Geschwindigkeit und Richtung. Im Allgemeinen sinkt die Rate um 3 Einheiten / Schritt. Es bewegt sich auch in eine xRichtung und yRichtung. Wenn Sie a zurückgeben Hit, übergeben Sie die x-, y- und z-Richtungen, in die Sie die Sprechblase drücken. Sie können nicht einen Ballon , deren Höhe größer als 10 oder deren Entfernung von Ihnen (nur auf zwei Dimensionen) größer ist als 4. Zusätzlich schlagen, wenn es wahr ist , dass , x^2 + y^2 + z^2 > s^2wo sIhre Stärke ist, und x, yund zsind die Anweisungen , die Sie getroffen Ihre Aktion wird verworfen. Die Stärke deines Treffers wird durch eine Zufallszahl zwischen 0und verstärkt luck(was bedeutet, dass er sinken kann, wenn dein Glück gering ist).

Ebenso können Sie Movementmit den Koordinaten xund y, die Sie bewegen, ein zurückgeben (beachten Sie, dass Sie nicht in die Luft springen können). Wenn x^2 + y^2 > s^2wo sdeine Geschwindigkeit ist, wird deine Aktion verworfen.

Wenn der Wasserballon auf dem Boden aufschlägt, wird ein zufälliger Spieler ausgewählt, bei dem denjenigen, die am nächsten sind, mehr Gewicht beigemessen wird - aber denjenigen, die mehr Glück haben, weniger. Der gewählte Spieler verliert 4 Punkte.

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

Das Spiel dauert 1000 Schritte. Am Ende wird eine Datei aufgerufen log.out. Kopieren Sie die Daten und fügen Sie sie in diese Geige ein, um das Spiel anzuzeigen: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Oder noch besser, sehen Sie es sich in 3D an: http://www.brianmacintosh.com/waterballoonwars (danke an BMac)

Der Spieler mit der höchsten Punktzahl nach 100 (möglicherweise mehr, aber nicht weniger) Spielen gewinnt.

Wenn Sie eine Lösung einreichen möchten, können Sie die wirklich spezifischen Details unter https://github.com/prakol16/water-balloon-wars/tree/master lesen .

Edit 3/8 :

Dies sind die Endergebnisse für den Moment (1000 Iterationen, ohne Spieler 1 und 2). Wenn Sie Ihren Beitrag bearbeiten, können Sie einen Kommentar abgeben, und ich werde die Ergebnisse wiederholen:

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

Der Gewinner war Weaklingmit durchschnittlich 39 Punkten. Der 2. Platz war Repellermit 21 Punkten.

soktinpk
quelle
1
Was passiert, wenn Sie den Ballon treffen? Wie bewegt es sich? Was ist, wenn mehrere Leute es treffen?
Keith Randall
Die Animation mit der Jsfiddle ist wirklich schön!
CommonGuy
Übrigens sollten Sie die Methoden in der Player-Klasse endgültig festlegen, da sie andernfalls von Einsendungen überschrieben werden können.
CommonGuy
2
Sie haben speedund strengthim Player-Konstruktor invertiert .
Thrax
@KeithRandall Das dirX, dirYund dirZ(durch Ihr Glück verstärkt) werden einfach auf die Geschwindigkeiten des Ballons hinzugefügt. Wenn mehrere Spieler es treffen (etwas unwahrscheinlich), entscheidet sich der Spieler, der möglicherweise drei Punkte erzielt (siehe Einzelheiten)
soktinpk

Antworten:

7

Simulator

Ich hoffe das ist okay, da es eigentlich kein Eintrag ist. Ich mochte die Idee des visuellen Simulators sehr und wollte meinen eigenen erstellen, der es ein wenig einfacher macht, alles auf einmal zu sehen (volles 3D).

28.02.09 : 06 Uhr PST : Update mit folgenden Steuerelementen, Farben

04.03., 08:47 Uhr PST : Aktualisierung mit einem Schieberegler für die Simulationsgeschwindigkeit und Start eines neuen Spiels ohne Aktualisierung der Seite (verwenden Sie Strg-F5, um das zwischengespeicherte Skript neu zu laden)

Online ThreeJS Visualizer

Bildbeschreibung hier eingeben

BMac
quelle
3
+1000 Das ist unglaublich. Vielen Dank
soktinpk
Meinst du nicht Strg + F5, nicht Umschalt + F5?
Timtech
Sieht so aus, als ob beide in Chrome funktionieren.
BMac
7

Hin und her

Dieser Bot versucht, sich dem Ballon zu nähern und ihn zu treffen, bis seine Höhe zu niedrig ist und er versucht zu entkommen.

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

    }

}
Thrax
quelle
Es sieht so aus, als ob Ihr Bot illegale Bewegungen ausführt und daher nichts unternimmt, wenn dies der Fall ist.
Moogie
@soktinpk Ich habe meine Eingabe korrigiert, es sollte jetzt besser gehen. Danke auch Moogie!
Thrax
Ich stelle immer noch fest, dass Ihr Bot nach einer Bewegung fragt, die über das Mögliche hinausgeht. Ich habe eine Bearbeitung Ihres Beitrags zur Überprüfung eingereicht. Grundsätzlich haben Sie die Position des Ballons als Bewegung verwendet.
Moogie
@ Moogie Richtig, vielen Dank!
Thrax
Froh, dass ich Helfen kann. Ihr Bot ist ziemlich gut darin, positive Ergebnisse zu erzielen. gut gemacht!
Moogie
5

AngryPenguin

Dieser Pinguin ist wütend, weil er nicht zum Ballon fliegen kann und versucht, den Ballon in das Gesicht von Menschen zu schlagen, die um ihn herum stehen.

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

}
CommonGuy
quelle
Dies ist derjenige, den man schlagen muss.
Kevin Workman
5

Schwächling

Dieser Bot kann den Ballon nur berühren, weil er so schwach ist, stattdessen verlässt er sich nur auf sein großes Glück. Es verhält sich daher ähnlich wie LuckyLoser (von dem dieser Bot inspiriert ist).

Er scheint alle aktuellen Bots zu übertreffen, einschließlich 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: Geschwindigkeit zugunsten des Glücks reduziert

Moogie
quelle
3

Hydrophob

Dies ist einer der einfachsten möglichen Bot, aber da es wettbewerbsfähig ist, werde ich es veröffentlichen.

Strategie: Nun ... dieser Bots hasst Wasser, also geht es einfach weg.

Da der Bot sehr selten bespritzt wird, erzielt er im Durchschnitt etwas weniger als 0 Punkte. Die Summe aller Bots ergibt -1 * (Ballonschlag), sodass Hydrophobe wahrscheinlich überdurchschnittlich gut abschneidet.

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);
    }
}
randomra
quelle
3

Bleib weg

Dieser Spieler jagt den Ballon, solange seine Höhe> 2 ist. Sobald er den Ballon treffen kann, schlägt er den Ballon vom nächsten Spieler weg . Wenn der Ballon eine Höhe von <2 hat, rennt dieser Spieler davon.

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

}

Edit: Ich habe mit Player1 und Player2 gespielt. Dieser Spieler gewinnt in diesem Fall, verliert aber, wenn ich ihn herausnehme. Booooo.

Kevin Workman
quelle
3

Glücklicher Verlierer

Dieser Bot verlässt sich auf seine hohe Glücksquote. Wenn es sich nicht in der Nähe des Ballons befindet, läuft es in Richtung des Ballons. Sobald er sich dem Ballon nähert und sich mindestens zwei andere Spieler in Reichweite des Ballons befinden, stößt er ihn auf den Boden. Andernfalls klopft er sofort an.

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

BEARBEITEN: Bewegungsfehler behoben, der dazu führte, dass ich nicht zum Ballon rannte> _ <Jetzt renne ich direkt zum Ballon, wenn ich ihn nicht treffen kann.

Fongoid
quelle
3

Repeller

Dieser Roboter muss nur eine einzige echte Bewegung ausführen, und zwar, um den Ballon weiter von sich wegzuschieben. dh stößt den Ballon ab.

Es scheint eine gute Leistung gegen die aktuelle Ernte von Bots (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) zu bringen, die fast immer gewinnen. Durch Untätigkeit ist Hydrophobe jedoch immer bereit zu gewinnen, wenn die anderen Bots alle eine negative Punktzahl erzielen: 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);
    }
}
Moogie
quelle