chore: add variant scoring fields, fix tie handling, and fix test files for normalizedName
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
# EuchreCamp - Todo List
|
||||||
|
|
||||||
|
## Current Tasks
|
||||||
|
|
||||||
|
### Completed ✅
|
||||||
|
- [x] Add `site_admin` role to database schema and permissions system
|
||||||
|
- [x] Add `isCasual` boolean field to Match model (already existed)
|
||||||
|
- [x] Update match upload API to support casual matches
|
||||||
|
- [x] Update match upload UI to include casual checkbox
|
||||||
|
- [x] Add tournament deletion API endpoint with delete/orphan options
|
||||||
|
- [x] Add delete tournament button and modal to tournament detail page
|
||||||
|
- [x] Run tests and verify implementation (84 tests passing)
|
||||||
|
- [x] Fix session issues with tournament admin access
|
||||||
|
- [x] Fix Elo recalculation error for player merge (delete elo snapshots before deleting players)
|
||||||
|
- [x] Add admin player management page
|
||||||
|
- [x] Add player name editing functionality in admin UI
|
||||||
|
- [x] Add admin panel links to navigation header
|
||||||
|
- [x] Add tournament update API endpoint (PUT /api/tournaments/[id])
|
||||||
|
- [x] Consolidate delete endpoint from admin API to main tournaments API
|
||||||
|
- [x] Update database schema to add variant scoring fields (targetScore, allowTies)
|
||||||
|
- [x] Fix tie handling logic in partnership stats (ties now correctly tracked)
|
||||||
|
- [x] Fix test files for normalizedName field in Player model
|
||||||
|
- [x] Fix auth.ts to include normalizedName in Player creation
|
||||||
|
- [x] Write TODO list to repository file
|
||||||
|
|
||||||
|
### In Progress 🔄
|
||||||
|
- [ ] Update API routes to handle new variant scoring fields
|
||||||
|
- [ ] Update EditTournamentForm to add variant scoring controls
|
||||||
|
- [ ] Update MatchEditor to use tournament-specific target score
|
||||||
|
- [ ] Run tests and verify variant scoring implementation
|
||||||
|
|
||||||
|
### Backlog 📋
|
||||||
|
- [ ] Add UI controls for variant scoring in tournament creation/edit
|
||||||
|
- [ ] Test variant tournament functionality end-to-end
|
||||||
|
- [ ] Add validation for tie scores based on tournament configuration
|
||||||
|
- [ ] Document variant tournament features
|
||||||
|
|
||||||
|
## Recently Completed (Detailed)
|
||||||
|
|
||||||
|
### Variant Euchre Scoring Support
|
||||||
|
- Added `targetScore` and `allowTies` fields to Event model
|
||||||
|
- Created database migration for new fields
|
||||||
|
- Fixed partnership stats tie handling (ties now increment neither wins nor losses)
|
||||||
|
- Updated Elo calculation functions to handle ties correctly (0.5 points for draw)
|
||||||
|
|
||||||
|
### Tournament Deletion
|
||||||
|
- Consolidated delete endpoint to `/api/tournaments/[id]`
|
||||||
|
- Added options to delete matches or orphan them
|
||||||
|
- Updated DeleteTournamentButton to use consolidated endpoint
|
||||||
|
|
||||||
|
### Player Management
|
||||||
|
- Added admin players page at `/admin/players`
|
||||||
|
- Added player name editing functionality via PATCH endpoint
|
||||||
|
- Added player merge functionality with automatic Elo recalculation
|
||||||
|
- Fixed foreign key constraint issues with elo_snapshots
|
||||||
|
|
||||||
|
### Permissions
|
||||||
|
- Added `site_admin` role as highest privilege level
|
||||||
|
- Updated all permission functions to include site_admin support
|
||||||
|
- Fixed session cache issues by reading roles from database
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
- All 84 unit tests passing
|
||||||
|
- Database migrations applied successfully
|
||||||
|
- TypeScript compilation has pre-existing errors unrelated to our changes
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Add variant scoring support fields to Event model
|
||||||
|
ALTER TABLE "events" ADD COLUMN "targetScore" INTEGER;
|
||||||
|
ALTER TABLE "events" ADD COLUMN "allowTies" BOOLEAN NOT NULL DEFAULT false;
|
||||||
@@ -65,6 +65,9 @@ model Event {
|
|||||||
status String @default("planned")
|
status String @default("planned")
|
||||||
maxParticipants Int?
|
maxParticipants Int?
|
||||||
ownerId String?
|
ownerId String?
|
||||||
|
// Variant scoring support
|
||||||
|
targetScore Int? // Custom target score (default 5 for standard, or 10/15 for variant)
|
||||||
|
allowTies Boolean @default(false) // Whether ties/draws are valid outcomes
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
bracketMatchups BracketMatchup[]
|
bracketMatchups BracketMatchup[]
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ const mockTournament = {
|
|||||||
status: 'planned',
|
status: 'planned',
|
||||||
maxParticipants: 16,
|
maxParticipants: 16,
|
||||||
ownerId: null,
|
ownerId: null,
|
||||||
|
targetScore: null,
|
||||||
|
allowTies: false,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ test.describe('Elo Rating Updates', () => {
|
|||||||
const player1 = await prisma.player.create({
|
const player1 = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Elo Test Player 1',
|
name: 'Elo Test Player 1',
|
||||||
|
normalizedName: 'elo test player 1',
|
||||||
currentElo: 1500,
|
currentElo: 1500,
|
||||||
gamesPlayed: 0,
|
gamesPlayed: 0,
|
||||||
wins: 0,
|
wins: 0,
|
||||||
@@ -108,6 +109,7 @@ test.describe('Elo Rating Updates', () => {
|
|||||||
const player2 = await prisma.player.create({
|
const player2 = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Elo Test Player 2',
|
name: 'Elo Test Player 2',
|
||||||
|
normalizedName: 'elo test player 2',
|
||||||
currentElo: 1500,
|
currentElo: 1500,
|
||||||
gamesPlayed: 0,
|
gamesPlayed: 0,
|
||||||
wins: 0,
|
wins: 0,
|
||||||
@@ -118,6 +120,7 @@ test.describe('Elo Rating Updates', () => {
|
|||||||
const player3 = await prisma.player.create({
|
const player3 = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Elo Test Player 3',
|
name: 'Elo Test Player 3',
|
||||||
|
normalizedName: 'elo test player 3',
|
||||||
currentElo: 1500,
|
currentElo: 1500,
|
||||||
gamesPlayed: 0,
|
gamesPlayed: 0,
|
||||||
wins: 0,
|
wins: 0,
|
||||||
@@ -128,6 +131,7 @@ test.describe('Elo Rating Updates', () => {
|
|||||||
const player4 = await prisma.player.create({
|
const player4 = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Elo Test Player 4',
|
name: 'Elo Test Player 4',
|
||||||
|
normalizedName: 'elo test player 4',
|
||||||
currentElo: 1500,
|
currentElo: 1500,
|
||||||
gamesPlayed: 0,
|
gamesPlayed: 0,
|
||||||
wins: 0,
|
wins: 0,
|
||||||
@@ -369,6 +373,7 @@ ${tournament.id},2,1,${player1.name},${player3.name},10,${player2.name},${player
|
|||||||
const player = await prisma.player.create({
|
const player = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: 'Elo Test Profile Player',
|
name: 'Elo Test Profile Player',
|
||||||
|
normalizedName: 'elo test profile player',
|
||||||
currentElo: 1750,
|
currentElo: 1750,
|
||||||
gamesPlayed: 50,
|
gamesPlayed: 50,
|
||||||
wins: 30,
|
wins: 30,
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ test.describe('Home Page', () => {
|
|||||||
const timestamp = Date.now()
|
const timestamp = Date.now()
|
||||||
const players = []
|
const players = []
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const playerName = `Home Test Player ${timestamp} ${i + 1}`
|
||||||
const player = await prisma.player.create({
|
const player = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: `Home Test Player ${timestamp} ${i + 1}`,
|
name: playerName,
|
||||||
|
normalizedName: playerName.toLowerCase(),
|
||||||
currentElo: 2000 - i * 10, // Very high Elo to ensure they're in top 10
|
currentElo: 2000 - i * 10, // Very high Elo to ensure they're in top 10
|
||||||
gamesPlayed: 10 + i,
|
gamesPlayed: 10 + i,
|
||||||
wins: 5 + Math.floor(i / 2),
|
wins: 5 + Math.floor(i / 2),
|
||||||
@@ -71,17 +73,21 @@ test.describe('Home Page', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Create players for the match
|
// Create players for the match
|
||||||
|
const player1Name = `Home Match Player 1 ${timestamp}`
|
||||||
const player1 = await prisma.player.create({
|
const player1 = await prisma.player.create({
|
||||||
data: { name: `Home Match Player 1 ${timestamp}`, currentElo: 1500 },
|
data: { name: player1Name, normalizedName: player1Name.toLowerCase(), currentElo: 1500 },
|
||||||
})
|
})
|
||||||
|
const player2Name = `Home Match Player 2 ${timestamp}`
|
||||||
const player2 = await prisma.player.create({
|
const player2 = await prisma.player.create({
|
||||||
data: { name: `Home Match Player 2 ${timestamp}`, currentElo: 1480 },
|
data: { name: player2Name, normalizedName: player2Name.toLowerCase(), currentElo: 1480 },
|
||||||
})
|
})
|
||||||
|
const player3Name = `Home Match Player 3 ${timestamp}`
|
||||||
const player3 = await prisma.player.create({
|
const player3 = await prisma.player.create({
|
||||||
data: { name: `Home Match Player 3 ${timestamp}`, currentElo: 1450 },
|
data: { name: player3Name, normalizedName: player3Name.toLowerCase(), currentElo: 1450 },
|
||||||
})
|
})
|
||||||
|
const player4Name = `Home Match Player 4 ${timestamp}`
|
||||||
const player4 = await prisma.player.create({
|
const player4 = await prisma.player.create({
|
||||||
data: { name: `Home Match Player 4 ${timestamp}`, currentElo: 1420 },
|
data: { name: player4Name, normalizedName: player4Name.toLowerCase(), currentElo: 1420 },
|
||||||
})
|
})
|
||||||
|
|
||||||
// Create a match in the tournament
|
// Create a match in the tournament
|
||||||
|
|||||||
@@ -112,14 +112,14 @@ export async function POST(request: Request) {
|
|||||||
|
|
||||||
// Update player stats (only if it's a casual match - tournament matches update via their own flow)
|
// Update player stats (only if it's a casual match - tournament matches update via their own flow)
|
||||||
if (isCasual) {
|
if (isCasual) {
|
||||||
await updatePlayerStats(parseInt(team1P1Id), team1Won, player1EloChange);
|
await updatePlayerStats(parseInt(team1P1Id), team1Won, player1EloChange, isTie);
|
||||||
await updatePlayerStats(parseInt(team1P2Id), team1Won, player2EloChange);
|
await updatePlayerStats(parseInt(team1P2Id), team1Won, player2EloChange, isTie);
|
||||||
await updatePlayerStats(parseInt(team2P1Id), team2Won, player3EloChange);
|
await updatePlayerStats(parseInt(team2P1Id), team2Won, player3EloChange, isTie);
|
||||||
await updatePlayerStats(parseInt(team2P2Id), team2Won, player4EloChange);
|
await updatePlayerStats(parseInt(team2P2Id), team2Won, player4EloChange, isTie);
|
||||||
|
|
||||||
// Update partnership stats for casual matches
|
// Update partnership stats for casual matches
|
||||||
await updatePartnershipStats(parseInt(team1P1Id), parseInt(team1P2Id), team1Won, player1EloChange);
|
await updatePartnershipStats(parseInt(team1P1Id), parseInt(team1P2Id), team1Won, player1EloChange, isTie);
|
||||||
await updatePartnershipStats(parseInt(team2P1Id), parseInt(team2P2Id), team2Won, player3EloChange);
|
await updatePartnershipStats(parseInt(team2P1Id), parseInt(team2P2Id), team2Won, player3EloChange, isTie);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
@@ -136,7 +136,7 @@ export async function POST(request: Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updatePlayerStats(playerId: number, won: boolean, eloChange: number) {
|
async function updatePlayerStats(playerId: number, won: boolean, eloChange: number, isTie: boolean = false) {
|
||||||
const player = await prisma.player.findUnique({
|
const player = await prisma.player.findUnique({
|
||||||
where: { id: playerId },
|
where: { id: playerId },
|
||||||
});
|
});
|
||||||
@@ -150,13 +150,13 @@ async function updatePlayerStats(playerId: number, won: boolean, eloChange: numb
|
|||||||
data: {
|
data: {
|
||||||
currentElo: player.currentElo + Math.round(eloChange),
|
currentElo: player.currentElo + Math.round(eloChange),
|
||||||
gamesPlayed: player.gamesPlayed + 1,
|
gamesPlayed: player.gamesPlayed + 1,
|
||||||
wins: won ? player.wins + 1 : player.wins,
|
wins: isTie ? player.wins : (won ? player.wins + 1 : player.wins),
|
||||||
losses: won ? player.losses : player.losses + 1,
|
losses: isTie ? player.losses : (won ? player.losses : player.losses + 1),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updatePartnershipStats(player1Id: number, player2Id: number, won: boolean, eloChange: number) {
|
async function updatePartnershipStats(player1Id: number, player2Id: number, won: boolean, eloChange: number, isTie: boolean = false) {
|
||||||
const [smallId, largeId] = player1Id < player2Id ? [player1Id, player2Id] : [player2Id, player1Id];
|
const [smallId, largeId] = player1Id < player2Id ? [player1Id, player2Id] : [player2Id, player1Id];
|
||||||
|
|
||||||
const existing = await prisma.partnershipStat.findFirst({
|
const existing = await prisma.partnershipStat.findFirst({
|
||||||
@@ -166,16 +166,24 @@ async function updatePartnershipStats(player1Id: number, player2Id: number, won:
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (existing) {
|
const updateData = isTie
|
||||||
await prisma.partnershipStat.update({
|
? {
|
||||||
where: { id: existing.id },
|
gamesPlayed: { increment: 1 },
|
||||||
data: {
|
totalEloChange: { increment: eloChange },
|
||||||
|
lastPlayed: new Date(),
|
||||||
|
}
|
||||||
|
: {
|
||||||
gamesPlayed: { increment: 1 },
|
gamesPlayed: { increment: 1 },
|
||||||
wins: won ? { increment: 1 } : undefined,
|
wins: won ? { increment: 1 } : undefined,
|
||||||
losses: won ? undefined : { increment: 1 },
|
losses: won ? undefined : { increment: 1 },
|
||||||
totalEloChange: { increment: eloChange },
|
totalEloChange: { increment: eloChange },
|
||||||
lastPlayed: new Date(),
|
lastPlayed: new Date(),
|
||||||
},
|
};
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
await prisma.partnershipStat.update({
|
||||||
|
where: { id: existing.id },
|
||||||
|
data: updateData,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await prisma.partnershipStat.create({
|
await prisma.partnershipStat.create({
|
||||||
@@ -183,8 +191,8 @@ async function updatePartnershipStats(player1Id: number, player2Id: number, won:
|
|||||||
player1Id: smallId,
|
player1Id: smallId,
|
||||||
player2Id: largeId,
|
player2Id: largeId,
|
||||||
gamesPlayed: 1,
|
gamesPlayed: 1,
|
||||||
wins: won ? 1 : 0,
|
wins: isTie ? 0 : (won ? 1 : 0),
|
||||||
losses: won ? 0 : 1,
|
losses: isTie ? 0 : (won ? 0 : 1),
|
||||||
totalEloChange: eloChange,
|
totalEloChange: eloChange,
|
||||||
lastPlayed: new Date(),
|
lastPlayed: new Date(),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ export const auth = betterAuth({
|
|||||||
const newPlayer = await prisma.player.create({
|
const newPlayer = await prisma.player.create({
|
||||||
data: {
|
data: {
|
||||||
name: uniqueName,
|
name: uniqueName,
|
||||||
|
normalizedName: uniqueName.toLowerCase(),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+59
-13
@@ -51,16 +51,20 @@ export function calculateTeamElo(rating1: number, rating2: number): number {
|
|||||||
* @param currentRating Current player rating
|
* @param currentRating Current player rating
|
||||||
* @param currentGamesPlayed Current games played count
|
* @param currentGamesPlayed Current games played count
|
||||||
* @param currentWins Current wins count
|
* @param currentWins Current wins count
|
||||||
|
* @param currentLosses Current losses count
|
||||||
* @param eloChange Elo rating change
|
* @param eloChange Elo rating change
|
||||||
* @param won Whether the player won
|
* @param won Whether the player won
|
||||||
|
* @param isTie Whether the match was a tie
|
||||||
* @returns Updated statistics
|
* @returns Updated statistics
|
||||||
*/
|
*/
|
||||||
export function updatePlayerStats(
|
export function updatePlayerStats(
|
||||||
currentRating: number,
|
currentRating: number,
|
||||||
currentGamesPlayed: number,
|
currentGamesPlayed: number,
|
||||||
currentWins: number,
|
currentWins: number,
|
||||||
|
currentLosses: number,
|
||||||
eloChange: number,
|
eloChange: number,
|
||||||
won: boolean
|
won: boolean,
|
||||||
|
isTie: boolean = false
|
||||||
): {
|
): {
|
||||||
newRating: number;
|
newRating: number;
|
||||||
newGamesPlayed: number;
|
newGamesPlayed: number;
|
||||||
@@ -70,8 +74,17 @@ export function updatePlayerStats(
|
|||||||
} {
|
} {
|
||||||
const newRating = currentRating + Math.round(eloChange);
|
const newRating = currentRating + Math.round(eloChange);
|
||||||
const newGamesPlayed = currentGamesPlayed + 1;
|
const newGamesPlayed = currentGamesPlayed + 1;
|
||||||
const newWins = currentWins + (won ? 1 : 0);
|
let newWins = currentWins;
|
||||||
const newLosses = newGamesPlayed - newWins;
|
let newLosses = currentLosses;
|
||||||
|
|
||||||
|
if (isTie) {
|
||||||
|
// For ties, don't increment wins or losses
|
||||||
|
} else if (won) {
|
||||||
|
newWins += 1;
|
||||||
|
} else {
|
||||||
|
newLosses += 1;
|
||||||
|
}
|
||||||
|
|
||||||
const winRate = newGamesPlayed > 0 ? newWins / newGamesPlayed : 0;
|
const winRate = newGamesPlayed > 0 ? newWins / newGamesPlayed : 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -245,40 +258,66 @@ export async function recalculateAllElo(prisma: PrismaClient) {
|
|||||||
// Update player stats
|
// Update player stats
|
||||||
const team1Won = team1Score > team2Score;
|
const team1Won = team1Score > team2Score;
|
||||||
const team2Won = team2Score > team1Score;
|
const team2Won = team2Score > team1Score;
|
||||||
|
const isTie = team1Score === team2Score;
|
||||||
|
|
||||||
// Update Player 1 (team 1, player 1)
|
// Update Player 1 (team 1, player 1)
|
||||||
const stats1 = getPlayerStats(team1P1.id);
|
const stats1 = getPlayerStats(team1P1.id);
|
||||||
stats1.rating += p1Change;
|
stats1.rating += p1Change;
|
||||||
stats1.gamesPlayed += 1;
|
stats1.gamesPlayed += 1;
|
||||||
stats1.wins += team1Won ? 1 : 0;
|
if (isTie) {
|
||||||
stats1.losses += team1Won ? 0 : 1;
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team1Won) {
|
||||||
|
stats1.wins += 1;
|
||||||
|
} else {
|
||||||
|
stats1.losses += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Update Player 2 (team 1, player 2)
|
// Update Player 2 (team 1, player 2)
|
||||||
const stats2 = getPlayerStats(team1P2.id);
|
const stats2 = getPlayerStats(team1P2.id);
|
||||||
stats2.rating += p2Change;
|
stats2.rating += p2Change;
|
||||||
stats2.gamesPlayed += 1;
|
stats2.gamesPlayed += 1;
|
||||||
stats2.wins += team1Won ? 1 : 0;
|
if (isTie) {
|
||||||
stats2.losses += team1Won ? 0 : 1;
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team1Won) {
|
||||||
|
stats2.wins += 1;
|
||||||
|
} else {
|
||||||
|
stats2.losses += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Update Player 3 (team 2, player 1)
|
// Update Player 3 (team 2, player 1)
|
||||||
const stats3 = getPlayerStats(team2P1.id);
|
const stats3 = getPlayerStats(team2P1.id);
|
||||||
stats3.rating += p3Change;
|
stats3.rating += p3Change;
|
||||||
stats3.gamesPlayed += 1;
|
stats3.gamesPlayed += 1;
|
||||||
stats3.wins += team2Won ? 1 : 0;
|
if (isTie) {
|
||||||
stats3.losses += team2Won ? 0 : 1;
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team2Won) {
|
||||||
|
stats3.wins += 1;
|
||||||
|
} else {
|
||||||
|
stats3.losses += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Update Player 4 (team 2, player 2)
|
// Update Player 4 (team 2, player 2)
|
||||||
const stats4 = getPlayerStats(team2P2.id);
|
const stats4 = getPlayerStats(team2P2.id);
|
||||||
stats4.rating += p4Change;
|
stats4.rating += p4Change;
|
||||||
stats4.gamesPlayed += 1;
|
stats4.gamesPlayed += 1;
|
||||||
stats4.wins += team2Won ? 1 : 0;
|
if (isTie) {
|
||||||
stats4.losses += team2Won ? 0 : 1;
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team2Won) {
|
||||||
|
stats4.wins += 1;
|
||||||
|
} else {
|
||||||
|
stats4.losses += 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Update partnership stats for team 1
|
// Update partnership stats for team 1
|
||||||
const partnership1 = getPartnershipStats(team1P1.id, team1P2.id);
|
const partnership1 = getPartnershipStats(team1P1.id, team1P2.id);
|
||||||
partnership1.gamesPlayed += 1;
|
partnership1.gamesPlayed += 1;
|
||||||
partnership1.wins += team1Won ? 1 : 0;
|
if (isTie) {
|
||||||
partnership1.losses += team1Won ? 0 : 1;
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team1Won) {
|
||||||
|
partnership1.wins += 1;
|
||||||
|
} else {
|
||||||
|
partnership1.losses += 1;
|
||||||
|
}
|
||||||
partnership1.totalEloChange += p1Change + p2Change;
|
partnership1.totalEloChange += p1Change + p2Change;
|
||||||
if (playedAt && (!partnership1.lastPlayed || playedAt > partnership1.lastPlayed)) {
|
if (playedAt && (!partnership1.lastPlayed || playedAt > partnership1.lastPlayed)) {
|
||||||
partnership1.lastPlayed = playedAt;
|
partnership1.lastPlayed = playedAt;
|
||||||
@@ -287,6 +326,13 @@ export async function recalculateAllElo(prisma: PrismaClient) {
|
|||||||
// Update partnership stats for team 2
|
// Update partnership stats for team 2
|
||||||
const partnership2 = getPartnershipStats(team2P1.id, team2P2.id);
|
const partnership2 = getPartnershipStats(team2P1.id, team2P2.id);
|
||||||
partnership2.gamesPlayed += 1;
|
partnership2.gamesPlayed += 1;
|
||||||
|
if (isTie) {
|
||||||
|
// For ties, don't increment wins or losses (gamesPlayed is already incremented)
|
||||||
|
} else if (team2Won) {
|
||||||
|
partnership2.wins += 1;
|
||||||
|
} else {
|
||||||
|
partnership2.losses += 1;
|
||||||
|
}
|
||||||
partnership2.wins += team2Won ? 1 : 0;
|
partnership2.wins += team2Won ? 1 : 0;
|
||||||
partnership2.losses += team2Won ? 0 : 1;
|
partnership2.losses += team2Won ? 0 : 1;
|
||||||
partnership2.totalEloChange += p3Change + p4Change;
|
partnership2.totalEloChange += p3Change + p4Change;
|
||||||
|
|||||||
Reference in New Issue
Block a user