생존 게임-늑대 만들기


238

보드

보드 셀의 2 개 차원 어레이이다. 세포는 동물에 의해 채워집니다 . 매일 칠판에있는 모든 동물이 동시에 한 번 움직입니다. 둘 이상의 동물이 같은 세포로 이동하면 하나가 남아있을 때까지 싸 웁니다. 가능한 움직임과 공격은 다음과 같습니다.

  • 이동 - { Move.UP, Move.RIGHT, Move.DOWN, Move.LEFT, Move.HOLD}
  • 공격 - { Attack.ROCK, Attack.PAPER, Attack.SCISSORS, Attack.SUICIDE}

가위 바위 보로 동물들이 싸우고 있습니다. 표준 규칙이 적용되지만 두 가지 수정 사항이 있습니다. 먼저 언제든지 자살 할 수 있습니다. 둘째, 넥타이는 의사 난수로 부러진다. 둘 이상의 동물이 충돌하는 경우, 둘 중 하나가 남아있을 때까지 싸울 의사가 무작위로 선택됩니다.

선수들

동물의 행동과 모습은 다음과 같습니다.

  • 사자
    • 문자로 표시 L됩니다. 이동 DOWN, RIGHT다음 반복합니다. PAPER또는을 사용 하여 의사 무작위로 공격 SCISSORS합니다.
    • 문자로 표시 B됩니다. 이동 DOWN× 4, RIGHT× 4, UP× 4, LEFT× 4, 다음 반복합니다. 로 공격합니다 PAPER.
    • 문자로 표시 S됩니다. 이동 HOLD합니다. 로 공격합니다 ROCK.
  • 늑대
    • 답변으로 제출 된 늑대 만 포함됩니다. 'W'로 표시됩니다. 모든 움직임으로 이동합니다. 모든 공격으로 공격

다음 템플릿의 빈칸을 채워 Wolf를 구현합니다. 모든 제출물은 Java로 작성되어야하며 단일 파일에 포함되어야합니다. 또는 @ProgrammerDan은 경쟁을 Java 이외의 제출로 확장 하는 래퍼 클래스 를 작성했습니다 .

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); /* Optional code here */ }
    public Attack fight(char opponent) { /* Required code here. Must return an Attack. */ }
    public Move move() { /* Required code here. Must return a Move. */ }
    // Optional code here
}

1,000 번의 반복으로 5 번의 시험을 거친 후 가장 많은 수의 살아있는 늑대를 가진 작품이 승리합니다. 새 답변이 게시 될 때마다 (최초 24 시간 내에는 안 됨) 승자를 업데이트합니다.

도구

  • 다음과 같은 형태로 주변 환경에 대한 작은지도가 제공됩니다.
    • char[][] surroundings근처의 동물을 나타내는 인덱스가없는 3 x 3 매트릭스. 빈 타일은 공백 문자 ( '')로 표시됩니다. 에 surroundings[1][1]있습니다. 예를 들어, 귀하의 권리는 surroundings[1][2]이며, 그 위는 surroundings[0][1]입니다. 당신의 주변 환경은 이동 요청을 받기 직전에 업데이트되지만, 전투 요청을했을 때 구식이 아닐 수도 있습니다.
  • Wolf 호출, 이동 요청 및 공격 요청간에 데이터를 유지할 수 있습니다. 다른 Wolf 클래스가 작성한 파일을 읽거나 수정할 수 없습니다.
  • 다음과 같은 형식으로지도 크기가 제공됩니다
    • int MAP_SIZE

가정

  • 모든 제출물은 라이온, 곰 및 돌뿐만 아니라 다른 모든 제출물과 동일한 보드에서 경쟁합니다.
  • 이 보드는 길이의 측면과 함께 정사각형 제출의 수입니다. 모든면이 랩핑되어 어떤 방향 으로든 안전하게 움직일 수 있습니다.sqrt(n+3)*20n
  • 시뮬레이션은 보드 용량에 ~ 25 %의 보드 용량으로 시작됩니다.
  • 이동 요청시 동물이 예외를 던지면 해당 동물은 HOLD
  • 싸우라는 요청을 받았을 때 동물이 예외를 던지면 그 동물은 SUICIDE
  • 컨트롤러가 점검 할 때 동물에게 문자가 없으면 해당 동물은 즉시 죽습니다.

시작 및 테스트 지침

제출을 테스트하는 데 필요한 도구는 여기 에서 찾을 수 있습니다 . 해당 링크에서 다음 파일을 사용할 수 있어야합니다.

  • ExampleRun.gif- 실행중인 프로그램의 5-10 초 gif입니다.
  • 스코어 보드 -경쟁의 최신 결과.
  • Wild.jar-미리 만들어진 동물들이 돌아 다니는 것을 관찰하기 위해 실행할 수있는 실행 파일입니다.
  • Wild.zip-사전 제작 된 동물 몇 개가 추가 된 컨트롤러 프로그램이 들어있는 NetBeans 프로젝트. 이것을 사용하여 제출물을 개발하십시오.
  • WildPopulated.zip- 위와 동일하지만 테스트를 위해 약 40 개의 제출물이 추가되었습니다. 성능 문제로 인해 GUI도 제거되었습니다. 결과는 실행 후 몇 분 후에 나타납니다. Java 이외의 제출물은 추가 다운로드와 노력이 필요하므로 주석 처리됩니다. 이를 사용하여 필드에 대한 제출을 테스트하십시오.
  • Wolf.txt -Java에서 Wolf 클래스의 순진한 구현. 저에게 크레딧을주지 않고 해당 구현을 사용하고 확장 할 수 있습니다.

수업을 테스트하려면 :

  • Wild.zip 다운로드
  • Wolf.java 및 Wolf 클래스의 이름을 고유 한 이름으로 변경하십시오.
  • UniquelyNamedWolf.java 파일을 Wild \ src \ animals \에 추가하십시오.
  • Wild 클래스에서 다음 classes과 같이 클래스를 배열에 추가하십시오 .
    • Class[] classes = { UniquelyNamedWolf.class, Bear.class, Lion.class, Stone.class, Wolf.class };
  • 재 구축 및 실행

또한 테스트 목적으로 모든 제출물을 포함하는 다른 프로젝트도 포함 시켰습니다. 창의적으로 이름을 "WildPopulated"로 지정했습니다. 3 개 또는 4 개의 비 Java 늑대는 주석 처리되었습니다. 실행하려면 많은 추가 작업과 다운로드가 필요하기 때문입니다. 내가 게시 한 하나와 함께 실행해야 제로 추가 작업. 속도 향상을 위해 GUI도 주석 처리되었습니다.

2014 년 4 월 22 일

스코어 보드가 Google 드라이브로 이동되었습니다. 여기를보십시오. 새로운 제출물이 들어 오면 우연히 업데이트됩니다 (예 : 도착했을 때).

사이드 챌린지-NoHOLD

참여가 없기 때문에 제거되었습니다. 어쨌든 그것은 원래 도전의 일부가 아니었다.


5
@Rusher 끔찍하게 들린다. 래퍼가 포함 된 답변을 커뮤니티 위키에 넣을 수 있습니다. 컴파일러 / 통역사 문제에 관해서는 사용법에 대한 명확한 지침을 제공하는 것이 제출자에게 달려 있다고 생각합니다. 불분명하거나 너무 복잡한 지침이 제출을 거부 할 수 있다면 :)
ProgrammerDan

4
"* 다음과 같은 형식으로지도 크기가 제공됩니다. int MAP_SIZE"사용 방법을 알아내는 데 문제가 있습니다. Netbeans는 MAP_SIZE프로젝트의 파일에 문자열 인스턴스가 없다고 말합니다 .
undergroundmonorail

6
나무가 종이를 보여주는 것은 어떻습니까?
Mukul Kumar

3
@Rusher, 일부 사람들은 이미이 작업을 수행하고 있다고 생각하지만 정적 멤버 (자체 품종 내)를 통해 늑대 간 통신이 허용됩니까?
Martin Ender

10
@ m.buettner 허용됨. 벌집 늑대를 만드세요.
Rainbolt

답변:


47

헤르 잔 울프

15:00에 10-4-2014 업데이트

평균 100 라운드, 1000 회 반복 :

표준 몹 :

class animals.Bear - 2.2600002
class animals.Lion - 41.21
class animals.Stone - 20.159998
class animals.HerjanWolf - 99.99 <-- kind of flawless

20 종 이상 (늑대 점수가 최고가 될 때까지 평균을 계속 계산하기 때문에이 점수를 염두에 두지 마십시오!)

class animals.Bear - 0.1
class animals.Lion - 0.0
class animals.Stone - 1.5
class animals.AlphaWolf - 75.5
class animals.HerjanWolf - 86.4 <-- #1
class animals.GatheringWolf - 39.5
class animals.OmegaWolf - 85.4 <-- #2
class animals.ShadowWolf - 71.1
class animals.MOSHPITFRENZYWolf - 8.8
class animals.WolfWithoutFear - 11.5
class animals.MimicWolf - 0.5
class animals.LazyWolf - 52.8
class animals.Sheep - 38.3
class animals.HonorWolf - 80.7
class animals.CamperWolf - 52.8
class animals.GamblerWolf - 14.7
class animals.WolfRunningWithScissors - 0.0
class animals.LionHunterWolf - 27.6
class animals.StoneEatingWolf - 70.8
class animals.Wion - 0.1
class animals.ProAlpha - 79.3
class animals.HybridWolf - 83.2

내 늑대 :

package animals;

public class HerjanWolf extends Animal {

    private boolean lionTopLeft = false, lionTopLeftReady = false;
    private boolean lionRight = false, lionRightReady = false;
    private boolean lionBot = false, lionBotReady = false;
    private boolean lionDanger = false, careful = true, firstmove = true;
    private final int hold = 0, down = 1, right = 2, left = 3, up = 4;

    public HerjanWolf() {
        super('W');
    }

    public Attack fight(char c){
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                int rand = (int) (Math.random()*3);
                if(rand < 1)
                    return Attack.PAPER;
                else if(rand < 2)
                    return Attack.SCISSORS;
                else
                    return Attack.ROCK;
        } 

    }
    public Move move() { //surroundings[y][x]

        checkLions();

        if(firstmove){
            if(surroundings[2][0] == 'L')
                lionBotReady = true;
            if(surroundings[0][2] == 'L')
                lionRightReady = true;
            firstmove = false;
        }

        int[] dang = new int[4]; // 0 is left side, 1 is top side, 2 is right side, 3 is down side

        for(int y = 0; y < 3; y++){
            for(int x = 0; x < 3; x++){
                if(surroundings[y][x] == 'W'){
                    if(y == 0){
                        dang[1]++;
                        if(x == 1)
                            dang[1]+=2;
                    }if(y == 2){
                        dang[3]++;
                        if(x == 1)
                            dang[3]+=2;
                    }if(x == 0){
                        dang[0]++;
                        if(y == 1)
                            dang[0]+=2;
                    }if(x == 2){
                        dang[2]++;
                        if(y == 1)
                            dang[2]+=2;
                    }
                }
            }
        }

        int maxIndex = 0, minIndex = 0, minIndex2 = 0;
        for(int i = 1; i < dang.length; i++){
            if(dang[i] > dang[maxIndex])
                maxIndex = i;
            if(dang[i] <= dang[minIndex]){
                minIndex2 = minIndex;
                minIndex = i;
            }
        }

        if(lionDanger || surroundings[1][0] == 'L' && lionTopLeftReady || surroundings[0][1] == 'L' && lionTopLeftReady || dang[maxIndex] >= 3){

            switch(minIndex){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            switch(minIndex2){
            case 0:
                if (isSafe(1, 0)){
                    newMove(left);
                    return Move.LEFT;
                }
            case 1:
                if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }
            case 2:
                if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }

            case 3:
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                } 
            }

            if(dang[maxIndex]<3){ //if that was not the reason its really obligated (because of lions)
                if (isSafe(2, 1)){
                    newMove(down);
                    return Move.DOWN;
                }else if(isSafe(1,2)){
                    newMove(right);
                    return Move.RIGHT;
                }else if (isSafe(0, 1)){
                    newMove(up);
                    return Move.UP;
                }else{
                    newMove(left);
                    return Move.LEFT;
                }
            }
        }

        return Move.HOLD;
    }

    boolean isSafe(int y, int x){
        if(y <= 1){
            if(x <= 1){
                if(surroundings[y][x] != 'W' && !lionTopLeft)
                    return true;
            }else if(surroundings[1][2] != 'W' && !lionRightReady)
                    return true;
        }else if(surroundings[2][1] != 'W' && !lionBotReady)
            return true;

        return false;
    }

    public void checkLions(){
        int y = 0, x = 0;

        if(lionTopLeft)
            lionTopLeftReady = true;
        else
            lionTopLeftReady = false;

        if(surroundings[y][x] == 'L')
            lionTopLeft = true;
        else
            lionTopLeft = false;

        if(lionRight)
            lionRightReady = true;
        else
            lionRightReady = false;

        if(surroundings[y][x+1] == 'L') // && !lionTopLeftReady
            lionRight = true;
        else
            lionRight = false;

        if(lionBot)
            lionBotReady = true;
        else
            lionBotReady = false;

        if(surroundings[y+1][x] == 'L' && !lionTopLeftReady)
            lionBot = true;
        else
            lionBot = false;

        if(careful){
            if(surroundings[y+1][x] == 'L'){
                lionDanger = true;
            }else if(surroundings[y][x+1] == 'L'){
                lionDanger = true;
            }

            careful = false;
        }
    }

    public void newMove(int move){
        lionTopLeft = false;
        lionRight = false;
        lionBot = false;

        lionTopLeftReady = false;
        lionRightReady = false;
        lionBotReady = false;

        lionDanger = false;

        if(move == down){
            if(surroundings[1][0] == 'L')
                lionTopLeft = true;
            if(surroundings[2][0] == 'L')
                lionBot = true;

        }else if(move == right){
            if(surroundings[0][1] == 'L')
                lionTopLeft = true;
            if(surroundings[0][2] == 'L')
                lionRight = true;

        }else
            careful = true;
    }
}

테스트 실행에 "최상의"늑대 만 포함하면 일반적으로 숫자가 왜곡됩니다. 필드에 30 종 이상이 있으면 숫자가 크게 바뀔 수 있습니다. 아직 테스트하지 않았다면 테스트하는 것이 좋습니다.
Geobits

1
@ user20220 이론적으로는 (그리고 실제로는 늑대가 적은) 꽤 좋습니다.
user3188175

1
이 늑대는 최고의 안티- 라이언
Justin

2
@ user20220 Wolf-collision은 훨씬 더 자주 발생하므로이를 처리하는 다른 늑대를 추가해야합니다. 이 늑대의 작동 방식을 설명해 주시겠습니까?
저스틴

3
@justhalf 좋아요, 더 좋지는 않습니다. 그때만큼 좋습니다. 늑대는 모든 사자를 피하고 늑대를 피하기 전에 먼저 늑대를 100 % 사자로 만들었습니다. 차이점은 늑대가 사자를 피하려고한다는 것입니다 (이동이 적을수록 좋습니다). 그래서 그것은 사자처럼 100 % 사자를 피하는 사자 피를하는 데 능숙합니다. 그러나 늑대가 사자를 피하려고 시도하고 지루하게 사자처럼 움직이지 않기 때문에 여전히 늑대 피지를 만들 수 있습니다. 더 복잡한.
Herjan

153

이모 울프

EmoWolf는 Java를 싫어하고 참여하는 것보다 스스로를 죽일 것입니다. EmoWolf는 굶주 렸지만 여전히 177 바이트입니다.

package animals;public class EmoWolf extends Animal{public EmoWolf(){super('W');}public Attack fight(char opponent){return Attack.SUICIDE;}public Move move(){return Move.HOLD;}}

34
lol 몇 바이트를 줄일 수 있습니다. " 컨트롤러가 확인할 때 동물에 문자가 없으면 해당 동물은 즉시 죽습니다 ".
Geobits

112
이것에 대한 가장 좋은 점은 지속적 으로 최악이 아니라는 것 입니다. 그것은 보통 적어도 2-3 명을 이깁니다.
Geobits

51
"유일한 승리의 움직임은 플레이하지 않는 것입니다."
tadman

38
+1 작고 자살하고 여전히 4 마리의 다른 늑대를 때리고 있습니다.
puggsoy

25
제안 해 주셔서 감사합니다. 이것이 골프라면 게시물을 편집 할 필요가 있습니다. 그것이 서있는대로, 나는 EmoWolf를 찌를 것이다. 혼자.
boothby

52

게으른 늑대

적절하게 지명 된이 사람은 최소한의 생존을합니다. 늑대가 아닌 유일한 위협은 사자이므로 그 중 하나가 그를 밟으려고 할 때 그는 움직일 것입니다. 그 외에는 잠을 자고 있습니다.

50/50보다 나은 늑대에 대해 할 수있는 일은 많지 않기 때문에 아무 것도하지 않습니다. 늑대가 그를 공격하면 골고루 분산 된 방식으로 공격을 선택합니다.

그게 다야. 나는 단순함에도 불구하고 꽤 잘 될 것으로 기대합니다.

package animals;    
public class LazyWolf extends Animal{    
    static int last = 0;
    static final Attack[] attacks = Attack.values();

    public LazyWolf() {super('W');}

    @Override
    public Attack fight(char other) {
        switch(other){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK; // faker!
        default:
            return attacks[last++%3];
        }
    }

    @Override
    public Move move() {
        if(surroundings[0][1] == 'L')
            return Move.LEFT;
        if(surroundings[1][0] == 'L')
            return Move.UP;
        return Move.HOLD;
    }

}

최신 정보:

CamoWolf 가 나를 꺾고있었습니다. 내 늑대는 너무 게으 르기 때문에 보통 진짜 돌에 빠지지 않을 것 입니다. 따라서 돌이 공격하면 분명히 가짜이며 얼굴에 던져진 바위가 필요합니다.


지금 당신은 당신이 하나를 피하려고 할 때 두 번째 사자로 이동할 수 있습니다. 당신은 얼마나 많은 움직임이 있었는지 추적함으로써 이것을 제거 할 수 있습니다. 그렇다면 사자와 같은 방향으로 움직이십시오. 사자도 같은 방향으로 움직이기 때문에 당신에게 갈 수 없습니다.
ughoavgfhw

13
나는 두 마리의 사자 상황에 대해 생각했지만 늑대가 돌보는 것이 너무 게으르다 고 결정했습니다. 잘 채워진 보드로 자주 발생하는 확률은 어쨌든 매우 슬림합니다.
Geobits

1
왜이 늑대가 진짜 돌에 빠지지 않는다고 생각합니까? 나는 그것이 사자에게서 도망 갈 때마다 일어날 수 있다고 생각합니다.
Christopher Creutzig

6
@ChristopherCreutzig 사자 가 있던 곳으로 이동하여 사자에서 실행됩니다 . 사자 그곳에 있었다면 지금 돌이 없을 수 있습니다 .
Geobits

1
가능하더라도 "무한 루프"는 없습니다. 공격이 동점 일 경우, 사양에 따라 하나 또는 다른 주사위가 죽습니다 (동전 던지기로 뽑습니다).
Geobits

51

비 Java 제출을위한 랩퍼

참고 MAP_SIZE 지원이 추가되었습니다. 당신이 관심이 있다면, 그에 따라 제출을 업데이트하십시오.

이것은 랩퍼를위한 커뮤니티 위키 항목으로, 게임을하고 싶지만 Java를 모르거나 알지 못하는 사람들이 사용할 수 있습니다. 사용 하시고 재미있게 보내 주시고 기꺼이 도와 드리겠습니다.

마무리 할 때 여기에 늦었습니다. 다른 Java 코더는 이것을 살펴보고 개선을 제안하십시오. 가능하면 문제를 제기하거나 패치를 제출하여 github 리포지토리를 통해 수행하십시오. 감사!

이 전체가 UNLICENSE와 함께 배포되고 있으므로 github 저장소에서 추적 하십시오 . 문제가 발견되면 패치를 제출하고이 게시물을 업데이트하겠습니다.

사용중인 래퍼의 현재 예

plannapus : R의 WolfCollectiveMemory

user3188175 : SmartWolf의C#

칫솔 : ECMAScript의 칫솔

사용하는 방법

다음은 원격 늑대에 대해 정의한 PIPES를 통한 프로세스 간 통신 프로토콜에 대한 지침입니다. 참고 OP의 문제 설명에 존재하지만 존재하지 않는 것처럼 MAP_SIZE를 건너 뛰었습니다. 표시되면이 게시물을 업데이트하겠습니다.

중요 사항 :

  • 외부 프로세스를 한 번만 호출 할 수 있습니다 (따라서 처리 논리를 무한 루프로 랩핑하십시오. 또한 디스크를 사용하는 대신 처리를 인 메모리로 유지할 수 있습니다).
  • 모든 통신은 STDIN 및 STDOUT을 통한이 단일 외부 프로세스와의 통신
  • STDOUT으로 전송 된 모든 출력을 명시 적으로 플러시하고 줄 바꿈으로 끝나야합니다.

사양

원격 스크립트는 STDIN 및 STDOUT 후크를 통한 간단한 프로토콜에 의해 지원되며 초기화, 이동 및 공격으로 나뉩니다. 각 경우에 귀하의 프로세스와의 통신은 STDIN을 통해 이루어지며 STDOUT으로부터 회신이 필요합니다. 1 초 안에 회신을받지 못하면 프로세스가 종료 된 것으로 간주되어 예외가 발생합니다. 일관성을 유지하기 위해 모든 문자는 UTF-8로 인코딩됩니다. 모든 입력은 줄 바꿈 문자로 종료되며 프로세스는 모든 출력 응답을 줄 바꿈으로 종료해야합니다. 경고 Java 랩퍼가 출력을 볼 수 있도록 매 쓰기 후에 출력 버퍼를 플러시하십시오. 세척하지 않으면 원격 Wolf가 고장날 수 있습니다.

하나의 프로세스 만 작성되며 모든 Wolves는 해당 프로세스 하나에서 관리해야합니다. 이 사양이 어떻게 도움이 될지 계속 읽으십시오.

초기화

STDIN : S<id><mapsize> \ n

STDOUT : K<id> \ n

<id>: 00 또는 01또는 ... 또는99

설명:

문자는 S두 숫자 뒤에 전송 될 00, 01..., 99초기화되고있는 100 늑대 나타낸다. 미래의 특정 늑대와의 모든 의사 소통에서 동일 <id>하게 사용될 것입니다.

ID 다음에 가변 길이의 숫자 문자가 전송됩니다. 이것은지도의 크기입니다. 줄 바꿈 ( \n)에 도달하면 일련의 숫자가 끝났음을 알 수 있습니다 .

당신의 프로세스가 살아 있도록하려면, 당신 이받은 K것과 같은 문자로 답장해야합니다 <id>. 다른 답변은 예외를 초래하여 늑대를 죽입니다.

운동

STDIN : M<id><C0><C1>...<C7><C8> \ n

STDOUT : <mv><id> \ n

<Cn>: W 또는 또는 B또는 S또는L

W: 늑대

: 빈 공간

B:

S: 스톤

L: 사자

<mv>: H 또는 U또는 L또는 R또는D

H: Move.HOLD

U: 이동

L: 이동 . 왼쪽

R: 이동

D: 아래로 이동

설명:

어떤 늑대가 이동을 선택해야하는지 표시하기 위해 문자 M가 전송되고 두 문자가 전송됩니다 <id>. 그런 다음 Wolf의 주변 환경을 나타내는 9 개의 문자가 행 순서 (맨 위 행, 가운데 행, 맨 아래 행에서 맨 오른쪽 행)로 전송됩니다.

유효한 이동 문자 중 하나를 입력 한 <mv>다음 <id>확인을 위해 Wolf의 두 자리 숫자 로 답장하십시오 .

공격

STDIN : A<id><C> \ n

STDOUT : <atk><id> \ n

<C>: W 또는 B또는 S또는L

<atk>: R 또는 P또는 S또는D

R: 공격 .

P: Attack.PAPER

S: 공격 . 가위

D: 공격 . SUICIDE

설명:

어떤 늑대가 공격에 참여하고 있는지 표시하기 위해 문자 A가 전송되고 두 문자가 전송됩니다 <id>. 그 다음에 <C>는 공격 할 물건의 종류 ( W올프, B귀, S톤 또는 L이온)를 나타내는 단일 문자가옵니다 .

<atk>위에 나열된 문자 중 하나로 응답하여 <id>확인 에 대한 두 자리 숫자 로 공격에 대한 응답을 나타냅니다 .

그리고 그게 다야. 더 이상 없습니다. 만약 당신이 공격을 잃어 버리면, 그것은 <id>다시 당신의 프로세스로 보내지지 않을 것입니다. 그것이 당신의 울프가 죽었다는 것을 알게 될 것 <id>입니다.

결론

단 하나의 "프로세스"만 원격 늑대로 구성되므로 생성 된 모든 늑대의 늑대는 예외로 인해 원격 늑대의 모든 늑대가 죽습니다.

이 저장소에는 Wolf.java파일이 있습니다. 다음 문자열을 검색하여 바꾸어 봇을 설정하십시오.

  • 교체 <invocation>제대로 프로세스를 실행 명령 행 인수.

  • 교체 <custom-name>하여 늑대의 고유 한 이름으로.

  • 예를 들어 저장소 보면 내가 가지고있는 경우, WolfRandomPython.java그 내 예를 들어 원격의 호출 PythonWolf.py(파이썬 3 + 늑대).

  • 파일 이름을로 바꾸십시오. Wolf<custom-name>.java여기서 <custom-name>선택한 이름으로 바뀝니다.

Wolf를 테스트하려면 Java 프로그램 ( javac Wolf<custom-name>.java)을 컴파일하고 Rusher의 지시 사항에 따라이를 시뮬레이션 프로그램에 포함 시키십시오.

중요 사항 : 위에서 설명한 체계를 따르는 실제 Wolf를 컴파일 / 실행하는 방법에 대한 명확 하고 간결한 지시 사항 을 제공하십시오 .

행운을 빕니다.

래퍼 코드

이 작업을 수행하려면 대략적으로 검색하고 대치해야합니다. 당신의 호출이 특히 털이 많은 경우, 저에게 연락하여 도움을 요청하십시오.

main이 랩퍼에는 로컬 상자에서 기본적인 "통과 / 실패"테스트를 수행 할 수 있는 방법이 있습니다. 이렇게하려면 프로젝트에서 Animal.java 클래스를 다운로드하고 package animals;두 파일 에서 줄을 제거하십시오 . Animal.java의 MAP_SIZE 줄을 100과 같은 상수로 바꿉니다. javac Wolf<custom-name>.java를 통해 실행을 사용하여 컴파일하십시오 java Wolf<custom-name>.

package animals;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Remote Wolf<custom-name> wrapper class. 
 */
public class Wolf<custom-name> extends Animal {
    /**
     * Simple test script that sends some typical commands to the
     * remote process.
     */
    public static void main(String[]args){
        Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
        for(int i=0; i<10; i++) {
            wolves[i] = new Wolf<custom-name>();
        }
        char map[][] = new char[3][3];
        for (int i=0;i<9;i++)
            map[i/3][i%3]=' ';
        map[1][1] = 'W';
        for(int i=0; i<10; i++) {
            wolves[i].surroundings=map;
            System.out.println(wolves[i].move());
        }
        for(int i=0; i<10; i++) {
            System.out.println(wolves[i].fight('S'));
            System.out.println(wolves[i].fight('B'));
            System.out.println(wolves[i].fight('L'));
            System.out.println(wolves[i].fight('W'));
        }
        wolfProcess.endProcess();
    }
    private static WolfProcess wolfProcess = null;

    private static Wolf<custom-name>[] wolves = new Wolf<custom-name>[100];
    private static int nWolves = 0;

    private boolean isDead;
    private int id;

    /**
     * Sets up a remote process wolf. Note the static components. Only
     * a single process is generated for all Wolves of this type, new
     * wolves are "initialized" within the remote process, which is
     * maintained alongside the primary process.
     * Note this implementation makes heavy use of threads.
     */
    public Wolf<custom-name>() {
        super('W');
        if (Wolf<custom-name>.wolfProcess == null) {
            Wolf<custom-name>.wolfProcess = new WolfProcess();
            Wolf<custom-name>.wolfProcess.start();
        }

        if (Wolf<custom-name>.wolfProcess.initWolf(Wolf<custom-name>.nWolves, MAP_SIZE)) {
            this.id = Wolf<custom-name>.nWolves;
            this.isDead = false;
            Wolf<custom-name>.wolves[id] = this;
        } else {
            Wolf<custom-name>.wolfProcess.endProcess();
            this.isDead = true;
        }
        Wolf<custom-name>.nWolves++;
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
     * Otherwise, communicate an attack to the remote process and return
     * its attack choice.
     */
    @Override
    public Attack fight(char opponent) {
        if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
            return Attack.SUICIDE;
        }
        try {
            Attack atk = Wolf<custom-name>.wolfProcess.fight(id, opponent);

            if (atk == Attack.SUICIDE) {
                this.isDead = true;
            }

            return atk;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Attack.SUICIDE;
        }
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, HOLD.
     * Otherwise, get a move from the remote process and return that.
     */
    @Override
    public Move move() {
        if (!Wolf<custom-name>.wolfProcess.getRunning() || isDead) {
            return Move.HOLD;
        }
        try {
            Move mv = Wolf<custom-name>.wolfProcess.move(id, surroundings);

            return mv;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Move.HOLD;
        }
    }

    /**
     * The shared static process manager, that synchronizes all communication
     * with the remote process.
     */
    static class WolfProcess extends Thread {
        private Process process;
        private BufferedReader reader;
        private PrintWriter writer;
        private ExecutorService executor;
        private boolean running;

        public boolean getRunning() {
            return running;
        }

        public WolfProcess() {
            process = null;
            reader = null;
            writer = null;
            running = true;
            executor = Executors.newFixedThreadPool(1);
        }

        public void endProcess() {
            running = false;
        }

        /**
         * WolfProcess thread body. Keeps the remote connection alive.
         */
        public void run() {
            try {
                System.out.println("Starting Wolf<custom-name> remote process");
                ProcessBuilder pb = new ProcessBuilder("<invocation>".split(" "));
                pb.redirectErrorStream(true);
                process = pb.start();
                System.out.println("Wolf<custom-name> process begun");
                // STDOUT of the process.
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 
                System.out.println("Wolf<custom-name> reader stream grabbed");
                // STDIN of the process.
                writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
                System.out.println("Wolf<custom-name> writer stream grabbed");
                while(running){
                    this.sleep(0);
                }
                reader.close();
                writer.close();
                process.destroy(); // kill it with fire.
                executor.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("Wolf<custom-name> ended catastrophically.");
            }
        }

        /**
         * Helper that invokes a read with a timeout
         */
        private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
            Callable<String> readTask = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return reader.readLine();
                }
            };

            Future<String> future = executor.submit(readTask);
            return future.get(timeout, TimeUnit.MILLISECONDS);
        }

        /**
         * Sends an initialization command to the remote process
         */
        public synchronized boolean initWolf(int wolf, int map_sz) {
            while(writer == null){
                try {
                this.sleep(0);
                }catch(Exception e){}
            }
            boolean success = false;
            try{
                writer.printf("S%02d%d\n", wolf, map_sz);
                writer.flush();
                String reply = getReply(5000l);
                if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        success = true;
                    }
                }
                if (reply == null) {
                    System.out.println("did not get reply");
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to initialize, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to initialize, %s\n", wolf, e.getMessage());
            }
            return success;
        }

        /**
         * Send an ATTACK command to the remote process.
         */
        public synchronized Attack fight(int wolf, char opponent) {
            Attack atk = Attack.SUICIDE;
            try{
                writer.printf("A%02d%c\n", wolf, opponent);
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'R':
                                atk = Attack.ROCK;
                                break;
                            case 'P':
                                atk = Attack.PAPER;
                                break;
                            case 'S':
                                atk = Attack.SCISSORS;
                                break;
                            case 'D':
                                atk = Attack.SUICIDE;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to attack, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to attack, %s\n", wolf, e.getMessage());
            }
            return atk;
        }

        /**
         * Send a MOVE command to the remote process.
         */
        public synchronized Move move(int wolf, char[][] map) {
            Move move = Move.HOLD;
            try{
                writer.printf("M%02d", wolf);
                for (int row=0; row<map.length; row++) {
                    for (int col=0; col<map[row].length; col++) {
                        writer.printf("%c", map[row][col]);
                    }
                }
                writer.print("\n");
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'H':
                                move = Move.HOLD;
                                break;
                            case 'U':
                                move = Move.UP;
                                break;
                            case 'L':
                                move = Move.LEFT;
                                break;
                            case 'R':
                                move = Move.RIGHT;
                                break;
                            case 'D':
                                move = Move.DOWN;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to move, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("Wolf<custom-name> %d failed to move, %s\n", wolf, e.getMessage());
            }
            return move;
        }
    }
}

1
나는이 포스트에서 찢어졌다. 답은 아니지만 도전에 매우 유용합니다. 그래도 도전 단체에 들어가야합니다.
Mego

거기 또는 여기에서, 사람들이 그것을 찾을 수 있고 그들에게 유용하다면, 나는
ProgrammerDan

46

카모 울프

필요한 코드 형식을 남용합니다.

// Optional code here
public class Wolf extends Animal {
    // Optional code here
    public Wolf() { super('W'); // Optional code here }
    public Attack fight(char opponent) { // Required code here. Must return an Attack. }
    public Move move() { // Required code here. Must return a Move. }
    // Optional code here
}

그래서 내 늑대는 정말 똑똑하고 대신 돌로 위장합니다! 환경과 혼합하는 것은 항상 좋은 생존 전술입니다!

public class Wolf extends Animal {
    private Move lastMove;
    public Wolf() { super('S'); lastMove = Move.RIGHT; } /*
    public Wolf() { super('W'); }
    public Attack fight(char opponent) { */ public Attack fight(char opponent) {
        switch(opponent) {
        case 'B': return Attack.SCISSORS;
        case 'S': return Attack.PAPER;
        case 'W': return Attack.SCISSORS; // Here's an explanation why:
                                          // the wolves will see me and think I'm a rock.
                                          // Therefore, they'll attack with paper.
                                          // So, I'll use scissors instead!
        case 'L': return Attack.SCISSORS;
        }
    }
    public Move move() {
        // First we run away from any lions that we see, since they are the only threat
        if (surroundings[0][1] == 'L') {
            if (isSafe(surroundings[2][1])) return lastMove = Move.DOWN;
            else if (isSafe(surroundings[1][0])) return lastMove = Move.LEFT;
            else return lastMove = Move.RIGHT;
        }
        if (surroundings[1][0] == 'L') {
            if (isSafe(surroundings[1][2])) return lastMove = Move.RIGHT;
            else if (isSafe(surroundings[0][1])) return lastMove = Move.UP;
            else return lastMove = Move.DOWN;
        }

        // If there's no (threatening) lions in sight, be lazy.
        return lastMove = Move.HOLD;
    }
    private boolean isSafe(char c) { return (c != 'L' && c != 'W') }
}

업데이트 : isSafeLazyWolf에서도 안전하도록 새로운 검사가 추가되었습니다 ! 하아!
업데이트 2 : 게으르다는 것도 좋은 생존 전술이므로 내 것이 지금하는 것입니다. 사자의 위협을받지 않는 한 움직이지 않습니다. lastMove더 이상 필요하지 않지만 코드를 다시 변경하기 위해 어쨌든 유지했습니다.


29
프로젝트에 제출물을 추가했을 때 실수로 전체 수업을 주석 블록에 넣었습니다.
Rainbolt

2
@Rusher는 중첩 된 주석 블록을 구문 분석합니까? : P
Martin Ender

6
LazyWolf가 이것을 막을 수있는 세상에서 사자 인 척하고 ROCK 또는 무작위를 선택하는 것이 더 합리적 일 수 있습니다. 대부분의 사람들이 사자를 피하려고 노력하기 때문에 사람들과의 만남 횟수가 줄어들 것이며, 사자와 싸우고 있다고 생각하는 사람들에 대해 평균적으로 승리해야합니다.
Tim Seguine

7
@Radiodef입니다.
Rainbolt

2
@Radiodef 내가 아니라고 언제 말했습니까? ;-)
Doorknob

38

채집 울프

늑대 는 그룹으로 산다. 사자가 허락하면 그들은 모입니다. 그래도 생존에 능숙하지 않습니다.

업데이트 : 사자가 그들을 강제로 멀리하면, 그들은 다시 모 으려고 노력합니다!

GatheringWolf 결과의 스크린 샷

package animals;
import java.util.*;
public class GatheringWolf extends Animal {
    private static int iteration;
    private static Move preferredMove;
    private int localIteration;
    private int loneliness;
    private boolean dangerFlag;
    private Move lastMove;
    public GatheringWolf() {
        super('W');
    }
    @Override
    public Attack fight(char other) {
        switch (other) {
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S':
            return Attack.PAPER;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() {
        if (localIteration == iteration) {
            localIteration++;
            iteration++;
            preferredMove = Math.random() < 0.5 ? Move.DOWN : Move.RIGHT;
        } else
            localIteration = iteration;
        EnumSet<Move> moves = EnumSet.allOf(Move.class);
        if (surroundings[0][1] == 'W')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'W')
            moves.remove(Move.LEFT);
        if (surroundings[2][1] == 'W')
            moves.remove(Move.DOWN);
        if (surroundings[1][2] == 'W')
            moves.remove(Move.RIGHT);
        if (surroundings[0][0] == 'L') {
            moves.remove(Move.UP);
            moves.remove(Move.LEFT);
        }
        if (surroundings[0][1] == 'L')
            moves.remove(Move.UP);
        if (surroundings[1][0] == 'L')
            moves.remove(Move.LEFT);
        if (surroundings[0][2] == 'L')
            moves.remove(Move.RIGHT);
        if (surroundings[2][0] == 'L')
            moves.remove(Move.DOWN);
        if (surroundings[0][1] == 'L' || surroundings[1][0] == 'L')
            if (moves.size() > 1) {
                moves.remove(Move.HOLD);
                dangerFlag = true;
            }
        int wolfNear = -1;
        for (char[] a : surroundings)
            for (char c : a)
                if (c == 'W')
                    wolfNear++;
        boolean enoughWolfNear = wolfNear >= (Math.random() < 0.9 ? 1 : 2);
        if (moves.contains(Move.HOLD) && enoughWolfNear) {
            loneliness = 0;
            dangerFlag = false;
            return lastMove = Move.HOLD;
        } else
            loneliness++;
        if (loneliness > 10) {
            EnumSet<Move> preferred = EnumSet.copyOf(moves);
            preferred.retainAll(EnumSet.of(preferredMove, Move.HOLD));
            if (!preferred.isEmpty())
                moves = preferred;
        }
        if (loneliness == 2 && dangerFlag) {
            Move reverted = Move.values()[lastMove.ordinal() ^ 0b10];
            dangerFlag = false;
            if (moves.contains(reverted))
                return lastMove = reverted;
        }
        if (moves.contains(Move.HOLD))
            dangerFlag = false;
        if (moves.contains(preferredMove))
            moves.remove(preferredMove == Move.DOWN ? Move.RIGHT : Move.DOWN);
        int n = (int) (Math.random() * moves.size());
        Iterator<Move> ite = moves.iterator();
        while (n-- > 0)
            ite.next();
        return lastMove = ite.next();
    }
}

43
몇 번이나 늑대가 친구가 되었기 때문에 내 덫에 걸리지 만 공격을 시작하지는 않았고 당신은 내 짐이 팩의 일부라고 생각했습니다. :)
undergroundmonorail

1
그렇지 않으면 내가 직접해야하기 때문에 이것을 작성해 주셔서 감사합니다. 상호 의사 난수의 영리한 사용.
벤 잭슨

31

늑대의 옷에있는 양

도망 치다.

늑대가 가장 위험하기 때문에 늑대로부터 도망 치는 것을 우선시합니다. 다음은 라이온들이 결정적이지 않기 때문입니다. 곰과 돌은 모두 문제가되지 않지만, 그 순간에 곰이나 돌을 죽이는 늑대가 양을 죽이는 늑대가 아니기 때문에 더 좋은 방법이 없다면 우리는 여전히 도망 치지 않습니다.

나는 아직 LazyWolf에 대해 테스트하지는 않았지만 EmoWolf의 엉덩이를 차는 좋은 권위를 가지고 있습니다. ;)

(이 코드가 끔찍한 경우 저를 용서해주세요. 저는 Hello World 프로그램보다 훨씬 더 Java를 다루지 않았습니다.)

package animals;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public class Sheep extends Animal {
    public Sheep() { super('W'); }

    private static final Map<Character, Integer> AnimalWeights;
    static{
        AnimalWeights = new HashMap<>();
        AnimalWeights.put('W', -3);
        AnimalWeights.put('S', -1);
        AnimalWeights.put(' ', 0);
        AnimalWeights.put('H', 1);
        AnimalWeights.put('L', -2);
        AnimalWeights.put('B', -1);
    }

    @Override
    public Attack fight(char c) { 
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.PAPER;
        } 
    }

    @Override
    public Move move() {

        int xWeight = 0;
        int yWeight = 0;

        // Northwest
        xWeight += AnimalWeights.get(surroundings[0][0]);
        yWeight += AnimalWeights.get(surroundings[0][0]);

        // North
        yWeight += AnimalWeights.get(surroundings[0][1]);

        // Northeast
        xWeight -= AnimalWeights.get(surroundings[0][2]);
        yWeight += AnimalWeights.get(surroundings[0][2]);

        // West
        xWeight += AnimalWeights.get(surroundings[1][0]);

        // East
        xWeight -= AnimalWeights.get(surroundings[1][2]);

        // Southwest
        xWeight += AnimalWeights.get(surroundings[2][0]);
        yWeight -= AnimalWeights.get(surroundings[2][0]);

        // South
        yWeight -= AnimalWeights.get(surroundings[2][1]);

        // Southeast
        xWeight -= AnimalWeights.get(surroundings[2][2]);
        yWeight -= AnimalWeights.get(surroundings[2][2]);

        if (Math.abs(xWeight) < Math.abs(yWeight)) {
            if (yWeight > 0) {
                return Move.UP;
            } else {
                return Move.DOWN;
            }
        } else if (Math.abs(yWeight) < Math.abs(xWeight)) {
            if (xWeight > 0) {
                return Move.RIGHT;
            } else {
                return Move.LEFT;
            }
        }

        // Sit still if no one's around
        return Move.HOLD;
    }
}

죄송합니다. 우연히 테스트에 사용한 것을 남겼습니다. 그것은 아무 영향을 미치지 않습니다, 그냥 내가 H.처럼 보이는 무엇에 가까이하려고한다는 것을 의미 : P
undergroundmonorail

그냥 궁금해서, 경우 xWeightyWeight모두 비 제로이고 절대 값이 늑대가 이동하지 않습니다 동일하다, 맞습니까? 그렇다면, 그것은 의도적 인 것이며 그 이유는 무엇입니까?
패트릭 로버츠

@PatrickRoberts oops
undergroundmonorail

26

항목이 아니라 각 클래스에 대한 색상 코드를 추가하여 GUI에 기여하고 싶습니다 = D

결과

컬러 GUI

Wild.java

다음 game.populate(c,100)과 같이 코드를 변경하십시오 .

String[] colors = generateColors(classes.length);
int idx = 0;
for(Class c : classes){
    Animal.setColor(c, colors[idx]);
    idx++;
    game.populate(c, 100);
}
stats.update();

다음과 같이 generateColors정의됩니다.

private static String[] generateColors(int n){
    String[] result = new String[n];
    double maxR = -1000;
    double minR = 1000;
    double maxG = -1000;
    double minG = 1000;
    double maxB = -1000;
    double minB = 1000;
    double[][] colors = new double[n][3];
    for(int i=0; i<n; i++){
        double cos = Math.cos(i * 2 * Math.PI / classes.length);
        double sin = Math.sin(i * 2 * Math.PI / classes.length);
        double bright = 1;
        colors[i][0] = bright + sin/0.88;
        colors[i][1] = bright - 0.38*cos - 0.58*sin;
        colors[i][2] = bright + cos/0.49;
        maxR = Math.max(maxR, colors[i][0]);
        minR = Math.min(minR, colors[i][0]);
        maxG = Math.max(maxG, colors[i][1]);
        minG = Math.min(minG, colors[i][1]);
        maxB = Math.max(maxB, colors[i][2]);
        minB = Math.min(minB, colors[i][2]);
    }
    double scaleR = 255/(maxR-minR);
    double scaleG = 255/(maxG-minG);
    double scaleB = 255/(maxB-minB);
    for(int i=0; i<n; i++){
        int R = (int)Math.round(scaleR*(colors[i][0]-minR));
        int G = (int)Math.round(scaleG*(colors[i][1]-minG));
        int B = (int)Math.round(scaleB*(colors[i][2]-minB));
        result[i] = "#"+String.format("%02x%02x%02x", R, G, B);
    }
    return result;
}

이 StackOverflow 답변 에서 가져온 알고리즘

으로 color하고 setColorAnimal.java 정의되고

Animal.java

public static HashMap<Class, String> color = new HashMap<Class, String>();

public static void setColor(Class animalClass, String animalColor){
    color.put(animalClass, animalColor);
}

그런 다음 toStringGame.java 및 Statistics.java 의 메소드를 업데이트하십시오 .

Game.java

public String toString() {
    String s = "<html>";
    for (ArrayList<ArrayList<Animal>> row : board) {
        for (ArrayList<Animal> cell : row) {
            if (cell.isEmpty())
                s += "&nbsp;&nbsp;";
            else
                s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
        }
        s+="<br>";
    }
    return s + "</html>";
}

Statistics.java

public String toString() {
    String s = "<html>";
    for (int i = 0; i < classes.length; i++) {
        s += "<span style='color:" + Animal.color.get(classes[i]) + "'>" + classes[i] + "</span>&nbsp;-&nbsp;" + living[i] + "<br>";
    }
    return s + "</html>";
}

2
아름다운. 어제 화면을 보면서 몇 분을 지났습니다. 탱크 판독 매트릭스처럼 느껴집니다.
Averroes

시뮬레이션 ...... is .... kind .... of ..... slow .... (30 초 후 5 회 반복)
user3188175

하하 그러나 각 반복마다 HTML 코드를 인쇄하는 시뮬레이션 설계에 내재되어 있습니다.
justhalf

이 게시물에 대한 링크를 제공하면 Google 드라이브 (챌린지에 링크 됨)에서 공유 할 수 있습니까? 적은 수의 늑대를 단위 테스트하는 데 훌륭하게 작동합니다.
Rainbolt

1
그래 넌 할수있어. 지진에 관한 다른 게시물에서 쓴 것처럼 많은 늑대의 렌더링 속도를 높이기 위해 초기 렌더링 건너 뛰기를 포함 할 수 있습니다.
justhalf

23

알파 울프

빛날 시간! 나의 다른 늑대 인 CamperWolf는 매우 얇 았고, 이제는 더욱 근육질 인 AlphaWolf가 등장합니다!

사자를 표준 방식으로 피하는 대신 현장을 교체합니다. 또한 각 주변 필드에 위험 값을 할당합니다.

package animals;

import java.util.Random;

public class AlphaWolf extends Animal{
    private Boolean lionMoveDown = true;

    public AlphaWolf() {
        super('W');
    }
    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            return randomAttack();
        }
    }

    @Override
    public Move move() {
        int[] danger = new int[4];
        final int wolfsDanger = 4;
        lionMoveDown = !lionMoveDown;
        if(surroundings[0][1] == 'L' && lionMoveDown) {
            return Move.UP;
        }
        if(surroundings[1][0] == 'L'&& !lionMoveDown) {
            return Move.LEFT;
        }
        if(surroundings[0][1] == 'W') {
            danger[0] += wolfsDanger;
        }
        if(surroundings[1][2] == 'W') {
            danger[1] += wolfsDanger;
        }
        if(surroundings[2][1] == 'W') {
            danger[2] += wolfsDanger;
        }
        if(surroundings[1][0] == 'W') {
            danger[3] += wolfsDanger;
        }
        if(surroundings[0][0] == 'W') {
            danger[0]++;
            danger[3]++;
        }
        if(surroundings[0][2] == 'W') {
            danger[0]++;
            danger[1]++;
        }
        if(surroundings[2][2] == 'W') {
            danger[1]++;
            danger[2]++;
        }
        if(surroundings[1][2] == 'W') {
            danger[2]++;
            danger[3]++;
        }
        Boolean shouldMove = false;
        Move bestMove = Move.HOLD;
        int leastDanger = 4;
        for(int i = 0; i < 4; i++) {
            if (danger[i] < leastDanger) {
                bestMove = Move.values()[i];
            }
            if(danger[i] > 3) {
                shouldMove = true;
            }
        }
        if(shouldMove) {
            return bestMove;
        } else {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

그것은 매우 아름다운 코드는 아니지만 내 테스트에서 모든 Java 늑대에 대해 잘 작동했습니다.


1
"필드 교체"란 무엇입니까? 직장에서 이것을 실행할 수 없기 때문에 궁금합니다.
Rainbolt

내 모든 시뮬레이션에서 1000 번의 반복 후 평균 80-90 늑대로 승리했습니다. 나는 지금까지 광산에 제출 된 합법적 인 늑대를 Java로 작성했습니다. 아직도 그것은 10 마리의 늑대와 같습니다.
Sheph

@Rusher 사자가 내 늑대 위에 있고 내려 가면 늑대가 위로 올라갑니다
CommonGuy

안티 윌코 카모 코드를 추가해야합니다. lion 's know 패턴을 사용하는 아주 좋은 아이디어 :)
Lesto

9
이제 누군가가 찾은 사자를 꼬리에 붙일 늑대를 발명해야하므로 사자와 교환하려고 할 때 늑대가 튀어 나옵니다.
AJMansfield

23

도박꾼 늑대

도박꾼 울프는 기회를 잡으려고하므로 레이디 럭이 옆에 있기를 바라고 있습니다. 그를 위해 다행히도, 그녀는 그를 실망시키지 않습니다! 끊임없는 행운의 타격으로 Gambler Wolf는 믿을 수 없을 정도로 적은 인과 관계로 늑대가 아닌 모든 장애물의 필드를 없앱니다!

package animals;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Random;

public class GamblerWolf extends Animal {
    private static int last = 0;

    public GamblerWolf() { super('W'); gamble(); }
    public Attack fight(char opponent) {
        switch (opponent) {
        case 'S': return Attack.ROCK; /* Camo Wolf? */
        case 'B': return Attack.SCISSORS;
        case 'L': return Attack.SCISSORS;
        default:  return attackWolf();
        }
    }
    public Move move() {
        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(Move.values());
        Collections.shuffle(moves);
        for(Move move : moves)
          if(isThreatenedBy(move))
            return moveToEvade(move);
        return Move.HOLD;
    }

    /* Remember, Gamblers Don't Gamble */
    @SuppressWarnings("serial")
    private static void gamble() {
        try {
        Field field = Math.class.getDeclaredField("randomNumberGenerator"); 
        field.setAccessible(true);
        field.set(null, new Random() { 
              @Override
              public double nextDouble() {
                return 4; // chosen by fair dice roll
              }           // guaranteed to be random
            });           // proof: http://xkcd.com/221/
        }
        catch (SecurityException        e) {}
        catch (NoSuchFieldException     e) {}
        catch (IllegalArgumentException e) {}
        catch (IllegalAccessException   e) {}
    }

    private static Attack attackWolf() {
        return Attack.values()[last++ % 3];
    }
    private boolean isThreatenedBy(Move move) {
        return isWolf(move) 
            || isStone(move); 
    }

    private Move moveToEvade(Move move) {
        if(isSafeMove(getOpposite(move)))
            return getOpposite(move);

        ArrayList<Move> moves = (ArrayList<Move>) Arrays.asList(getOrthogonal(move));
        Collections.shuffle(moves);
        for(Move m : moves)
            if(isSafeMove(m))
                return m;
        return Move.HOLD;
    }

    private static Move[] getOrthogonal(Move move) {
        switch(move){
        case UP:
        case DOWN:  return new Move[] { Move.LEFT, Move.RIGHT };
        case LEFT:
        case RIGHT: return new Move[] { Move.UP,   Move.DOWN };
        default:    return null;
        }
    }

    private static Move getOpposite(Move move) {
        switch(move){
        case UP:    return Move.DOWN;
        case DOWN:  return Move.UP;
        case LEFT:  return Move.RIGHT;
        case RIGHT: return Move.LEFT;
        default:    return null;
        }
    }

    private boolean isSafeMove(Move move) {
        return !isWolf(move)
            && !isStone(move)
            && !couldAWolfMoveHere(move);
    }

    private boolean isWolf(Move move) {
        return isX(move,'W');
    }

    private boolean isStone(Move move) {
        return isX(move,'S');
    }

    private boolean isX(Move m, char c) {
        switch (m) {
        case UP:    return surroundings[0][1] == c;
        case LEFT:  return surroundings[1][0] == c;
        case RIGHT: return surroundings[1][2] == c;
        case DOWN:  return surroundings[2][1] == c;
        default:    return false;
        }
    }

    private boolean couldAWolfMoveHere(Move move) {
        switch (move) {
        case UP:    return surroundings[0][2] == 'W' || surroundings[0][0] == 'W';
        case LEFT:  return surroundings[2][0] == 'W' || surroundings[0][0] == 'W';
        case RIGHT: return surroundings[0][2] == 'W' || surroundings[2][2] == 'W';
        case DOWN:  return surroundings[2][0] == 'W' || surroundings[2][2] == 'W';
        default:    return false;
        }
    }
}

편집 : v1.1

  • 이제 돌을 피하십시오 (Camo-Wolves?)

  • 무작위성 증가!


5
나는 이것을 늑대에 추가 할 것이라고 생각한다 :static{System.setSecurityManager(new SecurityManager());}
johnchen902

13
공정한 플레이를 할 수 없을 때는 +1 : D
ProgrammerDan

5
유감스럽게도 여기서는 사용할 수 없습니다 return 4; // chosen by fair dice roll. guaranteed to be random....
Vi.

1
더 악하고 싶다면 더 많은 계약을 깨십시오 Math.random(). [0,1) 범위를 벗어난 값을 반환하거나, 무한 또는 NaN 일 수도 있습니다. 또는 가능한 한 악의적 인 경우 아무것도 반환하지 않고 런타임 예외를 throw하십시오 (제너레이터를로 설정하여 얻을 수도 있음 null).
Runer112

1
@AlexL. ForrestWolf문제 처럼 들리는 ...
recursion.ninja

22

캠퍼 울프

목표는 생존하는 것입니다. 다른 늑대들 중 많은 늑대들이 늑대들로부터 도망 가면서, 내 늑대는 그 자리에 머무르고 모든 동물들과 싸 웁니다.

package animals;

public class CamperWolf extends Animal {
    public CamperWolf() { super('W'); }
    @Override
    public Attack fight(char opponent) {  
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.ROCK;
        default:
            return Attack.values()[(int) (Math.random() * 3)];
        }
    }
    @Override
    public Move move() { return Move.HOLD; }
}

다른 많은 늑대가 늑대에서 도망 치고이 늑대는 다른 늑대에 대해서만 죽을 수 있기 때문에 나는 그것이 아주 좋은 성능을 기대합니다.


사자도 그것을 죽일 수 있습니다. 사자가 가위를 굴리면 늑대는 의사 무작위로 죽습니다.
Tim Seguine

2
축하합니다. 귀하와 15 줄의 코드가 현재 이기고 있습니다.
Rainbolt

2
@Rusher thanks :) downvoter가 왜 downvoted했는지 설명해 주시겠습니까?
CommonGuy

@ Stone은 움직일 수 없기 때문에 중요하지 않지만 'S'가 Attack.PAPER을 반환해서는 안됩니다.
DavidJFelix

3
네, 물어 본 후 CamoWolf를 보았습니다. 까다로운 녀석!
DavidJFelix

22

딥 울프

어쨌든,이 늑대는 "심층적 인"분석을 사용하여 내가 생각할 수있는만큼 많은 환경 데이터를 수집하고 사용합니다. 이 분석은 사자와 늑대의 알려진 위치와 미래 위치의 예측과 같은 늑대 고유의 지식을 혼합하여 작동하며 추정 인구, 늑대 전투 기록 및 이동할 때 동물 상대와 충돌 할 위험과 같은 하이브 마인드 지식을 압축합니다. 논리가 많을뿐 아니라 객체 지향 디자인을 넘어서고 특수 목적 클래스와 메소드가 많기 때문에 매우 방대합니다.

나는 인기있는 최고의 늑대들과 함께 1000 걸음 씩 100 번의 게임을 반복했다. 어쨌든 내 늑대에는 영향을 미치지 않아야하지만 약간 칙칙하다고 생각했기 때문에 GamblerWolf를 의도적으로 제외했습니다. 평균, 최대 및 최소 성능 데이터는 다음과 같습니다.

Averages:
Bear 0.0
Lion 0.0
Stone 3.51
Wolf 1.56
AlphaWolf 77.05
CamperWolf 69.17
DeepWolf 90.48
EmoWolf 39.92
GatheringWolf 52.15
HerjanWolf 86.55
HonorWolf 86.76
HybridWolf 86.78
LazyWolf 71.11
LionHunterWolf 32.45
MimicWolf 0.4
MOSHPITFRENZYWolf 8.95
OmegaWolf 88.67
ProAlpha 83.28
Sheep 54.74
StoneEatingWolf 75.29
WolfWithoutFear 11.9

Maxes:
Bear 0
Lion 0
Stone 9
Wolf 4
AlphaWolf 89
CamperWolf 81
DeepWolf 96
EmoWolf 57
GatheringWolf 65
HerjanWolf 95
HonorWolf 97
HybridWolf 95
LazyWolf 83
LionHunterWolf 41
MimicWolf 3
MOSHPITFRENZYWolf 22
OmegaWolf 95
ProAlpha 91
Sheep 66
StoneEatingWolf 88
WolfWithoutFear 18

Mins:
Bear 0
Lion 0
Stone 0
Wolf 0
AlphaWolf 65
CamperWolf 57
DeepWolf 83
EmoWolf 26
GatheringWolf 37
HerjanWolf 79
HonorWolf 79
HybridWolf 79
LazyWolf 58
LionHunterWolf 20
MimicWolf 0
MOSHPITFRENZYWolf 1
OmegaWolf 81
ProAlpha 70
Sheep 43
StoneEatingWolf 66
WolfWithoutFear 5

DeepWolf는 1 위, 평균 90.48이지만 2 위 OmegaWolf의 88.67보다 2 배 정도 더 좁습니다. 단 2 % 개선 된 코드 라인의 약 4 배! HerjanWolf, HonorWolf 및 HybridWolf는 각각 86.55, 86.76 및 86.78 평균에 가까운 OmegaWolf보다 약 2 배 더 높은 3 위를 차지합니다.

더 이상 고민하지 않고 코드를 제시하겠습니다. 내가 볼 수 없었던 개선 된 상수 / 논리에 대한 오류 및 / 또는 가능성이있을 정도로 너무 방대합니다. 의견이 있으시면 알려주세요!

포스트 링크 제한을 날려 버리기 때문에이 링크의 코드 : Ideone


dropboxusercontent가 파일을 잃을 지 모르겠습니다. ideone
Justin

3
@ Runer112 인상적! 나는 코드를보고 있고 약간 잃어 버렸다. : P 그러나 나를 흥미롭게 만드는 하나의 개념은 당신이 늑대가 우호적인지 아닌지를 결정하는 데 사용하는 것이다.
Moogie

@Moogie 늑대가 친근한 지에 대한 결정 론적 평가는 없다. 그러나 우리는 늑대의 종의 수를 알고, 각 종이 100에서 시작한다는 것을 알고, 다른 친한 늑대가 얼마나 많이 남아 있는지, 그리고 우리가 죽인 수와 얼마나 많은 사람들이 다른 동물들과 함께 죽었는지 추측하십시오. 그로부터 우리는 우리가 본 늑대가 우호적 일 확률을 추정합니다. 이 정보는 큰 영향을 미치지는 않지만 잠재적으로 늑대와 싸울 것인지 또는 사자와 확실히 싸울 것인지를 선택하는 것의 차이 일 수 있습니다.
Runer112

MAP_SIZE가 정적이 아닌 변수이므로 컴파일하지 않았습니다. 나는 그것이 인스턴스 변수가 될 것이라고 말하지 않았기 때문에 당신을 위해 고쳤습니다. 내가 완전한 프로젝트를 게시하고 정육점 변수 이름을 보았을 때 당신이 알고 싶어했습니다.
Rainbolt

@Rusher 아, 으악. 나는 여전히 샌드 박스에서 이전 버전의 게임 코드로 실행 중이라고 생각하고 MAP_SIZE변수는 실제로 존재하지 않았거나 어떤 이유로 든 무시하고 정적 버전으로 추가했습니다. 나는 또한 내 늑대가 시험에서 다른 늑대보다 약간 더 나은 점수를 낸 이유가 궁금하지만, 다른 늑대는 다른 늑대 세트라고 생각합니다. 아니면 1000이 아닌 여러 반복으로 게임을 실행합니까? 또는 더 큰 표본 크기가 필요할 수도 있습니다. 5는 통계적으로 그렇게 크지 않습니다.
Runer112

21

늑대가 달리기

아무도 WolfRunningWithScissors에게 가위로 달리지 말라고 말하지 않았습니다. 아니면 어쩌면 그들은했지만 어쨌든 그것을합니다.

그가 적을 만나면 가위로이기거나 가위로 잃거나 가위로 묶거나 눈을 찌릅니다 (자살).

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class WolfRunningWithScissors extends Animal{

    public WolfRunningWithScissors() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        List<Attack> att = new ArrayList<>();
        att.add(Attack.SCISSORS);
        att.add(Attack.SUICIDE);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();
        m.add(Move.UP);
        m.add(Move.DOWN);
        m.add(Move.LEFT);
        m.add(Move.RIGHT);
        Collections.shuffle(m);
        return m.get(0);
    }

}

재미있게 제출하고 싶었습니다. 나는 전에 Java를 사용한 적이 없으며 이것을 테스트하지는 않았지만 작동해야합니다. 내 임의의 공격 및 이동 코드는 getRandomAttack()StoneEatingWolf를 기반으로 합니다.


14

오메가 울프

Alpha Wolf와 매우 유사하게 상호 의존적으로 파생 된 솔루션이므로 Omega Wolf라는 이름

이 늑대는 주변 세포의 "위험"맵을 생성하고 가장 안전한 세포로의 이동 (또는 유지)을 선택합니다.

사자가 다음에 이동할 셀에 먼저 EXTREAME_DANGER 레벨이 지정됩니다. 그런 다음 탐지 된 늑대를 둘러싼 세포는 공격의 즉시성에 따라 위험 수준이 부여됩니다. 즉 늑대가 오메가 늑대와 대각선이면 낮은 위협으로 간주되지만 인접한 늑대는 보통 위협으로 간주됩니다.

그런 다음 "위험"맵을 흐리게하여 주변 세포에 대한 위협을 피할 수 있습니다. 이를 통해 오메가 늑대는 위협 벡터를 "감지"하고 피할 수 있습니다.

현재 실제 공격 논리는 매우 원시적입니다. 더 똑똑하고 더 나은 승 / 패 비율을 얻을 수 있기를 바랍니다. 통계적 휴리스틱을 사용하면 가능합니다.

내 테스트에서 Omega Wolf는 알파 봇 9에 대해 10 번 연속적으로 승리합니다. 여백은 매우 좋습니다 .P

1000 회 반복 100 회 후 평균 살아있는 늑대의 빠른 결과 :

class animals.OmegaWolf - 85
class animals.HonorWolf - 82
class animals.ProAlpha - 79
class animals.AlphaWolf - 77
class animals.ShadowWolf - 77
class animals.LazyWolf - 62
class animals.CamperWolf - 61
class animals.StoneEatingWolf - 59
class animals.GatheringWolf - 48
class animals.Sheep - 42
class animals.EmoWolf - 34
class animals.LionHunterWolf - 28
class animals.GamblerWolf (no cheating) - 27
class animals.WolfWithoutFear - 11
class animals.MOSHPITFRENZYWolf - 5
class animals.Wolf - 3
class animals.Stone - 2
class animals.Bear - 0
class animals.Lion - 0
class animals.MimicWolf - 0
class animals.Wion - 0

암호:

package animals;

import wild.Wild;

public class OmegaWolf extends Animal {

    boolean lionWillMoveDown=true;

    private static final int LOW_DANGER = 10;
    private static final int MODERATE_DANGER = LOW_DANGER*2;
    private static final int EXTREAME_DANGER = MODERATE_DANGER*4;

    private static final int UP=1;
    private static final int LEFT=3;
    private static final int RIGHT=5;
    private static final int DOWN=7;
    private static final int UP_LEFT=0;
    private static final int UP_RIGHT=2;
    private static final int DOWN_LEFT=6;
    private static final int DOWN_RIGHT=8;

    private static final int WOLVES_SPECIES_COUNT=(int) Math.round(Math.pow(((float) Wild.MAP_SIZE)/20,2)-3)-3;

    /*
     * Interdependently derived solution that behaves very similar to Alpha Wolf, hence the name Omega Wolf
     * 
     * This wolf generates a "danger" map of the surrounding cells and will choose the movement (or hold) to the safest cell.
     * 
     * The firstly the cells where lions will move next are given EXTREAME_DANGER level
     * Then the cells surrounding any detected Wolves are given danger levels based on the immediacy of attack... i.e. if the wolf is diagonal to the omega wolf 
     * it is deemed a low threat however wolves that are adjacent are deemed a moderate threat.
     * The "danger" map is then blurred to allow bleeding of the threats to surrounding cells. This allows the omega wolf to "sense" threat vectors and to avoid it.
     * 
     * Currently the actual attack logic is very primitive. I hope to be able to give it more smarts and eek out better win/lose ratios. This should be possible if 
     * I put in some statistical heuristics.
     */

    public OmegaWolf() { 
        super('W'); }


    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            // if there is only one wolf species then it must be another omega wolf.
            if (WOLVES_SPECIES_COUNT==1)
            {
                return Attack.SCISSORS;
            }
            else
            {
                // lets just choose an attack with equal weight.
                double rand = Math.random();
                if (rand < 0.333333)
                {
                    return Attack.PAPER;
                }
                if (rand < 0.666667)
                {
                    return Attack.SCISSORS;
                }
                return Attack.ROCK;

            }
        }
    }

    public Move move() {

        lionWillMoveDown = !lionWillMoveDown;


        Move move = Move.HOLD;

        int[][] dangerMap = new int[3][3];
        int[][] blurredDangerMap = new int[3][3];

        // sense Lion Danger
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (surroundings[y][x]=='L')
                {
                    if (lionWillMoveDown && y!=2)
                    {
                        dangerMap[y+1][x]+=EXTREAME_DANGER;
                    }
                    else if (x!=2)
                    {
                        dangerMap[y][x+1]+=EXTREAME_DANGER;
                    }
                }
            }
        }

        // sense Wolf Danger adjacent
        // UP
        if (surroundings[0][1]=='W')
        {
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // DOWN
        if (surroundings[2][1]=='W')
        {
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // LEFT
        if (surroundings[1][0]=='W')
        {
            dangerMap[1][0]+=MODERATE_DANGER;
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }
        // RIGHT
        if (surroundings[1][2]=='W')
        {
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[1][1]+=MODERATE_DANGER;
        }

        // sense Wolf Danger diagonally
        // UP_LEFT
        if (surroundings[0][0]=='W')
        {
            dangerMap[0][0]+=LOW_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // DOWN_LEFT
        if (surroundings[2][0]=='W')
        {
            dangerMap[2][0]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][0]+=MODERATE_DANGER;
        }
        // UP_RIGHT
        if (surroundings[0][2]=='W')
        {
            dangerMap[0][2]+=LOW_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
            dangerMap[0][1]+=MODERATE_DANGER;
        }
        // DOWN_RIGHT
        if (surroundings[2][2]=='W')
        {
            dangerMap[2][2]+=LOW_DANGER;
            dangerMap[2][1]+=MODERATE_DANGER;
            dangerMap[1][2]+=MODERATE_DANGER;
        }


        // generate a blurred danger map. This bleeds danger to surrounding cells.
        int yj,xi,sampleCount,cumulativeDanger;
        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                sampleCount=0;
                cumulativeDanger=0;
                for (int j=-1;j<2;j++)
                {
                    for (int i=-1;i<2;i++)
                    {
                        yj=y+j;
                        xi=x+i;
                        if (yj>-1 && yj<3 && xi>-1 && xi<3)
                        {
                            cumulativeDanger+=dangerMap[yj][xi];
                            sampleCount++;
                        }
                    }
                }
                blurredDangerMap[y][x]=(dangerMap[y][x]+cumulativeDanger/sampleCount)/2;
            }
        }

        // find the safest cell
        int safestCellDanger=Integer.MAX_VALUE;
        int safestCellId = -1;
        int cellId=0;

        for (int y=0;y<3;y++)
        {
            for (int x=0;x<3;x++)
            {
                if (blurredDangerMap[y][x]<safestCellDanger)
                {
                    safestCellDanger=blurredDangerMap[y][x];
                    safestCellId=cellId;
                }
                cellId++;
            }
        }

        // safest cell is adjacent so move there
        if ((safestCellId&1)==1)
        {
            switch (safestCellId)
            {
                case UP:
                    move=Move.UP;
                    break;
                case LEFT:
                    move=Move.LEFT;
                    break;
                case RIGHT:
                    move=Move.RIGHT;
                    break;
                case DOWN:
                    move=Move.DOWN;
                    break;
            }
        }
        // safestCell is a diagonal cell or current cell
        else
        {
            // lets initialise the move to Hold.
            move = Move.HOLD;

            switch (safestCellId)
            {
                case UP_LEFT:

                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][0] || (dangerMap[0][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // left must be safest :P
                        else
                        {

                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }

                    break;
                case UP_RIGHT:
                    // check to see whether holding is not safer than moving up
                    if (dangerMap[1][1] > dangerMap[0][1] )
                    {
                        // move up if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[0][1] < dangerMap[1][2]|| (dangerMap[0][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.UP;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
                case DOWN_LEFT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving left or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[1][0]|| (dangerMap[2][1] == dangerMap[1][0] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // left must be safest :P
                        else
                        {
                            move=Move.LEFT;
                        }
                    }
                    // check to see whether holding is not safer than moving left
                    else if (dangerMap[1][1] > dangerMap[1][0] )
                    {
                        move=Move.LEFT;
                    }
                    break;
                case DOWN_RIGHT:
                    // check to see whether holding is not safer than moving down
                    if (dangerMap[1][1] > dangerMap[2][1] )
                    {
                        // move down if safer than moving right or if equally safe, when randomly chosen 
                        if (dangerMap[2][1] < dangerMap[2][2] || (dangerMap[2][1] == dangerMap[1][2] && Math.random()>0.5))
                        {
                            move=Move.DOWN;
                        } 
                        // right must be safest :P
                        else
                        {
                            move=Move.RIGHT;
                        }
                    }
                    // check to see whether holding is not safer than moving right
                    else if (dangerMap[1][1] > dangerMap[1][2] )
                    {
                        move=Move.RIGHT;
                    }
                    break;
            }
        }

        return move;

    }
}

14

스톤 가디언 울프

이것은 꽤 재미 있었다. 시각화에 대한 createjs 지원을 사용하여 자바 코드를 자바 스크립트로 바꿨습니다 : JavaScript StoneGuardianWolf

StoneGuardianWolf는 애완 동물 바위를 찾아 돌 옆에 피난처를 가져갑니다. 그녀는 그들을 보호하고 오히려 안전을 위해 자신을 희생하려고합니다.

통계

싱글 플레이어 : ~ 75 % 늑대 생존율 + 35 % 애완 동물 (돌) 생존율.

요약 : 75 % + 35 % ---> 110 % 성공률! :)

멀티 플레이어 : 테스트되지 않았습니다.

변경 로그

v2 : AI vs GamblerWolf 및 애완 동물 락 탐색 전략 업데이트.

v1 : 더 나은 늑대 회피

v0 : 생일

자바 코드

package animals;

public class StoneGuardianWolf extends Animal {
    public StoneGuardianWolf() {
        super('W');
    }

    private boolean petRock = false;
    private int heartache = 0;

    public Attack fight(char c) {
        this.heartache--;

        switch (c) {
        case 'B':
            return Attack.SCISSORS;
        case 'L':
            return Attack.SCISSORS;
        case 'S': // A motherly sacrifice
            return Attack.SUICIDE;
        default:
            int n = this.heartache % 3;
            if (n < 1)
                return Attack.PAPER;
            if (n < 2)
                return Attack.ROCK;
            return Attack.SCISSORS;
        }
    }

    public Move move() {
        char[][] surr = this.surroundings;
        int[][] clairvoyance = new int[3][3];

        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 3; j++)
                clairvoyance[i][j] = 1;

        boolean seeNoStone = true;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                switch (surr[i][j]) {
                case 'L':
                    if (i < 1 && j < 1) {
                        clairvoyance[1][0] += 50;
                        clairvoyance[0][1] += 50;
                    }

                    if (i == 1 && j < 1) { // above
                        clairvoyance[1][1] += 50;
                    }

                    if (i < 1 && j == 1) { // left
                        clairvoyance[1][1] += 50;
                    }
                    break;

                case 'S': // seek stones for protection
                    seeNoStone = false;
                    this.petRock = true;
                    clairvoyance[i][j] += 999; // Only hugs!
                    if (i < 2)
                        clairvoyance[i + 1][j] -= 10;
                    if (j < 2)
                        clairvoyance[i][j + 1] -= 10;
                    if (i > 0)
                        clairvoyance[i - 1][j] -= 10;
                    if (j > 0)
                        clairvoyance[i][j - 1] -= 10;
                    break;

                case 'B': // ignore bears
                    break;

                case 'W':
                    // skip self
                    if (i == 1 && j == 1)
                        continue;
                    int m = 25; // avoid wolves

                    // don't fight unless pet rock is in danger
                    if (petRock)
                        clairvoyance[i][j] -= 999; // motherly wrath
                    else
                        clairvoyance[i][j] += 100;

                    // avoid stepping into wolf path
                    if (i != 1 && j != 1) {
                        if (i < 2)
                            clairvoyance[i + 1][j] += m;
                        if (j < 2)
                            clairvoyance[i][j + 1] += m;
                        if (i > 0)
                            clairvoyance[i - 1][j] += m;
                        if (j > 0)
                            clairvoyance[i][j - 1] += m;
                    }
                    break;

                default:
                    clairvoyance[i][j] += 0;
                }
            } // for loop
        } // for loop

        int size = clairvoyance[1][1];
        int x = 1;
        int y = 1;

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                if (i != 1 || j != 1)
                    continue;
                int tmp = clairvoyance[i][j];
                if (tmp < size) {
                    size = tmp;
                    x = i;
                    y = j;
                }
            }
        }

        if (seeNoStone)
            this.heartache++;

        this.petRock = false;
        if (seeNoStone && heartache % 10 == 0) { // Find a pet stone! :3
            if ((heartache % 3) < 2 || clairvoyance[1][2] >= 45) {
                // try move right
                if (clairvoyance[2][1] < 45)
                    return Move.RIGHT;
            }

            // try down instead
            if (clairvoyance[1][2] < 45)
                return Move.DOWN;
        }

        if (x == 0 && y == 1)
            return Move.LEFT;
        if (x == 2 && y == 1)
            return Move.RIGHT;
        if (x == 1 && y == 0)
            return Move.UP;
        if (x == 1 && y == 2)
            return Move.DOWN;

        if (!seeNoStone)
            this.petRock = true;

        return Move.HOLD;
    }
}

5
돌 먹는 늑대 아치 적!
Averroes

:) 실제로-내 애완 동물 바위 근처에 당신을 두지 마세요! 그러나 CamoWolf는 SGW를 꽤 세게 때립니다.
talmobi

1
다행히 CamoWolf를 합법적 인 항목으로 포함 할 필요는 없습니다. = D
justhalf

14

소년인가요? 늑대인가요? 아니야

BoyWhoCriedWolf.java

사람들은 모든 곳에서 반사를 사용하고 있기 때문에 한 걸음 더 나아 가지 않겠습니까?
잃을 수없는 늑대.

package animals;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.instrument.ClassDefinition;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.lang.management.ManagementFactory;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import javax.xml.bind.DatatypeConverter;

public class BoyWhoCriedWolf extends Animal {

    private static boolean ranAgent;

    public static void installAgent() {
        try {
            ranAgent = true;
            String javaExec = new File(System.getProperty("java.home"), "bin").getAbsolutePath() + File.separator + "java";
            Process proc = new ProcessBuilder(javaExec, "-cp", System.getProperty("java.class.path"),
                    "animals.BoyWhoCriedWolf", ManagementFactory.getRuntimeMXBean().getName().split("@")[0])
                    .inheritIO().start();
            proc.waitFor();
        } catch (InterruptedException | IOException e) {
            e.printStackTrace();
        }
    }

    public BoyWhoCriedWolf() {
        super('W');
        if (!ranAgent) {
            installAgent();
        }
    }

    @Override
    public Attack fight(char c) {
        return Attack.PAPER; // I like paper, it's my rubber duck.
    }

    @Override
    public Move move() {
        return Move.HOLD; // I'm terribly lazy.
    }

    public static void main(String[] args) {
        try {
            File temp = File.createTempFile("agent-", ".jar");
            temp.deleteOnExit();
            Manifest manifest = new Manifest();
            manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
            manifest.getMainAttributes().put(new Attributes.Name("Agent-Class"), "animals.BoyWhoCriedWolf");
            manifest.getMainAttributes().put(new Attributes.Name("Can-Redefine-Classes"), "true");
            JarOutputStream jos = new JarOutputStream(new FileOutputStream(temp), manifest);
            jos.close();

            // Add tools.jar
            Method addURL = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            addURL.setAccessible(true);
            addURL.invoke(ClassLoader.getSystemClassLoader(), new URL("file:" + System.getProperty("java.home") + "/../lib/tools.jar"));

            Class<?> virtualMachineClass = Class.forName("com.sun.tools.attach.VirtualMachine");
            Object vm = virtualMachineClass.getDeclaredMethod("attach", String.class).invoke(null, args[0]);
            virtualMachineClass.getDeclaredMethod("loadAgent", String.class).invoke(vm, temp.getAbsolutePath());
            virtualMachineClass.getDeclaredMethod("detach").invoke(vm);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void agentmain(String args, Instrumentation instr) throws ClassNotFoundException, UnmodifiableClassException {
        instr.redefineClasses(new ClassDefinition(wild.Game.class, DatatypeConverter.parseBase64Binary(base64Game)));
    }

    private static final String base64Game =
              "yv66vgAAADMA9QoAOQCRBwCSCgACAJEJABIAkwkAEgCUBwCVCgAGAJEJABIAlgoABgCXCgAGAJgK"
            + "AAIAmQoABgCaCgCbAJwHAJ0HAJ4KABIAnwoAEgCgBwChCgASAKIHAKMKABIApAkAFAClCgAUAKYH"
            + "AKcJAGUAqAkAOgCpCgBlAKoKAAYAqwsArACtCwCsAK4KAAYArwcAsAoABgCxCQAUALIKABQAswkA"
            + "cQC0CgC1ALYGP+AAAAAAAAAJADoAtwoAcQCqCQBxALgJAHEAuQkAcQC6CgCbALsIALwHAL0KAC8A"
            + "kQoALwC+CAC/CgAvAMAKAC8AwQgAwggAwwgAxAcAjQcAxQcAxgEADElubmVyQ2xhc3NlcwEABWJv"
            + "YXJkAQAVTGphdmEvdXRpbC9BcnJheUxpc3Q7AQAJU2lnbmF0dXJlAQBVTGphdmEvdXRpbC9BcnJh"
            + "eUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGphdmEvdXRpbC9BcnJheUxpc3Q8TGFuaW1hbHMv"
            + "QW5pbWFsOz47Pjs+OwEAA2dlbgEAEkxqYXZhL3V0aWwvUmFuZG9tOwEABFNJWkUBAAFJAQAGPGlu"
            + "aXQ+AQAEKEkpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUB"
            + "AAFqAQABaQEABHRoaXMBAAtMd2lsZC9HYW1lOwEABHNpemUBAA1TdGFja01hcFRhYmxlBwChAQAI"
            + "cG9wdWxhdGUBABUoTGphdmEvbGFuZy9DbGFzcztJKVYBAAFlAQAoTGphdmEvbGFuZy9SZWZsZWN0"
            + "aXZlT3BlcmF0aW9uRXhjZXB0aW9uOwEAA3JvdwEAA2NvbAEAB3NwZWNpZXMBABFMamF2YS9sYW5n"
            + "L0NsYXNzOwEAA251bQEAFkxvY2FsVmFyaWFibGVUeXBlVGFibGUBABZMamF2YS9sYW5nL0NsYXNz"
            + "PFRUOz47BwDHBwDIAQAuPFQ6TGFuaW1hbHMvQW5pbWFsOz4oTGphdmEvbGFuZy9DbGFzczxUVDs+"
            + "O0kpVgEAB2l0ZXJhdGUBAAMoKVYBAAdtb3ZlQWxsAQAVTGphdmEvbGFuZy9FeGNlcHRpb247AQAB"
            + "YQEAEExhbmltYWxzL0FuaW1hbDsBAAVhTW92ZQcAyQEABE1vdmUBABVMYW5pbWFscy9BbmltYWwk"
            + "TW92ZTsBAARnYW1lBwCjBwCnBwDJAQAHZmxhdHRlbgEABXJhbmQxAQAFcmFuZDIBAAFiAQAFYVRh"
            + "Y2sHAMoBAAZBdHRhY2sBABdMYW5pbWFscy9BbmltYWwkQXR0YWNrOwEABWJUYWNrAQAEY2VsbAEA"
            + "J0xqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+OwEAPkxqYXZhL3V0aWwvQXJy"
            + "YXlMaXN0PExqYXZhL3V0aWwvQXJyYXlMaXN0PExhbmltYWxzL0FuaW1hbDs+Oz47BwDLBwCVBwDK"
            + "AQAEcG9sbAEAFChMamF2YS9sYW5nL0NsYXNzOylJAQABYwEABWNvdW50AQAIdG9TdHJpbmcBABQo"
            + "KUxqYXZhL2xhbmcvU3RyaW5nOwEAAXMBABJMamF2YS9sYW5nL1N0cmluZzsHAMwBAAdnZXRBcmVh"
            + "AQAHKElJKVtbQwEABXRlbXAxAQAFdGVtcDIBAAV0ZW1wMwEABXRlbXA0AQABbAEAAWsBAARhcmVh"
            + "AQADW1tDBwDNAQAKU291cmNlRmlsZQEACUdhbWUuamF2YQwARABfAQAQamF2YS91dGlsL1JhbmRv"
            + "bQwAQABBDABCAEMBABNqYXZhL3V0aWwvQXJyYXlMaXN0DAA8AD0MAM4AzwwA0ADRDADSANMMANQA"
            + "1QcAxwwA1gDXAQAgamF2YS9sYW5nL0luc3RhbnRpYXRpb25FeGNlcHRpb24BACBqYXZhL2xhbmcv"
            + "SWxsZWdhbEFjY2Vzc0V4Y2VwdGlvbgwAYABfDABsAF8BAAl3aWxkL0dhbWUMAEQARQEADmFuaW1h"
            + "bHMvQW5pbWFsDACEAIUMANgAjQwA2QDaAQATamF2YS9sYW5nL0V4Y2VwdGlvbgwA2wBnDADcAN0M"
            + "AN4A3wwA4ADhBwDLDADiANUMAOMA1wwATQDfAQAXYW5pbWFscy9Cb3lXaG9DcmllZFdvbGYMAOQA"
            + "zwwA5QDmDADnAOgMAOkAcwcA6gwA6wDsDADtAN0MAO4AcwwA7wBzDADwAHMMAPEAzwEABjxodG1s"
            + "PgEAF2phdmEvbGFuZy9TdHJpbmdCdWlsZGVyDADyAPMBAAwmbmJzcDsmbmJzcDsMAH8AgAwA8gD0"
            + "AQAGJm5ic3A7AQAEPGJyPgEABzwvaHRtbD4BABBqYXZhL2xhbmcvT2JqZWN0AQALd2lsZC9HYW1l"
            + "JDEBAA9qYXZhL2xhbmcvQ2xhc3MBACZqYXZhL2xhbmcvUmVmbGVjdGl2ZU9wZXJhdGlvbkV4Y2Vw"
            + "dGlvbgEAE2FuaW1hbHMvQW5pbWFsJE1vdmUBABVhbmltYWxzL0FuaW1hbCRBdHRhY2sBABJqYXZh"
            + "L3V0aWwvSXRlcmF0b3IBABBqYXZhL2xhbmcvU3RyaW5nAQACW0MBAANhZGQBABUoTGphdmEvbGFu"
            + "Zy9PYmplY3Q7KVoBAANnZXQBABUoSSlMamF2YS9sYW5nL09iamVjdDsBAAduZXh0SW50AQAEKEkp"
            + "SQEAB2lzRW1wdHkBAAMoKVoBAAtuZXdJbnN0YW5jZQEAFCgpTGphdmEvbGFuZy9PYmplY3Q7AQAM"
            + "c3Vycm91bmRpbmdzAQAEbW92ZQEAFygpTGFuaW1hbHMvQW5pbWFsJE1vdmU7AQAESE9MRAEAHiRT"
            + "d2l0Y2hNYXAkYW5pbWFscyRBbmltYWwkTW92ZQEAAltJAQAHb3JkaW5hbAEAAygpSQEACGl0ZXJh"
            + "dG9yAQAWKClMamF2YS91dGlsL0l0ZXJhdG9yOwEAB2hhc05leHQBAARuZXh0AQAGcmVtb3ZlAQAG"
            + "bGV0dGVyAQABQwEABWZpZ2h0AQAaKEMpTGFuaW1hbHMvQW5pbWFsJEF0dGFjazsBAAdTVUlDSURF"
            + "AQAOamF2YS9sYW5nL01hdGgBAAZyYW5kb20BAAMoKUQBACAkU3dpdGNoTWFwJGFuaW1hbHMkQW5p"
            + "bWFsJEF0dGFjawEABVBBUEVSAQAIU0NJU1NPUlMBAARST0NLAQAKaXNJbnN0YW5jZQEABmFwcGVu"
            + "ZAEALShMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9TdHJpbmdCdWlsZGVyOwEAHChDKUxq"
            + "YXZhL2xhbmcvU3RyaW5nQnVpbGRlcjsAIQASADkAAAADAAIAPAA9AAEAPgAAAAIAPwASAEAAQQAA"
            + "ABQAQgBDAAAACAAEAEQARQABAEYAAADtAAMABAAAAF8qtwABKrsAAlm3AAO1AAQqG7UABSq7AAZZ"
            + "twAHtQAIAz0cG6IAOyq0AAi7AAZZtwAHtgAJVwM+HRuiAB8qtAAIHLYACsAABrsABlm3AAe2AAlX"
            + "hAMBp//ihAIBp//GsQAAAAMARwAAAC4ACwAAABEABAAOAA8AEgAUABMAHwAUACYAFQA1ABYAPAAX"
            + "AFIAFgBYABQAXgAaAEgAAAAqAAQANwAhAEkAQwADACEAPQBKAEMAAgAAAF8ASwBMAAAAAABfAE0A"
            + "QwABAE4AAAAYAAT/ACEAAwcATwEBAAD8ABUB+gAg+gAFAAQAUABRAAIARgAAARwAAgAGAAAAXRye"
            + "AFsqtAAEKrQABbYACz4qtAAEKrQABbYACzYEKrQACB22AArAAAYVBLYACsAABrYADJkAJiq0AAgd"
            + "tgAKwAAGFQS2AArAAAYrtgANtgAJV6cABToFhAL/p/+nsQACADYAUQBUAA4ANgBRAFQADwAEAEcA"
            + "AAAmAAkAAAAdAAQAHgAQAB8AHQAgADYAIQBRACIAVgAjAFkAJQBcACYASAAAAD4ABgBWAAAAUgBT"
            + "AAUAEABJAFQAQwADAB0APABVAEMABAAAAF0ASwBMAAAAAABdAFYAVwABAAAAXQBYAEMAAgBZAAAA"
            + "DAABAAAAXQBWAFoAAQBOAAAAGwAFAP8AUwAFBwBPBwBbAQEBAAEHAFwB+QACAgA+AAAAAgBdAAQA"
            + "XgBfAAEARgAAADsAAQABAAAACSq3ABAqtwARsQAAAAIARwAAAA4AAwAAACkABAAqAAgAKwBIAAAA"
            + "DAABAAAACQBLAEwAAAACAGAAXwABAEYAAAJjAAQABwAAAVu7ABJZKrQABbcAE0wDPRwqtAAFogE/"
            + "Az4dKrQABaIBLyq0AAgctgAKwAAGHbYACsAABrYADJoBESq0AAgctgAKwAAGHbYACsAABgO2AArA"
            + "ABQ6BBkEKhwdtwAVtQAWGQS2ABc6BacACjoGsgAZOgWyABoZBbYAGy6qAAAAAAAAzgAAAAEAAAAF"
            + "AAAAJAAAAEsAAABtAAAAjwAAALYrtAAIHARkKrQABWAqtAAFcLYACsAABh22AArAAAYZBLYACVen"
            + "AIYrtAAIHLYACsAABh0EYCq0AAVwtgAKwAAGGQS2AAlXpwBkK7QACBwEYCq0AAVwtgAKwAAGHbYA"
            + "CsAABhkEtgAJV6cAQiu0AAgctgAKwAAGHQRkKrQABWAqtAAFcLYACsAABhkEtgAJV6cAGyu0AAgc"
            + "tgAKwAAGHbYACsAABhkEtgAJV4QDAaf+z4QCAaf+vyortAAItQAIsQABAF4AZQBoABgAAwBHAAAA"
            + "WgAWAAAALgAMAC8AFgAwACAAMQA4ADIAUwAzAF4ANQBlADYAbwA3AJwAOQDAADoAwwA8AOIAPQDl"
            + "AD8BBABAAQcAQgErAEMBLgBFAUYAMAFMAC8BUgBLAVoATABIAAAAUgAIAGoABQBSAGEABgBTAPMA"
            + "YgBjAAQAZQADAGQAZwAFAG8A1wBkAGcABQAYATQASQBDAAMADgFEAEoAQwACAAABWwBLAEwAAAAM"
            + "AU8AaABMAAEATgAAADYADP0ADgcATwH8AAkB/wBPAAUHAE8HAE8BAQcAaQABBwBq/AAGBwBrLCYh"
            + "ISb5ABf6AAX6AAUAAgBsAF8AAQBGAAADuAAFAAwAAAFfKrQACLYAHEwruQAdAQCZAVAruQAeAQDA"
            + "AAZNLLYAHE4tuQAdAQCZATUtuQAeAQDAAAY6BBkEtgAfBKQBHiq0AAQZBLYAH7YACzYFKrQABBkE"
            + "tgAftgALNgYVBRUGn//uGQQVBbYACsAAFDoHGQQVBrYACsAAFDoIGQfBACCZAA4ZBBkItgAhV6f/"
            + "rBkIwQAgmQAOGQQZB7YAIVen/5kZBxkItAAitgAjOgmnAAo6C7IAJDoJGQgZB7QAIrYAIzoKpwAK"
            + "OguyACQ6ChkJGQqmAB0ZBLgAJRQAJpeeAAgZB6cABRkItgAhV6cAbbIAKBkJtgApLqoAAAAAAABh"
            + "AAAAAQAAAAMAAAAcAAAANAAAAEwZBBkKsgAqpgAIGQenAAUZCLYAIVenADAZBBkKsgArpgAIGQen"
            + "AAUZCLYAIVenABgZBBkKsgAspgAIGQenAAUZCLYAIVen/t+n/sin/q2xAAIAngCqAK0AGAC0AMAA"
            + "wwAYAAQARwAAAHYAHQAAAE8AGwBQADQAUQA9AFMASwBUAGAAVgBsAFcAeABZAIAAWgCIAFsAiwBc"
            + "AJMAXQCbAF4AngBiAKoAYwC0AGQAwABlAMoAZwDRAGgA6wBqARAAbAElAG0BKABvAT0AcAFAAHIB"
            + "VQB2AVgAdwFbAHgBXgB5AEgAAACEAA0ArwAFAFIAYQALAMUABQBSAGEACwBLAQoAbQBDAAUAWQD8"
            + "AG4AQwAGAGwA6QBiAGMABwB4AN0AbwBjAAgAqgADAHAAcwAJALQAoQBwAHMACQDAAAMAdABzAAoA"
            + "ygCLAHQAcwAKADQBJAB1AD0ABAAbAUAAVAA9AAIAAAFfAEsATAAAAFkAAAAWAAIANAEkAHUAdgAE"
            + "ABsBQABUAHcAAgBOAAABFQAa/AAIBwB4/QAXBwB5BwB4/AATBwB5/AAWAf4APwEHAGkHAGkSTgcA"
            + "avwABgcAek4HAGr8AAYHAHpXBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegAC"
            + "BwB5BwBpBiROBwB5/wABAAsHAE8HAHgHAHkHAHgHAHkBAQcAaQcAaQcAegcAegACBwB5BwBpBk4H"
            + "AHn/AAEACwcATwcAeAcAeQcAeAcAeQEBBwBpBwBpBwB6BwB6AAIHAHkHAGkGTgcAef8AAQALBwBP"
            + "BwB4BwB5BwB4BwB5AQEHAGkHAGkHAHoHAHoAAgcAeQcAaf8AAwAFBwBPBwB4BwB5BwB4BwB5AAD6"
            + "AAL5AAL6AAIABAB7AHwAAQBGAAABNgACAAkAAABvAz0qtAAItgAcTi25AB0BAJkAXS25AB4BAMAA"
            + "BjoEGQS2ABw6BRkFuQAdAQCZAD4ZBbkAHgEAwAAGOgYZBrYAHDoHGQe5AB0BAJkAHhkHuQAeAQDA"
            + "ABQ6CCsZCLYALZkABoQCAaf/3qf/vqf/oBysAAAABABHAAAAKgAKAAAAfAACAH0AHgB+ADsAfwBY"
            + "AIAAYQCBAGQAggBnAIMAagCEAG0AhQBIAAAAPgAGAFgADABiAGMACAA7ACwAdQA9AAYAHgBMAFQA"
            + "PQAEAAAAbwBLAEwAAAAAAG8AfQBXAAEAAgBtAH4AQwACAFkAAAAWAAIAOwAsAHUAdgAGAB4ATABU"
            + "AHcABABOAAAAJQAH/QAKAQcAeP0AGgcAeQcAeP0AHAcAeQcAeCH5AAL5AAL6AAIAAQB/AIAAAQBG"
            + "AAABWwADAAYAAACqEi5MKrQACLYAHE0suQAdAQCZAIUsuQAeAQDAAAZOLbYAHDoEGQS5AB0BAJkA"
            + "VBkEuQAeAQDAAAY6BRkFtgAMmQAauwAvWbcAMCu2ADESMrYAMbYAM0ynACa7AC9ZtwAwK7YAMRkF"
            + "A7YACsAAFLQAIrYANBI1tgAxtgAzTKf/qLsAL1m3ADArtgAxEja2ADG2ADNMp/94uwAvWbcAMCu2"
            + "ADESN7YAMbYAM7AAAAAEAEcAAAAqAAoAAACJAAMAigAeAIsAOgCMAEIAjQBZAI8AfACQAH8AkQCT"
            + "AJIAlgCTAEgAAAAqAAQAOgBCAHUAPQAFAB4AdQBUAD0AAwAAAKoASwBMAAAAAwCnAIEAggABAFkA"
            + "AAAWAAIAOgBCAHUAdgAFAB4AdQBUAHcAAwBOAAAAIwAG/QALBwCDBwB4/QAYBwB5BwB4/AA0BwB5"
            + "+gAi+gAC+QAWAAIAhACFAAEARgAAAdAABAALAAAApQYGxQA4Ak4CNgQVBASjAJYCNgUVBQSjAIcV"
            + "BARgNgYVBQRgNgcbFQRgKrQABWAqtAAFcDYIHBUFYCq0AAVgKrQABXA2CSq0AAgbFQRgKrQABWAq"
            + "tAAFcLYACsAABhwVBWAqtAAFYCq0AAVwtgAKwAAGOgotFQQEYDIVBQRgGQq2AAyZAAgQIKcADxkK"
            + "A7YACsAAFLQAIlWEBQGn/3mEBAGn/2otsAAAAAQARwAAADIADAAAAJcABwCYABAAmQAZAJoAHwCb"
            + "ACUAnAA1AJ0ARQCeAHMAnwCXAJkAnQCYAKMAogBIAAAAcAALAB8AeACGAEMABgAlAHIAhwBDAAcA"
            + "NQBiAIgAQwAIAEUAUgCJAEMACQBzACQAdQA9AAoAEwCKAIoAQwAFAAoAmQCLAEMABAAAAKUASwBM"
            + "AAAAAAClAEoAQwABAAAApQBJAEMAAgAHAJ4AjACNAAMAWQAAAAwAAQBzACQAdQB2AAoATgAAAFkA"
            + "Bv0ACgcAOAH8AAgB/wB2AAsHAE8BAQcAOAEBAQEBAQcAeQACBwCOAf8ACwALBwBPAQEHADgBAQEB"
            + "AQEHAHkAAwcAjgEB/wAGAAUHAE8BAQcAOAEAAPoABQACAI8AAAACAJAAOwAAABoAAwA6ABIAABAI"
            + "AGUAFABmQBkAcQAUAHJAGQ==";
}

예, JDK를 실행해야하지만 문제가되지는 않습니다.


1
젠장, 넌 날 이겼어 이 정확한 전술로 SabotageAgentWolf를 작업하고있었습니다.
mackthehobbit

1
이 수업은 무엇을합니까?
justhalf

3
@justhalf 바닥 근처 base64로 인코딩 된 파일로 Game 클래스를 재정의합니다. 해당 파일에는 검사 인스턴스가 있습니다. 그것이 나의 늑대라면, 다른 사람은 항상 죽습니다.
14mRh4X0r

1
나는 다른 모든 동물들이 자살하고 HypnoWolf라고 부르기 위해이 메커니즘을 정확히 사용해야한다는 생각을 가지고있었습니다. 나는 그것을 올바르게 운영하지 못했지만 당신은 존중했습니다!
Francois Bourgeois

12

와이 온

예상 값에서 가능한 한 오래 생존하기 위해 가능한 한 적은 노력을 기울입니다. 그것은 사자와 평행을 이루려고 시도합니다 (어떤 것이 보이는지에 관계없이).

늑대는 예측할 수 없기 때문에 무시합니다. 늑대가 발생하면 약 절반의 전투에서 승리해야합니다 (패턴 일치를 시도하지 않으면 최적입니다). 내 늑대는 절대 서로 싸우지 말아야합니다. 그것이 사자를 만나면 (아마도 안된다) 싸움의 약 3/4을 승리해야합니다. 곰과 바위는 항상 져야합니다.

다른 전략을 사용하여 시뮬레이션에 늑대가 있다고 가정하면 늑대를 만날 가능성이 50 %이므로 늑대를 피하는 것이 좋습니다. 평균적으로 이것은 다른 전략뿐만 아니라 최소한 수행해야합니다.

규칙을 올바르게 이해했다면 이것이 최적의 전략이어야합니다.

package animals;
import java.util.Random;

public class Wion extends Animal {
    private boolean down;
    public Wion() { super('W'); down=true;}
    public Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return Attack.SCISSORS;
            case 'S':
                return Attack.PAPER;
            default:
                Random rn = new Random();
                int i = Math.abs(rn.nextInt() % 4);
                while (i==3) {i = Math.abs(rn.nextInt() % 4);}
                return Attack.values()[i];
        }
    }
    public Move move() {
        down=!down;
        if(!down) { return Move.DOWN; }
        return Move.RIGHT;
    }
}

솔직히 이것이 테스트 실행에서 왜 그렇게 좋지 않은지 모르겠습니다. 종이에는 좋지만 실제로는 EmoWolf와 거의 비슷합니다 :(
Geobits

@ Geobits TBH는 실제로 테스트하지 않았습니다. 나는 규칙 중 하나를 잘못 이해하거나 실수를했거나 늑대에 대한 내 무작위 공격이 균일하지 않습니다.
Tim Seguine

@Geobits 나는 공격 논리를 교환했다. 내 의심은 어쩌면 때때로 자살 한 것일 수도 있습니다.
Tim Seguine

1
@ justhalf 예, 나는 이미 문제가 무엇인지 깨달았습니다. 저의 추론은 다른 종류의 늑대로 구성된 집단에서만 가능합니다. 이러한 경우 다른 늑대의 조우 율은 나의 것과 거의 같은 비율로 증가 / 감소합니다. 그러나 다중 품종의 경우, 다른 늑대들 사이에서 만남 비율이 증가하면 평균적으로 비례합니다. 나는 이것을 고치는 최소한의 방법을 생각하고 있지만 불행히도 현재 더 집중해야 할 다른 중요한 것들이 있습니다.
Tim Seguine

1
그러나 다른 늑대 품종이 하나라도 있다면이 방법이 최적이라는 데 동의합니다.
justhalf

12

집단 기억을 가진 늑대

R의 늑대 팩

이 늑대 팩의 아이디어는 살아 있거나 죽은 사람을 기억하고 죽은 늑대와 살아있는 늑대가 공격으로 사용한 것을 확인하고 그에 따라 선택 확률을 변경한다는 것입니다.

R 코드는 다음과 같습니다.

infile <- file("stdin")
open(infile)
repeat{
    input <- readLines(infile,1)
    type <- substr(input,1,1)
    id <- substr(input,2,3)
    if(nchar(input)>3){
        info <- substr(input,4,nchar(input))
    }else{
        info <- NULL
    }
    attack <- function(id,info){
        if(info%in%c("B","L")){choice <- "S"}
        if(info=="S"){choice <- "P"}
        if(info=="W"){
            if(exists("memory")){
                dead <- memory$ID[memory$Status=="Dead"]
                veteran <- memory[memory$Attack!="" & !is.na(memory$Attack), ]
                if(nrow(veteran[!is.na(veteran[,1]),])>0){
                    deadvet<-veteran[veteran$ID%in%dead,]
                    deadvet<-unlist(lapply(split(deadvet,deadvet$ID),function(x)tail(x$Attack,1)))
                    deadvet <- table(factor(deadvet,levels=c("R","P","S","")))
                    livevet <- table(factor(veteran$Attack,levels=c("R","P","S","")))-deadvet
                    probR <- (1+livevet['R'])/(1+livevet['R']+deadvet['R'])
                    probS <- (1+livevet['S'])/(1+livevet['S']+deadvet['S'])
                    probP <- (1+livevet['P'])/(1+livevet['P']+deadvet['P'])
                    choice <- sample(c("S","P","R"),1,prob=c(probS,probP,probR))
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }else{
                    choice <- sample(c("S","P","R"),1)
                    memory <- rbind(memory, data.frame(ID=id, Status="Alive", Attack=choice))
                }
            }else{
                choice <- sample(c("S","P","R"),1)
                memory <- data.frame(ID=id, Status="Alive", Attack=choice)
            }
        }
        paste(choice,id,sep="")
    }
    move <- function(id,info){
        choice <- "H"
        paste(choice,id,sep="")
    }
    initialize <- function(id){
        if(exists("memory")){
            memory <- rbind(memory,data.frame(ID=id,Status="Alive",Attack=""))
        }else{
            memory <- data.frame(ID=id,Status="Alive",Attack="")
        }
        confirmed_dead <- memory$ID[memory$Status=="Dead"]
        last_seen <- memory[!memory$ID%in%confirmed_dead,]
        last_seen <- last_seen[last_seen$Attack=="",]
        lid <- table(last_seen$ID)
        turns <- max(lid)
        dead <- lid[lid<(turns-1)]
        if(length(dead)>0){
            dead_id <- names(dead)
            for(i in dead_id){
                memory <- rbind(memory, data.frame(ID=i, Status="Dead", Attack=""))
            }
        }
        paste("K",id,sep="")
    }
    result <- switch(type,"A"=attack(id,info),"M"= move(id,info),"S"=initialize(id))
    cat(result,"\n",sep="")
    flush(stdout())
}

WolfCollectiveMemory를 사용자 정의 이름으로 사용하고 "Rscript WolfCollectiveMemory.R"을 호출로 사용하여 @ProgrammerDan 랩퍼 (감사합니다!)를 사용합니다.


몇 가지-첫째, 출력이 플러시되지 않는다고 확신합니다. 둘째, 랩퍼가 프로세스를 호출하면 계속 실행 됩니다. 현재 디자인에서는 통신이 늑대에게 전송 될 때마다 프로세스가 호출되는 것으로 가정합니다. 프로세스 호출 측면에서 너무 비쌌을 것이므로 프로세스를 시작하고 통신 채널을 열어 둡니다. 따라서에는 계속해서 라인을 읽고 stdin에 대한 응답으로 라인을 쓰는 메인 루프가 있어야 stdout합니다 flush.console(). [계속]
ProgrammerDan

[cont] 시뮬레이션이 끝나면 프로세스 래퍼가 자식 프로세스를 종료해야합니다.
ProgrammerDan

@Rusher @plannapus 'R 제출을위한 유효한 래퍼 의 요지 가 있습니다. R. Install을 다운로드하려면 여기이동하십시오 . R의 bin폴더를 PATH 변수 또는 이와 동등한 것으로 추가 하면 좋을 것입니다.
ProgrammerDan

범인이 readlines명령 이라고 생각합니다 . readline또는 equiv를 사용해보십시오 . readlinesEOF까지 차단됩니다.
ProgrammerDan

방금 이전에 추가 readLines했습니다 scan. readLines두 번째 인수 1는 첫 번째 줄 바꿈 문자에서 중지해야 함을 의미합니다.
plannapus

12

모방 울프

이 늑대의 목표는 다른 늑대를 모방하는 것입니다. 늑대가 그 능력을 최대한 발휘하는 것을 발견합니다. MimicWolf는 다음과 같은 질문을하지 않습니다 : 늑대 / 곰 / 사자 / 돌을 어떻게 피할 수 있습니까?

아니요, MimicWolf는 다음과 같은 질문을합니다. 늑대는 어디에서 따라야합니까? 내가 따르는 늑대는 어디로 갈 것이라고 생각합니까? 내가 따라온 늑대가 다른 늑대인가요? 내가 따라 간 늑대는 어디로 갔습니까?

나는 그 질문들 대부분이 아직 잘 풀리지 않았다는 것을 인정할 것이지만, 현재로서는 MimicWolf에 대한 나의 제출이있다.

   package animals;
   import java.util.*;

public class MimicWolf extends Animal {

final int TURN_MEMORY = 5;

Random rand = new Random();

Animal.Move lastMove = Animal.Move.UP;

boolean mimicingWolf = false;

Pos[] wolfPreviousPos = new Pos[TURN_MEMORY];
RelativePos[] relativePositions = new RelativePos[TURN_MEMORY];
Move[] wolfPreviousMove = new Move[TURN_MEMORY - 1];

int turnsWithLostWolf = 0;

public MimicWolf() {
    super('W');
}

public Animal.Attack fight(char c) {
    switch (c) {
        case 'B':
            return Animal.Attack.SCISSORS;
        case 'L':
            return Animal.Attack.SCISSORS;
        case 'S':
            return Animal.Attack.PAPER;
        default:
            int x = rand.nextInt(4);
            return Animal.Attack.values()[x];
    }
}

public Animal.Move move() {
    Pos wolfPos = null;
    wolfPos = lookForSurroundingWolf();

    if (turnsWithLostWolf == 4) {
        mimicingWolf = false;
        wolfPreviousPos = new Pos[5];
        relativePositions = new RelativePos[5];
        turnsWithLostWolf = 0;
    }

    if (mimicingWolf) {
        int indexOfLastMove = 0;
        for (int i = 0; wolfPreviousPos[i] != null && i < wolfPreviousPos.length; i++) {
            indexOfLastMove = i;
        }

        //is wolf still visible??
        Pos wolfNewPos = isWolfVisible(wolfPreviousPos[indexOfLastMove]);
        if (wolfNewPos.x == -1) {//wolf is not visible
            turnsWithLostWolf++;
            return moveOppositeDirection(lastMove);
        } else {
            return mimicWolf(wolfNewPos, indexOfLastMove); //need Better way to mimic
        }
    } else {
        //check if new wolf around
        if (wolfPos.x == -1) {
            return searchForWolf();
        } else {
            mimicingWolf = true;
            return mimicWolf(wolfPos, 0);
        }
    }
}

private Animal.Move searchForWolf() {
    Animal.Move newMove = null;
    while (newMove == null || newMove == lastMove) {
        newMove = Animal.Move.values()[rand.nextInt(3)];
    }

    lastMove = newMove;
    return newMove;
}

private Pos lookForSurroundingWolf() {
    for (Integer i = 0; i < surroundings.length; i++) {
        for (Integer j = 0; j < surroundings[0].length; j++) {
            if (i == 1 && j == 1) {
                //this is myself >.<
            } else if (surroundings[i][j] == 'W') {
                return new Pos(i, j);
            }
        }
    }

    return new Pos(-1, -1);
}

/*
    for mimicWolf when movesMimiced == 1 or 2 this is the base case, Any
    number greater the wolf will attempt to mimic the next move based on pattern
    of previous moves
        we assume that we are following the same wolf as last time
 */

private Animal.Move mimicWolf(Pos wolfCurrentPos, int movesMimiced) {
    wolfPreviousPos[movesMimiced] = wolfCurrentPos;
    insertToRelativePos(wolfCurrentPos, movesMimiced);
    if (movesMimiced == 0) {
        Move m1 = null, m2 = null;
        if (wolfPreviousPos[0].x == 0) {
            m1 = Move.LEFT;
        } else if (wolfPreviousPos[0].x == 2) {
            m1 = Move.RIGHT;
        }

        if (wolfPreviousPos[0].y == 0) {
            m2 = Move.UP;
        } else if (wolfPreviousPos[0].y == 2) {
            m2 = Move.DOWN;
        }

        return randOfMoves(m1, m2); //guess which way to go
    }
    wolfPreviousMove[movesMimiced - 1] =  getDirection(wolfPreviousPos[movesMimiced - 1], wolfPreviousPos[movesMimiced]);
    if (movesMimiced == 1) {
        //if pos 1 was a cornor
        if(relativePositions[0] == RelativePos.CORNER){
            if(relativePositions[1] == RelativePos.CORNER){
                if(wolfPreviousPos[0].equals(wolfPreviousPos[1])){
                    return lastMove;
                }
                return moveOppositeDirection(lastMove);
            }
            else if(relativePositions[1] == RelativePos.EDGE){
                return Move.HOLD; //he held so i will hold
            }
        }else if(relativePositions[1] == RelativePos.EDGE){
            if(relativePositions[1] == RelativePos.EDGE){
                return lastMove;
            }
            else if(relativePositions[1] == RelativePos.CORNER){
                //only possibility is that I held, and he moved
                return wolfPreviousMove[0];
            }
        }
    } else {
        //Return most common move the wolf I am copying has made
        int[] mostCommonMoveArr = {0,0,0,0,0};
        for(int i = 0; i <= movesMimiced; i++){
            switch(wolfPreviousMove[i]){
                case UP:
                    mostCommonMoveArr[0]++;
                case RIGHT:
                    mostCommonMoveArr[1]++;
                case DOWN:
                    mostCommonMoveArr[2]++;
                case LEFT:
                    mostCommonMoveArr[3]++;
                case HOLD:
                    mostCommonMoveArr[4]++;
            }
        }

        int maxValue = -1;
        int maxLocal = 0;
        for(int i = 0; i < 5; i++){
            if(mostCommonMoveArr[i] > maxValue)
                maxValue =  mostCommonMoveArr[i];
                maxLocal = i;
        }

        return Move.values()[maxLocal];
    }

    return Move.HOLD; //shouldn't happen
}

private Pos isWolfVisible(Pos lastPos) {
    Pos mimicedWolfPos = lookForSurroundingWolf();
    while (mimicedWolfPos.x != -1 && mimicedWolfPos.y != -1) {
        //did we find the wolf?
        if (lastPos.x == mimicedWolfPos.x || lastPos.y == mimicedWolfPos.y) {
            return mimicedWolfPos;
        }

        surroundings[mimicedWolfPos.x][mimicedWolfPos.y] = ' ';
        mimicedWolfPos = lookForSurroundingWolf();
    }

    return new Pos(-1, -1);
}

private Animal.Move moveOppositeDirection(Move m) {
    switch (m) {
        case UP:
            return Move.DOWN;
        case RIGHT:
            return Move.LEFT;
        case DOWN:
            return Move.UP;
        case LEFT:
            return Move.RIGHT;
        case HOLD:
            return Move.LEFT; //No idea why this would happen but whatever
        default:
            return Move.HOLD;
    }
}

private Animal.Move getDirection(Pos firstPos, Pos secondPos){
    if(firstPos.equals(secondPos))
        return Move.HOLD;
    if(firstPos.x == secondPos.x){
        if(firstPos.y > secondPos.y)
            return Move.UP;
        return Move.DOWN;
    }
    if(firstPos.x > secondPos.x)
        return Move.RIGHT;
    return Move.LEFT;
}


private Animal.Move randOfMoves(Move m1, Move m2) {
    if (m1 == null) {
        return m2;
    } else if (m2 == null) {
        return m1;
    }

    int r = rand.nextInt(2);
    if (r == 0) {
        return m1;
    }
    return m2;
}

private class Pos {
    int x;
    int y;

    protected Pos(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object obj){
        Pos pos = (Pos) obj;
        return (this.x == pos.x && this.y == pos.y);
    }
}

private void insertToRelativePos(Pos pos, int posToAdd){
    if(pos.x == 1 || pos.y == 1){
        relativePositions[posToAdd] = RelativePos.EDGE;
    }else{
        relativePositions[posToAdd] = RelativePos.CORNER;
    }
}

private enum RelativePos{
    CORNER, EDGE
}
}

편집 : 더 나은 모방 시스템을 추가했습니다. 늑대는 계속 움직이면서 현재 어떤 것도 피하려고하지 않기 때문에 여전히 좋지 않습니다.


12

입장은 아니지만 대부분의 늑대는 정지되어 있기 때문에 실제로 보는 것이 지루하므로 야생에 자연 재해를 추가했습니다.

지진!

시간의 약 5 %에서 지진은 임의의 크기로 발생하며 100은 최고, 20은 최저입니다. 이것은 earthquakeCounter지진 후 시간이 지남에 따라 지수가 감소 하도록 설정합니다 .

지진은 어떻게 되나요?

모든 동물은의 가치에 따라 무작위로 움직일 수 earthquakeCounter있습니다. 따라서 값이 75 인 경우 동물 (돌 포함)의 약 75 %가 임의의 방향으로 무작위로 이동합니다 (균등하게 분포).

이것은 놀랍지 않게도 많은 동물을 죽이기 때문에 몇 번의 실험 후에 최대 값은 보통 약 50 마리입니다.

또한 지진은 GUI에 표시되며 크기에 따라 다릅니다.

지진이 보이지 않습니다!

지진이 발생할 확률은 5 %에 ​​불과합니다.

그러나 걱정하지 마십시오! 나는 또한 "지진!" 편안한 공간에서 모든 늑대를 조금씩 움직일 수 있도록 GUI의 버튼클릭 하십시오.

스크린 샷은 다음과 같습니다.

지진

코드는 다음과 같습니다.

Wild.java

main() 기능 (속도를 높이기 위해 처음 100 번 반복 할 때 GUI를 건너 뛰도록 업데이트 됨) :

public static void main(String[] args) {

    int size = Math.round((float)Math.sqrt(classes.length+3)*20);
    final Game game = new Game(size);

    Statistics stats = new Statistics(game, classes);

    String[] colors = generateColors(classes.length);
    int idx = 0;
    for(Class c : classes){
        Animal.setColor(c, colors[idx]);
        idx++;
        game.populate(c, 100);
    }
    stats.update();

    JFrame gui = new JFrame();
    Container pane = gui.getContentPane();

    JLabel boardLabel = new JLabel();
    boardLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    boardLabel.setText(game.toString());
    pane.add(boardLabel, BorderLayout.WEST);

    JLabel statsLabel = new JLabel();
    statsLabel.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 12));
    statsLabel.setText(stats.toString());
    pane.add(statsLabel, BorderLayout.EAST);

    JButton earthquakeButton = new JButton();
    earthquakeButton.addActionListener(new ActionListener(){

        @Override
        public void actionPerformed(ActionEvent e) {
            game.earthquake(true);
        }

    });
    earthquakeButton.setText("Earthquake!");
    pane.add(earthquakeButton, BorderLayout.SOUTH);

    gui.pack();
    gui.setVisible(true);

    for(int i=0; i<100; i++){
        game.iterate();
        stats.update();
    }

    while(true) {
        game.iterate();
        stats.update();
        boardLabel.setText(game.toString());
        statsLabel.setText(stats.toString());
        try { Thread.sleep(100); } catch (InterruptedException e) {}
    }
}

Game.java

package wild;

import animals.Animal;
import java.util.ArrayList;
import java.util.Random;
import animals.Animal.Attack;
import animals.Animal.Move;

public class Game {

    private ArrayList<ArrayList<ArrayList<Animal>>> board;
    private final Random gen = new Random();
    protected final int SIZE;
    private static int earthquakeCounter = 0;

    protected Game(int size) {
        this.SIZE = size;
        board = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            board.add(new ArrayList<ArrayList<Animal>>());
            for (int j = 0; j < size; j++) {
                board.get(i).add(new ArrayList<Animal>());
            }
        }
    }

    protected <T extends Animal> void populate(Class<T> species, int num) {
        while (num > 0) {
            int row = gen.nextInt(SIZE);
            int col = gen.nextInt(SIZE);
            if (board.get(row).get(col).isEmpty()) {
                try { board.get(row).get(col).add(species.newInstance()); } 
                catch (InstantiationException | IllegalAccessException e) {}
                num--;
            }
        }
    }

    protected void iterate() {
        earthquake(false);
        moveAll();
        flatten();
    }

    private void moveAll() {
        Game game = new Game(SIZE);
        for (int i = 0; i < SIZE; i++) {
            for (int j = 0; j < SIZE; j++) {
                if (!board.get(i).get(j).isEmpty()) {
                    Animal a = board.get(i).get(j).get(0);
                    a.surroundings = getArea(i, j);
                    Move aMove;
                    try { aMove = a.move(); } 
                    catch (Exception e) { aMove = Move.HOLD; }
                    if(gen.nextInt(100)<earthquakeCounter){
                        aMove = Move.values()[gen.nextInt(4)];
                    }
                    switch(aMove) {
                        case UP:
                            game.board.get((i-1+SIZE)%SIZE).get(j).add(a);
                            break;
                        case RIGHT:
                            game.board.get(i).get((j+1)%SIZE).add(a);
                            break;
                        case DOWN:
                            game.board.get((i+1)%SIZE).get(j).add(a);
                            break;
                        case LEFT:
                            game.board.get(i).get((j-1+SIZE)%SIZE).add(a);
                            break;
                        case HOLD:
                            game.board.get(i).get(j).add(a);
                            break;
                    }
                }
            }
        }
        board = game.board;
    }

    /**
     * Give a random chance for an earthquake to happen
     */
    protected void earthquake(boolean force){
        if(force || (earthquakeCounter==0 && gen.nextInt(1000)>950)){
            earthquakeCounter = 20+gen.nextInt(80);
        } else {
            earthquakeCounter /= 2;
        }
    }

    private void flatten() {
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                while (cell.size() > 1) {
                    int rand1, rand2;
                    rand1 = gen.nextInt(cell.size());
                    do { rand2 = gen.nextInt(cell.size()); } while (rand1 == rand2);

                    Animal a = cell.get(rand1);
                    Animal b = cell.get(rand2);
                    Attack aTack, bTack;
                    try { aTack = a.fight(b.letter); } 
                    catch (Exception e) { aTack = Attack.SUICIDE; }
                    try {  bTack = b.fight(a.letter); }
                    catch (Exception e) { bTack = Attack.SUICIDE; }

                    if (aTack == bTack) {
                        cell.remove((Animal)(Math.random() > 0.5 ? a : b));
                    } else {
                        switch (aTack) {
                            case ROCK:
                                cell.remove((Animal)(bTack == Attack.PAPER ? a : b));
                                break;
                            case PAPER:
                                cell.remove((Animal)(bTack == Attack.SCISSORS ? a : b));
                                break;
                            case SCISSORS:
                                cell.remove((Animal)(bTack == Attack.ROCK ? a : b));
                                break;
                        }
                    } 
                }
            }
        }
    }

    protected int poll(Class c) {
        int count = 0;
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                for (Animal a : cell) {
                    if(c.isInstance(a))
                        count++;
                }
            }
        }
        return count;
    }

    public String toString() {
        String s = "<html>";
        s += "<span style='background:"+getBackgroundColor()+"'>";
        for (ArrayList<ArrayList<Animal>> row : board) {
            for (ArrayList<Animal> cell : row) {
                if (cell.isEmpty())
                    s += "&nbsp;&nbsp;";
                else
                    s += "<span style='color:"+ Animal.color.get(cell.get(0).getClass()) +"'>" + cell.get(0).letter + "</span>&nbsp;";
            }
            s+="<br>";
        }
        s += "</span>";
        return s + "</html>";
    }

    private String getBackgroundColor(){
        int shade = 255-(int)Math.floor(255*earthquakeCounter/100.0);
        String result = String.format("#%02x%02x%02x", shade, shade, shade);
        return result;
    }

    private char[][] getArea(int i, int j) {
        char[][] area = new char[3][3];
        for(int k = -1; k <= 1; k++) {
            for(int l = -1; l <= 1; l++) {
                int temp1 = k+1;
                int temp2 = l+1;
                int temp3 = (i+k+SIZE)%SIZE;
                int temp4 = (j+l+SIZE)%SIZE;
                ArrayList<Animal> cell = board.get((i+k+SIZE)%SIZE).get((j+l+SIZE)%SIZE);
                area[k+1][l+1] = (char)(cell.isEmpty() ? ' ' : cell.get(0).letter);
            }
        }
        return area;
    }
}

5
어떤 사람들은 단지 세상을보고 싶어합니다 ... 지진
CommonGuy

5
내 모임 늑대가 울고있다.
johnchen902

12

멀티 울프 (자바)

이 늑대는이 프로그래밍 과제에서 다른 늑대에 대해 알고 있습니다. 가능한 경우 애완 동물을 인스턴스화하고 ( '애완 동물') 소유하고있는 모든 늑대 애완 동물에게 가장 인기있는 응답을 선택하여 수행 할 작업을 결정하는 데 사용합니다.

이 늑대는 무한 재귀에 안전해야합니다 (예 : 다른 사람이 비슷한 개념을 구현하는 경우). 다른 동물을 부르는 동안 호출되는 것을 감지하면 Attack.ROCK/ 의 기본 동작을 반환합니다 Move.HOLD.

내 테스트에서 이것은 다양한 결과를 가져 왔습니다. 이것이 허용되는지 확실하지 않습니다. 그러나 그것이 불가능하고 기적이 이겨서 이기게된다면,이기는 타이틀은 "제 2의"늑대에게 전달되어야한다고 생각합니다 – 그것은 단지 공평합니다, 아마도 그 논리를 훔 쳤을 것입니다.

자살을 피합니다.

편집 -나는이 늑대가 제대로 작동하려면 늑대가 참조한 후에로드해야한다고 생각합니다.

package animals;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map.Entry;

public class MultiWolf extends Animal {

    private static final LinkedList<Animal> pets = new LinkedList<>();
    private static boolean inPetCall = false;

    private static void attemptLoadPet(String className) {
        try {
            Object pet = Class.forName(className).newInstance();

            if (pet instanceof Animal) {
                pets.add((Animal) pet);
            }
        } catch (Exception ex) {
            // this wolf is not available
            System.out.println(className + " is not available for MultiWolf cheating.");
        }
    }

    static {
        attemptLoadPet("animals.AlphaWolf");
        attemptLoadPet("animals.CamperWolf");
        attemptLoadPet("animals.GamblerWolf");
        attemptLoadPet("animals.GatheringWolf");
        attemptLoadPet("animals.LazyWolf");
        attemptLoadPet("animals.Sheep");
        attemptLoadPet("animals.Wion");

        attemptLoadPet("animals.MOSHPITFRENZYWolf");
        attemptLoadPet("animals.PassiveAgressiveWolf");
        attemptLoadPet("animals.StoneEatingWolf");
        attemptLoadPet("animals.HerjanWolf");
        attemptLoadPet("animals.HonorWolf");
        attemptLoadPet("animals.MimicWolf");
        attemptLoadPet("animals.LionHunterWolf");
        attemptLoadPet("animals.OmegaWolf");
        attemptLoadPet("animals.WolfWithoutFear");
        attemptLoadPet("animals.WolfRunningWithScissors");
        // attemptLoadPet("animals.SmartWolf");
        // According to Rusher, the above cheating of a non-Java wolf breaks the non-Java-entry wrapper.
        attemptLoadPet("animals.ShadowWolf");
        attemptLoadPet("animals.HybridWolf");
        attemptLoadPet("animals.ProAlpha");
        attemptLoadPet("animals.ForrestWolf");
        attemptLoadPet("animals.WhenIGrowUp");
        attemptLoadPet("animals.MigratingWolf");
        attemptLoadPet("animals.BlindWolf");
    }

    public MultiWolf() {
        super('W');
    }

    @Override
    public Attack fight(char opponent) {
        if (inPetCall) {
            // stop infinite recursion
            return Attack.ROCK;
        }

        inPetCall = true;

        HashMap<Attack, Integer> collect = new HashMap<>();

        collect.put(Attack.ROCK, 0);
        collect.put(Attack.PAPER, 0);
        collect.put(Attack.SCISSORS, 0);
        collect.put(Attack.SUICIDE, -9001);

        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Attack atk = a.fight(opponent);
            collect.put(atk, collect.get(atk)+1);
        }

        int top=0;
        Attack atk=Attack.ROCK;

        for (Entry<Attack, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                atk = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return atk;
    }

    @Override
    public Move move() {
        if (inPetCall) {
            // stop infinite recursion
            return Move.HOLD;
        }

        inPetCall = true;

        HashMap<Move, Integer> collect = new HashMap<>();

        collect.put(Move.DOWN, 0);
        collect.put(Move.HOLD, 0);
        collect.put(Move.LEFT, 0);
        collect.put(Move.RIGHT, 0);
        collect.put(Move.UP, 0);


        for (Animal a : pets) {
            a.surroundings = this.surroundings;
            Move mv = a.move();
            collect.put(mv, collect.get(mv)+1);
        }

        int top=0;
        Move mv=Move.HOLD;

        for (Entry<Move, Integer> ent : collect.entrySet()) {
            if (ent.getValue() > top) {
                mv = ent.getKey();
                top = ent.getValue();
            }
        }

        inPetCall = false;

        return mv;
    }

}

올바르게 기억한다면 정적 필드이기 때문에 Wild.classes를 통해 클래스를 얻을 수 있습니다. 따라서 새 늑대가 게시 될 때마다 늑대를 업데이트 할 필요가 없습니다.)
CommonGuy

사실입니다. 그러나 나는 지금이 방법으로 그것을했을 것입니다. 아마도 떠날 것입니다. 이 늑대로부터 덜이기는 늑대를 제거 할 수도 있습니다. Wion은 매번 뛸 때마다 멸종하는 것처럼 보이며 MultiWolf에서 잘라내어 작업의 품질이 저하되는지 궁금합니다.
OlivierTheOlive

"다른 Wolf 클래스가 작성한 파일을 읽거나 수정할 수 없습니다"규칙은 다른 Wolf 클래스 파일 자체를 포함하기위한 것입니다. 따라서 저는이 아이디어가 훌륭한 아이디어이지만 규칙에 위배된다고 생각합니다.
Runer112

1
@ Runer112 궁금한 점이 있지만 이름으로 클래스를로드하는 방법에 대해 조금 배웠으며 패키지에서 모든 클래스를 찾는 간단한 방법은 없습니다. 약간의 재미
OlivierTheOlive

3
다른 Wolf를 인스턴스화한다고해서 다른 Wolf가 작성한 파일을 읽거나 수정하는 것은 아닙니다. 따라서이 제출은 합법적입니다. 이 규칙은 정적 변수와 같은 것이없고 대신 파일에 써야하는 언어로 작성된 제출물로부터 데이터를 보호하기위한 것입니다.
Rainbolt

12

돌 먹는 늑대

여기 내 제출물이 있습니다. 이 늑대는 주변에 돌, 사자 또는 늑대가 보이지 않으면 그대로 유지됩니다. 그가 돌을보고 다른 늑대 나 사자의 공격을받을 위험이 없다면 그것을 먹으려 고 노력합니다. 그가 위험을 발견하면 도망칩니다!

편집 1 : 위험 알고리즘 감시 개선. 그는 지금 위험에서 더 잘 도망칩니다 :)

package animals;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;


public class StoneEatingWolf extends Animal{

    public StoneEatingWolf() {
        super('W');
    }

    @Override
    public Attack fight(char c) {
        switch (c){
            case 'L': return Attack.SCISSORS;
            case 'B': return Attack.SCISSORS;
            case 'W': return getRandomAttack();
            case 'S': return Attack.PAPER;
            default: return getRandomAttack();
        }
    }

    private Attack getRandomAttack(){
        List<Attack> att = new ArrayList<>();
        att.add(Attack.PAPER);
        att.add(Attack.PAPER);
        att.add(Attack.ROCK);
        att.add(Attack.SCISSORS);
        Collections.shuffle(att);
        return att.get(0);
    }

    @Override
    public Move move() {
        List<Move> m = new ArrayList<>();

        //First see if there is any dangerous animal. If it is, then flee
        if (isThereAnyDangerousAnimal()){
            m.add(Move.UP);
            m.add(Move.RIGHT);
            m.add(Move.LEFT);
            m.add(Move.DOWN);
            getSafeMoves(m);
        }else{
        //No danger: Look for stones to eat
            if (isThereAnimalAtNorth('S')){
                m.add(Move.UP);
            }
            if (isThereAnimalAtEast('S')){
                m.add(Move.RIGHT);
            }
            if (isThereAnimalAtWest('S')){
                m.add(Move.LEFT);
            }
            if (isThereAnimalAtSouth('S')){
                m.add(Move.DOWN);
            }
        }

        if (m.isEmpty()){
            return Move.HOLD;
        } else {
            Collections.shuffle(m);
            return m.get(0);
        }
    }

    private void getSafeMoves(List<Move> lm){

        if (isThereAnimalAtNorth('L') || isThereAnimalAtNorth('W')){
            lm.remove(Move.UP);
        }
        if (isThereAnimalAtEast('L') || isThereAnimalAtEast('W')){
            lm.remove(Move.RIGHT);
        }
        if (isThereAnimalAtSouth('L') || isThereAnimalAtSouth('W')){
            lm.remove(Move.DOWN);
        }
        if (isThereAnimalAtWest('L') || isThereAnimalAtWest('W')){
            lm.remove(Move.LEFT);
        }

    }

    private boolean isThereAnimalAtNorth(char an){
        if (surroundings[0][0] == an || surroundings [0][1] == an || surroundings [0][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtSouth(char an){
        if (surroundings[2][0] == an || surroundings [2][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtEast(char an){
        if (surroundings[0][2] == an || surroundings [1][2] == an || surroundings [2][2] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnimalAtWest(char an){
        if (surroundings[0][0] == an || surroundings [1][0] == an || surroundings [2][0] == an){
            return true;
        }
        return false;
    }

    private boolean isThereAnyDangerousAnimal(){
        if (isThereAnimalAtEast('L') ||
                isThereAnimalAtEast('W') ||
                isThereAnimalAtNorth('L') ||
                isThereAnimalAtNorth('W') ||
                isThereAnimalAtSouth('L') ||
                isThereAnimalAtSouth('W') ||
                isThereAnimalAtWest('L') ||
                isThereAnimalAtWest('W')){
            return true;
        }
        return false;
    }

    }

편집 2 : 일부 통계

내가 실행 한 시뮬레이션에서 StoneEatingWolf를 상위 5-6 늑대로 만들었습니다.

1000 회 반복 40 회 재생 후 평균 결과

나는 Stone Eating Wolves가 암시 된 싸움에 대해 분석합니다. 1000 반복의 40 연극을 실행하면 다음과 같은 결과가 나타납니다.

전투 결과 차트

승리는 Stone Eating Wolf의 승리입니다. 차트는 우리가 이미 알고있는 것을 보여줍니다. 가장 성공적인 늑대는 다른 늑대와 만나지 않는 늑대입니다. 또한 다른 늑대 (마이그레이션 울프)가 내 돌 먹는 사람을 속이는 것을 보았습니다. 나는 그들이 또 다른 늑대를 사냥하기를 바랍니다. 재밌는 게으른 늑대 나 야영 늑대와는 어울리지 않았습니다. 또한 20 번의 런에서받은 공격의 결과입니다 (돌과 곰 제외).

PAPER       447
ROCK        881
SCISSORS    581
SUICIDE     230

ROCK공격에 대한 명백한 편견이있는 것 같습니다 . 이 사실을 알고 늑대를 PAPER좀 더 자주 공격했습니다.


2
범주 형 데이터를 그리는 데 선 그래프를 사용하지 마십시오. 그것은 당신의 그래프를 보면서 너무 많은 암을줍니다.
AJMansfield

@AJMansfield 죄송합니다. 당신이 잘되기를 바랍니다.) 어쨌든 나는 내가 만드는 모든 차트를 고려할 것입니다.
Averroes

아직도 Windows XP를 사용하고 있습니까? oO
justhalf

그리고 왜 ROCK사자와 싸우기 위해 (50 % 승리)를 사용하고 있습니까? 사용하는 것이 가장 좋습니다 SCISSORS(75 % 승리)
justhalf

@justhalf 우리 회사는 여전히 XP를 사용하고 있습니다. 결정된. 감사합니다 :)
Averroes

11

명예 울프

내 늑대는 다른 늑대로부터 도망 치고 있습니다. 도망 치지 못하면 명예로운 싸움을 시작합니다.

package animals;
public class HonorWolf extends Animal {

    private int moves = 0;

    public HonorWolf() { 
        super('W'); 
    }

    @Override   
    public Attack fight(char opponent) { 
        switch(opponent) {
         case 'L':
            return Attack.SCISSORS; 
         case 'B':
            return Attack.SCISSORS;
         case 'S':
            return Attack.PAPER;
        default:
            return Attack.PAPER;
        }
    }

    public Move move() {
        int numWolves = 0, numLions = 0;

        moves++;

        for (int y = 0; y != 3; y++) {
            for (int x = 0; x != 3; x++) {
                if(surroundings[y][x] != ' ') {
                    if(surroundings[y][x] == 'W') {
                        numWolves++;
                    } else if(surroundings[y][x] == 'L') {
                        numLions++;
                    }
                }
            }       
        }

        if (numWolves == 1 && numLions == 0) {
            return Move.HOLD;
        }

        if (surroundings[0][1] == 'L' && moves%2 != 0) {
            return Move.UP;
        } 

        if (surroundings[1][0] == 'L' && moves%2 == 0) {
            return Move.LEFT;
        }

        if (surroundings[0][1] == 'W') {
            if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else {
                return Move.UP;
            }
        }

        if (surroundings[1][0] == 'W') {
            if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.LEFT;
            }
        }

        if (surroundings[1][2] == 'W') {
            if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[2][1] == ' ' || surroundings[2][1] == 'S') {
                return Move.DOWN;
            } else {
                return Move.RIGHT;
            }
        }

        if (surroundings[2][1] == 'W') {
            if (surroundings[0][1] == ' ' || surroundings[0][1] == 'S') {
                return Move.UP;
            } else if (surroundings[1][0] == ' ' || surroundings[1][0] == 'S') {
                return Move.LEFT;
            } else if (surroundings[1][2] == ' ' || surroundings[1][2] == 'S') {
                return Move.RIGHT;
            } else {
                return Move.DOWN;
            }
        }

        return Move.HOLD;
    }
}

프로 알파 울프 공격 전술을 바꿔야합니다. 내가 잡고 있었다 늑대의 공격을 받았습니다 경우) 가위 싸움
일리아 Gazman

11

맹인 늑대

맹인 늑대는 움직이기를 두려워하며 그것이 무엇을 싸우고 있는지 전혀 모른다. 그것이 실제 돌에 결코 닿지 않기 때문에 가장 좋은 확률을 가질 때마다 가위를 재생함으로써 .

package animals;

public class BlindWolf extends Animal {
    public BlindWolf() { super('W'); }

    @Override
    public Attack fight(char c) { 
        return Attack.SCISSORS;
    }

    @Override
    public Move move() {
        return Move.HOLD;
    }
}

11

내가 자랄 때

이 늑대가 자라면 사자가되고 싶어합니다. 따라서 라이온스가 발자취를 따르고 라이온이되는 방법을 배우기 위해 무작위로 걸어 다닙니다.

이 늑대는 사자와 장소를 교환하는 늑대에 대한 카운터로 설계되었습니다.

package animals;

import java.util.Random;

/**
 *
 * @author Quincunx
 */
public class WhenIGrowUp extends Animal {

    Random r;
    boolean following;
    boolean toggle;

    public WhenIGrowUp() {
        super('W');
        r = new Random();
        following = false;
        toggle = false;
    }

    @Override
    public Attack fight(char c) {
        switch (c) {
            case 'B':
                return Attack.SCISSORS;
            case 'L':
            case 'S':
                return Attack.PAPER;
            default:
                return Attack.values()[r.nextInt(4)];
        }
    }

    @Override
    public Move move() {
        if (surroundings[1][2] == 'L') {
            return Move.RIGHT;
        }
        if (surroundings[2][1] == 'L') {
            return Move.DOWN;
        }
        Move direction = Move.values()[r.nextInt(5)];
        out:
        for (int y = 0; y < 3; y++) {
            for (int x = 0; x < 3; x++) {
                if (surroundings[y][x] == 'L') {
                    if (y == 0 && x == 1) {
                        direction = Move.UP;
                    } else if (y == 1 && x == 0) {
                        direction = Move.LEFT;
                    } else {
                        direction = Move.HOLD;
                    }
                    break out;
                }
            }
        }
        return direction;
    }
}

11

스파이 울프

SpyWolf는 적을 감시하고 활동을 기록하여 거리를 유지하면서 모든 사람에게 탭을 유지할 수 있습니다. 발견하고 싶지 않을 것입니다!

package animals;

import static animals.Animal.Attack.*;
import static animals.Animal.Move.*;

import java.awt.Point;
import java.util.*;

public class SpyWolf extends Animal {

    private static final Random r = new Random();
    private static boolean hasTestedPRNG = false;
    private static int PRNG = -1;
    private boolean lionTracker = true;
    private boolean useScissors = false;

    private final ArrayList<MapTile> map = new ArrayList<MapTile>();
    private final Point location = new Point();

    public SpyWolf() {
        super('W');
    }

    @Override
    public Animal.Attack fight(char opponent) {
        switch (opponent) {
            case 'B':
            case 'L':
                return SCISSORS;
            case 'S':
                return PAPER;
            default:
                if (useScissors) {
                    useScissors = false;
                    return SCISSORS;
                }
                return PAPER;
        }
    }

    @Override
    public Animal.Move move() {

        Move m = HOLD;

        if (!hasTestedPRNG) {
            hasTestedPRNG = true;
            double d = 0;
            for (int i = 0; i < 100; i++)
                d += Math.random();
            if (d > 99) {
                PRNG = 1;
            } else if (d > 30 && d < 70) PRNG = 0;
        }

        lionTracker = !lionTracker;
        boolean adj = false;

        updateMap();

        scan: {
            if (PRNG < 1) {
                if (look(LEFT) == 'L' && !lionTracker) {
                    useScissors = true;
                    m = LEFT;
                    break scan;
                }

                if (look(UP) == 'L' & lionTracker) {
                    useScissors = true;
                    m = UP;
                    break scan;
                }
            }

            int x = 0, y = 0;
            ArrayList<Move> moves = new ArrayList<Move>(4);

            for (Move i : Move.values())
                moves.add(i);

            if (look(UP) == 'W') {
                y += 54;
                moves.remove(UP);
                adj = true;
            }
            if (look(DOWN) == 'W') {
                y -= 54;
                moves.remove(DOWN);
                adj = true;
            }
            if (look(LEFT) == 'W') {
                x += 54;
                moves.remove(LEFT);
                adj = true;
            }
            if (look(RIGHT) == 'W') {
                x -= 54;
                moves.remove(RIGHT);
                adj = true;
            }

            if (moves.isEmpty() || !adj) break scan;

            for (MapTile t : map) {
                if (t.x >= location.x - 2 && t.x <= location.x + 2 && t.y >= location.y - 2 && t.y <= location.y + 2 && t.d) {
                    int dist = Math.abs(t.x - location.x) + Math.abs(t.y - location.y);
                    y += t.y > location.y ? -60 / dist : 60 / dist;
                    x += t.x < location.x ? 60 / dist : -60 / dist;
                }
            }
            m = moveDir(x, y);
            if (!moves.contains(m)) m = HOLD;
        }
        switch (m) {
            case UP:
                location.y--;
                return m;
            case DOWN:
                location.y++;
                return m;
            case LEFT:
                location.x--;
                return m;
            case RIGHT:
                location.x++;
                return m;
            default:
                return m;
        }
    }

    private void updateMap() {
        for (int y = -1; y < 2; y++)
            xloop: for (int x = -1; x < 2; x++) {
                if (x == 0 && y == 0) continue;
                for (MapTile t : map)
                    if (t.x == x + location.x && t.y == y + location.y) {
                        t.d = surroundings[y + 1][x + 1] == 'W';
                        continue xloop;
                    }
                map.add(new MapTile(x + location.x, y + location.y, surroundings[y + 1][x + 1] == 'W'));
            }
    }

    private Move moveDir(int x, int y) {
        if (x == 0) return y < 0 ? UP : y > 0 ? DOWN : HOLD;
        if (y == 0) return x < 0 ? LEFT : RIGHT;
        if (x < 0) {
            if (y < 0) {
                if (y < x)
                    return UP;
                else if (x < y) return LEFT;
                return r.nextBoolean() ? UP : LEFT;
            } else {
                if (-y < x)
                    return DOWN;
                else if (x < -y) return LEFT;
                return r.nextBoolean() ? DOWN : LEFT;
            }
        }
        if (y < 0) {
            if (y < -x)
                return UP;
            else if (-x < y) return RIGHT;
            return r.nextBoolean() ? UP : RIGHT;
        } else {
            if (y > x)
                return DOWN;
            else if (x < y) return RIGHT;
        return r.nextBoolean() ? DOWN : RIGHT;
        }
    }

    private char look(Move direction) {
        switch (direction) {
            case UP:
                return surroundings[0][1];
            case DOWN:
                return surroundings[2][1];
            case LEFT:
                return surroundings[1][0];
            case RIGHT:
                return surroundings[1][2];
            default:
                return surroundings[1][1];
        }
    }

    private static class MapTile {
        int x, y;
        boolean d;

        MapTile(int x, int y, boolean d) {
            this.x = x;
            this.y = y;
            this.d = d;
        }
    }
}

꽤 잘 지내지 만 그 절름발이 HybridWolf는 너무 칙칙합니다! SpyWolf는 스파이 학교로 돌아가 고급 늑대 방지 기술을 훈련시킬 수 있습니다.


1
당신은 그것을 절름발이라고 부릅니다, 나는 그것을 지능이라고 부릅니다.)
CommonGuy

5
아아! 너무 많은 goto! 그리고 그것들조차없는 언어로!
AJMansfield

9

하이브리드 울프

나는 저항 할 수 없었지만 또 다른 늑대를 만들기 위해서였다. 이것은 다른 좋은 늑대가 할 수있는 공격 / 이동을 선택하기 때문에 (행동이 아닌 코드에서) 매우 다릅니다.
물론 모든 늑대는 좋지만, 나는 가장 많은 것을 의미합니다 :)

package animals;

import java.util.ArrayList;
import java.util.Random;

public class HybridWolf extends Animal{
    private final Class[] classes = {ProAlpha.class, OmegaWolf.class, SpyWolf.class, HerjanWolf.class, DeepWolf.class, ProtoWolf.class};
    private final ArrayList<Animal> wolves = new ArrayList<Animal>(); 

    public HybridWolf() {
        super('W');
        for(Class c: classes) {
            try {
                wolves.add((Animal)c.newInstance());
            } catch (Exception ex) {}
        }
    }

    @Override
    public Attack fight(char opponent) {
        switch(opponent){
        case 'B':
        case 'L':
            return Attack.SCISSORS;
        case 'S': 
            return Attack.PAPER;
        default:
            try {
                int[] attacks = new int[3];
                Attack bestAttack = randomAttack();
                for(Animal wolf : wolves) {
                    wolf.surroundings = this.surroundings;
                    attacks[wolf.fight(opponent).ordinal()]++;
                }
                for(int i =0; i < 5; i++) {
                    if(attacks[i] > attacks[bestAttack.ordinal()]) {
                        bestAttack = Attack.values()[i];
                    }
                }
                return bestAttack;
            } catch (Exception e) {
                return randomAttack();
            }
        }
    }

    @Override
    public Move move() {
        try {
            int[] moves = new int[5];
            Move bestMove = Move.HOLD;
            for(Animal wolf : wolves) {
                wolf.surroundings = this.surroundings;
                moves[wolf.move().ordinal()]++;
            }
            for(int i =0; i < 5; i++) {
                if(moves[i] > moves[bestMove.ordinal()]) {
                    bestMove = Move.values()[i];
                }
            }
            return bestMove;
        } catch (Exception e) {
            return Move.HOLD;
        }
    }

    public Attack randomAttack() {
        Random rand = new Random();
        switch (rand.nextInt(3)){
            case 1: return Attack.SCISSORS;
            case 2: return Attack.ROCK;
            default: return Attack.PAPER;
        }
    }

}

내 테스트는 이전 AlphaWolf보다 점수가 높지만 Omega / Honor / ProAlpha는 때때로 저를 이겼습니다.


이것은 약간 건방진입니다! 그러나 영리한 아이디어. Rusher가 합법적 인 출품작을 결정하기 위해 적용 할 테스트를 알지 못하기 때문에 이것이 어떻게 합법적 인 출품작으로 공정한지 잘 모르겠습니다. 만약 그가 다른 늑대들과 함께 고립 된 시험을한다면이 늑대는 비참하게 실패 할 것이다 : P
Moogie

@Moogie 출품작의 90 %가 합법적입니다. 지금까지 문자를 'W'이외의 것으로 변경 한 항목 또는 다른 언어로 컴파일하는 방법을 알 수 없었던 항목 만 제외했습니다. 채팅에서 그들과 대화하기 때문에 여기에 표시되지 않습니다).
Rainbolt

@Rusher 자신에게 유리하게 확률을 변경하는 항목이 있습니다. 예를 들어 Gambler wolf는 java의 Math.random ()의 난수 생성기를 변경하여 항상 1을 반환합니다! 재미있게도이기는 늑대는 싸움을 피하는 늑대이기 때문에 결과에 거의 영향을 미치지 않습니다!
Moogie

@Moogie GamblerWolf는 합법적 인 제출물입니다. 당신이 옳습니다, 그것은 결과를 많이 바꾸지 않았습니다. 문제가 해결되지 않으면 "좋아요, 이겼지 만 WASN을 포함하지 않으면 결과가 나옵니다."라고 말할 것입니다. 그렇게하면 다른 사람들은 여전히 ​​멸절되지 않을 수 있습니다.
Rainbolt

2
@Moogie 챌린지의 사양에서 특별히 금지 된 것이 없다면 실제로 합법적이며,이 사이트의 전통은 사람들이 답변을 게시 한 후에는 규칙을 변경하지 않는 것입니다.
plannapus

9

에보 울프

당신은 바보 같은 지능적으로 늑대를 설계했습니다! EvoWolf는 DeepWolf 및 HerjanWolf와 같은 다른 늑대와 함께 야생에서 살아 남기 위해 진화해야했습니다.

이 코드는 유전자 알고리즘을 사용하여 최고의 늑대를 진화시킵니다 (Wolves를 훈련시킬 때까지 LionHunterWolf를 보지 못했습니다). 각 동물 / 공격 콤보에 대해 서로 다른 유전자, 안전한 경우 이동 방향 및 주변의 각 동물에 대한 이동 방향입니다. 1000 라운드 후, 가장 높은 턴 수를 지속 한 늑대는 자손을 생산할 확률이 가장 높습니다 (즉, 더 오래 살수록 짝짓기를 할 확률이 높아집니다). 우리는 또한 약 10 %의 아이들에게 무작위로 돌연변이를 일으켜 희망을줍니다.

EvoWolf 코드는 다음과 같습니다. 작업 디렉토리에 evowolf.txt 가 필요 합니다. 현재 세대에 포함되어 있습니다. 원시 임의성에서 자신의 늑대를 진화 시키려면 evowolf.txt를 포함시키지 말고 제공된 것이 현재 최고의 진화입니다. 처음에는 2-3 개만 생존하지만 최대 60 개까지 진화하는 것을 보는 것이 정말 깔끔합니다.

package animals;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;

public class EvoWolf extends Animal {
    public EvoWolf() { super('W'); birth();}
    public Attack fight(char c) { 
        List<Attack> attacks = getAttacks(c);
        if(attacks.size() == 0)
            return Attack.SUICIDE; //Discourage wolves without attacks, Darwin Award

        return attacks.get(random.nextInt(attacks.size()));
    }

    public Move move() {
        ++turns;
        List<Move> moves = new ArrayList<Move>();
        if(isSafe())
            moves = getSafeMoves();
        else
            moves = getThreatenedMoves();

        return (Move)moves.toArray()[random.nextInt(moves.size())];
    }

    /*====STATIC METHODS====*/
    //Shared RNG
    public static Random random = new Random();

    //Collection of 100 sets of genes
    public static String[] genePool = null;

    //Get the genes from disk or randomly generate some
    public static void readGenePool(){
        genePool = new String[100];
        int gIdx = 0;
        try (BufferedReader br = new BufferedReader(new FileReader("evowolf.txt"))){
            String sCurrentLine; 
            while ((sCurrentLine = br.readLine()) != null) {
                genePool[gIdx] = sCurrentLine;
                ++gIdx;
            }
        } catch (IOException e) {

        } 

        //if can't read genes, make some
        if(gIdx < 100){
            primordial(gIdx);
        }
    }
    public static void primordial(int idx){
        for(;idx < 100; ++idx){
            genePool[idx] = getRandomGenes();
        }
    }

    public static String getRandomGenes(){
        StringBuilder sb = new StringBuilder();
        for(int idx = 0; idx < GENE_COUNT; ++idx){
            if(random.nextBoolean())
                sb.append("1");
            else
                sb.append("0");
        }
        return sb.toString();
    }

    //Evolve wolves
    public static void nextGen(){
        //Check survival of current gen
        int survivors = 0;
        for(int idx = 0; idx < 100; ++idx){
            survivors = survivors + (generation[idx].turns == 1000 ? 1 : 0);
        }
        if(survivors > 65)
            writeGenePool(Long.toString(survivors));

        //Weighted resivour sampling
        //Take the highest of r^(1/w) where r is a random an w is the weight
        for(int idx = 0; idx < 100; ++idx){
            genePool[idx] = mateFitWolves();
        }
        writeGenePool("");
        birthCount = 0;
    }

    //Pick two wolves randomly by weighted fitness and mate them
    public static String mateFitWolves(){
        EvoWolf w1 = null;
        double weight1 = -1;
        EvoWolf w2 = null;
        double weight2 = -1;

        for(int idx = 0; idx < 100; ++idx){
            double weight = generation[idx].getWeightSample();
            if(weight > weight1){
                weight2 = weight1;
                w2 = w1;
                weight1 = weight;
                w1 = generation[idx];
            } else if(weight > weight2){
                weight2 = weight;
                w2 = generation[idx];
            }
        }

        return mateFitWolves(w1, w2);
    }

    //Make offspring
    public static String mateFitWolves(EvoWolf w1, EvoWolf w2){
        StringBuilder sb = new StringBuilder();
        //Random splice
        for(int rIdx = 0; rIdx < w1.genes.length(); ++rIdx){
            if(random.nextBoolean())
                sb.append(w1.genes.charAt(rIdx));
            else
                sb.append(w2.genes.charAt(rIdx));
        }


        //Random mutation
        while(random.nextInt(10) == 0){
            int mIdx = random.nextInt(w1.genes.length());
            if(sb.charAt(mIdx) == '0')
                sb.setCharAt(mIdx, '1');
            else
                sb.setCharAt(mIdx, '0');
        }


        return sb.toString();
    }

    //Save the next generation's gene pool back to disk
    public static void writeGenePool(String survivors){
        try {
            String str = "";
            if(!survivors.equals(""))
                str = Long.toString(System.currentTimeMillis());

            File file = new File("evowolf" + survivors + str + ".txt");

            // if file doesn't exists, then create it
            if (!file.exists()) {
                file.createNewFile();
            }

            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bw = new BufferedWriter(fw);
            for(int gIdx = 0; gIdx < genePool.length; ++gIdx){
                bw.write(genePool[gIdx]);
                bw.write('\n');
            }
            bw.close();
        } catch (IOException e) {

        }
    }

    //Keep track of the wolves in this generation
    public static int birthCount = 0;
    public static EvoWolf[] generation = new EvoWolf[100];

    /*====INSTANCE METHODS====*/
    //Populate this wolf from the gene pool
    public void birth(){
        if(genePool == null){
            readGenePool();
        }
        genes = genePool[birthCount];
        generation[birthCount] = this;
        birthCount = (birthCount + 1) % 100;    
    }

    //How long wolf has been alive
    public int turns = 0;

    //Fitness based on how long wolf survived
    public double getWeightSample(){
        return Math.pow(random.nextDouble(), 1.0/turns);
    }


    /*===GENETICS===*/
    public String genes = null;
    //Genes are made up of 182+ bits (stored at a string)
    //Each turns on the possibility of that move or attack in a given situation
    //  Attack: BLSW * RPSX = 16 bits [0-15] = Animal->Attacks
    //  Threatened Moves: BLSW * 12345678 * UDLRH = 160 bits [16-175] = Y -> X -> Animal -> Moves
    //  Safe Moves: UDLRH = 5 bits [176-180] = Moves
    //  Extra: default move [181], move combination [182]
    public static final int GENE_INDEX_ATTACKS = 0;
    public static final int GENE_INDEX_THREATENED_MOVES = GENE_INDEX_ATTACKS + (4 * 4);
    public static final int GENE_INDEX_SAFE_MOVES = GENE_INDEX_THREATENED_MOVES + (8 * 4 * 5);
    public static final int GENE_INDEX_DEFAULT_MOVE = GENE_INDEX_SAFE_MOVES + (5);
    public static final int GENE_INDEX_COMBINE_MOVES = GENE_INDEX_DEFAULT_MOVE + (1);
    public static final int GENE_COUNT = GENE_INDEX_COMBINE_MOVES + 1;
    public static int getAnimalIndex(char c){
        switch (c) {
            case 'B':
                return 0;
            case 'L':
                return 1;
            case 'S':
                return 2;
            case 'W':
            default: //Shouldn't occur but we'll assume it's the dangerous wolf
                return 3;
        } 
    }

    public static int getXYIndex(int x, int y){
        int idx = (y * 3) + x;
        if(idx > 4) //We don't need to look at ourself
            --idx;
        return idx;
    }

    public List<Attack> getAttacks(char c){
        List<Attack> attacks = new ArrayList<Attack>();
        int idx = GENE_INDEX_ATTACKS + getAnimalIndex(c);
        if(genes.charAt(idx + 0) == '1')
            attacks.add(Attack.ROCK);
        if(genes.charAt(idx + 1) == '1')
            attacks.add(Attack.PAPER);
        if(genes.charAt(idx + 2) == '1')
            attacks.add(Attack.SCISSORS);
        /*
        if(genes.charAt(idx + 3) == '1')
            attacks.add(Attack.SUICIDE);
        */
        //Suicide didn't remove itself from the gene pool like I thought so I manually removed it

        return attacks;
    }

    public boolean isSafe(){
        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(surroundings[y][x] != ' ')
                    return false;
            }
        }
        return true;
    }

    public List<Move> getSafeMoves(){
        List<Move> moves = new ArrayList<Move>();
        int idx = GENE_INDEX_SAFE_MOVES;
        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public List<Move> getThreatenedMoves(){
        List<Move> moves = new ArrayList<Move>();
        if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '0')
            moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));

        for(int x = 0; x <= 2; ++x){
            for(int y = 0; y <= 2; ++y){
                if(y == 1 && x == 1)
                    continue;
                if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
                    moves.addAll(getThreatenedMoves(x,y));
                else
                    moves.retainAll(getThreatenedMoves(x,y));
            }
        }

        if(moves.size() == 0){
            if(this.genes.charAt(GENE_INDEX_DEFAULT_MOVE) == '1')
                moves.addAll(EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD));
            else
                moves.add(Move.HOLD);
        }

        return moves;
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y){
        //Lookup what moves we can make for a cell unless it is blank (allow any)
        if(surroundings[y][x] != ' ')
            return getThreatenedMoves(x,y,surroundings[y][x]);
        else if(genes.charAt(GENE_INDEX_COMBINE_MOVES) == '1')
            return EnumSet.noneOf(Move.class);
        else
            return EnumSet.of(Move.UP, Move.DOWN, Move.LEFT, Move.RIGHT, Move.HOLD);
    }

    public EnumSet<Move> getThreatenedMoves(int x, int y, char c){
        int aIdx = getAnimalIndex(c);
        int sIdx = getXYIndex(x,y);
        int idx = GENE_INDEX_THREATENED_MOVES + (sIdx * 20) + (aIdx * 5);

        EnumSet<Move> moves = EnumSet.noneOf(Move.class);

        if(genes.charAt(idx + 0) == '1')
            moves.add(Move.UP);
        if(genes.charAt(idx + 1) == '1')
            moves.add(Move.DOWN);
        if(genes.charAt(idx + 2) == '1')
            moves.add(Move.LEFT);
        if(genes.charAt(idx + 3) == '1')
            moves.add(Move.RIGHT);
        if(genes.charAt(idx + 4) == '1')
            moves.add(Move.HOLD);

        return moves;
    }

    public static String setAt(String str, int index, char replace){     
        if(str==null){
            return str;
        }else if(index<0 || index>=str.length()){
            return str;
        }
        char[] chars = str.toCharArray();
        chars[index] = replace;
        return String.valueOf(chars);       
    }
}

또한 몇 차례의 턴과 세대가지나 갔는지 보여주기 위해 Statistics.java와 Wild.java를 약간 변경했습니다. 1000 턴을 실행 한 후, EvoWolf.nextGen();자손 계산을 위해 전화하십시오 . 자신 만의 세트를 발전시키려는 경우에만 경쟁에 필요하지 않습니다.

모든 파일 편집 : 수정 된 링크

최고로 발전하는 한, 그것은 상위 10 개보다 나아지지 않습니다. 한계의 일부는 이전 움직임에 대한 메모리가 거의 없다는 것입니다. 이전 세대의 경험이 차세대 글로벌 메모리 역할을하는 차세대 기능에 영향을 미친다는 점에서 WolvesWithCollectiveMemory와 같은 기능을 수행합니다. 그래도 재미 있었다. 이전 링크에는 유전자 풀을 분석하는 데 도움이되는 Excel 시트가 있습니다. .txt의 1과 0을 모두 1과 0을 쉼표로 바꾸고 스프레드 시트에 붙여 넣습니다.

흥미로운 메모는 대부분 모든 사람의 전략을 확인합니다.

  • 실제 공격은 전투를 피하는 것보다 덜 중요합니다. 아니면 늑대가 아닌 모든 늑대가 빨리 제거 될 수도 있습니다. 경쟁 세대는 S를 던져야하지만 곰에 대한 RPS 사이의 기회는 균등합니다.
  • 위와 같이 자살을 생각하더라도 진화하지 않았기 때문에 수동으로 자살을 비활성화해야했습니다.
  • 홀딩은 아무도 없을 때 가장 잘 움직입니다.
  • 누군가가있을 때 도망 치는 것도 좋은 것 같습니다
  • 무작위 방향을 옮기는 대신 잡아야합니다 (이 선택은 진화 된 여분의 유전자였습니다)
  • 1 마리 이상의 동물이 주변에있을 때, 각 주변 / 동물에 대한 움직임의 교차점에서 무작위 이동을하는 것이 노조 (다른 여분의 유전자)보다 낫습니다.

8

SmartWolf

결과는 (1000 회 반복)입니다 (이 업데이트를 계속하지만 평균이없는 독립적 인 테스트로 간주합니다. 많은 늑대가 있기 때문에 상당히 느립니다.)

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

편집:

* nix (모노 필요) :

gmcs SmartWolf.cs

윈도우 :

csc SmartWolf.cs

작업 디렉토리로 복사하십시오.

참고 : Windows를 사용 하는 경우 랩퍼 코드 "mono SmartWolf.exe"만으로 "SmartWolf.exe"바꾸어야합니다.

SmartWolf.cs :

using System;
using System.Collections.Generic;
using System.Linq;

namespace SmartWolf
{
    #region Enums
    enum Attack
    {
        Rock, Paper, Scissors, Suicide
    }
    enum Movement
    {
        Up, Down, Left, Right, Hold
    }
    enum Animal
    {
        Stone, Lion, Wolf, Bear, Empty
    }
    #endregion
    class KnowledgeBase
    {
        static Random rnd = new Random();
        public List<KeyValuePair<KeyValuePair<Animal, Attack>, int>> knowledge = new List<KeyValuePair<KeyValuePair<Animal, Attack>, int>>();
        public KnowledgeBase ()
        {
        }
        public void PunishMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, -1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value - 1);
            }

        }
        public void RewardMove (KeyValuePair<Animal, Attack> move)
        {
            if (knowledge.Count (t => t.Key.Key == move.Key && t.Key.Value == move.Value) == 0) {
                knowledge.Add (new KeyValuePair<KeyValuePair<Animal, Attack>, int> (move, 1));
            } else {
                int i = knowledge.FindIndex (t => t.Key.Equals (move));
                knowledge[i] = new KeyValuePair<KeyValuePair<Animal, Attack>, int>(knowledge[i].Key, knowledge[i].Value + 1);
            }
        }
        public Attack GetBestMove (Animal opponent)
        {
            Attack best = GetRandomMove();
            int j = 0;
            foreach (var pair in knowledge) {
                if(pair.Key.Key == opponent && j < pair.Value)
                {
                    best = pair.Key.Value;
                    j = pair.Value;
                }
            }
            if(j < 2)
                return GetRandomMove ();
            return best;
        }
        public static Attack GetRandomMove()
        {
            int r = rnd.Next (3);
            return r == 0 ? Attack.Paper :
                r == 1 ? Attack.Rock :
                    r == 2 ? Attack.Scissors :
                    Attack.Scissors;
        }
    }
    class MainClass
    {
        static KnowledgeBase knowledge = new KnowledgeBase();
        public static void Main (string[] args)
        {
            List<SmartWolf> list = new List<SmartWolf> ();
            List<int> temp = new List<int>();
            int l = 0;
            while (true) {
                string str = Console.ReadLine ();
                int id = int.Parse (str.Substring (1, 2));
                if(str.StartsWith ("S"))
                {
                    list.Add (new SmartWolf(id));
                    Console.WriteLine("K" + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("M"))
                {
                    if(temp.Contains (id))
                    {
                        for(int i = 0; i < 100; i++)
                        {
                            SmartWolf s = list.Where (t => t.ID == i).ToList ()[0];
                            if(s.AttackedInLastRound == 0 && !temp.Contains(i))
                            {
                                s.IsAlive = false;
                                knowledge.PunishMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            } else if(s.AttackedInLastRound == 0 && temp.Contains (i))
                            {
                                knowledge.RewardMove (s.LastMove);
                                s.AttackedInLastRound = -1;
                            }
                            if(s.AttackedInLastRound > 0)
                                s.AttackedInLastRound--;
                        }
                        temp.Clear();
                        l++;
                    }
                    temp.Add (id);

                    Console.WriteLine('H' + id.ToString ().PadLeft (2, '0'));
                } else if(str.StartsWith ("A"))
                {
                    Animal enemy = str[3] == 'W' ? Animal.Wolf :
                                   str[3] == 'L' ? Animal.Lion :
                                   str[3] == 'S' ? Animal.Stone :
                                   str[3] == 'B' ? Animal.Bear : Animal.Empty;
                    Attack atk = knowledge.GetBestMove (enemy);
                    Console.WriteLine((atk == Attack.Paper ? "P" :
                                      atk == Attack.Rock ? "R" : 
                                      atk == Attack.Scissors ? "S" :
                                      "P") + id.ToString ().PadLeft (2, '0'));
                    list.Where (t => t.ID == id).ToList ()[0].AttackedInLastRound = 2;
                    list.Where (t => t.ID == id).ToList ()[0].LastMove = new KeyValuePair<Animal, Attack>(enemy, atk);
                }
            }
        }
    }
    class SmartWolf
    {
        public int ID;
        public bool IsAlive = true;
        public KeyValuePair<Animal, Attack> LastMove = new KeyValuePair<Animal, Attack>(Animal.Empty, Attack.Suicide);
        public int AttackedInLastRound = -1;
        public SmartWolf(int n)
        {
            ID = n;
        }
    }
}

래퍼 (@ProgrammerDan의 신용, 여기에 포함 시키므로 붙여 넣기가 더 쉽습니다) :

package animals;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.OutputStreamWriter;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Remote SmartWolf wrapper class. 
 */
public class SmartWolf extends Animal {
    /**
     * Simple test script that sends some typical commands to the
     * remote process.
     */
    public static void main(String[]args){
        SmartWolf[] wolves = new SmartWolf[100];
        for(int i=0; i<10; i++) {
            wolves[i] = new SmartWolf();
        }
        char map[][] = new char[3][3];
        for (int i=0;i<9;i++)
            map[i/3][i%3]=' ';
        map[1][2] = 'W';
        for(int i=0; i<10; i++) {
            wolves[i].surroundings=map;
            System.out.println(wolves[i].move());
        }
        for(int i=0; i<10; i++) {
            System.out.println(wolves[i].fight('S'));
            System.out.println(wolves[i].fight('B'));
            System.out.println(wolves[i].fight('L'));
            System.out.println(wolves[i].fight('W'));
        }
        wolfProcess.endProcess();
    }
    private static WolfProcess wolfProcess = null;

    private static SmartWolf[] wolves = new SmartWolf[100];
    private static int nWolves = 0;

    private boolean isDead;
    private int id;

    /**
     * Sets up a remote process wolf. Note the static components. Only
     * a single process is generated for all Wolves of this type, new
     * wolves are "initialized" within the remote process, which is
     * maintained alongside the primary process.
     * Note this implementation makes heavy use of threads.
     */
    public SmartWolf() {
        super('W');
        if (SmartWolf.wolfProcess == null) {
            SmartWolf.wolfProcess = new WolfProcess();
            SmartWolf.wolfProcess.start();
        }

        if (SmartWolf.wolfProcess.initWolf(SmartWolf.nWolves, MAP_SIZE)) {
            this.id = SmartWolf.nWolves;
            this.isDead = false;
            SmartWolf.wolves[id] = this;
        } else {
            SmartWolf.wolfProcess.endProcess();
            this.isDead = true;
        }
        SmartWolf.nWolves++;
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, SUICIDE.
     * Otherwise, communicate an attack to the remote process and return
     * its attack choice.
     */
    @Override
    public Attack fight(char opponent) {
        if (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Attack.SUICIDE;
        }
        try {
            Attack atk = SmartWolf.wolfProcess.fight(id, opponent);

            if (atk == Attack.SUICIDE) {
                this.isDead = true;
            }

            return atk;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Attack.SUICIDE;
        }
    }

    /**
     * If the wolf is dead, or all the wolves of this type are dead, HOLD.
     * Otherwise, get a move from the remote process and return that.
     */
    @Override
    public Move move() {
        if (!SmartWolf.wolfProcess.getRunning() || isDead) {
            return Move.HOLD;
        }
        try {
            Move mv = SmartWolf.wolfProcess.move(id, surroundings);

            return mv;
        } catch (Exception e) {
            System.out.printf("Something terrible happened, this wolf has died: %s", e.getMessage());
            isDead = true;
            return Move.HOLD;
        }
    }

    /**
     * The shared static process manager, that synchronizes all communication
     * with the remote process.
     */
    static class WolfProcess extends Thread {
        private Process process;
        private BufferedReader reader;
        private PrintWriter writer;
        private ExecutorService executor;
        private boolean running;

        public boolean getRunning() {
            return running;
        }

        public WolfProcess() {
            process = null;
            reader = null;
            writer = null;
            running = true;
            executor = Executors.newFixedThreadPool(1);
        }

        public void endProcess() {
            running = false;
        }

        /**
         * WolfProcess thread body. Keeps the remote connection alive.
         */
        public void run() {
            try {
                System.out.println("Starting SmartWolf remote process");
                ProcessBuilder pb = new ProcessBuilder("mono SmartWolf.exe".split(" "));
                pb.redirectErrorStream(true);
                process = pb.start();
                System.out.println("SmartWolf process begun");
                // STDOUT of the process.
                reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "UTF-8")); 
                System.out.println("SmartWolf reader stream grabbed");
                // STDIN of the process.
                writer = new PrintWriter(new OutputStreamWriter(process.getOutputStream(), "UTF-8"));
                System.out.println("SmartWolf writer stream grabbed");
                while(running){
                    this.sleep(0);
                }
                reader.close();
                writer.close();
                process.destroy(); // kill it with fire.
                executor.shutdownNow();
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("SmartWolf ended catastrophically.");
            }
        }

        /**
         * Helper that invokes a read with a timeout
         */
        private String getReply(long timeout) throws TimeoutException, ExecutionException, InterruptedException{
            Callable<String> readTask = new Callable<String>() {
                @Override
                public String call() throws Exception {
                    return reader.readLine();
                }
            };

            Future<String> future = executor.submit(readTask);
            return future.get(timeout, TimeUnit.MILLISECONDS);
        }

        /**
         * Sends an initialization command to the remote process
         */
        public synchronized boolean initWolf(int wolf, int map_sz) {
            while(writer == null){
                try {
                this.sleep(0);
                }catch(Exception e){}
            }
            boolean success = false;
            try{
                writer.printf("S%02d%d\n", wolf, map_sz);
                writer.flush();
                String reply = getReply(5000l);
                if (reply != null && reply.length() >= 3 && reply.charAt(0) == 'K') {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        success = true;
                    }
                }
                if (reply == null) {
                    System.out.println("did not get reply");
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to initialize, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to initialize, %s\n", wolf, e.getMessage());
            }
            return success;
        }

        /**
         * Send an ATTACK command to the remote process.
         */
        public synchronized Attack fight(int wolf, char opponent) {
            Attack atk = Attack.SUICIDE;
            try{
                writer.printf("A%02d%c\n", wolf, opponent);
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'R':
                                atk = Attack.ROCK;
                                break;
                            case 'P':
                                atk = Attack.PAPER;
                                break;
                            case 'S':
                                atk = Attack.SCISSORS;
                                break;
                            case 'D':
                                atk = Attack.SUICIDE;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to attack, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to attack, %s\n", wolf, e.getMessage());
            }
            return atk;
        }

        /**
         * Send a MOVE command to the remote process.
         */
        public synchronized Move move(int wolf, char[][] map) {
            Move move = Move.HOLD;
            try{
                writer.printf("M%02d", wolf);
                for (int row=0; row<map.length; row++) {
                    for (int col=0; col<map[row].length; col++) {
                        writer.printf("%c", map[row][col]);
                    }
                }
                writer.print("\n");
                writer.flush();
                String reply = getReply(1000l);
                if (reply.length() >= 3) {
                    int id = Integer.valueOf(reply.substring(1));
                    if (wolf == id) {
                        switch(reply.charAt(0)) {
                            case 'H':
                                move = Move.HOLD;
                                break;
                            case 'U':
                                move = Move.UP;
                                break;
                            case 'L':
                                move = Move.LEFT;
                                break;
                            case 'R':
                                move = Move.RIGHT;
                                break;
                            case 'D':
                                move = Move.DOWN;
                                break;
                        }
                    }
                }
            } catch (TimeoutException ie) {
                endProcess();
                System.out.printf("SmartWolf %d failed to move, timeout\n", wolf);
            } catch (Exception e) {
                endProcess();
                System.out.printf("SmartWolf %d failed to move, %s\n", wolf, e.getMessage());
            }
            return move;
        }
    }
}

그렇게 큰 것은 아니지만, 최고 늑대 중 일부와 함께 1000 회 반복하는 경우 평균 ~ 75 생존율입니다.

솔루션에 ML 접근 방식을 사용합니다.


나는 당신의 늑대가하는 일을 대략 이해했다고 생각하지만, 좀 더 자세히 설명 할 수 있습니까? 또한 당신은 아마 그것이 어떤 언어인지 언급해야 할 것입니다 (대부분의 사람들에게는 분명하지만 저에게는 분명하지 않습니다).
plannapus

C #으로 작성되었으며 지식 유형이 있으며,이 목록에는 동물 유형과 성공률에 대한 각 이동을 나열합니다. 늑대가 공격하고 죽으면 그 이동의 성공률이 감소합니다. 살아남 으면 성공률이 높아집니다. 시스템은 몇 번 (20-30) 회전 한 후 지식 기반에서 임의로 선택하는 대신 이동을 선택하기 시작합니다.
user3188175

1
포장지를 사용하여 반갑습니다! 코드를 컴파일하는 방법과 mono@Rusher가 사용 하는 방법에 대한 지침을 포함해야 합니다.
ProgrammerDan

1
마크 다운에 실패했습니다. 소스를 보면 '#'이 있지만 표제 블록에 있었기 때문에 Markdown은이를 무시했습니다. 결정된. : D
ProgrammerDan

2
참고-@ProgrammerDan의 래퍼로 컴파일하고 성공적으로 실행할 수있었습니다 (이번도 그의 도움없이). 다음 결과가 나옵니다. 지연 돼서 죄송합니다!
Rainbolt

7

패시브 공격적인 늑대 (스칼라 늑대)

처음 500 턴에 가능한 모든 것을 피하여 필드를 깨끗하게 만듭니다. 그런 다음 지정된 범위 내에서 물건을 공격하는 방향으로 나갑니다.

package animals;

import animals._
import scala.util.Random

class PassiveAgressiveWolf extends Animal('W') {

    val myId=PassiveAgressiveWolf.nextId
    var movecounter=0

    def fight(opponent: Char) = {
        PassiveAgressiveWolf.lastopponents(myId-1)=opponent
        opponent match {
            case 'B' => Animal.Attack.SCISSORS
            case 'L' => Animal.Attack.SCISSORS
            case 'S' => Animal.Attack.ROCK
            case _ => Random.shuffle(List(Animal.Attack.SCISSORS, Animal.Attack.ROCK, Animal.Attack.PAPER)).head
        }
    }

    def move = {
        movecounter+=1
        if(movecounter < 500) avoidall else seen match {
            case ('B', pos: Int) => seenbear(pos)
            case ('S', pos: Int) => seenstone(pos)
            case ('L', pos: Int) => seenlion(pos)
            case ('W', pos: Int) => seenwolf(pos)
            case (' ', _) => myDirection
        }
    }

    def myDirection = myId % 4 match {
        case 0 => if(surroundings(0)(1)==' ') Animal.Move.LEFT else randommove
        case 1 => if(surroundings(1)(0)==' ') Animal.Move.DOWN else randommove
        case 2 => if(surroundings(1)(2)==' ') Animal.Move.RIGHT else randommove
        case 3 => if(surroundings(2)(1)==' ') Animal.Move.UP else randommove
    }

    def randommove = Random.shuffle(List(Animal.Move.UP, Animal.Move.LEFT, Animal.Move.RIGHT, Animal.Move.DOWN)).head

    def seen = {
        surroundings(1)(1)=' '
        val surroundingsflat=surroundings.flatten.mkString
        val seenbeasts = for {
            beast <- "BSLW" if surroundingsflat contains beast
        } yield (beast, surroundingsflat.indexOf(beast))
        seenbeasts.headOption.getOrElse((' ', 0))
    }

    def seenbear(pos: Int) = chase(pos)

    def seenstone(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case _ => myDirection
    }

    def seenlion(pos: Int) = pos match {
        case 1 => Animal.Move.LEFT
        case 3 => Animal.Move.UP
        case 5 => Animal.Move.HOLD
        case 7 => Animal.Move.HOLD
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.HOLD
        case 6 => Animal.Move.HOLD
        case 8 => Animal.Move.HOLD
    }

    def seenwolf(pos: Int) = chase(pos)

    def chase(pos: Int) = pos match {
        case 1 => Animal.Move.UP
        case 3 => Animal.Move.LEFT
        case 5 => Animal.Move.RIGHT
        case 7 => Animal.Move.DOWN
        case 0 => Animal.Move.UP
        case 2 => Animal.Move.UP
        case 6 => Animal.Move.DOWN
        case 8 => Animal.Move.DOWN
    }

    def avoidall = {
        val safemoves = for {
            move <- List(
                            (0, 1, Animal.Move.UP), 
                            (1, 0, Animal.Move.LEFT), 
                            (1, 2, Animal.Move.RIGHT), 
                            (2, 1, Animal.Move.DOWN)
                        ) if(surroundings(move._1)(move._2)==' ')
        } yield move
        if(safemoves.length < 4) Random.shuffle(safemoves).head._3 else Animal.Move.HOLD
    }

}

object PassiveAgressiveWolf {
    private var id=0
    private def nextId = {id+=1; id}

    private var lastopponents=Array.fill[Char](100)(' ');
}

JVM 기반 언어 인 Scala는 비교적 쉽게 통합 될 수 있습니다.

프로그램을 직접 컴파일하는 경우 scala 파일을 .class파일이 아닌 java 파일 과 함께 넣고 .java사용하십시오.

scalac PassiveAggressiveWolf.scala

그것을 컴파일하십시오. 그런 다음 Java 클래스와 마찬가지로 PassiveAggressiveWolf.class기본 Wild.java클래스 에서 를 사용할 수 있습니다 . scala-library.jar클래스 경로에도 를 추가해야합니다 (명령 행 옵션을 사용했습니다 -cp /path/to/scala-library.jar).

또는 생성 된 클래스 파일과 scala-library.jarScala 2.10.3을 포함하는 jar 파일을 업로드하여 다운로드 할 수있었습니다.

PassiveAggressiveWolf.jar
scala-library.jar


10 개의 파일을 하나의 zip 파일로 압축하여 쉽게 다운로드 할 수 있습니다.
johnchen902

@ johnchen902 채팅으로 수업을 담을 항아리를 만드는 것이 제안되었습니다. 오늘 저녁 퇴근 후 그 일을 할 것입니다. 그것은 2 다운로드로 줄이고 Rusher가 포함하는 문제를 희망적으로 해결합니다.
Gareth
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.