-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
sw_concepts: replace code examples slides with code examples in code
Only seeing part of the example was difficult. And the slides did not offer enough space to show a meaningful part of an example. So now the students can browse a normal maven repo and look for the patterns they learned.
- Loading branch information
Showing
57 changed files
with
3,004 additions
and
411 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,6 @@ | ||
include(js_document) | ||
|
||
js_slides(sw_concept_slides sw_concept_slides.md) | ||
js_slides(sw_concept_code_examples sw_concept_code_examples.md) | ||
|
||
file(GLOB_RECURSE code RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "code/*") | ||
js_add_to_global_archive_file_list(${code}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 127 additions & 0 deletions
127
.../pattern-examples/src/main/java/ch/scs/jumpstart/pattern/examples/checkers/GameLogic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
package ch.scs.jumpstart.pattern.examples.checkers; | ||
|
||
import ch.scs.jumpstart.pattern.examples.checkers.dom.*; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.board.Board; | ||
import ch.scs.jumpstart.pattern.examples.checkers.movevalidator.MoveValidator; | ||
import ch.scs.jumpstart.pattern.examples.checkers.movevalidator.NoOtherMoveToJumpPossible; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.Console; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
@SuppressWarnings("ClassCanBeRecord") | ||
public class GameLogic { | ||
private final Console console; | ||
private final Board board; | ||
private final List<MoveValidator> moveValidators; | ||
private final MoveExecutor moveExecutor; | ||
private final NoOtherMoveToJumpPossible noOtherMoveToJumpPossible; | ||
private final WinCondition winCondition; | ||
|
||
public GameLogic( | ||
Console console, | ||
Board board, | ||
List<MoveValidator> moveValidators, | ||
MoveExecutor moveExecutor, | ||
NoOtherMoveToJumpPossible noOtherMoveToJumpPossible, | ||
WinCondition winCondition) { | ||
this.console = console; | ||
this.board = board; | ||
this.moveValidators = moveValidators; | ||
this.moveExecutor = moveExecutor; | ||
this.noOtherMoveToJumpPossible = noOtherMoveToJumpPossible; | ||
this.winCondition = winCondition; | ||
} | ||
|
||
public void run() { | ||
Player currentPlayer = Player.PLAYER_RED; | ||
while (true) { | ||
Player otherPlayer = | ||
currentPlayer == Player.PLAYER_RED ? Player.PLAYER_WHITE : Player.PLAYER_RED; | ||
console.print( | ||
currentPlayer | ||
+ ", make your move. Or type 'undo' to go back to the start of the turn of " | ||
+ otherPlayer); | ||
if (doPlayerMove(currentPlayer)) { | ||
return; | ||
} | ||
if (currentPlayer == Player.PLAYER_WHITE) { | ||
currentPlayer = Player.PLAYER_RED; | ||
} else { | ||
currentPlayer = Player.PLAYER_WHITE; | ||
} | ||
} | ||
} | ||
|
||
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.CognitiveComplexity"}) | ||
private boolean doPlayerMove(Player player) { | ||
BoardCoordinates startCoordinatesForMultipleJump = null; | ||
while (true) { | ||
String userInput = console.getUserInput(); | ||
if ("undo".equals(userInput.toLowerCase().trim())) { | ||
try { | ||
Player playerOfUndoneMove = board.undoLastTurn(); | ||
if (playerOfUndoneMove.equals(player)) { | ||
continue; | ||
} else { | ||
return false; | ||
} | ||
} catch (Board.NoPreviousMovesException e) { | ||
console.print("There were no previous moves to undo. Please make a move."); | ||
continue; | ||
} | ||
} | ||
Move move; | ||
try { | ||
move = Move.parse(player, userInput); | ||
} catch (IllegalArgumentException e) { | ||
console.print("Invalid input, try again"); | ||
continue; | ||
} | ||
if (startCoordinatesForMultipleJump != null | ||
&& !startCoordinatesForMultipleJump.equals(move.start())) { | ||
console.print("For a multiple jump move, the same piece has to be used. Try again"); | ||
continue; | ||
} | ||
Optional<Piece> pieceAtStart = board.getPieceAt(move.start()); | ||
if (!moveValidators.stream().allMatch(moveValidator -> moveValidator.validate(move, board))) { | ||
console.print("Invalid move, try again"); | ||
continue; | ||
} | ||
|
||
Move executedMove = moveExecutor.executeMove(move); | ||
|
||
boolean hasPlayerWon = winCondition.hasPlayerWon(player, board); | ||
if (hasPlayerWon) { | ||
console.print("Congratulations, player " + player + " has won"); | ||
return true; | ||
} | ||
|
||
if (executedMove.jumpGambleResult() == JumpGambleResult.WON) { | ||
console.print("The gamble has been won, " + player + " can play again."); | ||
console.print( | ||
player + ", make your move. Or type 'undo' to go back to the start of your turn."); | ||
continue; | ||
} | ||
|
||
Optional<Piece> pieceAtEnd = board.getPieceAt(move.end()); | ||
boolean wasKingCreated = wasKingCreated(pieceAtStart.orElse(null), pieceAtEnd.orElse(null)); | ||
if (wasKingCreated) { | ||
return false; | ||
} | ||
if (!move.isJumpMove() | ||
|| !noOtherMoveToJumpPossible.jumpMovePossibleFrom(move.end(), board)) { | ||
return false; | ||
} | ||
console.print("Multiple jump move for " + player + ". Enter your next jump."); | ||
console.print("Or type 'undo' to go back to the start of your turn."); | ||
startCoordinatesForMultipleJump = move.end(); | ||
} | ||
} | ||
|
||
private boolean wasKingCreated(Piece pieceAtStart, Piece pieceAtEnd) { | ||
if (pieceAtStart == null || pieceAtEnd == null) { | ||
return false; | ||
} | ||
return !pieceAtStart.isKing() && pieceAtEnd.isKing(); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
.../code/pattern-examples/src/main/java/ch/scs/jumpstart/pattern/examples/checkers/Main.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package ch.scs.jumpstart.pattern.examples.checkers; | ||
|
||
import ch.scs.jumpstart.pattern.examples.checkers.dom.board.Board; | ||
import ch.scs.jumpstart.pattern.examples.checkers.movevalidator.*; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.BoardPrinter; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.CoinTosser; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.Console; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.PointsCalculator; | ||
import java.util.List; | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
GameLogic gameLogic = | ||
createGameLogic(Console.getInstance(), new CoinTosser(new PointsCalculator())); | ||
|
||
gameLogic.run(); | ||
} | ||
|
||
public static GameLogic createGameLogic(Console console, CoinTosser coinTosser) { | ||
Board board = new Board(); | ||
BoardPrinter boardPrinter = new BoardPrinter(console); | ||
board.registerObserver(boardPrinter::printBoard); | ||
|
||
MoveIsDiagonal moveIsDiagonal = new MoveIsDiagonal(); | ||
MoveLength moveLength = new MoveLength(); | ||
MoveIsForwardIfNotKing moveIsForwardIfNotKing = new MoveIsForwardIfNotKing(); | ||
OpponentPieceBetweenJump opponentPieceBetweenJump = new OpponentPieceBetweenJump(); | ||
TargetFieldEmpty targetFieldEmpty = new TargetFieldEmpty(); | ||
NoOtherMoveToJumpPossible noOtherMoveToJumpPossible = | ||
new NoOtherMoveToJumpPossible( | ||
moveIsForwardIfNotKing, opponentPieceBetweenJump, targetFieldEmpty); | ||
StartPieceValid startPieceValid = new StartPieceValid(); | ||
|
||
List<MoveValidator> moveValidators = | ||
List.of( | ||
moveIsDiagonal, | ||
moveIsForwardIfNotKing, | ||
moveLength, | ||
noOtherMoveToJumpPossible, | ||
opponentPieceBetweenJump, | ||
startPieceValid, | ||
targetFieldEmpty); | ||
|
||
WinCondition winCondition = | ||
new WinCondition( | ||
List.of( | ||
moveIsDiagonal, | ||
moveLength, | ||
moveIsForwardIfNotKing, | ||
opponentPieceBetweenJump, | ||
targetFieldEmpty, | ||
startPieceValid)); | ||
|
||
MoveExecutor moveExecutor = new MoveExecutor(board, coinTosser, console); | ||
GameLogic gameLogic = | ||
new GameLogic( | ||
console, board, moveValidators, moveExecutor, noOtherMoveToJumpPossible, winCondition); | ||
|
||
console.print("Welcome to checkers"); | ||
boardPrinter.printBoard(board); | ||
return gameLogic; | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
...ttern-examples/src/main/java/ch/scs/jumpstart/pattern/examples/checkers/MoveExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package ch.scs.jumpstart.pattern.examples.checkers; | ||
|
||
import static ch.scs.jumpstart.pattern.examples.checkers.util.CoinTosser.Result.HEADS; | ||
import static ch.scs.jumpstart.pattern.examples.checkers.util.CoinTosser.Result.TAILS; | ||
|
||
import ch.scs.jumpstart.pattern.examples.checkers.dom.JumpGambleResult; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.Move; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.board.Board; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.CoinTosser; | ||
import ch.scs.jumpstart.pattern.examples.checkers.util.Console; | ||
|
||
@SuppressWarnings("ClassCanBeRecord") | ||
public class MoveExecutor { | ||
private final Board board; | ||
private final CoinTosser coinTosser; | ||
private final Console console; | ||
|
||
public MoveExecutor(Board board, CoinTosser coinTosser, Console console) { | ||
this.board = board; | ||
this.coinTosser = coinTosser; | ||
this.console = console; | ||
} | ||
|
||
public Move executeMove(Move move) { | ||
if (!move.isJumpMove()) { | ||
board.executeMove(move); | ||
return move; | ||
} | ||
console.print(move.player() + " is making a jump move. Now " + move.player() + " may gamble."); | ||
console.print("If " + move.player() + " does not gamble, the jump move is executed normally."); | ||
console.print("If " + move.player() + " does gamble, a coin will be tossed."); | ||
console.print( | ||
"If the coin toss is " | ||
+ HEADS | ||
+ ", then the jump move will be executed, but " | ||
+ move.player() | ||
+ " gets another turn."); | ||
console.print( | ||
"If the coin toss is " | ||
+ TAILS | ||
+ ", then the jump move fails and the piece at " | ||
+ move.start() | ||
+ ", which would have been used for the jump move, is removed."); | ||
GambleChoice gambleChoice = null; | ||
do { | ||
console.print( | ||
move.player() + " type \"yes\" to gamble, \"no\" to execute the jump move normally"); | ||
String userInput = console.getUserInput(); | ||
try { | ||
gambleChoice = GambleChoice.valueOf(userInput.trim().toUpperCase()); | ||
} catch (IllegalArgumentException e) { | ||
console.print("The input of " + move.player() + " was invalid. Input was: " + userInput); | ||
} | ||
} while (gambleChoice == null); | ||
if (gambleChoice == GambleChoice.NO) { | ||
board.executeMove(move); | ||
return move; | ||
} | ||
CoinTosser.Result tossResult = coinTosser.toss(board, move.player()); | ||
JumpGambleResult jumpGambleResult = | ||
tossResult == HEADS ? JumpGambleResult.WON : JumpGambleResult.LOST; | ||
console.print("Coin toss resulted in " + tossResult + ", the gamble was: " + jumpGambleResult); | ||
Move newMove = move.withJumpGambleResult(jumpGambleResult); | ||
board.executeMove(newMove); | ||
return newMove; | ||
} | ||
|
||
private enum GambleChoice { | ||
@SuppressWarnings("unused") | ||
YES, | ||
NO | ||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
...ern-examples/src/main/java/ch/scs/jumpstart/pattern/examples/checkers/README.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# Checkers pattern examples | ||
|
||
These examples were taken from [Soco21-group8 checkersV3](https://github.com/soco21/soco21-group8/tree/main/assignment-3/checkersv3) | ||
with the permission of it's author [@BacLuc](https://github.com/BacLuc) |
51 changes: 51 additions & 0 deletions
51
...ttern-examples/src/main/java/ch/scs/jumpstart/pattern/examples/checkers/WinCondition.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package ch.scs.jumpstart.pattern.examples.checkers; | ||
|
||
import ch.scs.jumpstart.pattern.examples.checkers.dom.BoardCoordinates; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.BoardCoordinates.Column; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.BoardCoordinates.Row; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.Move; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.Piece; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.Player; | ||
import ch.scs.jumpstart.pattern.examples.checkers.dom.board.Board; | ||
import ch.scs.jumpstart.pattern.examples.checkers.movevalidator.MoveValidator; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
/** | ||
* Check if one player cannot move or has no pieces. This can be done in one go, as if one player | ||
* has no pieces, he cannot move. Use MoveValidators to check if any move is possible. | ||
*/ | ||
@SuppressWarnings("ClassCanBeRecord") | ||
public class WinCondition { | ||
private final List<MoveValidator> moveValidators; | ||
|
||
public WinCondition(List<MoveValidator> moveValidators) { | ||
this.moveValidators = moveValidators; | ||
} | ||
|
||
public boolean hasPlayerWon(Player player, Board board) { | ||
for (Row row : Row.values()) { | ||
for (Column col : Column.values()) { | ||
BoardCoordinates currentCoordinates = new BoardCoordinates(row, col); | ||
Optional<Piece> pieceAt = board.getPieceAt(currentCoordinates); | ||
if (pieceAt.isEmpty()) { | ||
continue; | ||
} | ||
Piece piece = pieceAt.get(); | ||
if (piece.owner() == player) { | ||
continue; | ||
} | ||
List<Move> possibleMoves = | ||
Move.generatePossibleMoves(currentCoordinates, piece.owner(), List.of(1, 2)); | ||
if (possibleMoves.stream() | ||
.anyMatch( | ||
move -> | ||
moveValidators.stream() | ||
.allMatch(moveValidator -> moveValidator.validate(move, board)))) { | ||
return false; | ||
} | ||
} | ||
} | ||
return true; | ||
} | ||
} |
Oops, something went wrong.