人狼知能セミナ
人狼知能セミナ2016に参加しました。
人狼知能はその名の通り人狼をAIでやっちまおうというプロジェクトです。
「まだ」実際に日本語を読んで日本語で発言するというわけではなく、ある程度すべきことや情報があらかじめパターン化されているので、それらを駆使して有効な行動をするものを作ろうというものです。詳しくはリンク先で。
タイムスケジュールは、午前中人狼知能の説明と、開発環境及び方法の導入。
午後いっぱいつかって各自エージェントを開発し、最後に対戦させるというスケジュール。午後のエージェント作成については、時間が3時間しかないということもあり、最初に1つ役職を割り当てられ、それについてのみの行動をつくるということになりました。
今回は、勝率が高いとのことにそそのかされて「人狼」を志願しました。
作成したエージェント
全員初心者ということだったので、「人狼知能初心者が3時間でつくれるエージェントには勝てるエージェント」を目標に据えて開発しました。
まず最初の30分で簡単なプログラムをつくって意図どおりに出力されるかなどの具合の確認。
次の30分で作るものの検討。あんまり細かいところは作ってられないので、他人の発言はほとんど無視で、次のような感じに。実際にこんなのいたらすぐ吊られそうですが、上記目標を前提に気にせず割りきってます。
役割「人狼」のエージェント
- 襲撃対象(attack)
- 占い師COが1人のみで、それが生きてて狼じゃなければ襲撃
- 生きてて狼じゃなくて占い師COしてない人からランダム
- 発言(talk)
- 最初の発言時点で誰も占い師COしてなければ占い師CO
- 占い師CO済みであれば毎日生きてる人間からランダムで黒認定
- 占い師COできなければ以降なにも発言しない
- 吊り投票(vote)
- 生きてる人間の中から狼以外でランダム
次の1時間で実装し、最後の1時間でデバッグ。バグだらけだったのでギリギリでした。
サンプルエージェント相手では100戦で80勝くらいにはなりました。
結果
100回対戦して、人狼側の99勝1敗。
占い師担当のかたが不慣れなのか占い師COを実装しておらず、図らずも全対戦で騙り占い師のみが存在する状況になってしまったようです。
15人対戦で3人が狼なので、自分だけの貢献ではないのですが、うまくいった感じはしました。
今回は勝てましたが、人狼知能サイト上で公開されているKajiAgent相手にはボロ負けだったので、当然ですがこんなのじゃ本戦には出られませんけど。
懇親会
@todojunさんや@fmhr__さんとお話しました。また会える気がしています。
今後について
まだわかんないですけど、たぶん第二回人狼知能大会に参加する気がしてます。やってみれば意外と敷居は低かったのです。
興味あるかたは6月にも同じイベントがあるそうなので参加してみてはいかがでしょうか。
ソースコード
こんな感じになりました。超適当。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
public class McreWerewolf extends AbstractWerewolf { private Set<Agent> coSeerList = new HashSet<Agent>(); private List<Agent> divinedList = new ArrayList<Agent>(); private boolean seerCo = false; private boolean divinedToday = false; @Override public Agent attack() { List<Agent> attackList = getLatestDayGameInfo().getAliveAgentList(); //狼をリストから消す for(Agent a: getWolfList()){ attackList.remove(a); } //占い師COが一人で、アタックリストにいる(生きてて狼じゃない)なら咬む if(coSeerList.size() == 1){ if(attackList.contains(coSeerList.toArray()[0])){ return (Agent)coSeerList.toArray()[0]; } } //占い師COが二人以上のときはリストから消す if(coSeerList.size() >= 2){ for(Agent a: coSeerList){ attackList.remove(a); } } if(attackList.size() > 0){ return randomSelect(attackList); }else{ //対象が居ない場合は自分も含め生きてる中からランダム(ありえないはずだけど) return randomSelect(getLatestDayGameInfo().getAliveAgentList()); } } @Override public void update(GameInfo gameInfo) { super.update(gameInfo); List<Talk> talkList = gameInfo.getTalkList(); for(int i = 0; i< talkList.size(); i++){ Talk talk = talkList.get(i); Utterance u = new Utterance(talk.getContent()); switch(u.getTopic()){ case COMINGOUT: if(u.getRole() == Role.SEER && u.getTarget().equals(talk.getAgent())){ coSeerList.add(talk.getAgent()); } break; case AGREE: break; case ATTACK: break; case DISAGREE: break; case DIVINED: break; case ESTIMATE: break; case GUARDED: break; case INQUESTED: break; case OVER: break; case SKIP: break; case VOTE: break; default: break; } } } @Override public void dayStart() { divinedToday = false; } @Override public void finish() { coSeerList = new HashSet<Agent>(); divinedList = new ArrayList<Agent>(); seerCo = false; divinedToday = false; } @Override public String talk() { //よくわからないので初日は何もしない if(getDay()==0){ return null; } //占い師COがいなければ占い師CO if(coSeerList.size() == 0){ seerCo = true; return TemplateTalkFactory.comingout(getMe(), Role.SEER); } //占い師COしてれば、1発言目で人狼以外で生きててまだ占ってない人をランダムに黒指定 if(seerCo && !divinedToday){ List<Agent> divineList = getLatestDayGameInfo().getAliveAgentList(); //狼をリストから消す for(Agent a: getWolfList()){ divineList.remove(a); } //占った人をリストから消す for(Agent a: divinedList){ divineList.remove(a); } //残った中からランダム if(divineList.size() > 0){ Agent target = randomSelect(divineList); divinedToday = true; divinedList.add(target); return TemplateTalkFactory.divined(target, Species.WEREWOLF); } } //それ以外は何もしない return null; } @Override public Agent vote() { //とりあえず生きてる中から狼以外でランダム List<Agent> voteList = getLatestDayGameInfo().getAliveAgentList(); for(Agent a: getLatestDayGameInfo().getRoleMap().keySet()){ voteList.remove(a); } return randomSelect(voteList); } @Override public String whisper() { return null; } private Agent randomSelect(List<Agent> agentList){ int num = new Random().nextInt(agentList.size()); return agentList.get(num); } } |
(以上のプログラムの著作権を放棄します。念のためです。)