Skip to content

Commit

Permalink
Merge branch 'main' into _SaadsBranch
Browse files Browse the repository at this point in the history
  • Loading branch information
saadkhairullah authored Apr 25, 2024
2 parents 578064e + 47aa0a7 commit bebf278
Show file tree
Hide file tree
Showing 15 changed files with 9,150 additions and 213 deletions.
8 changes: 8 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
```bash
export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64
$ mvn clean
$ mvn install
$ mvn package
$ mvn compile
$ mvn exec:java
```
Linux users can run "run.sh" script to start the game
31 changes: 28 additions & 3 deletions src/main/java/uta/cse3310/App.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package uta.cse3310;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
Expand Down Expand Up @@ -284,8 +283,34 @@ public void onOpen(WebSocket conn, ClientHandshake handshake) {

@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
System.out
.println("WebSocket connection closed: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());
System.out.println("WebSocket connection closed: " + conn.getRemoteSocketAddress().getAddress().getHostAddress());

// Find the username associated with the connection that caused the error
String errorUsername = null;
for (Map.Entry<String, Player> entry : playerMap.entrySet()) {
Player player = entry.getValue();
if (player.getWebSocket() != null && player.getWebSocket().equals(conn)) {
errorUsername = entry.getKey();
break;
}
}

// If a username was found, remove that player from the map
if (errorUsername != null) {
playerMap.remove(errorUsername);
connectionUserMap.remove(conn); // Clean up the connection map
System.out.println("\n--PLAYER REMOVED--\nPlayer removed (Tab Closed): " + errorUsername+"\n\n");
// Optionally broadcast the updated player list after removal
broadcastPlayerList();
System.out.println("On Disconnect : ");
;
broadcastGameRooms();
}

System.out.println("On Error : ");
;
broadcastGameRooms();

}

private void broadcastChatMessage(String roomID, String message) {
Expand Down
164 changes: 139 additions & 25 deletions src/main/java/uta/cse3310/Game.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.stream.Collectors;

import org.java_websocket.WebSocket;

Expand All @@ -26,6 +29,7 @@ public class Game {
private static List<String> allWords = new ArrayList<>(); // List of all words in the game
private char[][] grid; // The grid of the game
private Map<String, Boolean> wordsPlaced;
private Set<Integer> placedLetters = new HashSet<>();
private static Random random = new Random();

// Maintain the original naming convention
Expand All @@ -42,22 +46,19 @@ public Game(String lobbyName, String roomId) {
this.wordsPlaced = new HashMap<>();
loadWords(); // Load words specific to this game instance
System.out.println("Creating game with lobby name: " + lobbyName + " and room id: " + roomId);
initializeGrid();
placeWords();
System.out.println("Grid for [game: " + lobbyName + " room: " + roomId);
printGrid();
printWords();
this.chat = new Chat(); // Initialize a new Chat object for this game
startGame();

}

public boolean checkWord(String username, String word) {
Boolean foundStatus = wordsPlaced.get(word);
if (foundStatus != null && foundStatus) { // Check if the word exists and is set to true (available to be found)
wordsPlaced.put(word, false); // Mark the word as found by setting it to false
wordsFound.add(word); // Optionally maintain a list of all found words
wordsFoundByPlayer.computeIfAbsent(username, k -> new ArrayList<>()).add(word);
System.out.println(username + " found the word: " + word);
// print the list
// print the list
printWordsFoundByUser(username);
return true;
} else {
Expand All @@ -66,12 +67,11 @@ public boolean checkWord(String username, String word) {
}
}


public void printWordsFoundByUser(String username) {
List<String> foundWords = wordsFoundByPlayer.getOrDefault(username, new ArrayList<>());
System.out.println(username + " has found: " + foundWords);
}

public void printAllWordsAndTheirStatus() {
for (Map.Entry<String, Boolean> entry : wordsPlaced.entrySet()) {
System.out.println("Word: " + entry.getKey() + ", Available: " + entry.getValue());
Expand All @@ -87,7 +87,6 @@ public Map<String, Integer> getPlayerScores() {
return scores;
}


public void reset() {
// Reset the game's properties
System.out.println("Resetting game in lobby: " + lobbyName);
Expand All @@ -105,6 +104,7 @@ public void reset() {
initializeGrid();
placeWords();
System.out.println("Game reset in lobby: " + lobbyName);

}

// CHAT
Expand Down Expand Up @@ -146,7 +146,17 @@ public void sendGameDetails(WebSocket conn) {

private void initializeGrid() {
for (int i = 0; i < GRID_SIZE; i++) {
Arrays.fill(grid[i], '_');
Arrays.fill(grid[i], '_'); // Initialize all cells to '_'
}
}

private void fillRemainingCells() {
for (int i = 0; i < GRID_SIZE; i++) {
for (int j = 0; j < GRID_SIZE; j++) {
if (grid[i][j] == '_') { // Only fill cells that have not been filled with a word
grid[i][j] = (char) ('A' + random.nextInt(26));
}
}
}
}

Expand All @@ -163,22 +173,73 @@ private void placeWords() {
wordsPlaced.put(word, true);
}
}

// DEBUG
// System.out.println("IN placewords()");
// for (Map.Entry<String, Boolean> entry : wordsPlaced.entrySet()) {
// System.out.println("\"" + entry.getKey() + "\":" + entry.getValue());
// System.out.println("\"" + entry.getKey() + "\":" + entry.getValue());
// }
}

public void calculateWordDensity() {
int totalCells = GRID_SIZE * GRID_SIZE;
int wordCells = placedLetters.size(); // The set size gives us the number of unique cells with words

double density = (double) wordCells / totalCells * 100;
System.out.printf("Density of valid words in the grid: %.2f%%\n", density);
}

private int getRowIncrement(int orientation, int i) {
switch (orientation) {
case 0: // Horizontal right
case 2: // Horizontal left
return 0;
case 1: // Vertical down
case 7: // Diagonal right down
case 5: // Diagonal left down
return i;
case 3: // Vertical up
case 6: // Diagonal right up
case 4: // Diagonal left up
return -i;
default:
return 0;
}
}

private int getColIncrement(int orientation, int i) {
switch (orientation) {
case 0: // Horizontal right
case 7: // Diagonal right down
case 6: // Diagonal right up
return i;
case 1: // Vertical down
case 3: // Vertical up
return 0;
case 2: // Horizontal left
case 5: // Diagonal left down
case 4: // Diagonal left up
return -i;
default:
return 0;
}
}

// Attempts to place a single word in the grid randomly
public boolean placeWordInGrid(String word) {
private boolean placeWordInGrid(String word) {
int orientation = random.nextInt(2); // 0 for horizontal, 1 for vertical

private boolean placeWordInGrid(String word) {
int orientation = random.nextInt(8); // Updated for 8 orientations
for (int attempts = 0; attempts < 100; attempts++) {
int row = random.nextInt(GRID_SIZE);
int col = random.nextInt(GRID_SIZE);
if (canPlaceWord(word, row, col, orientation)) {
for (int i = 0; i < word.length(); i++) {
grid[row + (orientation == 1 ? i : 0)][col + (orientation == 0 ? i : 0)] = word.charAt(i);
int newRow = row + getRowIncrement(orientation, i);
int newCol = col + getColIncrement(orientation, i);
grid[newRow][newCol] = word.charAt(i);
placedLetters.add(newRow * GRID_SIZE + newCol); // Track positions
}
return true;
}
Expand All @@ -189,9 +250,9 @@ public boolean placeWordInGrid(String word) {
// Checks if a word can be placed at the specified position
private boolean canPlaceWord(String word, int row, int col, int orientation) {
for (int i = 0; i < word.length(); i++) {
int newRow = row + (orientation == 1 ? i : 0);
int newCol = col + (orientation == 0 ? i : 0);
if (newRow >= GRID_SIZE || newCol >= GRID_SIZE || grid[newRow][newCol] != '_') {
int newRow = row + getRowIncrement(orientation, i);
int newCol = col + getColIncrement(orientation, i);
if (newRow < 0 || newRow >= GRID_SIZE || newCol < 0 || newCol >= GRID_SIZE || grid[newRow][newCol] != '_') {
return false;
}
}
Expand All @@ -208,11 +269,62 @@ public void printGrid() {
}
}

// uses the concept of binary division by recursively splitting the list of
// words into halves, and then sub-halves, to select words uniformly from
// various sections. It starts by dividing the list into two equal segments,
// picking words from each, then further splits each segment again into smaller
// segments, continuing this binary division until selections have been made
// across all possible divisions.

// ensures a balanced and random selection from all parts of the list
private List<String> structuredShuffle(List<String> words, int segments) {
List<String> shuffled = new ArrayList<>(); // This will hold the shuffled list of words.
int segmentSize = words.size() / segments; // Calculate how many words each segment will contain.

// Set to track which indices have been added to the shuffled list to avoid
// duplicating words.
Set<Integer> addedIndices = new HashSet<>();

// Continue looping until the shuffled list contains all words from the original
// list.
while (shuffled.size() < words.size()) {
for (int i = 0; i < segments; i++) {
int start = i * segmentSize; // Calculate the start index of the current segment.
int end = (i + 1) * segmentSize; // Calculate the end index of the current segment.
if (i == segments - 1) {
end = words.size(); // Ensure the last segment includes all remaining words.
}

// Generate a random index within the current segment to pick a word.
int randomIndex = start + random.nextInt(end - start);
// Check if the index has already been used to prevent duplicate selections.
if (!addedIndices.contains(randomIndex)) {
shuffled.add(words.get(randomIndex)); // Add the selected word to the shuffled list.
addedIndices.add(randomIndex); // Mark this index as used.
}

// Break out of the loop if all words are already added to the shuffled list.
if (shuffled.size() >= words.size()) {
break;
}
}
}

return shuffled; // Return the uniformly shuffled list of words.
}

// Loads the words from a text file into the allWords list
public void loadWords() {
try {
allWords = Files.readAllLines(Paths.get("words.txt"));
System.out.println("Words loaded successfully");
List<String> loadedWords = Files.readAllLines(Paths.get("words.txt")).stream()
.map(String::toUpperCase) // Convert each word to uppercase
.filter(word -> word.length() > 3) // Filter out words that are too short
.collect(Collectors.toList());

// New method to shuffle words by picking from different segments
allWords = structuredShuffle(loadedWords, 10); // Shuffle with desired number of segments

System.out.println("Words loaded successfully. Total words loaded: " + allWords.size());
} catch (IOException e) {
System.err.println("Error loading words: " + e.getMessage());
}
Expand Down Expand Up @@ -243,7 +355,7 @@ public String getGridAsJson() {
public void printWords() {
System.out.println("----------PLACED WORDS-------------");
for (String word : wordsPlaced.keySet()) {
System.out.print(word + " " );
System.out.print(word + " ");
}

// print the count of words
Expand All @@ -254,11 +366,10 @@ public void printWords() {
// System.out.println("\nDEBUG : \n"+wordsPlaced.get("Buggati"));
// System.out.println("\n------------------------------------\n");
// for (Map.Entry<String, Boolean> entry : wordsPlaced.entrySet()) {
// System.out.println("\"" + entry.getKey() + "\":" + entry.getValue());
// System.out.println("\"" + entry.getKey() + "\":" + entry.getValue());
// }


}
}

// Method to add a player to the game
public boolean addPlayer(Player player) {
Expand Down Expand Up @@ -316,7 +427,12 @@ public String roomID() {
}

public void startGame() {
// Start the game
initializeGrid(); // first fill with dashes
placeWords(); // then place words
fillRemainingCells(); // then fill the dahses with the remaining letters
printGrid();
printWords();
calculateWordDensity();
}

public String getCurrentNumberOfPlayers() {
Expand Down Expand Up @@ -364,6 +480,4 @@ public String getGameRoomId() {
public Player[] getPlayers_chat() {
return new Player[] { player1, player2 };
}

// Other methods as needed...
}
2 changes: 1 addition & 1 deletion src/main/java/uta/cse3310/HttpServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
public class HttpServer {

int port = 8080;
String dirname = "src/main/webapp/html"; // Replace with the actual absolute path to the html folder.
String dirname = "src/main/webapp/html";

public HttpServer(int portNum, String dirName) {
port = portNum;
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/uta/cse3310/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class Player {

public Player(String username, WebSocket webSocket) {
this.username = username;
this.colorChoice = "Default"; // Default color, can be set later
this.colorChoice = "Default";
this.gamesWon = 0;
this.gamesLost = 0;
this.inGameScore = 0;
Expand Down
Binary file added src/main/webapp/html/background.JPG
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/main/webapp/html/body.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/*------------------Body------------------------------------*/
body {
font-family: Arial, sans-serif;
background-color: #292524;
scale: 1; /* Adjust as needed, due to my laptop screen size!*/
}
Loading

0 comments on commit bebf278

Please sign in to comment.