2 * System event parser
\r
4 * License : The MIT License
\r
5 * Copyright(c) 2009 olyutorskii
\r
8 package jp.sourceforge.jindolf.parser;
\r
10 import java.util.regex.Pattern;
\r
11 import jp.sourceforge.jindolf.corelib.EventFamily;
\r
12 import jp.sourceforge.jindolf.corelib.GameRole;
\r
13 import jp.sourceforge.jindolf.corelib.SysEventType;
\r
14 import jp.sourceforge.jindolf.corelib.Team;
\r
17 * 人狼BBSシステムが出力する各種イベント表記のパースを行うパーサ。
\r
18 * パース進行に従い{@link SysEventHandler}の各種メソッドが呼び出される。
\r
20 public class SysEventParser extends AbstractParser{
\r
22 private static final String AVATAR_REGEX =
\r
23 "[^<、" + SPCHAR + "]+\u0020[^<、。" + SPCHAR + "]+";
\r
25 private static final Pattern C_DIV_PATTERN =
\r
26 compile(SP_I+ "</div>" +SP_I);
\r
27 private static final Pattern AVATAR_PATTERN =
\r
28 compile(AVATAR_REGEX);
\r
31 private SysEventHandler sysEventHandler;
\r
33 private int pushedRegionStart = -1;
\r
34 private int pushedRegionEnd = -1;
\r
36 private final SeqRange rangepool_1 = new SeqRange();
\r
37 private final SeqRange rangepool_2 = new SeqRange();
\r
38 private final SeqRange rangepool_3 = new SeqRange();
\r
42 * @param parent 親パーサ
\r
44 public SysEventParser(ChainedParser parent){
\r
50 * {@link SysEventHandler}ハンドラを登録する。
\r
51 * @param sysEventHandler ハンドラ
\r
53 public void setSysEventHandler(SysEventHandler sysEventHandler){
\r
54 this.sysEventHandler = sysEventHandler;
\r
59 * Announceメッセージをパースする。
\r
60 * @throws HtmlParseException パースエラー
\r
62 public void parseAnnounce() throws HtmlParseException{
\r
63 setContextErrorMessage("Unknown Announce message");
\r
65 this.sysEventHandler.startSysEvent(EventFamily.ANNOUNCE);
\r
67 int regionStart = regionStart();
\r
68 int regionEnd = regionEnd();
\r
71 probeSimpleAnnounce()
\r
76 || probeSuddenDeath()
\r
78 || probePlayerList()
\r
83 throw buildParseException();
\r
86 getMatcher().region(regionStart, regionEnd);
\r
89 lookingAtAffirm(C_DIV_PATTERN);
\r
92 this.sysEventHandler.endSysEvent();
\r
97 private static final Pattern STARTENTRY_PATTERN =
\r
99 "昼間は人間のふりをして、夜に正体を現すという人狼。<br />"
\r
101 +"この村に紛れ込んでいるという噂が広がった。<br /><br />"
\r
103 +"村はずれの宿に集められることになった。"
\r
105 private static final Pattern STARTMIRROR_PATTERN =
\r
107 "さあ、自らの姿を鏡に映してみよう。<br />"
\r
109 +"それとも血に飢えた人狼か。<br /><br />"
\r
110 +"例え人狼でも、多人数で立ち向かえば怖くはない。<br />"
\r
111 +"問題は、だれが人狼なのかという事だ。<br />"
\r
112 +"占い師の能力を持つ人間ならば、それを見破れるだろう。"
\r
114 private static final Pattern STARTASSAULT_PATTERN =
\r
116 "ついに犠牲者が出た。人狼はこの村人達のなかにいる。<br />"
\r
117 +"しかし、それを見分ける手段はない。<br /><br />"
\r
118 +"村人達は、疑わしい者を排除するため、"
\r
119 +"投票を行う事にした。<br />"
\r
120 +"無実の犠牲者が出るのもやむをえない。"
\r
121 +"村が全滅するよりは……。<br /><br />"
\r
122 +"最後まで残るのは村人か、それとも人狼か。"
\r
124 private static final Pattern NOMURDER_PATTERN =
\r
126 "今日は犠牲者がいないようだ。人狼は襲撃に失敗したのだろうか。");
\r
127 private static final Pattern WINVILLAGE_PATTERN =
\r
129 "全ての人狼を退治した……。人狼に怯える日々は去ったのだ!"
\r
131 private static final Pattern WINWOLF_PATTERN =
\r
133 "もう人狼に抵抗できるほど村人は残っていない……。<br />"
\r
135 +"別の獲物を求めてこの村を去っていった。"
\r
137 private static final Pattern WINHAMSTER_PATTERN =
\r
139 "全ては終わったかのように見えた。<br />"
\r
140 +"だが、奴が生き残っていた……。");
\r
141 private static final Pattern PANIC_PATTERN =
\r
143 private static final Pattern SHORTMEMBER_PATTERN =
\r
148 private static Object[][] simpleRegexToType = {
\r
149 { STARTENTRY_PATTERN, SysEventType.STARTENTRY },
\r
150 { STARTMIRROR_PATTERN, SysEventType.STARTMIRROR },
\r
151 { STARTASSAULT_PATTERN, SysEventType.STARTASSAULT },
\r
152 { NOMURDER_PATTERN, SysEventType.NOMURDER },
\r
153 { WINVILLAGE_PATTERN, SysEventType.WINVILLAGE },
\r
154 { WINWOLF_PATTERN, SysEventType.WINWOLF },
\r
155 { WINHAMSTER_PATTERN, SysEventType.WINHAMSTER },
\r
156 { PANIC_PATTERN, SysEventType.PANIC },
\r
157 { SHORTMEMBER_PATTERN, SysEventType.SHORTMEMBER },
\r
161 * 文字列が固定されたシンプルなAnnounceメッセージのパースを試みる。
\r
162 * @return マッチしたらtrue
\r
163 * @throws HtmlParseException パースエラー
\r
165 private boolean probeSimpleAnnounce() throws HtmlParseException{
\r
170 SysEventType matchedType = null;
\r
172 for(Object[] pair : simpleRegexToType){
\r
173 Pattern pattern = (Pattern)( pair[0] );
\r
175 if(lookingAtProbe(pattern)){
\r
177 matchedType = (SysEventType)( pair[1] );
\r
182 if(matchedType == null){
\r
187 this.sysEventHandler.sysEventType(matchedType);
\r
194 private static final Pattern OPENROLE_HEAD_PATTERN =
\r
195 compile("どうやらこの中には、");
\r
196 private static final Pattern OPENROLE_NUM_PATTERN =
\r
197 compile("が([0-9]+)名(?:、)?");
\r
198 private static final Pattern OPENROLE_TAIL_PATTERN =
\r
202 * OPENROLEメッセージのパースを試みる。
\r
203 * @return マッチしたらtrue
\r
204 * @throws HtmlParseException パースエラー
\r
206 private boolean probeOpenRole() throws HtmlParseException{
\r
211 if( ! lookingAtProbe(OPENROLE_HEAD_PATTERN) ){
\r
217 this.sysEventHandler.sysEventType(SysEventType.OPENROLE);
\r
220 GameRole role = lookingAtRole();
\r
222 if( lookingAtProbe(OPENROLE_TAIL_PATTERN) ){
\r
231 if( ! lookingAtProbe(OPENROLE_NUM_PATTERN) ){
\r
235 int num = parseGroupedInt(1);
\r
238 this.sysEventHandler.sysEventOpenRole(role, num);
\r
246 private static final Pattern SURVIVOR_HEAD_PATTERN =
\r
247 compile("現在の生存者は、");
\r
248 private static final Pattern SURVIVOR_PATTERN =
\r
250 "(" + AVATAR_REGEX + ")"
\r
255 +"\u0020の\u0020([0-9]+)\u0020名。"
\r
260 * SURVIVORメッセージのパースを試みる。
\r
261 * @return マッチしたらtrue
\r
262 * @throws HtmlParseException パースエラー
\r
264 private boolean probeSurvivor() throws HtmlParseException{
\r
265 SeqRange avatarRange = this.rangepool_1;
\r
271 if( ! lookingAtProbe(SURVIVOR_HEAD_PATTERN) ){
\r
277 this.sysEventHandler.sysEventType(SysEventType.SURVIVOR);
\r
281 if( ! lookingAtProbe(SURVIVOR_PATTERN) ){
\r
285 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
286 this.sysEventHandler
\r
287 .sysEventSurvivor(getContent(), avatarRange);
\r
289 if(isGroupMatched(2)){
\r
290 int num = parseGroupedInt(2);
\r
292 if(num != avatarNum){
\r
293 throw new HtmlParseException(regionStart());
\r
305 private static final Pattern MURDERED_HEAD_PATTERN =
\r
307 private static final Pattern MURDERED_SW_PATTERN =
\r
312 +"\u0020が無残な姿で発見された。"
\r
313 +"(?:<br />)?" // E国対策
\r
318 * MURDEREDメッセージのパースを試みる。
\r
319 * @return マッチしたらtrue
\r
320 * @throws HtmlParseException パースエラー
\r
322 private boolean probeMurdered() throws HtmlParseException{
\r
323 SeqRange avatarRange = this.rangepool_1;
\r
324 SeqRange avatarRange2 = this.rangepool_2;
\r
325 avatarRange .setInvalid();
\r
326 avatarRange2.setInvalid();
\r
332 if( ! lookingAtProbe(MURDERED_HEAD_PATTERN)){
\r
338 this.sysEventHandler.sysEventType(SysEventType.MURDERED);
\r
341 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
345 if( ! avatarRange.isValid() ){
\r
346 avatarRange.setLastMatchedRange(getMatcher());
\r
347 }else if( ! avatarRange2.isValid() ){
\r
348 avatarRange2.setLastMatchedRange(getMatcher());
\r
351 throw buildParseException();
\r
355 if( ! lookingAtProbe(MURDERED_SW_PATTERN)){
\r
359 if(isGroupMatched(1)){
\r
362 }else if(isGroupMatched(2)){
\r
367 throw buildParseException();
\r
371 this.sysEventHandler
\r
372 .sysEventMurdered(getContent(), avatarRange);
\r
373 if(avatarRange2.isValid()){
\r
374 this.sysEventHandler
\r
375 .sysEventMurdered(getContent(), avatarRange2);
\r
383 private static final Pattern ONSTAGE_NO_PATTERN =
\r
384 compile("([0-9]+)人目、");
\r
385 private static final Pattern ONSTAGE_DOT_PATTERN =
\r
388 +"(?:" + AVATAR_REGEX + ")"
\r
389 +"|)" // F1556プロローグ対策
\r
393 * ONSTAGEメッセージのパースを試みる。
\r
394 * @return マッチしたらtrue
\r
395 * @throws HtmlParseException パースエラー
\r
397 private boolean probeOnStage() throws HtmlParseException{
\r
398 SeqRange avatarRange = this.rangepool_1;
\r
404 if( ! lookingAtProbe(ONSTAGE_NO_PATTERN) ){
\r
408 int entryNo = parseGroupedInt(1);
\r
411 this.sysEventHandler.sysEventType(SysEventType.ONSTAGE);
\r
413 if( ! lookingAtProbe(ONSTAGE_DOT_PATTERN) ){
\r
417 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
420 this.sysEventHandler
\r
421 .sysEventOnStage(getContent(), entryNo, avatarRange);
\r
428 private static final Pattern SUDDENDEATH_PATTERN =
\r
431 +"(?:" + AVATAR_REGEX + ")"
\r
432 +"|)" // F681 2d 対策
\r
437 * SUDDENDEATHメッセージのパースを試みる。
\r
438 * @return マッチしたらtrue
\r
439 * @throws HtmlParseException パースエラー
\r
441 private boolean probeSuddenDeath() throws HtmlParseException{
\r
442 SeqRange avatarRange = this.rangepool_1;
\r
448 if( ! lookingAtProbe(SUDDENDEATH_PATTERN)){
\r
452 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
455 this.sysEventHandler.sysEventType(SysEventType.SUDDENDEATH);
\r
456 this.sysEventHandler
\r
457 .sysEventSuddenDeath(getContent(), avatarRange);
\r
464 private static final Pattern COUNTING_PATTERN =
\r
468 +"(" + AVATAR_REGEX + ")"
\r
469 +"\u0020は村人達の手により処刑された。"
\r
471 +"(" + AVATAR_REGEX + ")"
\r
473 +"(" + AVATAR_REGEX + ")"
\r
480 * COUNTINGメッセージのパースを試みる。
\r
481 * @return マッチしたらtrue
\r
482 * @throws HtmlParseException パースエラー
\r
484 private boolean probeCounting() throws HtmlParseException{
\r
485 SeqRange voteByRange = this.rangepool_1;
\r
486 SeqRange voteToRange = this.rangepool_2;
\r
492 boolean hasVote = false;
\r
494 if( ! lookingAtProbe(COUNTING_PATTERN) ){
\r
497 if(isGroupMatched(1)){
\r
498 voteByRange.setInvalid();
\r
499 voteToRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
501 this.sysEventHandler
\r
502 .sysEventCounting(getContent(),
\r
506 }else if(isGroupMatched(2)){
\r
509 this.sysEventHandler.sysEventType(SysEventType.COUNTING);
\r
511 voteByRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
512 voteToRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
514 this.sysEventHandler
\r
515 .sysEventCounting(getContent(),
\r
520 throw buildParseException();
\r
534 private static final Pattern COUNTING2_PATTERN =
\r
536 "(" + AVATAR_REGEX + ")"
\r
538 +"(" + AVATAR_REGEX + ")"
\r
544 * COUNTING2メッセージのパースを試みる。
\r
545 * @return マッチしたらtrue
\r
546 * @throws HtmlParseException パースエラー
\r
548 private boolean probeCounting2() throws HtmlParseException{
\r
549 SeqRange voteByRange = this.rangepool_1;
\r
550 SeqRange voteToRange = this.rangepool_2;
\r
556 boolean hasVote = false;
\r
558 if( ! lookingAtProbe(COUNTING2_PATTERN) ){
\r
563 this.sysEventHandler.sysEventType(SysEventType.COUNTING2);
\r
565 voteByRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
566 voteToRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
568 this.sysEventHandler
\r
569 .sysEventCounting2(getContent(),
\r
584 private static final Pattern PLAYERID_PATTERN =
\r
586 "\u0020\uff08" // 全角開き括弧
\r
587 +"(?:<a\u0020href=\"([^\"]*)\">)?"
\r
590 +"\uff09、" // 全角閉じ括弧
\r
592 private static final Pattern LIVEORDIE_PATTERN =
\r
596 private static final Pattern PLAYER_DELIM_PATTERN =
\r
603 * PLAYERLISTメッセージのパースを試みる。
\r
604 * @return マッチしたらtrue
\r
605 * @throws HtmlParseException パースエラー
\r
607 private boolean probePlayerList() throws HtmlParseException{
\r
608 SeqRange avatarRange = this.rangepool_1;
\r
609 SeqRange anchorRange = this.rangepool_2;
\r
610 SeqRange accountRange = this.rangepool_3;
\r
616 boolean hasPlayerList = false;
\r
619 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
622 avatarRange.setLastMatchedRange(getMatcher());
\r
625 if( ! lookingAtProbe(PLAYERID_PATTERN)){
\r
629 if(isGroupMatched(1)){
\r
630 anchorRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
632 anchorRange.setInvalid();
\r
634 accountRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
637 boolean isLiving = false;
\r
638 if( ! lookingAtProbe(LIVEORDIE_PATTERN)){
\r
642 if(isGroupMatched(1)){
\r
644 }else if(isGroupMatched(2)){
\r
649 GameRole role = lookingAtRole();
\r
656 if( ! lookingAtProbe(PLAYER_DELIM_PATTERN)){
\r
662 if( ! hasPlayerList ){
\r
663 hasPlayerList = true;
\r
664 this.sysEventHandler.sysEventType(SysEventType.PLAYERLIST);
\r
667 this.sysEventHandler
\r
668 .sysEventPlayerList(getContent(),
\r
676 if( ! hasPlayerList ){
\r
686 private static final Pattern EXECUTION_PATTERN =
\r
689 + "(" + AVATAR_REGEX + ")、([0-9]+)票。(?:<br />)?"
\r
691 +"<br />(" + AVATAR_REGEX + ")\u0020は"
\r
697 * EXECUTIONメッセージのパースを試みる。
\r
698 * @return マッチしたらtrue
\r
699 * @throws HtmlParseException パースエラー
\r
701 private boolean probeExecution() throws HtmlParseException{
\r
702 SeqRange avatarRange = this.rangepool_1;
\r
708 boolean hasExecution = false;
\r
711 if( ! lookingAtProbe(EXECUTION_PATTERN)){
\r
715 if( ! hasExecution ){
\r
716 hasExecution = true;
\r
717 this.sysEventHandler.sysEventType(SysEventType.EXECUTION);
\r
720 if(isGroupMatched(1)){
\r
721 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
722 int votes = parseGroupedInt(2);
\r
724 this.sysEventHandler
\r
725 .sysEventExecution(getContent(),
\r
728 }else if(isGroupMatched(3)){
\r
729 avatarRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
731 this.sysEventHandler
\r
732 .sysEventExecution(getContent(),
\r
738 if( ! hasExecution ){
\r
748 private static final Pattern VANISH_PATTERN =
\r
751 +"(" + AVATAR_REGEX + ")"
\r
757 * VANISHメッセージのパースを試みる。
\r
758 * @return マッチしたらtrue
\r
759 * @throws HtmlParseException パースエラー
\r
761 private boolean probeVanish() throws HtmlParseException{
\r
762 SeqRange avatarRange = this.rangepool_1;
\r
768 boolean hasVanish = false;
\r
771 if( ! lookingAtProbe(VANISH_PATTERN)){
\r
777 this.sysEventHandler.sysEventType(SysEventType.VANISH);
\r
779 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
783 this.sysEventHandler
\r
784 .sysEventVanish(getContent(), avatarRange);
\r
798 * Orderメッセージをパースする。
\r
799 * @throws HtmlParseException パースエラー
\r
801 public void parseOrder() throws HtmlParseException{
\r
802 setContextErrorMessage("Unknown Order message");
\r
804 this.sysEventHandler.startSysEvent(EventFamily.ORDER);
\r
806 int regionStart = regionStart();
\r
807 int regionEnd = regionEnd();
\r
811 || probeAskCommit()
\r
812 || probeNoComment()
\r
813 || probeStayEpilogue()
\r
817 throw buildParseException();
\r
820 getMatcher().region(regionStart, regionEnd);
\r
823 lookingAtAffirm(C_DIV_PATTERN);
\r
826 this.sysEventHandler.endSysEvent();
\r
831 private static final Pattern ASKENTRY_PATTERN =
\r
833 "演じたいキャラクターを選び、発言してください。<br />"
\r
834 +"([0-2][0-9]):([0-5][0-9])\u0020に"
\r
835 +"([0-9]+)名以上がエントリーしていれば進行します。<br />"
\r
836 +"最大([0-9]+)名まで参加可能です。<br /><br />"
\r
837 +"※[\u0020]?エントリーは取り消せません。"
\r
838 +"ルールをよく理解した上でご参加下さい。<br />"
\r
839 +"(?:※始めての方は、村人希望での参加となります。<br />)?"
\r
840 +"(?:※希望能力についての発言は控えてください。<br />)?"
\r
844 * ASKENTRYメッセージのパースを試みる。
\r
845 * @return マッチしたらtrue
\r
846 * @throws HtmlParseException パースエラー
\r
848 private boolean probeAskEntry() throws HtmlParseException{
\r
853 if( ! lookingAtProbe(ASKENTRY_PATTERN)){
\r
858 int hour = parseGroupedInt(1);
\r
859 int minute = parseGroupedInt(2);
\r
860 int minLimit = parseGroupedInt(3);
\r
861 int maxLimit = parseGroupedInt(4);
\r
865 this.sysEventHandler.sysEventType(SysEventType.ASKENTRY);
\r
866 this.sysEventHandler
\r
867 .sysEventAskEntry(hour, minute, minLimit, maxLimit);
\r
874 private static final Pattern ASKCOMMIT_PATTERN =
\r
877 +"([0-2][0-9]):([0-5][0-9])\u0020までに、"
\r
878 +"誰を処刑するべきかの投票先を決定して下さい。<br />"
\r
879 +"一番票を集めた人物が処刑されます。"
\r
880 +"同数だった場合はランダムで決定されます。<br /><br />"
\r
883 +"([0-2][0-9]):([0-5][0-9])\u0020までに"
\r
884 +"行動を確定して下さい。<br />"
\r
888 * ASKCOMMITメッセージのパースを試みる。
\r
889 * @return マッチしたらtrue
\r
890 * @throws HtmlParseException パースエラー
\r
892 private boolean probeAskCommit() throws HtmlParseException{
\r
897 if( ! lookingAtProbe(ASKCOMMIT_PATTERN)){
\r
903 if(isGroupMatched(1)){
\r
909 int hh1 = parseGroupedInt(1);
\r
910 int mm1 = parseGroupedInt(2);
\r
911 int hh2 = parseGroupedInt(3);
\r
912 int mm2 = parseGroupedInt(4);
\r
916 if( ! is1stDay && (hh1 != hh2 || mm1 != mm2) ){
\r
917 throw new HtmlParseException(regionStart());
\r
920 this.sysEventHandler.sysEventType(SysEventType.ASKCOMMIT);
\r
921 this.sysEventHandler.sysEventAskCommit(hh2, mm2);
\r
928 private static final Pattern NOCOMMENT_HEAD_PATTERN =
\r
929 compile("本日まだ発言していない者は、");
\r
930 private static final Pattern NOCOMMENT_AVATAR_PATTERN =
\r
933 +"(" + AVATAR_REGEX + ")、"
\r
935 +"以上\u0020([0-9]+)\u0020名。"
\r
940 * NOCOMMENTメッセージのパースを試みる。
\r
941 * @return マッチしたらtrue
\r
942 * @throws HtmlParseException パースエラー
\r
944 private boolean probeNoComment() throws HtmlParseException{
\r
945 SeqRange avatarRange = this.rangepool_1;
\r
951 if( ! lookingAtProbe(NOCOMMENT_HEAD_PATTERN)){
\r
957 this.sysEventHandler.sysEventType(SysEventType.NOCOMMENT);
\r
961 if( ! lookingAtProbe(NOCOMMENT_AVATAR_PATTERN)){
\r
966 if(isGroupMatched(1)){
\r
967 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
968 this.sysEventHandler
\r
969 .sysEventNoComment(getContent(), avatarRange);
\r
972 }else if(isGroupMatched(2)){
\r
973 int num = parseGroupedInt(2);
\r
975 if(num != avatarNum){
\r
976 throw new HtmlParseException(regionStart());
\r
987 private static final Pattern STAYEPILOGUE_PATTERN =
\r
989 "(?:(村人)|(人狼)|(ハムスター))側の勝利です!<br />"
\r
990 +"全てのログとユーザー名を公開します。"
\r
991 +"([0-2][0-9]):([0-5][0-9])\u0020まで"
\r
993 +"今回の感想などをどうぞ。<br />"
\r
997 * STAYEPILOGUEメッセージのパースを試みる。
\r
998 * @return マッチしたらtrue
\r
999 * @throws HtmlParseException パースエラー
\r
1001 private boolean probeStayEpilogue() throws HtmlParseException{
\r
1006 if( ! lookingAtProbe(STAYEPILOGUE_PATTERN)){
\r
1011 Team winner = null;
\r
1012 if(isGroupMatched(1)){
\r
1013 winner = Team.VILLAGE;
\r
1014 }else if(isGroupMatched(2)){
\r
1015 winner = Team.WOLF;
\r
1016 }else if(isGroupMatched(3)){
\r
1017 winner = Team.HAMSTER;
\r
1020 int hour = parseGroupedInt(4);
\r
1021 int minute = parseGroupedInt(5);
\r
1025 this.sysEventHandler.sysEventType(SysEventType.STAYEPILOGUE);
\r
1026 this.sysEventHandler.sysEventStayEpilogue(winner, hour, minute);
\r
1033 private static final Pattern GAMEOVER_PATTERN =
\r
1034 compile("終了しました。" + "<br />");
\r
1037 * GAMEOVERメッセージのパースを試みる。
\r
1038 * @return マッチしたらtrue
\r
1039 * @throws HtmlParseException パースエラー
\r
1041 private boolean probeGameOver() throws HtmlParseException{
\r
1046 if( ! lookingAtProbe(GAMEOVER_PATTERN)){
\r
1053 this.sysEventHandler.sysEventType(SysEventType.GAMEOVER);
\r
1061 * Extraメッセージをパースする。
\r
1062 * @throws HtmlParseException パースエラー
\r
1064 public void parseExtra() throws HtmlParseException{
\r
1065 setContextErrorMessage("Unknown Extra message");
\r
1067 this.sysEventHandler.startSysEvent(EventFamily.EXTRA);
\r
1069 int regionStart = regionStart();
\r
1070 int regionEnd = regionEnd();
\r
1075 || probeCounting2();
\r
1077 throw buildParseException();
\r
1080 getMatcher().region(regionStart, regionEnd);
\r
1083 lookingAtAffirm(C_DIV_PATTERN);
\r
1086 this.sysEventHandler.endSysEvent();
\r
1091 private static final Pattern JUDGE_DELIM_PATTERN =
\r
1092 compile("\u0020は、");
\r
1093 private static final Pattern JUDGE_TAIL_PATTERN =
\r
1094 compile("\u0020を占った。");
\r
1097 * JUDGEメッセージのパースを試みる。
\r
1098 * @return マッチしたらtrue
\r
1099 * @throws HtmlParseException パースエラー
\r
1101 private boolean probeJudge() throws HtmlParseException{
\r
1102 SeqRange judgeByRange = this.rangepool_1;
\r
1103 SeqRange judgeToRange = this.rangepool_2;
\r
1109 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1113 judgeByRange.setLastMatchedRange(getMatcher());
\r
1116 if( ! lookingAtProbe(JUDGE_DELIM_PATTERN)){
\r
1122 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1126 judgeToRange.setLastMatchedRange(getMatcher());
\r
1129 if( ! lookingAtProbe(JUDGE_TAIL_PATTERN)){
\r
1135 this.sysEventHandler.sysEventType(SysEventType.JUDGE);
\r
1136 this.sysEventHandler
\r
1137 .sysEventJudge(getContent(),
\r
1145 private static final Pattern GUARD_DELIM_PATTERN =
\r
1146 compile("\u0020は、");
\r
1147 private static final Pattern GUARD_TAIL_PATTERN =
\r
1148 compile("\u0020を守っている。");
\r
1151 * GUARDメッセージのパースを試みる。
\r
1152 * @return マッチしたらtrue
\r
1153 * @throws HtmlParseException パースエラー
\r
1155 private boolean probeGuard() throws HtmlParseException{
\r
1156 SeqRange guardByRange = this.rangepool_1;
\r
1157 SeqRange guardToRange = this.rangepool_2;
\r
1163 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1167 guardByRange.setLastMatchedRange(getMatcher());
\r
1170 if( ! lookingAtProbe(GUARD_DELIM_PATTERN)){
\r
1176 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1180 guardToRange.setLastMatchedRange(getMatcher());
\r
1183 if( ! lookingAtProbe(GUARD_TAIL_PATTERN)){
\r
1189 this.sysEventHandler.sysEventType(SysEventType.GUARD);
\r
1190 this.sysEventHandler.sysEventGuard(getContent(),
\r
1198 private static final Pattern CONTENT_PATTERN =
\r
1205 +"<a\u0020href=\"([^\"]*)\">([^<>]*)</a>"
\r
1210 * システムイベントの内容文字列をパースする。
\r
1211 * @throws HtmlParseException パースエラー
\r
1213 private void parseContent() throws HtmlParseException{
\r
1214 SeqRange anchorRange = this.rangepool_1;
\r
1215 SeqRange contentRange = this.rangepool_2;
\r
1220 if( ! lookingAtProbe(CONTENT_PATTERN) ){
\r
1224 if(isGroupMatched(1)){
\r
1225 contentRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
1226 this.sysEventHandler
\r
1227 .sysEventContent(getContent(), contentRange);
\r
1228 }else if(isGroupMatched(2)){
\r
1229 this.sysEventHandler.sysEventContentBreak();
\r
1230 }else if(isGroupMatched(3)){
\r
1231 anchorRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
1232 contentRange.setLastMatchedGroupRange(getMatcher(), 4);
\r
1233 this.sysEventHandler
\r
1234 .sysEventContentAnchor(getContent(),
\r
1248 * 一時的に現在の検索領域を待避する。
\r
1249 * 待避できるのは1回のみ。複数回スタックはできない。
\r
1250 * @see #popRegion()
\r
1252 private void pushRegion(){
\r
1253 this.pushedRegionStart = regionStart();
\r
1254 this.pushedRegionEnd = regionEnd();
\r
1259 * 一時的に待避した検索領域を復活させる。
\r
1260 * @throws IllegalStateException まだ何も待避していない。
\r
1261 * @see #pushRegion()
\r
1263 private void popRegion() throws IllegalStateException{
\r
1264 if(this.pushedRegionStart < 0 || this.pushedRegionEnd < 0){
\r
1265 throw new IllegalStateException();
\r
1268 if( this.pushedRegionStart != regionStart()
\r
1269 || this.pushedRegionEnd != regionEnd() ){
\r
1270 getMatcher().region(this.pushedRegionStart, this.pushedRegionEnd);
\r
1273 this.pushedRegionStart = -1;
\r
1274 this.pushedRegionEnd = -1;
\r