diff options
Diffstat (limited to 'examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser')
3 files changed, 504 insertions, 0 deletions
diff --git a/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/BrowserDemoPlugin.java b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/BrowserDemoPlugin.java new file mode 100644 index 0000000000..5eb8805c51 --- /dev/null +++ b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/BrowserDemoPlugin.java @@ -0,0 +1,49 @@ +package org.eclipse.swt.examples.browser.demos; + +import org.eclipse.ui.plugin.*; +import org.osgi.framework.BundleContext; +import java.util.*; +import org.eclipse.core.runtime.*; + +public class BrowserDemoPlugin extends AbstractUIPlugin { + + public static BrowserDemoPlugin plugin; + ResourceBundle resourceBundle; + public static String PLUGIN_PATH = null; + + public BrowserDemoPlugin() { + super(); + plugin = this; + try { + resourceBundle = ResourceBundle.getBundle("org.eclipse.swt.examples.browser.demos.BrowserDemoPluginResources"); + } catch (MissingResourceException x) { + resourceBundle = null; + } + } + + public void start(BundleContext context) throws Exception { + super.start(context); + PLUGIN_PATH = Platform.resolve(plugin.getBundle().getEntry(".")).toString(); + } + + public void stop(BundleContext context) throws Exception { + super.stop(context); + } + + public static BrowserDemoPlugin getDefault() { + return plugin; + } + + public static String getResourceString(String key) { + ResourceBundle bundle = BrowserDemoPlugin.getDefault().getResourceBundle(); + try { + return (bundle != null) ? bundle.getString(key) : key; + } catch (MissingResourceException e) { + return key; + } + } + + public ResourceBundle getResourceBundle() { + return resourceBundle; + } +} diff --git a/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/Pawns.java b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/Pawns.java new file mode 100644 index 0000000000..cb08f32584 --- /dev/null +++ b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/Pawns.java @@ -0,0 +1,222 @@ +package org.eclipse.swt.examples.browser.demos; + +public class Pawns { + + /* Current board representation in compacted form */ + byte[] game = new byte[64]; + /* Best move */ + int bestIndex = -1; + /* Related best score */ + int bestScore = Integer.MIN_VALUE; + /* Estimated strategic value of each cell based on proximity to walls */ + static int[] gameWallWeight = new int[64]; + Thread thread = null; + boolean threadStop = false; + + final static byte EMPTY = 0; + final static byte WHITE = 1; + final static byte BLACK = 2; + final static byte WALL = 3; + +public Pawns() { +} + +/* Provide the current game and ignitiate the search of the best move for the given type + * Must return immediately as it will be called from the UI thread. + * The UI thread will fetch the best move any time thereafter. + */ +public void playRequest(byte[][] game, int type) { + threadStop = true; + synchronized (this) { + bestIndex = -1; + bestScore = Integer.MIN_VALUE; + convert(game, this.game); + initPawnBorders(this.game, gameWallWeight); + /* Quickly compute a legal move */ + for (int i = 0; i < this.game.length; i++) { + if (this.game[i] == EMPTY) { + bestIndex = i; + break; + } + } + new Thread() { + public void run() { + synchronized(Pawns.this) { + threadStop = false; + int[] result = new int[2]; + /* if long time, must check for threadStop and exit early */ + evalBest(Pawns.this.game, BLACK, 2, result); + bestIndex = result[0]; + bestScore = result[1]; + } + } + }.start(); + } +} + +/* Fetch best move in natural coordinates for the board previously given in + * the call to playRequest. + */ +public void getBestMove(int[] point) { + convert(bestIndex, point); + threadStop = true; +} + +/* Given an expanded representation of the board, format internal compact mode */ +static void convert(byte[][] board, byte[] g) { + for (int i = 0; i < board.length; i++) System.arraycopy(board[i], 0, g, i * 8, 8); +} +/* Update given compact model based on player move in natural coordinates */ +static void set(byte[] g, int x, int y, byte type) { + g[x*8+y] = type; +} +/* Given an index in compact representation, return natural coordinates */ +static void convert(int index, /*out [0] x [1] y */int[] point) { + point[0] = index / 8; + point[1] = index % 8; +} +/* Given an index into the compact model and the neighbour code, + * return the index of the corresponding neighbour index. + * Returns -1 if there is no neighbour. + * + * Neighbour code for the index X + * 0 1 2 + * 3 X 4 + * 5 6 7 + */ +static int getNeighbourIndex(byte[] g, int index, int neighbour) { + if (index < 0 || index >= g.length) return -1; + int result = -1; + switch (neighbour) { + case 0: result = index < 8 || index % 8 == 0 ? -1 : index - 9; break; + case 1: result = index < 8 ? -1 : index - 8; break; + case 2: result = index < 8 || index % 8 == 7 ? -1 : index - 7; break; + case 3: result = index % 8 == 0 ? -1 : index - 1; break; + case 4: result = index % 8 == 7 ? -1 : index + 1; break; + case 5: result = index % 8 == 0 || index >= 56 ? -1 : index + 7; break; + case 6: result = index >= 56 ? -1 : index + 8; break; + case 7: result = index % 8 == 7 || index >= 56 ? -1 : index + 9; break; + } + return result; +} +/* Make the player type play at index on given compact board + * Compute all pawns that must be reversed. + */ +static void play(byte[] g, int index, byte type) { + byte opponentType = type == WHITE ? BLACK : WHITE; + for (int neighbour = 0; neighbour <= 7; neighbour++) { + int nIndex = getNeighbourIndex(g, index, neighbour); + int[] reversiIndeces = new int[6]; + int nReversi = 0; + while (nIndex != -1 && nReversi < 6 && g[nIndex] == opponentType) { + reversiIndeces[nReversi] = nIndex; + nReversi++; + nIndex = getNeighbourIndex(g, nIndex, neighbour); + } + if (nReversi > 0 && nIndex != -1 && g[nIndex] == type) { + for (int i = 0; i < nReversi; i++) g[reversiIndeces[i]] = type; + } + } + g[index] = type; +} +/* Evaluate the given compact model based on pawns distribution + * High means white has advantage. Below zero means black has advantage. + */ +static int eval(byte[] g) { + int cntWhite = 0, cntBlack = 0, cntEmpty = 0; + int cntWhiteWallAdvantage = 0, cntBlackWallAdvantage = 0; + for (int i = 0; i < 64; i++) { + if (g[i] == WHITE) { + cntWhite++; + cntWhiteWallAdvantage += gameWallWeight[i]; + } + else if (g[i] == BLACK) { + cntBlack++; + cntBlackWallAdvantage += gameWallWeight[i]; + } + else if (g[i] == EMPTY) cntEmpty++; + } + if (cntEmpty == 0) { + if (cntWhite > cntBlack) return Integer.MAX_VALUE; /* White wins */ + if (cntWhite < cntBlack) return Integer.MIN_VALUE; /* Black wins */ + return 0; /* Stalemate */ + } + return cntWhite + cntWhiteWallAdvantage - cntBlack - cntBlackWallAdvantage; +} + +/* Recognize pawns protected by walls or borders + * TBD - note this should be called only once for each cell and stored + * in a separate byte[] gWallGain + * */ +static void initPawnBorders(byte[] g, int[] gameWallWeight) { + /* A pawn has 8 neighbours on 4 axes. + * Strategic pawns have one side of each axis protected by a wall and the other + * side not closed by a wall. + * A pawn cannot be reversed when each of its 4 axes are protected by a wall on + * one side. Pawns that have more than 4 walls are less interesting since they + * are not open enough to the board. + * + * Nbr walls, nbr axis covered, estimated value + * 0 n/a 0 + * 1 1 2 + * 2 1 1 + * 2 2 6 + * 3 2 4 + * 4 2 2 + * 3 3 9 + * 4 3 8 + * 4 4 16 + * 5 4 14 + * 6 4 9 + * 7 4 6 + * 8 4 0 + */ + int[] nTypes = new int[8]; + for (int i = 0; i < 64; i++) { + int nWalls = 0; + int nAxis = 0; + for (int n = 0; n < 8; n++) { + int nIndex = getNeighbourIndex(g, i, n); + nTypes[n] = nIndex != -1 ? g[nIndex] : WALL; + if (nTypes[n] == WALL) nWalls++; + } + int score = nWalls; + if (nWalls > 0) { + if (nTypes[0] == WALL || nTypes[7] == WALL) nAxis++; + if (nTypes[1] == WALL || nTypes[6] == WALL) nAxis++; + if (nTypes[2] == WALL || nTypes[5] == WALL) nAxis++; + if (nTypes[4] == WALL || nTypes[3] == WALL) nAxis++; + switch (nAxis) { + case 4: switch (nWalls) { case 4: score = 16; break; case 5: score = 14; break; case 6: score = 9; case 7: score = 6; break; case 8: score = 0; break;}; break; + case 3: switch (nWalls) { case 3: score = 9; break; case 4: score = 8;}; break; + case 2: switch (nWalls) { case 2: score = 6; break; case 3: score = 4; break; case 4: score = 2; }; break; + case 1: switch (nWalls) { case 1: score = 2; break; case 2: score = 1; break;}; break; + }; + } + gameWallWeight[i] = score; + } +} + +/* Evaluate the best move for player type for the given board, doing a depth 1 search */ +static void evalBest(byte[] g, byte type, int depth, /* out [0] best move, [1] minimax */int[] result) { + byte[] tmp = new byte[64]; + byte opponentType = type == WHITE ? BLACK : WHITE; + result[0] = -1; result[1] = Integer.MIN_VALUE; + for (int i = 0; i < 64; i++) { + if (g[i] == EMPTY) { + System.arraycopy(g, 0, tmp, 0, 64); + play(tmp, i, type); + int score = eval(tmp); + if (depth > 1) { + int[] tmpResult = new int[2]; + evalBest(tmp, opponentType, depth - 1, tmpResult); + score = tmpResult[1]; + } + if ((type == WHITE && score > result[1]) || (type == BLACK && score < result[1]) || result[0] == -1) { + result[0] = i; + result[1] = score; + } + } + } +} +}
\ No newline at end of file diff --git a/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/views/BrowserDemoView.java b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/views/BrowserDemoView.java new file mode 100644 index 0000000000..b56d49b02b --- /dev/null +++ b/examples/org.eclipse.swt.examples.browser.demos/src/org/eclipse/swt/examples/browser/demos/views/BrowserDemoView.java @@ -0,0 +1,233 @@ +package org.eclipse.swt.examples.browser.demos.views; + +import org.eclipse.ui.part.*; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.*; +import org.eclipse.swt.browser.*; +import org.eclipse.swt.widgets.*; +import org.eclipse.swt.examples.browser.demos.*; + +public class BrowserDemoView extends ViewPart { + Browser browser = null; + ReversiListener reversiListener; + + final static int TYPE_WELCOME = 1; + final static int TYPE_START = 2; + final static int TYPE_BOARD = 3; + final static int TYPE_BOARD_OVER = 4; + + final static String URL = "http://www.org.eclipse.swt.examples.browser.demos.pawns/"; + static String PLUGIN_PATH = BrowserDemoPlugin.PLUGIN_PATH; + static String CSS_FOLDER = "css1"; + static String URL_CSS = PLUGIN_PATH+CSS_FOLDER+"/style.css"; + static String URL_WELCOME =PLUGIN_PATH+CSS_FOLDER+"/welcome.html"; + + final static String ACTION_START_2_PLAYERS = "actionstart2players"; + final static String ACTION_START_1_PLAYER = "actionstart1player"; + final static String ACTION_WHITE = "actionwhite"; + final static String ACTION_BLACK = "actionblack"; + final static String ACTION_BLACK_COMPUTER = "actionblackcomputer"; + final static String ACTION_THEME = "actiontheme"; + + static byte[][] game = null; + static boolean isWhite = true; + static int cntWhite = 0, cntBlack = 0; + static boolean computer = false; + static int cx, cy; + final static byte EMPTY = 0; + final static byte WHITE = 1; + final static byte BLACK = 2; + final static byte WALL = 3; + + static Pawns ttr = null; + static int[] move = new int[2]; + + public BrowserDemoView() { + } + public void createPartControl(Composite parent) { + try { + browser = new Browser(parent, SWT.NONE); + } catch (SWTError e) { + e.printStackTrace(); + return; + } + reversiListener = new ReversiListener(); + browser.addLocationListener(reversiListener); + browser.setUrl(URL_WELCOME); + + } + private void showMessage(String message) { + MessageDialog.openInformation( + browser.getShell(), + "Browser Demo", + message); + } + public void setFocus() { + browser.setFocus(); + } + + static String getHtml(int type) { + String html = null; + switch (type) { + case TYPE_BOARD: + case TYPE_BOARD_OVER: { + html = "<html><header><link rel=\"stylesheet\" type=\"text/css\" href=\""+URL_CSS+"\"></header><body><div class=\"board\"><table><tbody>"; + String classPlayerWhite = "playerwhite", classPlayerBlack = "playerblack"; + if (type == TYPE_BOARD_OVER) { + if (cntWhite > cntBlack) { + classPlayerWhite += " winner"; + classPlayerBlack += " loser"; + } else { + classPlayerWhite += " loser"; + classPlayerBlack += " winner"; + } + } + for (int i = 0; i < game.length; i++) { + html += "<tr>"; + for (int j = 0; j < game[0].length; j++) { + switch (game[i][j]) { + case EMPTY: html += "<td class=\""+(isWhite ? "whitelink" : "blacklink")+"\"><a href=\""+URL+(isWhite ? ACTION_WHITE : computer ? ACTION_BLACK_COMPUTER : ACTION_BLACK)+"/xx"+i+"yy"+j+"\" class=\"empty\"/></td>"; break; + case WHITE: html += "<td class=\"white\"/>"; break; + case BLACK: html += "<td class=\"black\"/>"; break; + case WALL: html += "<td class=\"wall\"/>"; break; + } + } + html +="</tr>"; + } + html += "</tbody></table></div>"; + html += "<div class=\""+classPlayerWhite+"\">"+cntWhite+"</div>"; + html += "<div class=\""+classPlayerBlack+"\">"+cntBlack+"</div>"; + html += "</body></html>"; + break; + } + } + return html; + } + + public class ReversiListener implements LocationListener { + public void changed(LocationEvent e) { + } + public void changing(LocationEvent e) { + try { + final Browser browser = (Browser)e.widget; + if (e.location.indexOf(ACTION_START_1_PLAYER) != -1 || e.location.indexOf(ACTION_START_2_PLAYERS) != -1) { + computer = e.location.indexOf(ACTION_START_1_PLAYER) != -1; + game = new byte[8][8]; + if (computer) ttr = new Pawns(); + for (int i = 0; i < 5; i++) game[(int)(Math.random()*game.length)][(int)(Math.random()*game[0].length)] = WALL; + e.display.asyncExec(new Runnable() { + public void run() { + browser.setText(getHtml(TYPE_BOARD)); + }}); + e.doit = false; + return; + } + if (e.location.indexOf(ACTION_THEME) != -1) { + int index = e.location.indexOf(ACTION_THEME) + ACTION_THEME.length() + 1; + CSS_FOLDER = e.location.substring(index, index + 4); + URL_CSS = PLUGIN_PATH+CSS_FOLDER+"/style.css"; + URL_WELCOME = PLUGIN_PATH+CSS_FOLDER+"/welcome.html"; + e.display.asyncExec(new Runnable() { + public void run() { + browser.setUrl(URL_WELCOME); + }}); + e.doit = false; + return; + } + byte player = EMPTY; + if (e.location.indexOf(ACTION_WHITE) != -1) player = WHITE; + else if (e.location.indexOf(ACTION_BLACK) != -1) player = BLACK; + if (player != EMPTY) { + int index = e.location.indexOf("xx") + 2; + int x = Integer.parseInt(e.location.substring(index, index + 1)); + index = e.location.indexOf("yy") + 2; + int y = Integer.parseInt(e.location.substring(index, index + 1)); + boolean hasMore = add(x, y, player); + isWhite = player != WHITE; + browser.setText(getHtml(hasMore ? TYPE_BOARD : TYPE_BOARD_OVER)); + if (computer && hasMore && !isWhite) play(e.display, browser, 5000); + e.doit = false; + } + }catch (Exception e1 ) { + e1.printStackTrace(); + } + } + } + + public static boolean add(int x, int y, byte color) { + game[x][y] = color; + int cnt = Math.min(x, y), n = 0; + int other_color = color == WHITE ? BLACK : WHITE; + for (int d = 1; d <= cnt; d++) { + if (game[x-d][y-d] == other_color) n++; + else if (game[x-d][y-d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x-d][y-d] = color; break; } + } + cnt = Math.min(game.length - 1 - x, game[0].length - 1 - y); n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x+d][y+d] == other_color) n++; + else if (game[x+d][y+d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x+d][y+d] = color; break; } + } + cnt = Math.min(game.length - 1 - x, y); n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x+d][y-d] == other_color) n++; + else if (game[x+d][y-d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x+d][y-d] = color; break; } + } + cnt = Math.min(x, game[0].length - 1 - y); n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x-d][y+d] == other_color) n++; + else if (game[x-d][y+d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x-d][y+d] = color; break; } + } + cnt = y; n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x][y-d] == other_color) n++; + else if (game[x][y-d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x][y-d] = color; break; } + } + cnt = game[0].length - 1 - y; n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x][y+d] == other_color) n++; + else if (game[x][y+d] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x][y+d] = color; break; } + } + cnt = x; n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x-d][y] == other_color) n++; + else if (game[x-d][y] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x-d][y] = color; break; } + } + cnt = game.length - 1 - x; n = 0; + for (int d = 1; d <= cnt; d++) { + if (game[x+d][y] == other_color) n++; + else if (game[x+d][y] != color) break; + else { if (n > 0) for (d = 1; d <= n; d++) game[x+d][y] = color; break; } + } + + boolean hasMore = false; + cntWhite = 0; cntBlack = 0; + for (int i = 0; i < game.length; i++) + for (int j = 0; j < game[0].length; j++) { + switch (game[i][j]) { + case EMPTY: hasMore = true; break; + case WHITE: cntWhite++; break; + case BLACK: cntBlack++; break; + } + } + return hasMore; + } + + public static void play(final Display display, final Browser browser, int delay) { + ttr.playRequest(game, BLACK); + display.timerExec(3000, new Runnable() { + public void run() { + ttr.getBestMove(move); + boolean hasMore = add(move[0], move[1], BLACK); + isWhite = true; + browser.setText(getHtml(hasMore ? TYPE_BOARD : TYPE_BOARD_OVER)); + } + }); + } +}
\ No newline at end of file |