use crate::logic::*; use rand::seq::SliceRandom; use rand::{Rng, SeedableRng}; use rand_xoshiro::SplitMix64; use xxhash_rust::xxh3::xxh3_64; impl Board { pub fn new(seed: &str) -> Board { let mut rng = SplitMix64::seed_from_u64(xxh3_64(seed.as_bytes())); let hexes = { let mut arr = [[None; 7]; 7]; for h in Board::hexes(&mut rng) { arr[h.position.0 as usize][h.position.1 as usize] = Some(h); } arr }; let (edges, vertices) = { let mut es = [[None; 15]; 15]; let mut vs = [[None; 15]; 15]; for hex in hexes.iter().flatten() { match hex { Some(Hex { hextype: HexType::Resource | HexType::Desert, position: p, .. }) => { let mut d = Position::new(1, 0); for _ in 0..6 { let e = p.edge(&d); if es[e.0 as usize][e.1 as usize].is_none() { es[e.0 as usize][e.1 as usize] = Some(Edge { position: e, road: None, }); } if vs[e.0 as usize][e.1 as usize].is_none() { vs[e.0 as usize][e.1 as usize] = Some(Vertex { position: e.vertex(&d), settlement: None, city: None, }); } d.rotate(); } } _ => (), } } (es, vs) }; let board = Board { hexes, edges, vertices, robber: hexes .iter() .flatten() .find(|h| h.is_some() && h.unwrap().hextype == HexType::Desert) .unwrap() .unwrap() .position, }; board } fn hexes<R: Rng>(mut rng: &mut R) -> Vec<Hex> { // get random direction let direction = { let mut d = Position::new(1, 0); for _ in 0..rng.gen_range(0..6) { d.rotate(); } d }; let ps = Board::spiral_order(&direction); let mut hexes = Vec::new(); // randomize port resources let mut port_resources = { let mut v = vec![ None, None, None, None, Some(Resource::Wood), Some(Resource::Brick), Some(Resource::Sheep), Some(Resource::Wheat), Some(Resource::Ore), ]; v.shuffle(&mut rng); v }; let mut orientation = direction; orientation.rotate().rotate(); for (i, p) in ps[0..18].iter().enumerate() { if i % 2 == 0 { //is a port if i % 3 != 1 { orientation.rotate(); } hexes.push(Hex { hextype: HexType::Port, resource: port_resources.pop().unwrap(), position: *p, number: None, orientation: Some(orientation), }); } else { hexes.push(Hex { hextype: HexType::Ocean, resource: None, position: *p, number: None, orientation: None, }); } } let mut numbers = { let mut v = vec![5, 2, 6, 3, 8, 10, 9, 12, 11, 4, 8, 10, 9, 4, 5, 6, 3, 11]; v.reverse(); v }; let mut hex_resources = { let mut h = Vec::new(); for _ in 0..4 { h.push(Resource::Wood); h.push(Resource::Sheep); h.push(Resource::Wheat); } for _ in 0..3 { h.push(Resource::Brick); h.push(Resource::Ore); } h.shuffle(&mut rng); h }; let desert_pos = rng.gen_range(0..18); for (i, p) in ps[18..].iter().enumerate() { if i == desert_pos { hexes.push(Hex { hextype: HexType::Desert, resource: None, position: *p, number: None, orientation: None, }); } else { hexes.push(Hex { hextype: HexType::Resource, resource: Some(hex_resources.pop().unwrap()), position: *p, number: Some(numbers.pop().unwrap()), orientation: None, }); }; } hexes } fn spiral_order(direction: &Position) -> Vec<Position> { let mut ps = Vec::new(); for r in (1..=3).rev() { ps.extend(&Board::ring(&direction, r)); } ps.push(Position::new(3, 3)); ps } fn ring(direction: &Position, radius: u32) -> Vec<Position> { let mut ps = Vec::new(); let mut current = Position::new(3, 3); for _ in 0..radius { current.add(direction); } let mut d = *direction; d.rotate().rotate(); for _ in 0..6 { for _ in 0..radius { ps.push(current); current.add(&d); } d.rotate(); } ps } }