Skip to content

Commit

Permalink
improve versus battle
Browse files Browse the repository at this point in the history
  • Loading branch information
ReDBrother committed Apr 11, 2024
1 parent 2a3d15d commit b2aa41d
Show file tree
Hide file tree
Showing 6 changed files with 240 additions and 4 deletions.
188 changes: 188 additions & 0 deletions services/app/apps/codebattle/assets/js/widgets/machines/waitingRoom.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import { assign } from 'xstate';

const states = {
room: {
none: 'none',
active: 'active',
inactive: 'inactive',
},
player: {
ready: 'ready',
baned: 'baned',
},
matchmaking: {
progress: 'matchmaking.progress',
success: 'matchmaking.success',
paused: 'matchmaking.paused',
},
};

const machine = {
id: 'waitingRoom',
type: 'parallel',
initial: 'none',
context: {
waitingPlayers: [],
pausedPlayers: [],
finishedPlayers: [],
banedPlayers: [],
errorMessage: null,
},
states: {
status: {
initial: 'none',
on: {
'waiting_room:started': 'active',
},
states: {
none: {
on: {
LOAD_WAITING_ROOM: 'active',
REJECT_LOADING: 'inactive',
FAILED_LOADING: {
target: 'failure',
actions: ['handleError', 'throwError'],
},
},
},
active: {
entry: ['loadWaitingRoom'],
on: {
'waiting_room:ended': 'inactive',
'waiting_room:player:matchmaking_started': {
actions: 'addWaitingPlayer',
},
'waiting_room:player:matchmaking_paused': {
actions: 'addPausedPlayer',
},
'waiting_room:player:match_created': {
actions: 'removeWaitingPlayer',
},
'waiting_room:player:banned': {
actions: 'addBannedPlayer',
},
'waiting_room:player:unbanned': {
actions: 'removeBannedPlayer',
},
'waiting_room:player:finished': {
actions: 'addFinishedPlayer',
},
},
exit: ['unloadWaitingRoom'],
},
inactive: {},
failure: {},
},
},
player: {
initial: 'ready',
states: {
ready: {
on: {
'waiting_room:player:baned': 'baned',
'waiting_room:player:matchmaking_started': 'matchmaking',
'waiting_room:started': [
{ target: 'matchmaking.paused', cond: 'isMatchmakingPaused' },
{ target: 'matchmaking' },
],
},
},
matchmaking: {
initial: 'progress',
on: {
'waiting_room:player:baned': 'baned',
'waiting_room:player:matchmaking_stoped': 'ready',
},
states: {
progress: {
on: {
'waiting_room:player:matchmaking_paused': 'paused',
'waiting_room:player:match_created': 'success',
},
},
success: {},
paused: {
on: {
'waiting_room:player:matchmaking_restarted': 'progress',
},
},
},
},
baned: {
on: {
'waiting_room:player:unbaned': [
{ target: 'matchmaking', cond: 'isMatchmakingInProgress' },
{ target: 'ready' },
],
},
},
},
},
},
};

export const config = {
guards: {
isMatchmakingInProgress: (_ctx, { payload }) => !!payload.isWait,
isMatchmakingPaused: (_ctx, { payload }) => !!payload.isPaused,
},
actions: {
loadWaitingRoom: assign({
errorMessage: null,
waitingPlayers: (_ctx, { payload }) => payload?.waitingPlayers || [],
pausedPlayers: (_ctx, { payload }) => payload?.pausedPlayers || [],
finishedPlayers: (_ctx, { payload }) => payload?.finishedPlayers || [],
banedPlayers: (_ctx, { payload }) => payload?.banedPlayers || [],
}),
unloadWaitingRoom: assign({
errorMessage: null,
waitingPlayers: [],
pausedPlayers: [],
finishedPlayers: [],
banedPlayers: [],
}),
addWaitingPlayer: assign({
waitingPlayers: (ctx, { payload }) => (
payload.playerId
? ctx.waitingPlayers.push(payload?.playerId)
: ctx.waitingPlayers
),
pausedPlayers: (ctx, { payload }) => (
ctx.pausedPlayers.filter(payload.playerId)
),
finishedPlayers: (ctx, { payload }) => (
ctx.finishedPlayers.filter(payload.playerId)
),
}),
addPausedPlayer: assign({
waitingPlayers: (ctx, { payload }) => (
ctx.waitingPlayers.filter(payload.playerId)
),
pausedPlayers: (ctx, { payload }) => (
payload.playerId
? ctx.pausedPlayers.push(payload?.playerId)
: ctx.pausedPlayers
),
}),
removeWaitingPlayer: assign({
waitingPlayers: (ctx, { payload }) => (
ctx.waitingPlayers.filter(payload.playerId)
),
}),
addBannedPlayer: assign({
waitingPlayers: (ctx, { payload }) => (
ctx.waitingPlayers.filter(payload.playerId)
),
pausedPlayers: (ctx, { payload }) => (
ctx.pausedPlayers.filter(payload.playerId)
),
}),
handleError: assign({
errorMessage: (_ctx, { payload }) => payload.message,
}),
},
};

export const waitingRoomMachineStates = states;

export default machine;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import TournamentGameCreatePanel from './TournamentGameCreatePanel';
function CustomTournamentInfoPanel({
roundsLimit = 1,
currentRoundPosition = 0,
matchTimeoutSeconds,
matches,
players,
taskList,
Expand Down Expand Up @@ -45,6 +46,7 @@ function CustomTournamentInfoPanel({
matches={matches}
taskList={taskList}
currentRoundPosition={currentRoundPosition}
defaultMatchTimeoutSeconds={matchTimeoutSeconds}
/>
)}
<SwitchTransition mode="out-in">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function InfoPanel({
return (
<CustomTournamentInfoPanel
players={tournament.players}
matchTimeoutSeconds={tournament.matchTimeoutSeconds}
taskList={tournament.taskList}
topPlayerIds={tournament.topPlayerIds}
matches={tournament.matches}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ function TournamentGameCreatePanel({
matches,
taskList = [],
currentRoundPosition,
defaultMatchTimeoutSeconds,
}) {
const [selectedPlayer, setSelectedPlayer] = useState(emptyPlayer);
const [opponentPlayer, setOpponentPlayer] = useState(emptyPlayer);
const [selectedTaskLevel, setSelectedTaskLevel] = useState();
const [selectedTimeoutSeconds, setSelectedTimeoutSeconds] = useState();

const activeMatch = useMemo(() => {
if (!selectedPlayer) return null;

Expand Down Expand Up @@ -208,6 +211,33 @@ function TournamentGameCreatePanel({
<FontAwesomeIcon icon="pen" />
</button>
</div>
<div className="d-flex align-items-baseline px-1">
<input
id="round-seconds"
name="round-seconds"
type="number"
min="180"
max="7200"
step="60"
placeholder={defaultMatchTimeoutSeconds}
value={selectedTimeoutSeconds}
onChange={event => {
const newTimeout = Number(event.target.value);

if (newTimeout >= 180 && newTimeout <= 7200) {
setSelectedTimeoutSeconds(Number(event.target.value));
} else if (newTimeout <= 180) {
setSelectedTimeoutSeconds(180);
} else if (newTimeout >= 7200) {
setSelectedTimeoutSeconds(7200);
}
}}
className="my-1 mr-1"
/>
<label htmlFor="round-seconds">
Match seconds
</label>
</div>
{activeMatch ? (
<button
type="button"
Expand All @@ -222,7 +252,8 @@ function TournamentGameCreatePanel({
className="btn btn-sm btn-secondary rounded-lg p-1"
onClick={() => {
createCustomRound({
task_level: selectedTaskLevel,
task_id: availableTasks[selectedTaskLevel][0]?.id,
timeout_seconds: selectedTimeoutSeconds,
});
}}
disabled={availableTasks[selectedTaskLevel].length < 1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,9 @@ defmodule Codebattle.Tournament.Base do
tournament
|> update_struct(%{
break_state: "off",
last_round_started_at: NaiveDateTime.utc_now(:second)
last_round_started_at: NaiveDateTime.utc_now(:second),
match_timeout_seconds:
Map.get(round_params, :timeout_seconds, get_round_timeout_seconds(tournament))
})
|> build_and_save_round!()
|> maybe_preload_tasks()
Expand Down Expand Up @@ -493,10 +495,12 @@ defmodule Codebattle.Tournament.Base do
end

defp bulk_insert_round_games({tournament, player_pairs}, round_params) do
task_id = get_task_id_by_params(round_params)

player_pairs
|> Enum.with_index(matches_count(tournament))
|> Enum.chunk_every(50)
|> Enum.each(&bulk_create_round_games_and_matches(&1, tournament, nil))
|> Enum.each(&bulk_create_round_games_and_matches(&1, tournament, task_id))

tournament
end
Expand Down Expand Up @@ -725,6 +729,9 @@ defmodule Codebattle.Tournament.Base do
defp get_score("win_loss", level, player_result, _duration_sec) do
Score.WinLoss.get_score(level, player_result)
end

defp get_task_id_by_params(%{task_id: task_id}), do: task_id
defp get_task_id_by_params(_round_params), do: nil
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,14 @@ defmodule CodebattleWeb.TournamentChannel do
end
end

defp cast_start_round_params(%{"task_level" => level, "timeout_seconds" => seconds}),
do: %{task_level: level, timeout_seconds: seconds}

defp cast_start_round_params(%{"task_level" => level}), do: %{task_level: level}
defp cast_start_round_params(%{"task_id" => level}), do: %{task_id: level}

defp cast_start_round_params(%{"task_id" => id, "timeout_seconds" => seconds}),
do: %{task_id: id, timeout_seconds: seconds}

defp cast_start_round_params(%{"task_id" => id}), do: %{task_id: id}
defp cast_start_round_params(_params), do: %{}
end

0 comments on commit b2aa41d

Please sign in to comment.