I have a list of buttons that I use as tiles for my tic tac toe game and I want to make a method to check for a tie which would basically check if the board is full and there is no winner then it is a tie.
I want to grab the text from all the buttons and concat it all into 1 string and when that string's length is 9 and there isn't a winner then it is a tie.
my current method works but I was wondering if there's anyway to be more efficient with it by either using a loop or something
code for initializing the game
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
buttons = new ArrayList<>(Arrays.asList(button1,button2,button3,button4,button5,button6,button7,button8,button9));
buttons.forEach(button ->{
setupButton(button);
button.setFocusTraversable(false);
button.setText("");
});
}
code to check for tie
line2 = button1.getText() button2.getText() button3.getText() button4.getText() button5.getText() button6.getText() button7.getText() button8.getText() button9.getText();
if ((line2.length()) == 9 && winner == null) {
ties ;
tiesText.setText("" ties);
disableAllButtons();
newGame(null);
}
CodePudding user response:
You could use a counter and increment it on button click. If the counter is 9 it's a tie.
If you want sticking to the buttontext you can use a foreach loop like :
line2 = "";
foreach (Button button : buttons){
line2 = button.getText();
}
CodePudding user response:
You could create a listener on a concatenated string binding, then use that to monitor the concatenated text of all buttons.
For example:
StringExpression state = Bindings.concat(
board.getChildren().stream()
.map(node -> ((Button) node).textProperty())
.toArray()
);
state.addListener((observable, oldState, newState) ->
handleStateChange(newState)
);
This might be a little bit more complicated than necessary. For a basic solution, it is just fine to react to the button clicks and update the state there in a loop (as in
Example in context
Uses James' suggestion of checking lines for tie detection).
Uses Java 17 features.
import javafx.application.; import javafx.beans.binding.; import javafx.geometry.Insets; import javafx.scene.; import javafx.scene.control.; import javafx.scene.layout.TilePane; import javafx.stage.*;
public class OohhsAndExes extends Application { private static final int NUM_SQUARES = 9;
private static final String X = "X"; private static final String O = "O"; private static final String TIE = "-"; private static final String NONE = " "; private String nextPlayer = X; private Scene scene; private static final int[][] LINES = { {1,2,3}, {4,5,6}, {7,8,9}, // horizontal {1,4,7}, {2,5,8}, {3,6,9}, // vertical {1,5,9}, {3,5,7} // diagonal }; public void start(Stage stage) { scene = new Scene(newGame()); stage.setScene(scene); stage.setTitle("Noughts and Crosses"); stage.show(); } private Parent newGame() { TilePane board = createBoard(); if (scene != null) { scene.setRoot(board); } return board; } private TilePane createBoard() { TilePane board = new TilePane(10, 10); board.setStyle("-fx-base: antiquewhite; -fx-font-size: 30;"); board.setPadding(new Insets(10)); board.setPrefColumns(3); board.setMinSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE); board.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE); for (int i = 0; i < NUM_SQUARES; i ) { board.getChildren().add(createSquare()); } StringExpression state = Bindings.concat( board.getChildren().stream() .map(node -> ((Button) node).textProperty()) .toArray() ); state.addListener((observable, oldState, newState) -> handleStateChange(newState) ); return board; } private Button createSquare() { final Button square = new Button(NONE); square.setMinSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE); square.setPrefSize(65, 65); square.setMaxSize(Control.USE_PREF_SIZE, Control.USE_PREF_SIZE); square.setOnAction(e -> takeTurn(square)); return square; } private void takeTurn(Button square) { square.setText(nextPlayer); nextPlayer = X.equals(nextPlayer) ? O : X; } private void handleStateChange(String state) { int nTies = 0; for (int[] line : LINES) { String result = checkResult(line, state); switch (result) { case X -> { endGame(X); return; } case O -> { endGame(O); return; } case TIE -> nTies ; } } if (nTies == LINES.length - 1) { endGame(TIE); } } private String checkResult(int[] line, String state) { int numX = 0, numO = 0; for (int j : line) { String cellState = state.substring(j - 1, j); switch (cellState) { case X -> numX ; case O -> numO ; } } if (numX == 3) { return X; } else if (numO == 3) { return O; } if (numX > 0 && numO > 0) { return TIE; } return NONE; } private void endGame(String result) { String msg; msg = switch (result) { case X -> X " won"; case O -> O " won"; case TIE -> "Tie"; default -> "unexpected result"; }; Alert resultDialog = new Alert( Alert.AlertType.CONFIRMATION, """ Play again? %s will start first. """.formatted(X.equals(nextPlayer) ? O : X) ); resultDialog.setHeaderText(msg); resultDialog.setTitle("Game Over"); Window owner = scene.getWindow(); resultDialog.initOwner(owner); // we do this in a run later as we want the board state to update for the last interaction // before displaying the result dialog. Platform.runLater(() -> resultDialog.showAndWait() .filter(response -> response == ButtonType.OK) .ifPresentOrElse( response -> newGame(), Platform::exit ) ); } public static void main(String[] args) { launch(args); }
}