Skip to content

Commit

Permalink
More offer type validation
Browse files Browse the repository at this point in the history
  • Loading branch information
ekoutanov committed Feb 2, 2024
1 parent 3fa536f commit 11a1319
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 16 deletions.
2 changes: 2 additions & 0 deletions brumby-racing/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#![allow(clippy::too_many_arguments)]

pub mod model;
pub mod print;
pub mod data;
Expand Down
3 changes: 3 additions & 0 deletions brumby-soccer/src/domain/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ pub struct InvalidOfferType {
impl OfferType {
pub fn validate(&self) -> Result<(), InvalidOfferType> {
match self {
OfferType::HeadToHead(_, draw_handicap) => head_to_head::validate_type(self, draw_handicap),
OfferType::DrawNoBet(draw_handicap) => draw_no_bet::validate_type(self, draw_handicap),
OfferType::AsianHandicap(_, win_handicap) => asian_handicap::validate_type(self, win_handicap),
OfferType::SplitHandicap(_, draw_handicap, win_handicap) => split_handicap::validate_type(self, draw_handicap, win_handicap),
_ => Ok(()),
}
Expand Down
30 changes: 29 additions & 1 deletion brumby-soccer/src/domain/validation/asian_handicap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use brumby::hash_lookup::HashLookup;

use crate::domain::{validation, OfferType, Outcome, Side, WinHandicap};
use crate::domain::validation::{ExtraneousOutcome, InvalidOffer, InvalidOutcome};
use crate::domain::validation::{ExtraneousOutcome, InvalidOffer, InvalidOfferType, InvalidOutcome};

pub(crate) fn validate_outcomes(
offer_type: &OfferType,
Expand Down Expand Up @@ -36,6 +36,18 @@ pub(crate) fn validate_probs(offer_type: &OfferType, probs: &[f64]) -> Result<()
Ok(())
}

pub(crate) fn validate_type(
offer_type: &OfferType,
win_handicap: &WinHandicap,
) -> Result<(), InvalidOfferType> {
match win_handicap {
WinHandicap::BehindUnder(0) => Err(InvalidOfferType {
offer_type: offer_type.clone(),
}),
_ => Ok(()),
}
}

fn valid_outcomes(win_handicap: &WinHandicap) -> [Outcome; 2] {
[
Outcome::Win(Side::Home, win_handicap.clone()),
Expand Down Expand Up @@ -121,4 +133,20 @@ mod tests {
offer.validate().unwrap_err().to_string()
);
}

#[test]
fn invalid_type() {
let offer = Offer {
offer_type: OfferType::AsianHandicap(Period::FullTime, WinHandicap::BehindUnder(0)),
outcomes: HashLookup::from(vec![
Outcome::Win(Side::Home, WinHandicap::BehindUnder(0)),
Outcome::Win(Side::Away, WinHandicap::AheadOver(0)),
]),
market: Market::frame(&Overround::fair(), vec![0.4, 0.6], &PRICE_BOUNDS),
};
assert_eq!(
"AsianHandicap(FullTime, BehindUnder(0)) is not a valid offer type",
offer.validate().unwrap_err().to_string()
);
}
}
30 changes: 29 additions & 1 deletion brumby-soccer/src/domain/validation/draw_no_bet.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use brumby::hash_lookup::HashLookup;

use crate::domain::{DrawHandicap, validation, OfferType, Outcome, Side};
use crate::domain::validation::{ExtraneousOutcome, InvalidOffer, InvalidOutcome};
use crate::domain::validation::{ExtraneousOutcome, InvalidOffer, InvalidOfferType, InvalidOutcome};

pub(crate) fn validate_outcomes(
offer_type: &OfferType,
Expand Down Expand Up @@ -36,6 +36,18 @@ pub(crate) fn validate_probs(offer_type: &OfferType, probs: &[f64]) -> Result<()
Ok(())
}

pub(crate) fn validate_type(
offer_type: &OfferType,
draw_handicap: &DrawHandicap,
) -> Result<(), InvalidOfferType> {
match draw_handicap {
DrawHandicap::Behind(0) => Err(InvalidOfferType {
offer_type: offer_type.clone(),
}),
_ => Ok(()),
}
}

fn valid_outcomes(draw_handicap: &DrawHandicap) -> [Outcome; 2] {
[
Outcome::Win(Side::Home, draw_handicap.to_win_handicap()),
Expand Down Expand Up @@ -121,4 +133,20 @@ mod tests {
offer.validate().unwrap_err().to_string()
);
}

#[test]
fn invalid_type() {
let offer = Offer {
offer_type: OfferType::DrawNoBet(DrawHandicap::Behind(0)),
outcomes: HashLookup::from(vec![
Outcome::Win(Side::Home, WinHandicap::BehindUnder(0)),
Outcome::Win(Side::Away, WinHandicap::AheadOver(0)),
]),
market: Market::frame(&Overround::fair(), vec![0.4, 0.6], &PRICE_BOUNDS),
};
assert_eq!(
"DrawNoBet(Behind(0)) is not a valid offer type",
offer.validate().unwrap_err().to_string()
);
}
}
39 changes: 35 additions & 4 deletions brumby-soccer/src/domain/validation/head_to_head.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use brumby::hash_lookup::HashLookup;

use crate::domain::{DrawHandicap, validation, OfferType, Outcome, Side};
use crate::domain::validation::{ExtraneousOutcome, InvalidOffer, InvalidOutcome};
use crate::domain::validation::{
ExtraneousOutcome, InvalidOffer, InvalidOfferType, InvalidOutcome,
};
use crate::domain::{validation, DrawHandicap, OfferType, Outcome, Side};

pub(crate) fn validate_outcomes(
offer_type: &OfferType,
outcomes: &HashLookup<Outcome>,
draw_handicap: &DrawHandicap
draw_handicap: &DrawHandicap,
) -> Result<(), InvalidOutcome> {
validation::OutcomesCompleteAssertion {
outcomes: &valid_outcomes(draw_handicap),
Expand All @@ -18,7 +20,7 @@ pub(crate) fn validate_outcomes(
pub(crate) fn validate_outcome(
offer_type: &OfferType,
outcome: &Outcome,
draw_handicap: &DrawHandicap
draw_handicap: &DrawHandicap,
) -> Result<(), InvalidOutcome> {
let valid_outcomes = valid_outcomes(draw_handicap);
if valid_outcomes.contains(outcome) {
Expand All @@ -36,6 +38,18 @@ pub(crate) fn validate_probs(offer_type: &OfferType, probs: &[f64]) -> Result<()
Ok(())
}

pub(crate) fn validate_type(
offer_type: &OfferType,
draw_handicap: &DrawHandicap,
) -> Result<(), InvalidOfferType> {
match draw_handicap {
DrawHandicap::Behind(0) => Err(InvalidOfferType {
offer_type: offer_type.clone(),
}),
_ => Ok(()),
}
}

fn valid_outcomes(draw_handicap: &DrawHandicap) -> [Outcome; 3] {
[
Outcome::Win(Side::Home, draw_handicap.to_win_handicap()),
Expand Down Expand Up @@ -126,4 +140,21 @@ mod tests {
offer.validate().unwrap_err().to_string()
);
}

#[test]
fn invalid_type() {
let offer = Offer {
offer_type: OfferType::HeadToHead(Period::FullTime, DrawHandicap::Behind(0)),
outcomes: HashLookup::from(vec![
Outcome::Win(Side::Home, WinHandicap::BehindUnder(0)),
Outcome::Win(Side::Away, WinHandicap::AheadOver(0)),
Outcome::Draw(DrawHandicap::Behind(0)),
]),
market: Market::frame(&Overround::fair(), vec![0.4, 0.4, 0.2], &PRICE_BOUNDS),
};
assert_eq!(
"HeadToHead(FullTime, Behind(0)) is not a valid offer type",
offer.validate().unwrap_err().to_string()
);
}
}
9 changes: 4 additions & 5 deletions brumby-soccer/src/domain/validation/split_handicap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(crate) fn validate_type(
} else {
Err(InvalidOfferType {
offer_type: offer_type.clone(),
}.into())
})
}
};

Expand Down Expand Up @@ -99,7 +99,6 @@ mod tests {

use super::*;

const OFFER_TYPE: OfferType = OfferType::SplitHandicap(Period::FullTime, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2));
const PRICE_BOUNDS: RangeInclusive<f64> = 1.0..=1001.0;

#[test]
Expand Down Expand Up @@ -157,7 +156,7 @@ mod tests {
#[test]
fn wrong_booksum() {
let offer = Offer {
offer_type: OFFER_TYPE,
offer_type: OfferType::SplitHandicap(Period::FullTime, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2)),
outcomes: HashLookup::from(vec![
Outcome::SplitWin(Side::Home, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2)), // -2.25
Outcome::SplitWin(Side::Away, DrawHandicap::Behind(2), WinHandicap::BehindUnder(3)), // +2.25
Expand All @@ -173,7 +172,7 @@ mod tests {
#[test]
fn missing_outcome() {
let offer = Offer {
offer_type: OFFER_TYPE,
offer_type: OfferType::SplitHandicap(Period::FullTime, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2)),
outcomes: HashLookup::from(vec![Outcome::SplitWin(Side::Home, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2))]),
market: Market::frame(&Overround::fair(), vec![1.0], &PRICE_BOUNDS),
};
Expand All @@ -186,7 +185,7 @@ mod tests {
#[test]
fn extraneous_outcome() {
let offer = Offer {
offer_type: OFFER_TYPE,
offer_type: OfferType::SplitHandicap(Period::FullTime, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2)),
outcomes: HashLookup::from(vec![
Outcome::SplitWin(Side::Home, DrawHandicap::Ahead(2), WinHandicap::AheadOver(2)), // -2.25
Outcome::SplitWin(Side::Away, DrawHandicap::Behind(2), WinHandicap::BehindUnder(3)), // +2.25
Expand Down
2 changes: 1 addition & 1 deletion brumby-soccer/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
extern crate core;
#![allow(clippy::too_many_arguments)]

pub mod data;
pub mod domain;
Expand Down
8 changes: 4 additions & 4 deletions brumby-soccer/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ impl Model {

fn get_offer(&self, offer_type: &OfferType) -> Result<&Offer, MissingOffer> {
self.offers
.get(&offer_type)
.get(offer_type)
.ok_or(MissingOffer::Type(offer_type.clone()))
}

Expand Down Expand Up @@ -591,7 +591,7 @@ impl Model {
}

#[inline(always)]
fn sort_selections_by_increasing_prob(selections: &mut Vec<DetailedSelection>) {
fn sort_selections_by_increasing_prob(selections: &mut [DetailedSelection]) {
selections.sort_by(|s1, s2| s1.single_prob.total_cmp(&s2.single_prob))
}

Expand Down Expand Up @@ -716,7 +716,7 @@ impl Model {
);
let pruned = exploration.pruned;
let query_start = Instant::now();
let scan_result = scan_prefix(&sorted_selections, &exploration);
let scan_result = scan_prefix(&sorted_selections, exploration);
query_elapsed += query_start.elapsed();

let mut fringes =
Expand Down Expand Up @@ -807,7 +807,7 @@ impl Model {

let query_start = Instant::now();
let fringe_scan_result =
scan_prefix(&fringe_sorted_selections, &fringe_exploration);
scan_prefix(&fringe_sorted_selections, fringe_exploration);
query_elapsed += query_start.elapsed();

let probability = fringe_scan_result.lowest_prob;
Expand Down

0 comments on commit 11a1319

Please sign in to comment.