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
144 private static Object[][] simpleRegexToType = {
\r
145 { STARTENTRY_PATTERN, SysEventType.STARTENTRY },
\r
146 { STARTMIRROR_PATTERN, SysEventType.STARTMIRROR },
\r
147 { STARTASSAULT_PATTERN, SysEventType.STARTASSAULT },
\r
148 { NOMURDER_PATTERN, SysEventType.NOMURDER },
\r
149 { WINVILLAGE_PATTERN, SysEventType.WINVILLAGE },
\r
150 { WINWOLF_PATTERN, SysEventType.WINWOLF },
\r
151 { WINHAMSTER_PATTERN, SysEventType.WINHAMSTER },
\r
152 { PANIC_PATTERN, SysEventType.PANIC },
\r
156 * 文字列が固定されたシンプルなAnnounceメッセージのパースを試みる。
\r
157 * @return マッチしたらtrue
\r
158 * @throws HtmlParseException パースエラー
\r
160 private boolean probeSimpleAnnounce() throws HtmlParseException{
\r
165 SysEventType matchedType = null;
\r
167 for(Object[] pair : simpleRegexToType){
\r
168 Pattern pattern = (Pattern)( pair[0] );
\r
170 if(lookingAtProbe(pattern)){
\r
172 matchedType = (SysEventType)( pair[1] );
\r
177 if(matchedType == null){
\r
182 this.sysEventHandler.sysEventType(matchedType);
\r
189 private static final Pattern OPENROLE_HEAD_PATTERN =
\r
190 compile("どうやらこの中には、");
\r
191 private static final Pattern OPENROLE_NUM_PATTERN =
\r
192 compile("が([0-9]+)名(?:、)?");
\r
193 private static final Pattern OPENROLE_TAIL_PATTERN =
\r
197 * OPENROLEメッセージのパースを試みる。
\r
198 * @return マッチしたらtrue
\r
199 * @throws HtmlParseException パースエラー
\r
201 private boolean probeOpenRole() throws HtmlParseException{
\r
206 if( ! lookingAtProbe(OPENROLE_HEAD_PATTERN) ){
\r
212 this.sysEventHandler.sysEventType(SysEventType.OPENROLE);
\r
215 GameRole role = lookingAtRole();
\r
217 if( lookingAtProbe(OPENROLE_TAIL_PATTERN) ){
\r
226 if( ! lookingAtProbe(OPENROLE_NUM_PATTERN) ){
\r
230 int num = parseGroupedInt(1);
\r
233 this.sysEventHandler.sysEventOpenRole(role, num);
\r
241 private static final Pattern SURVIVOR_HEAD_PATTERN =
\r
242 compile("現在の生存者は、");
\r
243 private static final Pattern SURVIVOR_PATTERN =
\r
245 "(" + AVATAR_REGEX + ")"
\r
250 +"\u0020の\u0020([0-9]+)\u0020名。"
\r
255 * SURVIVORメッセージのパースを試みる。
\r
256 * @return マッチしたらtrue
\r
257 * @throws HtmlParseException パースエラー
\r
259 private boolean probeSurvivor() throws HtmlParseException{
\r
260 SeqRange avatarRange = this.rangepool_1;
\r
266 if( ! lookingAtProbe(SURVIVOR_HEAD_PATTERN) ){
\r
272 this.sysEventHandler.sysEventType(SysEventType.SURVIVOR);
\r
276 if( ! lookingAtProbe(SURVIVOR_PATTERN) ){
\r
280 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
281 this.sysEventHandler
\r
282 .sysEventSurvivor(getContent(), avatarRange);
\r
284 if(isGroupMatched(2)){
\r
285 int num = parseGroupedInt(2);
\r
287 if(num != avatarNum){
\r
288 throw new HtmlParseException(regionStart());
\r
300 private static final Pattern MURDERED_HEAD_PATTERN =
\r
302 private static final Pattern MURDERED_SW_PATTERN =
\r
307 +"\u0020が無残な姿で発見された。"
\r
308 +"(?:<br />)?" // E国対策
\r
313 * MURDEREDメッセージのパースを試みる。
\r
314 * @return マッチしたらtrue
\r
315 * @throws HtmlParseException パースエラー
\r
317 private boolean probeMurdered() throws HtmlParseException{
\r
318 SeqRange avatarRange = this.rangepool_1;
\r
319 SeqRange avatarRange2 = this.rangepool_2;
\r
320 avatarRange .setInvalid();
\r
321 avatarRange2.setInvalid();
\r
327 if( ! lookingAtProbe(MURDERED_HEAD_PATTERN)){
\r
333 this.sysEventHandler.sysEventType(SysEventType.MURDERED);
\r
336 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
340 if( ! avatarRange.isValid() ){
\r
341 avatarRange.setLastMatchedRange(getMatcher());
\r
342 }else if( ! avatarRange2.isValid() ){
\r
343 avatarRange2.setLastMatchedRange(getMatcher());
\r
346 throw buildParseException();
\r
350 if( ! lookingAtProbe(MURDERED_SW_PATTERN)){
\r
354 if(isGroupMatched(1)){
\r
357 }else if(isGroupMatched(2)){
\r
362 throw buildParseException();
\r
366 this.sysEventHandler
\r
367 .sysEventMurdered(getContent(), avatarRange);
\r
368 if(avatarRange2.isValid()){
\r
369 this.sysEventHandler
\r
370 .sysEventMurdered(getContent(), avatarRange2);
\r
378 private static final Pattern ONSTAGE_NO_PATTERN =
\r
379 compile("([0-9]+)人目、");
\r
380 private static final Pattern ONSTAGE_DOT_PATTERN =
\r
383 +"(?:" + AVATAR_REGEX + ")"
\r
384 +"|)" // F1556プロローグ対策
\r
388 * ONSTAGEメッセージのパースを試みる。
\r
389 * @return マッチしたらtrue
\r
390 * @throws HtmlParseException パースエラー
\r
392 private boolean probeOnStage() throws HtmlParseException{
\r
393 SeqRange avatarRange = this.rangepool_1;
\r
399 if( ! lookingAtProbe(ONSTAGE_NO_PATTERN) ){
\r
403 int entryNo = parseGroupedInt(1);
\r
406 this.sysEventHandler.sysEventType(SysEventType.ONSTAGE);
\r
408 if( ! lookingAtProbe(ONSTAGE_DOT_PATTERN) ){
\r
412 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
415 this.sysEventHandler
\r
416 .sysEventOnStage(getContent(), entryNo, avatarRange);
\r
423 private static final Pattern SUDDENDEATH_PATTERN =
\r
426 +"(?:" + AVATAR_REGEX + ")"
\r
427 +"|)" // F681 2d 対策
\r
432 * SUDDENDEATHメッセージのパースを試みる。
\r
433 * @return マッチしたらtrue
\r
434 * @throws HtmlParseException パースエラー
\r
436 private boolean probeSuddenDeath() throws HtmlParseException{
\r
437 SeqRange avatarRange = this.rangepool_1;
\r
443 if( ! lookingAtProbe(SUDDENDEATH_PATTERN)){
\r
447 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
450 this.sysEventHandler.sysEventType(SysEventType.SUDDENDEATH);
\r
451 this.sysEventHandler
\r
452 .sysEventSuddenDeath(getContent(), avatarRange);
\r
459 private static final Pattern COUNTING_PATTERN =
\r
463 +"(" + AVATAR_REGEX + ")"
\r
464 +"\u0020は村人達の手により処刑された。"
\r
466 +"(" + AVATAR_REGEX + ")"
\r
468 +"(" + AVATAR_REGEX + ")"
\r
475 * COUNTINGメッセージのパースを試みる。
\r
476 * @return マッチしたらtrue
\r
477 * @throws HtmlParseException パースエラー
\r
479 private boolean probeCounting() throws HtmlParseException{
\r
480 SeqRange voteByRange = this.rangepool_1;
\r
481 SeqRange voteToRange = this.rangepool_2;
\r
487 boolean hasVote = false;
\r
489 if( ! lookingAtProbe(COUNTING_PATTERN) ){
\r
492 if(isGroupMatched(1)){
\r
493 voteByRange.setInvalid();
\r
494 voteToRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
496 this.sysEventHandler
\r
497 .sysEventCounting(getContent(),
\r
501 }else if(isGroupMatched(2)){
\r
504 this.sysEventHandler.sysEventType(SysEventType.COUNTING);
\r
506 voteByRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
507 voteToRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
509 this.sysEventHandler
\r
510 .sysEventCounting(getContent(),
\r
515 throw buildParseException();
\r
529 private static final Pattern COUNTING2_PATTERN =
\r
531 "(" + AVATAR_REGEX + ")"
\r
533 +"(" + AVATAR_REGEX + ")"
\r
539 * COUNTING2メッセージのパースを試みる。
\r
540 * @return マッチしたらtrue
\r
541 * @throws HtmlParseException パースエラー
\r
543 private boolean probeCounting2() throws HtmlParseException{
\r
544 SeqRange voteByRange = this.rangepool_1;
\r
545 SeqRange voteToRange = this.rangepool_2;
\r
551 boolean hasVote = false;
\r
553 if( ! lookingAtProbe(COUNTING2_PATTERN) ){
\r
558 this.sysEventHandler.sysEventType(SysEventType.COUNTING2);
\r
560 voteByRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
561 voteToRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
563 this.sysEventHandler
\r
564 .sysEventCounting2(getContent(),
\r
579 private static final Pattern PLAYERID_PATTERN =
\r
581 "\u0020\uff08" // 全角開き括弧
\r
582 +"(?:<a\u0020href=\"([^\"]*)\">)?"
\r
585 +"\uff09、" // 全角閉じ括弧
\r
587 private static final Pattern LIVEORDIE_PATTERN =
\r
591 private static final Pattern PLAYER_DELIM_PATTERN =
\r
598 * PLAYERLISTメッセージのパースを試みる。
\r
599 * @return マッチしたらtrue
\r
600 * @throws HtmlParseException パースエラー
\r
602 private boolean probePlayerList() throws HtmlParseException{
\r
603 SeqRange avatarRange = this.rangepool_1;
\r
604 SeqRange anchorRange = this.rangepool_2;
\r
605 SeqRange accountRange = this.rangepool_3;
\r
611 boolean hasPlayerList = false;
\r
614 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
617 avatarRange.setLastMatchedRange(getMatcher());
\r
620 if( ! lookingAtProbe(PLAYERID_PATTERN)){
\r
624 if(isGroupMatched(1)){
\r
625 anchorRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
627 anchorRange.setInvalid();
\r
629 accountRange.setLastMatchedGroupRange(getMatcher(), 2);
\r
632 boolean isLiving = false;
\r
633 if( ! lookingAtProbe(LIVEORDIE_PATTERN)){
\r
637 if(isGroupMatched(1)){
\r
639 }else if(isGroupMatched(2)){
\r
644 GameRole role = lookingAtRole();
\r
651 if( ! lookingAtProbe(PLAYER_DELIM_PATTERN)){
\r
657 if( ! hasPlayerList ){
\r
658 hasPlayerList = true;
\r
659 this.sysEventHandler.sysEventType(SysEventType.PLAYERLIST);
\r
662 this.sysEventHandler
\r
663 .sysEventPlayerList(getContent(),
\r
671 if( ! hasPlayerList ){
\r
681 private static final Pattern EXECUTION_PATTERN =
\r
684 + "(" + AVATAR_REGEX + ")、([0-9]+)票。(?:<br />)?"
\r
686 +"<br />(" + AVATAR_REGEX + ")\u0020は"
\r
692 * EXECUTIONメッセージのパースを試みる。
\r
693 * @return マッチしたらtrue
\r
694 * @throws HtmlParseException パースエラー
\r
696 private boolean probeExecution() throws HtmlParseException{
\r
697 SeqRange avatarRange = this.rangepool_1;
\r
703 boolean hasExecution = false;
\r
706 if( ! lookingAtProbe(EXECUTION_PATTERN)){
\r
710 if( ! hasExecution ){
\r
711 hasExecution = true;
\r
712 this.sysEventHandler.sysEventType(SysEventType.EXECUTION);
\r
715 if(isGroupMatched(1)){
\r
716 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
717 int votes = parseGroupedInt(2);
\r
719 this.sysEventHandler
\r
720 .sysEventExecution(getContent(),
\r
723 }else if(isGroupMatched(3)){
\r
724 avatarRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
726 this.sysEventHandler
\r
727 .sysEventExecution(getContent(),
\r
733 if( ! hasExecution ){
\r
743 private static final Pattern VANISH_PATTERN =
\r
746 +"(" + AVATAR_REGEX + ")"
\r
752 * VANISHメッセージのパースを試みる。
\r
753 * @return マッチしたらtrue
\r
754 * @throws HtmlParseException パースエラー
\r
756 private boolean probeVanish() throws HtmlParseException{
\r
757 SeqRange avatarRange = this.rangepool_1;
\r
763 boolean hasVanish = false;
\r
766 if( ! lookingAtProbe(VANISH_PATTERN)){
\r
772 this.sysEventHandler.sysEventType(SysEventType.VANISH);
\r
774 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
778 this.sysEventHandler
\r
779 .sysEventVanish(getContent(), avatarRange);
\r
793 * Orderメッセージをパースする。
\r
794 * @throws HtmlParseException パースエラー
\r
796 public void parseOrder() throws HtmlParseException{
\r
797 setContextErrorMessage("Unknown Order message");
\r
799 this.sysEventHandler.startSysEvent(EventFamily.ORDER);
\r
801 int regionStart = regionStart();
\r
802 int regionEnd = regionEnd();
\r
806 || probeAskCommit()
\r
807 || probeNoComment()
\r
808 || probeStayEpilogue()
\r
812 throw buildParseException();
\r
815 getMatcher().region(regionStart, regionEnd);
\r
818 lookingAtAffirm(C_DIV_PATTERN);
\r
821 this.sysEventHandler.endSysEvent();
\r
826 private static final Pattern ASKENTRY_PATTERN =
\r
828 "演じたいキャラクターを選び、発言してください。<br />"
\r
829 +"([0-2][0-9]):([0-5][0-9])\u0020に"
\r
830 +"([0-9]+)名以上がエントリーしていれば進行します。<br />"
\r
831 +"最大([0-9]+)名まで参加可能です。<br /><br />"
\r
832 +"※[\u0020]?エントリーは取り消せません。"
\r
833 +"ルールをよく理解した上でご参加下さい。<br />"
\r
834 +"(?:※始めての方は、村人希望での参加となります。<br />)?"
\r
835 +"(?:※希望能力についての発言は控えてください。<br />)?"
\r
839 * ASKENTRYメッセージのパースを試みる。
\r
840 * @return マッチしたらtrue
\r
841 * @throws HtmlParseException パースエラー
\r
843 private boolean probeAskEntry() throws HtmlParseException{
\r
848 if( ! lookingAtProbe(ASKENTRY_PATTERN)){
\r
853 int hour = parseGroupedInt(1);
\r
854 int minute = parseGroupedInt(2);
\r
855 int minLimit = parseGroupedInt(3);
\r
856 int maxLimit = parseGroupedInt(4);
\r
860 this.sysEventHandler.sysEventType(SysEventType.ASKENTRY);
\r
861 this.sysEventHandler
\r
862 .sysEventAskEntry(hour, minute, minLimit, maxLimit);
\r
869 private static final Pattern ASKCOMMIT_PATTERN =
\r
872 +"([0-2][0-9]):([0-5][0-9])\u0020までに、"
\r
873 +"誰を処刑するべきかの投票先を決定して下さい。<br />"
\r
874 +"一番票を集めた人物が処刑されます。"
\r
875 +"同数だった場合はランダムで決定されます。<br /><br />"
\r
878 +"([0-2][0-9]):([0-5][0-9])\u0020までに"
\r
879 +"行動を確定して下さい。<br />"
\r
883 * ASKCOMMITメッセージのパースを試みる。
\r
884 * @return マッチしたらtrue
\r
885 * @throws HtmlParseException パースエラー
\r
887 private boolean probeAskCommit() throws HtmlParseException{
\r
892 if( ! lookingAtProbe(ASKCOMMIT_PATTERN)){
\r
898 if(isGroupMatched(1)){
\r
904 int hh1 = parseGroupedInt(1);
\r
905 int mm1 = parseGroupedInt(2);
\r
906 int hh2 = parseGroupedInt(3);
\r
907 int mm2 = parseGroupedInt(4);
\r
911 if( ! is1stDay && (hh1 != hh2 || mm1 != mm2) ){
\r
912 throw new HtmlParseException(regionStart());
\r
915 this.sysEventHandler.sysEventType(SysEventType.ASKCOMMIT);
\r
916 this.sysEventHandler.sysEventAskCommit(hh2, mm2);
\r
923 private static final Pattern NOCOMMENT_HEAD_PATTERN =
\r
924 compile("本日まだ発言していない者は、");
\r
925 private static final Pattern NOCOMMENT_AVATAR_PATTERN =
\r
928 +"(" + AVATAR_REGEX + ")、"
\r
930 +"以上\u0020([0-9]+)\u0020名。"
\r
935 * NOCOMMENTメッセージのパースを試みる。
\r
936 * @return マッチしたらtrue
\r
937 * @throws HtmlParseException パースエラー
\r
939 private boolean probeNoComment() throws HtmlParseException{
\r
940 SeqRange avatarRange = this.rangepool_1;
\r
946 if( ! lookingAtProbe(NOCOMMENT_HEAD_PATTERN)){
\r
952 this.sysEventHandler.sysEventType(SysEventType.NOCOMMENT);
\r
956 if( ! lookingAtProbe(NOCOMMENT_AVATAR_PATTERN)){
\r
961 if(isGroupMatched(1)){
\r
962 avatarRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
963 this.sysEventHandler
\r
964 .sysEventNoComment(getContent(), avatarRange);
\r
967 }else if(isGroupMatched(2)){
\r
968 int num = parseGroupedInt(2);
\r
970 if(num != avatarNum){
\r
971 throw new HtmlParseException(regionStart());
\r
982 private static final Pattern STAYEPILOGUE_PATTERN =
\r
984 "(?:(村人)|(人狼)|(ハムスター))側の勝利です!<br />"
\r
985 +"全てのログとユーザー名を公開します。"
\r
986 +"([0-2][0-9]):([0-5][0-9])\u0020まで"
\r
988 +"今回の感想などをどうぞ。<br />"
\r
992 * STAYEPILOGUEメッセージのパースを試みる。
\r
993 * @return マッチしたらtrue
\r
994 * @throws HtmlParseException パースエラー
\r
996 private boolean probeStayEpilogue() throws HtmlParseException{
\r
1001 if( ! lookingAtProbe(STAYEPILOGUE_PATTERN)){
\r
1006 Team winner = null;
\r
1007 if(isGroupMatched(1)){
\r
1008 winner = Team.VILLAGE;
\r
1009 }else if(isGroupMatched(2)){
\r
1010 winner = Team.WOLF;
\r
1011 }else if(isGroupMatched(3)){
\r
1012 winner = Team.HAMSTER;
\r
1015 int hour = parseGroupedInt(4);
\r
1016 int minute = parseGroupedInt(5);
\r
1020 this.sysEventHandler.sysEventType(SysEventType.STAYEPILOGUE);
\r
1021 this.sysEventHandler.sysEventStayEpilogue(winner, hour, minute);
\r
1028 private static final Pattern GAMEOVER_PATTERN =
\r
1029 compile("終了しました。" + "<br />");
\r
1032 * GAMEOVERメッセージのパースを試みる。
\r
1033 * @return マッチしたらtrue
\r
1034 * @throws HtmlParseException パースエラー
\r
1036 private boolean probeGameOver() throws HtmlParseException{
\r
1041 if( ! lookingAtProbe(GAMEOVER_PATTERN)){
\r
1048 this.sysEventHandler.sysEventType(SysEventType.GAMEOVER);
\r
1056 * Extraメッセージをパースする。
\r
1057 * @throws HtmlParseException パースエラー
\r
1059 public void parseExtra() throws HtmlParseException{
\r
1060 setContextErrorMessage("Unknown Extra message");
\r
1062 this.sysEventHandler.startSysEvent(EventFamily.EXTRA);
\r
1064 int regionStart = regionStart();
\r
1065 int regionEnd = regionEnd();
\r
1070 || probeCounting2();
\r
1072 throw buildParseException();
\r
1075 getMatcher().region(regionStart, regionEnd);
\r
1078 lookingAtAffirm(C_DIV_PATTERN);
\r
1081 this.sysEventHandler.endSysEvent();
\r
1086 private static final Pattern JUDGE_DELIM_PATTERN =
\r
1087 compile("\u0020は、");
\r
1088 private static final Pattern JUDGE_TAIL_PATTERN =
\r
1089 compile("\u0020を占った。");
\r
1092 * JUDGEメッセージのパースを試みる。
\r
1093 * @return マッチしたらtrue
\r
1094 * @throws HtmlParseException パースエラー
\r
1096 private boolean probeJudge() throws HtmlParseException{
\r
1097 SeqRange judgeByRange = this.rangepool_1;
\r
1098 SeqRange judgeToRange = this.rangepool_2;
\r
1104 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1108 judgeByRange.setLastMatchedRange(getMatcher());
\r
1111 if( ! lookingAtProbe(JUDGE_DELIM_PATTERN)){
\r
1117 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1121 judgeToRange.setLastMatchedRange(getMatcher());
\r
1124 if( ! lookingAtProbe(JUDGE_TAIL_PATTERN)){
\r
1130 this.sysEventHandler.sysEventType(SysEventType.JUDGE);
\r
1131 this.sysEventHandler
\r
1132 .sysEventJudge(getContent(),
\r
1140 private static final Pattern GUARD_DELIM_PATTERN =
\r
1141 compile("\u0020は、");
\r
1142 private static final Pattern GUARD_TAIL_PATTERN =
\r
1143 compile("\u0020を守っている。");
\r
1146 * GUARDメッセージのパースを試みる。
\r
1147 * @return マッチしたらtrue
\r
1148 * @throws HtmlParseException パースエラー
\r
1150 private boolean probeGuard() throws HtmlParseException{
\r
1151 SeqRange guardByRange = this.rangepool_1;
\r
1152 SeqRange guardToRange = this.rangepool_2;
\r
1158 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1162 guardByRange.setLastMatchedRange(getMatcher());
\r
1165 if( ! lookingAtProbe(GUARD_DELIM_PATTERN)){
\r
1171 if( ! lookingAtProbe(AVATAR_PATTERN)){
\r
1175 guardToRange.setLastMatchedRange(getMatcher());
\r
1178 if( ! lookingAtProbe(GUARD_TAIL_PATTERN)){
\r
1184 this.sysEventHandler.sysEventType(SysEventType.GUARD);
\r
1185 this.sysEventHandler.sysEventGuard(getContent(),
\r
1193 private static final Pattern CONTENT_PATTERN =
\r
1200 +"<a\u0020href=\"([^\"]*)\">([^<>]*)</a>"
\r
1205 * システムイベントの内容文字列をパースする。
\r
1206 * @throws HtmlParseException パースエラー
\r
1208 private void parseContent() throws HtmlParseException{
\r
1209 SeqRange anchorRange = this.rangepool_1;
\r
1210 SeqRange contentRange = this.rangepool_2;
\r
1215 if( ! lookingAtProbe(CONTENT_PATTERN) ){
\r
1219 if(isGroupMatched(1)){
\r
1220 contentRange.setLastMatchedGroupRange(getMatcher(), 1);
\r
1221 this.sysEventHandler
\r
1222 .sysEventContent(getContent(), contentRange);
\r
1223 }else if(isGroupMatched(2)){
\r
1224 this.sysEventHandler.sysEventContentBreak();
\r
1225 }else if(isGroupMatched(3)){
\r
1226 anchorRange.setLastMatchedGroupRange(getMatcher(), 3);
\r
1227 contentRange.setLastMatchedGroupRange(getMatcher(), 4);
\r
1228 this.sysEventHandler
\r
1229 .sysEventContentAnchor(getContent(),
\r
1243 * 一時的に現在の検索領域を待避する。
\r
1244 * 待避できるのは1回のみ。複数回スタックはできない。
\r
1245 * @see #popRegion()
\r
1247 private void pushRegion(){
\r
1248 this.pushedRegionStart = regionStart();
\r
1249 this.pushedRegionEnd = regionEnd();
\r
1254 * 一時的に待避した検索領域を復活させる。
\r
1255 * @throws IllegalStateException まだ何も待避していない。
\r
1256 * @see #pushRegion()
\r
1258 private void popRegion() throws IllegalStateException{
\r
1259 if(this.pushedRegionStart < 0 || this.pushedRegionEnd < 0){
\r
1260 throw new IllegalStateException();
\r
1263 if( this.pushedRegionStart != regionStart()
\r
1264 || this.pushedRegionEnd != regionEnd() ){
\r
1265 getMatcher().region(this.pushedRegionStart, this.pushedRegionEnd);
\r
1268 this.pushedRegionStart = -1;
\r
1269 this.pushedRegionEnd = -1;
\r