Skip to content

Commit

Permalink
Merge pull request #97 from Boost-Coder/feature/totalPoint-#49
Browse files Browse the repository at this point in the history
[#49] 종합 점수 계산 알고리즘 구현
  • Loading branch information
namewhat99 authored May 23, 2024
2 parents 338eaf9 + 19b1ea5 commit bcf5324
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 54 deletions.
4 changes: 2 additions & 2 deletions src/Entity/algorithm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ export class Algorithm {
@Column()
solvedCount: number;

@Column()
point: number;
@Column('double')
score: number;

@CreateDateColumn({
type: 'timestamp',
Expand Down
4 changes: 2 additions & 2 deletions src/Entity/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export class Github {
@Column()
githubId: number;

@Column()
point: number;
@Column('double')
score: number;

@Column()
accessToken: string;
Expand Down
4 changes: 2 additions & 2 deletions src/Entity/grade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export class Grade {
@Column('double')
grade: number;

@Column()
point: number;
@Column('double')
score: number;

@CreateDateColumn({
type: 'timestamp',
Expand Down
4 changes: 2 additions & 2 deletions src/Entity/totalPoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ export class TotalPoint {
})
userId: string;

@Column()
point: number;
@Column('double')
score: number;

@CreateDateColumn({
type: 'timestamp',
Expand Down
2 changes: 1 addition & 1 deletion src/batch/batch.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class BatchService {
private githubService: GithubService,
private totalService: TotalService,
) {}
@Cron('0 0 * * * *')
@Cron('0 0 0 * * *')
@Transactional({
isolationLevel: IsolationLevel.READ_COMMITTED,
})
Expand Down
2 changes: 1 addition & 1 deletion src/stat/dto/rank-list-option.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class RankListDto {
userId: string;

@ApiProperty()
point: number;
score: number;

@ApiProperty()
nickname: string;
Expand Down
2 changes: 1 addition & 1 deletion src/stat/repository/github.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class GithubRepository extends StatRepository {
{
githubId: github.githubId,
accessToken: github.accessToken,
point: github.point,
point: github.score,
},
);
}
Expand Down
2 changes: 1 addition & 1 deletion src/stat/repository/grade.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class GradeRepository extends StatRepository {
{ userId: newGrade.userId },
{
grade: newGrade.grade,
point: newGrade.point,
point: newGrade.score,
},
);
}
Expand Down
6 changes: 3 additions & 3 deletions src/stat/service/algorithm.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ describe('AlgorithmService', () => {
algorithm.rating = mockResponse.data.rating;
algorithm.tier = mockResponse.data.tier;
algorithm.solvedCount = mockResponse.data.solvedCount;
algorithm.point = 0;
algorithm.score = 91.96000000000001;
algorithmRepository.save.mockResolvedValue(algorithm);

await service.createAlgorithm(userId, bojId);
Expand Down Expand Up @@ -133,7 +133,7 @@ describe('AlgorithmService', () => {
algorithm.rating = 1500;
algorithm.tier = 16;
algorithm.solvedCount = 100;
algorithm.point = 0;
algorithm.score = 0;
algorithmRepository.findOneById.mockResolvedValue(algorithm);

const mockResponse = {
Expand Down Expand Up @@ -175,7 +175,7 @@ describe('AlgorithmService', () => {
algorithm.rating = 1500;
algorithm.tier = 16;
algorithm.solvedCount = 100;
algorithm.point = 0;
algorithm.score = 0;
algorithmRepository.findOneById.mockResolvedValue(algorithm);

const mockResponse = {
Expand Down
36 changes: 29 additions & 7 deletions src/stat/service/algorithm.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import {
import axios from 'axios';
import { AlgorithmRepository } from '../repository/algorithm.repository';
import { Algorithm } from '../../Entity/algorithm';
import { NotFoundError } from 'rxjs';
import { RankListDto, RankListOptionDto } from '../dto/rank-list-option.dto';
import { PointFindDto } from '../dto/rank-find.dto';
import { PERCENTILES, RATINGS } from '../../utils/algorithmData';

const URL = 'https://solved.ac/api/v3/user/show?handle=';

Expand Down Expand Up @@ -49,12 +49,13 @@ export class AlgorithmService {
algorithm.rating = bojInfo.rating;
algorithm.tier = bojInfo.tier;
algorithm.solvedCount = bojInfo.solvedCount;
algorithm.point = this.calculatePoint(bojInfo);
algorithm.score = this.calculatePoint(bojInfo);
await this.algorithmRepository.save(algorithm);
}

async updateAlgorithm(userId: string) {
const algorithm = await this.algorithmRepository.findOneById(userId);
const algorithm: Algorithm =
await this.algorithmRepository.findOneById(userId);
if (algorithm === null) {
return;
}
Expand All @@ -63,7 +64,7 @@ export class AlgorithmService {
algorithm.tier = bojInfo.tier;
algorithm.rating = bojInfo.rating;
algorithm.solvedCount = bojInfo.solvedCount;
algorithm.point = this.calculatePoint(bojInfo);
algorithm.score = this.calculatePoint(bojInfo);
await this.algorithmRepository.updateAlgorithm(userId, algorithm);
} catch (e) {
if (e instanceof BadRequestException) {
Expand All @@ -78,7 +79,8 @@ export class AlgorithmService {
}

async modifyAlgorithm(userId: string, bojId: string) {
const algorithm = await this.algorithmRepository.findOneById(userId);
const algorithm: Algorithm =
await this.algorithmRepository.findOneById(userId);
if (algorithm === null) {
throw new NotFoundException('Algorithm info not found');
}
Expand All @@ -87,7 +89,7 @@ export class AlgorithmService {
algorithm.tier = bojInfo.tier;
algorithm.rating = bojInfo.rating;
algorithm.solvedCount = bojInfo.solvedCount;
algorithm.point = this.calculatePoint(bojInfo);
algorithm.score = this.calculatePoint(bojInfo);
await this.algorithmRepository.updateAlgorithm(userId, algorithm);
}

Expand Down Expand Up @@ -118,7 +120,27 @@ export class AlgorithmService {
}

private calculatePoint(bojInfo: BOJInfo) {
return 0;
const rating = bojInfo.rating;
if (rating <= RATINGS[0]) {
return 100 - PERCENTILES[0];
} else if (rating >= RATINGS[RATINGS.length - 1]) {
return 100 - PERCENTILES[PERCENTILES.length - 1];
} else {
for (let i = 1; i < RATINGS.length; i++) {
if (rating < RATINGS[i]) {
// 선형 보간법
const x0 = RATINGS[i - 1],
x1 = RATINGS[i];
const y0 = PERCENTILES[i - 1],
y1 = PERCENTILES[i];
const percentile =
y0 + ((rating - x0) * (y1 - y0)) / (x1 - x0);
return 100 - percentile;
}
}
return 0;
}
// return bojInfo.rating;
}

public async getIndividualAlgorithmRank(
Expand Down
26 changes: 16 additions & 10 deletions src/stat/service/github.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { Github } from '../../Entity/github';
import { CreateGithubDto } from '../dto/createGitub.dto';
import { RankListOptionDto } from '../dto/rank-list-option.dto';
import { PointFindDto } from '../dto/rank-find.dto';
import { exponential_cdf, log_normal_cdf } from '../../utils/cdf';

@Injectable()
export class GithubService {
Expand All @@ -36,7 +37,7 @@ export class GithubService {

const github = new Github();
github.userId = userId;
github.point = githubPoint;
github.score = githubPoint;
github.accessToken = tokens.accessToken;
github.githubId = userResource.id;
await this.githubRepository.save(github);
Expand All @@ -56,7 +57,7 @@ export class GithubService {

const github = new Github();
github.userId = userId;
github.point = githubPoint;
github.score = githubPoint;
github.accessToken = tokens.accessToken;
github.githubId = userResource.id;
await this.githubRepository.updateGithub(github);
Expand All @@ -69,7 +70,7 @@ export class GithubService {
}
try {
const githubInfo = await this.getUserResource(github.accessToken);
github.point = await this.calculateGithubPoint(githubInfo);
github.score = await this.calculateGithubPoint(githubInfo);
await this.githubRepository.updateGithub(github);
} catch (e) {
this.logger.error(
Expand All @@ -91,18 +92,23 @@ export class GithubService {
}
public async calculateGithubPoint(userResource: object) {
const commitInfo = await this.getCommits(userResource['login']);
const PRInfo = await this.getPRs(userResource['login']);
const prInfo = await this.getPRs(userResource['login']);
const issueInfo = await this.getIssues(userResource['login']);
const followers = userResource['followers'];
const [COMMIT_WEIGHT, PR_WEIGHT, ISSUE_WEIGHT, FOLLOWER_WEIGHT] = [
2, 3, 2, 1,
];
return (
commitInfo * COMMIT_WEIGHT +
issueInfo * ISSUE_WEIGHT +
PRInfo * PR_WEIGHT +
followers * FOLLOWER_WEIGHT
);
const TOTAL_WEIGHT =
COMMIT_WEIGHT + PR_WEIGHT + ISSUE_WEIGHT + FOLLOWER_WEIGHT;

const point =
(COMMIT_WEIGHT * exponential_cdf(commitInfo / 250) +
ISSUE_WEIGHT * exponential_cdf(issueInfo / 25) +
PR_WEIGHT * exponential_cdf(prInfo / 50) +
FOLLOWER_WEIGHT * log_normal_cdf(followers / 10)) /
TOTAL_WEIGHT;

return point * 100;
}

public async getIssues(userName: string) {
Expand Down
8 changes: 5 additions & 3 deletions src/stat/service/grade.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export class GradeService {
const newGrade = new Grade();
newGrade.userId = userId;
newGrade.grade = grade;
newGrade.point = this.calculatePoint(grade);
newGrade.score = this.calculatePoint(grade);

await this.gradeRepository.save(newGrade);
}
Expand All @@ -40,7 +40,7 @@ export class GradeService {
const newGrade = new Grade();
newGrade.userId = userId;
newGrade.grade = grade;
newGrade.point = this.calculatePoint(grade);
newGrade.score = this.calculatePoint(grade);

await this.gradeRepository.updateGrade(newGrade);
}
Expand All @@ -56,7 +56,9 @@ export class GradeService {
}

public calculatePoint(grade: number) {
return 0;
const maxGrade = 4.5;
const maxPercentage = 100;
return (grade / maxGrade) * maxPercentage;
}

public async getIndividualGradeRank(userId: string, options: PointFindDto) {
Expand Down
12 changes: 6 additions & 6 deletions src/stat/service/total.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ describe('TotalService', () => {
const github = new Github();
const algorithm = new Algorithm();
const grade = new Grade();
github.point = 123;
algorithm.point = 123;
github.score = 123;
algorithm.score = 123;
grade.grade = 123;

mockGitService.findGithub.mockResolvedValue(github);
Expand All @@ -93,16 +93,16 @@ describe('TotalService', () => {

const result = await service.findStat(userId);
expect(result.grade).toEqual(grade.grade);
expect(result.githubPoint).toEqual(github.point);
expect(result.algorithmPoint).toEqual(algorithm.point);
expect(result.githubPoint).toEqual(github.score);
expect(result.algorithmPoint).toEqual(algorithm.score);
});

it('should return null if stat does not exist', async function () {
const userId = 'qwe';
const github = new Github();
const algorithm = null;
const grade = new Grade();
github.point = 123;
github.score = 123;
grade.grade = 123;

mockGitService.findGithub.mockResolvedValue(github);
Expand All @@ -111,7 +111,7 @@ describe('TotalService', () => {

const result = await service.findStat(userId);
expect(result.grade).toEqual(grade.grade);
expect(result.githubPoint).toEqual(github.point);
expect(result.githubPoint).toEqual(github.score);
expect(result.algorithmPoint).toEqual(null);
});
});
Expand Down
22 changes: 16 additions & 6 deletions src/stat/service/total.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ export class TotalService {
const total = await this.totalRepository.findOneById(userId);

return {
githubPoint: github ? github.point : null,
algorithmPoint: algorithm ? algorithm.point : null,
githubPoint: github ? github.score : null,
algorithmPoint: algorithm ? algorithm.score : null,
grade: grade ? grade.grade : null,
totalPoint: grade ? total.point : null,
totalPoint: grade ? total.score : null,
};
}

Expand All @@ -52,7 +52,7 @@ export class TotalService {
}
const totalPoint = new TotalPoint();
totalPoint.userId = userId;
totalPoint.point = 0;
totalPoint.score = 0;

await this.totalRepository.save(totalPoint);
}
Expand All @@ -62,12 +62,22 @@ export class TotalService {
const algorithm = await this.algorithmService.findAlgorithm(userId);
const grade = await this.gradeService.findGrade(userId);
const total = new TotalPoint();
total.point = this.calculateTotalPoint(github, algorithm, grade);
total.score = this.calculateTotalPoint(github, algorithm, grade);
await this.totalRepository.updateTotal(total, userId);
}

calculateTotalPoint(github: Github, algorithm: Algorithm, grade: Grade) {
return 0;
const [GRADE_WEIGHT, ALGORITHM_WEIGHT, GITHUB_WEIGHT] = [1, 4, 4];
const TOTAL_WEIGHT = GRADE_WEIGHT + ALGORITHM_WEIGHT + GITHUB_WEIGHT;
const githubPoint = github == null ? 0 : github.score;
const algorithmPoint = algorithm == null ? 0 : algorithm.score;
const gradePoint = grade == null ? 0 : grade.score;
const totalPoint =
(githubPoint * GITHUB_WEIGHT +
algorithmPoint * ALGORITHM_WEIGHT +
gradePoint * GRADE_WEIGHT) /
TOTAL_WEIGHT;
return totalPoint;
}

public async getIndividualTotalRank(userId: string, options: PointFindDto) {
Expand Down
11 changes: 11 additions & 0 deletions src/utils/algorithmData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const RATINGS: number[] = [
0, 30, 60, 90, 120, 150, 200, 300, 400, 500, 650, 800, 950, 1100, 1250,
1400, 1600, 1750, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700,
2800, 2850, 2900, 2950, 3000,
];

export const PERCENTILES: number[] = [
100.0, 100.0, 92.73, 87.89, 82.22, 77.32, 70.19, 58.91, 50.9, 43.87, 36.36,
30.36, 24.65, 19.65, 14.68, 10.32, 5.76, 3.32, 1.95, 1.45, 1.13, 0.86, 0.58,
0.39, 0.29, 0.2, 0.13, 0.068, 0.044, 0.031, 0.024, 0.019,
];
8 changes: 8 additions & 0 deletions src/utils/cdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function exponential_cdf(x) {
return 1 - 2 ** -x;
}

export function log_normal_cdf(x) {
// approximation
return x / (1 + x);
}
Loading

0 comments on commit bcf5324

Please sign in to comment.