# HG changeset patch # User Jaroslav Tulach # Date 1262900057 -3600 # Node ID 4b78d4f028b3f331ab2b397978e2199c65af3a68 # Parent 2f8672ac9f1a212cda033d89f83644deb37fbe56 Initial version of statistics and ELO rating. Donated by Martin Rexa diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/pom.xml --- a/freemarkerdor/pom.xml Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/pom.xml Thu Jan 07 22:34:17 2010 +0100 @@ -71,6 +71,12 @@ freemarker 2.3.8 + + ${project.groupId} + statistics + 1.0 + test + @@ -126,3 +132,4 @@ + diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/UI.java Thu Jan 07 22:34:17 2010 +0100 @@ -87,6 +87,7 @@ version = p.getProperty("version", "unknown"); // NOI18N } private static WebResource base; + private static WebResource stat; @Context private HttpHeaders headers; @@ -163,6 +164,7 @@ } String txt = wr.accept(MediaType.TEXT_PLAIN).get(String.class); Board b = Board.valueOf(txt); +// Board b = new Board(txt); ResponseBuilder resp = Response.ok(); CacheControl cc = new CacheControl(); cc.setNoCache(true); @@ -220,13 +222,25 @@ Document doc = url.accept(MediaType.TEXT_XML).get(Document.class); Board b; + String t = doc.getElementsByTagName("board").item(0).getTextContent(); try { b = Board.valueOf(doc.getElementsByTagName("board").item(0).getTextContent()); - } catch (IllegalPositionException ex) { + } catch (Exception ex) { +// b = new Board(t); +// } catch (IllegalStateException ex) { Exceptions.printStackTrace(ex); b = Board.empty(); } - v = viewable("game.fmt", doc, "message", msg, "format", format, "board", b); + String bCode = null; + try{ + bCode = stat.path("openings").path(Board.board2HashCode(b)+".check").queryParam("loginID", user.getId()).accept(MediaType.TEXT_PLAIN).get(String.class); + }catch(Exception e){ + bCode = null; + } + if(bCode == null || "".equals(bCode)) + v = viewable("game.fmt", doc, "message", msg, "format", format, "board", b,"textPicture",b.boardToPicture()); + else + v = viewable("game.fmt", doc, "message", msg, "format", format, "board", b,"textPicture",b.boardToPicture(),"bCode", bCode); return resp.entity(v).build(); } @@ -346,7 +360,72 @@ return welcome(10); } + + @GET + @Path("elo") + @Produces(MediaType.TEXT_HTML) + public Response getEloList(){ + Viewable v = checkLogin(); + if (v != null) { + return Response.status(Response.Status.FORBIDDEN).entity(v).build(); + } + final Document got = stat.path("elo").path("list").accept(MediaType.TEXT_XML).get(Document.class); + return Response.ok(viewable("elo.fmt", got)).build(); + } + @GET + @Path("openings") + @Produces(MediaType.TEXT_HTML) + public Response getOpeningRoot(){ + return getOpeningNode("ROOT"); + } + + @GET + @Path("openings/{code}") + @Produces(MediaType.TEXT_HTML) + public Response getOpeningNode(@PathParam("code") String code){ + Viewable v = checkLogin(); + if (v != null) { + return Response.status(Response.Status.FORBIDDEN).entity(v).build(); + } + final Document got = stat.path("openings").path(code).queryParam("loginID", user.getId()).accept(MediaType.TEXT_XML).get(Document.class); + Board b; + try { + b = Board.valueOf(got.getElementsByTagName("nodeCode").item(0).getTextContent()); + } catch (Exception ex) { + Exceptions.printStackTrace(ex); + b = Board.empty(); + } + return Response.ok(viewable("openings.fmt", got, "whitefences",b.getPlayers().get(0).getFences(),"blackfences",b.getPlayers().get(1).getFences())).build(); + } + + @GET + @Path("openings/{code}/{status}") + @Produces(MediaType.TEXT_HTML) + public Response getOpeningNodeGames(@PathParam("code") String code, @PathParam("status") String status){ + Viewable v = checkLogin(); + if (v != null) { + return Response.status(Response.Status.FORBIDDEN).entity(v).build(); + } + final Document got = stat.path("openings").path(code).path(status).queryParam("loginID", user.getId()).accept(MediaType.TEXT_XML).get(Document.class); + return Response.ok(viewable("opening_games.fmt", got,"code",code,"color",status)).build(); + } + + @GET + @Path("openings/{code}.png") + @Produces("image/png") + public Response getOpeningBoardImage( + @PathParam("code") String code, + @QueryParam("fieldSize") @DefaultValue("40") int fieldSize + ) throws IllegalPositionException { + Board b = new Board(code); + ResponseBuilder resp = Response.ok(); + CacheControl cc = new CacheControl(); + cc.setNoCache(true); + resp.cacheControl(cc); + return resp.entity(BoardImage.draw(b, fieldSize)).build(); + } + // // start the server // @@ -376,12 +455,14 @@ static Callable startServers(int port, String remoteAPI) throws Exception { Client client = new Client(); + Client client1 = new Client(); final HttpServer apiServer; if (remoteAPI == null) { throw new IllegalArgumentException("Provide URL to API server"); // NOI18N } else { base = client.resource(new URI(remoteAPI)); + stat = client1.resource(new URI("http://localhost:9444")); apiServer = null; } diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/W3CDocumentReader.java --- a/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/W3CDocumentReader.java Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/java/cz/xelfi/quoridor/freemarkerdor/W3CDocumentReader.java Thu Jan 07 22:34:17 2010 +0100 @@ -1,6 +1,27 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2009 Jaroslav Tulach */ package cz.xelfi.quoridor.freemarkerdor; diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle.properties --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle.properties Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle.properties Thu Jan 07 22:34:17 2010 +0100 @@ -77,3 +77,10 @@ cs=\u010Cesky LOCALE=en CHANGE_LANGUAGE=Change! + +ELO_LIST=Elo rating +ELO=Elo +GAMES=Games +OPENINGS=Openings +WHITE_WON=White won +BLACK_WON=Black won diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle_cs.properties --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle_cs.properties Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/Bundle_cs.properties Thu Jan 07 22:34:17 2010 +0100 @@ -89,3 +89,10 @@ LANGUAGE=Jazyk: CHANGE_LANGUAGE=Zm\u011Bnit! LOCALE=cs + +ELO_LIST=Elo rating +ELO=Elo +GAMES=Hry +OPENINGS=Zah\u00E1jen\u00ED +WHITE_WON=B\u00EDl\u00FD vyhr\u00E1l +BLACK_WON=\u010Cern\u00FD vyhr\u00E1l diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/elo.fmt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/elo.fmt Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,43 @@ + + + + ${bundle.ELO_LIST} + + + +

${bundle.TITLE_PLAIN}

+

${bundle.ELO_LIST}

+ + + + + + + + + + + <#assign cElo = 10000> + <#assign index = 0> + <#assign cIndex = index> + <#list doc.eloList.elolist.* as item> + + <#assign index = index + 1> + <#if cElo = item.@elo?number> + <#else> + <#assign cIndex = index> + + <#assign cElo = item.@elo?number> + + + + + + + + + + +
#${bundle.NAME}${bundle.ELO}${bundle.GAMES}
${cIndex}${item.@player}${item.@elo?number}${item.@games}
+ + \ No newline at end of file diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/game.fmt Thu Jan 07 22:34:17 2010 +0100 @@ -50,6 +50,7 @@ if (dir == 'W') r.x = -1; return r; } + <#if board.currentPlayer??> function paintPlayer() { var fifth = fieldSize / 5; var m1 = deltas(document.getElementById("pdir1").value.charAt(0)); @@ -72,7 +73,11 @@ var playerPos = { x: ${board.currentPlayer.column}, y: ${board.currentPlayer.row} - }; + }; + <#else> + function paintPlayer() { + } + @@ -177,7 +182,7 @@

<#if format?? && format = "text"> -

${doc.game.board}
+
${textPicture}
${bundle.BOARD_VIEW} ${bundle.BOARD_SMALL} ${bundle.BOARD_IMAGE} @@ -227,7 +232,9 @@ ${item.@move} - + <#if (bCode??) > +

${bundle.OPENINGS}

+

${bundle.MOVES}

diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt --- a/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt Fri Jan 01 20:53:17 2010 +0100 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/index.fmt Thu Jan 07 22:34:17 2010 +0100 @@ -167,6 +167,8 @@

+
${bundle.ELO_LIST}
+
${bundle.OPENINGS}
${bundle.OPTIONS}
diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/opening_games.fmt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/opening_games.fmt Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,36 @@ + + + + ${bundle.OPENINGS} - ${bundle.GAMES} + + + +

${bundle.TITLE_PLAIN}

+

${bundle.OPENINGS} - ${bundle.GAMES}

+ + <#macro before t> + <#assign seconds = (t / 1000)?long/> + <#assign minutes= (seconds / 60)?long/> + <#assign hours= (minutes / 60)?long/> + <#assign days= (hours / 24)?long/> + + ${bundle("LastMove", t?int, seconds?int, minutes?int, hours?int, days?int)} + + <#macro game game> + ${bundle("gameWhiteBlack", game.@white?string, game.@black?string)} + <@before (now - game.@modified?number)?long/> + <#if game.@comments?number != 0> + ${bundle("comments", game.@comments?number)} + + + +
    + <#list doc.gameIds.* as g> +
  1. + <@game g/> +
  2. + +
+

${bundle.OPENINGS}

+ + \ No newline at end of file diff -r 2f8672ac9f1a -r 4b78d4f028b3 freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/openings.fmt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freemarkerdor/src/main/resources/cz/xelfi/quoridor/freemarkerdor/UI/openings.fmt Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,97 @@ + + + + ${bundle.OPENINGS} + + + +

${bundle.TITLE_PLAIN}

+

${bundle.OPENINGS}

+

+ ${bundle.WHITE}: ${bundle("FENCES_LEFT", whitefences?number)}
+ ${bundle.BLACK}: ${bundle("FENCES_LEFT", blackfences?number)}
+

+
+ ${bundle.BOARD_TEXT} +
+
+
+ + <#macro move item> + ${item.move} + + <#macro games cnt gId status code> + <#if (cnt?number = 0)> + ${cnt?number} + + <#if (cnt?number = 1)> + ${cnt?number} + + <#if (cnt?number > 1)> + ${cnt?number} + + + <#if (doc.openingNodeView.children.*?size > 0)> +
+ + + + + + + + + <#list doc.openingNodeView.children.* as item> + + + + + + + +
${bundle.MOVENUMBER}${bundle.WHITE_WON}${bundle.BLACK_WON}
<@move item/><@games item.whiteWon item.whiteGame 'white' item.code/><@games item.blackWon item.blackGame 'black' item.code/>
+ + + <#macro before t> + <#assign seconds = (t / 1000)?long/> + <#assign minutes= (seconds / 60)?long/> + <#assign hours= (minutes / 60)?long/> + <#assign days= (hours / 24)?long/> + + ${bundle("LastMove", t?int, seconds?int, minutes?int, hours?int, days?int)} + + <#macro game game> + ${bundle("gameWhiteBlack", game.@white?string, game.@black?string)} + <@before (now - game.@modified?number)?long/> + <#if game.@status = "whiteWon"> + ${bundle.WHITE_WON} + + <#if game.@status = "blackWon"> + ${bundle.BLACK_WON} + + <#if game.@comments?number != 0> + ${bundle("comments", game.@comments?number)} + + + + <#if (doc.openingNodeView.@whiteCount?number + doc.openingNodeView.@blackCount?number > 0)> +

${bundle.GAMES}

+
    + <#list doc.openingNodeView.whiteGames.* as g> +
  1. + <@game g/> +
  2. + + <#list doc.openingNodeView.blackGames.* as g> +
  3. + <@game g/> +
  4. + +
+ + + \ No newline at end of file diff -r 2f8672ac9f1a -r 4b78d4f028b3 pom.xml --- a/pom.xml Fri Jan 01 20:53:17 2010 +0100 +++ b/pom.xml Thu Jan 07 22:34:17 2010 +0100 @@ -37,10 +37,11 @@ quoridor visidor webidor + statistics freemarkerdor emailer Quoridor related projects Master project that agregates all quoridor related functionality. - \ No newline at end of file + diff -r 2f8672ac9f1a -r 4b78d4f028b3 quoridor/src/main/java/cz/xelfi/quoridor/Board.java --- a/quoridor/src/main/java/cz/xelfi/quoridor/Board.java Fri Jan 01 20:53:17 2010 +0100 +++ b/quoridor/src/main/java/cz/xelfi/quoridor/Board.java Thu Jan 07 22:34:17 2010 +0100 @@ -42,6 +42,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -352,7 +353,11 @@ * @return board object, if the string can be read * @throws IllegalPositionException if the string does not represent the board */ - public static Board valueOf(String board) throws IllegalPositionException { + public static Board valueOf(String board) { + return new Board(board); + } + + public static Board picture2board(String board) throws IllegalPositionException { try { return read(new StringReader(board)); } catch (IOException ex) { @@ -697,6 +702,10 @@ */ @Override public String toString() { + return Board.board2HashCode(this); + } + + public String boardToPicture() { StringWriter w = new StringWriter(); try { write(w); @@ -863,4 +872,91 @@ return 17 * y + x; } + public Board(String hashCode) throws IllegalStateException{ + this.fences = new HashSet(); + if((hashCode != null) && (hashCode.length() > 6)){ + char[]c = hashCode.toCharArray(); + this.players = Collections.unmodifiableList (Arrays.asList (new Player[] { + new Player ((c[0]-'A')*2, (c[1]-'0')*2, c[2]-'a', Player.Direction.NORTH), + new Player ((c[3]-'A')*2, (c[4]-'0')*2, c[5]-'a', Player.Direction.SOUTH), + })); + if(c[6]=='w'){ + this.turn = 0; + this.winner = null; + }else if(c[6]=='b'){ + this.turn = 1; + this.winner = null; + }else if(c[6]=='W'){ + this.turn = 0; + this.winner = this.players.get(0); + }else if(c[6]=='B'){ + this.turn = 1; + this.winner = this.players.get(1); + }else{ + this.turn = 0; + this.winner = null; + } + for(int i=7; i 64){ + o = Fence.Orientation.VERTICAL; + f -= 64; + } + fences.add(new Fence((f/8)*2+1, (f%8)*2+1,o)); + } + }else{ + this.players = Collections.unmodifiableList (Arrays.asList (new Player[] { + new Player (8,0,10,Player.Direction.NORTH), + new Player (8,16,10,Player.Direction.SOUTH), + })); + this.winner = null; + this.turn = 0; + } + try { + this.occupied = computeOccupied (players, fences); + } catch (IllegalPositionException ex) { + throw new IllegalStateException (ex.getMessage ()); + } + } + + public static String board2HashCode(Board b){ + StringBuilder sb = new StringBuilder(); + for(Player p: b.getPlayers()){ + sb.append((char)(p.getColumn() + 'A')); + sb.append((char)(p.getRow() + '0')); + sb.append((char)(p.getFences() + 'a')); + } + Player winner = b.getWinner(); + if(winner == null){ + if(b.players.indexOf(b.getCurrentPlayer())==0) + sb.append('w'); + else if(b.players.indexOf(b.getCurrentPlayer())==1) + sb.append('b'); + else + sb.append('n'); + }else{ + if(b.players.indexOf(winner)==0) + sb.append('W'); + else if(b.players.indexOf(winner)==1) + sb.append('B'); + else + sb.append('N'); + } + + TreeSet fences = new TreeSet(); + for(Fence f: b.getFences()){ + int a = (f.getColumn() - 'A')*8 + (f.getRow()-1); + if(f.getOrientation().equals(Fence.Orientation.VERTICAL)) + a+=64; + fences.add(a); + } + for(int f: fences){ + if(f<16) + sb.append('0'); + sb.append(Integer.toHexString(f)); + } + return sb.toString(); + } + } diff -r 2f8672ac9f1a -r 4b78d4f028b3 quoridor/src/main/java/cz/xelfi/quoridor/Move.java --- a/quoridor/src/main/java/cz/xelfi/quoridor/Move.java Fri Jan 01 20:53:17 2010 +0100 +++ b/quoridor/src/main/java/cz/xelfi/quoridor/Move.java Thu Jan 07 22:34:17 2010 +0100 @@ -199,5 +199,26 @@ return hash; } + public Move getMirrorMove(){ + if(fence != null){ + return new Move(new Fence(16-fence.getX(), fence.getY(), fence.getOrientation())); + } + if(direction == null) + return new Move(); + int dirSize = direction.length; + Direction[] mirrorDirection = new Direction[dirSize]; + for(int i = 0; i < dirSize; i++){ + if(direction[i].equals(Direction.NORTH)) + mirrorDirection[i] = Direction.NORTH; + else if(direction[i].equals(Direction.SOUTH)) + mirrorDirection[i] = Direction.SOUTH; + else if(direction[i].equals(Direction.EAST)) + mirrorDirection[i] = Direction.WEST; + else if(direction[i].equals(Direction.WEST)) + mirrorDirection[i] = Direction.EAST; + } + return new Move(mirrorDirection); + } + } diff -r 2f8672ac9f1a -r 4b78d4f028b3 quoridor/src/test/java/cz/xelfi/quoridor/BoardCase.java --- a/quoridor/src/test/java/cz/xelfi/quoridor/BoardCase.java Fri Jan 01 20:53:17 2010 +0100 +++ b/quoridor/src/test/java/cz/xelfi/quoridor/BoardCase.java Thu Jan 07 22:34:17 2010 +0100 @@ -200,6 +200,7 @@ "\n" + " [S] \n"; + b = Board.picture2board(b).toString(); Board begin = Board.valueOf(b); try { diff -r 2f8672ac9f1a -r 4b78d4f028b3 quoridor/src/test/java/cz/xelfi/quoridor/SerializeTest.java --- a/quoridor/src/test/java/cz/xelfi/quoridor/SerializeTest.java Fri Jan 01 20:53:17 2010 +0100 +++ b/quoridor/src/test/java/cz/xelfi/quoridor/SerializeTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -72,7 +72,8 @@ StringWriter w = new StringWriter(); b.write(w); w.close(); - return Board.valueOf(w.toString()); + return Board.picture2board(w.toString()); + //return Board.valueOf(w.toString()); } } diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/all-zip.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/all-zip.xml Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,19 @@ + + + all + + zip + + + + false + lib + + + + + target/statistics-${version}.jar + / + + + diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/pom.xml --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/pom.xml Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,141 @@ + + + 4.0.0 + + all-quoridor + org.apidesign + 1.0 + + org.apidesign + statistics + jar + 1.0 + Game Statistics + http://maven.apache.org + + + maven2-repository.dev.java.net + Java.net Repository for Maven + http://download.java.net/maven/2/ + default + + + maven-repository.dev.java.net + Java.net Maven 1 Repository (legacy) + http://download.java.net/maven/1 + legacy + + + + + + junit + junit + 4.5 + test + + + com.sun.jersey + jersey-core + 1.1.0-ea + + + com.sun.jersey + jersey-server + 1.1.0-ea + + + com.sun.jersey + jersey-json + 1.1.0-ea + jar + + + jaxb-api + javax.xml.bind + + + stax-api + stax + + + + + com.sun.jersey.test.framework + jersey-test-framework + 1.1.0-ea + test + + + org.apidesign + quoridor + 1.0 + jar + + + ${project.groupId} + webidor + 1.11 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + 1.6 + 1.6 + + + + org.codehaus.mojo + exec-maven-plugin + + cz.xelfi.quoridor.statistics.resources.Statistics + + + + maven-assembly-plugin + 2.2-beta-2 + + + create-executable-jar + package + + single + + + + all-zip.xml + + statistics-${version} + + + + + + org.apache.maven.plugins + maven-jar-plugin + + + + true + lib/ + cz.xelfi.quoridor.statistics.resources.Statistics + + + + + + + Server with API for games statistics + + + + + + diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/EloEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/EloEntry.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,82 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import javax.xml.bind.annotation.XmlAttribute; +import java.util.Comparator; +/** + * + * @author Martin Rexa + */ +public class EloEntry { + String player; + double elo; + int games; + + public static final Comparator BEST_FIRST = new BestFirst(); + + EloEntry(){ + super(); + } + + EloEntry(String player, double elo, int games){ + super(); + this.player = player; + this.elo = elo; + this.games = games; + } + + @XmlAttribute + public String getPlayer(){ + return player; + } + + @XmlAttribute + public Double getElo(){ + return elo; + } + + @XmlAttribute + public Integer getGames(){ + return games; + } + + public String toString(){ + return "Player: " + player + ", ELO: " + elo + ", Games: " + games; + } + + private static final class BestFirst implements Comparator { + public int compare(EloEntry e1, EloEntry e2) { + if(e1.elo > e2.elo) + return -1; + else if(e1.elo < e2.elo) + return 1; + else return e1.player.compareTo(e2.player); + } + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/EloList.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/EloList.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,104 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Collections; +import java.util.ArrayList; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +/** + * + * @author Martin Rexa + */ +@XmlRootElement +@XmlAccessorType(XmlAccessType.FIELD) +public class EloList { + static int INITIAL_ELO = 1250; + static int MAX_ELO_DIFF = 400; + static int KVAL_START = 25; + static int KVAL_FOLLOW = 10; + static int KVAL_LIMIT = 30; + + private Map players; + private Map playerGames; + + public EloList () { + players = new HashMap(); + playerGames = new HashMap(); + } + + @XmlElementWrapper(name="elolist") + @XmlElement(name="item") + public List getFinalList(){ + List finalList = new ArrayList(); + for (Map.Entry player : players.entrySet()){ + finalList.add(new EloEntry(player.getKey(), player.getValue(), playerGames.get(player.getKey()))); + } + Collections.sort(finalList, EloEntry.BEST_FIRST); + return finalList; + } + + public EloList putResult(String winner, String looser){ + double wElo = getElo(winner); + double lElo = getElo(looser); + + double eloDiff = wElo - lElo; + if(eloDiff < - MAX_ELO_DIFF) + eloDiff = - MAX_ELO_DIFF; + if(eloDiff > MAX_ELO_DIFF) + eloDiff = MAX_ELO_DIFF; + + double wDiff = Math.round(100 * getKVal(winner) * (1 - (1 / (1 + Math.pow(10, -eloDiff / MAX_ELO_DIFF))))); + wDiff /= 100.0; + double lDiff = Math.round(100 * getKVal(looser) * (0 - (1 / (1 + Math.pow(10, eloDiff / MAX_ELO_DIFF))))); + lDiff /= 100.0; + + players.put(winner, wElo + wDiff); + players.put(looser, lElo + lDiff); + return this; + } + + public double getElo(String player){ + Double elo = players.get(player); + return (elo == null) ? INITIAL_ELO : elo; + } + + private int getKVal(String player){ + Integer games = playerGames.get(player); + int g = (games == null) ? 0 : games; + // Side effect, method should not be called more times for the same game/player + playerGames.put(player, g + 1); + return g < KVAL_LIMIT ? KVAL_START : KVAL_FOLLOW; + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/JAXBContextResolver.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/JAXBContextResolver.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,58 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ +package cz.xelfi.quoridor.statistics; + +import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.api.json.JSONJAXBContext; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import javax.ws.rs.ext.ContextResolver; +import javax.ws.rs.ext.Provider; +import javax.xml.bind.JAXBContext; + +/** + * + * @author Martin Rexa + */ +@Provider +public final class JAXBContextResolver implements ContextResolver { + + private final JAXBContext context; + + private final Set types; + + private final Class[] cTypes = {EloList.class, EloEntry.class, OpeningNodeView.class, OpeningNodeViewEntry.class}; + + public JAXBContextResolver() throws Exception { + this.types = new HashSet(Arrays.asList(cTypes)); + this.context = new JSONJAXBContext(JSONConfiguration.natural().build(), cTypes); + } + + public JAXBContext getContext(Class objectType) { + return (types.contains(objectType)) ? context : null; + } +} \ No newline at end of file diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningNodeView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningNodeView.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,129 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import cz.xelfi.quoridor.webidor.GameId; +import cz.xelfi.quoridor.webidor.GameStatus; +import cz.xelfi.quoridor.Move; +import java.util.Set; +import java.util.HashSet; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.ArrayList; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlElementWrapper; +import javax.xml.bind.annotation.XmlRootElement; +//import javax.xml.bind.annotation.XmlAccessType; +//import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; + +/** + * + * @author Martin Rexa + */ + +@XmlRootElement +//@XmlAccessorType(XmlAccessType.FIELD) +public class OpeningNodeView { + @XmlAttribute + String code; + @XmlElementWrapper(name="whiteGames") + @XmlElement(name="gameId") + List whiteGames; + @XmlElementWrapper(name="blackGames") + @XmlElement(name="gameId") + List blackGames; + Map entries; + boolean empty; + + public OpeningNodeView(){ + } + + public OpeningNodeView(String code){ + this.code = code; + entries = new HashMap(); + whiteGames = new ArrayList(); + blackGames = new ArrayList(); + empty = true; + } + + @XmlElement + public String getNodeCode(){ + return code; + } + + public void processGame(Move m, String code, GameId gId){ + OpeningNodeViewEntry e = entries.get(m); + if(e == null){ + e = new OpeningNodeViewEntry(m,code); + entries.put(m, e); + } + e.processGame(gId); + empty = false; + } + + @XmlElementWrapper(name="children") + @XmlElement(name="item") + public Set getChildren(){ + Set result = new HashSet(); + for(Map.Entry e: entries.entrySet()){ + result.add(e.getValue()); + } + return result; + } + + + public void addFinishedGame(GameId gId){ + if(gId.getStatus().equals(GameStatus.whiteWon)) + whiteGames.add(gId); + if(gId.getStatus().equals(GameStatus.blackWon)) + blackGames.add(gId); + empty = false; + } + + @XmlAttribute + public int getWhiteCount(){ + return whiteGames.size(); + } + + @XmlAttribute + public int getBlackCount(){ + return blackGames.size(); + } + + + @XmlAttribute + public boolean getChildrenNotEmpty(){ + return !entries.isEmpty(); + } + + public boolean isEmpty(){ + return this.empty; + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningNodeViewEntry.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningNodeViewEntry.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,86 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import cz.xelfi.quoridor.Move; +import cz.xelfi.quoridor.webidor.GameId; +import cz.xelfi.quoridor.webidor.GameStatus; +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; + +/** + * + * @author Martin Rexa + */ +@XmlAccessorType(XmlAccessType.FIELD) +public class OpeningNodeViewEntry extends Object{ + String move; + String code; + GameId gameId; + GameId whiteGame; + GameId blackGame; + int whiteWon; + int blackWon; + + public OpeningNodeViewEntry(){ + } + + public OpeningNodeViewEntry(Move m, String code){ + move = m.toString(); + this.code = code; + } + + public void processGame(GameId gId){ + gameId = gId; + if(gId.getStatus().equals(GameStatus.whiteWon)){ + whiteWon++; + whiteGame = gId; + } + if(gId.getStatus().equals(GameStatus.blackWon)){ + blackWon++; + blackGame = gId; + } + } + + @Override + public boolean equals(Object obj){ + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final OpeningNodeViewEntry other = (OpeningNodeViewEntry) obj; + return this.move.equals(other.move); + } + + @Override + public String toString(){ + return move+": "+whiteWon+"/"+blackWon; + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningTree.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,107 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import cz.xelfi.quoridor.Board; +import cz.xelfi.quoridor.Move; +import cz.xelfi.quoridor.webidor.Game; +import cz.xelfi.quoridor.webidor.CommentedMove; +import cz.xelfi.quoridor.IllegalPositionException; +import java.util.Map; +import java.util.HashMap; + +/** + * + * @author Martin Rexa + */ +public class OpeningTree { + Map nodes = new HashMap(); + OpeningTreeNode root; + + public OpeningTree(){ + root = new OpeningTreeNode("ROOT"); + nodes.put("ROOT", root); + } + + public OpeningTreeNode getRoot(){ + return root; + } + + public OpeningTreeNode getNode(String hashCode){ + return nodes.get(hashCode); + } + + public void processGame(Game game) throws IllegalPositionException{ + OpeningTreeNode node = root; + OpeningTreeNode parentNode; + OpeningTreeNode mirrorNode = root; + OpeningTreeNode mirrorParentNode; + Board board = Board.empty(); + Board mirrorBoard = Board.empty(); + root.addGame(game); + for(CommentedMove move: game.getMoves()){ + if(!move.getMove().equals(Move.RESIGN)){ + parentNode = node; + mirrorParentNode = mirrorNode; + board = board.apply(move.getMove()); + mirrorBoard = mirrorBoard.apply(move.getMove().getMirrorMove()); + String hashCode = Board.board2HashCode(board); + String mirrorHashCode = Board.board2HashCode(mirrorBoard); + node = nodes.get(hashCode); + if(node == null){ + node = new OpeningTreeNode(hashCode); + nodes.put(hashCode, node); + } + node.addGame(game); + mirrorNode = nodes.get(mirrorHashCode); + if(mirrorHashCode.equals(hashCode)){ + if(mirrorNode == null){ + mirrorNode = node; + } + }else{ + if(mirrorNode == null){ + mirrorNode = new OpeningTreeNode(mirrorHashCode); + nodes.put(mirrorHashCode, mirrorNode); + } + mirrorNode.addGame(game); + } + if(parentNode != null) + parentNode.addChild(move.getMove(),node); + if(mirrorParentNode != null){ + if(parentNode.equals(mirrorParentNode) && node.equals(mirrorNode)) + ; + else + mirrorParentNode.addChild(move.getMove().getMirrorMove(),mirrorNode); + } + } + } + node.addFinishedGame(game); + if(!node.equals(mirrorNode)) + mirrorNode.addFinishedGame(game); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningTreeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/OpeningTreeNode.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,138 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import cz.xelfi.quoridor.webidor.Game; +import cz.xelfi.quoridor.webidor.GameId; +import cz.xelfi.quoridor.webidor.GameStatus; +import cz.xelfi.quoridor.webidor.User; +import cz.xelfi.quoridor.Move; +import java.util.HashMap; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import javax.xml.bind.annotation.XmlAttribute; + +/** + * + * @author Martin Rexa + */ +public class OpeningTreeNode { + @XmlAttribute + String hashCode; + List gameIds; + List finishedGames; + Map children; + + public OpeningTreeNode(){ + } + + public OpeningTreeNode(String hashCode){ + this.hashCode = hashCode; + gameIds = new ArrayList(); + finishedGames = new ArrayList(); + children = new HashMap(); + } + + public OpeningTreeNode addGame(Game game){ + gameIds.add(game.getId()); + return this; + } + + public OpeningTreeNode addFinishedGame(Game game){ + finishedGames.add(game.getId()); + return this; + } + + public OpeningTreeNode addGameId(GameId gameId){ + gameIds.add(gameId); + return this; + } + + public OpeningTreeNode addChild(Move move, OpeningTreeNode child){ + children.put(move, child); + return this; + } + + public OpeningNodeView getView(User user){ + return getView(user.getId()); + } + + public OpeningNodeView getView(String userId){ + OpeningNodeView view = new OpeningNodeView(hashCode); + for(Map.Entry e: children.entrySet()){ + for(GameId gId: e.getValue().gameIds){ + if(User.canSee(gId, userId)){ + view.processGame(e.getKey(), e.getValue().hashCode, gId); + } + } + } + for(GameId gId: finishedGames){ + view.addFinishedGame(gId); + } + return view; + } + + public List filterGames(String userId, GameStatus status){ + List result = new ArrayList(); + for(GameId gId: gameIds){ + if(User.canSee(gId, userId)) + if(gId.getStatus().equals(status)) + result.add(gId); + } + return result; + } + + public List getGameIds(){ + return gameIds; + } + +// @XmlAttribute +// @XmlElement + public String getHashCode(){ + return this.hashCode; + } + + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + OpeningTreeNode other = (OpeningTreeNode)obj; + return hashCode.equals(other.hashCode); + } + + @Override + public int hashCode() { + return hashCode.hashCode(); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Elo.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Elo.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,75 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics.resources; + +import cz.xelfi.quoridor.statistics.EloList; +import cz.xelfi.quoridor.webidor.Game; +import cz.xelfi.quoridor.webidor.GameId; +import cz.xelfi.quoridor.webidor.GameStatus; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +/** + * + * @author Martin Rexa + */ +public final class Elo { + private EloList list; + + public Elo(){ + list = new EloList(); + } + + public void processGame(Game game){ + GameId gId = game.getId(); + GameStatus status = gId.getStatus(); + if(status.equals(GameStatus.whiteWon)){ + list.putResult(gId.getWhite(), gId.getBlack()); + }else if(status.equals(GameStatus.blackWon)){ + list.putResult(gId.getBlack(), gId.getWhite()); + } + } + + @GET + @Path("list") + @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public EloList getList(){ + return list; + } + + @GET + @Path("{username}") + @Produces(MediaType.TEXT_PLAIN) + public String getElo(@PathParam("username") String id){ + list.getElo(id); + return Double.toString(list.getElo(id)); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Openings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Openings.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,107 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics.resources; + +import cz.xelfi.quoridor.IllegalPositionException; +import cz.xelfi.quoridor.webidor.Game; +import cz.xelfi.quoridor.webidor.GameId; +import cz.xelfi.quoridor.statistics.OpeningTree; +import cz.xelfi.quoridor.statistics.OpeningTreeNode; +import cz.xelfi.quoridor.statistics.OpeningNodeView; +import cz.xelfi.quoridor.webidor.GameStatus; +import java.util.List; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.core.MediaType; + +/** + * + * @author Martin Rexa + */ +public class Openings { + OpeningTree tree; + + public Openings(){ + tree = new OpeningTree(); + } + + public void processGame(Game game) { + try{ + tree.processGame(game); + }catch (IllegalPositionException e){ + e.printStackTrace(); + } + } + + @GET + @Path("{nodeId}") + @Produces({ MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public OpeningNodeView getNode(@QueryParam("loginID") @DefaultValue("") String loginId, + @PathParam("nodeId") String nodeId){ + OpeningTreeNode node = tree.getNode(nodeId); + if(node == null) + node = tree.getRoot(); + return node.getView(loginId); + } + + @GET + @Path("{nodeId}.check") + @Produces({ MediaType.TEXT_PLAIN }) + public String checkNode(@QueryParam("loginID") @DefaultValue("") String loginId, + @PathParam("nodeId") String nodeId){ + OpeningTreeNode node = tree.getNode(nodeId); + if(node == null) + return ""; + if(node.getView(loginId).isEmpty()) + return ""; + else + return nodeId; + } + + @GET + @Path("{nodeId}/{status}") + @Produces({MediaType.APPLICATION_JSON, MediaType.TEXT_XML }) + public List listGames( + @DefaultValue("") @QueryParam("loginID") String loginId, + @PathParam("nodeId") String nodeId, + @DefaultValue("") @PathParam("status") String status + ) { + OpeningTreeNode node = tree.getNode(nodeId); + if(node == null) + return null; + if("white".equals(status)) + return node.filterGames(loginId, GameStatus.whiteWon); + else if("black".equals(status)) + return node.filterGames(loginId, GameStatus.blackWon); + else + return null; + } +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Statistics.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/main/java/cz/xelfi/quoridor/statistics/resources/Statistics.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,156 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics.resources; + +import com.sun.jersey.api.container.httpserver.HttpServerFactory; +import com.sun.jersey.api.core.PackagesResourceConfig; +import com.sun.jersey.api.core.ResourceConfig; +import com.sun.jersey.spi.resource.Singleton; +import com.sun.net.httpserver.HttpServer; +import java.io.File; +import java.io.IOException; +import java.util.Comparator; +import java.util.List; +import java.util.Collections; +import java.net.ServerSocket; +import javax.ws.rs.Path; +import cz.xelfi.quoridor.webidor.resources.Games; +import cz.xelfi.quoridor.webidor.Game; + +/** + * + * @author Martin Rexa + */ +@Path("/") +@Singleton +public class Statistics { + static final Comparator OLDEST_FIRST = new OldestFirst(); + static Elo elo; + static Openings openings; + + @Path("elo") + public Elo getElo() { + return elo; + } + + @Path("openings") + public Openings getOpenings() { + return openings; + } + + public static void main( String[] args ) throws IOException, InterruptedException + { + int port = 9444; + // timeout between reprocessing games in miliseconds +// long timeout = 1000 * 60 * 60; + long timeout = 1000 * 10; + + try { + port = Integer.parseInt(args[0]); + } catch (Exception ex) { + // OK + } + + if (System.getProperty("quoridor.dir") == null) { + File home = new File(System.getProperty("user.home")); + File quoridor = new File(home, ".quoridor"); + System.setProperty("quoridor.dir", quoridor.getPath()); + } + + processGames(); + HttpServer s = start(port); + System.out.println("Statistics started at port " + port); + Object monitor = new Object(); + for(;;){ + synchronized (monitor) { + monitor.wait(timeout); + } + processGames(); + } + } + + public static HttpServer start(int port) throws IOException { + if (port == -1) { + ServerSocket ss = new ServerSocket(0); + port =ss.getLocalPort(); + ss.close(); + } + final String baseUri = "http://localhost:" + port + "/"; + + if (System.getProperty("quoridor.dir") == null) { + File home = new File(System.getProperty("user.home")); + File quoridor = new File(home, ".quoridor"); + System.setProperty("quoridor.dir", quoridor.getPath()); + } + + ResourceConfig rc = new PackagesResourceConfig("cz.xelfi.quoridor.statistics"); + HttpServer server = HttpServerFactory.create(baseUri, rc); + server.start(); + return server; + } + + public static void processGames(){ + Elo eloTmp = new Elo(); + Openings openingsTmp = new Openings(); + + final String prop = System.getProperty("quoridor.dir"); // NOI18N + if (prop == null) { + throw new IllegalStateException("quoridor.dir property must be specified"); // NOI18N + } + File path = new File(prop); + path.mkdirs(); + File fGames = new File(path, "games"); + //fGames.mkdirs(); + Games games = new Games(fGames, null); + List lGames = games.getGames(); + Collections.sort(lGames, OLDEST_FIRST); + + // process games + for(Game g: lGames){ + if(g.getId().isFinished()){ + eloTmp.processGame(g); + openingsTmp.processGame(g); + } + } + + elo = eloTmp; + openings = openingsTmp; + } + + private static final class OldestFirst implements Comparator { + public int compare(Game g1, Game g2) { + if(g1.getId() == g2.getId()) + return 0; + long diff = g2.getId().getModified() - g1.getId().getModified(); + if (diff != 0) { + return diff < 0 ? -1 : 1; + } + return g1.getId().getId().compareTo(g2.getId().getId()); + } + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/test/java/cz/xelfi/quoridor/statistics/EloTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/test/java/cz/xelfi/quoridor/statistics/EloTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author Martin Rexa + */ +public class EloTest extends Object { + + public EloTest() throws Exception { + } + + @Test public void testEloList() throws Exception { + EloList eloList = new EloList(); + eloList.putResult("p1", "p2"); + assertFalse("empty list", eloList.getFinalList().isEmpty()); + eloList.putResult("p3", "p4"); + assertTrue("wrong list", eloList.getFinalList().get(0).getElo().equals(eloList.getFinalList().get(1).getElo())); + eloList.putResult("p2", "p1"); + eloList.putResult("p2", "p1"); + eloList.putResult("p2", "p1"); + assertTrue("wrong list", eloList.getFinalList().get(0).player.equals("p2")); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/test/java/cz/xelfi/quoridor/statistics/OpeningsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/test/java/cz/xelfi/quoridor/statistics/OpeningsTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,129 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics; + +import cz.xelfi.quoridor.Fence.Orientation; +import org.junit.Test; +import static org.junit.Assert.*; +import cz.xelfi.quoridor.Move; +import cz.xelfi.quoridor.webidor.Game; +import java.util.Map; + +/** + * + * @author Martin Rexa + */ +public class OpeningsTest extends Object { + + public OpeningsTest() throws Exception { + } + + @Test public void testMirrorMoves() throws Exception { + assertEquals("bad symetric move", Move.NORTH.getMirrorMove(), Move.NORTH); + assertEquals("bad symetric move", Move.SOUTH.getMirrorMove(), Move.SOUTH); + assertEquals("bad symetric move", Move.WEST.getMirrorMove(), Move.EAST); + assertEquals("bad symetric move", Move.EAST.getMirrorMove(), Move.WEST); + assertEquals("bad symetric move", Move.fence('A', 1, Orientation.HORIZONTAL).getMirrorMove(), Move.fence('H', 1, Orientation.HORIZONTAL)); + assertEquals("bad symetric move", Move.fence('D', 3, Orientation.VERTICAL).getMirrorMove(), Move.fence('E', 3, Orientation.VERTICAL)); + } + + @Test public void testMirrorJump() throws Exception { + Game g = new Game("w","b"); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.EAST, new java.util.Date()); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.valueOf("WW"), new java.util.Date()); + g.apply("w", Move.RESIGN, new java.util.Date()); + OpeningTree t = new OpeningTree(); + t.processGame(g); + OpeningTreeNode n = t.root; + n = n.children.get(Move.NORTH); + n = n.children.get(Move.SOUTH); + n = n.children.get(Move.NORTH); + n = n.children.get(Move.SOUTH); + n = n.children.get(Move.NORTH); + n = n.children.get(Move.SOUTH); + n = n.children.get(Move.NORTH); + n = n.children.get(Move.WEST); + n = n.children.get(Move.NORTH); + n = n.children.get(Move.valueOf("EE")); + assertEquals("bad number of children", n.children.size(), 0); + for(Map.Entry e: n.children.entrySet()){ + System.out.println(e.getKey()); + } + } + + @Test public void testOpeningTreeNodes() throws Exception { + OpeningTree t = new OpeningTree(); + assertEquals("bad number of nodes", t.nodes.size(), 1); + Game g = new Game("w","b"); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.EAST, new java.util.Date()); + g.apply("b", Move.EAST, new java.util.Date()); + g.apply("w", Move.WEST, new java.util.Date()); + g.apply("b", Move.WEST, new java.util.Date()); + g.apply("w", Move.RESIGN, new java.util.Date()); + t.processGame(g); + assertEquals("bad number of nodes", t.nodes.size(), 9); + g = new Game("w","b"); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.fence('A', 1, Orientation.HORIZONTAL), new java.util.Date()); + g.apply("b", Move.fence('C', 1, Orientation.VERTICAL), new java.util.Date()); + g.apply("w", Move.RESIGN, new java.util.Date()); + t.processGame(g); + assertEquals("bad number of nodes", t.nodes.size(), 13); + g = new Game("w","b"); + g.apply("w", Move.NORTH, new java.util.Date()); + g.apply("b", Move.SOUTH, new java.util.Date()); + g.apply("w", Move.fence('C', 1, Orientation.VERTICAL), new java.util.Date()); + g.apply("b", Move.fence('A', 1, Orientation.HORIZONTAL), new java.util.Date()); + g.apply("w", Move.RESIGN, new java.util.Date()); + t.processGame(g); + assertEquals("bad number of nodes", t.nodes.size(), 15); + OpeningTreeNode n = t.root; + n = n.children.get(Move.NORTH); + n = n.children.get(Move.SOUTH); + OpeningTreeNode n1 = n; + n = n.children.get(Move.WEST); + n = n.children.get(Move.WEST); + n = n.children.get(Move.EAST); + n = n.children.get(Move.EAST); + assertEquals("different nodes", n.hashCode, n1.hashCode); + n = n.children.get(Move.fence('F', 1, Orientation.VERTICAL)); + n = n.children.get(Move.fence('H', 1, Orientation.HORIZONTAL)); + assertEquals("bad number of children", n.children.size(), 0); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 statistics/src/test/java/cz/xelfi/quoridor/statistics/resources/StatisticsTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/statistics/src/test/java/cz/xelfi/quoridor/statistics/resources/StatisticsTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -0,0 +1,131 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2010 Martin Rexa + */ + +package cz.xelfi.quoridor.statistics.resources; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.core.header.MediaTypes; +import com.sun.net.httpserver.HttpServer; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.URI; +import java.util.Locale; +import javax.ws.rs.core.MediaType; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; +import cz.xelfi.quoridor.statistics.EloList; +/** + * + * @author Martin Rexa + */ +public class StatisticsTest { + private static File dir; + private static File fGames; + private static HttpServer stopAPI; + private WebResource apiResource; + + public StatisticsTest() throws Exception { + } + + @BeforeClass + public static void localeEnglish() throws Exception { + Locale.setDefault(Locale.ENGLISH); + dir = File.createTempFile("quoridor", ".dir"); + dir.delete(); + dir.mkdirs(); + fGames = new File(dir, "games"); + fGames.mkdirs(); + + System.setProperty("quoridor.dir", dir.getPath()); + stopAPI = Statistics.start(9990); + + File passwd = new File(dir, "passwd"); + FileOutputStream os = new FileOutputStream(passwd); + os.write("test=pes\nJarda=darda\n".getBytes("UTF-8")); + os.close(); + } + + @Before + public void setUp() throws Exception { + Client client = new Client(); + apiResource = client.resource(new URI("http://localhost:9990/")); + } + + @AfterClass + public static void cleanUpAll() throws Exception { + deleteRec(dir); + if (stopAPI != null) { + stopAPI.stop(0); + } + } + + static void deleteRec(File dir) throws IOException { + if (dir == null) { + return; + } + File[] arr = dir.listFiles(); + if (arr != null) { + for (File f : arr) { + deleteRec(f); + } + } + dir.delete(); + } + + @Test public void testApplicationWadl() { + String serviceWadl = apiResource.path("application.wadl"). + accept(MediaTypes.WADL).get(String.class); + assertTrue(serviceWadl.length() > 0); + } + + @Test public void testEloList() throws Exception { + createFile(fGames, "g1", "# white: W\n# black: B\n# status: IN_PROGRESS\nN S\n\n"); + createFile(fGames, "g2", "# white: W\n# black: B\n# status: blackWon\nRESIGN\n\n"); + createFile(fGames, "g3", "# white: W\n# black: B\n# status: blackWon\nRESIGN\n\n"); + createFile(fGames, "g4", "# white: W\n# black: B\n# status: blackWon\nRESIGN\n\n"); + Statistics.processGames(); + + EloList eloList = apiResource.path("elo").path("list").accept(MediaType.TEXT_XML).get(EloList.class); +// assertFalse(eloList.getFinalList().isEmpty()); +// System.out.println("ELO LIST"); +// for (EloEntry entry : eloList.getFinalList()){ +// System.out.println(entry); +// } + } + + private void createFile(File dir, String filename, String content) throws Exception{ + File f = new File(dir, filename); + FileOutputStream os = new FileOutputStream(f); + os.write(content.getBytes("UTF-8")); + os.close(); + } + +} diff -r 2f8672ac9f1a -r 4b78d4f028b3 visidor/src/main/java/cz/xelfi/quoridor/visidor/Viewer.java --- a/visidor/src/main/java/cz/xelfi/quoridor/visidor/Viewer.java Fri Jan 01 20:53:17 2010 +0100 +++ b/visidor/src/main/java/cz/xelfi/quoridor/visidor/Viewer.java Thu Jan 07 22:34:17 2010 +0100 @@ -1,8 +1,28 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * Portions Copyrighted 2009 Jaroslav Tulach */ - package cz.xelfi.quoridor.visidor; import cz.xelfi.quoridor.Board; diff -r 2f8672ac9f1a -r 4b78d4f028b3 webidor/pom.xml --- a/webidor/pom.xml Fri Jan 01 20:53:17 2010 +0100 +++ b/webidor/pom.xml Thu Jan 07 22:34:17 2010 +0100 @@ -1,5 +1,7 @@ - + 4.0.0 all-quoridor diff -r 2f8672ac9f1a -r 4b78d4f028b3 webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java Fri Jan 01 20:53:17 2010 +0100 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/Game.java Thu Jan 07 22:34:17 2010 +0100 @@ -82,10 +82,19 @@ @XmlAttribute final String getCurrentPlayer() { - if (board.getCurrentPlayer() == board.getPlayers().get(0)) { - return id.getWhite(); - } else { - return id.getBlack(); + Player w = board.getWinner(); + if(w==null){ + if (board.getCurrentPlayer() == board.getPlayers().get(0)) { + return id.getWhite(); + } else { + return id.getBlack(); + } + }else{ + if (w == board.getPlayers().get(0)) { + return id.getWhite(); + } else { + return id.getBlack(); + } } } @@ -191,11 +200,13 @@ @Override public Board unmarshal(String v) throws Exception { return v == null ? null : Board.valueOf(v); +// return v == null ? null : new Board(v); } @Override public String marshal(Board v) throws Exception { return v == null ? null : v.toString(); +// return v == null ? null : Board.board2HashCode(v); } } diff -r 2f8672ac9f1a -r 4b78d4f028b3 webidor/src/main/java/cz/xelfi/quoridor/webidor/User.java --- a/webidor/src/main/java/cz/xelfi/quoridor/webidor/User.java Fri Jan 01 20:53:17 2010 +0100 +++ b/webidor/src/main/java/cz/xelfi/quoridor/webidor/User.java Thu Jan 07 22:34:17 2010 +0100 @@ -90,6 +90,23 @@ return permissions.contains(permission); } + public static boolean canSee(GameId gId, String userId) { + if (!gId.isFinished()) { + return true; + } + if (userId.equals(gId.getWhite())) { + return true; + } + if (userId.equals(gId.getBlack())) { + return true; + } + return false; + } + + public boolean canSee(GameId gId){ + return canSee(gId, id); + } + public String getId() { return id; } diff -r 2f8672ac9f1a -r 4b78d4f028b3 webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java Fri Jan 01 20:53:17 2010 +0100 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/FinishedGameTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -184,4 +184,45 @@ assertFalse("is finished", end.getId().getStatus().isInProgress()); } + @Test public void testResignBGame() throws Exception { + String logJarda = webResource.path("login"). + queryParam("name", "Jarda"). + queryParam("password", "heslo"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + String logJirka = webResource.path("login"). + queryParam("name", "Jirka"). + queryParam("password", "pesko"). + accept(MediaType.TEXT_PLAIN). + put(String.class); + + GameId s = webResource.path("games").queryParam("white", "Jarda") + .queryParam("loginID", logJarda) + .queryParam("black", "Jirka").post(GameId.class); + + assertTrue("In progress", s.getStatus().isInProgress()); + + webResource.path("games/" + s.getId()). + queryParam("loginID", logJarda). + queryParam("player", "Jarda"). + queryParam("move", "N").put(GameId.class); + webResource.path("games/" + s.getId()). + queryParam("loginID", logJirka). + queryParam("player", "Jirka"). + queryParam("move", "RESIGN").put(GameId.class); + + + try { + Game end = webResource.path("games/" + s.getId()).accept(MediaType.TEXT_XML).get(Game.class); + fail("Should not be able to get game when finished"); + } catch (UniformInterfaceException ex) { + // OK + } + Game end = webResource.path("games/" + s.getId()).queryParam("loginID", logJarda).accept(MediaType.TEXT_XML).get(Game.class); + assertEquals("WhiteWins", GameStatus.whiteWon, end.getId().getStatus()); + assertEquals("Jarda wins", "Jarda", end.getCurrentPlayer()); + + assertFalse("is finished", end.getId().getStatus().isInProgress()); + } + } diff -r 2f8672ac9f1a -r 4b78d4f028b3 webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java --- a/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Fri Jan 01 20:53:17 2010 +0100 +++ b/webidor/src/test/java/cz/xelfi/quoridor/webidor/QuoridorTest.java Thu Jan 07 22:34:17 2010 +0100 @@ -201,14 +201,17 @@ class GMap extends GenericType>{} String text = webResource.path("games").path(s.getId()).accept(MediaType.TEXT_PLAIN).get(String.class); + text = (new Board(text)).boardToPicture(); if (text.indexOf("-----") == -1) { fail("Expecting board:\n" + text); } Game readGame = webResource.path("games").path(s.getId()).accept(MediaType.TEXT_XML).get(Game.class); String sGame = webResource.path("games").path(s.getId()).accept(MediaType.TEXT_XML).get(String.class); assertNotNull("Game really returned", readGame); - assertEquals("Same game as in text representation", readGame.getBoard(), Board.valueOf(text)); - assertEquals("It is same as text of our game", readGame.getBoard().toString(), text); +// assertEquals("Same game as in text representation", readGame.getBoard(), Board.valueOf(text)); + assertEquals("Same game as in text representation", readGame.getBoard(), Board.picture2board(text)); +// assertEquals("It is same as text of our game", readGame.getBoard().toString(), text); + assertEquals("It is same as text of our game", readGame.getBoard().boardToPicture(), text); assertEquals(Move.NORTH, readGame.getMoves().get(0).getMove()); assertEquals(Move.SOUTH, readGame.getMoves().get(1).getMove());