/*
* Copyright 2011 Vancouver Ywebb Consulting Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package ywb.c;
import java.util.ArrayList;
import ywb.c.tic.Logic;
import ywb.c.tic.XY;
import ywb.c.ui.ImageButton;
import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.MouseDownEvent;
import com.google.gwt.event.dom.client.MouseDownHandler;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
public class TicTacToe implements EntryPoint {
public static int TYPE_AI_FIRST = 0;
public static int TYPE_PLAYER_FIRST = 1;
public static int TYPE_2PLAYERS = 2;
/**
* <pre>
* 0 = 00,
* 1 = 01,
* 2 = 02,
* 3 = 10,
* 4 = 11,
* 5 = 12,
* 6 = 20,
* 7 = 21,
* 8 = 22
* </pre>
*/
/**
*
*/
private Combination combinaton = new Combination();
private final Logic logic = new Logic();
public static enum Side {
_, X, O
}
Side[][] cellValue = new Side[3][3];
RootPanel[][] cellPanel = new RootPanel[3][3];
PushButton[][] cellButton = new PushButton[3][3];
Image[][] cellImg = new Image[3][3];
final String X = "images/x.png";
final String O = "images/o.png";
final String _ = "images/blank.png";
int type;
int turn;
boolean win = false;
/**
* This is the entry point method.
*/
public void onModuleLoad() {
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
cellPanel[i][j] = RootPanel.get("cell" + i + j);
cellImg[i][j] = new Image(_);
cellButton[i][j] = new PushButton(cellImg[i][j], CLICKHANDLER);
cellPanel[i][j].add(cellButton[i][j]);
}
}
RootPanel controlPanel = RootPanel.get("control");
VerticalPanel controlPanelH = new VerticalPanel();
final UiResources RES = UiResources.INSTANCE;
final ImageButton btn2Players = new ImageButton(RES.btn2PlayersOn());
final ImageButton btnAiFirst = new ImageButton(RES.btnPlaybookFirst());
final ImageButton btnPlayerFirst = new ImageButton(RES.btnYouFirst());
btn2Players.addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
btn2Players.setResource(RES.btn2PlayersOn());
btnAiFirst.setResource(RES.btnPlaybookFirst());
btnPlayerFirst.setResource(RES.btnYouFirst());
reset(TYPE_2PLAYERS);
}
});
controlPanelH.add(btn2Players);
btnAiFirst.addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
btn2Players.setResource(RES.btn2Players());
btnAiFirst.setResource(RES.btnPlaybookFirstOn());
btnPlayerFirst.setResource(RES.btnYouFirst());
reset(TYPE_AI_FIRST);
}
});
controlPanelH.add(btnAiFirst);
btnPlayerFirst.addMouseDownHandler(new MouseDownHandler() {
@Override
public void onMouseDown(MouseDownEvent event) {
btn2Players.setResource(RES.btn2Players());
btnAiFirst.setResource(RES.btnPlaybookFirst());
btnPlayerFirst.setResource(RES.btnYouFirstOn());
reset(TYPE_PLAYER_FIRST);
}
});
controlPanelH.add(btnPlayerFirst);
controlPanel.add(controlPanelH);
reset(TYPE_2PLAYERS);
}
void move(XY obj, Side side, boolean isAiMove) {
if (win) {
return;
}
if (!isEmpty(obj.x, obj.y)) {
return;
}
cellValue[obj.x][obj.y] = side;
if (!isAiMove) {
combinaton.addToRows(obj);
combinaton.debug();
}
if (side == Side.X) {
// if (side == 1) {
cellImg[obj.x][obj.y].setUrl(X);
} else if (side == Side.O) {
// } else if (side == 2) {
cellImg[obj.x][obj.y].setUrl(O);
}
XY xyWinner = winner();
win = (xyWinner != null);
if (win) {
// ArrayList<Row> rows = combinaton.getRows(xyWinner);
ArrayList<XY> winningRow = getWinningRow(xyWinner);
System.out.println("We have a WINNER @" + xyWinner + ", row " + winningRow + ". Do action here.");
repaintOnWin(winningRow);
}
++turn;
if (isAiMove()) {
aiMove();
}
}
private void repaintOnWin(ArrayList<XY> winningRow){
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
cellImg[i][j].getElement().getStyle().setOpacity(0.4);
}
}
for (XY xy : winningRow) {
cellImg[xy.x][xy.y].getElement().getStyle().setOpacity(1);
}
}
private ArrayList<XY> getWinningRow(XY w) {
Side side = cellValue[w.x][w.y];
ArrayList<XY> reslt = new ArrayList<XY>();
for (int i = 0; i < 3; i++) {
if (cellValue[i][w.y] == side) {
reslt.add(new XY(i, w.y));
}
}
if (reslt.size() == 3) {
return reslt;
}
reslt.clear();
for (int i = 0; i < 3; i++) {
if (cellValue[w.x][i] == side) {
reslt.add(new XY(w.x, i));
}
}
if (reslt.size() == 3) {
return reslt;
}
reslt.clear();
if (cellValue[0][0] == side && cellValue[1][1] == side && cellValue[2][2] == side) {
reslt.add(new XY(0, 0));
reslt.add(new XY(1, 1));
reslt.add(new XY(2, 2));
return reslt;
}
reslt.clear();
if (cellValue[0][2] == side && cellValue[1][1] == side && cellValue[2][0] == side) {
reslt.add(new XY(0, 2));
reslt.add(new XY(1, 1));
reslt.add(new XY(2, 0));
return reslt;
}
return null;
}
void reset(int type) {
combinaton.reset();
this.type = type;
this.turn = 0;
this.win = false;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
cellValue[i][j] = Side._;
cellImg[i][j].setUrl(_);
cellImg[i][j].getElement().getStyle().setOpacity(1);
}
}
if (isAiMove()) {
aiMove();
}
}
boolean isAiMove() {
if (win) {
return false;
} else if ((type == TYPE_AI_FIRST) && ((turn & 1) == 0)) {
return true;
} else if ((type == TYPE_PLAYER_FIRST) && ((turn & 1) != 0)) {
return true;
} else {
return false;
}
}
void debug() {
System.out.println("-------------");
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
System.out.print(i + "," + j + "=" + cellValue[i][j] + "\t");
}
System.out.println();
}
}
XY randomSpot(int retryCount) {
int x = Random.nextInt(3);
int y = Random.nextInt(3);
if (isEmpty(x, y)) {
return new XY(x, y);
} else if (retryCount < 5) {
return randomSpot(++retryCount);
} else {
boolean iterateReverse = Random.nextBoolean();
if (iterateReverse) {
for (int i = 2; i > -1; --i) {
for (int k = 2; k > -1; --k) {
if (isEmpty(i, k)) {
return new XY(i, k);
}
}
}
} else {
for (int i = 0; i < 3; ++i) {
for (int k = 0; k < 3; ++k) {
if (isEmpty(i, k)) {
return new XY(i, k);
}
}
}
}
}
throw new RuntimeException("all spots are filled");
}
void aiMove() {
// XY xy = logic.move(turnToSide(turn), cellValue);
// move(xy.x, xy.y, turnToSide(turn));
debug();
Timer t = new Timer() {
public void run() {
XY xy = null;
ArrayList<XY> potentialWins = combinaton.getPotentialWin();
System.out.println("getPotentialWin=" + potentialWins);
for (XY p : potentialWins) {
if (isEmpty(p.x, p.y)) {
xy = p;
break;
}
}
System.out.println("SINGLE PotentialWin=" + xy);
if (xy == null) {
xy = randomSpot(0);
}
move(xy, turnToSide(turn), true);
}
};
t.schedule(400);
}
private boolean isEmpty(int x, int y) {
return (cellValue[x][y] == Side._);
}
XY winner() {
Side side;
for (int i = 0; i < 3; ++i) {
side = winTest(i, 0, 0, 1);
if (side != Side._) {
XY xy = new XY(i, 0);
return xy;
}
side = winTest(0, i, 1, 0);
if (side != Side._) {
XY xy = new XY(0, i);
return xy;
}
}
side = winTest(0, 0, 1, 1);
if (side != Side._) {
XY xy = new XY(0, 0);
return xy;
}
side = winTest(0, 2, 1, -1);
if (side != Side._) {
XY xy = new XY(0, 2);
return xy;
}
return null;
}
Side winTest(int x, int y, int dx, int dy) {
if (cellValue[x][y] != cellValue[x + dx][y + dy]) {
return Side._;
}
if (cellValue[x][y] != cellValue[x + dx + dx][y + dy + dy]) {
return Side._;
}
return cellValue[x][y];
}
final ClickHandler CLICKHANDLER = new ClickHandler() {
@Override
public void onClick(ClickEvent event) {
if (isAiMove()) {
return;
}
PushButton button = (PushButton) event.getSource();
int myI = -1, myJ = -1;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
if (button == cellButton[i][j]) {
myI = i;
myJ = j;
}
}
}
move(new XY(myI, myJ), turnToSide(turn), false);
}
};
Side turnToSide(int turn) {
return ((turn & 1) == 0) ? Side.X : Side.O;
// return ((turn & 1) == 0) ? 1 : 2;
}
}