1.1 --- a/freemarkerdor/pom.xml Sat Sep 19 12:51:50 2009 +0200
1.2 +++ b/freemarkerdor/pom.xml Sat Sep 19 14:38:29 2009 +0200
1.3 @@ -10,7 +10,7 @@
1.4 <groupId>org.apidesign</groupId>
1.5 <artifactId>freemarkerdor</artifactId>
1.6 <name>freemarkerdor</name>
1.7 - <version>1.11</version>
1.8 + <version>1.15</version>
1.9 <url>http://maven.apache.org</url>
1.10 <dependencies>
1.11 <dependency>
2.1 --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Sat Sep 19 12:51:50 2009 +0200
2.2 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Sat Sep 19 14:38:29 2009 +0200
2.3 @@ -140,20 +140,34 @@
2.4 }
2.5
2.6 private Viewable board(String id) {
2.7 - return board(id, "");
2.8 + return board(id, "", null);
2.9 }
2.10 @GET
2.11 @Path("games/{id}/")
2.12 @Produces(MediaType.TEXT_HTML)
2.13 - public Viewable board(@PathParam("id") String id, @QueryParam("format") @DefaultValue("") String format) {
2.14 - return board(id, null, format);
2.15 + public Viewable board(
2.16 + @PathParam("id") String id,
2.17 + @QueryParam("format") @DefaultValue("") String format,
2.18 + @QueryParam("move") @DefaultValue("-1") String move
2.19 + ) {
2.20 + return board(id, null, format, move);
2.21 }
2.22 - private Viewable board(@PathParam("id") String id, String msg, String format) {
2.23 + private Viewable board(@PathParam("id") String id, String msg, String format, String m) {
2.24 Viewable v = checkLogin();
2.25 if (v != null) {
2.26 return v;
2.27 }
2.28 - Document doc = base.path("games").path(id).accept(MediaType.TEXT_XML).get(Document.class);
2.29 + int move;
2.30 + try {
2.31 + move = Integer.parseInt(m);
2.32 + } catch (NumberFormatException ex) {
2.33 + move = -1;
2.34 + }
2.35 + WebResource url = base.path("games").path(id);
2.36 + if (move >= 0) {
2.37 + url = url.queryParam("move", "" + move);
2.38 + }
2.39 + Document doc = url.accept(MediaType.TEXT_XML).get(Document.class);
2.40 Board b;
2.41 try {
2.42 b = Board.valueOf(doc.getElementsByTagName("board").item(0).getTextContent());
2.43 @@ -196,7 +210,7 @@
2.44 return board(id);
2.45 }
2.46 } catch (UniformInterfaceException ex) {
2.47 - return board(id, "WRONG_MOVE");
2.48 + return board(id, "WRONG_MOVE", "-1");
2.49 }
2.50 return board(id);
2.51 }
3.1 --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle.properties Sat Sep 19 12:51:50 2009 +0200
3.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle.properties Sat Sep 19 14:38:29 2009 +0200
3.3 @@ -24,8 +24,14 @@
3.4 WHITE=White
3.5 BLACK=Black
3.6
3.7 -BOARD_IMAGE=Image
3.8 -BOARD_TEXT=Text View
3.9 +NEXT=Next
3.10 +PREVIOUS=Prev
3.11 +LATEST=Last
3.12 +
3.13 +BOARD_VIEW=View:
3.14 +BOARD_IMAGE=Large
3.15 +BOARD_SMALL=Small
3.16 +BOARD_TEXT=Text
3.17
3.18 players={0} vs. {1}
3.19 PLACE=Place!
4.1 --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle_cs.properties Sat Sep 19 12:51:50 2009 +0200
4.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle_cs.properties Sat Sep 19 14:38:29 2009 +0200
4.3 @@ -33,8 +33,18 @@
4.4 432000#{4}-ti dny\
4.5 }
4.6
4.7 -BOARD_IMAGE=Grafick\u00FD pohled
4.8 -BOARD_TEXT=Textov\u00FD pohled
4.9 +NEXT=Dal\u0161\u00ED
4.10 +PREVIOUS=P\u0159edchoz\u00ED
4.11 +LATEST=Posledn\u00ED
4.12 +
4.13 +NEXT=Dal\u0161\u00ED
4.14 +PREVIOUS=P\u0159edchoz\u00ED
4.15 +LATEST=Posledn\u00ED
4.16 +
4.17 +BOARD_VIEW=Pohled:
4.18 +BOARD_IMAGE=Obrovsk\u00FD
4.19 +BOARD_SMALL=Drobn\u00FD
4.20 +BOARD_TEXT=Textov\u00FD
4.21
4.22 players={0} proti {1}
4.23 PLACE=Um\u00EDstit
5.1 --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt Sat Sep 19 12:51:50 2009 +0200
5.2 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt Sat Sep 19 14:38:29 2009 +0200
5.3 @@ -29,12 +29,24 @@
5.4
5.5
5.6 <p>
5.7 + <b>${bundle.MOVENUMBER}: </b> ${(doc.game.@currentMove?number / 2 + 1)?string("0")}<br>
5.8 <b>${bundle.WHITE}:</b> <@status doc.game.id.@white/> ${bundle("FENCES_LEFT", board.players[0].fences)}<br>
5.9 <b>${bundle.BLACK}:</b> <@status doc.game.id.@black/> ${bundle("FENCES_LEFT", board.players[1].fences)}<br>
5.10 </p>
5.11
5.12 <p>
5.13 <a href="/">${bundle.ROOT}</a>
5.14 + <#if (doc.game.@currentMove?number > 0)>
5.15 + <a href="/games/${doc.game.id.@id}?move=${doc.game.@currentMove?number - 1}">${bundle.PREVIOUS}</a>
5.16 + <#else>
5.17 + ${bundle.PREVIOUS}
5.18 + </#if>
5.19 + <a href="/games/${doc.game.id.@id}"">${bundle.LATEST}</a>
5.20 + <#if (doc.game.@currentMove?number < doc.game.moves.*?size)>
5.21 + <a href="/games/${doc.game.id.@id}?move=${doc.game.@currentMove?number + 1}">${bundle.NEXT}</a>
5.22 + <#else>
5.23 + ${bundle.NEXT}
5.24 + </#if>
5.25 </p>
5.26
5.27 <#if message?? >
5.28 @@ -99,20 +111,38 @@
5.29 <input type="submit" value="${bundle.RESIGN}" />
5.30 </form>
5.31 </#if>
5.32 -
5.33 + <p>
5.34 + ${bundle.BOARD_VIEW}
5.35 <#if format?? && format = "text">
5.36 <pre>${doc.game.board}</pre>
5.37 + <a href="/games/${doc.game.id.@id}?format=small">${bundle.BOARD_SMALL}</a>
5.38 <a href="/games/${doc.game.id.@id}?format=image">${bundle.BOARD_IMAGE}</a>
5.39 + ${bundle.BOARD_TEXT}
5.40 + <#elseif format?? && format = "small">
5.41 + <p>
5.42 + <img src="/api/games/${doc.game.id.@id}?fieldSize=20<#if doc.game.@currentMove??>&move=${doc.game.@currentMove}</#if>" alt="${bundle.BOARD_TEXT}">
5.43 + </p>
5.44 + ${bundle.BOARD_SMALL}
5.45 + <a href="/games/${doc.game.id.@id}?format=image">${bundle.BOARD_IMAGE}</a>
5.46 + <a href="/games/${doc.game.id.@id}?format=text">${bundle.BOARD_TEXT}</a>
5.47 <#else>
5.48 <p>
5.49 - <img src="/api/games/${doc.game.id.@id}" alt="text">
5.50 + <img src="/api/games/${doc.game.id.@id}<#if doc.game.@currentMove??>?move=${doc.game.@currentMove}</#if>" alt="${bundle.BOARD_TEXT}">
5.51 </p>
5.52 + <a href="/games/${doc.game.id.@id}?format=small">${bundle.BOARD_SMALL}</a>
5.53 + ${bundle.BOARD_IMAGE}
5.54 <a href="/games/${doc.game.id.@id}?format=text">${bundle.BOARD_TEXT}</a>
5.55 -
5.56 </#if>
5.57
5.58 + <#macro printMove item>
5.59 + <#if item.@index = doc.game.@currentMove>
5.60 + <b>${item.@move}</b>
5.61 + <#else>
5.62 + <a href="/games/${doc.game.id.@id}?move=${item.@index}">${item.@move}</a>
5.63 + </#if>
5.64 + </#macro>
5.65
5.66 - <h3>${bundle.MOVES}</h3>
5.67 + <h3><a href="/games/${doc.game.id.@id}?move=0">${bundle.MOVES}</a></h3>
5.68
5.69 <table border="0">
5.70 <thead>
5.71 @@ -125,11 +155,12 @@
5.72 <tbody>
5.73 <#assign index = 0>
5.74 <#list doc.game.moves.* as item>
5.75 +
5.76 <#if item.@index?number % 2 = 1>
5.77 <#assign index = index + 1>
5.78 - <tr><td>${index}</td><td>${item.@move}</td>
5.79 + <tr><td>${index}</td><td><@printMove item/></td>
5.80 <#else>
5.81 - <td>${item.@move}</td></tr>
5.82 + <td><@printMove item/></td></tr>
5.83 </#if>
5.84 </#list>
5.85 </tbody>
6.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java Sat Sep 19 12:51:50 2009 +0200
6.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java Sat Sep 19 14:38:29 2009 +0200
6.3 @@ -56,6 +56,7 @@
6.4 @XmlElement
6.5 @XmlJavaTypeAdapter(MoveAdapter.class)
6.6 private List<Move> moves;
6.7 + private Integer move;
6.8
6.9 Game() {
6.10 }
6.11 @@ -115,6 +116,35 @@
6.12 return moves;
6.13 }
6.14
6.15 + @XmlAttribute
6.16 + public int getCurrentMove() {
6.17 + return move == null ? getMoves().size() : move;
6.18 + }
6.19 +
6.20 + public Game snapshot(int move) throws IllegalPositionException {
6.21 + Board b = Board.empty();
6.22 + int cnt = 0;
6.23 + for (Move m : getMoves()) {
6.24 + if (move-- <= 0) {
6.25 + break;
6.26 + }
6.27 + b = b.apply(m);
6.28 + cnt++;
6.29 + }
6.30 +
6.31 + Game g = new Game(
6.32 + new GameId(
6.33 + id.getId(), id.getWhite(), id.getBlack(),
6.34 + new Date(id.getStarted()), new Date(id.getModified()),
6.35 + GameStatus.history
6.36 + )
6.37 + );
6.38 + g.board = b;
6.39 + g.move = cnt;
6.40 + g.moves = new ArrayList<Move>(getMoves());
6.41 + return g;
6.42 + }
6.43 +
6.44 @XmlAccessorType(XmlAccessType.FIELD)
6.45 private static final class MoveTmp {
6.46 @XmlAttribute
7.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/GameStatus.java Sat Sep 19 12:51:50 2009 +0200
7.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/GameStatus.java Sat Sep 19 14:38:29 2009 +0200
7.3 @@ -36,7 +36,8 @@
7.4 whiteMove,
7.5 blackMove,
7.6 whiteWon,
7.7 - blackWon;
7.8 + blackWon,
7.9 + history;
7.10
7.11 /** Creates appropriate status of the game based on the state
7.12 * on the board.
8.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/BoardImage.java Sat Sep 19 12:51:50 2009 +0200
8.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/BoardImage.java Sat Sep 19 14:38:29 2009 +0200
8.3 @@ -40,13 +40,7 @@
8.4 * @author Jaroslav Tulach <jtulach@netbeans.org>
8.5 */
8.6 final class BoardImage {
8.7 -
8.8 -
8.9 - public static Image draw(Board b) {
8.10 - return draw(b, 50);
8.11 - }
8.12 -
8.13 - private static Image draw(Board b, int fieldSize) {
8.14 + static Image draw(Board b, int fieldSize) {
8.15 int fifth = fieldSize / 10;
8.16
8.17 BufferedImage img = new BufferedImage(fieldSize * 9, fieldSize * 9, BufferedImage.TYPE_INT_ARGB);
9.1 --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java Sat Sep 19 12:51:50 2009 +0200
9.2 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/resources/Games.java Sat Sep 19 14:38:29 2009 +0200
9.3 @@ -43,6 +43,7 @@
9.4 import java.util.List;
9.5 import java.util.logging.Level;
9.6 import java.util.logging.Logger;
9.7 +import javax.ws.rs.DefaultValue;
9.8 import javax.ws.rs.GET;
9.9 import javax.ws.rs.POST;
9.10 import javax.ws.rs.PUT;
9.11 @@ -121,23 +122,26 @@
9.12 @GET
9.13 @Path("{id}")
9.14 @Produces("image/png")
9.15 - public Image getBoardImage(@PathParam("id") String id) {
9.16 - Game g = findGame(id);
9.17 + public Image getBoardImage(
9.18 + @PathParam("id") String id,
9.19 + @QueryParam("fieldSize") @DefaultValue("50") int fieldSize,
9.20 + @QueryParam("move") @DefaultValue("-1") int move
9.21 + ) {
9.22 + Game g = findGame(id, move);
9.23 if (g == null) {
9.24 throw new IllegalArgumentException("Unknown game " + id);
9.25 }
9.26 - return BoardImage.draw(g.getBoard());
9.27 + return BoardImage.draw(g.getBoard(), fieldSize);
9.28 }
9.29
9.30 @GET
9.31 @Path("{id}")
9.32 @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML })
9.33 - public Game getBoardInfo(@PathParam("id") String id) {
9.34 - Game g = findGame(id);
9.35 - if (g == null) {
9.36 - throw new IllegalArgumentException("Unknown game " + id);
9.37 - }
9.38 - return g;
9.39 + public Game getBoardInfo(
9.40 + @PathParam("id") String id,
9.41 + @QueryParam("move") @DefaultValue("-1") int move
9.42 + ) {
9.43 + return findGame(id, move);
9.44 }
9.45
9.46 @PUT
9.47 @@ -194,6 +198,18 @@
9.48 }
9.49 return null;
9.50 }
9.51 + private Game findGame(String id, int move) {
9.52 + Game g = findGame(id);
9.53 + if (g == null) {
9.54 + throw new IllegalArgumentException("Unknown game " + id);
9.55 + }
9.56 + try {
9.57 + return move == -1 ? g : g.snapshot(move);
9.58 + } catch (IllegalPositionException ex) {
9.59 + Logger.getLogger(Games.class.getName()).log(Level.SEVERE, null, ex);
9.60 + return null;
9.61 + }
9.62 + }
9.63
9.64 private Game readGame(File f) throws IOException {
9.65 BufferedReader r = new BufferedReader(new FileReader(f));
10.1 --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/GamesTest.java Sat Sep 19 12:51:50 2009 +0200
10.2 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/GamesTest.java Sat Sep 19 14:38:29 2009 +0200
10.3 @@ -82,7 +82,7 @@
10.4 Thread.sleep(1000);
10.5
10.6 Games games = new Games(dir, new Quoridor());
10.7 - Game g = games.getBoardInfo("x");
10.8 + Game g = games.getBoardInfo("x", -1);
10.9 assertNotNull("Game found", g);
10.10 assertNotNull("Board found", g.getBoard());
10.11 assertEquals("List of moves has two", 2, g.getMoves().size());
11.1 --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Sat Sep 19 12:51:50 2009 +0200
11.2 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Sat Sep 19 14:38:29 2009 +0200
11.3 @@ -161,6 +161,11 @@
11.4 if (s2.getModified() <= now) {
11.5 fail("The game is newly modified");
11.6 }
11.7 + Game snapshot = webResource.path("games/" + s.getId()).queryParam("move", "0").accept(MediaType.TEXT_XML).get(Game.class);
11.8 + assertEquals("All moves listed", 2, snapshot.getMoves().size());
11.9 + assertEquals("Current move", 0, snapshot.getCurrentMove());
11.10 + assertEquals("Position 0", 0, snapshot.getBoard().getPlayers().get(0).getRow());
11.11 + assertEquals("Position 8", 8, snapshot.getBoard().getPlayers().get(1).getRow());
11.12
11.13 File game = new File(new File(dir, "games"), s2.getId());
11.14 assertTrue("File for game exists", game.exists());