2 * Summarize game information
4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.jindolf.summary;
10 import java.net.MalformedURLException;
12 import java.net.URISyntaxException;
14 import java.text.DateFormat;
15 import java.util.Collections;
16 import java.util.Comparator;
17 import java.util.Date;
18 import java.util.EnumMap;
19 import java.util.HashMap;
20 import java.util.LinkedList;
21 import java.util.List;
24 import jp.sfjp.jindolf.VerInfo;
25 import jp.sfjp.jindolf.data.Avatar;
26 import jp.sfjp.jindolf.data.Period;
27 import jp.sfjp.jindolf.data.Player;
28 import jp.sfjp.jindolf.data.SysEvent;
29 import jp.sfjp.jindolf.data.Talk;
30 import jp.sfjp.jindolf.data.Topic;
31 import jp.sfjp.jindolf.data.Village;
32 import jp.sfjp.jindolf.dxchg.FaceIconSet;
33 import jp.sfjp.jindolf.dxchg.WolfBBS;
34 import jp.sourceforge.jindolf.corelib.Destiny;
35 import jp.sourceforge.jindolf.corelib.GameRole;
36 import jp.sourceforge.jindolf.corelib.SysEventType;
37 import jp.sourceforge.jindolf.corelib.Team;
38 import jp.sourceforge.jindolf.corelib.VillageState;
43 public class GameSummary{
45 /** キャスティング表示用Comparator。 */
46 public static final Comparator<Player> COMPARATOR_CASTING =
47 new CastingComparator();
49 private static final String GENERATOR =
50 VerInfo.TITLE + "\u0020Ver." + VerInfo.VERSION;
53 private final Map<Avatar, Player> playerMap =
54 new HashMap<Avatar, Player>();
55 private final List<Player> playerList =
56 new LinkedList<Player>();
57 private final Map<SysEventType, List<SysEvent>> eventMap =
58 new EnumMap<SysEventType, List<SysEvent>>(SysEventType.class);
60 private final Village village;
66 private int ctScryVillage = 0;
67 private int ctScryHamster = 0;
68 private int ctScryMadman = 0;
69 private int ctScryWolf = 0;
72 private int ctGuardVillage = 0;
73 private int ctGuardHamster = 0;
74 private int ctGuardMadman = 0;
75 private int ctGuardWolf = 0;
76 private int ctGuardVillageGJ = 0;
77 private int ctGuardHamsterGJ = 0;
78 private int ctGuardMadmanGJ = 0;
79 private int ctGuardFakeGJ = 0;
82 private long talk1stTimeMs = -1;
83 private long talkLastTimeMs = -1;
90 public GameSummary(Village village){
93 VillageState state = village.getState();
94 if( state != VillageState.EPILOGUE
95 && state != VillageState.GAMEOVER){
96 throw new IllegalStateException();
99 this.village = village;
108 * プレイヤーのリストから役職バランス文字列を得る。
110 * @param players プレイヤーのリスト
113 public static String getRoleBalanceSequence(List<Player> players){
114 List<GameRole> roleList = new LinkedList<GameRole>();
115 for(Player player : players){
116 GameRole role = player.getRole();
119 Collections.sort(roleList, GameRole.getPowerBalanceComparator());
121 StringBuilder result = new StringBuilder();
122 for(GameRole role : roleList){
123 char ch = role.getShortName();
127 return result.toString();
133 private void summarize(){
140 for(Period period : this.village.getPeriodList()){
141 summarizePeriod(period);
151 * SysEventの種別ごとに集計する。
153 private void buildEventMap(){
154 for(SysEventType type : SysEventType.values()){
155 List<SysEvent> eventList = new LinkedList<SysEvent>();
156 this.eventMap.put(type, eventList);
159 for(Period period : this.village.getPeriodList()){
160 for(Topic topic : period.getTopicList()){
161 if( ! (topic instanceof SysEvent) ) continue;
162 SysEvent event = (SysEvent) topic;
163 SysEventType type = event.getSysEventType();
164 List<SysEvent> eventList = this.eventMap.get(type);
165 eventList.add(event);
175 private void summarizeWinner(){
176 List<SysEvent> eventList;
178 eventList = this.eventMap.get(SysEventType.WINVILLAGE);
179 if( ! eventList.isEmpty() ){
180 this.winner = Team.VILLAGE;
183 eventList = this.eventMap.get(SysEventType.WINWOLF);
184 if( ! eventList.isEmpty() ){
185 this.winner = Team.WOLF;
188 eventList = this.eventMap.get(SysEventType.WINHAMSTER);
189 if( ! eventList.isEmpty() ){
190 this.winner = Team.HAMSTER;
193 if(this.winner == null) assert false;
201 private void summarizePlayers(){
202 List<SysEvent> eventList;
204 List<Avatar> avatarList;
205 List<GameRole> roleList;
206 List<Integer> integerList;
207 List<CharSequence> textList;
209 eventList = this.eventMap.get(SysEventType.ONSTAGE);
210 for(SysEvent event : eventList){
211 avatarList = event.getAvatarList();
212 integerList = event.getIntegerList();
213 Avatar onstageAvatar = avatarList.get(0);
214 Player onstagePlayer = registPlayer(onstageAvatar);
215 onstagePlayer.setEntryNo(integerList.get(0));
218 eventList = this.eventMap.get(SysEventType.PLAYERLIST);
219 assert eventList.size() == 1;
220 SysEvent event = eventList.get(0);
222 avatarList = event.getAvatarList();
223 roleList = event.getRoleList();
224 integerList = event.getIntegerList();
225 textList = event.getCharSequenceList();
226 int avatarNum = avatarList.size();
227 for(int idx = 0; idx < avatarNum; idx++){
228 Avatar avatar = avatarList.get(idx);
229 GameRole role = roleList.get(idx);
230 CharSequence urlText = textList.get(idx * 2);
231 CharSequence idName = textList.get(idx * 2 + 1);
232 int liveOrDead = integerList.get(idx);
234 Player player = registPlayer(avatar);
235 player.setRole(role);
236 player.setUrlText(urlText.toString());
237 player.setIdName(idName.toString());
238 if(liveOrDead != 0){ // 生存
239 player.setObitDay(-1);
240 player.setDestiny(Destiny.ALIVE);
243 this.playerList.add(player);
251 * @param period Period
253 private void summarizePeriod(Period period){
254 int day = period.getDay();
255 for(Topic topic : period.getTopicList()){
256 if(topic instanceof SysEvent){
257 SysEvent sysEvent = (SysEvent) topic;
258 summarizeDestiny(day, sysEvent);
268 * @param sysEvent システムイベント
270 private void summarizeDestiny(int day, SysEvent sysEvent){
271 List<Avatar> avatarList = sysEvent.getAvatarList();
272 List<Integer> integerList = sysEvent.getIntegerList();
274 int avatarTotal = avatarList.size();
275 Avatar lastAvatar = null;
276 if(avatarTotal > 0) lastAvatar = avatarList.get(avatarTotal - 1);
278 SysEventType eventType = sysEvent.getSysEventType();
280 case EXECUTION: // G国のみ
281 if(integerList.get(avatarTotal - 1) > 0) break; // 処刑無し
282 Player executedPl = registPlayer(lastAvatar);
283 executedPl.setDestiny(Destiny.EXECUTED);
284 executedPl.setObitDay(day);
287 Avatar suddenDeathAvatar = avatarList.get(0);
288 Player suddenDeathPlayer = registPlayer(suddenDeathAvatar);
289 suddenDeathPlayer.setDestiny(Destiny.SUDDENDEATH);
290 suddenDeathPlayer.setObitDay(day);
292 case COUNTING: // G国COUNTING2は運命に関係なし
293 if(avatarTotal % 2 == 0) break; // 処刑無し
294 Player executedPlayer = registPlayer(lastAvatar);
295 executedPlayer.setDestiny(Destiny.EXECUTED);
296 executedPlayer.setObitDay(day);
299 for(Avatar avatar : avatarList){
300 Player player = registPlayer(avatar);
301 player.setDestiny(Destiny.EATEN);
302 player.setObitDay(day);
316 private void summarizeTime(){
317 for(Period period : this.village.getPeriodList()){
318 for(Topic topic : period.getTopicList()){
319 if( ! (topic instanceof Talk) ) continue;
320 Talk talk = (Talk) topic;
322 long epoch = talk.getTimeFromID();
324 if(this.talk1stTimeMs < 0) this.talk1stTimeMs = epoch;
325 if(this.talkLastTimeMs < 0) this.talkLastTimeMs = epoch;
327 if(epoch < this.talk1stTimeMs ) this.talk1stTimeMs = epoch;
328 if(epoch > this.talkLastTimeMs) this.talkLastTimeMs = epoch;
338 private void summarizeJudge(){
339 List<SysEvent> eventList = this.eventMap.get(SysEventType.JUDGE);
341 for(SysEvent event : eventList){
342 List<Avatar> avatarList = event.getAvatarList();
343 Avatar avatar = avatarList.get(1);
344 Player seered = getPlayer(avatar);
345 GameRole role = seered.getRole();
347 case WOLF: this.ctScryWolf++; break;
348 case MADMAN: this.ctScryMadman++; break;
349 case HAMSTER: this.ctScryHamster++; break;
350 default: this.ctScryVillage++; break;
361 public CharSequence dumpSeerActivity(){
362 StringBuilder result = new StringBuilder();
364 if(this.ctScryVillage > 0){
365 result.append("村陣営を");
366 result.append(this.ctScryVillage);
370 if(this.ctScryHamster > 0){
371 if(result.length() > 0) result.append('、');
372 result.append("ハムスターを");
373 result.append(this.ctScryHamster);
377 if(this.ctScryMadman > 0){
378 if(result.length() > 0) result.append('、');
379 result.append("狂人を");
380 result.append(this.ctScryMadman);
384 if(this.ctScryWolf > 0){
385 if(result.length() > 0) result.append('、');
386 result.append("人狼を");
387 result.append(this.ctScryWolf);
391 if(result.length() <= 0) result.append("誰も占わなかった。");
392 else result.append("占った。");
394 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
402 private void summarizeGuard(){
403 List<SysEvent> eventList;
405 eventList = this.eventMap.get(SysEventType.GUARD);
406 for(SysEvent event : eventList){
407 List<Avatar> avatarList = event.getAvatarList();
408 Avatar avatar = avatarList.get(1);
409 Player guarded = getPlayer(avatar);
410 GameRole guardedRole = guarded.getRole();
412 case WOLF: this.ctGuardWolf++; break;
413 case MADMAN: this.ctGuardMadman++; break;
414 case HAMSTER: this.ctGuardHamster++; break;
415 default: this.ctGuardVillage++; break;
419 for(Period period : this.village.getPeriodList()){
420 summarizeGjPeriod(period);
430 private void summarizeGjPeriod(Period period){
431 if(period.getDay() <= 2) return;
433 boolean hasAssaultTried = period.hasAssaultTried();
434 boolean hunterAlive = false;
437 Set<Avatar> voters = period.getVoterSet();
438 for(Avatar avatar : voters){
439 Player player = getPlayer(avatar);
440 switch(player.getRole()){
441 case HUNTER: hunterAlive = true; break;
442 case WOLF: wolfNum++; break;
447 Avatar executed = period.getExecutedAvatar();
448 if(executed != null){
449 Player player = getPlayer(executed);
450 switch(player.getRole()){
451 case HUNTER: hunterAlive = false; break;
452 case WOLF: wolfNum--; break;
457 if( ! hunterAlive || wolfNum <= 0) return;
461 sysEvent = period.getTypedSysEvent(SysEventType.NOMURDER);
462 if(sysEvent == null) return;
464 sysEvent = period.getTypedSysEvent(SysEventType.GUARD);
465 if(sysEvent == null) return;
468 Avatar guarded = sysEvent.getAvatarList().get(1);
469 Player guardedPlayer = getPlayer(guarded);
470 GameRole guardedRole = guardedPlayer.getRole();
472 case MADMAN: this.ctGuardMadmanGJ++; break;
473 case HAMSTER: this.ctGuardHamsterGJ++; break;
474 default: this.ctGuardVillageGJ++; break;
477 this.ctGuardFakeGJ++; // 偽装GJ
487 public CharSequence dumpHunterActivity(){
488 StringBuilder result = new StringBuilder();
491 if(this.ctGuardFakeGJ > 0) atLeast = "少なくとも";
494 if(this.ctGuardVillage > 0){
495 result.append(atLeast);
496 result.append("村陣営を");
497 result.append(this.ctGuardVillage);
498 result.append("回護衛し");
499 if(this.ctGuardVillageGJ > 0){
500 result.append("GJを");
501 result.append(this.ctGuardVillageGJ);
502 result.append("回出した。");
508 if(this.ctGuardHamster > 0){
509 result.append(atLeast);
510 result.append("ハムスターを");
511 result.append(this.ctGuardHamster);
512 result.append("回護衛し");
513 if(this.ctGuardHamsterGJ > 0){
514 result.append("GJを");
515 result.append(this.ctGuardHamsterGJ);
516 result.append("回出した。");
522 if(this.ctGuardMadman > 0){
523 result.append(atLeast);
524 result.append("狂人を");
525 result.append(this.ctGuardMadman);
526 result.append("回護衛し");
527 if(this.ctGuardMadmanGJ > 0){
528 result.append("GJを");
529 result.append(this.ctGuardMadmanGJ);
530 result.append("回出した。");
536 if(this.ctGuardWolf > 0){
537 result.append(atLeast);
538 result.append("人狼を");
539 result.append(this.ctGuardWolf);
540 result.append("回護衛した。");
543 if(this.ctGuardFakeGJ > 0){
544 result.append("護衛先は不明ながら偽装GJが");
545 result.append(this.ctGuardFakeGJ);
546 result.append("回あった。");
549 if(result.length() <= 0) result.append("誰も護衛できなかった");
551 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
560 public CharSequence dumpExecutionInfo(){
561 StringBuilder result = new StringBuilder();
566 for(Player player : this.playerList){
567 Destiny destiny = player.getDestiny();
568 if(destiny != Destiny.EXECUTED) continue;
569 GameRole role = player.getRole();
571 case WOLF: exeWolf++; break;
572 case MADMAN: exeMad++; break;
573 default: exeVillage++; break;
578 result.append("▼村陣営×").append(exeVillage).append("回");
581 if(result.length() > 0) result.append("、");
582 result.append("▼狂×").append(exeMad).append("回");
585 if(result.length() > 0) result.append("、");
586 result.append("▼狼×").append(exeWolf).append("回");
588 if(result.length() <= 0) result.append("なし");
590 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
599 public CharSequence dumpAssaultInfo(){
600 StringBuilder result = new StringBuilder();
604 for(Player player : this.playerList){
605 if(player.getAvatar() == Avatar.AVATAR_GERD){
606 result.append("▲ゲルト");
609 Destiny destiny = player.getDestiny();
610 if(destiny != Destiny.EATEN) continue;
611 GameRole role = player.getRole();
613 case MADMAN: eatMad++; break;
614 default: eatVillage++; break;
619 if(result.length() > 0) result.append("、");
620 result.append("▲村陣営×").append(eatVillage).append("回");
623 if(result.length() > 0) result.append("、");
624 result.append("▲狂×").append(eatMad).append("回");
627 if(result.length() <= 0) result.append("襲撃なし");
629 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
636 * @return 投票BoxのWikiテキスト
638 public CharSequence dumpVoteBox(){
639 StringBuilder wikiText = new StringBuilder();
641 for(Player player : getCastingPlayerList()){
642 Avatar avatar = player.getAvatar();
643 if(avatar == Avatar.AVATAR_GERD) continue;
644 GameRole role = player.getRole();
645 CharSequence fullName = avatar.getFullName();
646 CharSequence roleName = role.getRoleName();
647 StringBuilder line = new StringBuilder();
648 line.append("[").append(roleName).append("] ").append(fullName);
649 if(wikiText.length() > 0) wikiText.append(',');
650 wikiText.append(WolfBBS.escapeWikiSyntax(line));
651 wikiText.append("[0]");
654 wikiText.insert(0, "#vote(").append(")\n");
661 * @param iconSet 顔アイコンセット
662 * @return キャスト表のWikiテキスト
664 public CharSequence dumpCastingBoard(FaceIconSet iconSet){
665 StringBuilder wikiText = new StringBuilder();
667 String vName = this.village.getVillageFullName();
668 String author = iconSet.getAuthor() + "氏"
669 +" [ "+iconSet.getUrlText()+" ]";
671 wikiText.append(WolfBBS.COMMENTLINE);
672 wikiText.append("// ↓キャスト表開始\n");
673 wikiText.append("// Village : ")
676 wikiText.append("// Generator : ")
679 wikiText.append("// アイコン作者 : ")
682 wikiText.append("// ※アイコン画像の著作財産権保持者")
683 .append("および画像サーバ運営者から\n");
684 wikiText.append("// 新しい意向が示された場合、")
685 .append("そちらを最優先で尊重してください。\n");
686 wikiText.append(WolfBBS.COMMENTLINE);
688 wikiText.append("|配役")
695 wikiText.append(WolfBBS.COMMENTLINE);
697 for(Player player : getCastingPlayerList()){
698 Avatar avatar = player.getAvatar();
699 GameRole role = player.getRole();
700 Destiny destiny = player.getDestiny();
701 int obitDay = player.getObitDay();
702 String name = player.getIdName();
703 String urlText = player.getUrlText();
704 if(urlText == null) urlText = "";
705 urlText = urlText.replace("~", "%7e");
706 urlText = urlText.replace(" ", "%20");
708 URL url = new URL(urlText);
709 URI uri = url.toURI();
710 urlText = uri.toASCIIString();
711 }catch(MalformedURLException e){
713 }catch(URISyntaxException e){
716 // PukiWikiではURL内の&のエスケープは不要?
718 wikiText.append("// ========== ");
719 wikiText.append(name)
720 .append(" acts as [")
721 .append(avatar.getName())
723 wikiText.append(" ==========\n");
725 String teamColor = "BGCOLOR("
726 + WolfBBS.getTeamWikiColor(role)
729 String avatarIcon = iconSet.getAvatarIconWiki(avatar);
731 wikiText.append('|').append(teamColor);
732 wikiText.append(avatarIcon).append("&br;");
734 wikiText.append("[[").append(avatar.getName()).append("]]");
736 wikiText.append('|').append(teamColor);
737 wikiText.append("[[").append(WolfBBS.escapeWikiBracket(name));
738 if(urlText != null && urlText.length() > 0){
739 wikiText.append('>').append(urlText);
741 wikiText.append("]]");
743 wikiText.append('|').append(teamColor);
744 wikiText.append(WolfBBS.getRoleIconWiki(role));
745 wikiText.append("&br;");
746 wikiText.append("[[");
747 wikiText.append(role.getRoleName());
748 wikiText.append("]]");
750 String destinyColor = WolfBBS.getDestinyColorWiki(destiny);
751 wikiText.append('|');
752 wikiText.append("BGCOLOR(").append(destinyColor).append("):");
753 if(destiny == Destiny.ALIVE){
754 wikiText.append("最後まで&br;生存");
756 wikiText.append(obitDay).append("日目").append("&br;");
757 wikiText.append(destiny.getMessage());
760 wikiText.append('|');
761 wikiText.append(avatar.getJobTitle()).append('。');
763 if(avatar == Avatar.AVATAR_GERD){
764 wikiText.append("寝てばかりいた。");
765 }else if(role == GameRole.HUNTER){
766 CharSequence report = dumpHunterActivity();
767 wikiText.append(report);
768 }else if(role == GameRole.SEER){
769 CharSequence report = dumpSeerActivity();
770 wikiText.append(report);
773 wikiText.append("|\n");
777 wikiText.append("|>|>|>|>|");
778 wikiText.append("RIGHT:");
779 wikiText.append("顔アイコン提供 : [[");
780 wikiText.append(WolfBBS.escapeWikiBracket(iconSet.getAuthor()));
782 .append(iconSet.getUrlText());
783 wikiText.append("]]氏");
784 wikiText.append("|\n");
786 wikiText.append(WolfBBS.COMMENTLINE);
787 wikiText.append("// ↑キャスト表ここまで\n");
788 wikiText.append(WolfBBS.COMMENTLINE);
797 public CharSequence dumpVillageWiki(){
798 StringBuilder wikiText = new StringBuilder();
801 DateFormat.getDateTimeInstance(DateFormat.FULL,
804 String vName = this.village.getVillageFullName();
806 wikiText.append(WolfBBS.COMMENTLINE);
807 wikiText.append("// ↓村詳細開始\n");
808 wikiText.append("// Village : ")
811 wikiText.append("// Generator : ")
815 wikiText.append("* 村の詳細\n");
817 wikiText.append(WolfBBS.COMMENTLINE);
818 wikiText.append("- 勝者\n");
819 Team winnerTeam = getWinnerTeam();
820 String wonTeam = winnerTeam.getTeamName();
821 wikiText.append(wonTeam).append('\n');
823 wikiText.append(WolfBBS.COMMENTLINE);
824 wikiText.append("- エントリー開始時刻\n");
825 Date date = get1stTalkDate();
826 String talk1st = dform.format(date);
827 wikiText.append(talk1st).append('\n');
829 wikiText.append(WolfBBS.COMMENTLINE);
830 wikiText.append("- 参加人数\n");
831 int avatarNum = countAvatarNum();
832 String totalMember = "ゲルト + " + (avatarNum - 1) + "名 = "
834 wikiText.append(WolfBBS.escapeWikiSyntax(totalMember))
837 wikiText.append(WolfBBS.COMMENTLINE);
838 wikiText.append("- 役職内訳\n");
839 StringBuilder roleMsg = new StringBuilder();
840 for(GameRole role : GameRole.values()){
841 List<Player> players = getRoledPlayerList(role);
842 String roleName = role.getRoleName();
843 if(players.size() <= 0) continue;
844 if(roleMsg.length() > 0) roleMsg.append('、');
845 roleMsg.append(roleName)
847 .append(players.size())
850 wikiText.append(WolfBBS.escapeWikiSyntax(roleMsg)).append('\n');
852 wikiText.append(WolfBBS.COMMENTLINE);
853 wikiText.append("- 処刑内訳\n");
854 wikiText.append(dumpExecutionInfo()).append('\n');
856 wikiText.append(WolfBBS.COMMENTLINE);
857 wikiText.append("- 襲撃内訳\n");
858 wikiText.append(dumpAssaultInfo()).append('\n');
860 wikiText.append(WolfBBS.COMMENTLINE);
861 wikiText.append("- 突然死\n");
862 wikiText.append(countSuddenDeath()).append("名").append('\n');
864 wikiText.append(WolfBBS.COMMENTLINE);
865 wikiText.append("- 人口推移\n");
866 for(int day = 1; day < this.village.getPeriodSize(); day++){
867 List<Player> players = getSurvivorList(day);
868 CharSequence roleSeq =
869 GameSummary.getRoleBalanceSequence(players);
871 Period period = this.village.getPeriod(day);
872 daySeq = period.getCaption();
880 wikiText.append(WolfBBS.COMMENTLINE);
881 wikiText.append("- 占い師の成績\n");
882 wikiText.append(dumpSeerActivity()).append('\n');
884 wikiText.append(WolfBBS.COMMENTLINE);
885 wikiText.append("- 狩人の成績\n");
886 wikiText.append(dumpHunterActivity()).append('\n');
888 wikiText.append(WolfBBS.COMMENTLINE);
889 wikiText.append("// ↑村詳細ここまで\n");
890 wikiText.append(WolfBBS.COMMENTLINE);
899 public Date get1stTalkDate(){
900 return new Date(this.talk1stTimeMs);
907 public Date getLastTalkDate(){
908 return new Date(this.talkLastTimeMs);
916 public List<Player> getSurvivorList(int day){
917 if(day < 0 || this.village.getPeriodSize() <= day){
918 throw new IndexOutOfBoundsException();
921 List<Player> result = new LinkedList<Player>();
923 Period period = this.village.getPeriod(day);
925 if( period.isPrologue()
926 || (period.isProgress() && day == 1) ){
927 result.addAll(this.playerList);
931 if(period.isEpilogue()){
932 for(Player player : this.playerList){
933 if(player.getDestiny() == Destiny.ALIVE){
940 for(Topic topic : period.getTopicList()){
941 if( ! (topic instanceof SysEvent) ) continue;
942 SysEvent sysEvent = (SysEvent) topic;
943 if(sysEvent.getSysEventType() == SysEventType.SURVIVOR){
944 List<Avatar> avatarList = sysEvent.getAvatarList();
945 for(Avatar avatar : avatarList){
946 Player player = getPlayer(avatar);
960 public List<Player> getPlayerList(){
961 List<Player> result = Collections.unmodifiableList(this.playerList);
966 * キャスティング表用にソートされたプレイヤー一覧を得る。
969 public List<Player> getCastingPlayerList(){
970 List<Player> sortedPlayers =
971 new LinkedList<Player>();
972 sortedPlayers.addAll(this.playerList);
973 Collections.sort(sortedPlayers, COMPARATOR_CASTING);
974 return sortedPlayers;
978 * 指定された役職のプレイヤー一覧を得る。
980 * @return 役職に合致するプレイヤーのリスト
982 public List<Player> getRoledPlayerList(GameRole role){
983 List<Player> result = new LinkedList<Player>();
985 for(Player player : this.playerList){
986 if(player.getRole() == role){
998 public Team getWinnerTeam(){
1006 public int countSuddenDeath(){
1007 int suddenDeath = 0;
1008 for(Player player : this.playerList){
1009 if(player.getDestiny() == Destiny.SUDDENDEATH) suddenDeath++;
1018 public int countAvatarNum(){
1019 int playerNum = this.playerList.size();
1024 * AvatarからPlayerを得る。
1025 * 参加していないAvatarならnullを返す。
1026 * @param avatar Avatar
1029 public final Player getPlayer(Avatar avatar){
1030 Player player = this.playerMap.get(avatar);
1035 * AvatarからPlayerを得る。
1037 * @param avatar Avatar
1040 private Player registPlayer(Avatar avatar){
1041 Player player = getPlayer(avatar);
1043 player = new Player();
1044 player.setAvatar(avatar);
1045 this.playerMap.put(avatar, player);
1054 private static final class CastingComparator
1055 implements Comparator<Player> {
1060 private CastingComparator(){
1067 * @param p1 {@inheritDoc}
1068 * @param p2 {@inheritDoc}
1069 * @return {@inheritDoc}
1072 public int compare(Player p1, Player p2){
1073 if(p1 == p2) return 0;
1074 if(p1 == null) return -1;
1075 if(p2 == null) return +1;
1078 Avatar avatar1 = p1.getAvatar();
1079 Avatar avatar2 = p2.getAvatar();
1080 if(avatar1.equals(avatar2)) return 0;
1081 if(avatar1 == Avatar.AVATAR_GERD) return -1;
1082 if(avatar2 == Avatar.AVATAR_GERD) return +1;
1085 Destiny dest1 = p1.getDestiny();
1086 Destiny dest2 = p2.getDestiny();
1088 if (dest1 == Destiny.ALIVE) return +1;
1089 else if(dest2 == Destiny.ALIVE) return -1;
1093 int obitDay1 = p1.getObitDay();
1094 int obitDay2 = p2.getObitDay();
1095 if(obitDay1 > obitDay2) return +1;
1096 if(obitDay1 < obitDay2) return -1;
1099 int destinyOrder = dest1.compareTo(dest2);
1100 if(destinyOrder != 0) return destinyOrder;
1103 int entryOrder = p1.getEntryNo() - p2.getEntryNo();