three-ore/src/board.rs
2023-12-17 05:33:50 -05:00

189 lines
5.8 KiB
Rust

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
}
}