1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/json-tck/src/main/java/net/java/html/json/tests/MinesTest.java Fri Mar 07 19:45:23 2014 +0100
1.3 @@ -0,0 +1,309 @@
1.4 +/**
1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 + *
1.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
1.8 + *
1.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
1.10 + * Other names may be trademarks of their respective owners.
1.11 + *
1.12 + * The contents of this file are subject to the terms of either the GNU
1.13 + * General Public License Version 2 only ("GPL") or the Common
1.14 + * Development and Distribution License("CDDL") (collectively, the
1.15 + * "License"). You may not use this file except in compliance with the
1.16 + * License. You can obtain a copy of the License at
1.17 + * http://www.netbeans.org/cddl-gplv2.html
1.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.19 + * specific language governing permissions and limitations under the
1.20 + * License. When distributing the software, include this License Header
1.21 + * Notice in each file and include the License file at
1.22 + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
1.23 + * particular file as subject to the "Classpath" exception as provided
1.24 + * by Oracle in the GPL Version 2 section of the License file that
1.25 + * accompanied this code. If applicable, add the following below the
1.26 + * License Header, with the fields enclosed by brackets [] replaced by
1.27 + * your own identifying information:
1.28 + * "Portions Copyrighted [year] [name of copyright owner]"
1.29 + *
1.30 + * Contributor(s):
1.31 + *
1.32 + * The Original Software is NetBeans. The Initial Developer of the Original
1.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
1.34 + *
1.35 + * If you wish your version of this file to be governed by only the CDDL
1.36 + * or only the GPL Version 2, indicate your decision by adding
1.37 + * "[Contributor] elects to include this software in this distribution
1.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
1.39 + * single choice of license, a recipient has the option to distribute
1.40 + * your version of this file under either the CDDL, the GPL Version 2 or
1.41 + * to extend the choice of license to its licensees as provided above.
1.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
1.43 + * Version 2 license, then the option applies only if the new code is
1.44 + * made subject to such option by the copyright holder.
1.45 + */
1.46 +
1.47 +package net.java.html.json.tests;
1.48 +
1.49 +import java.util.ArrayList;
1.50 +import java.util.List;
1.51 +import java.util.Random;
1.52 +import net.java.html.BrwsrCtx;
1.53 +import net.java.html.json.ComputedProperty;
1.54 +import net.java.html.json.Model;
1.55 +import net.java.html.json.ModelOperation;
1.56 +import net.java.html.json.Models;
1.57 +import net.java.html.json.Property;
1.58 +import org.apidesign.html.json.tck.KOTest;
1.59 +
1.60 +/** Tests model of a mine field and its behavior in the browser.
1.61 + */
1.62 +@Model(className = "Mines", properties = {
1.63 + @Property(name = "state", type = MinesTest.GameState.class),
1.64 + @Property(name = "rows", type = Row.class, array = true),
1.65 +})
1.66 +public final class MinesTest {
1.67 + @KOTest public void paintTheGrid() throws Throwable {
1.68 + BrwsrCtx ctx = Utils.newContext(KnockoutTest.class);
1.69 + Object exp = Utils.exposeHTML(KnockoutTest.class,
1.70 +" <table class=\"field\">\n" +
1.71 +" <tbody id='table'>\n" +
1.72 +" <!-- ko foreach: rows -->\n" +
1.73 +" <tr>\n" +
1.74 +" <!-- ko foreach: columns -->\n" +
1.75 +" <td data-bind=\"css: style, click: $parents[1].click\" >\n" +
1.76 +" <div data-bind='text: html'></div>\n" +
1.77 +" </td>\n" +
1.78 +" <!-- /ko -->\n" +
1.79 +" </tr>\n" +
1.80 +" <!-- /ko -->\n" +
1.81 +" </tbody>\n" +
1.82 +" </table>\n" +
1.83 +""
1.84 + );
1.85 + try {
1.86 +
1.87 + Mines m = Models.bind(new Mines(), ctx);
1.88 + m.init(10, 10, 0);
1.89 + m.applyBindings();
1.90 +
1.91 + int cnt = countChildren("table");
1.92 + assert cnt == 10 : "There is ten rows in the table: " + cnt;
1.93 + } catch (Throwable t) {
1.94 + throw t;
1.95 + } finally {
1.96 + Utils.exposeHTML(KnockoutTest.class, "");
1.97 + }
1.98 + }
1.99 +
1.100 + private static int countChildren(String id) throws Exception {
1.101 + return ((Number)Utils.executeScript(
1.102 + KnockoutTest.class,
1.103 + "var e = window.document.getElementById(arguments[0]);\n "
1.104 + + "if (typeof e === 'undefined') return -2;\n "
1.105 + + "return e.children.length;",
1.106 + id
1.107 + )).intValue();
1.108 + }
1.109 +
1.110 + enum GameState {
1.111 + IN_PROGRESS, WON, LOST;
1.112 + }
1.113 +
1.114 + @Model(className = "Row", properties = {
1.115 + @Property(name = "columns", type = Square.class, array = true)
1.116 + })
1.117 + static class RowModel {
1.118 + }
1.119 +
1.120 + @Model(className = "Square", properties = {
1.121 + @Property(name = "state", type = SquareType.class),
1.122 + @Property(name = "mine", type = boolean.class)
1.123 + })
1.124 + static class SquareModel {
1.125 + @ComputedProperty static String html(SquareType state) {
1.126 + if (state == null) return " ";
1.127 + switch (state) {
1.128 + case EXPLOSION: return "✗";
1.129 + case UNKNOWN: return " ";
1.130 + case DISCOVERED: return "✔";
1.131 + case N_0: return " ";
1.132 + }
1.133 + return "ɸ" + (state.ordinal() - 1);
1.134 + }
1.135 +
1.136 + @ComputedProperty static String style(SquareType state) {
1.137 + return state == null ? null : state.toString();
1.138 + }
1.139 + }
1.140 +
1.141 + enum SquareType {
1.142 + N_0, N_1, N_2, N_3, N_4, N_5, N_6, N_7, N_8,
1.143 + UNKNOWN, EXPLOSION, DISCOVERED;
1.144 +
1.145 + final boolean isVisible() {
1.146 + return name().startsWith("N_");
1.147 + }
1.148 +
1.149 + final SquareType moreBombsAround() {
1.150 + switch (this) {
1.151 + case EXPLOSION:
1.152 + case UNKNOWN:
1.153 + case DISCOVERED:
1.154 + case N_8:
1.155 + return this;
1.156 + }
1.157 + return values()[ordinal() + 1];
1.158 + }
1.159 + }
1.160 +
1.161 + @ComputedProperty static boolean fieldShowing(GameState state) {
1.162 + return state != null;
1.163 + }
1.164 +
1.165 +
1.166 + @ModelOperation static void init(Mines model, int width, int height, int mines) {
1.167 + List<Row> rows = new ArrayList<Row>(height);
1.168 + for (int y = 0; y < height; y++) {
1.169 + Square[] columns = new Square[width];
1.170 + for (int x = 0; x < width; x++) {
1.171 + columns[x] = new Square(SquareType.UNKNOWN, false);
1.172 + }
1.173 + rows.add(new Row(columns));
1.174 + }
1.175 +
1.176 + Random r = new Random();
1.177 + while (mines > 0) {
1.178 + int x = r.nextInt(width);
1.179 + int y = r.nextInt(height);
1.180 + final Square s = rows.get(y).getColumns().get(x);
1.181 + if (s.isMine()) {
1.182 + continue;
1.183 + }
1.184 + s.setMine(true);
1.185 + mines--;
1.186 + }
1.187 +
1.188 + model.setState(GameState.IN_PROGRESS);
1.189 + model.getRows().clear();
1.190 + model.getRows().addAll(rows);
1.191 + }
1.192 +
1.193 + @ModelOperation static void computeMines(Mines model) {
1.194 + List<Integer> xBombs = new ArrayList<Integer>();
1.195 + List<Integer> yBombs = new ArrayList<Integer>();
1.196 + final List<Row> rows = model.getRows();
1.197 + boolean emptyHidden = false;
1.198 + SquareType[][] arr = new SquareType[rows.size()][];
1.199 + for (int y = 0; y < rows.size(); y++) {
1.200 + final List<Square> columns = rows.get(y).getColumns();
1.201 + arr[y] = new SquareType[columns.size()];
1.202 + for (int x = 0; x < columns.size(); x++) {
1.203 + Square sq = columns.get(x);
1.204 + if (sq.isMine()) {
1.205 + xBombs.add(x);
1.206 + yBombs.add(y);
1.207 + }
1.208 + if (sq.getState().isVisible()) {
1.209 + arr[y][x] = SquareType.N_0;
1.210 + } else {
1.211 + if (!sq.isMine()) {
1.212 + emptyHidden = true;
1.213 + }
1.214 + }
1.215 + }
1.216 + }
1.217 + for (int i = 0; i < xBombs.size(); i++) {
1.218 + int x = xBombs.get(i);
1.219 + int y = yBombs.get(i);
1.220 +
1.221 + incrementAround(arr, x, y);
1.222 + }
1.223 + for (int y = 0; y < rows.size(); y++) {
1.224 + final List<Square> columns = rows.get(y).getColumns();
1.225 + for (int x = 0; x < columns.size(); x++) {
1.226 + Square sq = columns.get(x);
1.227 + final SquareType newState = arr[y][x];
1.228 + if (newState != null && newState != sq.getState()) {
1.229 + sq.setState(newState);
1.230 + }
1.231 + }
1.232 + }
1.233 +
1.234 + if (!emptyHidden) {
1.235 + model.setState(GameState.WON);
1.236 + showAllBombs(model, SquareType.DISCOVERED);
1.237 + }
1.238 + }
1.239 +
1.240 + private static void incrementAround(SquareType[][] arr, int x, int y) {
1.241 + incrementAt(arr, x - 1, y - 1);
1.242 + incrementAt(arr, x - 1, y);
1.243 + incrementAt(arr, x - 1, y + 1);
1.244 +
1.245 + incrementAt(arr, x + 1, y - 1);
1.246 + incrementAt(arr, x + 1, y);
1.247 + incrementAt(arr, x + 1, y + 1);
1.248 +
1.249 + incrementAt(arr, x, y - 1);
1.250 + incrementAt(arr, x, y + 1);
1.251 + }
1.252 +
1.253 + private static void incrementAt(SquareType[][] arr, int x, int y) {
1.254 + if (y >= 0 && y < arr.length) {
1.255 + SquareType[] r = arr[y];
1.256 + if (x >= 0 && x < r.length) {
1.257 + SquareType sq = r[x];
1.258 + if (sq != null) {
1.259 + r[x] = sq.moreBombsAround();
1.260 + }
1.261 + }
1.262 + }
1.263 + }
1.264 +
1.265 + static void showAllBombs(Mines model, SquareType state) {
1.266 + for (Row row : model.getRows()) {
1.267 + for (Square square : row.getColumns()) {
1.268 + if (square.isMine()) {
1.269 + square.setState(state);
1.270 + }
1.271 + }
1.272 + }
1.273 + }
1.274 +
1.275 + private static void expandKnown(Mines model, Square data) {
1.276 + final List<Row> rows = model.getRows();
1.277 + for (int y = 0; y < rows.size(); y++) {
1.278 + final List<Square> columns = rows.get(y).getColumns();
1.279 + for (int x = 0; x < columns.size(); x++) {
1.280 + Square sq = columns.get(x);
1.281 + if (sq == data) {
1.282 + expandKnown(model, x, y);
1.283 + return;
1.284 + }
1.285 + }
1.286 + }
1.287 + }
1.288 + private static void expandKnown(Mines model, int x , int y) {
1.289 + if (y < 0 || y >= model.getRows().size()) {
1.290 + return;
1.291 + }
1.292 + final List<Square> columns = model.getRows().get(y).getColumns();
1.293 + if (x < 0 || x >= columns.size()) {
1.294 + return;
1.295 + }
1.296 + final Square sq = columns.get(x);
1.297 + if (sq.getState() == SquareType.UNKNOWN) {
1.298 + sq.setState(SquareType.N_0);
1.299 + model.computeMines();
1.300 + if (sq.getState() == SquareType.N_0) {
1.301 + expandKnown(model, x - 1, y - 1);
1.302 + expandKnown(model, x - 1, y);
1.303 + expandKnown(model, x - 1, y + 1);
1.304 + expandKnown(model, x , y - 1);
1.305 + expandKnown(model, x, y + 1);
1.306 + expandKnown(model, x + 1, y - 1);
1.307 + expandKnown(model, x + 1, y);
1.308 + expandKnown(model, x + 1, y + 1);
1.309 + }
1.310 + }
1.311 + }
1.312 +}
2.1 --- a/json-tck/src/main/java/org/apidesign/html/json/tck/KnockoutTCK.java Fri Mar 07 14:06:31 2014 +0100
2.2 +++ b/json-tck/src/main/java/org/apidesign/html/json/tck/KnockoutTCK.java Fri Mar 07 19:45:23 2014 +0100
2.3 @@ -48,11 +48,12 @@
2.4 import net.java.html.json.tests.ConvertTypesTest;
2.5 import net.java.html.json.tests.JSONTest;
2.6 import net.java.html.json.tests.KnockoutTest;
2.7 +import net.java.html.json.tests.MinesTest;
2.8 import net.java.html.json.tests.OperationsTest;
2.9 import net.java.html.json.tests.Utils;
2.10 import net.java.html.json.tests.WebSocketTest;
2.11 +import org.apidesign.html.context.spi.Contexts.Builder;
2.12 import org.openide.util.lookup.ServiceProvider;
2.13 -import org.apidesign.html.context.spi.Contexts.Builder;
2.14
2.15 /** Entry point for providers of different HTML binding technologies (like
2.16 * Knockout.js in JavaFX's WebView). Sample usage:
2.17 @@ -121,6 +122,7 @@
2.18 ConvertTypesTest.class,
2.19 JSONTest.class,
2.20 KnockoutTest.class,
2.21 + MinesTest.class,
2.22 OperationsTest.class,
2.23 WebSocketTest.class
2.24 };