Guerras de globos de agua

12

Este juego del rey de la colina es un juego de estrategia en el que debes lanzar alrededor de un globo de agua y evitar que te salpique el agua. El objetivo es obtener la mayor cantidad de puntos. Se le dará un mapa del campo y la ubicación del globo de agua. Puede devolver que desea golpear el globo de agua (si está lo suficientemente cerca) en una determinada dirección o que desea moverse en una determinada dirección.

Específicamente: el globo de agua comenzará a (0, 0)30 unidades de altura y caerá. Si el globo de agua toca el suelo, se elegirá al jugador al azar para que pierda 4 puntos, y se otorgará más peso a quienes estén más cerca del globo. Además, el jugador que golpeó el globo por última vez ganará 3 puntos. Por lo tanto, si golpeas el globo hacia abajo, lo más probable es que pierdas 1 punto.

Escribirás una clase que se extienda Player. Debe implementar el constructor. El constructor se verá así:

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

Estos números son doubles. El primer número representa la velocidad del jugador, el segundo representa la fuerza y ​​el tercero representa la suerte. Los números deben sumar 10 o menos y ningún número puede ser menor o igual a cero.

En segundo lugar, debe implementar el movemétodo. Este es un movemétodo de ejemplo :

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

Hay una serie de cosas importantes aquí. Primero, observe que el campo se pasa como a Map<Player, Point2D>. El campo es infinito: no hay límite de cuán lejos puede llegar. No es una matriz bidimensional ni nada por el estilo. Además, esto significa que tendrá coordenadas no enteras como su ubicación. Esto está perfectamente bien.

Otra consecuencia es que los jugadores y el globo pueden superponerse. De hecho, ¡dos jugadores pueden estar exactamente en la misma ubicación!

El globo tiene una cierta velocidad y dirección. En general, caerá a una velocidad de 3 unidades / paso. También se mueve en una xdirección y ydirección. Cuando regresas a Hit, pasas las direcciones x, y y z en las que estás empujando el globo. No se puede golpear un globo cuya altura es superior a 10 o cuya distancia de usted (sólo en dos dimensiones) es superior a 4. Además, si bien es cierto que x^2 + y^2 + z^2 > s^2cuando ses su fuerza, y x, yy zson las direcciones que alcanze , tu acción se descarta. La fuerza de tu golpe se amplifica con un número aleatorio entre 0y luck(lo que significa que podría disminuir si tu suerte es baja).

Del mismo modo, puede devolver a Movementcon las coordenadas xy yque está moviendo (tenga en cuenta que no puede saltar en el aire). Si x^2 + y^2 > s^2dónde sestá tu velocidad, tu acción se descarta.

Si el globo de agua toca el suelo, se elige un jugador aleatorio, con más peso para los que están más cerca, pero menos peso para los que tienen más suerte. El jugador elegido pierde 4 puntos.

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

El juego dura 1000 pasos. Al final, habrá un archivo llamado log.out. Copie y pegue los datos en este violín para ver el juego: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

O incluso mejor, verlo en 3D: http://www.brianmacintosh.com/waterballoonwars (gracias a BMac)

El jugador con la suma más alta de puntajes después de 100 (puede ser más, pero no menos) juegos gana.

Si desea enviar una solución, puede leer los detalles realmente específicos en https://github.com/prakol16/water-balloon-wars/tree/master .

Editar 3/8 :

Estos son los puntajes finales por ahora (1000 iteraciones, sin incluir a los jugadores 1 y 2). Si edita su publicación, puede comentar y rehaceré las puntuaciones:

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

El ganador fue Weaklingcon un promedio de 39 puntos. El segundo lugar fue Repellercon 21 puntos.

soktinpk
fuente
1
¿Qué sucede cuando golpeas el globo? ¿Cómo se mueve? ¿Qué pasa si varias personas lo golpean?
Keith Randall
¡La animación con jsfiddle es realmente agradable!
CommonGuy
Por cierto, debe hacer que los métodos en la clase Player sean finales, de lo contrario, los envíos pueden anularlos.
CommonGuy
2
Invertiste speedy strengthen el constructor Player.
Thrax
@KeithRandall El dirX, dirYy dirZ(amplificada por su suerte) están simplemente añadido a las velocidades del globo. Si varias personas lo golpean (algo poco probable), entonces el jugador que podría obtener tres puntos se decide por suerte (ver detalles específicos)
soktinpk

Respuestas:

7

Simulador

Espero que esto esté bien, ya que en realidad no es una entrada. Realmente me gustó la idea del simulador visual y quería crear el mío para que fuera un poco más fácil ver todo a la vez (3D completo).

2/28 9:06 AM PST : actualización con los siguientes controles, colores

3/4 8:47 AM PST : actualizar con un control deslizante para la velocidad de simulación, y hacer que comenzar un nuevo juego realmente funcione sin actualizar la página (use Ctrl-F5 para volver a cargar el script en caché)

Visualizador de ThreeJS en línea

ingrese la descripción de la imagen aquí

BMac
fuente
3
+1000 Eso es asombroso. Gracias
soktinpk
¿No quieres decir Ctrl + F5, no Shift + F5?
Timtech
Parece que ambos funcionan en Chrome.
BMac
7

De ida y vuelta

Este bot intenta acercarse y golpear el globo hasta que su altura es demasiado baja y trata de escapar.

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
fuente
parece que su bot realiza movimientos ilegales y, por lo tanto, no hace nada cuando lo hace.
Moogie
@soktinpk Arregle mi presentación, debería hacerlo mejor ahora. Gracias Moogie también!
Thrax
Todavía encuentro que tu bot está pidiendo un movimiento más allá de lo posible. He puesto una edición de su publicación para su revisión. Básicamente estabas usando la posición del globo como movimiento.
Moogie
@Moogie Correcto, ¡muchas gracias!
Thrax
Encantado de ayudar. Tu bot es bastante bueno para obtener puntajes positivos. ¡bien hecho!
Moogie
5

AngryPenguin

Este pingüino está enojado porque no puede volar hasta el globo, por lo que intenta golpear el globo en la cara de las personas que lo rodean.

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
fuente
Este es el que hay que vencer.
Kevin Workman
5

Alfeñique

Este bot solo puede tocar el globo ya que es muy débil, en cambio solo depende de su gran suerte. Por lo tanto, funciona de manera similar a LuckyLoser (del cual está inspirado este bot).

Parece que supera a todos los bots actuales, incluido 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);
    }
}

EDITAR: velocidad reducida a favor de la suerte

Moogie
fuente
3

Hidrófobo

Este es uno de los bot más simples posibles, pero como es competitivo, lo publicaré.

Estrategia: bueno ... este robot odia el agua, así que simplemente desaparece.

Como el bot se salpicará muy raramente, su puntaje será inferior a 0 puntos en promedio La suma de las puntuaciones de todos los bots es -1 * [globo golpeando el suelo], por lo que Hydrophobe probablemente obtendrá una puntuación superior a la 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);
    }
}
randomra
fuente
3

Manténgase alejado

Este jugador persigue el globo siempre que su altura sea> 2. Tan pronto como puede golpear el globo, golpea el globo lejos del jugador más cercano. Cuando la altura del globo es <2, este jugador se escapa.

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

}

Editar: estaba jugando con Player1 y Player2 incluidos. Este jugador gana en ese caso, pero pierde cuando los elimino. Booooo

Kevin Workman
fuente
3

Lucky Loser

Este bot se basa en su alto puntaje de suerte. Si no está cerca del globo, corre hacia el globo. Una vez cerca del globo, si hay al menos otros 2 jugadores dentro del alcance del globo, lo clavará al suelo. De lo contrario, lo golpeará hacia arriba.

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

EDITAR: Se corrigió un error de movimiento que realmente me hacía huir no hacia el globo> _ <Ahora solo corro directamente hacia el globo si no puedo golpearlo.

Fongoid
fuente
3

Repelente

Este bot depende solo tiene un movimiento real y es seguir empujando el globo lejos de sí mismo. es decir, repele el globo.

Parece funcionar bien contra la actual cosecha de bots (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) casi siempre ganando. Sin embargo, Hydrophobe, por inacción, siempre está listo para ganar si los otros bots logran obtener una puntuación negativa: 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
fuente