2 * Summarize game information
4 * License : The MIT License
5 * Copyright(c) 2009 olyutorskii
8 package jp.sfjp.jindolf.summary;
10 import java.awt.Color;
11 import java.net.MalformedURLException;
13 import java.net.URISyntaxException;
15 import java.text.DateFormat;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.Date;
19 import java.util.EnumMap;
20 import java.util.HashMap;
21 import java.util.LinkedList;
22 import java.util.List;
25 import jp.sfjp.jindolf.VerInfo;
26 import jp.sfjp.jindolf.data.Avatar;
27 import jp.sfjp.jindolf.data.Period;
28 import jp.sfjp.jindolf.data.Player;
29 import jp.sfjp.jindolf.data.SysEvent;
30 import jp.sfjp.jindolf.data.Talk;
31 import jp.sfjp.jindolf.data.Topic;
32 import jp.sfjp.jindolf.data.Village;
33 import jp.sfjp.jindolf.dxchg.FaceIconSet;
34 import jp.sfjp.jindolf.dxchg.WolfBBS;
35 import jp.sourceforge.jindolf.corelib.Destiny;
36 import jp.sourceforge.jindolf.corelib.GameRole;
37 import jp.sourceforge.jindolf.corelib.SysEventType;
38 import jp.sourceforge.jindolf.corelib.Team;
39 import jp.sourceforge.jindolf.corelib.VillageState;
44 public class GameSummary{
46 /** キャスティング表示用Comparator。 */
47 public static final Comparator<Player> COMPARATOR_CASTING =
48 new CastingComparator();
50 private static final Color COLOR_PLAINTABLE = new Color(0xedf5fe);
52 private static final String GENERATOR =
53 VerInfo.TITLE + "\u0020Ver." + VerInfo.VERSION;
56 private final Map<Avatar, Player> playerMap =
58 private final List<Player> playerList =
60 private final Map<SysEventType, List<SysEvent>> eventMap =
61 new EnumMap<>(SysEventType.class);
63 private final Village village;
69 private int ctScryVillage = 0;
70 private int ctScryHamster = 0;
71 private int ctScryMadman = 0;
72 private int ctScryWolf = 0;
75 private int ctGuardVillage = 0;
76 private int ctGuardHamster = 0;
77 private int ctGuardMadman = 0;
78 private int ctGuardWolf = 0;
79 private int ctGuardVillageGJ = 0;
80 private int ctGuardHamsterGJ = 0;
81 private int ctGuardMadmanGJ = 0;
82 private int ctGuardFakeGJ = 0;
85 private long talk1stTimeMs = -1;
86 private long talkLastTimeMs = -1;
93 public GameSummary(Village village){
96 VillageState state = village.getState();
97 if( state != VillageState.EPILOGUE
98 && state != VillageState.GAMEOVER){
99 throw new IllegalStateException();
102 this.village = village;
111 * プレイヤーのリストから役職バランス文字列を得る。
113 * @param players プレイヤーのリスト
116 public static String getRoleBalanceSequence(List<Player> players){
117 List<GameRole> roleList = new LinkedList<>();
118 for(Player player : players){
119 GameRole role = player.getRole();
122 Collections.sort(roleList, GameRole.getPowerBalanceComparator());
124 StringBuilder result = new StringBuilder();
125 for(GameRole role : roleList){
126 char ch = role.getShortName();
130 return result.toString();
136 private void summarize(){
143 for(Period period : this.village.getPeriodList()){
144 summarizePeriod(period);
154 * SysEventの種別ごとに集計する。
156 private void buildEventMap(){
157 for(SysEventType type : SysEventType.values()){
158 List<SysEvent> eventList = new LinkedList<>();
159 this.eventMap.put(type, eventList);
162 for(Period period : this.village.getPeriodList()){
163 for(Topic topic : period.getTopicList()){
164 if( ! (topic instanceof SysEvent) ) continue;
165 SysEvent event = (SysEvent) topic;
166 SysEventType type = event.getSysEventType();
167 List<SysEvent> eventList = this.eventMap.get(type);
168 eventList.add(event);
178 private void summarizeWinner(){
179 List<SysEvent> eventList;
181 eventList = this.eventMap.get(SysEventType.WINVILLAGE);
182 if( ! eventList.isEmpty() ){
183 this.winner = Team.VILLAGE;
186 eventList = this.eventMap.get(SysEventType.WINWOLF);
187 if( ! eventList.isEmpty() ){
188 this.winner = Team.WOLF;
191 eventList = this.eventMap.get(SysEventType.WINHAMSTER);
192 if( ! eventList.isEmpty() ){
193 this.winner = Team.HAMSTER;
196 if(this.winner == null) assert false;
204 private void summarizePlayers(){
205 List<SysEvent> eventList;
207 List<Avatar> avatarList;
208 List<GameRole> roleList;
209 List<Integer> integerList;
210 List<CharSequence> textList;
212 eventList = this.eventMap.get(SysEventType.ONSTAGE);
213 for(SysEvent event : eventList){
214 avatarList = event.getAvatarList();
215 integerList = event.getIntegerList();
216 Avatar onstageAvatar = avatarList.get(0);
217 Player onstagePlayer = registPlayer(onstageAvatar);
218 onstagePlayer.setEntryNo(integerList.get(0));
221 eventList = this.eventMap.get(SysEventType.PLAYERLIST);
222 assert eventList.size() == 1;
223 SysEvent event = eventList.get(0);
225 avatarList = event.getAvatarList();
226 roleList = event.getRoleList();
227 integerList = event.getIntegerList();
228 textList = event.getCharSequenceList();
229 int avatarNum = avatarList.size();
230 for(int idx = 0; idx < avatarNum; idx++){
231 Avatar avatar = avatarList.get(idx);
232 GameRole role = roleList.get(idx);
233 CharSequence urlText = textList.get(idx * 2);
234 CharSequence idName = textList.get(idx * 2 + 1);
235 int liveOrDead = integerList.get(idx);
237 Player player = registPlayer(avatar);
238 player.setRole(role);
239 player.setUrlText(urlText.toString());
240 player.setIdName(idName.toString());
241 if(liveOrDead != 0){ // 生存
242 player.setObitDay(-1);
243 player.setDestiny(Destiny.ALIVE);
246 this.playerList.add(player);
254 * @param period Period
256 private void summarizePeriod(Period period){
257 int day = period.getDay();
258 for(Topic topic : period.getTopicList()){
259 if(topic instanceof SysEvent){
260 SysEvent sysEvent = (SysEvent) topic;
261 summarizeDestiny(day, sysEvent);
271 * @param sysEvent システムイベント
273 private void summarizeDestiny(int day, SysEvent sysEvent){
274 List<Avatar> avatarList = sysEvent.getAvatarList();
275 List<Integer> integerList = sysEvent.getIntegerList();
277 int avatarTotal = avatarList.size();
278 Avatar lastAvatar = null;
279 if(avatarTotal > 0) lastAvatar = avatarList.get(avatarTotal - 1);
281 SysEventType eventType = sysEvent.getSysEventType();
283 case EXECUTION: // G国のみ
284 if(integerList.get(avatarTotal - 1) > 0) break; // 処刑無し
285 Player executedPl = registPlayer(lastAvatar);
286 executedPl.setDestiny(Destiny.EXECUTED);
287 executedPl.setObitDay(day);
290 Avatar suddenDeathAvatar = avatarList.get(0);
291 Player suddenDeathPlayer = registPlayer(suddenDeathAvatar);
292 suddenDeathPlayer.setDestiny(Destiny.SUDDENDEATH);
293 suddenDeathPlayer.setObitDay(day);
295 case COUNTING: // G国COUNTING2は運命に関係なし
296 if(avatarTotal % 2 == 0) break; // 処刑無し
297 Player executedPlayer = registPlayer(lastAvatar);
298 executedPlayer.setDestiny(Destiny.EXECUTED);
299 executedPlayer.setObitDay(day);
302 for(Avatar avatar : avatarList){
303 Player player = registPlayer(avatar);
304 player.setDestiny(Destiny.EATEN);
305 player.setObitDay(day);
319 private void summarizeTime(){
320 for(Period period : this.village.getPeriodList()){
321 for(Topic topic : period.getTopicList()){
322 if( ! (topic instanceof Talk) ) continue;
323 Talk talk = (Talk) topic;
325 long epoch = talk.getTimeFromID();
327 if(this.talk1stTimeMs < 0) this.talk1stTimeMs = epoch;
328 if(this.talkLastTimeMs < 0) this.talkLastTimeMs = epoch;
330 if(epoch < this.talk1stTimeMs ) this.talk1stTimeMs = epoch;
331 if(epoch > this.talkLastTimeMs) this.talkLastTimeMs = epoch;
341 private void summarizeJudge(){
342 List<SysEvent> eventList = this.eventMap.get(SysEventType.JUDGE);
344 for(SysEvent event : eventList){
345 List<Avatar> avatarList = event.getAvatarList();
346 Avatar avatar = avatarList.get(1);
347 Player seered = getPlayer(avatar);
348 GameRole role = seered.getRole();
350 case WOLF: this.ctScryWolf++; break;
351 case MADMAN: this.ctScryMadman++; break;
352 case HAMSTER: this.ctScryHamster++; break;
353 default: this.ctScryVillage++; break;
364 public CharSequence dumpSeerActivity(){
365 StringBuilder result = new StringBuilder();
367 if(this.ctScryVillage > 0){
368 result.append("村陣営を");
369 result.append(this.ctScryVillage);
373 if(this.ctScryHamster > 0){
374 if(result.length() > 0) result.append('、');
375 result.append("ハムスターを");
376 result.append(this.ctScryHamster);
380 if(this.ctScryMadman > 0){
381 if(result.length() > 0) result.append('、');
382 result.append("狂人を");
383 result.append(this.ctScryMadman);
387 if(this.ctScryWolf > 0){
388 if(result.length() > 0) result.append('、');
389 result.append("人狼を");
390 result.append(this.ctScryWolf);
394 if(result.length() <= 0) result.append("誰も占わなかった。");
395 else result.append("占った。");
397 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
405 private void summarizeGuard(){
406 List<SysEvent> eventList;
408 eventList = this.eventMap.get(SysEventType.GUARD);
409 for(SysEvent event : eventList){
410 List<Avatar> avatarList = event.getAvatarList();
411 Avatar avatar = avatarList.get(1);
412 Player guarded = getPlayer(avatar);
413 GameRole guardedRole = guarded.getRole();
415 case WOLF: this.ctGuardWolf++; break;
416 case MADMAN: this.ctGuardMadman++; break;
417 case HAMSTER: this.ctGuardHamster++; break;
418 default: this.ctGuardVillage++; break;
422 for(Period period : this.village.getPeriodList()){
423 summarizeGjPeriod(period);
433 private void summarizeGjPeriod(Period period){
434 if(period.getDay() <= 2) return;
436 boolean hasAssaultTried = period.hasAssaultTried();
437 boolean hunterAlive = false;
440 Set<Avatar> voters = period.getVoterSet();
441 for(Avatar avatar : voters){
442 Player player = getPlayer(avatar);
443 switch(player.getRole()){
444 case HUNTER: hunterAlive = true; break;
445 case WOLF: wolfNum++; break;
450 Avatar executed = period.getExecutedAvatar();
451 if(executed != null){
452 Player player = getPlayer(executed);
453 switch(player.getRole()){
454 case HUNTER: hunterAlive = false; break;
455 case WOLF: wolfNum--; break;
460 if( ! hunterAlive || wolfNum <= 0) return;
464 sysEvent = period.getTypedSysEvent(SysEventType.NOMURDER);
465 if(sysEvent == null) return;
467 sysEvent = period.getTypedSysEvent(SysEventType.GUARD);
468 if(sysEvent == null) return;
471 Avatar guarded = sysEvent.getAvatarList().get(1);
472 Player guardedPlayer = getPlayer(guarded);
473 GameRole guardedRole = guardedPlayer.getRole();
475 case MADMAN: this.ctGuardMadmanGJ++; break;
476 case HAMSTER: this.ctGuardHamsterGJ++; break;
477 default: this.ctGuardVillageGJ++; break;
480 this.ctGuardFakeGJ++; // 偽装GJ
490 public CharSequence dumpHunterActivity(){
491 StringBuilder result = new StringBuilder();
494 if(this.ctGuardFakeGJ > 0) atLeast = "少なくとも";
497 if(this.ctGuardVillage > 0){
498 result.append(atLeast);
499 result.append("村陣営を");
500 result.append(this.ctGuardVillage);
501 result.append("回護衛し");
502 if(this.ctGuardVillageGJ > 0){
503 result.append("GJを");
504 result.append(this.ctGuardVillageGJ);
505 result.append("回出した。");
511 if(this.ctGuardHamster > 0){
512 result.append(atLeast);
513 result.append("ハムスターを");
514 result.append(this.ctGuardHamster);
515 result.append("回護衛し");
516 if(this.ctGuardHamsterGJ > 0){
517 result.append("GJを");
518 result.append(this.ctGuardHamsterGJ);
519 result.append("回出した。");
525 if(this.ctGuardMadman > 0){
526 result.append(atLeast);
527 result.append("狂人を");
528 result.append(this.ctGuardMadman);
529 result.append("回護衛し");
530 if(this.ctGuardMadmanGJ > 0){
531 result.append("GJを");
532 result.append(this.ctGuardMadmanGJ);
533 result.append("回出した。");
539 if(this.ctGuardWolf > 0){
540 result.append(atLeast);
541 result.append("人狼を");
542 result.append(this.ctGuardWolf);
543 result.append("回護衛した。");
546 if(this.ctGuardFakeGJ > 0){
547 result.append("護衛先は不明ながら偽装GJが");
548 result.append(this.ctGuardFakeGJ);
549 result.append("回あった。");
552 if(result.length() <= 0) result.append("誰も護衛できなかった");
554 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
563 public CharSequence dumpExecutionInfo(){
564 StringBuilder result = new StringBuilder();
569 for(Player player : this.playerList){
570 Destiny destiny = player.getDestiny();
571 if(destiny != Destiny.EXECUTED) continue;
572 GameRole role = player.getRole();
574 case WOLF: exeWolf++; break;
575 case MADMAN: exeMad++; break;
576 default: exeVillage++; break;
581 result.append("▼村陣営×").append(exeVillage).append("回");
584 if(result.length() > 0) result.append("、");
585 result.append("▼狂×").append(exeMad).append("回");
588 if(result.length() > 0) result.append("、");
589 result.append("▼狼×").append(exeWolf).append("回");
591 if(result.length() <= 0) result.append("なし");
593 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
602 public CharSequence dumpAssaultInfo(){
603 StringBuilder result = new StringBuilder();
607 for(Player player : this.playerList){
608 if(player.getAvatar() == Avatar.AVATAR_GERD){
609 result.append("▲ゲルト");
612 Destiny destiny = player.getDestiny();
613 if(destiny != Destiny.EATEN) continue;
614 GameRole role = player.getRole();
616 case MADMAN: eatMad++; break;
617 default: eatVillage++; break;
622 if(result.length() > 0) result.append("、");
623 result.append("▲村陣営×").append(eatVillage).append("回");
626 if(result.length() > 0) result.append("、");
627 result.append("▲狂×").append(eatMad).append("回");
630 if(result.length() <= 0) result.append("襲撃なし");
632 CharSequence seq = WolfBBS.escapeWikiSyntax(result);
639 * @return 投票BoxのWikiテキスト
641 public CharSequence dumpVoteBox(){
642 StringBuilder wikiText = new StringBuilder();
644 for(Player player : getCastingPlayerList()){
645 Avatar avatar = player.getAvatar();
646 if(avatar == Avatar.AVATAR_GERD) continue;
647 GameRole role = player.getRole();
648 CharSequence fullName = avatar.getFullName();
649 CharSequence roleName = role.getRoleName();
650 StringBuilder line = new StringBuilder();
651 line.append("[").append(roleName).append("] ").append(fullName);
652 if(wikiText.length() > 0) wikiText.append(',');
653 wikiText.append(WolfBBS.escapeWikiSyntax(line));
654 wikiText.append("[0]");
657 wikiText.insert(0, "#vote(").append(")\n");
664 * @param iconSet 顔アイコンセット
665 * @return キャスト表のWikiテキスト
667 public CharSequence dumpCastingBoard(FaceIconSet iconSet){
668 StringBuilder wikiText = new StringBuilder();
670 String vName = this.village.getVillageFullName();
671 String author = iconSet.getAuthor() + "氏"
672 +" [ "+iconSet.getUrlText()+" ]";
674 wikiText.append(WolfBBS.COMMENTLINE);
675 wikiText.append("// ↓キャスト表開始\n");
676 wikiText.append("// Village : ")
679 wikiText.append("// Generator : ")
682 wikiText.append("// アイコン作者 : ")
685 wikiText.append("// ※アイコン画像の著作財産権保持者")
686 .append("および画像サーバ運営者から\n");
687 wikiText.append("// 新しい意向が示された場合、")
688 .append("そちらを最優先で尊重してください。\n");
689 wikiText.append(WolfBBS.COMMENTLINE);
691 wikiText.append("|配役")
698 wikiText.append(WolfBBS.COMMENTLINE);
702 for(Player player : getCastingPlayerList()){
703 Avatar avatar = player.getAvatar();
704 GameRole role = player.getRole();
705 Destiny destiny = player.getDestiny();
706 int obitDay = player.getObitDay();
707 String name = player.getIdName();
708 String urlText = player.getUrlText();
709 if(urlText == null) urlText = "";
710 urlText = urlText.replace("~", "%7e");
711 urlText = urlText.replace(" ", "%20");
713 URL url = new URL(urlText);
714 URI uri = url.toURI();
715 urlText = uri.toASCIIString();
716 }catch(MalformedURLException | URISyntaxException e){
719 // PukiWikiではURL内の&のエスケープは不要?
721 wikiText.append("// ========== ");
722 wikiText.append(name)
723 .append(" acts as [")
724 .append(avatar.getName())
726 wikiText.append(" ==========\n");
728 Color teamColor = WolfBBS.getTeamColor(role);
729 Color destinyColor = WolfBBS.getDestinyColor(destiny);
730 Color plainColor = COLOR_PLAINTABLE;
732 teamColor = WolfBBS.evenColor(teamColor);
733 destinyColor = WolfBBS.evenColor(destinyColor);
734 plainColor = WolfBBS.evenColor(plainColor);
738 String teamWikiColor = "BGCOLOR("
739 + WolfBBS.cnvWikiColor(teamColor)
741 String destinyWikiColor = "BGCOLOR("
742 + WolfBBS.cnvWikiColor(destinyColor)
744 String plainWikiColor = "BGCOLOR("
745 + WolfBBS.cnvWikiColor(plainColor)
748 String avatarIcon = iconSet.getAvatarIconWiki(avatar);
750 wikiText.append('|').append(teamWikiColor);
751 wikiText.append(avatarIcon).append("&br;");
753 wikiText.append("[[").append(avatar.getName()).append("]]");
755 wikiText.append('|').append(teamWikiColor);
756 wikiText.append("[[").append(WolfBBS.escapeWikiBracket(name));
757 if(urlText != null && urlText.length() > 0){
758 wikiText.append('>').append(urlText);
760 wikiText.append("]]");
762 wikiText.append('|').append(teamWikiColor);
763 wikiText.append(WolfBBS.getRoleIconWiki(role));
764 wikiText.append("&br;");
765 wikiText.append("[[");
766 wikiText.append(role.getRoleName());
767 wikiText.append("]]");
769 wikiText.append('|').append(destinyWikiColor);
770 if(destiny == Destiny.ALIVE){
771 wikiText.append("最後まで&br;生存");
773 wikiText.append(obitDay).append("日目").append("&br;");
774 wikiText.append(destiny.getMessage());
777 wikiText.append('|').append(plainWikiColor);
778 wikiText.append(avatar.getJobTitle()).append('。');
780 if(avatar == Avatar.AVATAR_GERD){
781 wikiText.append("寝てばかりいた。");
782 }else if(role == GameRole.HUNTER){
783 CharSequence report = dumpHunterActivity();
784 wikiText.append(report);
785 }else if(role == GameRole.SEER){
786 CharSequence report = dumpSeerActivity();
787 wikiText.append(report);
790 wikiText.append("|\n");
794 wikiText.append("|>|>|>|>|");
795 wikiText.append("RIGHT:");
796 wikiText.append("顔アイコン提供 : [[");
797 wikiText.append(WolfBBS.escapeWikiBracket(iconSet.getAuthor()));
799 .append(iconSet.getUrlText());
800 wikiText.append("]]氏");
801 wikiText.append("|\n");
803 wikiText.append(WolfBBS.COMMENTLINE);
804 wikiText.append("// ↑キャスト表ここまで\n");
805 wikiText.append(WolfBBS.COMMENTLINE);
814 public CharSequence dumpVillageWiki(){
815 StringBuilder wikiText = new StringBuilder();
818 DateFormat.getDateTimeInstance(DateFormat.FULL,
821 String vName = this.village.getVillageFullName();
823 wikiText.append(WolfBBS.COMMENTLINE);
824 wikiText.append("// ↓村詳細開始\n");
825 wikiText.append("// Village : ")
828 wikiText.append("// Generator : ")
832 wikiText.append("* 村の詳細\n");
834 wikiText.append(WolfBBS.COMMENTLINE);
835 wikiText.append("- 勝者\n");
836 Team winnerTeam = getWinnerTeam();
837 String wonTeam = winnerTeam.getTeamName();
838 wikiText.append(wonTeam).append('\n');
840 wikiText.append(WolfBBS.COMMENTLINE);
841 wikiText.append("- エントリー開始時刻\n");
842 Date date = get1stTalkDate();
843 String talk1st = dform.format(date);
844 wikiText.append(talk1st).append('\n');
846 wikiText.append(WolfBBS.COMMENTLINE);
847 wikiText.append("- 参加人数\n");
848 int avatarNum = countAvatarNum();
849 String totalMember = "ゲルト + " + (avatarNum - 1) + "名 = "
851 wikiText.append(WolfBBS.escapeWikiSyntax(totalMember))
854 wikiText.append(WolfBBS.COMMENTLINE);
855 wikiText.append("- 役職内訳\n");
856 StringBuilder roleMsg = new StringBuilder();
857 for(GameRole role : GameRole.values()){
858 List<Player> players = getRoledPlayerList(role);
859 String roleName = role.getRoleName();
860 if(players.size() <= 0) continue;
861 if(roleMsg.length() > 0) roleMsg.append('、');
862 roleMsg.append(roleName)
864 .append(players.size())
867 wikiText.append(WolfBBS.escapeWikiSyntax(roleMsg)).append('\n');
869 wikiText.append(WolfBBS.COMMENTLINE);
870 wikiText.append("- 処刑内訳\n");
871 wikiText.append(dumpExecutionInfo()).append('\n');
873 wikiText.append(WolfBBS.COMMENTLINE);
874 wikiText.append("- 襲撃内訳\n");
875 wikiText.append(dumpAssaultInfo()).append('\n');
877 wikiText.append(WolfBBS.COMMENTLINE);
878 wikiText.append("- 突然死\n");
879 wikiText.append(countSuddenDeath()).append("名").append('\n');
881 wikiText.append(WolfBBS.COMMENTLINE);
882 wikiText.append("- 人口推移\n");
883 for(int day = 1; day < this.village.getPeriodSize(); day++){
884 List<Player> players = getSurvivorList(day);
885 CharSequence roleSeq =
886 GameSummary.getRoleBalanceSequence(players);
888 Period period = this.village.getPeriod(day);
889 daySeq = period.getCaption();
897 wikiText.append(WolfBBS.COMMENTLINE);
898 wikiText.append("- 占い師の成績\n");
899 wikiText.append(dumpSeerActivity()).append('\n');
901 wikiText.append(WolfBBS.COMMENTLINE);
902 wikiText.append("- 狩人の成績\n");
903 wikiText.append(dumpHunterActivity()).append('\n');
905 wikiText.append(WolfBBS.COMMENTLINE);
906 wikiText.append("// ↑村詳細ここまで\n");
907 wikiText.append(WolfBBS.COMMENTLINE);
916 public Date get1stTalkDate(){
917 return new Date(this.talk1stTimeMs);
924 public Date getLastTalkDate(){
925 return new Date(this.talkLastTimeMs);
933 public List<Player> getSurvivorList(int day){
934 if(day < 0 || this.village.getPeriodSize() <= day){
935 throw new IndexOutOfBoundsException();
938 List<Player> result = new LinkedList<>();
940 Period period = this.village.getPeriod(day);
942 if( period.isPrologue()
943 || (period.isProgress() && day == 1) ){
944 result.addAll(this.playerList);
948 if(period.isEpilogue()){
949 for(Player player : this.playerList){
950 if(player.getDestiny() == Destiny.ALIVE){
957 for(Topic topic : period.getTopicList()){
958 if( ! (topic instanceof SysEvent) ) continue;
959 SysEvent sysEvent = (SysEvent) topic;
960 if(sysEvent.getSysEventType() == SysEventType.SURVIVOR){
961 List<Avatar> avatarList = sysEvent.getAvatarList();
962 for(Avatar avatar : avatarList){
963 Player player = getPlayer(avatar);
977 public List<Player> getPlayerList(){
978 List<Player> result = Collections.unmodifiableList(this.playerList);
983 * キャスティング表用にソートされたプレイヤー一覧を得る。
986 public List<Player> getCastingPlayerList(){
987 List<Player> sortedPlayers =
989 sortedPlayers.addAll(this.playerList);
990 Collections.sort(sortedPlayers, COMPARATOR_CASTING);
991 return sortedPlayers;
995 * 指定された役職のプレイヤー一覧を得る。
997 * @return 役職に合致するプレイヤーのリスト
999 public List<Player> getRoledPlayerList(GameRole role){
1000 List<Player> result = new LinkedList<>();
1002 for(Player player : this.playerList){
1003 if(player.getRole() == role){
1015 public Team getWinnerTeam(){
1023 public int countSuddenDeath(){
1024 int suddenDeath = 0;
1025 for(Player player : this.playerList){
1026 if(player.getDestiny() == Destiny.SUDDENDEATH) suddenDeath++;
1035 public int countAvatarNum(){
1036 int playerNum = this.playerList.size();
1041 * AvatarからPlayerを得る。
1042 * 参加していないAvatarならnullを返す。
1043 * @param avatar Avatar
1046 public final Player getPlayer(Avatar avatar){
1047 Player player = this.playerMap.get(avatar);
1052 * AvatarからPlayerを得る。
1054 * @param avatar Avatar
1057 private Player registPlayer(Avatar avatar){
1058 Player player = getPlayer(avatar);
1060 player = new Player();
1061 player.setAvatar(avatar);
1062 this.playerMap.put(avatar, player);
1071 private static final class CastingComparator
1072 implements Comparator<Player> {
1077 private CastingComparator(){
1084 * @param p1 {@inheritDoc}
1085 * @param p2 {@inheritDoc}
1086 * @return {@inheritDoc}
1089 public int compare(Player p1, Player p2){
1090 if(p1 == p2) return 0;
1091 if(p1 == null) return -1;
1092 if(p2 == null) return +1;
1095 Avatar avatar1 = p1.getAvatar();
1096 Avatar avatar2 = p2.getAvatar();
1097 if(avatar1.equals(avatar2)) return 0;
1098 if(avatar1 == Avatar.AVATAR_GERD) return -1;
1099 if(avatar2 == Avatar.AVATAR_GERD) return +1;
1102 Destiny dest1 = p1.getDestiny();
1103 Destiny dest2 = p2.getDestiny();
1105 if (dest1 == Destiny.ALIVE) return +1;
1106 else if(dest2 == Destiny.ALIVE) return -1;
1110 int obitDay1 = p1.getObitDay();
1111 int obitDay2 = p2.getObitDay();
1112 if(obitDay1 > obitDay2) return +1;
1113 if(obitDay1 < obitDay2) return -1;
1116 int destinyOrder = dest1.compareTo(dest2);
1117 if(destinyOrder != 0) return destinyOrder;
1120 int entryOrder = p1.getEntryNo() - p2.getEntryNo();