อสมมาตร KOTH: Catch the Cat (Catcher Thread)


17

KOTH อสมมาตร: จับแมว

UPDATE : ไฟล์ gist-update แล้ว (รวมถึง submisisons ใหม่) เนื่องจาก Controller.java ไม่พบข้อยกเว้น (ข้อผิดพลาดเท่านั้น) ตอนนี้มันตรวจจับข้อผิดพลาดและข้อยกเว้นแล้วพิมพ์ออกมา

ความท้าทายนี้ประกอบด้วยสองหัวข้อนี้เป็นหัวข้อจับด้ายแมวสามารถพบได้ที่นี่

ควบคุมสามารถดาวน์โหลดได้ที่นี่

นี่คือความไม่สมดุล KOTH: การส่งแต่ละคนเป็นทั้งแมวหรือจับ มีเกมระหว่างแมวและแมวจับแต่ละคู่ แมวและมือปราบมารมีอันดับแยกกัน

สิ่งที่จับ

มีแมวอยู่บนตะแกรงหกเหลี่ยม งานของคุณคือการจับมันให้เร็วที่สุด ทุกเทิร์นคุณสามารถวางถังน้ำบนเซลล์กริดเดียวเพื่อป้องกันไม่ให้แมวไปที่นั่น แต่แมวไม่ได้เป็นใบ้ (และบางที) เป็นใบ้และเมื่อใดก็ตามที่คุณวางถังแมวจะย้ายไปที่เซลล์กริดอื่น เนื่องจากกริดนั้นเป็นรูปหกเหลี่ยมแมวจึงสามารถไปได้ 6 ทิศทาง เป้าหมายของคุณคือล้อมรอบแมวด้วยที่เก็บน้ำได้เร็วขึ้นดีกว่า

แมว

คุณรู้ว่าผู้จับต้องการจับคุณโดยการวางถังน้ำรอบตัวคุณ แน่นอนว่าคุณพยายามหลบเลี่ยง แต่ในขณะที่คุณเป็นแมวขี้เกียจ (ในฐานะที่เป็นแมว) คุณต้องก้าวไปทีละขั้น หมายความว่าคุณจะไม่สามารถอยู่ในที่เดียวกันกับคุณได้ แต่คุณต้องย้ายไปยังหนึ่งในหกจุดโดยรอบ เมื่อใดก็ตามที่คุณเห็นว่าผู้จับวางถังน้ำใหม่คุณจะไปที่เซลล์อื่น แน่นอนคุณพยายามหลบเลี่ยงให้นานที่สุด

ตะแกรง

กริดนั้นเป็นรูปหกเหลี่ยม แต่เนื่องจากเราไม่มีโครงสร้างข้อมูลแบบหกเหลี่ยมเราจึงใช้11 x 11อาร์เรย์ 2d ของสี่เหลี่ยมและเลียนแบบ 'พฤติกรรม' หกเหลี่ยมที่แมวสามารถเคลื่อนที่ได้ใน 6 ทิศทาง:

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

โทโพโลยีคือ toroidal ซึ่งหมายความว่าถ้าคุณเหยียบเซลล์ 'นอก' ของอาร์เรย์คุณจะถูกโอนไปยังเซลล์ที่เกี่ยวข้องในอีกด้านหนึ่งของอาร์เรย์

เกม

แมวเริ่มต้นที่ตำแหน่งที่กำหนดในตาราง ผู้จับสามารถทำการเดินครั้งแรกจากนั้นแมวและการจับการเคลื่อนไหวแบบอื่น ๆ จนกว่าแมวจะถูกจับ จำนวนขั้นตอนคือคะแนนสำหรับเกมนั้น แมวพยายามที่จะได้รับคะแนนที่ดีที่สุดเท่าที่เป็นไปได้ที่จับพยายามที่จะได้รับคะแนนที่ต่ำที่สุด ผลรวมเฉลี่ยของทุกเกมที่คุณเข้าร่วมจะเป็นคะแนนการส่งของคุณ มีการจัดอันดับแยกกันสองรายการสำหรับแมวหนึ่งรายการสำหรับมือปราบมาร

ตัวควบคุม

คอนโทรลเลอร์ที่กำหนดถูกเขียนใน Java ในฐานะที่เป็น catcher หรือ cat คุณแต่ละคนจะต้องใช้คลาส Java (มีตัวอย่างดั้งเดิมอยู่แล้ว) และวางไว้ในplayersแพ็คเกจ (และอัปเดตรายชื่อ cat / catchers ในคลาส Controller) แต่คุณอาจเขียน ฟังก์ชันเพิ่มเติมภายในคลาสนั้น คอนโทรลเลอร์มาพร้อมกับตัวอย่างการทำงานสองอย่างของคลาส cat / catcher แบบง่าย ๆ

เขตข้อมูลนั้นเป็นอาร์เรย์ 2 11 x 11มิติintที่เก็บค่าสถานะปัจจุบันของเซลล์ ถ้ามือถือเป็นที่ว่างเปล่ามันจะมีค่า0ถ้ามีแมวมันมีค่าและถ้ามีถังมี-11

มีฟังก์ชั่นบางอย่างที่คุณสามารถใช้ได้: isValidMove()/ isValidPosition()ใช้สำหรับตรวจสอบว่าการเคลื่อนไหวของคุณ (cat) / ตำแหน่ง (catcher) นั้นถูกต้อง

ทุกครั้งที่ถึงตาคุณtakeTurn()จะมีการเรียกฟังก์ชั่นของคุณ อาร์กิวเมนต์ประกอบด้วยสำเนาของกริดปัจจุบันที่มีวิธีการเช่นread(i,j)อ่านเซลล์ที่(i,j)และisValidMove()/ isValidPosition()ตรวจสอบความถูกต้องของคำตอบของคุณ สิ่งนี้ยังจัดการการตัดทอพอโลยีโทโพโลยีซึ่งหมายความว่าแม้ว่ากริดมีเพียง 11 x 11 คุณยังสามารถเข้าถึงเซลล์ (-5,13)

วิธีควรคืนค่าintอาร์เรย์ของสององค์ประกอบซึ่งเป็นตัวแทนของการเคลื่อนไหวที่เป็นไปได้ สำหรับแมวเหล่านี้เป็นซึ่งเป็นตัวแทนของตำแหน่งสัมพัทธ์ของแมวที่อยากจะไปและปราบมารกลับพิกัดที่แน่นอนของที่พวกเขาต้องการที่จะวางถัง{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}{i,j}

หากวิธีการของคุณสร้างการย้ายที่ไม่ถูกต้องการส่งของคุณจะถูกตัดสิทธิ์ การย้ายนั้นถือว่าไม่ถูกต้องหากที่ปลายทางของคุณเป็นที่เก็บข้อมูลอยู่แล้วหรือการย้ายนั้นไม่ได้รับอนุญาต / ปลายทางถูกครอบครองอยู่แล้ว (เป็นแมว) หรือหากมีการฝากข้อมูล / แมว (เป็นตัวจับ) อยู่แล้ว คุณสามารถตรวจสอบว่าก่อนมือด้วยฟังก์ชั่นที่กำหนด

ข้อมูลที่คุณส่งควรจะทำงานเร็วพอสมควร หากวิธีการของคุณใช้เวลานานกว่า 200ms สำหรับแต่ละขั้นตอนมันจะถูกตัดสิทธิ์ด้วย (โดยเฉพาะอย่างยิ่งน้อย ... )

โปรแกรมได้รับอนุญาตให้จัดเก็บข้อมูลระหว่างขั้นตอน

การส่ง

  • คุณสามารถส่งได้มากเท่าที่คุณต้องการ
  • โปรดอย่าแก้ไขการส่งที่คุณส่งมาอย่างมีนัยสำคัญ
  • โปรดส่งแต่ละคำตอบด้วยคำตอบใหม่
  • การส่งแต่ละครั้งควรมีชื่อที่ไม่ซ้ำกัน
  • การส่งควรประกอบด้วยรหัสของชั้นเรียนของคุณเช่นเดียวกับคำอธิบายที่บอกเราถึงวิธีการทำงานของคุณ
  • คุณสามารถเขียนบรรทัดสำหรับ<!-- language: lang-java -->ซอร์สโค้ดของคุณเพื่อรับการเน้นไวยากรณ์โดยอัตโนมัติ

เกณฑ์การให้คะแนน

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

ความท้าทายนี้ได้รับแรงบันดาลใจจากเกมแฟลชเก่า

ขอบคุณ @PhiNotPi สำหรับการทดสอบและให้ข้อเสนอแนะที่สร้างสรรค์

คะแนนปัจจุบัน (100 เกมต่อการจับคู่)

Name              Score      Rank   Author

RandCatcher       191674     8      flawr   
StupidFill        214246     9      flawr
Achilles          76820      6      The E
Agamemnon         74844      5      The E
CloseCatcher      54920      4      randomra
ForwordCatcher    94246      7      MegaTom  
Dijkstra          46500      2      TheNumberOne
HexCatcher        48832      3      randomra
ChoiceCatcher     43828      1      randomra

RandCat           77928      7      flawr
StupidRightCat    81794      6      flawr
SpiralCat         93868      5      CoolGuy
StraightCat       82452      9      CoolGuy
FreeCat           106304     3      randomra
RabidCat          77770      8      cain
Dijkstra's Cat    114670     1      TheNumberOne
MaxCat            97768      4      Manu
ChoiceCat         113356     2      randomra

โปรแกรมอะไรที่ทำให้อนิเมชั่น?
MegaTom

ภาพเคลื่อนไหวเป็นเพียง GUI (เมื่อเริ่มต้นคอนโทรลเลอร์ที่คุณต้องตั้งค่าPRINT_STEPS = trueรายละเอียดเพิ่มเติมในไฟล์MyFrame.java) แล้วฉันบันทึกนี้กับLICEcapและแก้ไขมันด้วยGIMP หากคุณมีคำถามเพิ่มเติมเพียงแค่ถาม!
ข้อผิดพลาด

หากคุณเพิ่มผู้ใช้งานอินพุตให้กับคอนโทรลเลอร์มันอาจสร้างซอฟต์แวร์ที่ดีด้วย GUI และบอทที่เขียนไปแล้ว นอกจากนี้ยังเป็นที่น่าสนใจที่จะเห็นว่ามนุษย์สามารถแตก / ละเมิดยุทธศาสตร์บอทที่เฉพาะเจาะจงได้มากเพียงใด
Randomra

บอทของฉันสามารถเก็บข้อมูลจากการแข่งขันก่อนหน้าเพื่อพยายามหาลำดับการเคลื่อนที่ที่ดีขึ้นกับบอทเดียวกันได้หรือไม่? ฉันไม่คิดว่าจะดีไปกว่านี้หากคุณทำมากขึ้น นอกจากนี้ยังต้องเดาว่าจะเล่นกับบอทใหม่หรือไม่ดังนั้นลำดับการรันก็จะสำคัญเช่นกัน
randomra

1
ทำไมคะแนนของแมวถึงสั่งยกเลิก?
Spikatrix

คำตอบ:


6

จุดอ่อน

Achilles ไม่สว่างเกินไป แต่เขาก็ไร้ประสิทธิภาพ ก่อนอื่นเขาจะหยุดแมวไม่ให้ใช้แผ่นปิดล้อมรอบกระดานจากนั้นเขาก็แบ่งกระดานออกเป็นสองส่วน จากนั้นเขาก็แบ่งส่วนของกระดานต่อไปแมวก็แบ่งครึ่งแมวจนติดกับดัก

การสาธิต RandCat กับ Achilles

Randcat vs Achilles

package players;
/**
 * @author The E
 */
import main.*;



public class Achilles implements Catcher
{
    public Achilles() {

    }
    @Override
    public String getName() {

        return "Achilles";
    }

    @Override
    public int[] takeTurn(Field f) {
        try{
        if(f.read(0, f.SIZE-1)!=Field.BUCKET)
        {
            //Make the first line

            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j) == Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            return WasteGo(f);

        }
        else if (f.read(f.SIZE-1, 0)!=Field.BUCKET)
        {
            //Make the second line
            for(int i = 0; i<f.SIZE; i++)
            {
                if(f.read(i, 0) == Field.EMPTY)
                {
                    return new int[]{i,0};
                }
            }
            //The cat got in the way
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(1, j) == Field.EMPTY)
                {
                    return new int[]{1,j};
                }
            }
            return WasteGo(f);
        }
        else
        {
            return TrapCat(1,1,f.SIZE-1, f.SIZE-1, false, f);

        }
        }
        catch (Exception e)
        {
            return WasteGo(f);
        }
    }
    private int[] TrapCat(int i1, int j1, int i2, int j2, Boolean direction, Field f) {
        for(int a = 0; a<f.SIZE+10; a++)
        {
            if(direction)
            {

                int height = j2-j1+1;
                int row = j1 + height/2;
                for(int i = i1; i<=i2; i++)
                {
                    if(f.read(i, row)==Field.EMPTY)
                    {
                        return new int[]{i,row};
                    }
                }

                    //Done that Row
                    //Find cat
                    if(f.findCat()[1]>row)
                    {
                        //he's above the line
                        j1 = row+1;
                        direction = !direction;
                        //return TrapCat(i1, row+1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's below the line
                        j2 = row - 1;
                        direction = !direction;
                        //return TrapCat(i1, j1, i2, row-1, !direction, f);
                    }


            }
            else
            {
                int bredth = i2-i1+1;
                int column = i1 + bredth/2;
                //Continue making the line
                for(int j = j1; j<=j2; j++)
                {
                    if(f.read(column,j)==Field.EMPTY)
                    {
                        return new int[]{column,j};
                    }
                }

                    //Done that Column
                    //Find cat
                    if(f.findCat()[0]>column)
                    {
                        //he's right of the line
                        i1 = column + 1;
                        direction = !direction;
                        //return TrapCat(column+1, j1, i2, j2, !direction, f);
                    }
                    else
                    {
                        //he's left of the line
                        i2 = column -1;
                        direction = !direction;
                        //return TrapCat(i1, j1, column-1, j2, !direction, f);
                    }

            }
        }
        return WasteGo(f);
    }
    private int[] WasteGo(Field f) {
        for (int i = 0; i<f.SIZE;i++)
        {
            for(int j=0;j<f.SIZE;j++)
            {
                if(f.read(i,j)==Field.EMPTY)
                {
                    return new int[]{i,j};
                }
            }
        }
        //Something drastic happened
        return new int[]{0,0};
    }



}

ตอนนี้อันไหนล่ะ Achilles หรือ Hector (หรือใครบางคนที่มีความผิดปกติของตัวตน dissiociative? =)
ข้อบกพร่อง

@flawr Achilles ฮ่า ๆ ฉันเปลี่ยนชื่อครึ่งทาง (มันฉลาดกว่าที่จะตั้งชื่อ Achilles และ cat Hector) แต่ลืมเปลี่ยน java - มันเป็นสิ่งที่เกิดขึ้นเมื่อคุณเขียนโปรแกรมหลังจากชา :(
euanjt

แต่เฮ็กเตอร์ค่อนข้างจะเป็นชื่อสุนัข =) ขอบคุณสำหรับการส่งของคุณใช้งานได้ดี ฉันหวังว่าคุณไม่คิดว่าฉันจะใส่ 'preamble' ในโค้ดของคุณด้วย
ข้อบกพร่อง

ใช่ไม่มีปัญหา เฮคเตอร์ไม่เสียงเหมือนสุนัขชื่อ ...
euanjt

ฉันเพิ่งจำลองสถานการณ์ (10,000 เกมสำหรับการจับคู่แต่ละครั้ง) และ Achilles ถูกตัดสิทธิ์เนื่องจาก StackOverflowError ซ้ำ ฉันคิดว่าการเรียกซ้ำไม่ได้จบ: pastebin.com/9n6SQQnd
ข้อบกพร่อง

5

Agamemnon

อะกาเม็มนอนแยกแมวครึ่งตัวออกเป็นเส้นแนวตั้งจนกว่าแมวจะมีแถบกว้าง 2 เท่านั้นที่จะย้ายเข้าไปในจุดที่เขาดักแมว

อกาเม็มนอน vs แรนต์แคท:

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

package players;
/**
 * @author The E
 */
import main.*;



    public class Agamemnon implements Catcher {
        boolean up = true;
        @Override
        public String getName() {
            return "Agamemnon";
        }

        @Override
        public int[] takeTurn(Field f) {
            //First Make Line in column 1
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(0, j)==Field.EMPTY)
                {
                    return new int[]{0,j};
                }
            }
            //Then in column SIZE/2
            for(int j = 0; j<f.SIZE; j++)
            {
                if(f.read(f.SIZE/2, j)==Field.EMPTY)
                {
                    return new int[]{f.SIZE/2,j};
                }
            }
            //Then work out where the cat is
            int left, right;
            int cati = f.findCat()[0];
            if(cati<f.SIZE/2)
            {
                left = 1;
                right = f.SIZE/2-1;
            }
            else
            {
                left = f.SIZE/2+1;
                right = f.SIZE-1;
            }
            while(right-left>1)
            {
                //If the cat is not in a two width column
                //Split the area the cat is in in half
                int middleColumn = (left+right)/2;
                for(int j = 0; j<f.SIZE; j++)
                {
                    if(f.read(middleColumn, j)==Field.EMPTY)
                    {
                        return new int[]{middleColumn,j};
                    }
                }
                //If we got here we had finished that column
                //So update left and/or right
                if(cati<middleColumn)
                {
                    //he's left of the middle Column
                    right = middleColumn - 1;
                }
                else
                {
                    //he's right of the middle Column
                    left = middleColumn+1;
                }
                //Repeat
            }
            //Otherwise try to trap the cat
            //Make a line up and down on the opposite side of the cat
            int catj = f.findCat()[1];
            if(left!=right){
                if(cati==left)
                {
                    if(f.read(right, catj)==Field.EMPTY)
                    {
                        return new int[]{right, catj};
                    }
                    if(f.read(right, catj-1)==Field.EMPTY)
                    {
                        return new int[]{right, catj-1};
                    }
                    if(f.read(right, catj+1)==Field.EMPTY)
                    {
                        return new int[]{right, catj+1};
                    }


                }
                else
                {
                    if(f.read(left, catj)==Field.EMPTY)
                    {
                        return new int[]{left, catj};
                    }
                    if(f.read(left, catj-1)==Field.EMPTY)
                    {
                        return new int[]{left, catj-1};
                    }
                    if(f.read(left, catj+1)==Field.EMPTY)
                    {
                        return new int[]{left, catj+1};
                    }

                }
            }
            //Alternate between above and below
            if(up)
            {
                up = !up;
                if(f.read(cati, catj+1)==Field.EMPTY)
                {

                    return new int[]{cati, catj+1};
                }
            }
            up = !up;
            if(f.read(cati, catj-1)==Field.EMPTY)
            {

                return new int[]{cati, catj-1};
            }
            return WasteGo(f);
        }

        private int[] WasteGo(Field f) {
            for (int i = 0; i<f.SIZE;i++)
            {
                for(int j=0;j<f.SIZE;j++)
                {
                    if(f.read(i,j)==Field.EMPTY)
                    {
                        return new int[]{i,j};
                    }
                }
            }
            //Something drastic happened
            return new int[]{0,0};
        }
    }

ผู้จับนี้ทำได้ดีกว่า Achilles อย่างสม่ำเสมอและฉันคิดว่าเขาแตกต่างกันพอที่จะรับประกันคำตอบใหม่


วิธีการแก้ปัญหาที่ดีมากผมแน่ใจว่าจุดอ่อนได้ใกล้เคียงกับที่ดีที่สุด แต่ตอนนี้ผมคิดว่าแม้ Agamemnon อาจจะดีขึ้นเล็กน้อย =)
flawr

ใช่ Agamemnon มีช่วงท้ายเกมที่ดีมากดักอัลกอริทึมกว่าจุดอ่อน แต่ผมค่อนข้างมั่นใจว่ามีการปรับแต่งบางอย่าง ... ตอนนี้ผมจะพยายามและการทำงานในแมว :)
euanjt

@flawr tweak ขนาดเล็กมากถูกเพิ่มเพื่อเพิ่มความเร็วในการจับในกรณีพิเศษบางอย่างนี่ไม่ได้ส่งผลกระทบต่อภาพเคลื่อนไหวที่นี่ (แม้ว่าฉันคิดว่ามันอาจส่งผลกระทบต่อภาพเคลื่อนไหวของ SpiralCat)
euanjt

คำถาม! จะเกิดอะไรขึ้นถ้าคุณกำลังจะปิดสาย แต่แมวกำลังยืนอยู่ในจุดสุดท้าย?
Mr. Llama

@ Mr.Llama มันเริ่มสร้างบรรทัดถัดไปราวกับว่าบรรทัดนั้นถูกเติมเต็ม (เช่นในความเป็นจริงแล้วแมวเป็นที่เก็บข้อมูล) - ไม่ใช่การใช้เทิร์นที่มีประสิทธิภาพมากที่สุด แต่เกิดขึ้นน้อยมากว่ามันไม่สำคัญ - แมวต้องย้ายไปแล้วในเทิร์นถัดไปเพื่อให้ฉันสามารถวางถังของฉันที่นั่น
euanjt

5

HexCatcher

หากผู้จับสามารถนำแมวเข้าไปด้านในของรูปหกเหลี่ยมขนาดใหญ่ที่มี 3 ด้านที่มุมของรูปหกเหลี่ยมนั้นถูกครอบครองโดยถังแล้วตัวจับสามารถเก็บแมวไว้ในบริเวณนี้และจับเขาได้ รูปหกเหลี่ยมมีลักษณะดังนี้:

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

นี่คือสิ่งที่ HexCatcher พยายามที่จะบรรลุ มันจัดเรียงเขตข้อมูลด้วยรูปหกเหลี่ยมขนาดใหญ่เหล่านี้ในลักษณะที่แต่ละมุมเซลล์เป็นส่วนหนึ่งของรูปหกเหลี่ยมขนาดใหญ่ 3 รูป

หากมีโอกาสที่จะให้แมวอยู่ในพื้นที่ปัจจุบันโดยเชื่อมต่อสองมุมที่อยู่ถัดจากแมวบ็อตจะทำเช่นนั้น (เช่นในภาพถ้าแมวอยู่ที่ 7,5 เราเลือก 7,6 ถึงแม้ว่าจะมีเพียงเซลล์ 6,6 และ 8,5 เท่านั้น)

หากก่อนหน้านี้ไม่ใช่ตัวเลือกเราเลือกที่จะเล่นมุมซึ่งเป็นส่วนหนึ่งของพื้นที่ที่แมวอยู่ หากเลือกมุมดังกล่าวทั้งหมดแล้ว (เหมือนในภาพ) เราจะเลือกเซลล์ถัดจากแมว

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

DijkstrasCat vs HexCatcher:

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

package players;
/**
 * @author randomra
 */
import main.Field;

public class HexCatcher implements Catcher {
    public String getName() {
        return "HexCatcher";
    }

    final int[][] o = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 }, { 0, -1 },
            { 1, -1 } };// all valid moves
    final int[][] t = { { -2, 2 }, { 0, 2 }, { -2, 0 }, { 2, 0 }, { 0, -2 },
            { 2, -2 } };// all valid double moves in one direction
    final int[][] h = { { -1, 2 }, { -2, 1 }, { -1, -1 }, { 1, -2 }, { 2, -1 },
            { 1, 1 } };// all valid moves in not one direction
    int opp = 0;

    public int[] takeTurn(Field f) {
        int[] p = f.findCat();
        // center of the hexagon the cat is in
        int[] c = { ((int) p[0] / 3) * 3 + 1, ((int) p[1] / 3) * 3 + 1 };
        // change priority of catching direction at every turn
        opp = 1 - opp;

        // check missing corner piece next to cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            boolean close = false;
            for (int k = 0; k < 6; k++) {
                if (c[0] + h[ind][0] == p[0] + o[k][0]
                        && c[1] + h[ind][1] == p[1] + o[k][1]) {
                    close = true;
                }
            }
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0 && close) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // cut off escape route if needed
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + o[ind][0], c[1] + o[ind][1]) == -1
                    && f.read(c[0] + t[ind][0], c[1] + t[ind][1]) == 0) {
                return new int[] { c[0] + t[ind][0], c[1] + t[ind][1] };
            }
        }
        // check any missing corner piece in the area
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(c[0] + h[ind][0], c[1] + h[ind][1]) == 0) {
                return new int[] { c[0] + h[ind][0], c[1] + h[ind][1] };
            }
        }
        // choose an empty cell next to the cat
        for (int i = 0; i < 6; i++) {
            int ind = (i + opp * 3) % 6;
            if (f.read(p[0] + o[ind][0], p[1] + o[ind][1]) == 0) {
                return new int[] { p[0] + o[ind][0], p[1] + o[ind][1] };
            }
        }
        return null;
    }
}

3

CloseCatcher

เลือกหนึ่งในตำแหน่งที่แมวสามารถก้าวไปในขั้นตอนต่อไป มันเลือกเส้นทางที่จะให้เส้นทางที่เป็นไปได้มากที่สุดหลังจาก 3 ขั้นตอนสำหรับแมวหากมันเคลื่อนที่ไปที่นั่นและทุ่งจะไม่เปลี่ยน

โค้ดเกือบจะเหมือนกับรายการแมวของฉันFreeCatซึ่งเลือกทิศทางในลักษณะที่คล้ายกันมาก

SpiralCat vs CloseCatcher:

SpiralCat vs CloseCatcher

package players;
/**
 * @author randomra
 */

import main.Field;
import java.util.Arrays;

public class CloseCatcher implements Catcher {
    public String getName() {
        return "CloseCatcher";
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { -1, 0 }, { 1, 0 },
            { 0, -1 }, { 1, -1 } };// all valid moves
    final int turnCheck = 3;

    public int[] takeTurn(Field f) {

        int[] pos = f.findCat();
        int[] bestMove = { 0, 1 };
        int bestMoveCount = -1;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            int moveCount = free_count(currPos, turnCheck, f);
            if (moveCount > bestMoveCount) {
                bestMoveCount = moveCount;
                bestMove = t;
            }
        }
        int[] bestPos = { pos[0] + bestMove[0], pos[1] + bestMove[1] };
        return bestPos;
    }

    private int free_count(int[] pos, int turnsLeft, Field f) {
        if (f.isValidPosition(pos) || Arrays.equals(pos, f.findCat())) {
            if (turnsLeft == 0) {
                return 1;
            }
            int routeCount = 0;
            for (int[] t : turns) {
                int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
                int moveCount = free_count(currPos, turnsLeft - 1, f);
                routeCount += moveCount;
            }
            return routeCount;
        }
        return 0;
    }

}

ดี +1 CloseCatcher ได้อย่างง่ายดายจับStraightCat
Spikatrix

3

Dijkstra

เขาไม่ชอบแมวมาก (:v{ >

FreeCat vs Dijkstra (ต้องการการปรับปรุง) :

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

package players;

import main.Controller;
import main.Field;

import java.util.*;

/**
 * @author TheNumberOne
 *
 * Catches the cat.
 */

public class Dijkstra implements Catcher{

    private static final int[][][] CACHE;

    static {
        CACHE = new int[Controller.FIELD_SIZE][Controller.FIELD_SIZE][2];
        for (int x = 0; x < Controller.FIELD_SIZE; x++){
            for (int y = 0; y < Controller.FIELD_SIZE; y++){
                CACHE[x][y] = new int[]{x,y};
            }
        }
    }

    private static final int[][] possibleMoves = {{-1,1},{0,1},{-1,0},{1,0},{0,-1},{1,-1}};
    @Override
    public String getName() {
        return "Dijkstra";
    }

    @Override
    public int[] takeTurn(Field f) {
        long startTime = System.nanoTime();

        final int[] theCat = f.findCat();
        int[] bestMove = {-1,1};
        int[] bestOpenness = {Integer.MAX_VALUE, 0};
        List<int[]> possiblePositions = new ArrayList<>();
        for (int x = 0; x < 11; x++){
            for (int y = 0; y < 11; y++){
                int[] pos = {x,y};
                if (f.isValidPosition(pos)){
                    possiblePositions.add(pos);
                }
            }
        }
        Collections.sort(possiblePositions, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return distance(o1, theCat) - distance(o2, theCat);
            }
        });
        for (int i = 0; i < possiblePositions.size() && System.nanoTime() - startTime < Controller.MAX_TURN_TIME/2; i++){
            int[] pos = possiblePositions.get(i);
            int before = f.field[pos[0]][pos[1]];
            f.placeBucket(pos);
            int[] openness = openness(theCat, f, true);
            if (openness[0] < bestOpenness[0] ||
                    (openness[0] == bestOpenness[0] &&
                            (openness[1] > bestOpenness[1])
                    )
                    ){
                bestOpenness = openness;
                bestMove = pos;
            }
            f.field[pos[0]][pos[1]] = before;
        }
        return bestMove;
    }


    /**
     *
     * @param pos The pos to calculate the openness of.
     * @param f The field to use.
     * @return Two integers. The first integer represents the number of reachable hexagons.
     * The second integer represents how strung out the squares are relative to the pos.
     */
    public static int[] openness(int[] pos, Field f, boolean catZeroWeight){
        Map<int[], Integer> lengths = new HashMap<>();
        PriorityQueue<int[]> open = new PriorityQueue<>(10,new Comparator<int[]>() {
            Map<int[], Integer> lengths;
            @Override
            public int compare(int[] o1, int[] o2) {
                return lengths.get(o1) - lengths.get(o2);
            }
            public Comparator<int[]> init(Map<int[], Integer> lengths){
                this.lengths = lengths;
                return this;
            }
        }.init(lengths));
        Set<int[]> closed = new HashSet<>();
        lengths.put(pos, catZeroWeight ? 0 : 6 - pointsAround(pos, f).size());
        open.add(pos);
        while (open.size() > 0){
            int[] top = open.remove();
            if (closed.contains(top)){
                continue;
            }
            closed.add(top);
            int l = lengths.get(top);
            List<int[]> pointsAround = pointsAround(top, f);

            for (ListIterator<int[]> iter = pointsAround.listIterator(); iter.hasNext();){
                int[] point = iter.next();
                if (closed.contains(point)){
                    iter.remove();
                }
            }

            for (int[] p : pointsAround){
                int length = l + 7 - pointsAround(p, f).size();
                if (lengths.containsKey(p)){
                    length = Math.min(length, lengths.get(p));
                }
                lengths.put(p, length);
                open.add(p);
            }
        }
        int sum = 0;
        for (int integer : lengths.values()){
            sum += integer;
        }
        return new int[]{lengths.size(),sum};
    }

    public static int distance(int[] p1, int[] p2){
        p2 = Arrays.copyOf(p2, 2);
        while (p2[0] < p1[0]){
            p2[0] += 11;
        }
        while (p2[1] < p2[0]){
            p2[1] += 11;
        }
        int lowestDistance = 0;
        for (int dx = 0; dx == 0; dx -= 11){
            for (int dy = 0; dy == 0; dy -= 11){
                lowestDistance = Math.min(lowestDistance,Math.min(Math.abs(p1[0]-p2[0]-dx),Math.min(Math.abs(p1[1]-p2[1]-dy),Math.abs(p1[0]+p1[1]-p2[0]-dx-p2[1]-dy))));
            }
        }
        return Math.min(Math.abs(p1[0]-p2[0]),Math.min(Math.abs(p1[1]-p2[1]),Math.abs(p1[0]+p1[1]-p2[0]-p2[1])));
    }

    public static int[] normalize(int[] p){
        return CACHE[(p[0]%11+11)%11][(p[1]%11+11)%11];
    }

    public static List<int[]> pointsAround(int[] p, Field f){
        int[] cat = f.findCat();
        List<int[]> locations = new ArrayList<>();
        for (int[] move : possibleMoves){
            int[] location = normalize(new int[]{p[0]+move[0], p[1] + move[1]});
            if (f.isValidPosition(location) || Arrays.equals(cat, location)){
                locations.add(location);
            }
        }
        return locations;
    }
}

เขาพยายามจับแมวอย่างไร:

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

การเปิดกว้าง:

การเปิดกว้างของบอร์ดเทียบกับตำแหน่งคือจำนวนตำแหน่งที่เข้าถึงได้จากตำแหน่งนั้น

Stringiness:

ความเข้มงวดของกระดานเทียบกับตำแหน่งคือผลรวมของระยะทางระหว่างตำแหน่งที่สามารถเข้าถึงได้และตำแหน่ง

ด้วยการอัปเดตล่าสุด:

ตอนนี้เขาดีกว่ามากที่จะจับฟรีแคทและแมวของเขาทุกตัวน่าเสียดายที่เขายังจับแมวที่ไม่ร่วมมือได้ เขาสามารถปรับปรุงได้โดยการตรวจสอบว่าแมวเป็นหนึ่งในคนบ้าและทำหน้าที่เป็น CloseCatcher

แก้ไขข้อผิดพลาด


สามารถยืนยันได้ว่ามันใช้งานได้ แต่โดยที่ช้าที่สุด แต่หนึ่งในดีที่สุดที่ฉันคิด ต้องใช้เวลา 134 วินาทีสำหรับเกม 100 เกมกับ RandCat ขณะที่ทำไปทั้งหมด 4406 ครั้ง! ฉันคิดว่าฉันจะต้องปล่อยให้พีซีของฉันทำงานข้ามคืนในอีกหนึ่งวันถัดไป ... คุณช่วยเล่าให้เราฟังหน่อยได้ไหมว่ามันทำงานอย่างไร
ข้อผิดพลาด

@flawr เพิ่มคำอธิบาย
TheNumberOne

ยังไม่ได้ผลสำหรับฉัน ทำให้ฉันมีข้อผิดพลาดหนึ่งข้อ: error: cannot infer type arguments for PriorityQueue<>ในบรรทัดPriorityQueue<int[]> open = new PriorityQueue<>(new Comparator<int[]>() {นี้
Spikatrix

@CoolGuy คุณใช้จาวา 6 หรือไม่? ฉันคิดว่าคุณต้องอัปเดต JDK ของคุณ
TheNumberOne

@CoolGuy นอกจากนี้คุณยังสามารถใส่int[]ระหว่างสองเพชรที่ว่างเปล่าหลังจากPriorityQueueนั้น
TheNumberOne

2

ForwordCatcher

วางถังหน้าแมวหรือถ้าเอาไปวางไว้ข้างหลัง

RabidCat vs ForwordCatcher:

RabidCat vs ForwordCatcher:

package players;

import main.Field;
import java.util.Arrays;

public class ForwordCatcher implements Catcher {
    public String getName() {
        return "ForwordCatcher";
    }

    private int[] lastPos = {0,0};

    public int[] takeTurn(Field f) {
        int[] temp = lastPos;
        int[] pos = f.findCat();
        lastPos = pos;
        int[] Move = {pos[0]*2-temp[0], pos[1]*2-temp[1]};
        if(f.isValidPosition(Move)){return Move;}
        if(f.isValidPosition(temp)){return temp;}
        Move[0] = pos[0];Move[1] = pos[1]+1;
        return Move;
    }
}

1
มีข้อผิดพลาดค่อนข้างน้อยซึ่งทำให้ฉันสันนิษฐานว่าคุณไม่ได้ทดสอบโปรแกรมของคุณ โปรดแก้ไข ...
ข้อผิดพลาด

@flawr คงที่ ขออภัยเกี่ยวกับข้อผิดพลาด ฉันไม่ได้ทดสอบและ Java ของฉันไม่ดี
MegaTom

ที่ดีเพื่อให้ห่างไกลทุกอย่างทำงาน smoothely แต่ฉันยังไม่แน่ใจว่ามันจะผลิตการเคลื่อนไหวที่ถูกต้อง =)
flawr

1
@flawr ช่องว่างด้านหลังแมวมักจะว่างเปล่าสำหรับผู้จับ :)
TheNumberOne

2

ChoiceCatcher

ใช้กลไกการให้คะแนนเช่นเดียวกับรายการ ChoiceCat ของฉัน มีการปรับเปลี่ยนเล็กน้อยซึ่งช่วยในการเลือกเซลล์ที่เกี่ยวข้องในสองสามขั้นตอนแรกเนื่องจาก ChoiceCat ไม่สนใจเกี่ยวกับที่เก็บข้อมูลสองสามอันแรกเนื่องจากไม่เห็นว่าเป็นภัยคุกคาม

ChoiceCatcher ดูเหมือนจะให้คะแนนดีกว่ามือปราบมารปัจจุบัน

ChoiceCat vs ChoiceCatcher:

ChoiceCat vs ChoiceCatcher

package players;
/**
 * @author randomra
 */
import java.util.Arrays;

import main.Field;

public class ChoiceCatcher implements Catcher {

    private class Values {
        public final int size;
        private double[][] f;

        Values(int size) {
            this.size = size;
            f = new double[size][size];
        }

        public double read(int[] p) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j];
        }

        private double write(int[] p, double v) {
            int i = p[0];
            int j = p[1];
            i = (i % size + size) % size;
            j = (j % size + size) % size;
            return f[i][j] = v;
        }
    }

    final int[][] turns = { { -1, 1 }, { 0, 1 }, { 1, 0 }, { 1, -1 },
            { 0, -1 }, { -1, 0 } };// all valid moves CW order
    final int stepCheck = 5;

    public String getName() {
        return "ChoiceCatcher";
    }

    @Override
    public int[] takeTurn(Field f) {
        int[] bestPos = null;
        double bestPosValue = Double.MAX_VALUE;
        for (int i = 0; i < f.SIZE; i++) {
            for (int j = 0; j < f.SIZE; j++) {
                if (f.read(i, j) == Field.EMPTY) {
                    Field myField = new Field(f);
                    myField.placeBucket(new int[] { i, j });
                    double posValue = catTurnValue(myField);
                    if (posValue < bestPosValue) {
                        bestPosValue = posValue;
                        bestPos = new int[] { i, j };
                    }
                }
            }
        }
        return bestPos;
    }

    private double catTurnValue(Field f) {

        int[] pos = f.findCat();
        double[] values = new double[6];
        int count=0;
        for (int[] t : turns) {
            int[] currPos = { pos[0] + t[0], pos[1] + t[1] };
            double moveValue = movePosValue(currPos, f);
            values[count++]=moveValue;
        }
        Arrays.sort(values);
        return values[5];
    }

    private double movePosValue(int[] pos, Field f) {

        Values v = new Values(f.SIZE);

        for (int ring = stepCheck; ring >= 0; ring--) {
            for (int phase = 0; phase < 2; phase++) {
                for (int sidepos = 0; sidepos < Math.max(1, ring); sidepos++) {
                    for (int side = 0; side < 6; side++) {
                        int[] evalPos = new int[2];
                        for (int coord = 0; coord < 2; coord++) {
                            evalPos[coord] = pos[coord] + turns[side][coord]
                                    * sidepos + turns[(side + 1) % 6][coord]
                                    * (ring - sidepos);
                        }
                        if (phase == 0) {
                            if (ring == stepCheck) {
                                // on outmost ring, init value
                                v.write(evalPos, -1);
                            } else {
                                v.write(evalPos, posValue(evalPos, v, f));
                            }
                        } else {
                            // finalize position value for next turn
                            v.write(evalPos, -v.read(evalPos));
                        }
                    }
                }
            }
        }

        return -v.read(pos);
    }

    private double posValue(int[] pos, Values v, Field f) {
        if (f.read(pos[0], pos[1]) == Field.BUCKET) {
            return 0;
        }
        int count = 0;
        int maxRoutes = 2;
        double[] product = new double[6];
        for (int[] t : turns) {
            int[] tPos = new int[] { pos[0] + t[0], pos[1] + t[1] };
            if (v.read(tPos) > 0) {
                product[count] = 1 - 1 / (v.read(tPos) + 1);
                count++;
            }
        }
        Arrays.sort(product);
        double fp = 1;
        for (int i = 0; i < Math.min(count, maxRoutes); i++) {
            fp *= product[5 - i];
        }
        double fp2 = 1;
        for (int i = 0; i < Math.min(count, 6); i++) {
            fp2 *= product[5 - i];
        }
        double retValue = Math.min(count, maxRoutes) + fp;
        double retValue2 = Math.min(count, 6) + fp2;
        return -retValue - retValue2 / 1000000;
    }

}

1

RandCatcher

สิ่งนี้ถูกสร้างขึ้นมาเพื่อทดสอบตัวควบคุมและสุ่มวางถัง (ไม่มีประสิทธิภาพมาก)

package players;

import main.Field;

public class RandCatcher implements Catcher {
    public String getName(){
        return "RandCatcher";
    }
    public int[] takeTurn(Field f){
        int[] pos = {0,0};
        do {
            pos[0] = (int) (Math.random()*f.SIZE);
            pos[1] = (int) (Math.random()*f.SIZE);
        } while( f.isValidPosition(pos)==false );
        return pos;
    }

}

1

StupidFillCatcher

นี่เป็นเพียงการทดสอบคอนโทรลเลอร์ มันแค่เติมคอลัมน์ทีละคอลัมน์จนกว่าจะจับแมว

package players;

import main.Field;

public class StupidFillCatcher implements Catcher {
    public String getName(){
        return "StupidFillCatcher";
    }
    public int[] takeTurn(Field f){
        for(int i=0; i < f.SIZE; i++){
            for(int j=0; j < f.SIZE; j++){
                if(f.isValidPosition(new int[] {i,j})){
                    return new int[] {i,j};
                }
            }
        }
        return new int[] {0,0};
    }

}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.