Kink scoring
This commit is contained in:
parent
00f2e2ba03
commit
4c28ce8264
|
@ -197,6 +197,8 @@
|
|||
@Hook('mounted')
|
||||
mounted(): void {
|
||||
core.connection.onMessage('ERR', (data) => {
|
||||
this.state = 'search';
|
||||
|
||||
switch(data.number) {
|
||||
case 18:
|
||||
this.error = l('characterSearch.error.noResults');
|
||||
|
|
|
@ -10,7 +10,9 @@ export enum TagId {
|
|||
ApparentAge = 64,
|
||||
RelationshipStatus = 42,
|
||||
Species = 9,
|
||||
LanguagePreference = 49
|
||||
LanguagePreference = 49,
|
||||
|
||||
Kinks = 99999
|
||||
}
|
||||
|
||||
export enum Gender {
|
||||
|
@ -481,3 +483,90 @@ export interface SpeciesMappingCache {
|
|||
[key: number]: SpeciesMappingCacheRecord[];
|
||||
}
|
||||
|
||||
|
||||
export const kinkMatchScoreMap = {
|
||||
favorite: {
|
||||
favorite: 0.55,
|
||||
yes: 0.25,
|
||||
maybe: -0.5,
|
||||
no: -1.0
|
||||
},
|
||||
|
||||
yes: {
|
||||
favorite: 0.20,
|
||||
yes: 0.20,
|
||||
maybe: -0.25,
|
||||
no: -0.5
|
||||
},
|
||||
|
||||
maybe: {
|
||||
favorite: -0.5,
|
||||
yes: -0.25,
|
||||
maybe: 0,
|
||||
no: 0
|
||||
},
|
||||
|
||||
no: {
|
||||
favorite: -1.0,
|
||||
yes: -0.5,
|
||||
maybe: -0.1,
|
||||
no: 0
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const kinkComparisonExclusions = {
|
||||
585: true, // amputees
|
||||
587: true, // anthro characters
|
||||
588: true, // body hair
|
||||
589: true, // canon characters
|
||||
458: true, // chubby
|
||||
605: true, // disabilities
|
||||
590: true, // facial hair / beards
|
||||
531: true, // femboys
|
||||
592: true, // femininity
|
||||
109: true, // older characters
|
||||
600: true, // shorter characters
|
||||
601: true, // skinny characters
|
||||
584: true, // slime / goo characters
|
||||
616: true, // superheroes / villains
|
||||
603: true, // taller characters
|
||||
532: true, // tomboys
|
||||
720: true, // toons
|
||||
354: true, // twinks
|
||||
183: true, // very fat characters
|
||||
85: true, // very lithe characters
|
||||
84: true, // very muscular characters
|
||||
197: true // younger characters
|
||||
};
|
||||
|
||||
export const kinkComparisonExclusionGroups = {
|
||||
29: true, // gender preferences
|
||||
30: true // species preferences
|
||||
};
|
||||
|
||||
|
||||
export const kinkComparisonSwaps: Record<any, number> = {
|
||||
137: 157, // anal sex giving -> receiving
|
||||
157: 137, // anal sex receiving -> giving
|
||||
163: 16, // rimming giving -> receiving
|
||||
16: 163, // rimming receiving -> giving
|
||||
229: 340, // vaginal sex giving -> receiving
|
||||
340: 229, // vaginal sex receiving -> giving
|
||||
513: 515, // cunnilingus giving -> receiving
|
||||
515: 513, // cunnilingus receiving -> giving
|
||||
141: 158, // oral sex giving -> receiving
|
||||
158: 141 // oral sex receiving -> giving
|
||||
};
|
||||
|
||||
|
||||
export interface KinkBucketScore {
|
||||
score: number;
|
||||
count: number;
|
||||
weighted: number;
|
||||
}
|
||||
|
||||
export interface MatchResultKinkScores {
|
||||
[key: string]: KinkBucketScore;
|
||||
}
|
||||
|
||||
|
|
124
learn/matcher.ts
124
learn/matcher.ts
|
@ -1,20 +1,21 @@
|
|||
/* eslint-disable no-null-keyword, max-file-line-count */
|
||||
|
||||
import * as _ from 'lodash';
|
||||
import { Character, CharacterInfotag } from '../interfaces';
|
||||
import { Character, CharacterInfotag, KinkChoice } from '../interfaces';
|
||||
import log from 'electron-log'; //tslint:disable-line:match-default-export-name
|
||||
|
||||
// tslint:disable-next-line ban-ts-ignore
|
||||
// @ts-ignore
|
||||
import anyAscii from 'any-ascii';
|
||||
|
||||
import {Store} from '../site/character_page/data_store';
|
||||
|
||||
import {
|
||||
BodyType, fchatGenderMap,
|
||||
FurryPreference,
|
||||
Gender, genderKinkMapping,
|
||||
Kink,
|
||||
kinkMapping,
|
||||
Kink, KinkBucketScore, kinkComparisonExclusionGroups, kinkComparisonExclusions, kinkComparisonSwaps,
|
||||
kinkMapping, kinkMatchScoreMap,
|
||||
KinkPreference, likelyHuman, mammalSpecies, nonAnthroSpecies,
|
||||
Orientation,
|
||||
Species, SpeciesMap, speciesMapping, SpeciesMappingCache,
|
||||
|
@ -25,6 +26,7 @@ import {
|
|||
|
||||
|
||||
export interface MatchReport {
|
||||
_isVue: true;
|
||||
you: MatchResult;
|
||||
them: MatchResult;
|
||||
youMultiSpecies: boolean;
|
||||
|
@ -47,6 +49,7 @@ export interface MatchResultScores {
|
|||
[TagId.Age]: Score;
|
||||
[TagId.FurryPreference]: Score;
|
||||
[TagId.Species]: Score;
|
||||
[TagId.Kinks]: Score;
|
||||
}
|
||||
|
||||
export interface MatchScoreDetails {
|
||||
|
@ -177,7 +180,7 @@ export class Matcher {
|
|||
readonly yourAnalysis: CharacterAnalysis;
|
||||
readonly theirAnalysis: CharacterAnalysis;
|
||||
|
||||
static readonly UNICORN_LEVEL = 5.5;
|
||||
static readonly UNICORN_LEVEL = 6.0;
|
||||
|
||||
|
||||
constructor(you: Character, them: Character, yourAnalysis?: CharacterAnalysis, theirAnalysis?: CharacterAnalysis) {
|
||||
|
@ -199,6 +202,7 @@ export class Matcher {
|
|||
const themYouMatch = themYou.match();
|
||||
|
||||
const report: MatchReport = {
|
||||
_isVue: true,
|
||||
you: youThemMatch,
|
||||
them: themYouMatch,
|
||||
youMultiSpecies: false,
|
||||
|
@ -216,6 +220,8 @@ export class Matcher {
|
|||
report.details.totalScoreDimensions = Matcher.countScoresTotal(report);
|
||||
report.details.dimensionsAtScoreLevel = Matcher.countScoresAtLevel(report, report.score) || 0;
|
||||
|
||||
// log.debug('report.generate', report);
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
|
@ -238,6 +244,7 @@ export class Matcher {
|
|||
const themYouMatch = themYou.match();
|
||||
|
||||
const report: MatchReport = {
|
||||
_isVue: true,
|
||||
you: youThemMatch,
|
||||
them: themYouMatch,
|
||||
youMultiSpecies: (yourCharacterAnalyses.length > 1),
|
||||
|
@ -275,7 +282,11 @@ export class Matcher {
|
|||
|
||||
log.debug(
|
||||
'report.identify.best',
|
||||
{buildTime: Date.now() - reportStartTime, variations: yourCharacterAnalyses.length * theirCharacterAnalyses.length}
|
||||
{
|
||||
buildTime: Date.now() - reportStartTime,
|
||||
variations: yourCharacterAnalyses.length * theirCharacterAnalyses.length,
|
||||
report: bestReport!
|
||||
}
|
||||
);
|
||||
|
||||
return bestReport!;
|
||||
|
@ -382,7 +393,8 @@ export class Matcher {
|
|||
[TagId.Age]: this.resolveAgeScore(),
|
||||
[TagId.FurryPreference]: this.resolveFurryPairingsScore(),
|
||||
[TagId.Species]: this.resolveSpeciesScore(),
|
||||
[TagId.SubDomRole]: this.resolveSubDomScore()
|
||||
[TagId.SubDomRole]: this.resolveSubDomScore(),
|
||||
[TagId.Kinks]: this.resolveKinkScore()
|
||||
},
|
||||
|
||||
info: {
|
||||
|
@ -557,6 +569,32 @@ export class Matcher {
|
|||
return this.formatScoring(score, theyAreAnthro ? 'furry pairings' : theyAreHuman ? 'human pairings' : '');
|
||||
}
|
||||
|
||||
|
||||
private resolveKinkScore(): Score {
|
||||
const kinkScore = this.resolveKinkBucketScore('all');
|
||||
|
||||
log.debug('report.score.kink', this.them.name, this.you.name, kinkScore.count, kinkScore.score, kinkScore.weighted);
|
||||
|
||||
if (kinkScore.weighted === 0) {
|
||||
return new Score(Scoring.NEUTRAL);
|
||||
}
|
||||
|
||||
if (kinkScore.weighted < 0) {
|
||||
if (Math.abs(kinkScore.weighted) < 0.45) {
|
||||
return new Score(Scoring.WEAK_MISMATCH, 'Challenging <span>kinks</span>');
|
||||
}
|
||||
|
||||
return new Score(Scoring.MISMATCH, 'Mismatching <span>kinks</span>');
|
||||
}
|
||||
|
||||
if (Math.abs(kinkScore.weighted) < 0.45) {
|
||||
return new Score(Scoring.WEAK_MATCH, 'Good <span>kinks</span>');
|
||||
}
|
||||
|
||||
return new Score(Scoring.MATCH, 'Great <span>kinks</span>');
|
||||
}
|
||||
|
||||
|
||||
static furryLikeabilityScore(c: Character): Scoring {
|
||||
const furryPreference = Matcher.getTagValueList(TagId.FurryPreference, c);
|
||||
|
||||
|
@ -747,6 +785,78 @@ export class Matcher {
|
|||
}
|
||||
|
||||
|
||||
private resolveKinkBucketScore(bucket: 'all' | 'favorite' | 'yes' | 'maybe' | 'no' | 'positive' | 'negative'): KinkBucketScore {
|
||||
const yourKinks = this.getAllStandardKinks(this.you);
|
||||
const theirKinks = this.getAllStandardKinks(this.them);
|
||||
|
||||
const result: any = _.reduce(
|
||||
yourKinks,
|
||||
(accum, yourKinkValue: any, yourKinkId: any) => {
|
||||
const theirKinkId = (yourKinkId in kinkComparisonSwaps) ? kinkComparisonSwaps[yourKinkId] : yourKinkId;
|
||||
|
||||
if (
|
||||
(!(theirKinkId in theirKinks))
|
||||
|| (yourKinkId in kinkComparisonExclusions)
|
||||
|| ((Store.shared.kinks[yourKinkId]) && (Store.shared.kinks[yourKinkId].kink_group in kinkComparisonExclusionGroups))
|
||||
) {
|
||||
return accum;
|
||||
}
|
||||
|
||||
const theirKinkValue = theirKinks[theirKinkId] as any;
|
||||
|
||||
if (
|
||||
(yourKinkValue === bucket)
|
||||
|| (bucket === 'all')
|
||||
|| ((bucket === 'negative') && ((yourKinkValue === 'no') || (yourKinkValue === 'maybe')))
|
||||
|| ((bucket === 'positive') && ((yourKinkValue === 'favorite') || (yourKinkValue === 'yes')))
|
||||
) {
|
||||
return {
|
||||
score: accum.score + this.getKinkMatchScore(yourKinkValue, theirKinkValue),
|
||||
count: accum.count + 1
|
||||
};
|
||||
}
|
||||
|
||||
return accum;
|
||||
},
|
||||
{ score: 0, count: 0 }
|
||||
);
|
||||
|
||||
result.weighted = (result.count === 0)
|
||||
? 0
|
||||
: (
|
||||
(Math.log(result.count) / Math.log(5)) // log 5 base
|
||||
* (result.score / result.count)
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private getAllStandardKinks(c: Character): { [key: number]: KinkChoice } {
|
||||
const kinks = _.pickBy(c.kinks, _.isString);
|
||||
|
||||
_.each(
|
||||
c.customs,
|
||||
(custom: any) => {
|
||||
if (!custom) {
|
||||
return;
|
||||
}
|
||||
|
||||
const children = (custom.children) ? custom.children : {};
|
||||
|
||||
_.each(children, (child) => kinks[child] = custom.choice);
|
||||
}
|
||||
);
|
||||
|
||||
return kinks as any;
|
||||
}
|
||||
|
||||
|
||||
private getKinkMatchScore(aValue: string, bValue: string): number {
|
||||
return _.get(kinkMatchScoreMap, `${aValue}.${bValue}`, 0);
|
||||
}
|
||||
|
||||
|
||||
static getTagValue(tagId: number, c: Character): CharacterInfotag | undefined {
|
||||
return c.infotags[tagId];
|
||||
}
|
||||
|
@ -1026,6 +1136,8 @@ export class Matcher {
|
|||
aboveLevelScore = (1 - (aboveLevelMul * 0.5)) * Math.pow(dimensionsAboveScoreLevel, matchRatio);
|
||||
}
|
||||
|
||||
// const kinkScore = match.you.kinkScore.weighted;
|
||||
|
||||
log.debug(
|
||||
'report.score.search',
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue