Su Balonu Savaşları


12

Tepenin kralı oyunu, bir su balonunun etrafına atmanız ve su sıçramasından kaçınmanız gereken bir strateji oyunudur. Amaç en çok puanı elde etmektir. Size alanın haritası ve su balonunun yeri verilecektir. Su balonuna (yeterince yakınsanız) belirli bir yönde vurmak istediğinizi ya da belirli bir yönde hareket etmek istediğinizi döndürebilirsiniz.

Özellikle: Su balonu (0, 0)30 ünite yükseklikte başlar ve düşer. Su balonu yere çarparsa, bir oyuncu rastgele olarak 4 puan kaybeder ve balona daha yakın olanlara daha fazla ağırlık verilir. Ayrıca, balona son vuran oyuncu 3 puan kazanacak. Bu nedenle, balona doğrudan vurursanız, büyük olasılıkla 1 puan kaybedersiniz.

Genişleyen bir sınıf yazacaksınız Player. Yapıcıyı uygulamanız gerekiyor. Yapıcı şöyle görünecektir:

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

Bu sayılar doubles. İlk sayı oyuncunun hızını, ikincisi gücü ve üçüncüsü de şansı temsil eder. Sayılar en fazla 10 veya daha az olmalıdır ve hiçbir sayı sıfıra eşit veya sıfırdan küçük olamaz .

İkincisi, moveyöntemi uygulamalısınız . Bu örnek bir moveyöntemdir:

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

Burada bir takım önemli şeyler var. İlk olarak, alanın a olarak iletildiğine dikkat edin Map<Player, Point2D>. Alan sonsuzdur - ne kadar ileri gidebileceğiniz konusunda bir sınır yoktur. 2 boyutlu bir dizi veya bunun gibi bir şey değildir. Ayrıca, konumunuz olarak tamsayı olmayan koordinatlara sahip olacağınız anlamına gelir. Bu gayet iyi.

Başka bir sonuç, oyuncuların ve balonun üst üste gelebilmesidir. Aslında, iki oyuncu tam olarak aynı yerde olabilir!

Balonun belirli bir hızı ve yönü vardır. Genel olarak, 3 birim / adım oranında düşecektir. Aynı zamanda bir xyönde ve yyönde hareket eder . A döndüğünüzde Hit, balonu ittiğiniz x, y ve z yönlerini geçersiniz. Sen eğer doğruysa o, kimin yükseklik 10'dan büyük ise veya kimin mesafe sizin (yalnızca iki boyut üzerine) den ek olarak daha büyük 4. olan bir balon vuramaz x^2 + y^2 + z^2 > s^2nerede ssenin gücünü ve x, yve zsen vurduğunu tarifi , işleminiz atılır. İsabet gücünüz 0ve arasında rastgele bir sayı ile güçlendirilir luck(yani şansınız düşükse düşebilir).

Benzer bir şekilde, dönebilir Movementile xve ysen (siz havada atlamak olamayacağını notu) hareket olduğunu koordinatlar. Hızınız x^2 + y^2 > s^2nerede sise, eyleminiz atılır.

Su balonu yere çarptığında, en yakın olanlara daha fazla ağırlık verilen, ancak daha fazla şansa sahip olanlara daha az ağırlık veren rastgele bir oyuncu seçilir. Seçilen oyuncu 4 puan kaybeder.

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

Oyun 1000 adım sürer. Sonunda adlı bir dosya olacak log.out. Oyunu görüntülemek için verileri kopyalayıp bu kemanın içine yapıştırın: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

Ya da daha iyisi, 3D olarak görüntüleyin: http://www.brianmacintosh.com/waterballoonwars (BMac sayesinde)

100 maçtan sonra en yüksek skoru alan oyuncu kazanır (daha fazla olabilir, ancak daha az olamaz).

Bir çözüm göndermek istiyorsanız, gerçekten ayrıntılı bilgileri https://github.com/prakol16/water-balloon-wars/tree/master adresinde okumak isteyebilirsiniz .

3/8 düzenle :

Bunlar şimdilik kesin skorlardır (1 ve 2 oyuncuları dahil etmeden 1000 iterasyon). Yayınınızı düzenlerseniz, yorum yapabilirsiniz ve puanları tekrar yapacağım:

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

Kazanan, Weaklingortalama 39 puan aldı. Repeller21 puanla 2. oldu .


1
Balona çarptığınızda ne olur? Nasıl hareket eder? Ya birden fazla kişi vurursa?
Keith Randall

JSfiddle ile animasyon gerçekten güzel!
commonguy

Bu arada, Player sınıfındaki yöntemleri sonlandırmalısınız, aksi takdirde gönderiler bunları geçersiz kılabilir.
CommonGuy

2
Tersine çevirdiniz speedve strengthPlayer yapıcısındasınız.
Thrax

@KeithRandall dirX, dirYve dirZ(sizin şans güçlendirilmiş) basitçe balonun hızları eklenir. Birden fazla kişi
vurursa

Yanıtlar:


7

Simülatör

Umarım bu tamamdır, çünkü aslında bir giriş değildir. Görsel simülatör fikrini gerçekten beğendim ve her şeyi aynı anda görmeyi biraz daha kolaylaştıracak olanı oluşturmak istedim (tam 3D).

2/28 09:06 PST : takip kontrolleri, renkler ile güncelleme

3/4 08:47 PST : simülasyon hızı için bir kaydırıcı ile güncelleme ve yeni bir oyun başlatmayı aslında sayfayı yenilemeden yaptı (önbelleğe alınmış komut dosyasını yeniden yüklemek için Ctrl-F5 kullanın)

Çevrimiçi ThreeJS Görüntüleyici

resim açıklamasını buraya girin


3
+1000 Bu inanılmaz. Thank you
soktinpk

Şunu mu demek istediniz: Shift + F5 değil, Ctrl + F5?
Timtech

Her ikisi de Chrome'da çalışıyor gibi görünüyor.
BMac

7

Geri ve ileri

Bu bot yakınlaşmaya ve yüksekliği çok düşük olana kadar balona vurmaya çalışır ve kaçmaya çalışır.

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

    }

}

botunuz yasadışı hareketler yapıyor ve böylece hiçbir şey yapmıyor gibi görünüyor.
Moogie

@soktinpk Gönderimi düzelttim, şimdi daha iyisini yapmalıyım. Çok Moogie teşekkürler!
Thrax

Hala botun mümkün olanın ötesinde hareket istediğini görüyorum. İncelemeniz için yayınınızın bir düzenlemesini yaptım. Temelde balonun pozisyonunu hareket olarak kullanıyordunuz.
Moogie

@Moogie Doğru, çok teşekkürler!
Thrax

Yardımcı olduğuma sevindim. Botunuz olumlu puanlar almakta oldukça iyidir. aferin!
Moogie

5

AngryPenguin

Bu penguen öfkeli çünkü balona uçamıyor, bu yüzden balonu etrafında duran insanların yüzüne vurmaya çalışıyor.

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

}

Bu dövülecek olan.
Kevin Workman

5

cılız

Bu bot, balona çok zayıf olduğu için dokunabilir, bunun yerine yüksek şansına dayanır. Bu nedenle LuckyLoser'a benzer şekilde çalışır (bu botun esinlendiği).

Repeller dahil olmak üzere mevcut tüm botları yerine getirmiş gibi görünüyor.

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: şans lehine azaltılmış hız


3

Hydrophobe

Bu mümkün olan en basit bot biridir ama rekabetçi olduğu gibi ben göndereceğiz.

Strateji: şey ... bu botlar sudan nefret ediyor, bu yüzden yok oluyor.

Bot çok nadiren sıçradığı için ortalama 0 puanın biraz altında kalacaktır. Tüm botların skorlarının toplamı -1 * [balon vurma alanı] 'dır, bu nedenle Hidrofob muhtemelen ortalamanın üzerinde bir puan alacaktır.

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

Uzak dur

Bu oyuncu, yüksekliği> 2 olduğu sürece balonu kovalar. Balona çarptığı anda, balonu en yakın oyuncudan uzağa vurur . Balonun yüksekliği <2 olduğunda, bu oyuncu kaçar.

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

}

Düzenleme: Player1 ve Player2 dahil olarak oynuyordum. Bu oyuncu bu durumda kazanır, ama onları çıkardığımda kaybeder. Booooo.


3

Şanslı kaybeden

Bu bot yüksek şans skoruna dayanıyor. Balonun yakınında değilse, balona doğru koşar. Balona yaklaştığında, balonun menzilinde en az 2 oyuncu varsa, onu yere fırlatır. Aksi takdirde, düz bir şekilde vurur.

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: Beni balon doğru değil kaçmak yapan sabit hareket hatası> _ <Şimdi eğer vuramaz eğer doğrudan balon doğru koşuyorum.


3

Kovucu

Bu botun sadece bir gerçek hareketi vardır ve bu da balonu kendisinden uzağa itmeye devam etmektir. yani balonu iter.

Neredeyse her zaman kazanan mevcut bot mahsulüne (LuckyLoser, AngryPenguin, Hydrophobe, BackAndForth) karşı iyi bir performans sergiliyor gibi görünüyor. Ancak, diğer botların hepsi negatif puan almayı başarırsa, hidrofob her zaman kazanmaya hazırdır: 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);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.