summaryrefslogtreecommitdiff
path: root/c1
diff options
context:
space:
mode:
Diffstat (limited to 'c1')
-rw-r--r--c1/.vscode/launch.json21
-rw-r--r--c1/AbstractStrategyGame.java47
-rw-r--r--c1/Client.java36
-rw-r--r--c1/ConnectFour.java117
-rw-r--r--c1/Testing.java53
-rw-r--r--c1/TicTacToe.java132
6 files changed, 406 insertions, 0 deletions
diff --git a/c1/.vscode/launch.json b/c1/.vscode/launch.json
new file mode 100644
index 0000000..8028593
--- /dev/null
+++ b/c1/.vscode/launch.json
@@ -0,0 +1,21 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "java",
+ "name": "Current File",
+ "request": "launch",
+ "mainClass": "${file}"
+ },
+ {
+ "type": "java",
+ "name": "Client",
+ "request": "launch",
+ "mainClass": "Client",
+ "projectName": "c1_b4eddbb1"
+ }
+ ]
+} \ No newline at end of file
diff --git a/c1/AbstractStrategyGame.java b/c1/AbstractStrategyGame.java
new file mode 100644
index 0000000..430aff5
--- /dev/null
+++ b/c1/AbstractStrategyGame.java
@@ -0,0 +1,47 @@
+import java.util.*;
+
+/**
+* A strategy game where all players have perfect information and no theme
+* or narrative around gameplay.
+*/
+public abstract class AbstractStrategyGame {
+ /**
+ * Constructs and returns a String describing how to play the game. Should include
+ * any relevant details on how to interpret the game state as returned by toString(),
+ * how to make moves, the game end condition, and how to win.
+ */
+ public abstract String instructions();
+
+ /**
+ * Constructs and returns a String representation of the current game state.
+ * This representation should contain all information that should be known to
+ * players at any point in the game, including board state (if any) and scores (if any).
+ */
+ public abstract String toString();
+
+ /**
+ * Returns true if the game has ended, and false otherwise.
+ */
+ public boolean isGameOver() {
+ return getWinner() != -1;
+ }
+
+ /**
+ * Returns the index of the player who has won the game,
+ * or -1 if the game is not over.
+ */
+ public abstract int getWinner();
+
+ /**
+ * Returns the index of the player who will take the next turn.
+ * If the game is over, returns -1.
+ */
+ public abstract int getNextPlayer();
+
+ /**
+ * Takes input from the parameter to specify the move the player
+ * with the next turn wishes to make, then executes that move.
+ * If any part of the move is illegal, throws an IllegalArgumentException.
+ */
+ public abstract void makeMove(Scanner input);
+}
diff --git a/c1/Client.java b/c1/Client.java
new file mode 100644
index 0000000..3bde980
--- /dev/null
+++ b/c1/Client.java
@@ -0,0 +1,36 @@
+import java.util.*;
+
+public class Client {
+ public static void main(String[] args) {
+ Scanner console = new Scanner(System.in);
+ AbstractStrategyGame game = new ConnectFour("dude", "bro");
+
+ System.out.println(game.instructions());
+ System.out.println();
+
+ while (!game.isGameOver()) {
+ System.out.println(game);
+ System.out.printf("Player %d's turn.\n", game.getNextPlayer());
+ try {
+ game.makeMove(console);
+ } catch (IllegalArgumentException ex) {
+ System.out.println("**Illegal move: " + ex.getMessage());
+ }
+ /**
+ * Note - the above structure is a try/catch, which is something
+ * we've included to help deal with the IllegalArgumentExceptions
+ * in your abstract strategy game!
+ * We want to remind you that try/catch is a forbidden feature in 123,
+ * so you SHOULD NOT INCLUDE IT in any code you submit (other than this file)!
+ * Please see the Code Quality Guide for more info on this.
+ */
+ }
+ System.out.println(game);
+ int winner = game.getWinner();
+ if (winner > 0) {
+ System.out.printf("Player %d wins!\n", winner);
+ } else {
+ System.out.println("It's a tie!");
+ }
+ }
+}
diff --git a/c1/ConnectFour.java b/c1/ConnectFour.java
new file mode 100644
index 0000000..ab3e33b
--- /dev/null
+++ b/c1/ConnectFour.java
@@ -0,0 +1,117 @@
+// Nik Johnson
+// 4-15-2024
+// TA: Zachary Bi
+
+import java.util.*;
+
+public class ConnectFour extends AbstractStrategyGame {
+
+ private char[][] board;
+ private int currentPlayer;
+ private String[] players;
+ private List<Character> playerSymbols;
+
+ public ConnectFour(String player1, String player2) {
+ this.board = new char[6][7];
+ this.players = new String[2];
+ this.playerSymbols = new ArrayList<>();
+ this.currentPlayer = 0;
+ players[0] = player1;
+ players[1] = player2;
+ playerSymbols.add('X');
+ playerSymbols.add('O');
+
+ // initialize empty board
+ for (int i = 0; i < board.length; i++) {
+ for (int n = 0; n < board[i].length; n++) {
+ board[i][n] = ' ';
+ }
+ }
+ }
+
+ public String instructions() {
+ String output = "";
+
+ output += "Welcome to Connect Four! This game consists of a 7x6 grid, each column of";
+ output += " which you may choose to 'drop' a disc down by inputting numbers 1-7.\n";
+ output += "Player 1's symbol is 'X', Player 2's is 'O'\n";
+ output += "To win, you must place 4 of your discs in a row, vertically or horizontally.\n";
+ output += "Have fun!";
+
+ return output;
+ }
+
+ // constructs game board in readable format
+ // no parameters
+ // returns formatted representation of game board
+ public String toString() {
+ String output = "";
+ for (char[] row : board) {
+ for (char loc : row) {
+ output += "[" + loc + "]";
+ }
+ output += "\n";
+ }
+ return output;
+ }
+
+
+ public int getWinner() {
+ // rows
+ for (int i = 0; i < board.length; i++) {
+ for (int j = 0; j <= board[i].length - 4; j++) {
+ char symbol = board[i][j];
+ if (symbol != ' ' && board[i][j + 1] == symbol && board[i][j + 2] == symbol && board[i][j + 3] == symbol) {
+ return playerSymbols.indexOf(symbol) + 1;
+ }
+ }
+ }
+
+ // columns
+ for (int j = 0; j < board[0].length; j++) {
+ for (int i = 0; i <= board.length - 4; i++) {
+ char symbol = board[i][j];
+ if (symbol != ' ' && board[i + 1][j] == symbol && board[i + 2][j] == symbol && board[i + 3][j] == symbol) {
+ return playerSymbols.indexOf(symbol) + 1;
+ }
+ }
+ }
+
+ return -1;
+}
+
+
+
+
+ public int getNextPlayer() {
+ return this.currentPlayer + 1;
+ }
+
+ public void makeMove(Scanner input) {
+ System.out.println(players[getNextPlayer() - 1] + ": Choose a column (1-7)");
+ int col = Integer.parseInt(input.next()) - 1;
+
+ if (col < 0 || col > 6) {
+ throw new IllegalArgumentException("selected column out of bounds");
+ }
+
+ boolean notPlaced = true;
+ for (int n = board.length - 1; n >= 0 && notPlaced; n--) {
+ if (board[n][col] == ' ') {
+ if (currentPlayer == 0) {
+ board[n][col] = 'X';
+ } else if (currentPlayer == 1) {
+ board[n][col] = 'O';
+ }
+ notPlaced = false;
+ }
+ }
+
+ if (currentPlayer == 0) {
+ currentPlayer = 1;
+ } else if (currentPlayer == 1) {
+ currentPlayer = 0;
+ }
+ }
+
+}
diff --git a/c1/Testing.java b/c1/Testing.java
new file mode 100644
index 0000000..34837d7
--- /dev/null
+++ b/c1/Testing.java
@@ -0,0 +1,53 @@
+import org.junit.jupiter.api.*;
+import static org.junit.jupiter.api.Assertions.*;
+import java.util.*;
+
+public class Testing {
+ @Test
+ @DisplayName("EXAMPLE TEST CASE - Small TicTacToe Example")
+ public void firstCaseTest() {
+ AbstractStrategyGame g = new TicTacToe();
+
+ // You can add optional error messages that will be displayed if a test fails
+ assertEquals(1, g.getNextPlayer(), "Player 1 not next player after construction");
+ assertEquals(-1, g.getWinner(), "Winner incorrectly declared after construction");
+ assertFalse(g.isGameOver(), "Game over immediately after construction");
+
+ // Weird way we're going to make moves - make our own scanners NOT
+ // connected to System.in. Since we can make Scanners over strings this will
+ // work the exact way and allow us to control input!
+ g.makeMove(new Scanner("0 0"));
+ assertEquals(2, g.getNextPlayer(), "Player 2 not next player after a single move");
+ assertEquals(-1, g.getWinner(), "Winner incorrectly declared after a single move");
+ assertFalse(g.isGameOver(), "Game over immediately after construction");
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ // -1 is an illegal move so our code should throw an IllegalArgumentException
+ g.makeMove(new Scanner("-1 2"));
+ }, "IllegalArgumentException not thrown for illegal move");
+ }
+
+ @Test
+ @DisplayName("EXAMPLE TEST CASE - Large TicTacToe Example")
+ public void secondCaseTest() {
+ // You definitely don't have to get this fancy in your tests!
+ AbstractStrategyGame g = new TicTacToe();
+
+ // Going to play a whole game where 1 plays in first row, 2 plays in second row
+ // No optional error messages - up to you if you want your code to be easier to debug!
+ for (int i = 0; i < 5; i++) {
+ int player = (i % 2) + 1;
+ assertEquals(player, g.getNextPlayer());
+ assertFalse(g.isGameOver());
+
+ int col = i / 2;
+ g.makeMove(new Scanner(player + " " + col));
+ }
+
+ // At this point, 5 moves have been played, player 1 should have three in a row and
+ // player 2 should have two
+ assertTrue(g.isGameOver());
+ assertEquals(1, g.getWinner());
+ assertEquals(-1, g.getNextPlayer());
+ }
+}
diff --git a/c1/TicTacToe.java b/c1/TicTacToe.java
new file mode 100644
index 0000000..dd2343a
--- /dev/null
+++ b/c1/TicTacToe.java
@@ -0,0 +1,132 @@
+// **THIS IS AN EXAMPLE IMPLEMENTATION!**
+// Brett Wortzman
+// CSE 123
+// C0: Abstract Strategy Games
+//
+// A class to represent a game of tic-tac-toe that implements the
+// AbstractStrategyGame interface.
+import java.util.*;
+
+public class TicTacToe extends AbstractStrategyGame {
+ private char[][] board;
+ private boolean isXTurn;
+
+ // Constructs a new TicTacToe game.
+ public TicTacToe() {
+ board = new char[][]{{'-', '-', '-'},
+ {'-', '-', '-'},
+ {'-', '-', '-'}};
+ isXTurn = true;
+ }
+
+ // Returns whether or not the game is over.
+ public boolean isGameOver() {
+ return getWinner() >= 0;
+ }
+
+ // Returns the index of the winner of the game.
+ // 1 if player 1 (X), 2 if player 2 (O), 0 if a tie occurred,
+ // and -1 if the game is not over.
+ public int getWinner() {
+ for (int i = 0; i < board.length; i++) {
+ // check row i
+ if (board[i][0] == board[i][1] && board[i][0] == board[i][2] && board[i][0] != '-') {
+ return board[i][0] == 'X' ? 1 : 2;
+ }
+
+ // check col i
+ if (board[0][i] == board[1][i] && board[0][i] == board[2][i] && board[0][i] != '-') {
+ return board[0][i] == 'X' ? 1 : 2;
+ }
+ }
+
+ // check diagonals
+ if (board[0][0] == board[1][1] && board[0][0] == board[2][2] && board[0][0] != '-') {
+ return board[0][0] == 'X' ? 1 : 2;
+ }
+ if (board[0][2] == board[1][1] && board[0][2] == board[2][0] && board[0][2] != '-') {
+ return board[0][2] == 'X' ? 1 : 2;
+ }
+
+ // check for tie
+ for (int i = 0; i < board.length; i++) {
+ for (int j = 0; j < board[i].length; j++) {
+ if (board[i][j] == '-') {
+ // unfilled space; game not over
+ return -1;
+ }
+ }
+ }
+
+ // it's a tie!
+ return 0;
+ }
+
+ // Returns the index of which player's turn it is.
+ // 1 if player 1 (X), 2 if player 2 (O), -1 if the game is over
+ public int getNextPlayer() {
+ if (isGameOver()) {
+ return -1;
+ }
+ return isXTurn ? 1 : 2;
+ }
+
+ // Given the input, places an X or an O where
+ // the player specifies.
+ // Throws an IllegalArgumentException if the position is
+ // invalid, whether that be out of bounds or already occupied.
+ // Board bounds are [0, 2] for both rows and cols.
+ public void makeMove(Scanner input) {
+ char currPlayer = isXTurn ? 'X' : 'O';
+
+ System.out.print("Row? ");
+ int row = input.nextInt();
+ System.out.print("Column? ");
+ int col = input.nextInt();
+
+ makeMove(row, col, currPlayer);
+ isXTurn = !isXTurn;
+ }
+
+ // Private helper method for makeMove.
+ // Given a row and col, as well as player index,
+ // places an X or an O in that row and col.
+ // Throws an IllegalArgumentException if the position is
+ // invalid, whether that be out of bounds or already occupied.
+ // Board bounds are [0, 2] for both rows and cols.
+ private void makeMove(int row, int col, char player) {
+ if (row < 0 || row >= board.length ||
+ col < 0 || col >= board[0].length) {
+ throw new IllegalArgumentException("Invalid board position: " + row + "," + col);
+ }
+
+ if (board[row][col] != '-') {
+ throw new IllegalArgumentException("Space already occupied: " + row + "," + col);
+ }
+
+ board[row][col] = player;
+ }
+
+ // Returns a String containing instructions to play the game.
+ public String instructions() {
+ String result = "";
+ result += "Player 1 is X and goes first. Choose where to play by entering a row and\n";
+ result += "column number, where (0, 0) is the upper left and (2, 2) is the lower right.\n";
+ result += "Spaces show as a - are empty. The game ends when one player marks three spaces\n";
+ result += "in a row, in which case that player wins, or when the board is full, in which\n";
+ result += "case the game ends in a tie.";
+ return result;
+ }
+
+ // Returns a String representation of the current state of the board.
+ public String toString() {
+ String result = "";
+ for (int i = 0; i < board.length; i++) {
+ for (int j = 0; j < board.length; j++) {
+ result += board[i][j] + " ";
+ }
+ result += "\n";
+ }
+ return result;
+ }
+}