선과 악


112

결과-2014 년 7 월 19 일

현재 언덕의 왕은 사용자 Fabigler에 의해 용병입니다 ! 항목을 계속 제출하고 그의 왕좌에서 그를 노크하십시오!

스코어 보드를 보려면 여기를 클릭하십시오.

2014 년 7 월 19 일 이전에 제출 된 프로그램이 포함되었습니다. 다른 모든 제출물은 향후 시험에 포함될 것입니다. 새로운 결과는 8 월 9 일경에 게시되므로 충분한 시간을 할애 할 수 있습니다.


형제가 그린 그림 Chris Rainbolt, 내 동생이자 Savannah College of Art and Design의 신입생

소개

천사와 악마는 싸우고 있으며 평소와 같이 지구를 전장으로 사용하고 있습니다. 인간은 가운데에 갇혀 있고 강제로 측면을 복용하고 있습니다. 알 수없는 중립 세력은 패배하는 쪽을 위해 끊임없이 싸우는 사람들에게 보상합니다.

게임

각 시험은 의사 무작위로 짝을 지어 20 ~ 30 개의 다른 제출물과 섞입니다. 각 시험은 1000 라운드로 구성됩니다. 각 라운드마다 입력을 전달 받고 출력을 생성해야합니다. 출력이 기록되고 점수가 매겨집니다. 이 과정은 1000 번 반복됩니다.

입력

각 플레이어의 과거 투표를 나타내는 단일 인수를 받게됩니다. 라운드는 쉼표로 구분됩니다. A 0는 해당 라운드에서 이블과 함께한 플레이어를 나타냅니다. A 1는 선의 편에 든 플레이어를 나타냅니다. 평가판 내에서 플레이어는 항상 같은 순서로 진행됩니다. 자신의 투표가 포함되지만 명시 적으로 식별되지는 않습니다. 예를 들면 다음과 같습니다.

101,100,100

이 예에서는 3 라운드가 완료되었으며 3 명의 선수가 경쟁하고 있습니다. 플레이어 1은 항상 좋은 편입니다. 2 번 선수는 항상 악과 편견이 있습니다. 3 번 선수는 1 라운드에서 Good에서 2 라운드와 3 라운드에서 Evil로 교체했습니다.

산출

자바 제출

  • goodGood을 사용 하려면 문자열을 반환하십시오 .
  • evilEvil을 사용 하려면 문자열을 반환하십시오 .

비 Java 제출

  • goodGood과 함께 하려면 문자열 을 stdout으로 출력하십시오 .
  • evilEvil을 사용 하려면 문자열 을 stdout으로 출력하십시오 .

프로그램이 다른 것을 출력하거나 리턴하거나, 예외를 발생 시키거나, 컴파일하지 않거나, 이 정확한 머신 에서 출력하는 데 1 초 이상 걸리면 , 실격 처리됩니다.

채점

현재 항목을 모두 컴파일 할 수있게되면 점수를 Google 문서 스프레드 시트에 게시하여 쉽게 볼 수 있습니다. 걱정하지 마십시오. 프로그램을 계속 제출하는 한 계속해서 시험 사용을하겠습니다.

  • 한 라운드 동안 다수와의 사이딩으로 3 점을받습니다.
  • 라운드 중 소수를 사이딩하기 위해 n-1 점을받습니다. 여기서 n은 소수를 상대로 한 연속 횟수입니다.

귀하의 점수는 5 번의 시험 중간 값이됩니다. 각 시험은 1000 라운드로 구성됩니다.

산출물

비 Java 제출

프로그램을 실행할 고유 한 제목, 프로그램 및 Windows 명령 줄 문자열을 제출해야합니다. 해당 문자열에 인수가 추가 될 수 있습니다. 예를 들면 다음과 같습니다.

  • python Angel.py
    • 이 인수에는 인수가 없습니다. 이것은 하나입니다! 준비하십시오.
  • python Angel.py 11011,00101,11101,11111,00001,11001,11001

자바 제출

아래에 작성된 추상 휴먼 클래스를 확장하는 고유 한 제목과 Java 클래스를 제출해야합니다.

public abstract class Human {
    public abstract String takeSides(String history) throws Exception;
}

테스팅

직접 제출 한 내용을 테스트하려면 여기 의 지침을 따르십시오 .

추가 사항

원하는만큼 다른 제출을 제출할 수 있습니다. 충돌로 보이는 제출물은 실격 처리됩니다. 이 도전의 저자는 그 문제에 대한 유일한 판사가 될 것입니다.

프로그램 또는 Java 클래스의 새 인스턴스는 호출 될 때마다 작성됩니다. 파일에 쓰면 정보를 유지할 수 있습니다. 자신의 클래스를 제외한 다른 것의 구조 나 동작을 수정할 수 없습니다.

평가판이 시작되기 전에 플레이어가 뒤섞입니다. 악마와 천사는 모든 시련에 참여할 것입니다. 플레이어 수가 짝수이면 Petyr Baelish도 참여합니다. 악마는 악을 위해 싸우고, 천사는 선을 위해 싸우며, Petyr Baelish는 의사 난수 측면을 선택합니다.


2
더 이상 사용되지 않고 OP의 요청에 따라 댓글이 삭제되었습니다. 삭제를 취소해야하는 의견이 있으면 알려주십시오.
손잡이

7
오, OP는 자신의 사용자 이름을 변경합니다. 좋아, 결과는 언제 표시됩니까?
justhalf

6
@Rainbolt 이것은 도전을 실행, 일의 하나의 괴물 지옥이어야합니다! 이 정도의 관심을 끄는 이유는 프로토콜과 규칙이 단순하기 때문에 액세스하기 쉽고 간단한 작업 항목을 허용하기 때문 입니다. TL; DR : 당신의 도전은 너무 좋습니다! : D
tomsmeding

3
@dgel 나는 원시 데이터, 상한, 하한, 평균 및 아마도 꺾은 선형 차트를 게시하여 경쟁이 치열해질 때 누가 더 잘했는지 볼 수 있습니다.
Rainbolt

6
포드 중 하나는 매번 같은 방식으로 투표 한 10 개의 항목으로 끝났습니다. 결과적으로, 2 명의 사용자는 약 450,000의 완벽한 또는 "한 번의 완벽한 부족"점수를 얻었습니다. 다른 시험에서 같은 항목이 약 1900 점을 기록했습니다. 평균 점수는 2000에 가깝습니다. 결과의 극단적 인 불균형으로 인해 더 의미있는 숫자가 중앙값이되도록 결정했습니다. 5 번의 시험 후 우승자가 가장 높은 중앙값을 가진 제출자가되도록 도전 과제를 수정했습니다. 평균에서 중간으로 이동하는 것이 불공평하거나 그렇지 않은 선택이라고 생각하는 사람은 의견을 말하십시오.
Rainbolt

답변:


11

용병

항상 마지막 라운드에서 가장 많은 돈을 지불 한 사람과 편입니다.

좋은 사람들이 통계적으로 더 많은 돈을 버는 것을 고려하면.

package Humans;
public class Mercenary extends Human {
    public String takeSides(String history) {
        // first round random!
        if (history.length() == 0) {
            return Math.random() >= 0.5 ? "good" : "evil";
        }

        String[] rounds = history.split(",");
        String lastRound = rounds[rounds.length - 1];

        double goodMoneyPaid = 0;
        double evilMoneyPaid = 0;
        for (char c : lastRound.toCharArray()) {
                switch (c) {
                case '0':
                    goodMoneyPaid = goodMoneyPaid + 0.2; //statistically proven: good people have more reliable incomes
                    break;
                case '1':
                    evilMoneyPaid++; 
                    break;
                default:
                    break;
                }
        }

        if (goodMoneyPaid > evilMoneyPaid)
        {
            return "good";
        } else {
            return "evil";
        }
    }
}

2
이것은 돈에 대해 이야기 하는 두 번째 게시물 입니다. 참조 또는 무언가가 누락 되었습니까?
Rainbolt

사실이 사람은 훨씬 더 나쁜 놈입니다. 돈을 위해서만 매 친구를 버림.
fabigler

switch 문에 기본 사례에 대한 return 문이 없어 컴파일되지 않았습니다. 나는 임의의 것을 추가했다.
Rainbolt

4
축하합니다, 언덕의 왕! 이 출품작이 어떻게 승리하는지 이해하지 못합니다. 300 개의 평판 현상금이 첨부되었으므로 설명을 추가할까요?
Rainbolt

4
아마도 버그이거나 의견과 설명을 잘못 이해했지만 용병은 실제로 의도했던대로 행동하지 않습니다. 첫 번째 무작위 라운드를 제외하고, 그는 이전 라운드에서 악의로 투표 한 사람의 1/6 미만이 아니라면 항상 악의 편에 서게됩니다.
jaybz

39

소식통, 루비

if ARGV.length == 0
    puts ["good", "evil"].sample
else
    last_round = ARGV[0].split(',').last
    n_players = last_round.length
    puts last_round.count('1') > n_players/2 ? "evil" : "good"
end

다른 모든 것이 주류이기 때문에 마지막 라운드의 소수와 함께하면됩니다.

다음과 같이 실행

ruby hipster.rb

30

페티 르 바 엘리 쉬

당신은 누구의 Petyr Baelish가 켜져 있는지 모른다.

package Humans;

/**
 * Always keep your foes confused. If they are never certain who you are or 
 * what you want, they cannot know what you are likely to do next.
 * @author Rusher
 */
public class PetyrBaelish extends Human {

    /**
     * Randomly take the side of good or evil.
     * @param history The past votes of every player
     * @return A String "good" or "evil
     */
    public String takeSides(String history) {
        return Math.random() < 0.5 ? "good" : "evil";
    }
}

이 항목은 플레이어 수가 짝수 인 경우에만 포함됩니다. 이를 통해 항상 다수가 유지됩니다.


28
Petyr Baelish의 편에서, 분명히.
크 툴후

2
@ 케빈 그것은 대부분의 봇을 지속적으로 능가합니다. 보통 27ish입니다.
cjfaure

3
@Kevin이 항목은 도전의 저자가 제출했습니다. 잘하지 않았습니다. 짝수가 많으면 동점이있을 수 있기 때문에 항상 과반수가 있어야합니다.
Rainbolt

4
왜 이런 하나님이이 표를 가장 많이 받았습니까? 그것은 단지 공평하지 .
tomsmeding

3
@tomsmeding 아니오. 왕좌의 게임 lol의 인용문입니다.
Rainbolt

29

C ++, 메타 과학자

이것은 과학자와 본질적으로 동일하지만 전체적으로 라운드가 아니라 개별 플레이어에서 작동합니다. 각 플레이어에 웨이브 (또는 상수 함수)를 개별적으로 매핑하려고 시도하고 다음 라운드에서 움직임을 예측합니다. 결과 라운드 예측에서, 메타 과학자는 과반수를 갖는 쪽을 선택합니다.

#include <iostream>
#include <utility>
#include <cstdlib>
#include <cstring>
#if 0
#define DBG(st) {st}
#else
#define DBG(st)
#endif

#define WINDOW (200)

using namespace std;

int main(int argc,char **argv){
    if(argc==1){
        cout<<(rand()%2?"good":"evil")<<endl;
        return 0;
    }
    DBG(cerr<<"WINDOW="<<WINDOW<<endl;)
    int nump,numr;
    nump=strchr(argv[1],',')-argv[1];
    numr=(strlen(argv[1])+1)/(nump+1);
    int period,r,p;
    int score,*scores=new int[WINDOW];
    int max; //some score will always get above 0, because if some score<0, the inverted wave will be >0.
    int phase,phasemax;
    int predicted=0; //The predicted number of goods for the next round
    int fromround=numr-WINDOW;
    if(fromround<0)fromround=0;
    pair<int,int> maxat; //period, phase
    DBG(cerr<<"Players:"<<endl;)
    for(p=0;p<nump;p++){
        DBG(cerr<<" p"<<p<<": ";)
        for(r=fromround;r<numr;r++)if(argv[1][r*(nump+1)+p]!=argv[1][p])break;
        if(r==numr){
            DBG(cerr<<"All equal! prediction="<<argv[1][p]<<endl;)
            predicted+=argv[1][(numr-1)*(nump+1)+p]-'0';
            continue;
        }
        max=0;
        maxat={-1,-1};
        for(period=1;period<=WINDOW;period++){
            scores[period-1]=0;
            phasemax=-1;
            for(phase=0;phase<2*period;phase++){
                score=0;
                for(r=fromround;r<numr;r++){
                    if(argv[1][r*(nump+1)+p]-'0'==1-(r+phase)%(2*period)/period)score++;
                    else score--;
                }
                if(score>scores[period-1]){
                    scores[period-1]=score;
                    phasemax=phase;
                }
            }
            if(scores[period-1]>max){
                max=scores[period-1];
                maxat.first=period;
                maxat.second=phasemax;
            }
            DBG(cerr<<scores[period-1]<<" ";)
        }
        DBG(cerr<<"(max="<<max<<" at {"<<maxat.first<<","<<maxat.second<<"})"<<endl;)
        DBG(cerr<<"     prediction: 1-("<<numr<<"+"<<maxat.second<<")%(2*"<<maxat.first<<")/"<<maxat.first<<"="<<(1-(numr+maxat.second)%(2*maxat.first)/maxat.first)<<endl;)
        predicted+=(1-(numr+maxat.second)%(2*maxat.first)/maxat.first);
    }
    DBG(cerr<<"Predicted outcome: "<<predicted<<" good + "<<(nump-predicted)<<" evil"<<endl;)
    if(predicted>nump/2)cout<<"evil"<<endl; //pick minority
    else cout<<"good"<<endl;
    delete[] scores;
    return 0;
}

디버그 명령문을 켜려면 행 읽기 #if 0를로 변경하십시오 #if 1.

로 컴파일하고 g++ -O3 -std=c++0x -o MetaScientist MetaScientist.cpp(경고가 필요하지 않으므로 -Wall) 실행하십시오 MetaScientist.exe(물론 인수를 포함하여). 정말 멋지게 물어 보면 Windows 실행 파일을 제공 할 수 있습니다.

편집 : 분명히 이전 버전의 게임에서 약 600 라운드가 부족했습니다. 그렇게하지 말아야합니다. 그것의 시간 소비는 #define WINDOW (...)라인에 의해 제어되고 , 더 느리지 만 더 멀리 보입니다.


2
나는 당신이 잃어버린 쪽을 선택하려고 겸손히 제안합니다. 일관되게 정확하게 추측 할 수 있으면 라운드 당 3 점 이상을 얻게됩니다.
케빈

1
@Kevin 그것은 사실이지만, 나는 그것이 잘못된면을 꽤 빨리 추측 할 수 있다고 생각했고, 항상 대다수를 올바르게 얻는 것보다 개선을 얻으려면 연속으로 패배 한면을 7 번 이상 정확하게 추측해야합니다. 그래도 변경 될 수 있습니다.
tomsmeding

1
@Kevin 또한 Rusher가 이번 주말에 OP에 대한 의견에서 지적했듯이 Rusher가 우리에게 점수 판을 줄 때 어떻게되는지 (과학자와 메타 과학자)를보고 싶습니다. 러셔, 미안하지만, 모든 것을 직접 컴파일하기에는 너무 게으르다 ... :)
tomsmeding

3
걱정 마! 어쨌든 이것을 실행하는 것이 안전하지 않을 수 있습니다. 인터넷에서 50 명의 낯선 사람이 작성한 코드로 내 컴퓨터를 망칠 수 있습니다.
Rainbolt

1
@ 케빈 그러나 그것은 너무 많은입니다 ! 실제로는 할 수 있지만 마음에 들지 않습니다. 이 요금이 어떻게 나오는지 봅시다.
tomsmeding

26

천사

모두의 가장 순수한 선수.

프로그램

print "good"

명령

python Angel.py

22
파이썬은 좋은 언어입니다. 천사가 그것을 사용해야하는 것은 당연한 것 같습니다.
jpmc26

23
사람들에게 파이썬이 뱀이라는 것을 상기시켜 드리겠습니다. 뱀.
Mr Lister

3
@MrLister 나는 루시퍼가 하나님이 그를 하늘에서 내 쫓기 전에 위대한 천사 였다는 것을 상기시켜 줄 수 있습니까?
Zibbobz

1
@Zibbobz 그래 ... 부끄러운 줄 알아. 그들은 너무 많은 것을 성취 할 수있었습니다.
Mr Lister

24

아르테미스 파울

package Humans;

public class ArtemisFowl extends Human {
    public final String takeSides(String history) {
        int good = 0, evil = 0;
        for(int i = 0; i < history.length(); i++)   {
            switch(history.charAt(i))   {
                case '0': evil++; break;
                case '1': good++; break;
            }
        }
        if(good % 5 == 0){
           return "good";
        } else if (evil % 5 == 0){
           return "evil";
        } else {
           if(good > evil){
              return "good";
           } else if(evil > good){
              return "evil";
           } else {
              return Math.random() >= 0.5 ? "good" : "evil";
           }
        }
    }
}

7 권에서 아틀란티스 단지 , 아르테미스 닭은 5 (말하기, 행동 등)의 배수로 모든 일을 그에게 강요 (아틀란티스 복잡한라고도 함) 심리적 질병에 걸렸다. 그가 5의 배수로 그것을 할 수 없을 때, 그는 당황했다. 나는 기본적으로 그렇게합니다 : 선 또는 악 (의도적 편향)이 5로 나눌 수 있는지 확인하십시오. 그렇지 않다면, 나는 패닉 & 더 큰 패닉을 보거나 더 패닉하고 무작위로 선택합니다.


4
Junior High에서 Artemis Fowl을 읽을 때 두 권의 책만 존재했습니다. 현재 7 명이 있고 디즈니가 영화로 만들고 있다는 것을 알게되어 기쁩니다.
Rainbolt

1
실제로 8 권의 책이 있습니다.
Kyle Kanos

7
더 많은
메리 어 (

1
그리고 당신은 잊었 break;당신에 switch.
johnchen902

1
@ johnchen902, @ Manu : 나는 Java에 익숙하지 않습니다 (Fortran90 +를 사용하고 여기에서 java 만 참조하십시오). 그래서 내 오류가 발생합니다. 한 시간 안에 사무실에 도착하면 문제를 해결하겠습니다.
Kyle Kanos

19

이질 소 공포증

홀수 숫자는 끔찍합니다.

package Humans;

public class Disparnumerophobic extends Human {
    public final String takeSides(String history) {
        int good = 0, evil = 0;
        for(int i = 0; i < history.length(); i++)   {
            switch(history.charAt(i))   {
                case '0': evil++; break;
                case '1': good++;
            }
        }
        if(good%2 == 1 && evil%2 == 0)  return "evil";
        if(evil%2 == 1 && good%2 == 0)  return "good";
        // well shit.... 
        return Math.random() >= 0.5 ? "good" : "evil";
    }
}

17
댓글로 나를 웃고 코를 골랐다.
phyrfox

17

리누스, 루비

항상 패턴을 깨뜨려 분석가들을 혼란스럽게하려한다 .

num_rounds = ARGV[0].to_s.count(',')
LINUS_SEQ = 0xcb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d232c4d2c8cb13b2d3734ecb4dcb232c4d2c8cb13b2d3734ecb4dc8cb134b232c4d3b2dcd3b2d3734ec4d2c8cb134b234dcd3b2d3734ec4d2c8cb134b23734ecb4dcd3b2c4d2c8cb134b2
puts %w[good evil][LINUS_SEQ[num_rounds]]

다른 이름으로 저장 linus.rb하고 실행ruby linus.rb


16

백패커

일치하는 소수를 가장 많이 선택한 플레이어를 결정하고 마지막 투표를 선택합니다.

package Humans;

public class BackPacker extends Human {
    // toggles weather the BackPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = false;

    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }

    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else {
            return ((!didGoodWin && playerVotedGood) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }

    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}

군중 추종자

일치하는 다수를 가장 많이 선택한 플레이어를 결정하고 마지막 투표를 선택합니다.

package Humans;

public class CrowdFollower extends Human {
    // toggles weather the FrontPacker thinks majority is better vs. minority is better
    private static final boolean goWithMajority = true;

    @Override
    public final String takeSides(String history)  {
        if (history == null || history.equals(""))
            return "evil";
        String[] roundVotes = history.split(",");
        int players = roundVotes[0].length();
        int[] winningPlayers = new int[players];
        for (String nextRound : roundVotes) {
            boolean didGoodWin = didGoodWin(nextRound, players);
            for (int player = 0; player < nextRound.length(); player++) {
                boolean playerVotedGood = nextRound.charAt(player) == '1';
                winningPlayers[player] += didPlayerWin(didGoodWin, playerVotedGood);
            }
        }
        int bestScore = -1;
        for (int nextPlayer : winningPlayers)
            if (bestScore < nextPlayer)
                bestScore = nextPlayer;
        int bestPlayer = 0;
        for (int ii = 0; ii < players; ii++) {
            if (winningPlayers[ii] == bestScore) {
                bestPlayer = ii;
                break;
            }
        }
        if (roundVotes[roundVotes.length - 1].charAt(bestPlayer) == '1')
            return "good";
        return "evil";
    }

    private int didPlayerWin(boolean didGoodWin, boolean playerVotedGood) {
        if(goWithMajority) {
            return ((didGoodWin && playerVotedGood) || (!didGoodWin && !playerVotedGood)) ? 1 : 0;
        } else playerVotedGood                return ((!didGoodWin && good) || (didGoodWin && !playerVotedGood)) ? 1 : 0;
        }
    }

    private boolean didGoodWin(String round, int players) {
        int good = 0;
        for (char next : round.toCharArray())
            good += next == '1' ? 1 : 0;
        return (good * 2) > players;
    }
}

매우 깨끗한 프로그램!
Rainbolt

프로그램을 다른 언어로 복사했을 수도 있습니다.
PyRulez

나는 코드를 업데이트하고 두 항목, 하나 같이이를 추가 할 @Rusher goWithMajority = true하나의를 false. 괜찮습니까, 아니면 이것을 위해 두 번째 BackPacker를 추가해야합니까?
Angelo Fuchs

@ AngeloNeuschitzer이 게시물을 편집했습니다. 이런 식으로 두 제출을 모두 추가하는 것을 잊지 않습니다. 내가 준 독창적이지 않은 이름을 변경하고 원하는 경우 둘 다에 설명을 추가하는 것이 좋습니다.
Rainbolt

1
@Rainbolt 사실 저는 FrontPacker를 더 좋아합니다. 롤드
tomsmeding

15

점쟁이

아직 진행 중입니다. 아직 테스트하지 않았습니다. OP가 규칙을 어 기고 있다고 생각하는지 알고 싶었습니다.

아이디어는 다른 모든 참가자를 몇 차례 실행하여 결과의 ​​확률을 얻고 그에 따라 행동함으로써 다음 라운드를 시뮬레이션하는 것입니다.

package Humans;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import sun.net.www.protocol.file.FileURLConnection;

public class FortuneTeller extends Human {

/**
 * Code from http://stackoverflow.com/a/22462785 Private helper method
 *
 * @param directory The directory to start with
 * @param pckgname The package name to search for. Will be needed for
 * getting the Class object.
 * @param classes if a file isn't loaded but still is in the directory
 * @throws ClassNotFoundException
 */
private static void checkDirectory(File directory, String pckgname,
        ArrayList<Class<?>> classes) throws ClassNotFoundException {
    File tmpDirectory;

    if (directory.exists() && directory.isDirectory()) {
        final String[] files = directory.list();

        for (final String file : files) {
            if (file.endsWith(".class")) {
                try {
                    classes.add(Class.forName(pckgname + '.'
                            + file.substring(0, file.length() - 6)));
                } catch (final NoClassDefFoundError e) {
                // do nothing. this class hasn't been found by the
                    // loader, and we don't care.
                }
            } else if ((tmpDirectory = new File(directory, file))
                    .isDirectory()) {
                checkDirectory(tmpDirectory, pckgname + "." + file, classes);
            }
        }
    }
}

/**
 * Private helper method.
 *
 * @param connection the connection to the jar
 * @param pckgname the package name to search for
 * @param classes the current ArrayList of all classes. This method will
 * simply add new classes.
 * @throws ClassNotFoundException if a file isn't loaded but still is in the
 * jar file
 * @throws IOException if it can't correctly read from the jar file.
 */
private static void checkJarFile(JarURLConnection connection,
        String pckgname, ArrayList<Class<?>> classes)
        throws ClassNotFoundException, IOException {
    final JarFile jarFile = connection.getJarFile();
    final Enumeration<JarEntry> entries = jarFile.entries();
    String name;

    for (JarEntry jarEntry = null; entries.hasMoreElements()
            && ((jarEntry = entries.nextElement()) != null);) {
        name = jarEntry.getName();

        if (name.contains(".class")) {
            name = name.substring(0, name.length() - 6).replace('/', '.');

            if (name.contains(pckgname)) {
                classes.add(Class.forName(name));
            }
        }
    }
}

/**
 * Attempts to list all the classes in the specified package as determined
 * by the context class loader
 *
 * @param pckgname the package name to search
 * @return a list of classes that exist within that package
 * @throws ClassNotFoundException if something went wrong
 */
private static ArrayList<Class<?>> getClassesForPackage(String pckgname)
        throws ClassNotFoundException {
    final ArrayList<Class<?>> classes = new ArrayList<Class<?>>();

    try {
        final ClassLoader cld = Thread.currentThread()
                .getContextClassLoader();

        if (cld == null) {
            throw new ClassNotFoundException("Can't get class loader.");
        }

        final Enumeration<URL> resources = cld.getResources(pckgname
                .replace('.', '/'));
        URLConnection connection;

        for (URL url = null; resources.hasMoreElements()
                && ((url = resources.nextElement()) != null);) {
            try {
                connection = url.openConnection();

                if (connection instanceof JarURLConnection) {
                    checkJarFile((JarURLConnection) connection, pckgname,
                            classes);
                } else if (connection instanceof FileURLConnection) {
                    try {
                        checkDirectory(
                                new File(URLDecoder.decode(url.getPath(),
                                                "UTF-8")), pckgname, classes);
                    } catch (final UnsupportedEncodingException ex) {
                        throw new ClassNotFoundException(
                                pckgname
                                + " does not appear to be a valid package (Unsupported encoding)",
                                ex);
                    }
                } else {
                    throw new ClassNotFoundException(pckgname + " ("
                            + url.getPath()
                            + ") does not appear to be a valid package");
                }
            } catch (final IOException ioex) {
                throw new ClassNotFoundException(
                        "IOException was thrown when trying to get all resources for "
                        + pckgname, ioex);
            }
        }
    } catch (final NullPointerException ex) {
        throw new ClassNotFoundException(
                pckgname
                + " does not appear to be a valid package (Null pointer exception)",
                ex);
    } catch (final IOException ioex) {
        throw new ClassNotFoundException(
                "IOException was thrown when trying to get all resources for "
                + pckgname, ioex);
    }

    return classes;
}

private static boolean isRecursiveCall = false;
private static ArrayList<Class<?>> classes;

static {
    if (classes == null) {
        try {
            classes = getClassesForPackage("Humans");
        } catch (ClassNotFoundException ex) {

        }
    }    
}

private String doThePetyrBaelish() {
    return Math.random() >= 0.5 ? "good" : "evil";
}

@Override
public String takeSides(String history) {
    if (isRecursiveCall) {
        return doThePetyrBaelish();
    }
    isRecursiveCall = true;

    int currentRoundGoodCount = 0;
    float probabilityOfGood = 0;
    int roundCount = 0;
    int voteCount = 0;



    do {
        for (int i = 0; i < classes.size(); i++) {
            try {
                if (classes.get(i).getName() == "Humans.FortuneTeller") {
                    continue;
                }

                Human human = (Human) classes.get(i).newInstance();
                String response = human.takeSides(history);
                switch (response) {
                    case "good":
                        currentRoundGoodCount++;
                        voteCount++;
                        break;
                    case "evil":
                        voteCount++;
                        break;
                    default:
                        break;
                }
            } catch (Exception e) {
            }
        }

        probabilityOfGood = (probabilityOfGood * roundCount
                + (float) currentRoundGoodCount / voteCount) / (roundCount + 1);

        roundCount++;
        currentRoundGoodCount = 0;
        voteCount = 0;

    } while (roundCount < 11);

    isRecursiveCall = false;
    if (probabilityOfGood > .7) {
        return "evil";
    }
    if (probabilityOfGood < .3) {
        return "good";
    }

    return doThePetyrBaelish();
}

}

봇이 응답하기 전에 매번 다른 모든 봇을 실행하면 응답하는 데 1 초 이상 걸리지 않습니까?
plannapus

@ plannapus이 봇의 가정은 다른 사람들이주의를 기울이려고하고 1 초 정도의 기다림을 피하는 것입니다. 0.9 초의 대기 시간으로 구성된 제출 및 출품작이 "좋음"으로 돌아 가기 전에 그에게 혼란을주는 것이 가치가 있다고 생각합니다. 실제로, SBoss는 저를 이겼습니다 : D
scragar

야! 그런 다음 코드에서 해당 봇을 블랙리스트에 추가해야합니다. 그것은 실망 스러울 것입니다 ... 또한 Python이나 Perl과 같은 다른 환경에서 다른 항목을 사용하면 인터프리터의 반복 로딩 이이 코드를 시간 제한 이상으로 가져 오기에 충분할 수 있습니다.
Andris

16
다른 사람이 이와 같은 일을하면 무한 루프가 발생합니다.
Brilliand

4
제출 시간이 초과되었습니다. 나는 프로파일 러를 첨부했으며 거의 ​​0.5 초가 제출을 요청하는 데 소비됩니다. 그것은 적어도 작동하지만 그렇게 축하합니다.
Rainbolt

15

과학자, C ++

이것은 라운드 당 다수가 선택한 것에 대한 이력 wave( 라운드에서 majority()다수의 선택을 제공함)으로 파장 2*period과 위상 의 데이터에 웨이브를 맞추려고 시도합니다 phase. 따라서 ( )를 0,1,1,1,0,1,0,1,1,1,0,0,0,1,0선택 하면 점수가 됩니다. 가능한 모든 기간에 걸쳐 반복되며, 해당 기간 동안 점수가 현재 최대 점수보다 높으면 발생한 점수를 저장 합니다.period=3, phase=5maxat=={3,5}9 3 11 5 5 3 5 7 9 7 7 7 7 7 7{period,phase}

그런 다음 발견 된 파를 다음 라운드로 추정하고 예측 된 다수를 취합니다.

#include <iostream>
#include <utility>
#include <cstdlib>
#include <cstring>
#if 0
#define DBG(st) {st}
#else
#define DBG(st)
#endif

#define WINDOW (700)

using namespace std;

int majority(const char *r){
    int p=0,a=0,b=0;
    while(true){
        if(r[p]=='1')a++;
        else if(r[p]=='0')b++;
        else break;
        p++;
    }
    return a>b;
}

int main(int argc,char **argv){
    if(argc==1){
        cout<<(rand()%2?"good":"evil")<<endl;
        return 0;
    }
    DBG(cerr<<"WINDOW="<<WINDOW<<endl;)
    int nump,numr;
    nump=strchr(argv[1],',')-argv[1];
    numr=(strlen(argv[1])+1)/(nump+1);
    int fromround=numr-30;
    if(fromround<0)fromround=0;
    int period,r;
    int *wave=new int[WINDOW];
    bool allequal=true;
    DBG(cerr<<"wave: ";)
    for(r=fromround;r<numr;r++){
        wave[r-fromround]=majority(argv[1]+r*(nump+1));
        if(wave[r-fromround]!=wave[0])allequal=false;
        DBG(cerr<<wave[r]<<" ";)
    }
    DBG(cerr<<endl;)
    if(allequal){
        DBG(cerr<<"All equal!"<<endl;)
        if(wave[numr-1]==1)cout<<"evil"<<endl; //choose for minority
        else cout<<"good"<<endl;
        return 0;
    }
    int score,*scores=new int[WINDOW];
    int max=0; //some score will always get above 0, because if some score<0, the inverted wave will be >0.
    int phase,phasemax;
    pair<int,int> maxat(-1,-1); //period, phase
    DBG(cerr<<"scores: ";)
    for(period=1;period<=WINDOW;period++){
        scores[period-1]=0;
        phasemax=-1;
        for(phase=0;phase<2*period;phase++){
            score=0;
            for(r=fromround;r<numr;r++){
                if(wave[r]==1-(r+phase)%(2*period)/period)score++;
                else score--;
            }
            if(score>scores[period-1]){
                scores[period-1]=score;
                phasemax=phase;
            }
        }
        if(scores[period-1]>max){
            max=scores[period-1];
            maxat.first=period;
            maxat.second=phasemax;
        }
        DBG(cerr<<scores[period-1]<<" ";)
    }
    DBG(cerr<<"(max="<<max<<" at {"<<maxat.first<<","<<maxat.second<<"})"<<endl;)
    DBG(cerr<<" max: ("<<numr<<"+"<<maxat.second<<")%(2*"<<maxat.first<<")/"<<maxat.first<<"=="<<((numr+maxat.second)%(2*maxat.first)/maxat.first)<<endl;)
    if(1-(numr+maxat.second)%(2*maxat.first)/maxat.first==1)cout<<"evil"<<endl; //choose for minority
    else cout<<"good"<<endl;
    delete[] wave;
    delete[] scores;
    return 0;
}

로 컴파일하고 g++ -O3 -std=c++0x -o Scientist Scientist.cpp(경고가 필요하지 않으므로 -Wall) 실행하십시오 Scientist.exe(물론 인수를 포함하여). 정말 멋지게 물어 보면 Windows 실행 파일을 제공 할 수 있습니다.

아, 그리고 입력 형식을 망쳐 놓지 마십시오. 그렇지 않으면 이상한 일을 할 것입니다.

편집 : 분명히 이전 버전의 게임에서 약 600 라운드가 부족했습니다. 그렇게하지 말아야합니다. 그것의 시간 소비는 #define WINDOW (...)라인에 의해 제어되고 , 더 느리지 만 더 멀리 보입니다.


8
인터넷에서 60 세 이상의 낯선 사람이 작성한 실행 파일을 다운로드하는 것은 나쁜 생각처럼 보입니다.
Rainbolt

@Rusher 전적으로 동의합니다. 문제가 필요한 경우 "견인 용"안내서의 1 단계입니다. 내 제안은 :)
tomsmeding

2
이것을 잘 컴파일하고 경쟁하기 위해 이것을 얻었다.
Rainbolt

14

코드 러너

따라서 흥미로운 점을 만들기 위해 게시 된 모든 답변에서 코드를 자동으로 다운로드하고 필요한 경우 컴파일 한 다음 규칙에 따라 모든 솔루션을 실행하는 스크립트를 만들었습니다. 이런 식으로 사람들은 자신이하는 일을 확인할 수 있습니다. 이 스크립트를 run_all.py (BeautifulSoup 필요)에 저장 한 후 다음을 수행하십시오.

usage:
To get the latest code: 'python run_all.py get'
To run the submissions: 'python run_all.py run <optional num_runs>'

몇 가지:

  1. 더 많은 언어에 대한 지원을 추가하거나 다른 언어에 대한 지원을 제거하려면을 참조하십시오 def submission_type(lang).
  2. 컴파일이 필요한 언어의 경우에도 스크립트 확장은 상당히 쉬워야합니다 (참조 CPPSubmission). 언어 유형은 메타 코드 태그에서 가져 오므로 코드 < !-- language: lang-java -- >를 실행하려면 추가해야합니다 (<> 앞뒤에 추가 공백 제거). 업데이트 : 언어가 정의되지 않은 경우 언어를 시도하고 감지하는 매우 기본적인 추론이 있습니다.
  3. 코드가 전혀 실행되지 않거나 할당 된 시간 내에 완료되지 않으면 코드가 추가되어 blacklist.text향후 시험에서 자동으로 제거됩니다. 코드를 수정 한 경우 블랙리스트에서 항목을 제거하고 다시 실행하십시오 get.

현재 지원되는 언어 :

 submission_types =  {
    'lang-ruby': RubySubmission,
    'lang-python': PythonSubmission,
    'lang-py': PythonSubmission,
    'lang-java': JavaSubmission,
    'lang-Java': JavaSubmission,
    'lang-javascript': NodeSubmission,
    'lang-cpp': CPPSubmission,
    'lang-c': CSubmission,
    'lang-lua': LuaSubmission,
    'lang-r': RSubmission,
    'lang-fortran': FortranSubmission,
    'lang-bash': BashSubmission
}

더 이상 고민하지 않고 :

import urllib2
import hashlib
import os
import re
import subprocess
import shutil
import time
import multiprocessing
import tempfile
import sys
from bs4 import BeautifulSoup

__run_java__ = """
public class Run {
    public static void main(String[] args) {
        String input = "";
        Human h = new __REPLACE_ME__();
        if(args.length == 1)
            input = args[0];
        try {
            System.out.println(h.takeSides(input));
        }
        catch(Exception e) {
        }
    }
}
"""

__human_java__ = """
public abstract class Human {
    public abstract String takeSides(String history) throws Exception;
}
"""

class Submission():
    def __init__(self, name, code):
        self.name = name
        self.code = code

    def submissions_dir(self):
        return 'submission'

    def base_name(self):
        return 'run'

    def submission_path(self):
        return os.path.join(self.submissions_dir(), self.name)

    def extension(self):
        return ""

    def save_submission(self):
        self.save_code()

    def full_command(self, input):
        return []

    def full_path(self):
        file_name = "%s.%s" % (self.base_name(), self.extension())
        full_path = os.path.join(self.submission_path(), file_name)
        return full_path

    def save_code(self):    
        if not os.path.exists(self.submission_path()):
            os.makedirs(self.submission_path())

        with open(self.full_path(), 'w') as f:
            f.write(self.code)

    def write_err(self, err):
        with open(self.error_log(), 'w') as f:
            f.write(err)

    def error_log(self):
        return os.path.join(self.submission_path(), 'error.txt')

    def run_submission(self, input):
        command = self.full_command()
        if input is not None:
            command.append(input)
        try:
            output,err,exit_code = run(command,timeout=1)
            if len(err) > 0:
                self.write_err(err)
            return output
        except Exception as e:
            self.write_err(str(e))
            return ""

class CPPSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['g++', '-O3', '-std=c++0x', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'cpp'

    def full_command(self):
        return [self.bin_path()]

class CSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['gcc', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'c'

    def full_command(self):
        return [self.bin_path()]

class FortranSubmission(Submission):
    def bin_path(self):
        return os.path.join(self.submission_path(), self.base_name())

    def save_submission(self):
        self.save_code()
        compile_cmd = ['gfortran', '-fno-range-check', '-o', self.bin_path(), self.full_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'f90'

    def full_command(self):
        return [self.bin_path()]

class JavaSubmission(Submission):   
    def base_name(self):
        class_name = re.search(r'class (\w+) extends', self.code)
        file_name = class_name.group(1)
        return file_name

    def human_base_name(self):
        return 'Human'

    def run_base_name(self):
        return 'Run'

    def full_name(self, base_name):
        return '%s.%s' % (base_name, self.extension())

    def human_path(self):
        return os.path.join(self.submission_path(), self.full_name(self.human_base_name()))

    def run_path(self):
        return os.path.join(self.submission_path(), self.full_name(self.run_base_name()))

    def replace_in_file(self, file_name, str_orig, str_new):
        old_data = open(file_name).read()
        new_data = old_data.replace(str_orig, str_new)

        with open(file_name, 'w') as f:
            f.write(new_data)

    def write_code_to_file(self, code_str, file_name):
        with open(file_name, 'w') as f:
            f.write(code_str)

    def save_submission(self):
        self.save_code()
        self.write_code_to_file(__human_java__, self.human_path())
        self.write_code_to_file(__run_java__, self.run_path())

        self.replace_in_file(self.run_path(), '__REPLACE_ME__', self.base_name())
        self.replace_in_file(self.full_path(), 'package Humans;', '')

        compile_cmd = ['javac', '-cp', self.submission_path(), self.run_path()]
        errout = open(self.error_log(), 'w')
        subprocess.call(compile_cmd, stdout=errout, stderr=subprocess.STDOUT)

    def extension(self):
        return 'java'

    def full_command(self):
        return ['java', '-cp', self.submission_path(), self.run_base_name()]

class PythonSubmission(Submission):
    def full_command(self):
        return ['python', self.full_path()]

    def extension(self):
        return 'py'

class RubySubmission(Submission):
    def full_command(self):
        return ['ruby', self.full_path()]

    def extension(self):
        return 'rb'

class NodeSubmission(Submission):
    def full_command(self):
        return ['node', self.full_path()]

    def extension(self):
        return 'js'

class LuaSubmission(Submission):
    def full_command(self):
        return ['lua', self.full_path()]

    def extension(self):
        return 'lua'

class RSubmission(Submission):
    def full_command(self):
        return ['Rscript', self.full_path()]

    def extension(self):
        return 'R'

class BashSubmission(Submission):
    def full_command(self):
        return [self.full_path()]

    def extension(self):
        return '.sh'

class Scraper():
    def download_page(self, url, use_cache = True, force_cache_update = False):
        file_name = hashlib.sha1(url).hexdigest()

        if not os.path.exists('cache'):
            os.makedirs('cache')

        full_path = os.path.join('cache', file_name)
        file_exists = os.path.isfile(full_path)

        if use_cache and file_exists and not force_cache_update:
            html = open(full_path, 'r').read()
            return html

        opener = urllib2.build_opener()
        opener.addheaders = [('User-agent', 'Mozilla/5.0')]
        response = opener.open(url)
        html = response.read()

        if use_cache:
            f = open(full_path, 'w')
            f.write(html)
            f.close()

        return html

    def parse_post(self, post):
        name = post.find(text=lambda t: len(t.strip()) > 0)
        pre = post.find('pre')
        lang = pre.attrs['class'][0] if pre.has_attr('class') else None
        code = pre.find('code').text
        user = post.find(class_='user-details').find(text=True)
        return {'name':name,'lang':lang,'code':code,'user':user}

    def parse_posts(self, html):
        soup = BeautifulSoup(html)
        # Skip the first post
        posts = soup.find_all(class_ = 'answercell')
        return [self.parse_post(post) for post in posts]

    def get_submissions(self,  page = 1, force_cache_update = False):
        url = "http://codegolf.stackexchange.com/questions/33137/good-versus-evil?page=%i&tab=votes#tab-top" % page
        html = self.download_page(url, use_cache = True, force_cache_update = force_cache_update)
        submissions = self.parse_posts(html)
        return submissions

class Timeout(Exception):
    pass

def run(command, timeout=10):
    proc = subprocess.Popen(command, bufsize=0, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    poll_seconds = .250
    deadline = time.time()+timeout
    while time.time() < deadline and proc.poll() == None:
        time.sleep(poll_seconds)

    if proc.poll() == None:
        if float(sys.version[:3]) >= 2.6:
            proc.terminate()
        raise Timeout()

    stdout, stderr = proc.communicate()
    return stdout, stderr, proc.returncode


def guess_lang(code):
    if re.search(r'class .* extends Human', code):
        return 'lang-java'
    if re.search(r'import sys', code):
        return 'lang-python'
    if re.search(r'puts', code) and (re.search(r'ARGV', code) or re.search(r'\%w', code)):
        return 'lang-ruby'
    if re.search(r'console\.log', code):
        return 'lang-javascript'
    if re.search(r'program', code) and re.search(r'subroutine', code):
        return 'lang-fortran'
    if re.search(r'@echo off', code):
        return 'lang-bash'
    return None


def submission_type(lang, code):
    submission_types =  {
        'lang-ruby': RubySubmission,
        'lang-python': PythonSubmission,
        'lang-py': PythonSubmission,
        'lang-java': JavaSubmission,
        'lang-Java': JavaSubmission,
        'lang-javascript': NodeSubmission,
        'lang-cpp': CPPSubmission,
        'lang-c': CSubmission,
        'lang-lua': LuaSubmission,
        'lang-r': RSubmission,
        'lang-fortran': FortranSubmission,
        'lang-bash': BashSubmission
    }

    klass = submission_types.get(lang)

    if klass is None:
        lang = guess_lang(code)
        klass = submission_types.get(lang)

    return klass

def instantiate(submission):
    lang = submission['lang']
    code = submission['code']
    name = submission['name']

    klass = submission_type(lang, code)
    if klass is not None:
        instance = klass(name, code)
        return instance
    print "Entry %s invalid - lang not supported: %s" % (name, lang)
    return None

def get_all_instances(force_update):
    scraper = Scraper()

    print 'Scraping Submissions..'

    pages = [1,2,3]
    submissions_by_page = [scraper.get_submissions(page=i, force_cache_update=force_update) for i in pages]
    submissions = [item for sublist in submissions_by_page for item in sublist]

    # Get instances
    raw_instances = [instantiate(s) for s in submissions]
    instances = [i for i in raw_instances if i]

    print "Using %i/%i Submissions" % (len(instances), len(submissions))

    return instances

def save_submissions(instances):
    print 'Saving Submissions..'

    for instance in instances:
        instance.save_submission()

def init_game(save=True, force_update=False):
    instances = get_all_instances(force_update)
    if save:
        save_submissions(instances)
    return instances

def one_run(instances, input):
    valid = {
        'good': 1,
        'evil': 0
    }

    disqualified = []
    results = []

    for instance in instances:
        out = instance.run_submission(input)
        res = out.strip().lower()
        if res not in valid:
            disqualified.append(instance)
        else:
            results.append(valid[res])

    return (results, disqualified)

def get_winner(scores, instances):
    max_value = max(scores)
    max_index = scores.index(max_value)
    instance = instances[max_index]
    return (instance.name, max_value)

def update_scores(results, scores, minority_counts, minority_num):
    for i in range(len(results)):
        if results[i] == minority_num:
            minority_counts[i] += 1
            scores[i] += (minority_counts[i] - 1)
        else:
            minority_counts[i] = 0
            scores[i] += 3

def try_run_game(instances, num_runs = 1000, blacklist = None):
    current_input = None
    minority_str = None
    num_instances = len(instances)
    scores = [0] * num_instances
    minority_counts = [0] * num_instances

    print "Running with %i instances..." % num_instances

    for i in range(num_runs):
        print "Round: %i - Last minority was %s" % (i, minority_str)
        results, disqualified = one_run(instances, current_input)

        if len(disqualified) > 0:
            for instance in disqualified:
                print "Removing %s!" % instance.name
                instances.remove(instance)

                if blacklist is not None:
                    with open(blacklist, 'a') as f:
                        f.write("%s\n" % instance.name)

            return False

        latest_result = "".join(map(str,results))
        current_input = "%s,%s" % (current_input, latest_result)

        minority_num = 1 if results.count(1) < results.count(0) else 0
        minority_str = 'good' if minority_num == 1 else 'evil'

        update_scores(results, scores, minority_counts, minority_num)
        name, score = get_winner(scores, instances)
        print "%s is currently winning with a score of %i" % (name, score)

    print "The winner is %s with a score of %i!!!" % (name, score)
    return True

def find_instance_by_name(instances, name):
    for instance in instances:
        if instance.name == name:
            return instance
    return None

def maybe_add_or_remove_baelish(instances, baelish):
    num_instances = len(instances)

    if num_instances % 2 == 0:
        print 'There are %i instances.' % num_instances
        try:
            instances.remove(baelish)
            print 'Baelish Removed!'
        except:
            instances.append(baelish)
            print 'Baelish Added!'

def remove_blacklisted(blacklist, instances):
    blacklisted = []

    try:
        blacklisted = open(blacklist).readlines()
    except:
        return

    print 'Removing blacklisted entries...'

    for name in blacklisted:
        name = name.strip()
        instance = find_instance_by_name(instances, name)
        if instance is not None:
            print 'Removing %s' % name
            instances.remove(instance)

def run_game(instances, num_runs):
    blacklist = 'blacklist.txt'
    remove_blacklisted(blacklist, instances)

    baelish = find_instance_by_name(instances, 'Petyr Baelish') 
    maybe_add_or_remove_baelish(instances, baelish)

    while not try_run_game(instances, num_runs = num_runs, blacklist = blacklist):
        print "Restarting!"
        maybe_add_or_remove_baelish(instances, baelish)

    print "Done!"

if __name__ == '__main__':
    param = sys.argv[1] if len(sys.argv) >= 2 else None

    if param == 'get':
        instances = init_game(save=True, force_update=True)
    elif param == 'run':
        instances = init_game(save=False, force_update=False)
        num_runs = 50
        if len(sys.argv) == 3:
            num_runs = int(sys.argv[2])
        run_game(instances, num_runs)
    else:
        self_name = os.path.basename(__file__)
        print "usage:"
        print "To get the latest code: 'python %s get'" % self_name
        print "To run the submissions: 'python %s run <optional num_runs>'" % self_name

포트란 언어가 없습니까?
Kyle Kanos

@KyleKanos-지원이 추가되었으며 코드가 곧 업데이트됩니다.
WhatAWorld

예이! 나는 (Sorta) Fortran 제출에 열심히 일했고 Rusher는 그것을 작동시킬 수 없어서 누군가 가 그것을
얻길 원합니다

1
@Rusher 다음과 같이 구문 강조 :이 하나 PeterTaylor에 동의 만을 제안 편집 거부해야합니다. 편집은 사소한 것이 아니라 실질적인 수정을 위해 사용되어야합니다 .
Kyle Kanos

1
당신은 이것에 대한 담당자를받을 자격이 있지만, 이것은 질문에 대한 대답이 아니기 때문에 (그리고 아마도 다른 언어로 물건을 추가하는 커뮤니티의 이점을 얻을 수 있음) 이것이 기술적으로 커뮤니티 위키라고 생각합니다.
마틴 엔더

13

아름다운 마음, 루비

마지막 라운드의 비트 표현에서 의심스러운 의미의 패턴을 기반으로 결정합니다.

require 'prime'

if ARGV.length == 0
    puts ["good", "evil"].sample
else
    last_round = ARGV[0].split(',').last
    puts Prime.prime?(last_round.to_i(2)) ? "good" : "evil"
end

다음과 같이 실행

ruby beautiful-mind.rb

13

인위적인, 루아

Signs and Wonders를 믿는 미신적 인 프로그램.

history = arg[1]

if history == nil then
    print("good")
else
    local EvilSigns, GoodSigns = 0,0
    local SoulSpace = ""

    for i in string.gmatch(history, "%d+") do
         SoulSpace = SoulSpace .. i 
    end

    if string.match(SoulSpace, "1010011010")  then -- THE NUBMER OF THE BEAST!
        local r = math.random(1000)
        if r <= 666 then print("evil") else print("good") end
    else
        for i in string.gmatch(SoulSpace, "10100") do -- "I'M COMING" - DEVIL
            EvilSigns = EvilSigns + 1
        end
        for i in string.gmatch(SoulSpace, "11010") do -- "ALL IS WELL" - GOD
            GoodSigns = GoodSigns + 1
        end

        if EvilSigns > GoodSigns then 
            print("evil")
        elseif GoodSigns > EvilSigns then
            print("good")
        elseif GoodSigns == EvilSigns then
            local r = math.random(1000)
            if r <= 666 then print("good") else print("evil") end
        end
    end
end

다음과 같이 실행하십시오.

lua Piustitious.lua

입력이 이어집니다.


11

윈체스터

샘과 딘은 좋다 (대부분의 시간).

package Humans;

public class TheWinchesters extends Human {

    @Override
    public String takeSides(String history) throws Exception {
        return Math.random() < 0.1 ? "evil" : "good";
    }

}

9:1올바른 비율 이 확실 합니까? 데이터 마이닝을 수행 하고 더 정확한 비율을 얻어야할까요?
recursion.ninja

1
@awashburn 나는 2 개월 전에 초자연을보고 시작 (지금 시즌 9에 붙어) 9:1나에게 좋아 보인다;)
CommonGuy

10

통계 학자

public class Statistician extends Human{
    public final String takeSides(String history) { 
        int side = 0;
        String[] hist = history.split(",");
        for(int i=0;i<hist.length;i++){
            for(char c:hist[i].toCharArray()){
                side += c == '1' ? (i + 1) : -(i + 1);
            }
        }
        if(side == 0) side += Math.round(Math.random());
        return side > 0 ? "good" : "evil";
    }
}

5
두 번째 마지막 줄은 정말 대단합니다
cjfaure

5
@Undeserved 대신 Math.ceil(Math.random()-Math.random())당신도 할 수 있습니다 Math.round(Math.random()).
tomsmeding

10

R, 다소 베이지안 봇

각 사용자에 대한 빈도 표를 다른 사용자 출력의 사전 확률로 사용하십시오.

args <- commandArgs(TRUE)
if(length(args)!=0){
    history <- do.call(rbind,strsplit(args,","))
    history <- do.call(rbind,strsplit(history,""))
    tabulated <- apply(history,2,function(x)table(factor(x,0:1)))
    result <- names(which.max(table(apply(tabulated, 2, function(x)sample(0:1,1, prob=x)))))
    if(result=="1"){cat("good")}else{cat("evil")}
}else{
    cat("good")
    }

Rscript BayesianBot.R다음에 입력을 사용하여 호출됩니다 .

편집 :이 작업을 명확하게하기 위해 입력 예제가있는 단계별 단계는 다음과 같습니다.

> args
[1] "11011,00101,11101,11111,00001,11001,11001"
> history #Each player is a column, each round a row
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    0    1    1
[2,]    0    0    1    0    1
[3,]    1    1    1    0    1
[4,]    1    1    1    1    1
[5,]    0    0    0    0    1
[6,]    1    1    0    0    1
[7,]    1    1    0    0    1

> tabulated #Tally of each player previous decisions.
  [,1] [,2] [,3] [,4] [,5]
0    2    2    4    5    0
1    5    5    3    2    7

그런 다음 result<-각 플레이어에 대해로 시작하는 행은 이 마지막 테이블을 가중치로 사용하여 무작위로 0 또는 1을 선택합니다 (즉, 플레이어 1의 경우 0을 선택할 확률은 2/7 일, 1 5/7을 따는 등). 각 플레이어 / 열에 대해 하나의 결과를 선택하고 마지막으로 가장 일반적인 숫자를 반환합니다.


10

스위스

항상 중립을 유지합니다. 절대 이길 운명이 아니었다.

package Humans;

/**
 * Never choosing a side, sustaining neutrality
 * @author Fabian
 */
public class Swiss extends Human {   
    public String takeSides(String history) {
        return "neutral"; // wtf, how boring is that?
    }
}

나는 이것을 쓰지 않았다!
Rainbolt

아이러니입니다. 중립성은 결코 이길 수 없습니다
fabigler

2
@Rusher 아 내가 지금 그것을 얻었다 : D
fabigler

1
컴파일조차되지 않으며 세미콜론이 없습니다.
Paŭlo Ebermann

9

HAL 9000

#!/usr/bin/env perl
print eval("evil")

편집 : 어쩌면 이것이 HAL 9000에 더 적합하지만 조심하십시오! 매우 악하다. cd디렉토리를 실행하기 전에 비우는 것이 좋습니다 .

#!/usr/bin/env perl
print eval {
    ($_) = grep { -f and !/$0$/ } glob('./*');
    unlink;
    evil
}

이것은 cwd각각의 호출 에서 하나의 파일을 제거합니다 !

그렇게 명백하지 않은 호출 :

M $

D:\>copy con hal_9000.pl
#!/usr/bin/env perl
print eval("evil")
^Z
        1 file(s) copied.

D:>hal_9000.pl
evil

* nix에서

[core1024@testing_pc ~]$ tee hal_9000.pl
#!/usr/bin/env perl
print eval("evil")
# Press C-D here
[core1024@testing_pc ~]$ chmod +x $_
[core1024@testing_pc ~]$ ./$_
evil[core1024@testing_pc ~]$

프로그램을 실행하는 데 사용할 수있는 명령을 제공해야합니다. 자세한 내용은 챌린지의 "납품"섹션을 참조하십시오.
Rainbolt

@Rusher Done;)
core1024

9

대다수의 의지

import sys
import random

if len(sys.argv)==1:
    print(random.choice(['good','evil']))
else:
    rounds=sys.argv[1].split(',')
    last_round=rounds[-1]
    zeroes=last_round.count('0')
    ones=last_round.count('1')
    if ones>zeroes:
        print('good')
    elif zeroes>ones:
        print('evil')
    elif ones==zeroes:
        print(random.choice(['good','evil']))

로 저장 WotM.py으로 실행, python3 WotM.py입력 하였다.

어떻게 작동하는지보기위한 간단한 프로그램입니다. 대다수가 마지막으로 말한 것과 달리 또는 무작위로 진행됩니다.


프로그램을 실행하는 데 사용할 수있는 명령을 제공해야합니다. 자세한 내용은 챌린지의 "납품"섹션을 참조하십시오.
Rainbolt

젠장, 그게 내 사본을 만듭니다. : D 광산을 소수로 변경했습니다.
마틴 엔더

@Rusher 명령을 추가했습니다. 그게 당신이 찾고 있던 것입니까?
isaacg

@isaacg 퍼펙트!
Rainbolt

1
스코어 보드의 점수에서 평균 순위를 계산했으며이 항목이 해당 수치로 이깁니다.
Brilliand

9

앨런 시어러

옆에 앉은 사람이 방금 말한 것을 반복합니다. 그 사람이 틀린 것으로 판명되면, 그 사람은 다음 사람으로 넘어 가서 대신 말하는 것을 반복합니다.

package Humans;

/**
 * Alan Shearer copies someone whilst they're right; if they get predict
 * wrongly then he moves to the next person and copies whatever they say.
 *
 * @author Algy
 * @url http://codegolf.stackexchange.com/questions/33137/good-versus-evil
 */
public class AlanShearer extends Human {

    private char calculateWinner(String round) {
        int good = 0, evil = 0;

        for (int i = 0, L = round.length(); i < L; i++) {
            if (round.charAt(i) == '1') {
                good++;
            } else {
                evil++;
            }
        }

        return (good >= evil) ? '1' : '0';
    }

    /**
     * Take the side of good or evil.
     * @param history The past votes of every player
     * @return A String "good" or "evil
     */
    public String takeSides(String history) {
        String[] parts = history.split(",");
        String lastRound = parts[parts.length() - 1];

        if (parts.length() == 0 || lastRound.length() == 0) {
            return "good";
        } else {
            if (parts.length() == 1) {
                return lastRound.charAt(0) == '1' ? "good" : "evil";
            } else {
                int personToCopy = 0;

                for (int i = 0, L = parts.length(); i < L; i++) {
                    if (parts[i].charAt(personToCopy) != calculateWinner(parts[i])) {
                        personToCopy++;

                        if (personToCopy >= L) {
                            personToCopy = 0;
                        }
                    }
                }
            }

            return lastRound.charAt(personToCopy) == '1' ? "good" : "evil";
        }
    }
}

lastRound선언하기 전에 호출 된 변수를 참조 합니다. 또한 모든 괄호를 추가 String.length했지만 기능이 아닙니다. 컴파일 지점으로 제출할 수 있습니까?
Rainbolt

@Rusher-done :)
Algy Taylor

@Algy : lastRound.length전에 lastRound선언 되어 있습니다 (첫 번째 if 에서). 여기에 코드를 제출하기 전에 코드를 컴파일하고 실행하십시오.
Paŭlo Ebermann

@ PaŭloEbermann-사과합니다, 저는 그것을 운영 할 수있는 환경에 있지 않습니다-그러나 수정
Algy Taylor

이제 범위를 벗어나면 "personToCopy"라는 변수를 참조합니다. 방금 else 블록으로 옮겨서 컴파일 할 수는 있었지만 그것이 원하는지 모르겠습니다.
Rainbolt

8

나중에는 악, JavaScript ( node.js )입니다

실행 사이의 시간을 측정합니다. 시차가 마지막 시간보다 크면 사악해야합니다. 그렇지 않으면 좋습니다.

var fs = require('fs'),
currentTime = (new Date).getTime();

try {
    var data = fs.readFileSync('./laterisevil.txt', 'utf8');
} catch (e) { data = '0 0'; } // no file? no problem, let's start out evil at epoch

var parsed = data.match(/(\d+) (\d+)/),
lastTime = +parsed[1],
lastDifference = +parsed[2],
currentDifference = currentTime - lastTime;

fs.writeFileSync('./laterisevil.txt', currentTime + ' ' + currentDifference, 'utf8');
console.log(currentDifference > lastDifference? 'evil' : 'good');

로 실행 : node laterisevil.js


8

패턴 파인더, Python

되풀이되는 패턴을 찾고, 찾을 수 없으면 대다수와 함께갑니다.

import sys

if len(sys.argv) == 1: 
    print('good')
    quit()

wins = ''.join(
    map(lambda s: str(int(s.count('1') > s.count('0'))),
        sys.argv[1].split(',')
    )
)

# look for a repeating pattern
accuracy = []

for n in range(1, len(wins)//2+1):
    predicted = wins[:n]*(len(wins)//n)
    actual    = wins[:len(predicted)]
    n_right = 0
    for p, a in zip(predicted, actual):
        n_right += (p == a)
    accuracy.append(n_right/len(predicted))

# if there's a good repeating pattern, use it
if accuracy:
    best = max(accuracy)
    if best > 0.8:
        n = accuracy.index(best)+1
        prediction = wins[:n][(len(wins))%n]
        # good chance of success by going with minority
        if prediction == '1':
            print('evil')
        else:
            print('good')
        quit()

# if there's no good pattern, just go with the majority
if wins.count('1') > wins.count('0'):
    print('good')
else:
    print('evil')

와 실행

python3 pattern_finder.py

1
나는이 코드를 너무 좋아해서 그것을 실행할 때 항상 3000pt를 얻습니다.
Realdeo

8

턴 코트

턴 코트는 지금까지 다른 전투원들 때문에 대다수는 선과 악이 같은면에 머무르는 것보다 더 자주 선과 악을 번갈아 가며 교대 할 것이라고 믿고있다. 따라서 그는 선으로 사이딩을하여 첫 번째 라운드를 시작한 다음 승리 또는 패배 팀에 더 자주 머 무르지 않기 위해 모든 라운드를 번갈아 진행합니다.

package Humans;

public class Turncoat extends Human {
    public final String takeSides(String history) {
        String[] hist = history.split(",");

        return (hist.length % 2) == 0 ? "good" : "evil";
    }
}

이 글을 쓰고 난 후, 통계 분석에 기반한 항목으로 인해 더 많은 라운드가 완료되면 모멘텀으로 인해 측면이 덜 전환 될 수 있음을 깨달았습니다. 따라서 게으른 턴 코트입니다.

게으른 턴 코트

게으른 턴 코트는 턴 코트처럼 시작하지만 라운드가 지나면 다른쪽으로 전환하기 위해 게으름과 게으름이 생깁니다.

package Humans;

public class LazyTurncoat extends Human {
    public final String takeSides(String history) {
        int round = history.length() == 0 ? 0 : history.split(",").length;
        int momentum = 2 + ((round / 100) * 6);
        int choice = round % momentum;
        int between = momentum / 2;

        return choice < between ? "good" : "evil";
    }
}

2
게으른 턴 코트는 훌륭합니다!
Angelo Fuchs

마음에 들지 않으면 둘 다 포함시킵니다.
Rainbolt

어서 나는 투표 통계를 컴파일하는 것과 비교하여 두 가지가 어떻게 될지 궁금합니다.
jaybz

@Rainbolt 방금 Turncoat의 바보 같은 버그를 발견했습니다. 그래도 수정할 필요가 없습니다. 그것은 완전히 의도 된대로가 아니라 여전히 작동하며, 수정하기에 너무 늦지 않더라도 수정하면 새로운 항목 중 하나와 똑같이 동작합니다. 원하는 경우 자유롭게 포함 / 제외하십시오.
jaybz

8

전기 작가, 루비

rounds = ARGV[0].split(',') rescue []

if rounds.length < 10
  choice = 1
else
  outcome_history = ['x',*rounds.map{|r|['0','1'].max_by{|s|r.count s}.tr('01','ab')}]
  player_histories = rounds.map{|r|r.chars.to_a}.transpose.map{ |hist| outcome_history.zip(hist).join }
  predictions = player_histories.map do |history|
    (10).downto(0) do |i|
      i*=2
      lookbehind = history[-i,i]
      @identical_previous_behavior = history.scan(/(?<=#{lookbehind})[10]/)
      break if @identical_previous_behavior.any?
    end
    if @identical_previous_behavior.any?
      (@identical_previous_behavior.count('1')+1).fdiv(@identical_previous_behavior.size+2)
    else
      0.5
    end
  end
  simulations = (1..1000).map do
    votes = predictions.map{ |chance| rand < chance ? 1 : 0 }
    [0,1].max_by { |i| votes.count(i) }
  end
  choice = case simulations.count(1)/10
    when 0..15
      1
    when 16..50
      0
    when 51..84
      1
    when 85..100
      0
  end
end

puts %w[evil good][choice]

거의 똑똑한 입장에서 나의 시도 (실제로 똑똑한 것은 현장에 대한 테스트가 필요하다). 루비로 작성되었으므로 속도가 너무 느릴 수 있지만 내 컴퓨터에서는 무작위 플레이어가 40 명일 때 마지막 라운드를 계산하는 데 11.11 초가 걸리므로 제대로 작동하기를 바랍니다.

다른 이름으로 저장 biographer.rb, 다른 이름으로 실행ruby biographer.rb

아이디어는 각 플레이어에 대해 지난 10 라운드에 대한 자신의 선택과 전체 결과를 모두보고 과거와 동일한 상황 (예 : 투표 + 전체)을 찾아 "좋은"선택 기회를 추정한다는 것입니다. 결과)가 발생했습니다. 그것은 가장 긴 lookbehind 길이, 최대 10 라운드를 선택하여 선례가 있고 빈도를 생성하는 데 사용합니다 (Laplace의 승계 법에 따라 조정되어 100 % 자신감을 가지지 않습니다).

그런 다음 몇 가지 시뮬레이션을 실행하고 Good이 얼마나 자주 승리하는지 확인합니다. 시뮬레이션이 대부분 같은 방식으로 밝혀지면 일반적으로 예측을 잘 수행하여 예측 된 소수를 선택합니다. 확신이 없으면 예상 과반수를 선택합니다.


8

유다

유다는 정말 좋은 사람입니다. 그가 몇 명의 돈을 위해 좋은 사람들을 배신하는 것은 유감입니다.

package Humans;

public class Judas extends Human {

    private static final String MONEY = ".*?0100110101101111011011100110010101111001.*?";

    public String takeSides(String history) {
       return history != null && history.replace(",","").matches(MONEY) ? "evil" : "good";
    }
}

1
이것은 오직 충분한 참가자가있는 경우, 당신은 제거 할 수 악 투표 ,의 아웃 history다그 침 쟁은 그룹으로 게임을 분할 예정으로 더욱 더.
Angelo Fuchs

나는 그가 게임을 그룹으로 나눌 것이라는 것을 몰랐다. 실제로 문자열 크기 때문에 답변을 게시하기 전에이 질문에 충분한 제출이있을 때까지 기다렸습니다. 알려 줘서 고마워.
William Barbosa

Windows의 프로세스에 60000 문자 인수를 전달하는 방법을 알고 있다면 알려주십시오. 그렇지 않으면 항목을 엉망으로하여 죄송합니다. 수정 해 주셔서 감사합니다. 나는 너무 많은 제출을 기대하지 않았다.
Rainbolt

7

악의적 인 도박꾼 (파이썬)

만약 한 쪽이 연속으로 다수를 이겼다면, 도박꾼은 다른 쪽이 다음 라운드에서 다수가 될 가능성이 높다는 것을 인식하고 (오른쪽?) 이것이 그의 투표에 영향을 미칩니다. 그는 소수를 목표로한다. 일단 소수에 도달하면 여러 번 거기에 올 수 있고 (오른쪽?) 많은 점수를 얻을 수 있기 때문이다.

import sys
import random

def whoWon(round):
    return "good" if round.count("1") > round.count("0") else "evil"

if len(sys.argv) == 1:
    print random.choice(["good", "evil"])
else:
    history = sys.argv[1]
    rounds = history.split(",")
    lastWin = whoWon(rounds[-1])
    streakLength = 1
    while streakLength < len(rounds) and whoWon(rounds[-streakLength]) == lastWin:
        streakLength += 1
    lastLoss = ["good", "evil"]
    lastLoss.remove(lastWin)
    lastLoss = lastLoss[0] 
    print lastWin if random.randint(0, streakLength) > 1 else lastLoss  

용법

첫 라운드 :

python gambler.py

그 후 :

python gambler.py 101,100,001 etc.

4
나는 당신이 당신의 코드를 어떻게 확신하는지 좋아합니다. : P
IEatBagels

7

세포질 오토 마톤

이것은 Conway의 Game of Life에 대한 기존 규칙을 사용하여 측면을 선택합니다. 먼저, 이전 투표에서 2D 그리드가 생성됩니다. 그런 다음 "세계"가 한 단계 앞으로 진행되고 남아있는 총 살아있는 세포 수가 계산됩니다. 이 수가 총 셀 수의 절반보다 큰 경우 "양호"가 선택됩니다. 그렇지 않으면 "악"이 선택됩니다.

실수를 용서해주십시오, 이것은 점심 시간 동안 박살났습니다. ;)

package Humans;

public class CellularAutomaton extends Human {

    private static final String GOOD_TEXT = "good";

    private static final String EVIL_TEXT = "evil";

    private int numRows;

    private int numColumns;

    private int[][] world;

    @Override
    public String takeSides(String history) {
        String side = GOOD_TEXT;

        if (history.isEmpty()) {
            side = Math.random() <= 0.5 ? GOOD_TEXT : EVIL_TEXT;
        }

        else {
            String[] prevVotes = history.split(",");

            numRows = prevVotes.length;

            numColumns = prevVotes[0].length();

            world = new int[numRows][numColumns];

            for (int i = 0; i < numColumns; i++) {
                for (int j = 0; j < numRows; j++) {
                    world[j][i] =
                        Integer.parseInt(Character.toString(prevVotes[j].charAt(i)));
                }
            }

            int totalAlive = 0;
            int total = numRows * numColumns;
            for (int i = 0; i < numColumns; i++) {
                for (int j = 0; j < numRows; j++) {
                    totalAlive += getAlive(world, i, j);
                }
            }
            if (totalAlive < total / 2) {
                side = EVIL_TEXT;
            }
        }

        return side;
    }

    private int getAlive(int[][] world, int i, int j) {
        int livingNeighbors = 0;

        if (i - 1 >= 0) {
            if (j - 1 >= 0) {
                livingNeighbors += world[j - 1][i - 1];
            }
            livingNeighbors += world[j][i - 1];
            if (j + 1 < numRows) {
                livingNeighbors += world[j + 1][i - 1];
            }
        }
        if (j - 1 >= 0) {
            livingNeighbors += world[j - 1][i];
        }
        if (j + 1 < numRows) {
            livingNeighbors += world[j + 1][i];
        }
        if (i + 1 < numColumns) {
            if (j - 1 >= 0) {
                livingNeighbors += world[j - 1][i + 1];
            }
            livingNeighbors += world[j][i + 1];
            if (j + 1 < numRows) {
                livingNeighbors += world[j + 1][i + 1];
            }
        }

        return livingNeighbors > 1 && livingNeighbors < 4 ? 1 : 0;
    }
}

1
테스트를 위해 코드에서 인쇄 라인을 제거했습니다. Java 항목은 인쇄하지 않고 선이나 악을 반환하면됩니다.
Rainbolt

7

릿지 교수

라이브러리를 사용하는 것이 허용되기를 바랍니다. 하나 없이이 작업을 수행하고 싶지 않다 =)

기본 아이디어는 각 라운드 전에 30 개의 결과를 기능으로 사용하여 마지막 라운드에서 각 참가자에 대해 능선 회귀 분류기를 학습하는 것입니다. 원래 모든 플레이어가 각 플레이어의 결과를 예측할 수 있도록 마지막 결과 라운드를 포함 시켰지만, 참가자 수가 많아 질수록 (예 : 50 정도) 시간이 다소 단축되었습니다.

#include <iostream>
#include <string>
#include <algorithm>
#include "Eigen/Dense"

using Eigen::MatrixXf;
using Eigen::VectorXf;
using Eigen::IOFormat;
using std::max;

void regress(MatrixXf &feats, VectorXf &classes, VectorXf &out, float alpha = 1) {
    MatrixXf featstrans = feats.transpose();
    MatrixXf AtA = featstrans * feats;

    out = (AtA + (MatrixXf::Identity(feats.cols(), feats.cols()) * alpha)).inverse() * featstrans * classes;
}

float classify(VectorXf &weights, VectorXf &feats) {
    return weights.transpose() * feats;
}

size_t predict(MatrixXf &train_data, VectorXf &labels, VectorXf &testitem) {
    VectorXf weights;
    regress(train_data, labels, weights);
    return (classify(weights, testitem) > 0 ? 1 : 0);
}

static const int N = 30;
static const int M = 10;
// use up to N previous rounds worth of data to predict next round
// train on all previous rounds available
size_t predict(MatrixXf &data, size_t prev_iters, size_t n_participants) {
    MatrixXf newdata(data.rows(), data.cols() + max(N, M));
    newdata << MatrixXf::Zero(data.rows(), max(N, M)), data;

    size_t n_samples = std::min(500ul, prev_iters);
    if (n_samples > (8 * max(N, M))) {
        n_samples -= max(N,M);
    }
    size_t oldest_sample = prev_iters - n_samples;
    MatrixXf train_data(n_samples, N + M + 1);
    VectorXf testitem(N + M + 1);
    VectorXf labels(n_samples);
    VectorXf averages = newdata.colwise().mean();
    size_t n_expected_good = 0;
    for (size_t i = 0; i < n_participants; ++i) {
        for (size_t iter = oldest_sample; iter < prev_iters; ++iter) {
            train_data.row(iter - oldest_sample) << newdata.row(i).segment<N>(iter + max(N, M) - N)
                                  , averages.segment<M>(iter + max(N, M) - M).transpose()
                                  , 1; 
        }
        testitem.transpose() << newdata.row(i).segment<N>(prev_iters + max(N, M) - N)
                  , averages.segment<M>(prev_iters + max(N, M) - M).transpose()
                  , 1;
        labels = data.row(i).segment(oldest_sample, n_samples);
        n_expected_good += predict(train_data, labels, testitem);
    }
    return n_expected_good;
}


void fill(MatrixXf &data, std::string &params) {
    size_t pos = 0, end = params.size();
    size_t i = 0, j = 0;
    while (pos < end) {
        switch (params[pos]) {
            case ',':
                i = 0;
                ++j;
                break;
            case '1':
                data(i,j) = 1;
                ++i;
                break;
            case '0':
                data(i,j) = -1;
                ++i;
                break;
            default:
                std::cerr << "Error in input string, unexpected " << params[pos] << " found." << std::endl;
                std::exit(1);
                break;
        }
        ++pos;
    }
}

int main(int argc, char **argv) {
    using namespace std;

    if (argc == 1) {
        cout << "evil" << endl;
        std::exit(0);
    }

    string params(argv[1]);
    size_t n_prev_iters = count(params.begin(), params.end(), ',') + 1;
    size_t n_participants = find(params.begin(), params.end(), ',') - params.begin();

    MatrixXf data(n_participants, n_prev_iters);
    fill(data, params);

    size_t n_expected_good = predict(data, n_prev_iters, n_participants);

    if (n_expected_good > n_participants/2) {
        cout << "evil" << endl;
    } else {
        cout << "good" << endl;
    }
}

컴파일하기

소스 코드를이라는 파일에 저장하고 Eigen 라이브러리를 ridge_professor.cc다운로드 한 다음 내부에있는 Eigen 폴더를 소스 파일과 동일한 폴더에 압축 해제하십시오. 로 컴파일하십시오 .g++ -I. -O3 -ffast-math -o ridge_professor ridge_professor.cc

실행

ridge_professor.exe를 호출하고 필요에 따라 인수를 제공하십시오.

질문

아직 아무데도 언급 할 수 없으므로 여기에서 물어볼 것입니다 .Windows의 인수 크기 제한으로 인해 전체 이력을 가진 결과 바이너리를 몇 백 번 회전시키는 것이 불가능하지 않습니까? 나는 논쟁에서 ~ 9000자를 넘을 수 없다고 생각했다 ...


이것에 관심을 가져 주셔서 감사합니다 . Java에서 아직 제대로 작동하지 않는 경우 작동시키는 방법을 알아 보겠습니다. Java가 할 수 없다면 C ++이 가능하다는 연구 결과가 있으며 C ++을 다시 배울 기회를 얻습니다. 곧 테스트 결과를 보도록하겠습니다.
Rainbolt

결과적으로 Java는 명령 프롬프트의 제한 사항이 아닙니다. 32k보다 큰 명령 만 문제를 일으키는 것으로 보입니다. docs.google.com/document/d/… 라는 내 증거는 다음과 같습니다 . 다시 한 번, 내일 시험이 시작되기 전에이 문제를 제기 해 주셔서 감사합니다.
레인 볼트

@Rusher 이미 57 개의 봇이 있으며 각 라운드마다 1000 라운드로 구성됩니다. 그러면 문자열이 57k 자 (따라서 32k 이상)가됩니까?
plannapus

1
@Rusher 저는 일주일 더 타임 라인을 연장하고 참가자들에게 인수 문자열을 사용하는 대신 stdin을 읽도록 프로그램을 변경하도록 요청하는 것이 좋습니다. 대부분의 프로그램이 변경
되기에는 쉽지 않습니다

@dgel 도전의 타임 라인은 무한히 길지만 모든 사람이 답을 다시 써야하는 방식으로 규칙을 바꾸고 싶지 않습니다. 나는 지난 밤에 추가 한 규칙이 단일 제출을 망칠 것이라고 확신하며, 그가 프로그램을 컴파일하는 지점으로 데려 가면 그 사람을 도울 계획입니다.
Rainbolt

6

크로울리

윈체스터는이 동료 없이는 훨씬 덜 흥미 롭기 때문입니다. 그는 더 큰 악을 돌봐야 할 필요가 없다면 분명히 악과 마주칩니다.

package Humans;

public class Crowley extends Human {
public String takeSides(String history) {
    int gd = 0, j=history.length(), comma=0, c=0, z=0;
    while(comma < 2 && j>0)   {
        j--;
        z++;
        if (history.charAt(j) == ',') {
            comma++;
            if(c> z/2) {gd++;}
            z=0;
            c=0;
        } else if (history.charAt(j)=='1') {
            c++;
        } else {
        }
    }
    if(gd == 0){
        return "good";
    } else {
        return "evil";
    }
}}

나는 마지막 두 턴 (지금까지는 쉼표 0, 지금까지는 1 개의 쉼표)을보고 둘 다 악의로 이길 수 있다면, 나는 좋은 투표를한다. 그렇지 않으면 나는 악을 표합니다.


이게 맞나요? 당신은 마지막 턴을보고 50 % 미만이 "좋은"투표를한다면 당신은 "좋은"투표를하고 그렇지 않으면 다른 것을 악으로 간주합니다. (호기심에서 : 암호 변수 이름을 선호합니까 아니면 우연입니까?)
Angelo Fuchs

1
@ AngeloNeuschitzer 나는 마지막 두 차례 (0 쉼표와 1 쉼표까지)를보고 둘 다 악의로 이길 수 있다면, 나는 좋은 투표를합니다. 그렇지 않으면 나는 악을 표합니다. 코드가 짧으면 코드의 목적이 혼란스럽지 않으면 입력하기가 짧은 변수 이름을 선호합니다. 나는 전문 프로그래머가 아니며 이것은 자바에서 프로그래밍 한 적이 있거나 6.5 년 동안 다른 사람이 코드를 본 것입니다. 나는 이것을 기억을 되살리기 위해 썼다. (TLDR 그들은 나에게 암호가 아니며 내가 보통 코딩하는 유일한 사람이다.)
kaine

명확하게하기 위해 ... 크라 울리 인간으로 시작 그가 빌어 먹을 ... 그를하지만 모든 라운드 좋은 유지 기대하지 않았다 ... 좋은 시작 의도적 그래서
케인
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.