Guerras de balão de água

12

Este jogo do rei da colina é um jogo de estratégia no qual você deve jogar um balão de água e evitar ser atingido pela água. O objetivo é obter o maior número de pontos. Você receberá um mapa do campo e a localização do balão de água. Você pode retornar que deseja bater no balão de água (se estiver próximo o suficiente) em uma determinada direção ou que deseja se mover em uma determinada direção.

Especificamente: O balão de água começará com (0, 0)30 unidades de altura e cairá. Se o balão de água atingir o chão, um jogador será escolhido aleatoriamente para perder 4 pontos, dando mais peso àqueles que estão mais próximos do balão. Além disso, o jogador que acertar o balão pela última vez ganhará 3 pontos. Portanto, se você acertar o balão para baixo, provavelmente perderá 1 ponto.

Você escreverá uma classe que se estende Player. Você é obrigado a implementar o construtor. O construtor será parecido com:

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

Esses números são doubles. O primeiro número representa a velocidade do jogador, o segundo representa força e o terceiro representa sorte. Os números devem somar 10 ou menos e nenhum número pode ser menor ou igual a zero.

Segundo, você deve implementar o movemétodo. Este é um movemétodo de exemplo :

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

Há várias coisas importantes aqui. Primeiro, observe que o campo é passado como a Map<Player, Point2D>. O campo é infinito - não há limite para o quão longe você pode ir. Não é uma matriz bidimensional ou algo assim. Além disso, isso significa que você terá coordenadas não inteiras como sua localização. Isso está perfeitamente bem.

Outra consequência é que os jogadores e o balão podem se sobrepor. De fato, dois jogadores podem estar exatamente no mesmo local!

O balão tem uma certa velocidade e direção. Em geral, ele cairá a uma taxa de 3 unidades / etapa. Ele também se move em uma xdireção e ydireção. Ao retornar a Hit, você passa pelas direções x, ye z que estão pressionando o balão. Você não pode bater um balão cuja altura é superior a 10 ou cuja distância de você (apenas em duas dimensões) é maior do que 4. Além disso, se é verdade que x^2 + y^2 + z^2 > s^2onde sé a sua força, e x, ye zsão as direções que você atingidas , sua ação é descartada. A força do seu acerto é amplificada por um número aleatório entre 0e luck(o que significa que pode diminuir se a sua sorte estiver baixa).

Da mesma forma, você pode retornar a Movementcom as coordenadas xe yque você está movendo (observe que você não pode pular no ar). Se a sua velocidade estiver x^2 + y^2 > s^2onde s, sua ação será descartada.

Se o balão de água atinge o chão, um jogador aleatório é escolhido, com mais peso dado aos que estão mais próximos - mas menos peso aos que têm mais sorte. O jogador escolhido perde 4 pontos.

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

O jogo dura 1000 etapas. No final, haverá um arquivo chamado log.out. Copie e cole os dados neste violino para visualizar o jogo: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Ou melhor ainda, veja-o em 3D: http://www.brianmacintosh.com/waterballoonwars (graças ao BMac)

O jogador com a maior soma de pontuações após 100 (pode ser mais, mas não menos) jogos vence.

Se você deseja enviar uma solução, leia os detalhes realmente específicos em https://github.com/prakol16/water-balloon-wars/tree/master .

Editar 3/8 :

Essas são as pontuações finais no momento (1000 iterações, sem incluir os jogadores 1 e 2). Se você editar sua postagem, poderá comentar, e eu refiz a pontuação:

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

O vencedor ficou Weaklingcom uma média de 39 pontos. O 2º lugar ficou Repellercom 21 pontos.

soktinpk
fonte
1
O que acontece quando você bate no balão? Como isso se move? E se várias pessoas acertarem?
Keith Randall
A animação com o jsfiddle é muito legal!
CommonGuy
A propósito, você deve finalizar os métodos na classe Player, caso contrário, os envios poderão substituí-los.
CommonGuy
2
Você inverteu speede strengthno construtor Player.
Thrax
@KeithRandall A dirX, dirYe dirZ(amplificado por sua sorte) são simplesmente adicionados para as velocidades do balão. Se várias pessoas atingi-lo (pouco provável), então o jogador que pode conseguir os três pontos é decidido na sorte (ver detalhes específicos)
soktinpk

Respostas:

7

Simulador

Espero que esteja tudo bem, já que não é realmente uma entrada. Gostei muito da ideia do simulador visual e queria criar o meu próprio que tornasse um pouco mais fácil ver tudo de uma só vez (3D completo).

28/2 9:06 PST : atualização com controles a seguir, cores

04/4 8:47 PST : atualize com um controle deslizante para velocidade de simulação e faça com que o início de um novo jogo funcione sem atualizar a página (use Ctrl-F5 para recarregar o script em cache)

Visualizador Online ThreeJS

insira a descrição da imagem aqui

BMac
fonte
3
+1000 Isso é incrível. Obrigado
soktinpk 28/02
Você não quer dizer Ctrl + F5, não Shift + F5?
Timtech 28/02
Parece que ambos funcionam no Chrome.
BMac 28/02
7

Vai e volta

Esse bot tenta se aproximar e acertar o balão até sua altura estar muito baixa e tentar fugir.

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
fonte
parece que seu bot executa movimentos ilegais e, portanto, não faz nada quando faz.
Moogie
@soktinpk Corrigi minha inscrição, ela deve melhorar agora. Obrigado Moogie também!
Thrax
Ainda estou descobrindo que seu bot está pedindo movimento além do que é possível. Fiz uma edição da sua postagem para revisão. Basicamente, você estava usando a posição do balão como movimento.
Moogie
@ Moogie Certo, muito obrigado!
Thrax
Feliz em ajudar. Seu bot é muito bom em obter pontuações positivas. bem feito!
Moogie
5

AngryPenguin

Este pinguim está com raiva porque ele não pode voar até o balão, então ele tenta acertar o balão na cara das pessoas ao seu redor.

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
fonte
Este é o único a vencer.
Kevin Workman
5

Fraco

Este bot só pode tocar o balão, pois é tão fraco, em vez disso, depende apenas de sua alta sorte. Portanto, ele tem desempenho semelhante ao LuckyLoser (do qual esse bot é inspirado).

Ele parece executar todos os bots atuais, incluindo 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: velocidade reduzida em favor da sorte

Moogie
fonte
3

Hydrophobe

Este é um dos bot mais simples possível, mas como é competitivo eu o publicarei.

Estratégia: bem ... esse bots odeia água e desaparece.

Como o bot será espirrado muito raramente, ele pontuará um pouco abaixo de 0 pontos em média. A soma das pontuações de todos os bots é -1 * [balão atingindo o solo], portanto o Hydrophobe provavelmente terá uma pontuação acima da média.

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
fonte
3

Mantenha-se afastado

Este jogador persegue o balão desde que sua altura seja> 2. Assim que consegue atingi-lo, ele bate no balão para longe do jogador mais próximo. Quando a altura do balão é <2, este jogador foge.

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: eu estava jogando com o Player1 e o Player2 incluídos. Esse jogador ganha nesse caso, mas perde quando eu o tiro. Booooo.

Kevin Workman
fonte
3

Perdedor sortudo

Este bot depende de sua pontuação de alta sorte. Se não estiver perto do balão, ele corre em direção ao balão. Uma vez perto do balão, se houver pelo menos 2 outros jogadores no alcance do balão, ele o arremessará no chão. Caso contrário, ele vai acertar.

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: Corrigido o erro de movimento que na verdade me fazia fugir, não em direção ao balão> _ <Agora eu corro direto em direção ao balão, se não consigo atingi-lo.

Fongoid
fonte
3

Repeller

Esse bot conta com apenas um movimento real e é continuar empurrando o balão para longe de si. ou seja, repele o balão.

Parece ter um bom desempenho em relação à atual safra de bots (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) quase sempre vencendo. No entanto, Hydrophobe, por inação, está sempre pronto para vencer se todos os outros bots conseguirem uma pontuação 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
fonte