setCopiedEmail(false)}>
Email copied! ✕
diff --git a/frontend/src/components/game/SpectatorGameView.tsx b/frontend/src/components/game/SpectatorGameView.tsx
index 1b65c695..7e3f8f7c 100644
--- a/frontend/src/components/game/SpectatorGameView.tsx
+++ b/frontend/src/components/game/SpectatorGameView.tsx
@@ -83,6 +83,7 @@ function SpectatorGameView() {
subscribePlayer(game.room.roomId, game.players[index].user.userId!);
}
}}
+ numProblems={game?.problems.length || 1}
/>
{error ? : null}
{loading ? : null}
diff --git a/frontend/src/components/results/PlayerResultsItem.tsx b/frontend/src/components/results/PlayerResultsItem.tsx
index e5aeab21..462696f7 100644
--- a/frontend/src/components/results/PlayerResultsItem.tsx
+++ b/frontend/src/components/results/PlayerResultsItem.tsx
@@ -1,12 +1,11 @@
import React from 'react';
import styled from 'styled-components';
+import { Player, Submission } from '../../api/Game';
import { LowMarginText, Text } from '../core/Text';
import { Color } from '../../api/Color';
-import { Player } from '../../api/Game';
-import { useBestSubmission } from '../../util/Hook';
+import { useBestSubmission, useGetScore, useGetSubmissionTime } from '../../util/Hook';
import Language, { displayNameFromLanguage } from '../../api/Language';
import { TextButton } from '../core/Button';
-import { getScore, getSubmissionCount, getSubmissionTime } from '../../util/Utility';
const Content = styled.tr`
border-radius: 5px;
@@ -83,23 +82,38 @@ type PlayerResultsCardProps = {
isCurrentPlayer: boolean,
gameStartTime: string,
color: Color,
+ numProblems: number,
onViewCode: (() => void) | null,
onSpectateLive: (() => void) | null,
};
function PlayerResultsItem(props: PlayerResultsCardProps) {
const {
- player, place, isCurrentPlayer, color, gameStartTime, onViewCode,
- onSpectateLive,
+ player, place, isCurrentPlayer, color, onViewCode, onSpectateLive,
} = props;
- const bestSubmission = useBestSubmission(player);
+ const score = useGetScore(player);
+ const time = useGetSubmissionTime(player);
+ const bestSubmission : Submission | null = useBestSubmission(player);
+
+ const getSubmissionCount = () => player.submissions.length || '0';
const getDisplayNickname = () => {
const { nickname } = player.user;
return `${nickname} ${isCurrentPlayer ? '(you)' : ''}`;
};
+ const getSubmissionTime = () => {
+ if (!time) {
+ return 'Never';
+ }
+
+ const currentTime = new Date().getTime();
+ const diffMilliseconds = currentTime - new Date(time).getTime();
+ const diffMinutes = Math.floor(diffMilliseconds / (60 * 1000));
+ return `${diffMinutes}m ago`;
+ };
+
const getSubmissionLanguage = () => {
if (!bestSubmission) {
return 'N/A';
@@ -129,13 +143,13 @@ function PlayerResultsItem(props: PlayerResultsCardProps) {
|
- {getScore(bestSubmission)}
+ {score}
|
- {getSubmissionTime(bestSubmission, gameStartTime)}
+ {getSubmissionTime()}
|
- {getSubmissionCount(player)}
+ {getSubmissionCount()}
|
{!onSpectateLive ? (
{getSubmissionLanguage()}
diff --git a/frontend/src/components/results/Podium.tsx b/frontend/src/components/results/Podium.tsx
index e11a55b6..3aab8cdc 100644
--- a/frontend/src/components/results/Podium.tsx
+++ b/frontend/src/components/results/Podium.tsx
@@ -3,7 +3,7 @@ import styled from 'styled-components';
import { Player } from '../../api/Game';
import { Text, MediumText } from '../core/Text';
import Language, { displayNameFromLanguage } from '../../api/Language';
-import { useBestSubmission } from '../../util/Hook';
+import { useBestSubmission, useGetScore, useGetSubmissionTime } from '../../util/Hook';
type PodiumProps = {
place: number,
@@ -12,6 +12,7 @@ type PodiumProps = {
inviteContent: React.ReactNode,
loading: boolean,
isCurrentPlayer: boolean,
+ numProblems: number,
};
type MedalProps = {
@@ -85,10 +86,12 @@ const Medal = styled.div`
function Podium(props: PodiumProps) {
const {
- place, player, gameStartTime, loading, inviteContent, isCurrentPlayer,
+ place, player, gameStartTime, loading, inviteContent, isCurrentPlayer, numProblems,
} = props;
+ const score = useGetScore(player);
const bestSubmission = useBestSubmission(player);
+ const time = useGetSubmissionTime(player);
const getMedalColor = () => {
switch (place) {
@@ -120,7 +123,7 @@ function Podium(props: PodiumProps) {
return inviteContent;
}
- if (!bestSubmission) {
+ if (!score) {
return (
Scored
@@ -130,7 +133,7 @@ function Podium(props: PodiumProps) {
);
}
- const percent = Math.round((bestSubmission.numCorrect / bestSubmission.numTestCases) * 100);
+ const percent = Math.round((score / numProblems) * 100);
return (
Scored
@@ -140,13 +143,13 @@ function Podium(props: PodiumProps) {
};
const getTimeText = () => {
- if (!bestSubmission) {
+ if (!time) {
return ;
}
// Calculate time from start of game till best submission
const startTime = new Date(gameStartTime).getTime();
- const diffMilliseconds = new Date(bestSubmission.startTime).getTime() - startTime;
+ const diffMilliseconds = new Date(time).getTime() - startTime;
const diffMinutes = Math.floor(diffMilliseconds / (60 * 1000));
return (
diff --git a/frontend/src/components/results/PreviewCodeContent.tsx b/frontend/src/components/results/PreviewCodeContent.tsx
index 4cbbb94d..fb614873 100644
--- a/frontend/src/components/results/PreviewCodeContent.tsx
+++ b/frontend/src/components/results/PreviewCodeContent.tsx
@@ -45,8 +45,9 @@ function PreviewCodeContent(props: PreviewCodeContentProps) {
bestSubmission?.language as Language || Language.Java}
+ defaultCodeMap={null}
+ currentProblem={0}
defaultCode={bestSubmission?.code || 'Uh oh! An error occurred fetching this player\'s code'}
liveCode={null}
/>
diff --git a/frontend/src/components/results/ResultsTable.tsx b/frontend/src/components/results/ResultsTable.tsx
index 1421982c..71413150 100644
--- a/frontend/src/components/results/ResultsTable.tsx
+++ b/frontend/src/components/results/ResultsTable.tsx
@@ -37,13 +37,14 @@ type ResultsTableProps = {
players: Player[],
currentUser: User | null,
gameStartTime: string,
+ numProblems: number,
viewPlayerCode: ((index: number) => void) | null,
spectatePlayer: ((index: number) => void) | null,
};
function ResultsTable(props: ResultsTableProps) {
const {
- players, currentUser, gameStartTime, viewPlayerCode, spectatePlayer,
+ players, currentUser, gameStartTime, numProblems, viewPlayerCode, spectatePlayer,
} = props;
return (
@@ -64,6 +65,7 @@ function ResultsTable(props: ResultsTableProps) {
isCurrentPlayer={currentUser?.userId === player.user.userId}
gameStartTime={gameStartTime}
color={player.color}
+ numProblems={numProblems}
onViewCode={viewPlayerCode ? (() => viewPlayerCode(index)) : null}
onSpectateLive={spectatePlayer ? (() => spectatePlayer(index)) : null}
/>
diff --git a/frontend/src/util/Hook.tsx b/frontend/src/util/Hook.tsx
index 3dc5c3fa..919eb0e7 100644
--- a/frontend/src/util/Hook.tsx
+++ b/frontend/src/util/Hook.tsx
@@ -30,6 +30,68 @@ export const useBestSubmission = (player?: Player | null) => {
return bestSubmission;
};
+export const useGetScore = (player?: Player) => {
+ const counted = new Set();
+ const [score, setScore] = useState(0);
+
+ useEffect(() => {
+ if (player) {
+ for (let i = 0; i < player.submissions.length; i += 1) {
+ if (player.submissions[i].numCorrect === player.submissions[i].numTestCases
+ && !counted.has(player.submissions[i].problemIndex)) {
+ counted.add(player.submissions[i].problemIndex);
+ }
+ }
+
+ setScore(counted.size);
+ }
+ }, [player, setScore, counted]);
+
+ if (player == null || player.submissions.length === 0) {
+ return null;
+ }
+ return score;
+};
+
+export const useGetSubmissionTime = (player?: Player) => {
+ const counted = new Set();
+ const [time, setTime] = useState();
+
+ useEffect(() => {
+ if (player) {
+ for (let i = 0; i < player.submissions.length; i += 1) {
+ if (player.submissions[i].numCorrect === player.submissions[i].numTestCases
+ && !counted.has(player.submissions[i].problemIndex)) {
+ counted.add(player.submissions[i].problemIndex);
+ setTime(player.submissions[i].startTime);
+ }
+ }
+ }
+ }, [player, counted]);
+
+ if (!time && player && player.submissions.length > 0) {
+ setTime(player.submissions[player.submissions.length - 1].startTime);
+ }
+
+ return time;
+};
+
+// Returns the most recent submission made for problem of index curr.
+export const useGetSubmission = (curr: number, playerSubmissions: Submission[]) => {
+ const [submission, setSubmission] = useState(null);
+
+ useEffect(() => {
+ for (let i = playerSubmissions.length - 1; i >= 0; i -= 1) {
+ if (playerSubmissions[i].problemIndex === curr) {
+ setSubmission(playerSubmissions[i]);
+ i = -1;
+ }
+ }
+ }, [curr, playerSubmissions]);
+
+ return submission;
+};
+
export const useProblemEditable = (user: FirebaseUserType | null, problem: Problem | null) => {
const [editable, setEditable] = useState(false);
diff --git a/frontend/src/util/Utility.ts b/frontend/src/util/Utility.ts
index b87c0245..96b1277e 100644
--- a/frontend/src/util/Utility.ts
+++ b/frontend/src/util/Utility.ts
@@ -143,6 +143,14 @@ export const getSubmissionTime = (bestSubmission: Submission | null,
export const getSubmissionCount = (player: Player | null) => player?.submissions.length || '0';
+export const getSubmission = (curr: number, playerSubmissions: Submission[]) => {
+ for (let i = playerSubmissions.length - 1; i >= 0; i -= 1) {
+ if (playerSubmissions[i].problemIndex === curr) {
+ return playerSubmissions[i];
+ }
+ }
+};
+
/**
* De-duplicate a list of SelectableProblems.
* Solution at: https://stackoverflow.com/a/1584377/7517518.
diff --git a/frontend/src/views/Game.tsx b/frontend/src/views/Game.tsx
index ca080c21..39b371c6 100644
--- a/frontend/src/views/Game.tsx
+++ b/frontend/src/views/Game.tsx
@@ -17,9 +17,7 @@ import { Difficulty } from '../api/Difficulty';
import { Game, manuallyEndGame } from '../api/Game';
import GameTimerContainer from '../components/game/GameTimerContainer';
import { GameTimer } from '../api/GameTimer';
-import {
- TextButton, DangerButton,
-} from '../components/core/Button';
+import { TextButton, DangerButton } from '../components/core/Button';
import {
connect, routes, subscribe,
} from '../api/Socket';
@@ -53,6 +51,7 @@ function GamePage() {
const [host, setHost] = useState(null);
const [spectators, setSpectators] = useState([]);
const [gameTimer, setGameTimer] = useState(null);
+
const [timeUp, setTimeUp] = useState(false);
const [allSolved, setAllSolved] = useState(false);
const [gameEnded, setGameEnded] = useState(false);
diff --git a/frontend/src/views/Lobby.tsx b/frontend/src/views/Lobby.tsx
index b7b10709..16e20fb0 100644
--- a/frontend/src/views/Lobby.tsx
+++ b/frontend/src/views/Lobby.tsx
@@ -166,6 +166,7 @@ function LobbyPage() {
const [duration, setDuration] = useState(15);
const [selectedProblems, setSelectedProblems] = useState([]);
const [size, setSize] = useState(10);
+ const [numProblems, setNumProblems] = useState(1);
const [hoverVisible, setHoverVisible] = useState(false);
const [showProblemSelector, setShowProblemSelector] = useState(true);
@@ -218,6 +219,7 @@ function LobbyPage() {
setDuration(newRoom.duration / 60);
setSelectedProblems(newRoom.problems);
setSize(newRoom.size);
+ setNumProblems(newRoom.numProblems);
// Set the room and current user.
dispatch(setRoom(newRoom));
@@ -343,7 +345,8 @@ function LobbyPage() {
});
// eslint-disable-next-line no-alert
- if (!allSpectators || window.confirm('Everybody in this room is a spectator, which means this is going to be a pretty boring game... are you sure you want to start the game?')) {
+ if (!allSpectators || window.confirm('Everybody in this room is a spectator, which means this is '
+ + 'going to be a pretty boring game... are you sure you want to start the game?')) {
startGame(currentRoomId, request)
.then(() => {
setLoading(true);
@@ -496,6 +499,25 @@ function LobbyPage() {
});
};
+ const updateNumProblems = () => {
+ setError('');
+ setLoading(true);
+ const prevNumProblems = numProblems;
+ const settings = {
+ initiator: currentUser!,
+ numProblems,
+ };
+
+ updateRoomSettings(currentRoomId, settings)
+ .catch((err) => {
+ setError(err.message);
+ // Set numProblems back to original if REST call failed
+ setNumProblems(prevNumProblems);
+ }).finally(() => {
+ setLoading(false);
+ });
+ };
+
/**
* Display the passed-in list of users on the UI, either as
* active or inactive.
@@ -826,6 +848,28 @@ function LobbyPage() {
/>
+ Number of Problems
+
+ {`${numProblems} problem${numProblems === 1 ? '' : 's'}`}
+
+
+
+
+ {
+ const newNumProblems = Number(e.target.value);
+ if (newNumProblems >= 1 && newNumProblems <= 10) {
+ setNumProblems(newNumProblems);
+ }
+ }}
+ onMouseUp={updateNumProblems}
+ />
+
+
diff --git a/frontend/src/views/Results.tsx b/frontend/src/views/Results.tsx
index fbe4fb40..5024fd4f 100644
--- a/frontend/src/views/Results.tsx
+++ b/frontend/src/views/Results.tsx
@@ -295,6 +295,7 @@ function GameResultsPage() {
inviteContent={inviteContent()}
loading={loading}
isCurrentPlayer={players[1]?.user.userId === currentUser?.userId}
+ numProblems={game?.problems.length || 1}
/>
@@ -353,6 +356,7 @@ function GameResultsPage() {
players={players}
currentUser={currentUser}
gameStartTime={startTime}
+ numProblems={game?.problems.length || 1}
viewPlayerCode={(index: number) => setCodeModal(index)}
spectatePlayer={null}
/>
diff --git a/src/main/java/com/codejoust/main/dto/game/GameMapper.java b/src/main/java/com/codejoust/main/dto/game/GameMapper.java
index b3724405..4925a471 100644
--- a/src/main/java/com/codejoust/main/dto/game/GameMapper.java
+++ b/src/main/java/com/codejoust/main/dto/game/GameMapper.java
@@ -3,10 +3,13 @@
import org.modelmapper.ModelMapper;
import org.modelmapper.convention.MatchingStrategies;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import com.codejoust.main.dto.problem.ProblemDto;
import com.codejoust.main.dto.problem.ProblemMapper;
@@ -71,6 +74,7 @@ public static Game fromRoom(Room room) {
if (!user.getSpectator()) {
Player player = PlayerMapper.playerFromUser(user);
player.setColor(colorList.get(index));
+ player.setSolved(new boolean[room.getNumProblems()]);
players.put(user.getUserId(), player);
index = (index + 1) % colorList.size();
}
@@ -102,29 +106,52 @@ public static void sortLeaderboard(List players) {
return -1;
}
- SubmissionDto bestSub1 = submissions1.get(0);
- SubmissionDto bestSub2 = submissions2.get(0);
+ int score1 = getScore(submissions1);
+ int score2 = getScore(submissions2);
- // Get the best solution by each player (highest score, then earliest submission)
- for (SubmissionDto sub : submissions1) {
- if (sub.getNumCorrect() > bestSub1.getNumCorrect()) {
- bestSub1 = sub;
- }
- }
+ // If both have the same numCorrect, whoever submits earlier is first
+ if (score1 == score2) {
+ Instant time1 = getTime(submissions1);
+ Instant time2 = getTime(submissions2);
- for (SubmissionDto sub : submissions2) {
- if (sub.getNumCorrect() > bestSub2.getNumCorrect()) {
- bestSub2 = sub;
+ // If neither has submitted correctly, oh well (if one is null, the other must be as well)
+ if (time1 == null || time2 == null) {
+ return 0;
}
- }
- // If both have the same numCorrect, whoever submits earlier is first
- if (bestSub1.getNumCorrect().equals(bestSub2.getNumCorrect())) {
- return bestSub1.getStartTime().compareTo(bestSub2.getStartTime());
+ return time1.compareTo(time2);
}
// Whoever has higher numCorrect is first
- return bestSub2.getNumCorrect() - bestSub1.getNumCorrect();
+ return score2 - score1;
});
}
+
+ // Get total number of problems solved
+ private static int getScore(List submissions) {
+ Set set = new HashSet<>();
+ for (SubmissionDto submission : submissions) {
+ if (submission.getNumCorrect().equals(submission.getNumTestCases())) {
+ set.add(submission.getProblemIndex());
+ }
+ }
+
+ return set.size();
+ }
+
+ // Get time of latest correct solution, or null if none exists
+ private static Instant getTime(List submissions) {
+ Set set = new HashSet<>();
+ Instant instant = null;
+
+ for (SubmissionDto submission : submissions) {
+ if (submission.getNumCorrect().equals(submission.getNumTestCases())
+ && !set.contains(submission.getProblemIndex())) {
+ set.add(submission.getProblemIndex());
+ instant = submission.getStartTime();
+ }
+ }
+
+ return instant;
+ }
}
diff --git a/src/main/java/com/codejoust/main/dto/game/PlayerDto.java b/src/main/java/com/codejoust/main/dto/game/PlayerDto.java
index 95478ad8..9107f091 100644
--- a/src/main/java/com/codejoust/main/dto/game/PlayerDto.java
+++ b/src/main/java/com/codejoust/main/dto/game/PlayerDto.java
@@ -13,12 +13,13 @@
@Getter
@Setter
-@EqualsAndHashCode
+@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class PlayerDto {
+ @EqualsAndHashCode.Include
private UserDto user;
private String code;
private CodeLanguage language;
private List submissions = new ArrayList<>();
- private Boolean solved;
+ private boolean[] solved;
private Color color;
}
diff --git a/src/main/java/com/codejoust/main/dto/game/SubmissionDto.java b/src/main/java/com/codejoust/main/dto/game/SubmissionDto.java
index 5478668b..3fe813bd 100644
--- a/src/main/java/com/codejoust/main/dto/game/SubmissionDto.java
+++ b/src/main/java/com/codejoust/main/dto/game/SubmissionDto.java
@@ -19,6 +19,7 @@
public class SubmissionDto {
private CodeLanguage language;
private String code;
+ private int problemIndex;
private List results;
private Integer numCorrect;
private Integer numTestCases;
diff --git a/src/main/java/com/codejoust/main/dto/game/SubmissionRequest.java b/src/main/java/com/codejoust/main/dto/game/SubmissionRequest.java
index ff7277fb..463f583f 100644
--- a/src/main/java/com/codejoust/main/dto/game/SubmissionRequest.java
+++ b/src/main/java/com/codejoust/main/dto/game/SubmissionRequest.java
@@ -13,4 +13,5 @@ public class SubmissionRequest {
private String code;
private String input;
private UserDto initiator;
+ private int problemIndex = 0;
}
diff --git a/src/main/java/com/codejoust/main/game_object/Player.java b/src/main/java/com/codejoust/main/game_object/Player.java
index c5db6761..bb9b9f18 100644
--- a/src/main/java/com/codejoust/main/game_object/Player.java
+++ b/src/main/java/com/codejoust/main/game_object/Player.java
@@ -28,9 +28,8 @@ public class Player {
* Solved variable if the user has successfully solved the problem,
* or is still competing.
*/
- private Boolean solved = false;
+ private boolean[] solved;
// Color associated with this player, generated on backend in game start.
private Color color;
-
}
diff --git a/src/main/java/com/codejoust/main/game_object/Submission.java b/src/main/java/com/codejoust/main/game_object/Submission.java
index cf28a3f6..fc7f4d8a 100644
--- a/src/main/java/com/codejoust/main/game_object/Submission.java
+++ b/src/main/java/com/codejoust/main/game_object/Submission.java
@@ -13,6 +13,7 @@
public class Submission {
private PlayerCode playerCode;
+ private int problemIndex;
private List results;
diff --git a/src/main/java/com/codejoust/main/service/GameManagementService.java b/src/main/java/com/codejoust/main/service/GameManagementService.java
index 96a9bca0..510e1f07 100644
--- a/src/main/java/com/codejoust/main/service/GameManagementService.java
+++ b/src/main/java/com/codejoust/main/service/GameManagementService.java
@@ -186,6 +186,10 @@ public SubmissionDto runCode(String roomId, SubmissionRequest request) {
throw new ApiException(GameError.EMPTY_FIELD);
}
+ if (request.getProblemIndex() >= game.getProblems().size() || request.getProblemIndex() < 0) {
+ throw new ApiException(GameError.BAD_SETTING);
+ }
+
String initiatorUserId = request.getInitiator().getUserId();
if (!game.getPlayers().containsKey(initiatorUserId)) {
throw new ApiException(GameError.INVALID_PERMISSIONS);
@@ -202,6 +206,10 @@ public SubmissionDto submitSolution(String roomId, SubmissionRequest request) {
throw new ApiException(GameError.EMPTY_FIELD);
}
+ if (request.getProblemIndex() >= game.getProblems().size() || request.getProblemIndex() < 0) {
+ throw new ApiException(GameError.BAD_SETTING);
+ }
+
String initiatorUserId = request.getInitiator().getUserId();
if (!game.getPlayers().containsKey(initiatorUserId)) {
throw new ApiException(GameError.INVALID_PERMISSIONS);
diff --git a/src/main/java/com/codejoust/main/service/SubmitService.java b/src/main/java/com/codejoust/main/service/SubmitService.java
index e8f7f2ad..f3e113fa 100644
--- a/src/main/java/com/codejoust/main/service/SubmitService.java
+++ b/src/main/java/com/codejoust/main/service/SubmitService.java
@@ -92,21 +92,18 @@ private Submission getDummySubmission(TesterRequest request) {
// Test the submission and send a socket update.
public SubmissionDto runCode(Game game, SubmissionRequest request) {
String userId = request.getInitiator().getUserId();
- Player player = game.getPlayers().get(userId);
PlayerCode playerCode = new PlayerCode();
playerCode.setCode(request.getCode());
playerCode.setLanguage(request.getLanguage());
- player.setPlayerCode(playerCode);
-
// Make a call to the tester service
TesterRequest testerRequest = new TesterRequest();
testerRequest.setCode(request.getCode());
testerRequest.setLanguage(request.getLanguage());
// Set the problem with the single provided test case.
- ProblemDto problemDto = getStrippedProblemDto(game.getProblems().get(0));
+ ProblemDto problemDto = getStrippedProblemDto(game.getProblems().get(request.getProblemIndex()));
/**
* Provide a temporary output to circumvent output parsing error.
@@ -126,6 +123,7 @@ public SubmissionDto runCode(Game game, SubmissionRequest request) {
// Return submission, and no further records necessary for running code.
Submission submission = getSubmission(testerRequest);
+ submission.setProblemIndex(request.getProblemIndex());
return GameMapper.submissionToDto(submission);
}
@@ -138,30 +136,31 @@ public SubmissionDto submitSolution(Game game, SubmissionRequest request) {
playerCode.setCode(request.getCode());
playerCode.setLanguage(request.getLanguage());
- player.setPlayerCode(playerCode);
-
// Make a call to the tester service
TesterRequest testerRequest = new TesterRequest();
testerRequest.setCode(request.getCode());
testerRequest.setLanguage(request.getLanguage());
// Invariant: Games have at least one problem (else it will fail to create)
- ProblemDto problemDto = getStrippedProblemDto(game.getProblems().get(0));
+ ProblemDto problemDto = getStrippedProblemDto(game.getProblems().get(request.getProblemIndex()));
testerRequest.setProblem(problemDto);
Submission submission = getSubmission(testerRequest);
+ submission.setProblemIndex(request.getProblemIndex());
player.getSubmissions().add(submission);
if (submission.getNumCorrect().equals(submission.getNumTestCases())) {
- player.setSolved(true);
+ player.getSolved()[request.getProblemIndex()] = true;
}
// Variable to indicate whether all players have solved the problem.
boolean allSolved = true;
for (Player p : game.getPlayers().values()) {
- if (p.getSolved() == null || !p.getSolved()) {
- allSolved = false;
- break;
+ for (Boolean b : p.getSolved()) {
+ if (b == null || !b) {
+ allSolved = false;
+ break;
+ }
}
}
diff --git a/src/test/java/com/codejoust/main/mapper/GameMapperTests.java b/src/test/java/com/codejoust/main/mapper/GameMapperTests.java
index efdd3a77..6081578e 100644
--- a/src/test/java/com/codejoust/main/mapper/GameMapperTests.java
+++ b/src/test/java/com/codejoust/main/mapper/GameMapperTests.java
@@ -4,6 +4,7 @@
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -34,9 +35,10 @@ public class GameMapperTests {
private static final int TEST_CASES = 10;
// Helper method to add a dummy submission to a PlayerDto object
- private void addSubmissionHelper(PlayerDto playerDto, int numCorrect) {
+ private void addSubmissionHelper(PlayerDto playerDto, int numCorrect, int problemIndex) {
SubmissionDto submissionDto = new SubmissionDto();
submissionDto.setNumCorrect(numCorrect);
+ submissionDto.setProblemIndex(problemIndex);
submissionDto.setStartTime(Instant.now());
playerDto.getSubmissions().add(submissionDto);
@@ -104,7 +106,7 @@ public void toDto() {
submission.setNumCorrect(TEST_CASES);
Player player = game.getPlayers().get(TestFields.USER_ID);
- player.setSolved(true);
+ player.setSolved(new boolean[]{true});
player.setPlayerCode(playerCode);
player.getSubmissions().add(submission);
@@ -119,9 +121,7 @@ public void toDto() {
PlayerDto playerDto = gameDto.getPlayers().get(0);
assertEquals(UserMapper.toDto(user), playerDto.getUser());
- assertEquals(player.getSolved(), playerDto.getSolved());
- assertEquals(playerCode.getCode(), playerDto.getCode());
- assertEquals(playerCode.getLanguage(), playerDto.getLanguage());
+ assertArrayEquals(player.getSolved(), playerDto.getSolved());
assertEquals(1, playerDto.getSubmissions().size());
assertEquals(player.getColor(), playerDto.getColor());
@@ -159,20 +159,23 @@ public void sortLeaderboardSuccess() {
// Note: order of addSubmissionHelper matters (time of submission)
PlayerDto player1 = new PlayerDto();
- addSubmissionHelper(player1, 0);
+ addSubmissionHelper(player1, TEST_CASES, 0);
+ addSubmissionHelper(player1, TEST_CASES, 0);
+ addSubmissionHelper(player1, TEST_CASES, 0);
PlayerDto player2 = new PlayerDto();
- addSubmissionHelper(player2, 0);
- addSubmissionHelper(player2, 3);
+ addSubmissionHelper(player2, TEST_CASES, 0);
+ addSubmissionHelper(player2, TEST_CASES, 1);
PlayerDto player3 = new PlayerDto();
- addSubmissionHelper(player3, 3);
-
- addSubmissionHelper(player2, 3);
+ addSubmissionHelper(player3, 0, 0);
PlayerDto player4 = new PlayerDto();
- addSubmissionHelper(player4, 5);
- addSubmissionHelper(player4, 1);
+ addSubmissionHelper(player4, TEST_CASES, 0);
+ addSubmissionHelper(player4, TEST_CASES, 1);
+
+ // Player 2 submits wrong afterwards, but it doesn't count against his time
+ addSubmissionHelper(player2, 0, 1);
PlayerDto player5 = new PlayerDto();
@@ -182,13 +185,13 @@ public void sortLeaderboardSuccess() {
players.add(player4);
players.add(player5);
- // Player order should be: [4, 2, 3, 1, 5]
+ // Player order should be: [2, 4, 1, 3, 5]
GameMapper.sortLeaderboard(players);
- assertEquals(player4, players.get(0));
- assertEquals(player2, players.get(1));
- assertEquals(player3, players.get(2));
- assertEquals(player1, players.get(3));
+ assertEquals(player2, players.get(0));
+ assertEquals(player4, players.get(1));
+ assertEquals(player1, players.get(2));
+ assertEquals(player3, players.get(3));
assertEquals(player5, players.get(4));
}
@@ -196,8 +199,10 @@ public void sortLeaderboardSuccess() {
public void toDtoSortsLeaderboard() {
Submission sub1 = new Submission();
sub1.setNumCorrect(0);
+ sub1.setNumTestCases(TEST_CASES);
Submission sub2 = new Submission();
- sub2.setNumCorrect(1);
+ sub2.setNumCorrect(TEST_CASES);
+ sub2.setNumTestCases(TEST_CASES);
Player player1 = new Player();
player1.getSubmissions().add(sub1);
@@ -213,7 +218,7 @@ public void toDtoSortsLeaderboard() {
List players = gameDto.getPlayers();
assertEquals(2, players.size());
- assertEquals(1, players.get(0).getSubmissions().get(0).getNumCorrect());
+ assertEquals(TEST_CASES, players.get(0).getSubmissions().get(0).getNumCorrect());
assertEquals(0, players.get(1).getSubmissions().get(0).getNumCorrect());
}
}
diff --git a/src/test/java/com/codejoust/main/mapper/PlayerMapperTests.java b/src/test/java/com/codejoust/main/mapper/PlayerMapperTests.java
index 62f5161a..2c6e3063 100644
--- a/src/test/java/com/codejoust/main/mapper/PlayerMapperTests.java
+++ b/src/test/java/com/codejoust/main/mapper/PlayerMapperTests.java
@@ -5,7 +5,6 @@
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import com.codejoust.main.dto.game.PlayerMapper;
@@ -25,7 +24,6 @@ public void playerFromUser() {
assertEquals(user, player.getUser());
assertNull(player.getPlayerCode());
- assertFalse(player.getSolved());
assertEquals(0, player.getSubmissions().size());
}
}
diff --git a/src/test/java/com/codejoust/main/service/GameManagementServiceTests.java b/src/test/java/com/codejoust/main/service/GameManagementServiceTests.java
index fcd8f08c..6c6e5705 100644
--- a/src/test/java/com/codejoust/main/service/GameManagementServiceTests.java
+++ b/src/test/java/com/codejoust/main/service/GameManagementServiceTests.java
@@ -87,7 +87,7 @@ private void addSubmissionHelper(Player player, int numCorrect) {
player.getSubmissions().add(submission);
if (numCorrect == TestFields.NUM_PROBLEMS) {
- player.setSolved(true);
+ player.setSolved(new boolean[]{true});
}
}
diff --git a/src/test/java/com/codejoust/main/service/RoomServiceTests.java b/src/test/java/com/codejoust/main/service/RoomServiceTests.java
index 87f1e779..a88c390e 100644
--- a/src/test/java/com/codejoust/main/service/RoomServiceTests.java
+++ b/src/test/java/com/codejoust/main/service/RoomServiceTests.java
@@ -277,6 +277,31 @@ public void manyUsersJoiningAnInfinitelySizedRoomSuccess() {
assertEquals(102, room.getUsers().size());
}
+ @Test
+ public void setInvalidNumProblemsFailure() {
+ /**
+ * Verify update settings request fails when numProblems is
+ * set to outside of the allowable range
+ */
+ User host = new User();
+ host.setNickname(TestFields.NICKNAME);
+
+ Room room = new Room();
+ room.setRoomId(TestFields.ROOM_ID);
+ room.setHost(host);
+ room.addUser(host);
+
+ UpdateSettingsRequest request = new UpdateSettingsRequest();
+ request.setInitiator(UserMapper.toDto(host));
+ request.setNumProblems(15);
+
+ // Mock repository to return room when called
+ Mockito.doReturn(room).when(repository).findRoomByRoomId(eq(TestFields.ROOM_ID));
+ ApiException exception = assertThrows(ApiException.class, () -> roomService.updateRoomSettings(TestFields.ROOM_ID, request));
+
+ verify(repository).findRoomByRoomId(TestFields.ROOM_ID);
+ assertEquals(ProblemError.INVALID_NUMBER_REQUEST, exception.getError());
+ }
@Test
public void getRoomSuccess() {