水風船戦争


12

このキングオブザヒルゲームは戦略ゲームであり、水風船を投げて水が飛び散らないようにする必要があります。目標は、ほとんどのポイントを獲得することです。フィールドの地図と水風船の位置が表示されます。特定の方向に水風船にぶつかる(十分近い場合)か、特定の方向に移動したいのかを返すことができます。

具体的には、水風船は (0, 0) 30ユニットの高、落下します。水風船が地面に当たった場合、プレーヤーはランダムに4ポイントを失うように選択され、風船に近い人により大きな重みが与えられます。さらに、バルーンを最後に打ったプレーヤーは3ポイントを獲得します。したがって、風船を真下に当てると、1ポイントを失う可能性が高くなります。

拡張するクラスを作成しますPlayer。コンストラクターを実装する必要があります。コンストラクターは次のようになります。

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

これらの番号はdoublesです。最初の数字はプレイヤーの速度を表し、2番目の数字は強さを表し、3番目の数字は運を表します。合計は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>。フィールドは無限です-あなたがどこまで行けるかに制限はありません。2次元配列などではありません。さらに、これは、位置として整数以外の座標を持つことを意味します。これはまったく問題ありません。

別の結果は、プレーヤーとバルーンが重なる可能性があることです。実際、2人のプレイヤーがまったく同じ場所にいる可能性があります。

バルーンには一定の速度と方向があります。一般に、3単位/ステップの割合で低下します。また、x方向とy方向に移動します。aを返すときHit、バルーンを押しているx、y、およびz方向を渡します。あなたはそれが本当であればということ、その高さが10以上であるか、その距離ます(2つのだけ次元上)からさらに4より大きいあるバルーンを打つことができないx^2 + y^2 + z^2 > s^2ところsあなたの強さで、かつxyzあなたがヒットすることを指示しています、アクションは破棄されます。ヒットの力は、0との間の乱数によって増幅されますluck(つまり、運が低い場合はダウンする可能性があります)。

同様に、あなたは返すことができMovementxyあなたは(あなたが空気中にジャンプすることはできませんのでご注意を)移動していることを座標。もし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 //www.brianmacintosh.com/waterballoonwars(BMacのおかげです)

100(以降ではなく、それ以上の場合もあります)ゲームのスコアの合計が最も高いプレーヤーが勝ちます。

ソリューションを送信する場合は、https://github.com/prakol16/water-balloon-wars/tree/masterで本当に具体的な詳細を読むことをお勧めします

編集3/8

これらは現在の最終スコアです(プレーヤー1と2を含まない1000回の反復)。投稿を編集したら、コメントすることができます。スコアをやり直します。

{
    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位はRepeller21点でした。


1
風船を打つとどうなりますか?どのように動くのですか?複数の人がヒットした場合はどうなりますか?
キースランドール

jsfiddleを使用したアニメーションは本当に素晴らしいです!
CommonGuy

ところで、Playerクラスのメソッドをfinalにする必要があります。そうしないと、サブミットによってそれらがオーバーライドされる可能性があります。
CommonGuy

2
あなたは反転speedし、strengthプレーヤーのコンストラクタインチ
スラックス

@KeithRandallザはdirXdirY、及びdirZ(運によって増幅)単にバルーンの速度に添加されます。複数の人がヒットした場合(多少ありそうもない)、3ポイントを獲得する可能性のあるプレイヤーが運で決定されます(具体的な詳細を参照)
-soktinpk

回答:


7

シミュレーター

実際にはエントリではないため、これで問題ないことを願っています。私はビジュアルシミュレーターのアイデアが本当に好きだったので、すべてを一度に見やすくする(フル3D)独自のツールを作成したかったのです。

2/28 9:06 AM PST:フォローコントロール、色で更新

3/4 8:47 AM PST:シミュレーション速度のスライダーを使用して更新し、ページを更新せずに新しいゲームの開始が実際に機能するようにしました(Ctrl-F5を使用してキャッシュされたスクリプトを再読み込みします)

オンラインThreeJSビジュアライザー

ここに画像の説明を入力してください


3
+1000それは驚くべきことです。ありがとう
-soktinpk

Shift + F5ではなく、Ctrl + F5を意味しませんか?
ティムテック

どちらも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);
                }
            }
        }

    }

}

ボットは違法な動きを実行しているため、実行しても何もしません。
ムージー

@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(このボットからインスピレーションを受けている)と同様に機能します。

彼はリペラーを含む現在のすべてのボットを実行しているようです。

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

編集:運を優先して速度を低下


3

疎水性

これは可能な限り単純なボットの1つですが、競争力があるので投稿します。

戦略:まあ...このボットは水を嫌うので、それは消えます。

ボットはめったにスプラッシュされないため、平均で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が同梱されていました。この場合、このプレイヤーは勝ちますが、それらを取り出すと負けます。うん


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

編集:実際に気球に向かって逃げてしまう移動のバグを修正しました> _ <今、私はそれを打つことができない場合、気球に向かってまっすぐに走ります。


3

リペラ

このボットに依存しているのは実際の動きが1つだけであり、それはそれ自体からバルーンを押し続けることです。すなわち、バルーンをはじきます。

現在のボット(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);
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.