Created
October 5, 2024 19:44
-
-
Save hising/742ef56f38e17fec87eda46cfae00f3b to your computer and use it in GitHub Desktop.
IK Sirius - Last 5 2024
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Football Points Simulation</title> | |
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script> | |
</head> | |
<body> | |
<canvas id="resultsChart" width="400" height="200"></canvas> | |
<h3>Top 3 Most Probable Points</h3> | |
<ul id="topThreePoints"></ul> | |
<h3>Additional Insights</h3> | |
<ul id="additionalStats"></ul> | |
<script> | |
// Number of simulations and games | |
const simulations = 10000; | |
const games = 5; | |
// Elfsborg, Halmstad, Hammarby, Mjällbu, GAIS | |
// Array of opponent strengths (adjust based on opponent difficulty, 0 to 1 scale) | |
const opponents_strength = [1, 0.3, 0.7, 0.6, 0.5]; // Strength of each opponent | |
const team_strength = 0.5; | |
// Home/Away modifier | |
const homeAway = [true, false, true, true, false]; // True = home, False = away | |
const homeAdvantage = 0.1; // Boost for home games | |
// Injuries and fatigue modifiers | |
const injuryImpact = [0, 0, 0, 0, 0]; | |
const fatigueFactor = [-0.3, 0, 0, 0, 0]; | |
// New factors based on team form and motivation | |
const motivationFactor = [1.2, 1.2, 1.2, 1.2, 0.8]; // 1.2 = high motivation (survival or Europe), 0.8 = less motivation (mid-table) | |
// Form-based multipliers (e.g., 1.1 for winning streak, 0.9 for losing streak) | |
const formMultiplier = [1, .9, 0.95, .95, .9]; // Reflects how recent form affects team performance | |
// Function to calculate win probability based on team, opponent strength, and motivation | |
function calculateWinProbability(teamStrength, opponentStrength, gameIndex) { | |
const randomness = Math.random() * 0.1 - 0.05; // +/- 0.05 random variation | |
const motivationBoost = motivationFactor[gameIndex]; | |
const formBoost = formMultiplier[gameIndex]; | |
const adjustedStrength = (teamStrength + injuryImpact[gameIndex] + fatigueFactor[gameIndex]) * motivationBoost * formBoost; | |
const baseWinProb = (adjustedStrength + randomness) / (adjustedStrength + opponentStrength); | |
const drawProb = 0.2; // Draw probability remains the same | |
return { | |
win: baseWinProb, | |
draw: drawProb, | |
loss: 1 - baseWinProb - drawProb | |
}; | |
} | |
// Function to simulate points for one match | |
function simulateMatch(teamStrength, opponentStrength, gameIndex) { | |
const probs = calculateWinProbability(teamStrength, opponentStrength, gameIndex); | |
const randomOutcome = Math.random(); | |
if (randomOutcome < probs.win) { | |
return 3; // Win | |
} else if (randomOutcome < probs.win + probs.draw) { | |
return 1; // Draw | |
} else { | |
return 0; // Loss | |
} | |
} | |
// Simulate points for the last 5 games with all factors | |
function simulatePoints() { | |
let totalPoints = 0; | |
for (let i = 0; i < games; i++) { | |
let adjustedTeamStrength = team_strength + (homeAway[i] ? homeAdvantage : 0); | |
totalPoints += simulateMatch(adjustedTeamStrength, opponents_strength[i], i); | |
} | |
return totalPoints; | |
} | |
// Running 10,000 simulations | |
let pointsDistribution = new Array(16).fill(0); // Possible points range from 0 to 15 | |
let allPoints = []; | |
for (let i = 0; i < simulations; i++) { | |
const points = simulatePoints(); | |
pointsDistribution[points]++; | |
allPoints.push(points); // Store all point outcomes for further analysis | |
} | |
// Normalize the data for the line chart | |
let normalizedData = pointsDistribution.map(p => p / simulations); | |
// Find the top 3 most probable point outcomes | |
function findTopThreePoints(pointsDistribution) { | |
const pointProbabilities = pointsDistribution.map((count, points) => ({ points, count })); | |
pointProbabilities.sort((a, b) => b.count - a.count); // Sort by count in descending order | |
return pointProbabilities.slice(0, 3); // Get top 3 | |
} | |
// Display the top 3 most probable points | |
const topThree = findTopThreePoints(pointsDistribution); | |
const topThreeList = document.getElementById('topThreePoints'); | |
topThree.forEach(({ points, count }) => { | |
const li = document.createElement('li'); | |
li.textContent = `${points} points - ${((count / simulations) * 100).toFixed(2)}% probability`; | |
topThreeList.appendChild(li); | |
}); | |
// Additional fun stats | |
function calculateAveragePoints(pointsArray) { | |
const totalPoints = pointsArray.reduce((a, b) => a + b, 0); | |
return totalPoints / pointsArray.length; | |
} | |
function calculateMedianPoints(pointsArray) { | |
pointsArray.sort((a, b) => a - b); | |
const middle = Math.floor(pointsArray.length / 2); | |
if (pointsArray.length % 2 === 0) { | |
return (pointsArray[middle - 1] + pointsArray[middle]) / 2; | |
} else { | |
return pointsArray[middle]; | |
} | |
} | |
function calculateVariance(pointsArray) { | |
const mean = calculateAveragePoints(pointsArray); | |
const squaredDiffs = pointsArray.map(p => Math.pow(p - mean, 2)); | |
const variance = squaredDiffs.reduce((a, b) => a + b, 0) / pointsArray.length; | |
return variance; | |
} | |
function calculateStandardDeviation(pointsArray) { | |
return Math.sqrt(calculateVariance(pointsArray)); | |
} | |
// Calculate the probability of getting more than 10 points | |
function probabilityMoreThan(pointsArray, threshold) { | |
const count = pointsArray.filter(p => p > threshold).length; | |
return (count / pointsArray.length) * 100; | |
} | |
// Display additional stats | |
const additionalStatsList = document.getElementById('additionalStats'); | |
const stats = [ | |
`Average points: ${calculateAveragePoints(allPoints).toFixed(2)}`, | |
`Median points: ${calculateMedianPoints(allPoints)}`, | |
`Variance: ${calculateVariance(allPoints).toFixed(2)}`, | |
`Standard Deviation: ${calculateStandardDeviation(allPoints).toFixed(2)}`, | |
`Probability of more than 5 points: ${probabilityMoreThan(allPoints, 5).toFixed(2)}%`, | |
`Probability of more than 10 points: ${probabilityMoreThan(allPoints, 10).toFixed(2)}%`, | |
]; | |
stats.forEach(stat => { | |
const li = document.createElement('li'); | |
li.textContent = stat; | |
additionalStatsList.appendChild(li); | |
}); | |
// Create the histogram chart | |
const ctx = document.getElementById('resultsChart').getContext('2d'); | |
const chart = new Chart(ctx, { | |
type: 'bar', | |
data: { | |
labels: [...Array(16).keys()], | |
datasets: [ | |
{ | |
label: 'Frequency of Points (Bar)', | |
data: pointsDistribution, | |
backgroundColor: 'rgba(75, 192, 192, 0.2)', | |
borderColor: 'rgba(75, 192, 192, 1)', | |
borderWidth: 1 | |
} | |
] | |
}, | |
options: { | |
scales: { | |
y: { | |
beginAtZero: true | |
} | |
} | |
} | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment