Coverage Summary for Class: ContractAttractiveness (core)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| ContractAttractiveness |
100%
(1/1)
|
100%
(1/1)
|
|
100%
(2/2)
|
100%
(7/7)
|
package core
import core.primitives.SalvagePolicy
import core.state.BoardContract
import core.state.ContractDraft
import core.state.Hero
/**
* Result of evaluating a contract's attractiveness to a hero.
*
* @property score Higher values indicate more attractive contracts.
* Negative scores indicate the hero would refuse the contract.
*/
data class ContractAttractiveness(
val score: Int
)
/**
* Evaluates how attractive a board contract is to a specific hero.
*
* Score calculation factors:
* - Base profit from fee and salvage rights
* - Risk penalty if difficulty exceeds hero's comfort zone
* - Personality modifiers (greed increases salvage value, honesty reduces theft temptation)
* - Courage affects risk tolerance
*
* Decision threshold:
* - score < 0: hero refuses contract
* - score >= 0: hero willing to take contract
*
* @param hero The hero evaluating the contract
* @param board The board contract being evaluated
* @param difficulty Base difficulty from the original draft (1 = easy, higher = harder)
* @return ContractAttractiveness with computed score
*/
fun evaluateContractForHero(
hero: Hero,
board: BoardContract,
difficulty: Int
): ContractAttractiveness {
// 1. Base profit score from fee
val feeScore = board.fee / 10
// 2. Salvage value (influenced by greed)
val salvageScore = when (board.salvage) {
SalvagePolicy.GUILD -> {
// No direct trophy benefit, hero dislikes this if greedy
val greedPenalty = (hero.traits.greed - 50) / 5 // -10..+10
-greedPenalty // Greedy heroes penalize GUILD salvage
}
SalvagePolicy.HERO -> {
// Full trophy ownership, value scales with expected loot
val baseValue = difficulty * 5 // Harder contracts = more trophies
val greedBonus = (hero.traits.greed - 50) / 10 // 0..+5 for greedy heroes
baseValue + greedBonus
}
SalvagePolicy.SPLIT -> {
// Compromise: moderate value
val baseValue = difficulty * 2
val greedBonus = (hero.traits.greed - 50) / 20 // 0..+2
baseValue + greedBonus
}
}
// 3. Risk assessment
val heroRankLevel = hero.rank.ordinal // F=0, E=1, D=2, etc.
val riskThreshold = (heroRankLevel + 1) * 2 // F can handle up to ~2, E up to ~4, etc.
val riskPenalty = if (difficulty > riskThreshold) {
// Too dangerous: apply courage-modified penalty
val basePenalty = (difficulty - riskThreshold) * 15
val courageMod = (50 - hero.traits.courage) / 10 // Cowards add more penalty
basePenalty + courageMod
} else {
0
}
// 4. Combine all factors
val finalScore = feeScore + salvageScore - riskPenalty
return ContractAttractiveness(score = finalScore)
}
/**
* Helper to extract difficulty from a contract draft.
* This is used during contract evaluation in the pickup phase.
*
* @param draft The contract draft to extract difficulty from
* @return The base difficulty value
*/
fun getDifficultyFromDraft(draft: ContractDraft): Int {
return draft.baseDifficulty
}
/**
* Helper to find the corresponding draft for a board contract.
* Used to retrieve difficulty during hero decision-making.
*
* Note: In the current PoC, drafts are removed from inbox when posted to board.
* For MVP, we'll need to either:
* 1. Store difficulty in BoardContract directly, OR
* 2. Maintain a difficulty lookup table
*
* For now, this returns a default difficulty based on rank.
*
* @param board The board contract
* @return Estimated difficulty (1-5 scale)
*/
fun estimateDifficultyFromBoard(board: BoardContract): Int {
// Temporary heuristic until we store difficulty in BoardContract
return when (board.rank) {
core.primitives.Rank.F -> 1
core.primitives.Rank.E -> 2
core.primitives.Rank.D -> 3
core.primitives.Rank.C -> 4
core.primitives.Rank.B -> 5
core.primitives.Rank.A -> 6
core.primitives.Rank.S -> 8
}
}