Last active
December 26, 2021 02:57
-
-
Save ViniciusGibran/5660814cccc7b3456e65db1e68814be3 to your computer and use it in GitHub Desktop.
DRIVER RATING - UPDATES
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
| // DRIVER RATINGS LOGICS | |
| //SETUPS | |
| // this class exists to get data from SPRINT RACE and calculate DRIVER RATINGS | |
| let RATING_DATA = SpreadsheetApp.getActive().getSheetByName("RATING_DATA") | |
| let IRC_DATA_SHEET = SpreadsheetApp.openById("1QaQUnQSiL_bKDY7zdCNp458fmDe8cS6N7taMem-b654") | |
| let DRIVER_DATA = IRC_DATA_SHEET.getSheetByName("DRIVER_DATA") | |
| // PROPERTIES | |
| // max xp limit to regular | |
| let XP_LIMIT_CUT = 100 | |
| // a max xp lvl to make even hard to earn points | |
| let SECOND_XP_CUT = 90 | |
| let FIRST_XP_CUT = 70 | |
| // this is the maximum value for the rating addition on lap times | |
| // driver can receive up to LAP_TIME_INITIAL_BONUS | |
| let RP_INITIAL_BONUS = 100 | |
| // race time target additional | |
| let RACE_LAP_TIME_TARGET_ADD = 1.5 // make an average from last season data (with top first & last drivers) | |
| // max random value for possibility point | |
| let POSSIBILITY_MAX_POINT = 3 //means max 2 -> review it to make a parameter? | |
| // TODO: APL - driver DNF by other driver incident | |
| // TODO: copy/use this for race result adding DNS [3.0,4.0] | |
| let RATINGS_PARAMS = { | |
| "experience": { | |
| "DNS": [2.5,3.5], | |
| "DNF": [1.0, 1.2], | |
| "DSQ": [1.0, 1.2], | |
| "APL": [0.0,0.0], | |
| "avg_DNF": [0.5,1.0], | |
| "in_game_warning_mult": [0.3, 0.4], | |
| "in_game_penalty_mult": [0.3, 0.6], | |
| "fia_warning_mult": [0.3, 1.0], | |
| "fia_penalty_mult": [0.3, 1.6], | |
| "performance_history": [0.5, 1.0], | |
| "result_div": [2.8,3.5], | |
| "fastest_lap": [1.0,2.0], | |
| "dotd": [1.5, 3.0], | |
| "avg_result": [1.0,2.4], | |
| "pos_mult": [0.2, 0.4], | |
| "consistency": [1.0,2.0], | |
| "time_lap": [2.0,2.5], | |
| "race_aditional": [2.0, 2.5], | |
| }, | |
| "race_craft": { | |
| "DNS": [2.5,3.5], | |
| "DNF": [1.0, 1.4], | |
| "DSQ": [1.0, 1.5], | |
| "APL": [0.0,0.0], | |
| "avg_DNF": [0.5,1.0], | |
| "in_game_warning_mult": [0.3, 0.4], | |
| "in_game_penalty_mult": [1.0, 1.6], | |
| "fia_warning_mult": [0.3, 1.0], | |
| "fia_penalty_mult": [0.3, 1.6], | |
| "performance_history": [0.5, 1.0], | |
| "result_div": [2.5,3.2], | |
| "fastest_lap": [2.0,2.5], | |
| "dotd": [2.0, 4.0], | |
| "avg_result": [1.0,2.0], | |
| "pos_mult": [0.35, 0.7], | |
| "consistency": [1.0,2.0], | |
| "time_lap": [3.0,3.5], | |
| "race_aditional": [2.2, 2.5] | |
| }, | |
| "awareness": { | |
| "DNS": [2.5,3.5], | |
| "DNF": [2.0, 2.5], | |
| "DSQ": [2.1, 3.0], | |
| "APL": [0.0,0.0], | |
| "avg_DNF": [0.5,1.0], | |
| "in_game_warning_mult": [0.3, 0.4], | |
| "in_game_penalty_mult": [1.3, 1.6], | |
| "fia_warning_mult": [0.3, 1.0], | |
| "fia_penalty_mult": [0.3, 1.6], | |
| "performance_history": [0.5, 1.0], | |
| "result_div": [2.0,3.0], | |
| "fastest_lap": [0.0,0.4], | |
| "dotd": [2.4, 4.2], | |
| "avg_result": [1.0,2.0], | |
| "pos_mult": [0.3, 0.5], | |
| "consistency": [1.0,2.0], | |
| "time_lap": [2.3,3.0], | |
| "race_aditional": [2.2, 2.5] | |
| }, | |
| "pace": { | |
| "DNS": [2.5,3.5], | |
| "DNF": [0.5, 1.0], | |
| "DSQ": [0.5, 1.2], | |
| "APL": [0.0,0.0], | |
| "avg_DNF": [0.5,1.0], | |
| "in_game_warning_mult": [0.3, 0.4], | |
| "in_game_penalty_mult": [0.3, 0.6], | |
| "fia_warning_mult": [0.3, 1.0], | |
| "fia_penalty_mult": [0.3, 1.6], | |
| "performance_history": [0.5, 1.0], | |
| "result_div": [2.5,3.2], | |
| "fastest_lap": [1.5, 2.2], | |
| "dotd": [1.5, 2.2], | |
| "avg_result": [1.0,2.0], | |
| "pos_mult": [0.45, 1.25], | |
| "consistency": [1.0,2.0], | |
| "time_lap": [2.5,3.4], | |
| "race_aditional": [1.0, 1.5] | |
| } | |
| } | |
| let LICENSES = { | |
| "s_license": { | |
| "emoji_id": "<:s_license:917610460562477066>", | |
| "img_url": "https://drive.google.com/uc?id=1wirknHWI37qYyX5nCa82buukmgsvrcg3", | |
| "min_sp": 18, | |
| "max_sp": 20 | |
| }, | |
| "a_license": { | |
| "emoji_id": "<:a_license:917610460285648927>", | |
| "img_url": "https://drive.google.com/uc?id=1n7xXoUMeijt_Cok9V2oRuoxv71MwJ-ut", | |
| "min_sp": 14, | |
| "max_sp": 17 | |
| }, | |
| "b_license": { | |
| "emoji_id": "<:b_license:917610460067545188>", | |
| "img_url": "https://drive.google.com/uc?id=10DJ15KS3kSWsppNCMpsjk-PbbXi_3JOt", | |
| "min_sp": 10, | |
| "max_sp": 13 | |
| }, | |
| "c_license": { | |
| "emoji_id": "<:c_license:917610459992043580>", | |
| "img_url": "https://drive.google.com/uc?id=1dKvBzOl7OdHA2volZEizGH-qJofqIooM", | |
| "min_sp": 7, | |
| "max_sp": 9 | |
| }, | |
| "d_license": { | |
| "emoji_id": "<:d_license:917610459975286844>", | |
| "img_url": "https://drive.google.com/uc?id=1oqBEw6jveh0HaA8KolzcRKbxhivXRHnQ", | |
| "min_sp": 4, | |
| "max_sp": 6 | |
| }, | |
| "n_license": { | |
| "emoji_id": "<:n_license:924330517233537074>", | |
| "img_url": "https://drive.google.com/uc?id=1PJGY74fNeodEzda5OiWEBEXL2dFFf6Ro", | |
| "min_sp": 0, | |
| "max_sp": 3 | |
| } | |
| } | |
| //------------------------------------------------------------------------------------------------------ | |
| function GET_RACE_RESULTS() { | |
| var minIndex = 3 | |
| let maxIndex = 22 | |
| var raceResults = [] | |
| // sort list by quali order | |
| SORT_BY_QUALI() | |
| // loop to get results | |
| while(minIndex <= maxIndex) { | |
| // race resut data | |
| let driverName = RATING_DATA.getRange(`C${minIndex}`).getValue() | |
| let rowRef = RATING_DATA.getRange(`D${minIndex}`).getValue() | |
| let qualiTime = parseFloat(RATING_DATA.getRange(`E${minIndex}`).getValue().toString().slice(2)) | |
| let raceTime = parseFloat(RATING_DATA.getRange(`F${minIndex}`).getValue().toString().slice(2)) | |
| let result = RATING_DATA.getRange(`G${minIndex}`).getValue() | |
| let inGameWarnings = RATING_DATA.getRange(`H${minIndex}`).getValue() | |
| let inGamePenalties = RATING_DATA.getRange(`I${minIndex}`).getValue() | |
| let fiaWarnings = RATING_DATA.getRange(`J${minIndex}`).getValue() | |
| let fiaPenalties = RATING_DATA.getRange(`K${minIndex}`).getValue() | |
| let backgroundDOTD = RATING_DATA.getRange(`C${minIndex}`).getFontColor() | |
| let backgroundFLP = RATING_DATA.getRange(`G${minIndex}`).getFontColor() | |
| let eventType = RATING_DATA.getRange("E24:F24").getValue().toString() | |
| let circuit = RATING_DATA.getRange("G24:H24").getValue().toString() | |
| let ratingDataRowRef = minIndex | |
| // check if reach last driver data | |
| if (driverName == "") { break } | |
| // pole | |
| let isPole = false | |
| if (minIndex == 3) { isPole = true } | |
| // is winner | |
| let isWinner = false | |
| if (parseInt(result) == 1) { isWinner = true } | |
| // is podium | |
| let isPodium = false | |
| if (minIndex <= 5) { isPodium = true } | |
| // driver data (rating) | |
| var driverXp = parseInt(DRIVER_DATA.getRange(`T${rowRef}`).getValue()) | |
| let driverRc = parseInt(DRIVER_DATA.getRange(`U${rowRef}`).getValue()) | |
| let driverAw = parseInt(DRIVER_DATA.getRange(`V${rowRef}`).getValue()) | |
| let driverPa = parseInt(DRIVER_DATA.getRange(`W${rowRef}`).getValue()) | |
| let driverAvg = parseInt(DRIVER_DATA.getRange(`X${rowRef}`).getValue()) | |
| let totalDNFs = parseInt(DRIVER_DATA.getRange(`R${rowRef}`).getValue()) // not counting this event result | |
| let numberOfSprintsRaced = parseInt(DRIVER_DATA.getRange(`L${rowRef}`).getValue()) | |
| let numberOfRacesRaced = parseInt(DRIVER_DATA.getRange(`M${rowRef}`).getValue()) | |
| let totalOfRacesRaced = numberOfRacesRaced + numberOfSprintsRaced + 1 | |
| // last results | |
| var lastResults = [] | |
| let lastResultsString = DRIVER_DATA.getRange(`S${rowRef}`).getValue().toString() | |
| lastResultsString = lastResultsString.replace("DNS", "25").replace("DNF", "22").replace("DSQ", "24").replace("APL", "") | |
| if (lastResultsString != "0") { lastResults = lastResultsString.split(",").map(Number).filter(number => number > 0) } | |
| if (!isNaN(result)) { lastResults.push(parseInt(result)) } | |
| // result avarage, variance, deviation (consistency) | |
| let avgRaceResult = CALCULATE_AVERAGE_RESULTS(lastResults) | |
| let variance = CALCULATE_DRIVER_RESULT_VARIANCE(lastResults) | |
| let deviation = CALCULATE_DRIVER_RESULT_DEVIATION(lastResults) | |
| // fastet lap & dotd | |
| let isFastestLap = (backgroundFLP == "#6842d5") | |
| let isDriverOfTheDay = (backgroundDOTD == "#10a499") | |
| console.log(isFastestLap) | |
| console.log(isDriverOfTheDay) | |
| // avg lap time target | |
| let qualiTargetFastesLap = parseFloat(RATING_DATA.getRange("I24:J24").getValue().toString().slice(2)) | |
| let qualiTargetSlowestLap = parseFloat(RATING_DATA.getRange("K24:L24").getValue().toString().slice(2)) | |
| // lap target values | |
| let raceAdditional = RACE_LAP_TIME_TARGET_ADD | |
| let avgTargetFastestLap = (qualiTargetFastesLap + (qualiTargetFastesLap + raceAdditional)) / 2 | |
| let avgTargetSlowestLap = (qualiTargetSlowestLap + qualiTargetSlowestLap + raceAdditional) / 2 | |
| let avgLapTime = (qualiTime + raceTime) / 2 | |
| // driver time target result | |
| let avgTargetRange = avgTargetSlowestLap - avgTargetFastestLap | |
| let driverDeltaTime = avgLapTime - avgTargetFastestLap | |
| let timeTargetResult = driverDeltaTime / avgTargetRange | |
| // performance history multiplier | |
| let titlesTotal = parseInt(DRIVER_DATA.getRange(`K${rowRef}`).getValue()) * 1.2 | |
| let polesTotal = parseInt(DRIVER_DATA.getRange(`N${rowRef}`).getValue()) * 1.15 | |
| let winsTotal = parseInt(DRIVER_DATA.getRange(`O${rowRef}`).getValue()) * 1.1 | |
| let podiumsTotal = parseInt(DRIVER_DATA.getRange(`P${rowRef}`).getValue()) * 1.08 | |
| let dotdTotal = parseInt(DRIVER_DATA.getRange(`Q${rowRef}`).getValue()) // keep same value | |
| let performanceAvg = (titlesTotal + polesTotal + winsTotal + podiumsTotal + dotdTotal) / 5 | |
| let performanceFactor = performanceAvg / totalOfRacesRaced | |
| // create max xp limit factor multiplier | |
| let xpLimitCutFactor = MAKE_XP_LIMIT_CUT_FACTOR(driverAvg) | |
| // safety points | |
| let safetyPoints = parseInt(DRIVER_DATA.getRange(`Z${minIndex}`).getValue()) | |
| let raceResult = { | |
| "driver_name": driverName, | |
| "row_ref": rowRef, | |
| "grid_start_pos": minIndex-2, | |
| "quali_time": qualiTime, | |
| "race_time": raceTime, | |
| "avg_lap_time": avgLapTime, | |
| "result": result, | |
| "dnfs_total": totalDNFs, | |
| "in_game_warnings": inGameWarnings, | |
| "in_game_penalties": inGamePenalties, | |
| "fia_warnings": fiaWarnings, | |
| "fia_penalties": fiaPenalties, | |
| "safety_points": safetyPoints, | |
| "last_results": lastResults, | |
| "avg_race_result": avgRaceResult, | |
| "is_fastest_lap": isFastestLap, | |
| "is_dotd": isDriverOfTheDay, | |
| "driver_xp": driverXp, | |
| "driver_rc": driverRc, | |
| "driver_aw": driverAw, | |
| "driver_pa": driverPa, | |
| "driver_avg": driverAvg, | |
| "eventType": eventType, | |
| "circuit": circuit, | |
| "avg_target_fastest_lap": avgTargetFastestLap, | |
| "avg_target_slowest_lap": avgTargetSlowestLap, | |
| "rating_data_row_ref": ratingDataRowRef, | |
| "time_target_result": timeTargetResult, | |
| "number_of_sprints_raced": numberOfSprintsRaced, | |
| "number_of_races_raced": numberOfRacesRaced, | |
| "total_of_races_raced": totalOfRacesRaced, | |
| "variance": variance, | |
| "deviation": deviation, | |
| "performance_factor": performanceFactor, | |
| "xp_limit_cut_factor": xpLimitCutFactor, | |
| "dotd_total": dotdTotal, | |
| "is_pole": isPole, | |
| "is_podium": isPodium, | |
| "is_winner": isWinner | |
| } | |
| raceResults.push(raceResult) | |
| minIndex ++ | |
| } | |
| return raceResults | |
| } | |
| //------------------------------------------------------------------------------------------------------ | |
| function CALCULATE_AVERAGE_RESULTS(lastResults) { | |
| let length = lastResults.length | |
| if (length == 0) { return 0 } | |
| let average = lastResults?.reduce((a,b) => a+b,0) / length | |
| return average | |
| } | |
| function CALCULATE_DRIVER_RESULT_VARIANCE(lastResults) { | |
| let length = lastResults.length | |
| if (length < 3) { return -1 } | |
| let avgResult = CALCULATE_AVERAGE_RESULTS(lastResults) | |
| let variance = lastResults.map(value => { | |
| let avgDelta = value - avgResult | |
| let squareValue = Math.pow(avgDelta, 2) | |
| return squareValue | |
| }).reduce((a,b) => a+b,0) / (length-1) / 100 | |
| return variance | |
| } | |
| function CALCULATE_DRIVER_RESULT_DEVIATION(lastResults) { | |
| let length = lastResults.length | |
| if (length < 3) { return -1 } | |
| let avgResult = CALCULATE_AVERAGE_RESULTS(lastResults) | |
| let deviation = Math.sqrt( | |
| lastResults | |
| .map(value => Math.pow(value - avgResult, 2)) | |
| .reduce((a,b) => a+b,0) / (length-1) | |
| ) / 20 | |
| return deviation | |
| } | |
| // UPDATE RATINGS | |
| //------------------------------------------------------------------------------------------------------ | |
| function UPDATE_DRIVER_RATING() { | |
| let raceResults = GET_RACE_RESULTS() | |
| raceResults.forEach(result => { | |
| // TODO: clead this | |
| console.log("######################################") | |
| console.log(result.driver_name) | |
| // experience | |
| let xpRatingFactor = RATINGS_PARAMS.experience | |
| var xpRatingValue = GET_EXPERIENCE_FOR(xpRatingFactor, result) | |
| var xpRating = parseInt(xpRatingValue + result.driver_xp) | |
| let xpValue = Math.min(Math.max(xpRating,50), 100) | |
| //DRIVER_DATA.getRange(`T${result.row_ref}`).setValue(xpValue) | |
| // race cra1ft | |
| let rcRatingFactor = RATINGS_PARAMS.race_craft | |
| let rcRating = parseInt(GET_RATING_FOR(rcRatingFactor, result) + result.driver_rc) | |
| let rcValue = Math.min(Math.max(rcRating,50), 100) | |
| //DRIVER_DATA.getRange(`U${result.row_ref}`).setValue(rcValue) | |
| // awareness | |
| let awRatingFactor = RATINGS_PARAMS.awareness | |
| let awRating = parseInt(GET_RATING_FOR(awRatingFactor, result) + result.driver_aw) | |
| let awValue = Math.min(Math.max(awRating,50), 100) | |
| //DRIVER_DATA.getRange(`V${result.row_ref}`).setValue(awValue) | |
| // pace | |
| let paRatingFactor = RATINGS_PARAMS.pace | |
| let paRating = parseInt(GET_RATING_FOR(paRatingFactor, result) + result.driver_pa) | |
| let paValue = Math.min(Math.max(paRating,50), 100) | |
| //DRIVER_DATA.getRange(`W${result.row_ref}`).setValue(paValue) | |
| // average | |
| let avgValue = Math.ceil((xpValue + rcValue + awValue + paValue) / 4) | |
| //DRIVER_DATA.getRange(`X${result.row_ref}`).setValue(avgValue) | |
| RATING_DATA.getRange(`N${result.rating_data_row_ref}`).setValue(avgValue) | |
| //number of races & sprints | |
| if (result.eventType == "SPRINT") { | |
| let numberOfSprintsRaced = result.number_of_sprints_raced + 1 | |
| //DRIVER_DATA.getRange(`L${result.row_ref}`).setValue(numberOfSprintsRaced) | |
| } | |
| if (result.eventType == "RACE") { | |
| let numberOfRacesRaced = result.number_of_races_raced + 1 | |
| //DRIVER_DATA.getRange(`M${result.row_ref}`).setValue(numberOfRacesRaced) | |
| } | |
| let ratings = `${xpValue}, ${rcValue}, ${awValue}, ${paValue}` | |
| RATING_DATA.getRange(`M${result.rating_data_row_ref}`).setValue(ratings) | |
| RATING_DATA.getRange(`N26`).setValue(result.total_of_races_raced) | |
| // TODO: right those values on DRIVER DATA | |
| // POLES WINS PODIUMS DOTD's DNF's LAST 5 RESULTS | |
| if (result.is_pole) { | |
| let polesTotal = parseInt(DRIVER_DATA.getRange(`N${result.row_ref}`).getValue()) + 1 | |
| //DRIVER_DATA.getRange(`N${result.row_ref}`).setValue(polesTotal) | |
| } | |
| if (result.is_winner) { | |
| let winsTotal = parseInt(DRIVER_DATA.getRange(`O${result.row_ref}`).getValue()) + 1 | |
| //DRIVER_DATA.getRange(`O${result.row_ref}`).setValue(winsTotal) | |
| } | |
| if (result.is_podium) { | |
| let podiumsTotal = parseInt(DRIVER_DATA.getRange(`P${result.row_ref}`).getValue()) + 1 | |
| //DRIVER_DATA.getRange(`P${result.row_ref}`).setValue(podiumsTotal) | |
| } | |
| // update driver of the day | |
| if (result.is_dotd) { | |
| let dotdTotal = result.dotd_total + 1 | |
| //DRIVER_DATA.getRange(`Q${result.row_ref}`).setValue(dotdTotal) | |
| } | |
| // update dnf | |
| if (result.result == "DNF") { | |
| let dnfsTotal = parseInt(DRIVER_DATA.getRange(`R${result.row_ref}`).getValue()) | |
| //DRIVER_DATA.getRange(`R${result.row_ref}`).setValue(dnfsTotal+1) | |
| } | |
| // last results | |
| var resultList = [] | |
| var driverLastResults = DRIVER_DATA.getRange(`S${result.row_ref}`).getValue().toString() | |
| if (driverLastResults != "0") { resultList = driverLastResults.split(",") } | |
| resultList.push(result.result) | |
| // drop first index (older result) | |
| if (resultList.length > 5) { resultList.shift() } | |
| driverLastResults = resultList.toString() | |
| //DRIVER_DATA.getRange(`S${result.row_ref}`).setValue(driverLastResults) | |
| // TODO: review the logic & move it to own method + calculate all points on GET_DRIVER_DATA and here only update on DRIVER_DATA sheet | |
| // license points | |
| let hasFiaIssuedAPenaltyOrWarning = ((result.fia_penalties <=0) && (result.fia_warnings <= 0)) | |
| let hasFinishedOrAppealed = (!(isNaN(result.result)) || (result.result == "APL")) | |
| if (hasFinishedOrAppealed && hasFiaIssuedAPenaltyOrWarning) { | |
| var licensePoints = result.safety_points | |
| if (result.safety_points < 20) { | |
| licensePoints += 1 | |
| } | |
| //DRIVER_DATA.getRange(`Y${result.row_ref}`).setValue(licensePoints) | |
| RATING_DATA.getRange(`L${result.rating_data_row_ref}`).setValue(licensePoints) | |
| } else { | |
| let licensePoints = result.safety_points - result.fia_penalties | |
| //DRIVER_DATA.getRange(`Y${result.row_ref}`).setValue(licensePoints) | |
| RATING_DATA.getRange(`L${result.rating_data_row_ref}`).setValue(licensePoints) | |
| } | |
| let totalLicensePoints = parseInt(RATING_DATA.getRange(`L${result.rating_data_row_ref}`).getValue()) | |
| let licenseImgUrl = GET_LICENSE_IMG_FORMULA_BY(totalLicensePoints) | |
| let licenseImgFormula = `=IMAGE(\"${licenseImgUrl}\";4;30;30)` | |
| //DRIVER_DATA.getRange(`AA${result.row_ref}`).setFormula(licenseImgFormula) | |
| }) | |
| // sort | |
| SORT_TABLE() | |
| } | |
| //------------------------------------------------------------------------------------------------------ | |
| // LICENSE HELPER | |
| function GET_LICENSE_IMG_FORMULA_BY(licensePoints) { | |
| if (licensePoints >= LICENSES.s_license.min_sp) { | |
| return LICENSES.s_license.img_url | |
| } else if (licensePoints >= LICENSES.a_license.min_sp) { | |
| return LICENSES.a_license.img_url | |
| } else if (licensePoints >= LICENSES.b_license.min_sp) { | |
| return LICENSES.b_license.img_url | |
| } else if (licensePoints >= LICENSES.c_license.min_sp) { | |
| return LICENSES.c_license.img_url | |
| } else if (licensePoints >= LICENSES.d_license.min_sp) { | |
| return LICENSES.d_license.img_url | |
| } else if (licensePoints >= LICENSES.n_license.min_sp) { | |
| return LICENSES.n_license.img_url | |
| } | |
| } | |
| // RATING METHODS | |
| // calculate value for experience | |
| function GET_EXPERIENCE_FOR(xpRatingFactor, result) { | |
| var xpRatingValue = GET_RATING_FOR(xpRatingFactor, result) | |
| return xpRatingValue | |
| // TODO: Move it to GET_RATING_FOR method and leave here only logic regarding XP (USE DNF's to calculate) | |
| // CHANGE IT TO BE FACTOR WITH MAX XP LVL ( DIVIDE BY 100 & GET PERCENTAGE ) | |
| // xp gets harder to earn regarding lvl and | |
| if (result.driver_xp > RP_INITIAL_BONUS) { | |
| // every 3 races may update xp | |
| if (result.total_of_races_raced % 3 == 0) { | |
| // max xp limit to calculations, now is up to possibility | |
| if (result.driver_xp >= MAX_XP_LIMIT) { | |
| return POSSIBILITY_POINT() | |
| } | |
| // limit to 3 | |
| if (xpRatingValue > 3) { | |
| xpRatingValue = 3 | |
| } | |
| // add possibility | |
| xpRatingValue += POSSIBILITY_POINT() | |
| } | |
| } | |
| // limit point removal to 5 | |
| if (xpRatingValue < -5) { xpRatingValue = -5 } | |
| return xpRatingValue | |
| } | |
| // small chance to return up to 2 points | |
| function POSSIBILITY_POINT() { | |
| let possibility = Math.random() | |
| let rating = Math.floor(Math.random() * POSSIBILITY_MAX_POINT) | |
| return possibility > 0.89 ? rating : 0 | |
| } | |
| // CALCULATIONS | |
| // timeTargetResult deviation variance total_of_dnfs (get avg of DNFs) lap_time_factor + review | |
| /* | |
| "DNS": [2.5,3.5], ok | |
| "DNF": [1.0, 1.2], ok | |
| "DSQ": [1.0, 1.2], ok | |
| "APL": [0.0,0.0], ok | |
| "avg_DNF": [0.5,1.0], | |
| "in_game_warning_mult": [0.3, 0.4],ok | |
| "in_game_penalty_mult": [0.3, 0.6],ok | |
| "fia_warning_mult": [0.3, 0.4],ok | |
| "fia_penalty_mult": [0.3, 0.6],ok | |
| "result_div": [3.0,4.8], ok | |
| "fastest_lap": [1.0,2.0], ok | |
| "dotd": [1.0, 2.5], ok | |
| "avg_result": [1.0,2.0] ok | |
| "pos_mult": [0.2, 0.4], ok | |
| "consistency": [1.0,2.0], ok | |
| "time_lap": [5.0,7.0] ok | |
| "race_aditional": [2.0, 2.5], ok | |
| */ | |
| //------------------------------------------------------------------------------------------------------ | |
| function GET_RATING_FOR(ratingFactor, raceResult) { | |
| var performancePoints = 0 | |
| // REMOVEs | |
| // dns | |
| if (raceResult.result == "DNS") { | |
| performancePoints -= RANDOM_VALUES(ratingFactor.DNS) | |
| } | |
| // dnf | |
| if (raceResult.result == "DNF") { | |
| performancePoints -= RANDOM_VALUES(ratingFactor.DNF) | |
| console.log("DNF") | |
| console.log(performancePoints) | |
| } | |
| // dsq | |
| if (raceResult.result == "DSQ") { | |
| performancePoints -= RANDOM_VALUES(ratingFactor.DSQ) | |
| } | |
| // avg dnf's - removes a small factor regarding driver avg dnf's in relation with total races | |
| // change avgDNF to DNF_DEBIT and add 5 debit | |
| // move this to DRIVER DATA initializer | |
| // driver dnf's avg debit - calculate remotion based on DNFs | |
| if (raceResult.dnfs_total > 0) { | |
| // more avg rating means higher dnf debit | |
| var avgDnfFactor = RANDOM_VALUES(ratingFactor.avg_DNF) * (raceResult.driver_avg/100) | |
| console.log("raceResult.dnfs_total") | |
| console.log(raceResult.dnfs_total) | |
| console.log("raceResult.totalOfRacesRaced") | |
| console.log(raceResult.total_of_races_raced) | |
| console.log("avgDnfFactor") | |
| console.log(avgDnfFactor) | |
| // move this to the drive data calculations | |
| performancePoints -= avgDnfFactor * (raceResult.dnfs_total / raceResult.total_of_races_raced) | |
| console.log("avgDnfFactor") | |
| console.log(performancePoints) | |
| } | |
| // TODO: get number of driver DNFs and calculate % with total number of races (make new factor) | |
| // incidents in game | |
| let inGameIncidentMult = RANDOM_VALUES(ratingFactor.in_game_warning_mult) | |
| performancePoints -= inGameIncidentMult * raceResult.in_game_warnings | |
| console.log("inGameIncidentMult") | |
| console.log(performancePoints) | |
| let inGamePenaltyMult = RANDOM_VALUES(ratingFactor.in_game_penalty_mult) | |
| performancePoints -= inGamePenaltyMult * raceResult.in_game_penalties | |
| console.log("inGamePenaltyMult") | |
| console.log(performancePoints) | |
| // incidents FIA | |
| let fiaIncidentMult = RANDOM_VALUES(ratingFactor.fia_warning_mult) | |
| performancePoints -= fiaIncidentMult * raceResult.fia_warnings | |
| console.log("fiaIncidentMult") | |
| console.log(performancePoints) | |
| let fiaPenaltyMult = RANDOM_VALUES(ratingFactor.fia_penalty_mult) | |
| performancePoints -= fiaPenaltyMult * raceResult.fia_penalties | |
| console.log("fiaPenaltyMult") | |
| console.log(performancePoints) | |
| // ADDs | |
| let performanceMult = RANDOM_VALUES(ratingFactor.performance_history) | |
| performancePoints += raceResult.performance_factor * performanceMult | |
| // consistency (variance & deviation) | |
| // only if the value is equal or higher than 0 (means more than 2 races at least) | |
| if (raceResult.variance >= 0 && raceResult.deviation >= 0) { | |
| let consistencyMultiplier = (raceResult.variance + raceResult.deviation) / 2 | |
| if (consistencyMultiplier >= 0) { | |
| let consistencyFactor = RANDOM_VALUES(ratingFactor.consistency) | |
| performancePoints += consistencyFactor - ( consistencyFactor * consistencyMultiplier) | |
| console.log("consistencyFactor") | |
| console.log(performancePoints) | |
| } | |
| } | |
| // quali time result additional | |
| let timelapFactor = RANDOM_VALUES(ratingFactor.time_lap) | |
| performancePoints += timelapFactor - (timelapFactor * raceResult.time_target_result).toFixed(2) | |
| console.log("timelapFactor") | |
| console.log(performancePoints) | |
| // race aditional | |
| performancePoints += RANDOM_VALUES(ratingFactor.race_aditional) | |
| console.log("race aditional") | |
| console.log(performancePoints) | |
| // fastest lap | |
| if(raceResult.is_fastest_lap) { | |
| performancePoints += RANDOM_VALUES(ratingFactor.fastest_lap) | |
| console.log("FASTEST LAP") | |
| console.log(performancePoints) | |
| } | |
| // driver of the day | |
| if (raceResult.is_dotd) { | |
| performancePoints += RANDOM_VALUES(ratingFactor.dotd) | |
| console.log("DOTD") | |
| console.log(performancePoints) | |
| } | |
| // TODO: review & test this | |
| if (isNaN(raceResult.result)) { | |
| console.log("result isNaN") | |
| console.log("raceResult.xp_limit_cut_factor") | |
| console.log(raceResult.xp_limit_cut_factor) | |
| console.log("performancePoints") | |
| console.log(Math.floor(performancePoints * raceResult.xp_limit_cut_factor)) | |
| return Math.floor(performancePoints * raceResult.xp_limit_cut_factor) | |
| } | |
| // result -> pace CONSIDER REVIEW THIS | |
| let resultFactor = RANDOM_VALUES(ratingFactor.result_div) | |
| performancePoints += resultFactor / raceResult.result | |
| console.log("resultFactor") | |
| console.log(performancePoints) | |
| // TODO: Add factor in % | |
| // avg result (delta) -> pace & race craft | |
| let avgResMult = RANDOM_VALUES(ratingFactor.avg_result) | |
| console.log("avg_race_result") | |
| console.log(raceResult.avg_race_result) | |
| console.log("raceResult.result") | |
| console.log(raceResult.result) | |
| var avgDeltaPos = raceResult.avg_race_result - raceResult.result | |
| console.log("avgDeltaPos") | |
| console.log(avgDeltaPos) | |
| avgDeltaPos = avgDeltaPos == 0 ? 1 : avgDeltaPos | |
| performancePoints += avgResMult * (avgDeltaPos/20) | |
| console.log("avgResMult") | |
| console.log(avgResMult * (avgDeltaPos/20)) | |
| console.log(performancePoints) | |
| // result (delta) -> race craft | |
| // start & final position multiplier | |
| let posMult = RANDOM_VALUES(ratingFactor.pos_mult) | |
| var deltaPos = raceResult.grid_start_pos - raceResult.result | |
| deltaPos = deltaPos == 0 ? 1 : deltaPos | |
| performancePoints += posMult * deltaPos | |
| console.log("posMult") | |
| console.log(performancePoints) | |
| //review this -> make this logic that cutting one on XP method | |
| let performancePointsTotal = performancePoints * raceResult.xp_limit_cut_factor | |
| console.log("raceResult.xp_limit_cut_factor") | |
| console.log(raceResult.xp_limit_cut_factor) | |
| console.log("### FINAL performancePointsTotal") | |
| console.log(performancePointsTotal) | |
| if (raceResult.driver_avg >= FIRST_XP_CUT) { | |
| return Math.floor(performancePointsTotal) | |
| } | |
| return Math.ceil(performancePointsTotal) | |
| } | |
| function MAKE_XP_LIMIT_CUT_FACTOR(driverAvg) { | |
| // if a driver has reach avg xp limit | |
| // return less % for new points | |
| if (driverAvg > SECOND_XP_CUT) { | |
| return (XP_LIMIT_CUT - driverAvg) / 110 | |
| } | |
| if (driverAvg > FIRST_XP_CUT) { | |
| return (XP_LIMIT_CUT - driverAvg) / 100 | |
| } | |
| let bonusFactor = RP_INITIAL_BONUS + XP_LIMIT_CUT | |
| console.log("NORMAL CUT") | |
| console.log((bonusFactor - driverAvg) / 100) | |
| return (bonusFactor - driverAvg) / 100 | |
| } | |
| // set quali factor regarding driver avg rating | |
| // this can return high rating values for drivers with target closest time | |
| // NOT TO BE USED ANYMORE | |
| function GET_LAP_TIME_FACTOR_BY(driverAvg) { | |
| // if a driver has reach avg xp limit for the higher lap time factor return a possibility points | |
| if (driverAvg > MAX_LAP_TIME_XP_BONUS) { | |
| return POSSIBILITY_POINT() | |
| } | |
| // first cut returns up to the lap factor limit | |
| let firstCut = MAX_LAP_TIME_XP_BONUS - 15 | |
| var lapFactorLimit = LAP_TIME_INITIAL_BONUS | |
| let minimumAvgRating = 50 | |
| if (driverAvg <= firstCut) { | |
| let lapTimeFactor = lapFactorLimit - (driverAvg - minimumAvgRating) | |
| return Math.min(Math.max(lapTimeFactor, 2), lapFactorLimit) | |
| } | |
| // second cut retuns lower factor | |
| // driver avg is between limit and first cut | |
| // note: there's a gap between lap factor and avg rating between cuts (minimumAvgRating values) | |
| lapFactorLimit -= 10 | |
| minimumAvgRating += 15 | |
| let lapTimeFactor = (lapFactorLimit - (driverAvg - minimumAvgRating)) | |
| return Math.max(lapTimeFactor, lapFactorLimit) | |
| } | |
| // TODO review shorting | |
| // sort by rating | |
| function SORT_TABLE() { | |
| var range = RATING_DATA.getRange("B3:N22") | |
| range.sort([{column: 14, ascending: false}]) | |
| } | |
| function SORT_BY_QUALI() { | |
| var range = RATING_DATA.getRange("B3:N22") | |
| range.sort([{column: 5, ascending: true}]) | |
| } | |
| function RANDOM_VALUES(factorValues) { | |
| // randomized between factor range | |
| let min = factorValues[0] | |
| let max = factorValues[1] | |
| let value = parseFloat((Math.random() * (max - min) + min).toFixed(2)) | |
| return value | |
| } | |
| //------------------------------------------------------------------------------------------------------ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment