Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

slash grades should have integer scores #138

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/GradeScale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ export const findScoreRange = (compareFn, list): number | Tuple => {
}
return [low, high]
}

export function getAvgScore (score: number | Tuple): number {
return typeof score === 'number' ? score : (score[1] + score[0]) / 2
}

/**
* For getting a whole number/integer tuple of a grade which resides between two adjacent grades.
* Returns an integer tuple, rounded EXCLUSIVELY of the adjacent grade scores.
* Related discussion: https://github.com/OpenBeta/sandbag/issues/137
*/
export const getRoundedScoreTuple = (gradeAverage: number, nextGradeAverage: number): Tuple => {
const low = Math.ceil(Math.min(gradeAverage, nextGradeAverage))
const high = Math.floor(Math.max(gradeAverage, nextGradeAverage))
return [low, high]
}
4 changes: 2 additions & 2 deletions src/__tests__/readme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
describe('Convert grades to scores', () => {
test('returns the correct score', () => {
expect(French.getScore('8a')).toEqual([84, 85])
expect(French.getScore('7c+/8a')).toEqual([82.5, 84.5])
expect(YosemiteDecimal.getScore('5.12+')).toEqual([78.5, 80.5])
expect(French.getScore('7c+/8a')).toEqual([83, 84])
expect(YosemiteDecimal.getScore('5.12+')).toEqual([79, 80])
})
})

Expand Down
8 changes: 4 additions & 4 deletions src/__tests__/scales/norwegian.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ describe('Norwegian', () => {
})

test('Slash grade provided', () => {
expect(Norwegian.getScore('4-/4')).toStrictEqual([30.5, 33.5])
expect(Norwegian.getScore('5/5+')).toStrictEqual([45.5, 51.5])
expect(Norwegian.getScore('7+/8-')).toStrictEqual([72.5, 75.5])
expect(Norwegian.getScore('7+/7')).toStrictEqual([72.5, 75.5])
expect(Norwegian.getScore('4-/4')).toStrictEqual([31, 33])
expect(Norwegian.getScore('5/5+')).toStrictEqual([46, 51])
expect(Norwegian.getScore('7+/8-')).toStrictEqual([73, 75])
expect(Norwegian.getScore('7+/7')).toStrictEqual([73, 75])
})
})

Expand Down
40 changes: 36 additions & 4 deletions src/__tests__/scales/yds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('YosemiteDecimal', () => {
const highGrade = YosemiteDecimal.getScore('5.12a')
expect(highGrade[0]).toBeGreaterThan(lowGrade[1])
})

describe('invalid grade format', () => {
jest.spyOn(console, 'warn').mockImplementation()
beforeEach(() => {
Expand Down Expand Up @@ -62,6 +63,10 @@ describe('YosemiteDecimal', () => {
expect(YosemiteDecimal.isType('5.11B')).toBeTruthy()
})

test('grade above 5.9 with no letter', () => {
expect(YosemiteDecimal.isType('5.11')).toBeTruthy()
})

test('grade plus modifier is accepted', () => {
expect(YosemiteDecimal.isType('5.12+')).toBeTruthy()
expect(YosemiteDecimal.isType('5.12-')).toBeTruthy()
Expand Down Expand Up @@ -124,14 +129,41 @@ describe('YosemiteDecimal', () => {

describe('Slash scores', () => {
test('scores of slash grades should be subset of neighboring scores', () => {
const slashScore = YosemiteDecimal.getScore('5.10a/b')
const lowScore = YosemiteDecimal.getScore('5.10a')
const highScore = YosemiteDecimal.getScore('5.10b')

const slashScore = YosemiteDecimal.getScore('5.11a/b')
const lowScore = YosemiteDecimal.getScore('5.11a')
const highScore = YosemiteDecimal.getScore('5.11b')
expect(slashScore[0]).toBeGreaterThan(lowScore[0])
expect(slashScore[1]).toBeGreaterThan(lowScore[1])
expect(slashScore[0]).toBeLessThan(highScore[0])
expect(slashScore[1]).toBeLessThan(highScore[1])
})
})
})

// see related discussion regarding handling of non-letter'd grades: https://github.com/OpenBeta/sandbag/issues/137
describe('grades above 5.9 with no letter', () => {
test('getScore returns an integer value', () => {
const score = YosemiteDecimal.getScore('5.11')
expect(Number.isInteger(score[0])).toBeTruthy()
expect(Number.isInteger(score[1])).toBeTruthy()
expect(score[1]).toBeGreaterThan(score[0])
})
test('5.11 > 5.11a', () => {
const lowGrade = YosemiteDecimal.getScore('5.11a')
const highGrade = YosemiteDecimal.getScore('5.11')
expect(highGrade[0]).toBeGreaterThan(lowGrade[1])
})
test('5.11d > 5.11', () => {
const lowGrade = YosemiteDecimal.getScore('5.11')
const highGrade = YosemiteDecimal.getScore('5.11d')
expect(highGrade[0]).toBeGreaterThan(lowGrade[1])
})
test('getScore and getGrade agree on value of grade', () => {
const grade = '5.11'
const score = YosemiteDecimal.getScore(grade)
const reParsedGrade = YosemiteDecimal.getGrade(score)
const reScoredParsedGrade = YosemiteDecimal.getScore(reParsedGrade)
expect(reParsedGrade).toEqual('5.11b/c')
expect(reScoredParsedGrade).toEqual(score)
})
})
7 changes: 5 additions & 2 deletions src/scales/ewbank.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, getRoundedScoreTuple, Tuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -69,7 +69,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Route) => r.ewbank === routes[otherGrade].ewbank,
routes
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/font.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import boulder from '../data/boulder.json'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'

import { Boulder } from '.'
import { boulderScoreToBand, GradeBandTypes } from '../GradeBands'
Expand Down Expand Up @@ -67,7 +67,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Boulder) => r.font.toLowerCase() === boulder[otherGrade].font.toLowerCase(),
boulder
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/french.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -66,7 +66,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Route) => r.french.toLowerCase() === routes[otherGrade].french.toLowerCase(),
routes
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/norwegian.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -66,7 +66,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Route) => r.norwegian === routes[otherGrade].norwegian,
routes
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/saxon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -66,7 +66,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Route) => r.saxon.toLowerCase() === routes[otherGrade].saxon.toLowerCase(),
routes
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/uiaa.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -66,7 +66,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Route) => r.uiaa.toLowerCase() === routes[otherGrade].uiaa.toLowerCase(),
routes
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/v.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import boulder from '../data/boulder.json'
import { Boulder } from '.'
import { boulderScoreToBand, GradeBandTypes } from '../GradeBands'
Expand Down Expand Up @@ -100,7 +100,10 @@ const getScore = (grade: string): number | Tuple => {
(r: Boulder) => r.v.toLowerCase() === boulder[otherGrade].v.toLowerCase(),
boulder
)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
7 changes: 5 additions & 2 deletions src/scales/yds.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple } from '../GradeScale'
import GradeScale, { findScoreRange, getAvgScore, GradeScales, Tuple, getRoundedScoreTuple } from '../GradeScale'
import routes from '../data/routes.json'
import { Route } from '.'
import { GradeBandTypes, routeScoreToBand } from '../GradeBands'
Expand Down Expand Up @@ -96,7 +96,10 @@ const getScore = (grade: string): number | Tuple => {
const nextGrade = findScoreRange((r: Route) => {
return r.yds.toLowerCase() === routes[Math.max(otherScore, 0)].yds.toLowerCase()
}, routes)
return [getAvgScore(basicScore), getAvgScore(nextGrade)].sort((a, b) => a - b) as Tuple
const basicAvg = getAvgScore(basicScore)
const nextGradeAvg = getAvgScore(nextGrade)
const tuple = getRoundedScoreTuple(basicAvg, nextGradeAvg)
return tuple
}
}
return basicScore
Expand Down
Loading