■ ルール定義
ブログにしては、ちょっと多めの行数だけど一行当たりの文字数が少ないので、記述量は全然大した事無い(以下、prettyprint が固まり気味なので小分けする)。
package tictactoe import tictactoe.Cell; import tictactoe.Row; import tictactoe.Game; import tictactoe.Game.State; rule "初期化" when game: Game(state == State.INITIALIZED) then for (Row row: game.getRows()) insert(row); for (Cell[] row: game.getBoard()) { for (Cell cell: row) insert(cell); } modify(game) { setState(State.START); } end rule "開始" when game: Game(state == State.START) then modify(game) { start(); } end
rule "マシン側戦略1" @Strategy(Win) salience 70 when game: Game(state == State.MACHINE_TURN) row: Row($cells: cells) c1: Cell(state == Cell.MACHINE) from $cells c2: Cell(state == Cell.MACHINE) from $cells c3: Cell(state == Cell.FREE) from $cells eval (c1 != c2) then modify(c3) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end rule "マシン側戦略2" @Strategy(Block) salience 60 when game: Game(state == State.MACHINE_TURN) row: Row($cells: cells) c1: Cell(state == Cell.USER) from $cells c2: Cell(state == Cell.USER) from $cells c3: Cell(state == Cell.FREE) from $cells eval (c1 != c2) then modify(c3) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end
rule "マシン側戦略3" @Strategy(Fork) salience 50 when game: Game(state == State.MACHINE_TURN) c: Cell(state == Cell.FREE) mc1: Cell(state == Cell.MACHINE) mc2: Cell(state == Cell.MACHINE) fc1: Cell(state == Cell.FREE) fc2: Cell(state == Cell.FREE) r1: Row(cells contains c, cells contains mc1, cells contains fc1) r2: Row(cells contains c, cells contains mc2, cells contains fc2) eval (r1 != r2 && c != fc1 && c != fc2) then modify(c) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end rule "マシン側戦略4" @Strategy(Block Opponent^s Fork) salience 40 when game: Game(state == State.MACHINE_TURN) c: Cell(state == Cell.FREE) mc1: Cell(state == Cell.USER) mc2: Cell(state == Cell.USER) fc1: Cell(state == Cell.FREE) fc2: Cell(state == Cell.FREE) r1: Row(cells contains c, cells contains mc1, cells contains fc1) r2: Row(cells contains c, cells contains mc2, cells contains fc2) eval (r1 != r2 && c != fc1 && c != fc2) then modify(c) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end
rule "マシン側戦略5" @Strategy(Center) salience 30 when game: Game(state == State.MACHINE_TURN) c: Cell(state == Cell.FREE, x == 1, y == 1) then modify(c) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end rule "マシン側戦略6" @Strategy(Opposite Corner) salience 20 when game: Game(state == State.MACHINE_TURN) uc: Cell(state == Cell.USER, $ux: x, $uy: y) mc: Cell(state == Cell.FREE, $mx: x, $my: y) eval (($ux==0 && $mx==2 || $ux==2 && $mx==0) && ($uy==0 && $my==2 || $uy==2 && $my==0)) then modify(mc) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end
rule "マシン側戦略7" @Strategy(Empty Corner) salience 10 when game: Game(state == State.MACHINE_TURN) c: Cell(state == Cell.FREE, x != 1, y != 1) then modify(c) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end rule "マシン側戦略8" @Strategy(Empty Side) when game: Game(state == State.MACHINE_TURN) c: Cell(state == Cell.FREE) then modify(c) { setState(Cell.MACHINE); } modify(game) { setState(State.JUDGING); } end
rule "ユーザの番" when game: Game(state == State.USER_TURN) then update(game.play()); modify(game) { setState(State.JUDGING); } end rule "決着" salience 20 when game: Game(state == State.JUDGING) row: Row($cells: cells) c1: Cell($s: state, state != Cell.FREE) from $cells c2: Cell(state == $s) from $cells c3: Cell(state == $s) from $cells eval (c1 != c2 && c2 != c3 && c3 != c1) then System.out.printf("== %s won!%n", (Cell.MACHINE == $s) ? "machine": "user"); modify(game) { setState(State.FINISHED); } end rule "引き分け" salience 10 when game: Game(state == State.JUDGING) not Cell(state == Cell.FREE) then System.out.println("== draw!"); modify(game) { setState(State.FINISHED); } end rule "続行" when game: Game(state == State.JUDGING) then modify(game) { change(); } end(割とすっきり書けたと思うが、いかにも Java なコードがまだまだ少なくないので、その辺りもう少し工夫したい。)
■ Java コード
ルール定義を見れば察しが付くようなコードばかりなので面白く無いので、以下のエベントリスナの定義を含む main() だけ抜粋。
public static final void main(String[] args) throws Exception { KnowledgeBase kbase = readKnowledgeBase(); StatefulKnowledgeSession ksession = kbase.newStatefulKnowledgeSession(); final Game game = new Game(); ksession.insert(game); ksession.addEventListener(new DefaultAgendaEventListener() { public void afterActivationFired(AfterActivationFiredEvent event) { Rule rule = event.getActivation().getRule(); String strategy = rule.getMetaAttribute("Strategy"); if (null != strategy) { System.out.printf("この辺りをもう一工夫すれば、ルール定義 と Java コードをもっときれいに分離できそうな気がする。strategy = %s%n", strategy); } else if (Arrays.asList(new String[]{ "続行", "引き分け", "決着"}).contains(rule.getName())) { game.printBoard(); } } }); ksession.fireAllRules(); }
0 件のコメント:
コメントを投稿