Війни на повітряній кулі


12

Ця гра короля-пагорба - це стратегічна гра, в якій ви повинні кидати навколо водної кулі і уникати бризок водою. Мета - отримати найбільшу кількість балів. Вам видадуть карту поля та місце розташування водної кулі. Ви можете або повернути, що хочете вдарити по водній кулі (якщо ви досить близько) в певному напрямку, або що хочете рухатися в певному напрямку.

Зокрема: водна куля стартує о (0, 0) 30 одиниць у висоту та опускається. Якщо водна куля потрапить на землю, гравець випадково буде обраний, щоб втратити 4 очки, при цьому більше ваги надається тим, хто ближче до повітряної кулі. Крім того, гравець, який востаннє потрапив на повітряну кулю, заробить 3 очки. Тому, якщо вдарити повітряну кулю прямо вниз, ви, швидше за все, втратите 1 бал.

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

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

Ці числа є doubles. Перше число відображає швидкість гравця, друге - силу, а третє - удачу. Числа повинні складати до 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(що означає, що воно може знизитися, якщо ваша удача буде низькою).

Так само ви можете повернути a 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 балом.


1
Що відбувається, коли ти потрапив на повітряну кулю? Як воно рухається? Що робити, якщо його вдарить кілька людей?
Кіт Рендалл

Анімація з jsfiddle справді приємна!
CommonGuy

До речі, ви повинні зробити методи в класі гравця остаточним, інакше подання може їх перекрити.
CommonGuy

2
Ви перевернуті speedі strengthв конструкторі програвача.
Фракс

@KeithRandall dirX, dirYі dirZ(посилюється вашої удачі) просто додаються до швидкості повітряної кулі. Якщо кілька людей ударять його (дещо малоймовірно), то гравець, який міг би отримати три очки, вирішується на удачу (див. Конкретні деталі)
soktinpk

Відповіді:


7

Симулятор

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

2/28 9:06 ранку PST : оновлення з подальшими елементами керування, кольори

3/4 8:47 AM 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);
                }
            }
        }

    }

}

схоже, ваш бот виконує незаконні рухи і, отже, нічого не робить, коли робить.
Moogie

@soktinpk Я виправив своє подання, це має зробити краще зараз. Дякую і Мугі!
Фракс

Я все ще знаходжу, що ваш бот просить рухатись понад те, що можливо. Я помістив редагування вашої публікації для ознайомлення. В основному ви використовували положення повітряної кулі як рух.
Мугі

@Moogie Правильно, спасибі велике!
Фракс

Радий допомогти. Ваш бот досить добре отримує позитивні бали. молодець!
Moogie

5

Злий Пінгвін

Цей пінгвін розлючений, бо не може підлетіти до повітряної кулі, тому він намагається вдарити повітряну кулю в обличчя людей, що стоять навколо нього.

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

}

Це той, кого бити.
Кевін Уордман

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

EDIT: зменшена швидкість на користь удачі


3

Гідрофоб

Це один з найпростіших можливих ботів, але оскільки він є конкурентоспроможним, я опублікую його.

Стратегія: ну ... цей бот ненавидить воду, тому вона просто йде.

Оскільки бот буде бризок дуже рідко, він набере трохи менше 0 балів в середньому. Сума балів усіх ботів дорівнює -1 * [повітряна куля, що потрапила в землю], тому Hydrophobe, ймовірно, набере вище середнього.

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

3

Триматися подалі

Цей гравець переслідує повітряну кулю до тих пір, поки її висота дорівнює> 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);
    }
}

EDIT: Виправлена ​​помилка при русі, яка насправді змусила мене тікати не до повітряної кулі> _ <Тепер я просто біжу прямо до повітряної кулі, якщо не можу її вдарити.


3

Репелер

Цей бот покладається лише на один справжній хід, а саме - продовжувати відштовхувати повітряну кулю від себе. тобто відштовхує повітряну кулю.

Схоже, це добре справляється з поточним урожаєм ботів (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth), майже завжди виграючи. Однак Hydrophobe за бездіяльністю завжди готовий до виграшу, якщо всім іншим ботам вдасться отримати негативний бал: 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);
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.