Home > OS >  Getting text from buttons in an array then concating all the values into a string
Getting text from buttons in an array then concating all the values into a string

Time:12-15

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 game

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);
     }
    

    }

  • Related