물 풍선 전쟁


12

이 King-of-the-hill 게임은 물 풍선을 던져 물이 튀지 않도록해야하는 전략 게임입니다. 목표는 가장 많은 점수를 얻는 것입니다. 필드의지도와 물 풍선의 위치가 제공됩니다. 물 풍선을 (충분한 경우) 특정 방향으로 치고 싶거나 특정 방향으로 움직이고 싶을 때 돌아올 수 있습니다.

구체적으로 : 물 풍선은 (0, 0)높이 30 단위로 시작하여 떨어집니다. 물 풍선이 땅에 닿으면 무작위로 4 점을 잃게됩니다. 또한, 마지막으로 풍선을 치는 플레이어는 3 점을 얻습니다. 따라서 풍선을 똑바로 누르면 1 포인트가 손실 될 수 있습니다.

당신은 확장하는 클래스를 작성합니다 Player. 생성자를 구현해야합니다. 생성자는 다음과 같습니다.

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

이 숫자는 doubles입니다. 첫 번째 숫자는 플레이어의 속도를 나타내고, 두 번째 숫자는 힘을, 세 번째 숫자는 운을 나타냅니다. 숫자는 최대 10 이하이어야하며 숫자는 0 보다 작 거나 같을 수 없습니다.

둘째, 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 차원 배열이 아닙니다. 또한 이는 정수가 아닌 좌표를 위치로 사용함을 의미합니다. 이것은 완벽하게 괜찮습니다.

또 다른 결과는 플레이어와 풍선이 겹칠 수 있다는 것입니다. 사실, 두 명의 플레이어가 정확히 같은 위치에있을 수 있습니다!

풍선에는 특정 속도와 방향이 있습니다. 일반적으로 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중인 xy좌표를 사용하여 a 를 반환 할 수 있습니다 (공중으로 점프 할 수 없음). 당신의 속도가 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 편집 :

현재 최종 점수입니다 (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
풍선을 치면 어떻게됩니까? 어떻게 움직입니까? 여러 사람이 충돌하면 어떻게됩니까?
Keith Randall

jsfiddle을 사용한 애니메이션이 정말 좋습니다!
CommonGuy

그런데 Player 클래스의 메서드를 final로 만들어야합니다. 그렇지 않으면 제출이 메서드를 재정의 할 수 있습니다.
CommonGuy

2
당신은 반전 speed하고 strength플레이어 생성자에 있습니다.
Thrax

@KeithRandall는 dirX, dirY그리고 dirZ(행운에 의해 증폭) 단순히 풍선의 속도에 추가됩니다. 여러 사람이 그것을 칠 경우 (
어쩌면 드물게

답변:


7

모의 실험 장치

나는 이것이 실제로 항목이 아니기 때문에 이것이 좋기를 바랍니다. 나는 시각적 시뮬레이터의 아이디어를 정말로 좋아했고 한 번에 모든 것을 한 번에 더 쉽게 볼 수 있도록 내 자신을 만들고 싶었습니다 (전체 3D).

2/28 9:06 AM PST : 따라 제어, 색상으로 업데이트

3/4 8:47 AM PST : 시뮬레이션 속도를위한 슬라이더로 업데이트하고 페이지를 새로 고치지 않고 실제로 새 게임을 시작하도록했습니다 (Ctrl-F5를 사용하여 캐시 된 스크립트를 다시로드)

온라인 ThreeJS Visualizer

여기에 이미지 설명을 입력하십시오


3
+1000 놀랍습니다. 감사합니다
soktinpk

Shift + F5가 아니라 Ctrl + 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!
Thrax

나는 아직도 당신의 봇이 가능한 것 이상의 움직임을 요구하고 있음을 알고 있습니다. 검토를 위해 게시물을 수정했습니다. 기본적으로 풍선의 위치를 ​​움직임으로 사용하고있었습니다.
Moogie

@Moogie 맞아, 고마워!
Thrax

기쁘다. 봇은 긍정적 인 점수를 얻는 데 능숙합니다. 잘 했어!
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;
    }

}

이것은 이길 것입니다.
Kevin Workman

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

편집 : 운이 유리한 속도 감소


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

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

편집 : 풍선으로 실제로 달려 나지 못하게하는 운동 버그 수정> _ <이제 풍선을 칠 수 없으면 풍선을 향해 똑바로 달려갑니다.


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);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.