diff --git a/README.md b/README.md index 09e3a9c..f264a54 100644 --- a/README.md +++ b/README.md @@ -45,4 +45,8 @@ While doing Step 6, I learned these things: 3. Smartly think of handling concurrent request without causing deadlock (Ex here is if we wanted to undo the suggested move , then high possibility is that parallel request can create deadlocks) -Step 7: Making tests extensible, we now don't rely on AiEngine to suggest move, as our main focus is to test the moves and rules. \ No newline at end of file +Step 7: Making tests extensible, we now don't rely on AiEngine to suggest move, as our main focus is to test the moves and rules. + +Step 8: Using Prototype Design Pattern: It is used when we wanted to deep or shallow clone the object. It is beneficial when new Object creation is expensive + +Step 9: We used Lambda functions to adhere to the DRY principle. diff --git a/api/RuleEngine.java b/api/RuleEngine.java index f5757c2..3f171a7 100644 --- a/api/RuleEngine.java +++ b/api/RuleEngine.java @@ -4,70 +4,29 @@ import game.Board; import game.GameState; +import java.util.function.BiFunction; +import java.util.function.Function; + public class RuleEngine { public GameState getState(Board board){ if(board instanceof TicTacToeBoard board1) { - boolean rowComplete = true; - for (int i = 0; i < 3; i++) { - String firstCharacter = board1.getSymbol(i,0); - rowComplete = firstCharacter!=null; - if(firstCharacter!=null){ - for (int j = 1; j < 3; j++) { - if (!firstCharacter.equals(board1.getSymbol(i,j))) { - rowComplete = false; - break; - } - } - } - if (rowComplete) { - return new GameState(true, firstCharacter); - } - } - boolean colComplete = true; - for (int i = 0; i < 3; i++) { - String firstCharacter = board1.getSymbol(0,i); - colComplete = firstCharacter!=null; - if(firstCharacter!=null){ - for (int j = 1; j < 3; j++) { - if (!firstCharacter.equals(board1.getSymbol(j,i))) { - colComplete = false; - break; - } - } - } - if (colComplete) { - return new GameState(true, firstCharacter); - } - } - String firstCharacter = board1.getSymbol(0,0); - boolean diagonalComplete = firstCharacter!=null; - if(firstCharacter!=null){ - for (int i = 1; i < 3; i++) { - if (!firstCharacter.equals(board1.getSymbol(i,i))) { - diagonalComplete = false; - break; - } - } - } + BiFunction getRow = board1::getSymbol; + BiFunction getCol = (i,j)->board1.getSymbol(j,i); + Function getDiagonal = (i)->board1.getSymbol(i,i); + Function getRevDiagonal = (i)->board1.getSymbol(i,3-i-1); - if (diagonalComplete) { - return new GameState(true, firstCharacter); - } - firstCharacter = board1.getSymbol(0,2); - boolean reverseDiagonalComplete = firstCharacter!=null; - if(firstCharacter!=null){ - for (int i = 1; i < 3; i++) { - if (!firstCharacter.equals(board1.getSymbol(i ,3 - i - 1))) { - reverseDiagonalComplete = false; - break; - } - } - } + GameState rowWin = outerTraversal(getRow); + if(rowWin.isOver()) return rowWin; - if (reverseDiagonalComplete) { - return new GameState(true, firstCharacter); - } + GameState colWin = outerTraversal(getCol); + if(colWin.isOver()) return colWin; + + GameState diagonalWin = traverse(getDiagonal); + if(diagonalWin.isOver()) return diagonalWin; + + GameState reverseDiagonalWin = traverse(getRevDiagonal); + if(reverseDiagonalWin.isOver()) return reverseDiagonalWin; int count=0; for (int i = 0; i < 3; i++) { @@ -87,4 +46,33 @@ public GameState getState(Board board){ return new GameState(true, "-"); } } + + public GameState outerTraversal(BiFunction next){ + GameState result = new GameState(false, "-"); + for (int i = 0; i < 3; i++) { + int finalI = i; + Function nextValue = (j) -> next.apply(finalI,j); + GameState traversal = traverse(nextValue); + if(traversal.isOver()) { + result = traversal; + break; + } + } + return result; + } + + public GameState traverse(Function next){ + GameState result = new GameState(false, "-"); + boolean possibleStreak = true; + for (int i = 0; i < 3; i++) { + if (next.apply(i)== null || !next.apply(0).equals(next.apply(i))) { + possibleStreak = false; + break; + } + } + if (possibleStreak) { + result = new GameState(true, next.apply(0)); + } + return result; + } }