สงครามบอลลูนน้ำ


12

เกม king-of-the-the-hill เกมนี้เป็นเกมวางแผนที่คุณจะต้องโยนลูกโป่งน้ำและหลีกเลี่ยงการโดนน้ำ เป้าหมายคือเพื่อให้ได้คะแนนมากที่สุด คุณจะได้รับแผนที่ของสนามและที่ตั้งของบอลลูนน้ำ คุณสามารถกลับมาว่าคุณต้องการที่จะตีลูกโป่งน้ำ (ถ้าคุณอยู่ใกล้พอ) ในทิศทางที่แน่นอนหรือว่าคุณต้องการที่จะย้ายไปในทิศทางที่แน่นอน

โดยเฉพาะ: บอลลูนน้ำจะเริ่มที่(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(ซึ่งหมายความว่ามันจะลงไปถ้าโชคของคุณต่ำ)

ในทำนองเดียวกันคุณสามารถส่งกลับMovementด้วยxและyพิกัดที่คุณกำลังเคลื่อนไหว (โปรดทราบว่าคุณไม่สามารถกระโดดในอากาศ) หากความเร็วของคุณอยู่x^2 + y^2 > s^2ที่ไหนsการกระทำของคุณจะถูกยกเลิก

หากบอลลูนน้ำกระทบพื้นจากนั้นจะมีการเลือกผู้เล่นแบบสุ่มโดยให้น้ำหนักแก่ผู้ที่อยู่ใกล้ที่สุดมากกว่า แต่ให้น้ำหนักน้อยกว่าผู้ที่โชคดี ผู้เล่นที่ถูกเลือกแพ้ 4 คะแนน

ผู้ควบคุม: https://github.com/prakol16/water-balloon-wars/tree/master

เกมใช้เวลา 1,000 ขั้นตอน log.outในตอนท้ายจะมีไฟล์ที่เรียกว่า คัดลอกและวางข้อมูลลงในซอนี้เพื่อดูเกม: https://jsfiddle.net/prankol57/s2x776dt/embedded/result/

หรือดียิ่งขึ้นดูในแบบ 3 มิติ: http://www.brianmacintosh.com/waterballoonwars (ขอบคุณ BMac)

ผู้เล่นที่มีคะแนนรวมสูงสุดหลังจากเกมที่ชนะ 100 (อาจมากกว่า แต่ไม่น้อยกว่า)

หากคุณต้องการที่จะส่งวิธีการแก้ปัญหาที่คุณอาจต้องการที่จะอ่านรายละเอียดเฉพาะจริงๆที่https://github.com/prakol16/water-balloon-wars/tree/master

แก้ไข 3/8 :

เหล่านี้เป็นคะแนนสุดท้ายในตอนนี้ (1,000 รอบโดยไม่รวมผู้เล่น 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 คือRepeller21 คะแนน


1
จะเกิดอะไรขึ้นเมื่อคุณตีลูกโป่ง มันเคลื่อนไหวอย่างไร เกิดอะไรขึ้นถ้ามีหลายคนเข้าชม
Keith Randall

แอนิเมชั่นกับ jsfiddle นั้นดีจริงๆ!
CommonGuy

โดยวิธีการที่คุณควรทำวิธีการในระดับผู้เล่นขั้นสุดท้ายมิฉะนั้นการส่งสามารถแทนที่พวกเขา
CommonGuy

2
คุณกลับหัวspeedและstrengthในตัวสร้าง Player
Thrax

@ KeithRandall The dirX, dirYและdirZ(ขยายโดยโชคของคุณ) จะถูกเพิ่มเข้าไปในความเร็วของบอลลูน หากมีหลายคนเข้าชม (ค่อนข้างไม่น่าเป็นไปได้) ผู้เล่นที่อาจได้รับสามคะแนนจะถูกตัดสินด้วยโชค (ดูรายละเอียดที่เฉพาะเจาะจง)
soktinpk

คำตอบ:


7

จำลอง

ฉันหวังว่ามันจะโอเคเพราะมันไม่ใช่รายการจริงๆ ฉันชอบความคิดของตัวจำลองภาพและฉันต้องการสร้างของตัวเองที่จะทำให้ง่ายขึ้นเล็กน้อยที่จะเห็นทุกอย่างในครั้งเดียว (3D เต็มรูปแบบ)

2/28 9:06 AM PST : อัปเดตด้วยการควบคุมตามสี

3/4 8:47 AM PST : อัปเดตด้วยแถบเลื่อนเพื่อจำลองความเร็วและทำให้การเริ่มเกมใหม่ใช้งานได้จริงโดยไม่ต้องรีเฟรชหน้าเว็บ (ใช้ Ctrl-F5 เพื่อโหลดสคริปต์แคชใหม่)

โปรแกรม ThreeJS Visualizer ออนไลน์

ป้อนคำอธิบายรูปภาพที่นี่


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 ด้วย!
Thrax

ฉันยังคงพบว่าบอทของคุณขอให้เคลื่อนไหวเกินกว่าที่จะเป็นไปได้ ฉันได้ทำการแก้ไขโพสต์ของคุณเพื่อตรวจสอบแล้ว โดยพื้นฐานแล้วคุณกำลังใช้ตำแหน่งของลูกโป่งเป็นการเคลื่อนไหว
Moogie

@ Moogie ใช่แล้วขอบคุณมาก ๆ !
Thrax

ดีใจที่ได้ช่วยเหลือ บอทของคุณค่อนข้างดีในการได้รับคะแนนบวก ทำได้ดี!
Moogie

5

AngryPenguin

เพนกวินตัวนี้โกรธเพราะเขาไม่สามารถบินขึ้นไปบนบอลลูนได้ดังนั้นเขาจึงพยายามที่จะชนลูกโป่งเข้าไปในใบหน้าของผู้คนที่ยืนอยู่รอบตัวเขา

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 * [พื้นที่ชนบอลลูน] ดังนั้น 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);
    }
}

แก้ไข: แก้ไขข้อผิดพลาดการเคลื่อนไหวซึ่งทำให้ฉันวิ่งหนีไปหาบอลลูน> _ <ตอนนี้ฉันวิ่งตรงไปที่บอลลูนถ้าฉันไม่สามารถตีมันได้


3

Repeller

บอทนี้อาศัยการเคลื่อนไหวจริงเพียงครั้งเดียวและนั่นคือการผลักบอลลูนออกไปจากตัวของมันเอง ie repells บอลลูน

ดูเหมือนว่าจะทำงานได้ดีกับการปลูกพืชในปัจจุบัน (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);
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.