Skip to content

Commit

Permalink
v4.0.0.0 completed
Browse files Browse the repository at this point in the history
- fixed: red cards didn't send players off the pitch correctly
- fixed: player skills incorrectly assigned for tackles and slide tackles
- fixed: corners and goal kicks not correctly assigned / calculated
- fixed: intentPOS sometimes returned as null
- fixed: second half returned kickoffTeam with the ball, now secondTeam
- new: added ability to set the width of the goal to make the game more customisable
  • Loading branch information
GallagherAiden committed Oct 7, 2022
1 parent 1276e03 commit d2afd17
Show file tree
Hide file tree
Showing 37 changed files with 15,699 additions and 2,725 deletions.
11 changes: 8 additions & 3 deletions engine.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ async function playIteration(matchDetails) {
common.matchInjury(matchDetails, kickOffTeam)
common.matchInjury(matchDetails, secondTeam)
matchDetails = ballMovement.moveBall(matchDetails)
if (matchDetails.endIteration == true) {
delete matchDetails.endIteration
return matchDetails
}
playerMovement.closestPlayerToBall(closestPlayerA, kickOffTeam, matchDetails)
playerMovement.closestPlayerToBall(closestPlayerB, secondTeam, matchDetails)
kickOffTeam = playerMovement.decideMovement(closestPlayerA, kickOffTeam, secondTeam, matchDetails)
Expand All @@ -68,9 +72,10 @@ async function startSecondHalf(matchDetails) {
setPositions.switchSide(matchDetails, secondTeam)
common.removeBallFromAllPlayers(matchDetails)
setVariables.resetPlayerPositions(matchDetails)
setPositions.setBallSpecificGoalScoreValue(matchDetails, matchDetails.kickOffTeam)
matchDetails.kickOffTeam.intent = `attack`
matchDetails.secondTeam.intent = `defend`
setPositions.setBallSpecificGoalScoreValue(matchDetails, matchDetails.secondTeam)
matchDetails.iterationLog = [`Second Half Started: ${matchDetails.secondTeam.name} to kick offs`]
matchDetails.kickOffTeam.intent = `defend`
matchDetails.secondTeam.intent = `attack`
matchDetails.half++
return matchDetails
}
Expand Down
8 changes: 8 additions & 0 deletions history.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# History of footballSimulationEngine

## Version 4.0.0
- fixed: red cards didn't send players off the pitch correctly
- fixed: player skills incorrectly assigned for tackles and slide tackles
- fixed: corners and goal kicks not correctly assigned / calculated
- fixed: intentPOS sometimes returned as null
- fixed: second half returned kickoffTeam with the ball, now secondTeam
- new: added ability to set the width of the goal to make the game more customisable

## Version 3.0.1
- added new test scripts
- code fixes for assigning actions
Expand Down
9 changes: 7 additions & 2 deletions init_config/iteration.json
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,8 @@
},
"pitchSize": [
680,
1050
1050,
90
],
"ball": {
"position": [
Expand All @@ -1262,7 +1263,11 @@
"Player": "78883930303030109",
"withTeam": "78883930303030002",
"direction": "south",
"lastTouch": "Peter Johnson",
"lastTouch": {
"playerName": "Peter Johnson",
"playerID": 78883930303030109,
"teamID": 72464187147564590
},
"ballOverIterations": []
},
"half": 1,
Expand Down
9 changes: 7 additions & 2 deletions init_config/iteration2.json
Original file line number Diff line number Diff line change
Expand Up @@ -1250,7 +1250,8 @@
},
"pitchSize": [
680,
1050
1050,
90
],
"ball": {
"position": [
Expand All @@ -1262,7 +1263,11 @@
"Player": "78883930303030109",
"withTeam": "78883930303030002",
"direction": "south",
"lastTouch": "Emily Smith",
"lastTouch": {
"playerName": "Emily Smith",
"playerID": 78883930303030204,
"teamID": 78883930303030003
},
"ballOverIterations": []
},
"half": 1,
Expand Down
3 changes: 2 additions & 1 deletion init_config/pitch.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"pitchWidth": 680,
"pitchHeight": 1050
"pitchHeight": 1050,
"goalWidth": 90
}
16 changes: 9 additions & 7 deletions lib/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,11 @@ function playerDoesNotHaveBall(player, ballX, ballY, matchDetails) {
position, currentPOS, originPOS
} = player
if (position === 'GK') return [0, 0, 0, 0, 0, 0, 0, 60, 40, 0, 0]
else if (common.isBetween(ballX, -2, 2) && common.isBetween(ballY, -2, 2)) {
else if (common.isBetween(ballX, -20, 20) && common.isBetween(ballY, -20, 20)) {
return noBallNotGK2CloseBall(matchDetails, currentPOS, originPOS, pitchWidth, pitchHeight)
} else if (common.isBetween(ballX, -4, 4) && common.isBetween(ballY, -4, 4)) {
} else if (common.isBetween(ballX, -40, 40) && common.isBetween(ballY, -40, 40)) {
return noBallNotGK4CloseBall(matchDetails, currentPOS, originPOS, pitchWidth, pitchHeight)
} else if (common.isBetween(ballX, -20, 20) && common.isBetween(ballY, -20, 20)) {
} else if (common.isBetween(ballX, -80, 80) && common.isBetween(ballY, -80, 80)) {
if (matchDetails.ball.withPlayer === false) return [0, 0, 0, 0, 0, 0, 0, 60, 40, 0, 0]
return [0, 0, 0, 0, 0, 40, 0, 30, 30, 0, 0]
}
Expand Down Expand Up @@ -341,7 +341,7 @@ function resolveTackle(player, team, opposition, matchDetails) {
setFoul(matchDetails, team, player, thatPlayer)
return true
}
if (calcTackleScore(player.skill, 5) > calcRetentionScore(thatPlayer.skill, 5)) {
if (calcTackleScore(player.skill.tackling, 5) > calcRetentionScore(thatPlayer.skill.tackling, 5)) {
setSuccessTackle(matchDetails, team, opposition, player, thatPlayer, tackleDetails)
return false
}
Expand All @@ -367,7 +367,7 @@ function resolveSlide(player, team, opposition, matchDetails) {
setFoul(matchDetails, team, player, thatPlayer)
return true
}
if (calcTackleScore(player.skill, 5) > calcRetentionScore(thatPlayer.skill, 5)) {
if (calcTackleScore(player.skill.tackling, 5) > calcRetentionScore(thatPlayer.skill.tackling, 5)) {
setSuccessTackle(matchDetails, team, opposition, player, thatPlayer, tackleDetails)
return false
}
Expand Down Expand Up @@ -400,7 +400,9 @@ function calcRetentionScore(skill, diff) {

function setPostTackleBall(matchDetails, team, opposition, player) {
player.hasBall = true
matchDetails.ball.lastTouch = player.name
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
let tempArray = player.currentPOS
matchDetails.ball.position = tempArray.map(x => x)
matchDetails.ball.Player = player.playerID
Expand Down Expand Up @@ -448,7 +450,7 @@ function wasFoul(x, y) {
}

function foulIntensity() {
return common.getRandomNumber(0, 100)
return common.getRandomNumber(1, 99)
}

module.exports = {
Expand Down
112 changes: 73 additions & 39 deletions lib/ballMovement.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ function moveBall(matchDetails) {
ballPos.splice()
let bPlayer = setBPlayer(ballPos)
let endPos = resolveBallMovement(bPlayer, bPosition, ballPos, power, kickOffTeam, secondTeam, matchDetails)
if (matchDetails.endIteration == true) return matchDetails
matchDetails.ball.ballOverIterations.shift()
matchDetails.iterationLog.push(`ball still moving from previous kick: ${endPos}`)
matchDetails.ball.position = endPos
Expand Down Expand Up @@ -43,11 +44,13 @@ function setBPlayer(ballPos) {
}
}

function ballKicked(matchDetails, player) {
function ballKicked(matchDetails, team, player) {
let { position, direction } = matchDetails.ball
const [, pitchHeight] = matchDetails.pitchSize
matchDetails.iterationLog.push(`ball kicked by: ${player.name}`)
matchDetails.ball.lastTouch = player.name
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
let newPos = [0, 0]
let teamShootingToTop = [`wait`, `north`, `north`, `north`, `north`, `east`, `east`, `west`, `west`]
let teamShootingToTop2 = [`northeast`, `northeast`, `northeast`, `northwest`, `northwest`, `northwest`]
Expand Down Expand Up @@ -91,10 +94,12 @@ function newKickedPosition(pos, lowX, highX, lowY, highY) {
return newPosition
}

function shotMade(matchDetails, player) {
function shotMade(matchDetails, team, player) {
const [pitchWidth, pitchHeight] = matchDetails.pitchSize
matchDetails.iterationLog.push(`Shot Made by: ${player.name}`)
matchDetails.ball.lastTouch = player.name
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
let shotPosition = [0, 0]
let shotPower = common.calculatePower(player.skill.strength)
let PlyPos = player.currentPOS
Expand All @@ -104,32 +109,42 @@ function shotMade(matchDetails, player) {
else throw new Error(`You cannot supply 0 as a half`)
thisTeamStats.shots.total++
player.stats.shots.total++
if (player.skill.shooting > common.getRandomNumber(0, 40)) {
let shotReachGoal
if (player.originPOS[1] > pitchHeight / 2) {
shotReachGoal = !(((PlyPos[1] - shotPower) > 0))
} else {
shotReachGoal = !(((PlyPos[1] + shotPower) < pitchHeight))
}
if (shotReachGoal && player.skill.shooting > common.getRandomNumber(0, 40)) {
thisTeamStats.shots.on++
player.stats.shots.on++
shotPosition[0] = common.getRandomNumber((pitchWidth / 2) - 50, (pitchWidth / 2) + 50)
matchDetails.iterationLog.push(`Shot On Target at X Position ${shotPosition[0]}`)
if (player.originPOS[1] > pitchHeight / 2) shotPosition[1] = -1
else shotPosition[1] = pitchHeight + 1
} else {
thisTeamStats.shots.off++
player.stats.off++
player.stats.shots.off++
let left = (common.getRandomNumber(0, 10) > 5)
let leftPos = common.getRandomNumber(0, (pitchWidth / 2) - 55)
let righttPos = common.getRandomNumber((pitchWidth / 2) + 55, pitchWidth)
shotPosition[0] = (left) ? leftPos : righttPos
matchDetails.iterationLog.push(`Shot Off Target at X Position ${shotPosition[0]}`)
if (player.originPOS[1] > pitchHeight / 2) shotPosition[1] = PlyPos[1] - shotPower
else shotPosition[1] = PlyPos[1] + shotPower
}
if (player.originPOS[1] > pitchHeight / 2) shotPosition[1] = PlyPos[1] - shotPower
else shotPosition[1] = PlyPos[1] + shotPower
let endPos = calcBallMovementOverTime(matchDetails, player.skill.strength, shotPosition, player)
checkGoalScored(matchDetails)
return endPos
}

function penaltyTaken(matchDetails, player) {
function penaltyTaken(matchDetails, team, player) {
const [pitchWidth, pitchHeight] = matchDetails.pitchSize
player.action = `none`
matchDetails.iterationLog.push(`Penalty Taken by: ${player.name}`)
matchDetails.ball.lastTouch = player.name
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
let shotPosition = [0, 0]
let shotPower = common.calculatePower(player.skill.strength)
let PlyPos = player.currentPOS
Expand Down Expand Up @@ -164,9 +179,9 @@ function checkGoalScored(matchDetails) {
let {
ball, half, kickOffTeam, secondTeam
} = matchDetails
const [pitchWidth, pitchHeight] = matchDetails.pitchSize
const [pitchWidth, pitchHeight, goalWidth] = matchDetails.pitchSize
const centreGoal = pitchWidth / 2
const goalEdge = centreGoal / 3
const goalEdge = goalWidth / 2
const goalX = common.isBetween(ball.position[0], centreGoal - goalEdge, centreGoal + goalEdge)
let KOGoalie = kickOffTeam.players[0]
let STGoalie = secondTeam.players[0]
Expand Down Expand Up @@ -202,7 +217,9 @@ function checkGoalScored(matchDetails) {
}

function throughBall(matchDetails, team, player) {
matchDetails.ball.lastTouch = player.name
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
const [, pitchHeight] = matchDetails.pitchSize
let { position } = matchDetails.ball
let closePlyPos = [0, 0]
Expand Down Expand Up @@ -262,7 +279,9 @@ function resolveBallMovement(player, thisPOS, newPOS, power, team, opp, matchDet
let thisTeam = (thisPlayerProx == playerInfo1.proxToBall) ? team : opp
if (thisPlayer) thisPlayerIsInProximity(matchDetails, thisPlayer, thisPOS, thisPos, power, thisTeam)
}
matchDetails = setPositions.keepInBoundaries(matchDetails, team.name, newPOS)
let lastTeam = matchDetails.ball.lastTouch.teamID
matchDetails = setPositions.keepInBoundaries(matchDetails, lastTeam, newPOS)
if (matchDetails.endIteration == true) return
let lastPOS = matchDetails.ballIntended || matchDetails.ball.position
delete matchDetails.ballIntended
return [common.round(lastPOS[0], 2), common.round(lastPOS[1], 2)]
Expand Down Expand Up @@ -299,7 +318,9 @@ function setBallMovementMatchDetails(matchDetails, thisPlayer, thisPos, thisTeam
matchDetails.ball.ballOverIterations = []
matchDetails.ball.Player = thisPlayer.playerID
matchDetails.ball.withPlayer = true
matchDetails.ball.lastTouch = thisPlayer.name
matchDetails.ball.lastTouch.playerName = thisPlayer.name
matchDetails.ball.lastTouch.playerID = thisPlayer.playerID
matchDetails.ball.lastTouch.teamID = thisTeam.teamID
matchDetails.ball.withTeam = thisTeam.teamID
let tempArray = thisPos
matchDetails.ball.position = tempArray.map(x => x)
Expand All @@ -314,15 +335,16 @@ function resolveDeflection(power, thisPOS, defPosition, defPlayer, defTeam, matc
let tempPosition = ['', '']
let { direction } = matchDetails.ball
if (newPower < 75) {
setDeflectiionPlayerHasBall(matchDetails, defPlayer, defTeam)
setDeflectionPlayerHasBall(matchDetails, defPlayer, defTeam)
return defPosition
}
defPlayer.hasBall = false
matchDetails.ball.Player = ''
matchDetails.ball.withPlayer = false
matchDetails.ball.withTeam = ''
tempPosition = setDeflectionDirectionPos(direction, defPosition, newPower)
matchDetails = setPositions.keepInBoundaries(matchDetails, defTeam.name, tempPosition)
let lastTeam = matchDetails.ball.lastTouch.teamID
matchDetails = setPositions.keepInBoundaries(matchDetails, lastTeam.name, tempPosition)
let intended = matchDetails.ballIntended
let lastPOS = (intended) ? intended.map(x => x) : matchDetails.ball.position.map(x => x)
delete matchDetails.ballIntended
Expand Down Expand Up @@ -352,9 +374,11 @@ function setDeflectionDirectionPos(direction, defPosition, newPower) {
return tempPosition
}

function setDeflectiionPlayerHasBall(matchDetails, defPlayer, defTeam) {
function setDeflectionPlayerHasBall(matchDetails, defPlayer, defTeam) {
defPlayer.hasBall = true
matchDetails.ball.lastTouch = defPlayer.name
matchDetails.ball.lastTouch.playerName = defPlayer.name
matchDetails.ball.lastTouch.playerID = defPlayer.playerID
matchDetails.ball.lastTouch.teamID = defTeam.teamID
if (defPlayer.offside == true) {
setDeflectionPlayerOffside(matchDetails, defTeam, defPlayer)
return matchDetails.ball.position
Expand Down Expand Up @@ -395,14 +419,16 @@ function getBallDirection(matchDetails, nextPOS) {
else if (movementX < 0 && movementY > 0) matchDetails.ball.direction = `northeast`
}

function ballPassed(matchDetails, teammates, player) {
matchDetails.ball.lastTouch = player.name
function ballPassed(matchDetails, team, player) {
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
const [, pitchHeight] = matchDetails.pitchSize
const side = (player.originPOS[1] > (pitchHeight / 2)) ? 'bottom' : 'top'
let { position } = matchDetails.ball
let closePlyPos = [0, 0]
let playersInDistance = getPlayersInDistance(teammates, player, matchDetails.pitchSize)
let tPlyr = getTargetPlayer(playersInDistance, side)
let playersInDistance = getPlayersInDistance(team, player, matchDetails.pitchSize)
let tPlyr = getTargetPlayer(playersInDistance, side, pitchHeight)
let bottomThird = (position[1] > (pitchHeight - (pitchHeight / 3)))
let middleThird = !!((position[1] > (pitchHeight / 3) && position[1] < (pitchHeight - (pitchHeight / 3))))
if (player.skill.passing > common.getRandomNumber(0, 100)) closePlyPos = tPlyr.position
Expand All @@ -426,26 +452,33 @@ function setTargetPlyPos(tplyr, lowX, highX, lowY, highY) {
return closePlyPos
}

function getTargetPlayer(playersArray, side) {
let thisRand = common.getRandomNumber(0, (playersArray.length - 1))
let thisPlayer = playersArray[thisRand]
if (thisRand > 5) thisRand = common.getRandomNumber(0, (playersArray.length - 1))
if (side == 'top' && playersArray[thisRand].proximity > thisPlayer.proximity) {
thisPlayer = playersArray[thisRand]
} else if (side == 'bottom' && playersArray[thisRand].proximity < thisPlayer.proximity) {
thisPlayer = playersArray[thisRand]
function getTargetPlayer(playersArray, side, pitchHeight) {
let tempArray = []
for (let tempPlayer of playersArray) {
if (tempPlayer.proximity < (pitchHeight / 2)) tempArray.push(tempPlayer)
}
if (tempArray.length === 0) tempArray = playersArray
let thisRand = common.getRandomNumber(0, (tempArray.length - 1))
let thisPlayer = tempArray[thisRand]
if (thisRand > 5) thisRand = common.getRandomNumber(0, (tempArray.length - 1))
if (side == 'top' && tempArray[thisRand].proximity > thisPlayer.proximity) {
thisPlayer = tempArray[thisRand]
} else if (side == 'bottom' && tempArray[thisRand].proximity < thisPlayer.proximity) {
thisPlayer = tempArray[thisRand]
}
if (thisRand > 5) thisRand = common.getRandomNumber(0, (playersArray.length - 1))
if (side == 'top' && playersArray[thisRand].proximity > thisPlayer.proximity) {
thisPlayer = playersArray[thisRand]
} else if (side == 'bottom' && playersArray[thisRand].proximity < thisPlayer.proximity) {
thisPlayer = playersArray[thisRand]
if (thisRand > 5) thisRand = common.getRandomNumber(0, (tempArray.length - 1))
if (side == 'top' && tempArray[thisRand].proximity > thisPlayer.proximity) {
thisPlayer = tempArray[thisRand]
} else if (side == 'bottom' && tempArray[thisRand].proximity < thisPlayer.proximity) {
thisPlayer = tempArray[thisRand]
}
return thisPlayer
}

function ballCrossed(matchDetails, player) {
matchDetails.ball.lastTouch = player.name
function ballCrossed(matchDetails, team, player) {
matchDetails.ball.lastTouch.playerName = player.name
matchDetails.ball.lastTouch.playerID = player.playerID
matchDetails.ball.lastTouch.teamID = team.teamID
const [pitchWidth, pitchHeight] = matchDetails.pitchSize
let ballIntended = []
if (player.originPOS[1] > (pitchHeight / 2)) {
Expand Down Expand Up @@ -477,6 +510,7 @@ function calcBallMovementOverTime(matchDetails, strength, nextPosition, player)
let BOIts = mergeArrays(powerArray.length, position, nextPosition, xArray, yArray, powerArray)
matchDetails.ball.ballOverIterations = BOIts
let endPos = resolveBallMovement(player, position, BOIts[0], power, kickOffTeam, secondTeam, matchDetails)
if (matchDetails.endIteration == true) return matchDetails
matchDetails.ball.ballOverIterations.shift()
matchDetails.iterationLog.push(`resolving ball movement`)
return endPos
Expand Down Expand Up @@ -522,7 +556,7 @@ module.exports = {
setDeflectionDirectionPos,
setDeflectionPlayerOffside,
getTargetPlayer,
setDeflectiionPlayerHasBall,
setDeflectionPlayerHasBall,
setBallMovementMatchDetails,
thisPlayerIsInProximity,
setTargetPlyPos,
Expand Down
Loading

0 comments on commit d2afd17

Please sign in to comment.