init
This commit is contained in:
47
c1/AbstractStrategyGame.java
Normal file
47
c1/AbstractStrategyGame.java
Normal file
@@ -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);
|
||||
}
|
||||
36
c1/Client.java
Normal file
36
c1/Client.java
Normal file
@@ -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!");
|
||||
}
|
||||
}
|
||||
}
|
||||
117
c1/ConnectFour.java
Normal file
117
c1/ConnectFour.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
53
c1/Testing.java
Normal file
53
c1/Testing.java
Normal file
@@ -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());
|
||||
}
|
||||
}
|
||||
132
c1/TicTacToe.java
Normal file
132
c1/TicTacToe.java
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user