Perang Balon Air

12

Gim king-of-the-hill ini adalah gim strategi di mana Anda harus melempar balon air dan menghindari percikan air. Tujuannya adalah untuk mendapatkan poin terbanyak. Anda akan diberikan peta lapangan dan lokasi balon air. Anda dapat kembali ke balon air (jika Anda cukup dekat) ke arah tertentu atau Anda ingin bergerak ke arah tertentu.

Secara khusus: Balon air akan mulai pada (0, 0)30 unit tinggi dan jatuh. Jika balon air menyentuh tanah, pemain akan dipilih secara acak untuk kehilangan 4 poin, dengan lebih banyak berat diberikan kepada mereka yang lebih dekat dengan balon. Selain itu, pemain yang terakhir memukul balon akan mendapatkan 3 poin. Karena itu, jika Anda menekan balon lurus ke bawah, kemungkinan besar Anda akan kehilangan 1 poin.

Anda akan menulis kelas yang diperluas Player. Anda harus mengimplementasikan konstruktor. Konstruktor akan terlihat seperti:

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

Angka-angka ini adalah doubles. Angka pertama mewakili kecepatan pemain, yang kedua mewakili kekuatan, dan yang ketiga mewakili keberuntungan. Angka-angka harus ditambahkan hingga 10 atau kurang dan tidak ada angka mungkin kurang dari atau sama dengan nol.

Kedua, Anda harus menerapkan movemetode ini. Ini adalah contoh movemetode:

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

Ada sejumlah hal penting di sini. Pertama, perhatikan bahwa bidang dilewatkan sebagai Map<Player, Point2D>. Bidang ini tidak terbatas - tidak ada batasan seberapa jauh Anda bisa melangkah. Ini bukan array 2 dimensi atau semacamnya. Selain itu, ini berarti Anda akan memiliki koordinat non-integer sebagai lokasi Anda. Ini sangat oke.

Konsekuensi lain adalah bahwa pemain dan balon mungkin tumpang tindih. Bahkan, dua pemain mungkin berada di lokasi yang sama persis!

Balon memiliki kecepatan dan arah tertentu. Secara umum, itu akan jatuh pada tingkat 3 unit / langkah. Itu juga bergerak ke xarah dan yarah. Ketika Anda mengembalikan a Hit, Anda melewati arah x, y, dan z yang Anda dorong balon. Anda tidak bisa memukul balon yang tingginya lebih besar dari 10 atau yang jarak dari Anda (hanya pada dua dimensi) lebih besar dari 4. Selain itu, jika memang benar bahwa x^2 + y^2 + z^2 > s^2di mana sadalah kekuatan Anda, dan x, y, dan zadalah arah yang anda menekan , tindakan Anda dibuang. Kekuatan hit Anda diperkuat oleh angka acak di antara 0dan luck(yang berarti itu bisa turun jika keberuntungan Anda rendah).

Demikian pula, Anda dapat mengembalikan a Movementdengan xdan ymengkoordinasikan bahwa Anda bergerak (perhatikan bahwa Anda tidak dapat melompat di udara). Jika di x^2 + y^2 > s^2mana skecepatan Anda, tindakan Anda dibuang.

Jika balon air menyentuh tanah maka pemain acak dipilih, dengan lebih banyak bobot diberikan kepada mereka yang paling dekat - tetapi lebih sedikit berat bagi mereka yang memiliki lebih banyak keberuntungan. Pemain yang dipilih kehilangan 4 poin.

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

Permainan ini berlangsung 1000 langkah. Pada akhirnya, akan ada file bernama log.out. Salin dan tempel data ke dalam biola ini untuk melihat permainan: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Atau lebih baik lagi, lihat dalam 3D: http://www.brianmacintosh.com/waterballoonwars (terima kasih kepada BMac)

Pemain dengan jumlah skor tertinggi setelah 100 (mungkin lebih, tetapi tidak kurang) permainan menang.

Jika Anda ingin mengirimkan solusi, Anda mungkin ingin membaca detail yang sangat spesifik di https://github.com/prakol16/water-balloon-wars/tree/master .

Edit 3/8 :

Ini adalah skor akhir untuk saat ini (1000 iterasi, tanpa menyertakan pemain 1 dan 2). Jika Anda mengedit posting Anda, Anda dapat berkomentar, dan saya akan mengulang skor:

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

Pemenangnya adalah Weaklingdengan rata-rata 39 poin. Posisi Kedua Repellerdengan 21 poin.

soktinpk
sumber
1
Apa yang terjadi ketika Anda menekan balon? Bagaimana cara bergeraknya? Bagaimana jika beberapa orang memukulnya?
Keith Randall
Animasi dengan jsfiddle sangat bagus!
CommonGuy
Ngomong-ngomong, Anda harus membuat metode di final kelas Player, jika tidak kiriman dapat menimpanya.
CommonGuy
2
Anda terbalik speeddan strengthdi konstruktor Player.
Thrax
@KeithRandall The dirX,, dirYdan dirZ(diperkuat oleh keberuntungan Anda) hanya ditambahkan ke kecepatan balon. Jika beberapa orang memukulnya (agak tidak mungkin) maka pemain yang mungkin mendapatkan tiga poin diputuskan beruntung (lihat detail spesifik)
soktinpk

Jawaban:

7

Simulator

Saya harap ini baik-baik saja, karena itu sebenarnya bukan entri. Saya benar-benar menyukai gagasan simulator visual dan saya ingin membuatnya sendiri yang akan membuatnya sedikit lebih mudah untuk melihat semuanya sekaligus (full 3D).

2/28 9:06 PST : perbarui dengan kontrol ikuti, warna

3/4 8:47 PST : perbarui dengan slider untuk kecepatan simulasi, dan membuat memulai game baru benar-benar berfungsi tanpa menyegarkan halaman (gunakan Ctrl-F5 untuk memuat ulang skrip yang di-cache)

Visualisasi ThreeJS online

masukkan deskripsi gambar di sini

BMac
sumber
3
+1000 Luar biasa. Terima kasih
soktinpk
Bukankah maksud Anda Ctrl + F5, bukan Shift + F5?
Timtech
Sepertinya keduanya berfungsi di Chrome.
BMac
7

Bolak-balik

Bot ini mencoba mendekat dan menabrak balon sampai ketinggiannya terlalu rendah dan mencoba untuk melarikan diri.

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
sumber
sepertinya bot Anda melakukan gerakan ilegal dan karenanya tidak melakukan apa pun saat melakukannya.
Moogie
@soktinpk saya memperbaiki kiriman saya, itu harus lebih baik sekarang Terima kasih Moogie juga!
Thrax
Saya masih menemukan bahwa bot Anda meminta pergerakan di luar apa yang mungkin. Saya telah melakukan pengeditan pos Anda untuk ditinjau. Pada dasarnya Anda menggunakan posisi balon sebagai gerakan.
Moogie
@ Moogie Benar, terima kasih banyak!
Thrax
Senang untuk membantu. Bot Anda cukup bagus untuk mendapatkan skor positif. sudah selesai dilakukan dengan baik!
Moogie
5

AngryPenguin

Penguin ini marah karena dia tidak bisa terbang ke balon, jadi dia mencoba untuk memukul balon ke wajah orang-orang yang berdiri di sekitarnya.

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
sumber
Ini yang harus dikalahkan.
Kevin Workman
5

Orang lemah

Bot ini hanya bisa menyentuh balon karena sangat lemah, melainkan hanya mengandalkan keberuntungannya yang tinggi. Karena itu ia melakukan mirip dengan LuckyLoser (dari mana bot ini terinspirasi).

Dia tampaknya melakukan semua bot saat ini termasuk 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: mengurangi kecepatan demi keberuntungan

Moogie
sumber
3

Hydrophobe

Ini adalah salah satu bot paling sederhana yang mungkin tetapi karena kompetitif saya akan mempostingnya.

Strategi: well ... bot ini membenci air sehingga hilang begitu saja.

Karena bot akan terciprat sangat jarang, skornya akan sedikit di bawah rata-rata 0 poin. Jumlah skor semua bot adalah -1 * [balon memukul tanah] sehingga Hydrophobe mungkin akan mencetak skor di atas rata-rata.

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

Jauhkan

Pemain ini mengejar balon selama tingginya> 2. Begitu balon itu mengenai balon, balon itu mengenai balon yang jauh dari pemain terdekat. Saat tinggi balon <2, pemain ini melarikan diri.

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

}

Sunting: Saya bermain dengan Player1 dan Player2 disertakan. Pemain ini menang dalam hal itu, tetapi kalah ketika saya mengeluarkannya. Booooo.

Kevin Workman
sumber
3

Lucky Loser

Bot ini mengandalkan skor keberuntungan tinggi. Jika tidak di dekat balon, balon itu berlari ke arah balon. Begitu mendekati balon, jika setidaknya ada 2 pemain lain di jangkauan balon, ia akan melonjak ke tanah. Kalau tidak, dia akan langsung mengetuknya.

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: Memperbaiki bug gerakan yang sebenarnya membuat saya melarikan diri tidak ke arah balon> _ <Sekarang saya hanya berlari lurus ke arah balon jika saya tidak bisa mengenai itu.

Fongoid
sumber
3

Repeller

Bot ini hanya memiliki satu gerakan nyata dan artinya terus mendorong balon menjauh dari dirinya sendiri. yaitu memukul mundur balon.

Tampaknya berkinerja baik terhadap tanaman bot saat ini (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) hampir selalu menang. Namun Hydrophobe, dengan tidak bertindak, selalu siap untuk menang jika bot lain semua berhasil mendapatkan skor negatif: 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
sumber