close

Вход

Забыли?

вход по аккаунту

код для вставкиСкачать
Lecture 11
CS202 Fall 2013
Event Methods
Event contains various methods you can use to get information about events. This example uses a few
of them.
public void start(Stage primaryStage) {
VBox v = new VBox();
Button b = new Button("Click Me!");
Label l = new Label();
b.setOnMouseClicked(e -> {
String info = "Source: " + e.getSource() + "\n" + "Event Type: " + e.getEventType() + "\n" + "Button: " + e.getButton() + "\n";
l.setText(info);
}
);
v.getChildren().add(b);
v.getChildren().add(l);
Scene sc = new Scene(v, 300, 300);
primaryStage.setScene(sc);
primaryStage.show();
}
Menus
• MenuItems are placed in Menus, which are grouped in
MenuBars (think of the typical File/Edit/View menu bar)
• MenuItems trigger events that can be handled with
EventHandlers or by using setters from the GUI component
classes
• setAccelerator() provides hotkeys as an alternative to using the
mouse; very useful for accessibility.
Menu Demo
package application;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class JavaFXMenuDemo extends Application {
@Override
public void start(Stage stage) {
GridPane gp = new GridPane();
Scene scene = new Scene(gp, 300, 300);
scene.getStylesheets().add(
getClass().getResource("application.css").toExternalForm());
stage.setTitle("Menu Sample");
MenuBar menuBar = setUpMenuBar(stage);
gp.getChildren().add(menuBar);
stage.setScene(scene);
stage.show();
}
private MenuBar setUpMenuBar(Stage stage) {
MenuBar menuBar = new MenuBar();
Menu fileMenu = setUpFileMenu();
Menu helpMenu = setUpHelpMenu(stage);
menuBar.getMenus().add(fileMenu);
menuBar.getMenus().add(helpMenu);
return menuBar;
}
Menu Demo
private Menu setUpFileMenu() {
Menu fileMenu = new Menu("File");
MenuItem quitItem = new MenuItem("Quit");
quitItem.setOnAction(e -> {
System.exit(0);
});
quitItem.setAccelerator(new KeyCodeCombination(KeyCode.Q,
KeyCombination.CONTROL_DOWN));
fileMenu.getItems().add(quitItem);
return fileMenu;
}
private Menu setUpHelpMenu(Stage stage) {
Menu helpMenu = new Menu("Help");
MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
Popup popup = new Popup();
// popup.setX(100);
VBox v = new VBox();
v.getStyleClass().add("about");
Text t = new Text("Copyright 2014 by John Hurley");
t.getStyleClass().add("text");
Button okButton = new Button("OK");
v.getChildren().addAll(t, okButton);
okButton.setOnAction(e -> {
popup.hide();
});
popup.getContent().addAll(v);
popup.show(stage);
}
});
aboutItem.setAccelerator(new KeyCodeCombination(KeyCode.A,
KeyCombination.CONTROL_DOWN));
helpMenu.getItems().add(aboutItem);
return helpMenu;
}
Menu Demo
.about{
-fx-background-color: #00BBBB;
-fx-alignment: center;
-fx-padding: 10;
-fx-border-style: solid;
}
FileChooser
• FileChooser is a dialog box that lets the user choose a file to open,
save as , etc.
• FileChooser returns a selected file or an array of selected files
• FileChooser.showOpenDialog() starts in the users' default directory
• Other starting directories can be specified using
setInitialDirectory().
• showOpenMultipleDialog() allows multiple file selections. This
may or may not be appropriate for your task.
• You can limit the files shown by their file name extensions this
way:
fileChooser.getExtensionFilters().addAll(
new FileChooser.ExtensionFilter("BMP", "*.bmp"),
new FileChooser.ExtensionFilter("JPG", "*.jpg"),
new FileChooser.ExtensionFilter("PNG", "*.png"));
FileChooser
• You can often show the contents of a file using a Desktop
object:
Desktop desktop = Desktop.getDesktop();
desktop.open(file);
• The user’s OS will try to choose a way to open the file
(for example, using Paint or a PDF reader), according the
the OS’s defaults and user settings.
• However, this is platform-dependent and may cause
results that don’t work well with your application. It is
much better to code your own ways to deal with opened
files
• The example on the next page will work with text files
only!
FileChooser
package application;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class JavaFXFileChooserDemo extends Application {
@Override
public void start(Stage stage) {
stage.setTitle("Text File Dumper");
VBox vb = new VBox();
Scene scene = new Scene(vb, 300, 300);
scene.getStylesheets().add(
getClass().getResource("application.css").toExternalForm());
stage.setTitle("File Chooser Sample");
Text text = new Text();
MenuBar menuBar = setUpMenuBar(stage, text);
vb.getChildren().add(menuBar);
vb.getChildren().add(text);
stage.setScene(scene);
stage.show();
stage.setScene(scene);
stage.show();
}
private MenuBar setUpMenuBar(Stage stage, Text text) {
MenuBar menuBar = new MenuBar();
Menu fileMenu = setUpFileMenu(stage, text);
Menu helpMenu = setUpHelpMenu(stage);
menuBar.getMenus().add(fileMenu);
menuBar.getMenus().add(helpMenu);
return menuBar;
}
private Menu setUpFileMenu(Stage stage, Text text) {
Menu fileMenu = new Menu("File");
FileChooser
MenuItem openItem = new MenuItem("Open");
openItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
text.setText(getFileContents(file));
}
}
});
openItem.setAccelerator(new KeyCodeCombination(KeyCode.O, KeyCombination.CONTROL_DOWN));
fileMenu.getItems().add(openItem);
MenuItem quitItem = new MenuItem("Quit");
quitItem.setOnAction(e -> {
System.exit(0);
});
quitItem.setAccelerator(new KeyCodeCombination(KeyCode.Q,
KeyCombination.CONTROL_DOWN));
fileMenu.getItems().add(quitItem);
return fileMenu;
}
private Menu setUpHelpMenu(Stage stage) {
Menu helpMenu = new Menu("Help");
MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
Popup popup = new Popup();
// popup.setX(100);
VBox v = new VBox();
v.getStyleClass().add("about");
Text t = new Text("Copyright 2014 by John Hurley");
t.getStyleClass().add("text");
Button okButton = new Button("OK");
v.getChildren().addAll(t, okButton);
okButton.setOnAction(e -> {
popup.hide();
});
popup.getContent().addAll(v);
popup.show(stage);
}
});
aboutItem.setAccelerator(new KeyCodeCombination(KeyCode.A,
KeyCombination.CONTROL_DOWN));
helpMenu.getItems().add(aboutItem);
return helpMenu;
}
FileChooser
private String getFileContents(File file) {
StringBuilder sb = new StringBuilder();
try {
Scanner reader;
reader = new Scanner(file);
// ... Loop as long as there are input lines.
String line = null;
while (reader.hasNextLine()) {
if(!(sb.length()==0)) sb.append("\n");
line = reader.nextLine();
sb.append(line);
}
reader.close();
} catch (IOException ex) {
ex.printStackTrace();
}
return sb.toString();
}
}
Image and ImageView
• Image class constructor uses a URI, not a file or
standard file path, so construct the Image like this:
String imageFileURI = file.toURI().toURL().toExternalForm();
i = new Image(imageFileURI);
ImageView iv = new ImageView(i);
• Use with the Image class
package application;
import java.io.File;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.control.ScrollPane;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyCodeCombination;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.FileChooser;
import javafx.stage.Popup;
import javafx.stage.Stage;
public class JavaFXImageDemo extends Application {
VBox vb;
ScrollPane scrollPane;
StackPane stackPane;
@Override
public void start(Stage stage) {
vb = new VBox();
scrollPane = new ScrollPane();
stackPane = new StackPane();
scrollPane.setPrefHeight(1500);
scrollPane.setContent(stackPane);
StackPane.setAlignment(scrollPane, Pos.BASELINE_CENTER);
//scrollPane.setFitToHeight(true);
//scrollPane.setFitToWidth(true);
Scene scene = new Scene(vb, 500,500);
scene.getStylesheets().add(
getClass().getResource("application.css").toExternalForm());
stage.setTitle("FX Image Demo");
MenuBar menuBar = setUpMenuBar(stage);
vb.getChildren().add(menuBar);
vb.getChildren().add(scrollPane);
stage.setScene(scene);
stage.show();
}
private MenuBar setUpMenuBar(Stage stage) {
MenuBar menuBar = new MenuBar();
Menu fileMenu = setUpFileMenu(stage);
Menu helpMenu = setUpHelpMenu(stage);
menuBar.getMenus().add(fileMenu);
menuBar.getMenus().add(helpMenu);
return menuBar;
}
private Menu setUpFileMenu(Stage stage) {
Menu fileMenu = new Menu("File");
MenuItem openItem = new MenuItem("Open");
openItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
FileChooser fileChooser = new FileChooser();
File file = fileChooser.showOpenDialog(stage);
if (file != null) {
Image i;
try {
String imageFileURI = file.toURI().toURL()
.toExternalForm();
i = new Image(imageFileURI);
ImageView iv = new ImageView(i);
stackPane.getChildren().clear();
stackPane.getChildren().add(iv);
stackPane.autosize();
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
openItem.setAccelerator(new KeyCodeCombination(KeyCode.O,
KeyCombination.CONTROL_DOWN));
fileMenu.getItems().add(openItem);
MenuItem quitItem = new MenuItem("Quit");
quitItem.setOnAction(e -> {
System.exit(0);
});
quitItem.setAccelerator(new KeyCodeCombination(KeyCode.Q,
KeyCombination.CONTROL_DOWN));
fileMenu.getItems().add(quitItem);
return fileMenu;
}
private Menu setUpHelpMenu(Stage stage) {
Menu helpMenu = new Menu("Help");
MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
Popup popup = new Popup();
// popup.setX(100);
VBox v = new VBox();
v.getStyleClass().add("about");
Text t = new Text("Copyright 2014 by John Hurley");
t.getStyleClass().add("text");
Button okButton = new Button("OK");
v.getChildren().addAll(t, okButton);
okButton.setOnAction(e -> {
popup.hide();
});
popup.getContent().addAll(v);
popup.show(stage);
}
});
aboutItem.setAccelerator(new KeyCodeCombination(KeyCode.A,
KeyCombination.CONTROL_DOWN));
helpMenu.getItems().add(aboutItem);
return helpMenu;
}
public static void main(String[] args) {
Application.launch(args);
}
}
GridPane
•
•
GridPane is a Pane that allows you to specify the relative location of controls using
row and column numbers
Column numbers are listed first
Celsius Converter: Version 1
public class CelsiusConverter extends Application{
@Override
public void start(Stage primaryStage) {
GridPane gp = new GridPane();
Scene sc = new Scene(gp);
sc.getStylesheets().add("styles/style.css");
Label lblFahr = new Label("Fahrenheit Value: ");
TextField tfFahr = new TextField();
Label lblCels = new Label("Celsius Value:");
Label lblCelsAns = new Label();
Button btnCalc = new Button("Convert");
btnCalc.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
double cels = (Double.parseDouble(tfFahr.getText())-32)*5/9;
lblCelsAns.setText(String.valueOf(cels));
}
});
gp.getStyleClass().add("pane");
gp.add(lblFahr, 0, 0);
gp.add(tfFahr, 2, 0);
gp.add(lblCels, 0, 1);
gp.add(lblCelsAns, 2, 1);
gp.add(btnCalc, 1, 2);
primaryStage.setScene(sc);
primaryStage.show();
}
}
CelsiusConverter
.pane{
-fx-font-size: 250%;
-fx-padding: 20px;
}
Separate Application Logic From The GUI
• The initial EventHandler examples showed simple responses
coded in the handlers. It is better to separate out any
substantial processing into separate methods, in other
classes, following the general principle of separation of
concerns.
– We may want to reuse code to handle various different events.
– We may want to use the same functionality with a different kind of
GUI
– When we need to change the processing code, it is easier to work with
if it is not mixed with GUI code.
– It's hard to unit test GUIs, so we should get the code that might have
subtle bugs away from the GUI.
Separate Application Logic From The GUI
• Don’t put any substantial processing in the Event Handlers
and don’t access the GUI from the processing code.
• Either
– use separately-defined classes for the GUI app and the processing; or
– In simple cases, use an inner class with processing methods.
Celsius Converter 2.0
• Let's move the conversion calculation to this
class:
package application;
public class CelsiusCalculator {
private final double CONVFACTOR = 5.0/9.0;
private final int FSTART = 32;
public double fToC(double f){
return (f-FSTART) * CONVFACTOR;
}
}
package test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import application.CelsiusCalculator;
Unit Tests
public class CelsiusCalculatorTester {
@Test
public void testFreezing() {
CelsiusCalculator calc = new CelsiusCalculator();
double freezingF = 32;
double freezingC = 0;
double freezingResult = calc.fToC(freezingF);
// assertEquals for two doubles takes a delta as the third argument!
assertEquals(freezingResult, freezingC, 0.1);
}
@Test
public void testBoiling() {
CelsiusCalculator calc = new CelsiusCalculator();
double boilingF = 212;
double boilingC = 100;
double boilingResult = calc.fToC(boilingF);
assertEquals(boilingResult, boilingC, 0.1);
}
@Test
public void testNegForty() {
CelsiusCalculator calc = new CelsiusCalculator();
double negForty = -40;
double negFortyResult = calc.fToC(negForty);
assertEquals(negFortyResult, negForty, 0.1);
}
}
CelsiusConverterGUI
package application;
import javafx.application.Application;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
public class CelsiusConverterGUI extends Application{
@Override
public void start(Stage primaryStage) {
CelsiusCalculator calc = new CelsiusCalculator();
GridPane gp = new GridPane();
Scene sc = new Scene(gp);
sc.getStylesheets().add("styles/style.css");
Label lblFahr = new Label("Fahrenheit Value: ");
TextField tfFahr = new TextField();
Label lblCels = new Label("Celsius Value:");
Label lblCelsAns = new Label();
Button btnCalc = new Button("Convert");
btnCalc.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<Event>(){
@Override
public void handle(Event event) {
double cels = calc.fToC(Double.parseDouble(tfFahr.getText()));
lblCelsAns.setText(String.valueOf(cels));
}
});
gp.getStyleClass().add("pane");
gp.add(lblFahr, 0, 0);
gp.add(tfFahr, 2, 0);
gp.add(lblCels, 0, 1);
gp.add(lblCelsAns, 2, 1);
gp.add(btnCalc, 1, 2);
primaryStage.setScene(sc);
primaryStage.show();
}
}
Separate Application Logic From The GUI
As your applications get larger, you will need to think about how to organize
them into packages. Eclipse creates a Main.java and application.css for
JavaFX in the application package. There are other reasonable ways to
structure a GUI app, but here is one good way.
Separate Application Logic From The GUI
package application;
import gui.TicTacToePane;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
try {
TicTacToePane root = new TicTacToePane();
Scene scene = new Scene(root,200,200);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setTitle("TicTacToe");
primaryStage.setScene(scene);
primaryStage.show();
root.startGame();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
Separate Application Logic From The GUI
*{
-fx-font-size: 300.0%;
-fx-alignment: center;
}
.leftAndBottomBorder{
-fx-border-style: none none solid solid;
}
.bottomBorder{
-fx-border-style: none none solid none;
}
.leftBorder{
-fx-border-style: none none none solid;
}
.victory{
-fx-background-color: #FF0000;
}
Separate Application Logic From The GUI
package gui;
import tictactoeFX.Coordinate;
import tictactoeFX.Game;
import javafx.event.EventHandler;
import javafx.scene.control.Label;
import javafx.scene.input.InputEvent;
import javafx.scene.layout.GridPane;
public class TicTacToePane extends GridPane {
Label[][] labels;
Game g;
public void startGame() {
setUpLabels();
g = new Game();
}
private void setUpLabels() {
labels = new Label[3][3];
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++) {
Label l = new Label();
setUpLabel(l, row, col);
labels[row][col] = l;
add(l, col, row);
}
}
private void setUpLabel(final Label l, final int row, final int col) {
l.setPrefHeight(75);
l.setPrefWidth(75);
l.setOnMouseClicked(new EventHandler<InputEvent>() {
@Override
public void handle(InputEvent arg0) {
if (!g.gameOver()) {
g.makePlayerMove(row, col);
l.setText("X");
}
if (!g.gameOver()) {
Coordinate c = g.makeAutoMove();
labels[c.getRow()][c.getCol()].setText("O");
}
}
});
if (row < 2 && col > 0)
l.getStyleClass().add("leftAndBottomBorder");
if (row < 2 && col == 0)
l.getStyleClass().add("bottomBorder");
if (row == 2 && col > 0)
l.getStyleClass().add("leftBorder");
}
}
Separate Application Logic From The GUI
package test;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import tictactoeFX.Coordinate;
import tictactoeFX.SolverImpl;
import tictactoeFX.Game.Turn;
public class SolverTest {
@Test
public final void testFirstMoveToCenterIfAvailable() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{' ', ' ', 'X'}, {' ', ' ', ' '}, {' ', ' ', ' '}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 1);
assertEquals(c.getCol(), 1);
}
@Test
public final void testTakeRowVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{'X', ' ', 'X'}, {' ', ' ', 'X'} ,{'O', ' ', 'O'}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 2);
assertEquals(c.getCol(), 1);
}
@Test
public final void testTakeColVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{'O', 'X', ' '}, {'O', 'X', ' '}, {' ', ' ', 'X'}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 2);
assertEquals(c.getCol(), 0);
}
@Test
public final void testTakeDiagVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{'O', 'X', 'O'}, {'X', 'O', ' '}, {' ', ' ', ' '}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 2);
assertEquals(c.getCol(), 0);
}
Separate Application Logic From The GUI
@Test
public final void testPreventEnemyRowVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{' ', ' ', ' '}, {'O', ' ', ' '} ,{'X', ' ', 'X'}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 2);
assertEquals(c.getCol(), 1);
}
@Test
public final void testPreventEnemyColVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{'X', ' ', 'O'}, {' ', ' ', 'X'} ,{'X', ' ', 'O'}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 1);
assertEquals(c.getCol(), 0);
}
@Test
public final void testPreventEnemyDiagVictory() {
SolverImpl solver = new SolverImpl();
Character[][] board = {{'X', ' ', 'O'}, {'O', ' ', ' '} ,{'X', ' ', 'X'}};
Coordinate c = solver.getMove('O', Turn.O, board);
assertEquals(c.getRow(), 1);
assertEquals(c.getCol(), 1);
}
}
Separate Application Logic From The GUI
package tictactoeFX;
public class Coordinate {
int row;
int col;
public Coordinate(int rowIn, int colIn){
row = rowIn;
col = colIn;
}
public int getRow(){
return row;
}
public int getCol(){
return col;
}
}
Separate Application Logic From The GUI
package tictactoeFX;
public class Game {
private TicTacToeSolver oPlayer;
public enum Turn {
X, O
};
private Turn turn;
private Character[][] board;
Turn is an enum, since there are only two possibilities
The board is represented by a 2D array of Characters
public Game() {
oPlayer = new SolverImpl();
turn = Turn.X;
board = new Character[3][3];
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++)
board[row][col] = ' ';
}
public void makePlayerMove(int row, int col) {
if (turn == Turn.X && board[row][col] == ' ') {
board[row][col] = 'X';
}
}
public Coordinate makeAutoMove() {
Coordinate oSquare = oPlayer.getMove('O', turn, board);
int row = oSquare.getRow();
int col = oSquare.getCol();
board[row][col] = 'O';
if (!oPlayer.checkForVictory('O', board)) {
turn = Turn.X;
}
return oSquare;
}
Set a value in board when a move is made
Call the solver when the autoplayer is due
To move
public boolean boardFull(){
for(int rowCounter =0; rowCounter < board.length; rowCounter++)
for(int colCounter =0; colCounter < board[0].length; colCounter++)
if(board[rowCounter][colCounter] == ' ') return false;
return true;
}
public boolean gameOver(){
if(oPlayer.checkForVictory('O', board) || oPlayer.checkForVictory('X', board) || boardFull()) return true;
return false;
}
}
Separate Application Logic From The GUI
package solver;
import tictactoeFX.Coordinate;
import tictactoeFX.Game;
import tictactoeFX.Game.Turn;
public class SolverImpl implements TicTacToeSolver {
@Override
public Coordinate getMove(char p, Turn turn, Character[][] board) {
Character[][] newBoard;
// if a one-move victory is available, choose the move
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
newBoard = copyBoard(board);
if (newBoard[row][col] == ' ') {
newBoard[row][col] = p;
if (checkForVictory(p, newBoard))
return new Coordinate(row, col);
}
}
}
if (p == 'O')
p = 'X';
else
p = 'O';
// if the enemy can win in one move, block the move
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
newBoard = copyBoard(board);
if (newBoard[row][col] == ' ') {
newBoard[row][col] = p;
if (checkForVictory(p, newBoard))
return new Coordinate(row, col);
}
}
}
// take the center square if available
if (board[1][1] == ' ')
return new Coordinate(1, 1);
// take a corner if available
int[] begEnd = { 0, 2 };
for (int i : begEnd) {
if (board[i][0] == ' ')
return new Coordinate(i, 0);
if (board[i][2] == ' ')
return new Coordinate(i, 2);
}
Separate Application Logic From The GUI
// take whatever is left
for (int row = 0; row < 3; row++)
for (int col = 0; col < 3; col++)
if (board[row][col] == ' ')
return new Coordinate(row, col);
// if board is full
return null;
}
private Character[][] copyBoard(Character[][] board) {
int numRows = board.length;
int numCols = board[0].length;
Character[][] newBoard = new Character[numRows][numCols];
for (int row = 0; row < numRows; row++)
for (int col = 0; col < numCols; col++)
newBoard[row][col] = new Character(board[row][col]);
return newBoard;
}
private boolean checkForRowVictory(char p, Character[][] board) {
for (int row = 0; row < 3; row++)
if (board[row][0] == p && board[row][1] == p && board[row][2] == p)
return true;
return false;
}
private boolean checkForColVictory(char p, Character[][] board) {
for (int col = 0; col < 3; col++)
if (board[0][col] == p && board[1][col] == p && board[2][col] == p)
return true;
return false;
}
private boolean checkForDiagonalVictory(char p, Character[][] board) {
if (board[1][1] != p)
return false;
if ((board[0][0] == p && board[2][2] == p)
|| (board[0][2] == p && board[2][0] == p)) {
return true;
}
return false;
}
public boolean checkForVictory(char p, Character[][] board) {
if (checkForRowVictory(p, board) || checkForColVictory(p, board)
|| checkForDiagonalVictory(p, board))
return true;
return false;
}
Separate Application Logic From The GUI
package solver;
import tictactoeFX.Coordinate;
import tictactoeFX.Game;
import tictactoeFX.Game.Turn;
public interface TicTacToeSolver {
public Coordinate getMove(char p, Turn turn, Character[][] board);
public boolean checkForVictory(char p, Character[][] board);
}
1/--страниц
Пожаловаться на содержимое документа