//! Pure presentation maths. Anything that touches a `Ui` is covered by the //! manual screenshot pass; these are the calculations a pixel test cannot //! express. use std::f32::consts::TAU; use eframe::egui::{Pos2, Rect, pos2, vec2}; use zagan_bet::roulette::{BetTarget, Outside}; use zagan_bet_gui::roulette::{Felt, number_under, size_for, target_name}; use zagan_bet_gui::theme::{group_digits, money}; #[test] fn money_is_grouped_in_threes() { assert_eq!(group_digits(0), "0"); assert_eq!(group_digits(999), "999"); assert_eq!(group_digits(1000), "1 000"); assert_eq!(group_digits(1234567), "1 234 567"); assert_eq!(group_digits(-1500), "-1 500"); assert_eq!(money(1000), "1 000 Kr"); } #[test] fn the_wheel_pointer_reads_the_number_at_the_top() { let segment = TAU / 37.0; assert_eq!(number_under(0.0), 0); // Rotating by -i segments puts wheel entry i under the pointer. for number in [0u8, 32, 17, 26] { let index = zagan_bet::roulette::WHEEL .iter() .position(|candidate| *candidate == number) .expect("number is on the wheel"); let rotation = -(index as f32) * segment; assert_eq!(number_under(rotation), number); } // One full turn changes nothing. assert_eq!(number_under(-TAU), 0); } #[test] fn table_size_keeps_the_felt_aspect_and_fits() { let available = eframe::egui::vec2(1300.0, 900.0); let size = size_for(available); assert!(size.x <= available.x + 0.01, "{size:?} overflows"); assert!(size.y <= available.y + 0.01, "{size:?} overflows"); // 13 cells wide and 4.89 cells tall, plus the felt border on every side. let cell = (size.x - 12.0) / 13.0; assert!((cell - (size.y - 12.0) / 4.89).abs() < 0.01); } fn felt() -> Felt { Felt::new(Rect::from_min_size( Pos2::ZERO, size_for(vec2(1300.0, 900.0)), )) } #[test] fn the_pointer_snaps_to_straights_splits_and_corners() { let felt = felt(); let cell = felt.cell_size(); let center = felt.number_rect(17).center(); // The inner half of a cell is a straight, even slightly off centre. assert_eq!( felt.target_at(center + vec2(cell * 0.2, 0.0)), Some(BetTarget::Straight { number: 17 }) ); // A quarter cell from the centre is the line: right of 17 is 20, above is 18. assert_eq!( felt.target_at(center + vec2(cell * 0.3, 0.0)), Some(BetTarget::Split { a: 17, b: 20 }) ); assert_eq!( felt.target_at(center + vec2(0.0, -cell * 0.3)), Some(BetTarget::Split { a: 17, b: 18 }) ); // Near both lines at once is the corner of the four cells. assert_eq!( felt.target_at(center + vec2(cell * 0.3, -cell * 0.3)), Some(BetTarget::Corner { numbers: [17, 18, 20, 21] }) ); // Zero is a straight and nothing else. assert_eq!( felt.target_at(felt.number_rect(0).center()), Some(BetTarget::Straight { number: 0 }) ); } #[test] fn the_pointer_finds_the_wide_bets_below_the_grid() { let felt = felt(); let cell = felt.cell_size(); let x = felt.number_rect(17).center().x; let grid_bottom = felt.number_rect(16).bottom(); // 17 sits in the second dozen (13-24). assert_eq!( felt.target_at(pos2(x, grid_bottom + cell * 0.3)), Some(BetTarget::Dozen { index: 1 }) ); // Below the dozens is the column row; 17 is in column 2 (2,5,...,17). assert_eq!( felt.target_at(pos2(x, grid_bottom + cell * (0.72 + 0.3))), Some(BetTarget::Column { index: 1 }) ); // And below that, the outside row: 17's column lands on RED. assert_eq!( felt.target_at(pos2(x, grid_bottom + cell * (0.72 + 0.55 + 0.3))), Some(BetTarget::Outside { kind: Outside::Red }) ); // Outside the board is not a bet. assert_eq!(felt.target_at(pos2(-1.0, -1.0)), None); } #[test] fn targets_read_as_bet_slips() { assert_eq!( target_name(&BetTarget::Straight { number: 17 }), "Straight 17" ); assert_eq!( target_name(&BetTarget::Split { a: 26, b: 29 }), "Split 26/29" ); assert_eq!( target_name(&BetTarget::Corner { numbers: [17, 18, 20, 21] }), "Corner 17/18/20/21" ); assert_eq!(target_name(&BetTarget::Dozen { index: 1 }), "2nd 12"); assert_eq!(target_name(&BetTarget::Column { index: 2 }), "Column 3"); assert_eq!( target_name(&BetTarget::Outside { kind: Outside::High }), "19-36" ); assert_eq!( target_name(&BetTarget::Outside { kind: Outside::Black }), "Black" ); }