Guerres de ballons d'eau

12

Ce jeu du roi de la colline est un jeu de stratégie dans lequel vous devez lancer un ballon d'eau et éviter d'être éclaboussé par l'eau. L'objectif est d'obtenir le plus de points. Vous recevrez une carte du terrain et l'emplacement du ballon d'eau. Vous pouvez soit retourner que vous voulez frapper le ballon d'eau (si vous êtes assez près) dans une certaine direction ou que vous voulez vous déplacer dans une certaine direction.

Plus précisément: le ballon d'eau commencera à (0, 0)30 unités de haut et baissera. Si le ballon d'eau touche le sol, un joueur sera choisi au hasard pour perdre 4 points, avec plus de poids accordé à ceux qui sont plus proches du ballon. De plus, le joueur qui a touché le ballon pour la dernière fois gagnera 3 points. Par conséquent, si vous frappez le ballon directement vers le bas, vous perdrez probablement 1 point.

Vous écrirez une classe qui s'étend Player. Vous devez implémenter le constructeur. Le constructeur ressemblera à:

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

Ces chiffres sont l' doubleart. Le premier nombre représente la vitesse du joueur, le second représente la force et le troisième représente la chance. Les nombres doivent totaliser 10 ou moins et aucun nombre ne peut être inférieur ou égal à zéro.

Deuxièmement, vous devez implémenter la moveméthode. Ceci est un exemple de moveméthode:

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

Il y a un certain nombre de choses importantes ici. Tout d'abord, notez que le champ est transmis en tant que Map<Player, Point2D>. Le champ est infini - il n'y a aucune limite à jusqu'où vous pouvez aller. Ce n'est pas un tableau à 2 dimensions ou quelque chose comme ça. De plus, cela signifie que vous aurez des coordonnées non entières comme emplacement. C'est parfaitement correct.

Une autre conséquence est que les joueurs et le ballon peuvent se chevaucher. En fait, deux joueurs peuvent être exactement au même endroit!

The balloon has a certain velocity and direction. In general, it will fall at a rate of 3 units/step. It also moves in an x direction and y direction. When you return a Hit, you pass the x, y, and z directions that you are pushing the balloon. You cannot hit a balloon whose height is greater than 10 or whose distance from you (only on two dimensions) is greater than 4. In addition, if it is true that x^2 + y^2 + z^2 > s^2 where s is your strength, and x, y, and z are the directions that you hit, your action is discarded. The force of your hit is amplified by a random number between 0 and luck (which means it could go down if your luck is low).

De même, vous pouvez renvoyer un Movementavec les coordonnées xet yque vous déplacez (notez que vous ne pouvez pas sauter en l'air). Si x^2 + y^2 > s^2sest votre vitesse, votre action est défaussée.

Si le ballon d'eau touche le sol, un joueur aléatoire est choisi, avec plus de poids accordé à ceux qui sont les plus proches - mais moins de poids à ceux qui ont plus de chance. Le joueur choisi perd 4 points.

Contrôleur: https://github.com/prakol16/water-balloon-wars/tree/master

Le jeu dure 1000 étapes. À la fin, il y aura un fichier appelé log.out. Copiez et collez les données dans ce violon pour voir le jeu: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Ou encore mieux, visualisez-le en 3D: http://www.brianmacintosh.com/waterballoonwars (merci à BMac)

Le joueur avec la somme de scores la plus élevée après 100 parties (peut être plus, mais pas moins) gagne.

Si vous souhaitez soumettre une solution, vous voudrez peut-être lire les détails vraiment spécifiques sur https://github.com/prakol16/water-balloon-wars/tree/master .

Modifier 3/8 :

Ce sont les scores finaux pour l'instant (1000 itérations, sans inclure les joueurs 1 et 2). Si vous modifiez votre message, vous pouvez commenter, et je vais refaire les scores:

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

Le vainqueur était Weaklingavec une moyenne de 39 points. La deuxième place était Repelleravec 21 points.

soktinpk
la source
1
Que se passe-t-il lorsque vous frappez le ballon? Comment ça bouge? Et si plusieurs personnes le frappaient?
Keith Randall
L'animation avec le jsfiddle est vraiment sympa!
CommonGuy
Soit dit en passant, vous devez rendre les méthodes de la classe Player finales, sinon les soumissions peuvent les remplacer.
CommonGuy
2
Vous inversé speedet strengthdans le constructeur Player.
Thrax
@KeithRandall Le dirX, dirYet dirZ(amplifié par votre chance) sont simplement ajoutés aux vitesses du ballon. Si plusieurs personnes l'atteignent (quelque peu improbable), alors le joueur qui pourrait obtenir trois points est décidé par chance (voir les détails spécifiques)
soktinpk

Réponses:

7

Simulateur

J'espère que ça va, car ce n'est pas vraiment une entrée. J'ai vraiment aimé l'idée du simulateur visuel et je voulais créer le mien qui permettrait un peu plus facilement de tout voir à la fois (full 3D).

2/28 9:06 AM PST : mise à jour avec contrôles de suivi, couleurs

3/4 8 h 47 HNP : mise à jour avec un curseur pour la vitesse de simulation, et fait fonctionner un nouveau jeu sans rafraîchir la page (utilisez Ctrl-F5 pour recharger le script mis en cache)

Visualiseur ThreeJS en ligne

entrez la description de l'image ici

BMac
la source
3
+1000 C'est incroyable. Merci
soktinpk
Vous ne voulez pas dire Ctrl + F5, pas Shift + F5?
Timtech
Il semble que les deux fonctionnent dans Chrome.
BMac
7

D'avant en arrière

Ce bot essaie de s'approcher et de frapper le ballon jusqu'à ce que sa hauteur soit trop basse et qu'il essaie de s'éloigner.

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
la source
il semble que votre bot effectue des mouvements illégaux et ne fait donc rien quand il le fait.
Moogie
@soktinpk J'ai corrigé ma soumission, elle devrait faire mieux maintenant. Merci aussi Moogie!
Thrax
Je trouve toujours que votre bot demande un mouvement au-delà de ce qui est possible. J'ai mis une modification de votre message pour examen. Fondamentalement, vous utilisiez la position du ballon comme mouvement.
Moogie
@Moogie Très bien, merci beaucoup!
Thrax
Heureux de vous aider. Votre bot est assez bon pour obtenir des scores positifs. bien joué!
Moogie
5

AngryPenguin

Ce pingouin est en colère parce qu'il ne peut pas voler jusqu'au ballon, alors il essaie de frapper le ballon face aux gens qui se tiennent autour de lui.

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
la source
C'est celui à battre.
Kevin Workman
5

Faible

Ce bot ne peut que toucher le ballon car il est si faible, au lieu de cela, il repose uniquement sur sa grande chance. Il fonctionne donc de manière similaire à LuckyLoser (dont ce bot est inspiré).

Il semble surpasser tous les bots actuels, y compris 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: vitesse réduite au profit de la chance

Moogie
la source
3

Hydrophobe

C'est l'un des robots les plus simples possibles mais comme il est compétitif, je le posterai.

Stratégie: eh bien ... ces bots détestent l'eau donc ça s'en va.

Comme le bot sera éclaboussé très rarement, il marquera un peu moins de 0 point en moyenne. La somme de tous les scores des bots est de -1 * [ballon atteignant le sol], donc Hydrophobe obtiendra probablement un score supérieur à la moyenne.

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
la source
3

Tenir à l'écart

Ce joueur poursuit le ballon tant que sa hauteur est> 2. Dès qu'il peut toucher le ballon, il frappe le ballon loin du joueur le plus proche. Lorsque la hauteur du ballon est <2, ce joueur s'enfuit.

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: je jouais avec Player1 et Player2 inclus. Ce joueur gagne dans ce cas, mais perd quand je les retire. Booooo.

Kevin Workman
la source
3

Chanceux perdant

Ce bot s'appuie sur son score de chance élevé. S'il n'est pas près du ballon, il court vers le ballon. Une fois près du ballon, s'il y a au moins 2 autres joueurs à portée du ballon, il le mettra au sol. Sinon, il va le frapper directement.

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: Correction d'un bug de mouvement qui me faisait en fait fuir pas vers le ballon> _ <Maintenant, je cours juste vers le ballon si je ne peux pas le frapper.

Fongoid
la source
3

Repeller

Ce bot repose sur un seul mouvement réel et c'est de continuer à repousser le ballon de lui-même. c'est-à-dire repousse le ballon.

Il semble bien performer contre la récolte actuelle de bots (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) presque toujours gagnant. Cependant Hydrophobe, par inaction, est toujours prêt à gagner si les autres bots parviennent tous à obtenir un score négatif: 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
la source