Regarding the Game: Understanding the significance of the tic-tac-toe game is essential. Typically, two players engage in a tic-tac-toe game using a 3x3 grid, each represented by symbols such as "X" and "O." Players take turns placing their symbols on the grid, with each player making one move per turn. The game is won when one player's symbols fill a row, column, diagonal, or anti-diagonal on the board.
Note: In this context, we enhance two aspects beyond the conventional game:
Utilizing more than two symbols - such as X, O, #, and more...
Expanding the board dimensions to an
nxn
configuration.
Approach to Design:
Initially, ascertain the key elements:
Board: Responsible for encompassing essential functions such as size initialization, managing the Symbols array, and facilitating symbol placement in designated positions.
Player: The Player class will be associated with the symbol that each participant employs during the game.
Symbols: This category encompasses all available symbols that users can opt for during gameplay.
Game Moderator or Controller: This entity oversees the game's initialization process, the creation of players and their chosen symbols, and the implementation of winning conditions.
Following is the sample UML diagram (Components)
Source Code - git (link)
Would like to delve into the idea of effective success strategies while keeping in mind that there are different methods for putting these strategies into action. Here's an example of one such popular approach
private boolean winnerLogic(int row, int col, Symbol symbol) {
boolean rowMatch = true;
boolean columnMatch = true;
boolean diagonalMatch = true;
boolean antiDiagonalMatch = true;
//row match
for (int i=0; i<board.getSize();i++){
if (board.getSymbol(row,i)==null || board.getSymbol(row,i)!=symbol){
rowMatch =false;
break;
}
}
//col match
for (int i=0; i<board.getSize();i++){
if (board.getSymbol(i,col)==null || board.getSymbol(i,col)!=symbol){
columnMatch =false;
break;
}
}
//Diagonal match
for (int i=0,j=0; i<board.getSize();i++,j++){
if (board.getSymbol(i,j)==null || board.getSymbol(i,j)!=symbol){
diagonalMatch =false;
break;
}
}
//Anti Diagonal match
for (int i=0,j= board.getSize()-1; i<board.getSize();i++,j--){
if (board.getSymbol(i,j)==null || board.getSymbol(i,j)!=symbol){
antiDiagonalMatch =false;
break;
}
}
return rowMatch || columnMatch || diagonalMatch || antiDiagonalMatch;
}
Note: Employing a private access modifier to conceal the internal fields of a class is considered a best practice. Utilize setters and getters to interact with the variable, rather than directly manipulating the class variable.
Conclusion: It is crucial to prioritize the initial design before diving into coding for any problem. The initial design serves as a foundational blueprint, encompassing all necessary elements. Following the design phase, proceed with coding, which may reveal flaws in the initial design. In such instances, return to the design phase and make necessary modifications, iterating this process until the requirements are met.