Водный шар Войны

12

Эта игра про короля холмов - стратегическая игра, в которой вы должны разбрасывать шарики с водой и избегать попадания брызг воды. Цель состоит в том, чтобы получить как можно больше очков. Вам будет предоставлена ​​карта поля и расположение водяного шара. Вы можете либо вернуть то, что хотите ударить по водяному шару (если вы достаточно близко) в определенном направлении, либо что вы хотите двигаться в определенном направлении.

В частности: воздушный шар начнется с (0, 0)высоты 30 единиц и упадет. Если водный шар падает на землю, игрок случайным образом будет выбран, чтобы потерять 4 очка, при этом больший вес будет отдан тем, кто находится ближе к воздушному шару. Кроме того, игрок, который последний раз ударил по воздушному шару, заработает 3 очка. Поэтому, если вы ударите по воздушному шару прямо вниз, вы, скорее всего, потеряете 1 очко.

Вы напишите класс, который расширяется Player. Вы обязаны реализовать конструктор. Конструктор будет выглядеть так:

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

Эти цифры doubleс. Первое число представляет скорость игрока, второе представляет силу, а третье представляет удачу. Числа должны составлять до 10 или менее, и ни одно число не может быть меньше или равно нулю.

Во-вторых, вы должны реализовать moveметод. Это пример 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));
    }
}

Здесь есть много важных вещей. Во-первых, обратите внимание, что поле передается как Map<Player, Point2D>. Поле бесконечно - нет предела тому, как далеко вы можете пройти. Это не двумерный массив или что-то в этом роде. Кроме того, это означает, что в качестве вашего местоположения у вас будут нецелые координаты. Это совершенно нормально.

Другое следствие - игроки и воздушный шар могут перекрываться. На самом деле, два игрока могут быть в одном месте!

Воздушный шар имеет определенную скорость и направление. Как правило, он будет падать со скоростью 3 единицы / шаг. Он также движется в xнаправлении и yнаправлении. Когда вы возвращаете a Hit, вы передаете направления x, y и z, которые нажимаете на шарик. Вы не можете нажать на воздушном шаре, высота которого превышает 10 или, расстояние от вас (только в двух измерениях) больше 4. Кроме того, если это правда , что , x^2 + y^2 + z^2 > s^2когда sваша сила, и x, yи zте направления , которые вы пострадали , ваше действие отбрасывается. Сила вашего удара усиливается случайным числом между 0и luck(что означает, что оно может уменьшиться, если ваша удача невелика).

Кроме того , вы можете вернуть Movementс xи yкоординатами , которые вы движущимися (обратите внимание , что вы не можете прыгать в воздухе). Если x^2 + y^2 > s^2где sваша скорость, ваши действия отменяются.

Если водяной шар падает на землю, то выбирается случайный игрок, причем больший вес отдается тем, кто ближе всего, но меньший вес тем, у кого больше удачи. Выбранный игрок теряет 4 очка.

Контроллер: https://github.com/prakol16/water-balloon-wars/tree/master

Игра длится 1000 шагов. В конце будет файл с именем log.out. Скопируйте и вставьте данные в эту скрипку для просмотра игры: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Или, что еще лучше, просмотрите его в 3D: http://www.brianmacintosh.com/waterballoonwars (благодаря BMac)

Игрок с наибольшим количеством очков после 100 (может быть больше, но не меньше) игр выигрывает.

Если вы хотите отправить решение, вы можете прочитать действительно конкретные детали по адресу https://github.com/prakol16/water-balloon-wars/tree/master .

Изменить 3/8 :

На данный момент это окончательные результаты (1000 итераций, без учета игроков 1 и 2). Если вы отредактируете свой пост, вы можете оставить комментарий, а я переделаю оценки:

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

Победитель получил Weaklingв среднем 39 баллов. 2 место было Repellerс 21 очком.

soktinpk
источник
1
Что происходит, когда вы ударяете шар? Как это движется? Что, если несколько человек поразят это?
Кит Рэндалл
Анимация с jsfiddle действительно хороша!
CommonGuy
Кстати, вы должны сделать методы класса Player окончательными, в противном случае представления могут переопределить их.
CommonGuy
2
Вы перевернули speedи strengthв конструкторе Player.
Thrax
@KeithRandall dirX, dirYи dirZ(усиливается вашей удачи) просто добавляются к скорости воздушного шара. Если его ударило несколько человек (что-то маловероятное), то игрок, который может получить три очка, решается на удачу (см. Конкретные подробности)
soktinpk

Ответы:

7

имитатор

Я надеюсь, что это нормально, так как на самом деле это не запись. Мне очень понравилась идея визуального симулятора, и я хотел создать свой собственный, который бы немного облегчил одновременный просмотр всего (полное 3D).

2/28 9:06 PST : обновление с последующими элементами управления, цвета

3/4 8:47 PST : обновление с помощью ползунка для скорости симуляции и запуск новой игры на самом деле работает без обновления страницы (используйте Ctrl-F5 для перезагрузки кэшированного скрипта)

Онлайн ThreeJS визуализатор

введите описание изображения здесь

ККЭЗ
источник
3
+1000 Это удивительно. Спасибо
soktinpk
Разве вы не имеете в виду Ctrl + F5, а не Shift + F5?
Timtech
Похоже, обе работают в Chrome.
BMac
7

Назад и вперед

Этот бот пытается приблизиться и ударить по воздушному шару, пока его высота не станет слишком низкой, и он попытается уйти.

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
источник
похоже, ваш бот выполняет нелегальные ходы и, следовательно, ничего не делает, когда делает это.
Муги
@soktinpk Я исправил свою заявку, теперь она должна стать лучше. Спасибо, Муги тоже!
Thrax
Я все еще нахожу, что ваш бот просит движения за пределы возможного. Я поместил в редактирование вашего поста для обзора. В основном вы использовали положение воздушного шара в качестве движения.
Муги
@ Хорошо, спасибо большое!
Thrax
Рад помочь. Ваш бот очень хорошо получает положительные оценки. отлично сработано!
Муги
5

AngryPenguin

Этот пингвин злится, потому что он не может взлететь на воздушный шар, поэтому он пытается ударить воздушный шар в лицо людей, стоящих вокруг него.

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
источник
Это тот, кто победит.
Кевин Воркман
5

слабовольный человек

Этот бот может касаться только воздушного шара, так как он очень слаб, вместо этого он просто полагается на свою удачу. Поэтому он работает так же, как LuckyLoser (из которого этот бот вдохновлен).

Он, кажется, превзошел всех текущих ботов, включая 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);
    }
}

РЕДАКТИРОВАТЬ: уменьшена скорость в пользу удачи

Moogie
источник
3

гидрофобное вещество

Это один из самых простых возможных ботов, но, поскольку он конкурентоспособен, я опубликую его.

Стратегия: хорошо ... эти боты ненавидят воду, поэтому она просто уходит.

Поскольку бот будет выплескиваться очень редко, в среднем он наберет чуть менее 0 баллов. Сумма баллов всех ботов равна -1 * [удар по шару], поэтому у Гидрофоба, вероятно, будет балл выше среднего.

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
источник
3

KeepAway

Этот игрок преследует воздушный шар, пока его высота> 2. Как только он может ударить воздушный шар, он ударяет воздушный шар от ближайшего игрока. Когда высота воздушного шара <2, этот игрок убегает.

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

}

Изменить: я играл с Player1 и Player2 включены. Этот игрок выигрывает в этом случае, но проигрывает, когда я их вынимаю. Booooo.

Кевин Воркман
источник
3

Счастливый неудачник

Этот бот полагается на свою высокую оценку удачи. Если это не около воздушного шара, это бежит к воздушному шару. Оказавшись рядом с воздушным шаром, если в зоне действия воздушного шара есть по крайней мере 2 других игрока, он подбросит его на землю. В противном случае, он выбьет это прямо.

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

РЕДАКТИРОВАТЬ: Исправлена ​​ошибка движения, из-за которой я убегал не к воздушному шару> _ <Теперь я бегу прямо к воздушному шару, если не могу его ударить.

Fongoid
источник
3

отражатель

У этого бота есть только один реальный ход, который состоит в том, чтобы продолжать отталкивать воздушный шар от себя. т.е. отталкивает шар.

Похоже, что он хорошо справляется с текущей культурой ботов (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) почти всегда побеждает. Однако Гидрофоб по бездействию всегда готов победить, если всем остальным ботам удастся получить отрицательный счет: 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
источник