1#![warn(missing_docs)]
36
37use std::{collections::hash_map::Entry, fmt::Debug, hash::Hash};
38
39use fxhash::FxHashMap;
40use nalgebra::{Vector2, Vector3};
41use rand::Rng;
42
43mod auto;
44mod wave;
45
46pub use auto::*;
47pub use wave::*;
48
49pub trait OffsetPosition:
52 Eq
53 + Hash
54 + Clone
55 + std::ops::Add<Self::Offset, Output = Self>
56 + std::ops::Add<Self::Diagonal, Output = Self>
57{
58 type Offset: std::ops::Neg<Output = Self::Offset> + Clone;
62 type Diagonal: std::ops::Neg<Output = Self::Diagonal> + Clone;
66 fn all_offsets() -> impl Iterator<Item = Self::Offset>;
69 fn all_diagonals() -> impl Iterator<Item = Self::Diagonal>;
72}
73
74impl OffsetPosition for Vector2<i32> {
75 type Offset = Vector2Offset;
76 type Diagonal = Vector2Diagonal;
77 fn all_offsets() -> impl Iterator<Item = Self::Offset> {
78 (0..4).map(Vector2Offset)
79 }
80 fn all_diagonals() -> impl Iterator<Item = Self::Diagonal> {
81 (0..4).map(Vector2Diagonal)
82 }
83}
84
85#[derive(Clone, Copy, PartialEq, Eq)]
87pub struct Vector2Diagonal(usize);
88
89impl Vector2Diagonal {
90 pub const LEFT_DOWN: Vector2Diagonal = Vector2Diagonal(0);
92 pub const RIGHT_DOWN: Vector2Diagonal = Vector2Diagonal(1);
94 pub const LEFT_UP: Vector2Diagonal = Vector2Diagonal(2);
96 pub const RIGHT_UP: Vector2Diagonal = Vector2Diagonal(3);
98 fn peering_bit(&self) -> usize {
102 DIAGONAL_PEERING_BITS[self.0]
103 }
104 pub fn dx(&self) -> i32 {
106 DIAG2[self.0].x
107 }
108 pub fn dy(&self) -> i32 {
110 DIAG2[self.0].y
111 }
112}
113
114impl Debug for Vector2Diagonal {
115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
116 f.debug_struct("Vector2Diagonal")
117 .field("dx", &self.dx())
118 .field("dy", &self.dy())
119 .finish()
120 }
121}
122
123impl std::ops::Add<Vector2Diagonal> for Vector2<i32> {
124 type Output = Vector2<i32>;
125
126 fn add(self, rhs: Vector2Diagonal) -> Self::Output {
127 self + DIAG2[rhs.0]
128 }
129}
130
131impl std::ops::Neg for Vector2Diagonal {
132 type Output = Self;
133
134 fn neg(self) -> Self::Output {
135 Vector2Diagonal(3 - self.0)
136 }
137}
138
139#[derive(Clone, Copy, PartialEq, Eq)]
142pub struct Vector2Offset(usize);
143
144const OFFSETS2: [Vector2<i32>; 4] = [
145 Vector2::new(-1, 0),
146 Vector2::new(0, -1),
147 Vector2::new(0, 1),
148 Vector2::new(1, 0),
149];
150
151const DIAG2: [Vector2<i32>; 4] = [
152 Vector2::new(-1, -1),
153 Vector2::new(1, -1),
154 Vector2::new(-1, 1),
155 Vector2::new(1, 1),
156];
157
158const fn bit_pos(x: usize, y: usize) -> usize {
159 x + y * 3
160}
161
162const OFFSET_PEERING_BITS: [[usize; 3]; 4] = [
163 [bit_pos(0, 0), bit_pos(0, 1), bit_pos(0, 2)],
164 [bit_pos(0, 0), bit_pos(1, 0), bit_pos(2, 0)],
165 [bit_pos(0, 2), bit_pos(1, 2), bit_pos(2, 2)],
166 [bit_pos(2, 0), bit_pos(2, 1), bit_pos(2, 2)],
167];
168
169const DIAGONAL_PEERING_BITS: [usize; 4] =
170 [bit_pos(0, 0), bit_pos(2, 0), bit_pos(0, 2), bit_pos(2, 2)];
171
172impl Vector2Offset {
173 pub const UP: Vector2Offset = Vector2Offset(2);
175 pub const DOWN: Vector2Offset = Vector2Offset(1);
177 pub const LEFT: Vector2Offset = Vector2Offset(0);
179 pub const RIGHT: Vector2Offset = Vector2Offset(3);
181 fn peering_bits(&self) -> impl Iterator<Item = usize> {
184 OFFSET_PEERING_BITS[self.0].iter().copied()
185 }
186 pub fn dx(&self) -> i32 {
188 OFFSETS2[self.0].x
189 }
190 pub fn dy(&self) -> i32 {
192 OFFSETS2[self.0].y
193 }
194}
195
196impl Debug for Vector2Offset {
197 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
198 f.debug_struct("Vector2Offset")
199 .field("dx", &self.dx())
200 .field("dy", &self.dy())
201 .finish()
202 }
203}
204
205impl From<Vector2Offset> for Vector2<i32> {
206 fn from(value: Vector2Offset) -> Self {
207 OFFSETS2[value.0]
208 }
209}
210
211impl std::ops::Add<Vector2Offset> for Vector2<i32> {
212 type Output = Vector2<i32>;
213
214 fn add(self, rhs: Vector2Offset) -> Self::Output {
215 self + OFFSETS2[rhs.0]
216 }
217}
218
219impl std::ops::Neg for Vector2Offset {
220 type Output = Self;
221
222 fn neg(self) -> Self::Output {
223 Vector2Offset(3 - self.0)
224 }
225}
226
227impl OffsetPosition for Vector3<i32> {
228 type Offset = Vector3Offset;
229 type Diagonal = Vector3Diagonal;
230 fn all_offsets() -> impl Iterator<Item = Self::Offset> {
231 (0..6).map(Vector3Offset)
232 }
233 fn all_diagonals() -> impl Iterator<Item = Self::Diagonal> {
234 (0..DIAG3.len()).map(|i| DIAG3[i]).map(Vector3Diagonal)
235 }
236}
237
238#[derive(Clone, Copy, PartialEq, Eq)]
240pub struct Vector3Diagonal(Vector3<i32>);
241
242const DIAG3: [Vector3<i32>; 20] = [
243 Vector3::new(-1, -1, -1),
244 Vector3::new(1, -1, -1),
245 Vector3::new(-1, 1, -1),
246 Vector3::new(1, 1, -1),
247 Vector3::new(-1, -1, 0),
248 Vector3::new(1, -1, 0),
249 Vector3::new(-1, 1, 0),
250 Vector3::new(1, 1, 0),
251 Vector3::new(-1, -1, 1),
252 Vector3::new(1, -1, 1),
253 Vector3::new(-1, 1, 1),
254 Vector3::new(1, 1, 1),
255 Vector3::new(-1, 0, -1),
256 Vector3::new(0, -1, -1),
257 Vector3::new(1, 0, -1),
258 Vector3::new(0, 1, -1),
259 Vector3::new(-1, 0, 1),
260 Vector3::new(0, -1, 1),
261 Vector3::new(1, 0, 1),
262 Vector3::new(0, 1, 1),
263];
264
265impl std::ops::Add<Vector3Diagonal> for Vector3<i32> {
266 type Output = Vector3<i32>;
267
268 fn add(self, rhs: Vector3Diagonal) -> Self::Output {
269 self + rhs.0
270 }
271}
272
273impl std::ops::Neg for Vector3Diagonal {
274 type Output = Self;
275
276 fn neg(self) -> Self::Output {
277 Vector3Diagonal(-self.0)
278 }
279}
280
281#[derive(Clone, Copy, PartialEq, Eq)]
284pub struct Vector3Offset(usize);
285
286impl Vector3Offset {
287 pub fn dx(&self) -> i32 {
289 OFFSETS3[self.0].x
290 }
291 pub fn dy(&self) -> i32 {
293 OFFSETS3[self.0].y
294 }
295 pub fn dz(&self) -> i32 {
297 OFFSETS3[self.0].z
298 }
299}
300
301const OFFSETS3: [Vector3<i32>; 6] = [
302 Vector3::new(-1, 0, 0),
303 Vector3::new(0, -1, 0),
304 Vector3::new(0, 0, -1),
305 Vector3::new(0, 0, 1),
306 Vector3::new(0, 1, 0),
307 Vector3::new(1, 0, 0),
308];
309
310impl From<Vector3Offset> for Vector3<i32> {
311 fn from(value: Vector3Offset) -> Self {
312 OFFSETS3[value.0]
313 }
314}
315
316impl std::ops::Add<Vector3Offset> for Vector3<i32> {
317 type Output = Vector3<i32>;
318
319 fn add(self, rhs: Vector3Offset) -> Self::Output {
320 self + OFFSETS3[rhs.0]
321 }
322}
323
324impl std::ops::Neg for Vector3Offset {
325 type Output = Self;
326
327 fn neg(self) -> Self::Output {
328 Vector3Offset(5 - self.0)
329 }
330}
331
332#[derive(Debug, Clone)]
336pub struct ProbabilitySet<V> {
337 total: f32,
338 content: Vec<(f32, V)>,
339}
340
341impl<V> Default for ProbabilitySet<V> {
342 fn default() -> Self {
343 Self {
344 total: 0.0,
345 content: Vec::default(),
346 }
347 }
348}
349
350impl<V> ProbabilitySet<V> {
351 pub fn iter(&self) -> impl Iterator<Item = (f32, &V)> {
353 self.content.iter().map(|(f, v)| (*f, v))
354 }
355 pub fn len(&self) -> usize {
357 self.content.len()
358 }
359 pub fn is_empty(&self) -> bool {
361 self.content.is_empty()
362 }
363 pub fn clear(&mut self) {
365 self.total = 0.0;
366 self.content.clear();
367 }
368 pub fn add(&mut self, frequency: f32, value: V) {
370 if frequency > 0.0 {
371 self.total += frequency;
372 self.content.push((frequency, value));
373 }
374 }
375
376 pub fn total_frequency(&self) -> f32 {
380 self.total
381 }
382
383 pub fn average_frequency(&self) -> f32 {
385 let size = self.content.len();
386 if size == 0 {
387 return 0.0;
388 }
389 self.total / (size as f32)
390 }
391
392 pub fn get_random<R: Rng + ?Sized>(&self, rng: &mut R) -> Option<&V> {
396 if self.total <= 0.0 {
397 return None;
398 }
399 let mut p = rng.gen_range(0.0..self.total);
400 for (f, v) in self.iter() {
401 if p < f {
402 return Some(v);
403 }
404 p -= f;
405 }
406 self.iter().next().map(|v| v.1)
407 }
408}
409
410pub trait TilePattern {
416 type Offset;
420 type Diagonal;
425 fn is_legal(&self, offset: &Self::Offset, to: &Self) -> bool;
428 fn is_legal_diagonal(&self, offset: &Self::Diagonal, to: &Self) -> bool;
431}
432
433#[derive(Default, Clone, Copy, PartialEq, Eq, Hash)]
449pub struct PatternBits(pub [i8; 9]);
450
451impl PatternBits {
452 pub fn center(&self) -> i8 {
457 self.0[bit_pos(1, 1)]
458 }
459 pub fn center_terrain_count(&self) -> usize {
462 let center = self.center();
463 self.0.iter().filter(|t| **t == center).count()
464 }
465 pub fn unique_terrain_count(&self) -> usize {
468 let mut count = 1;
469 'outer: for i in 1..9 {
470 let current = self.0[i];
471 for j in 0..i {
472 if self.0[j] == current {
473 continue 'outer;
474 }
475 }
476 count += 1;
477 }
478 count
479 }
480}
481
482impl Debug for PatternBits {
483 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
484 fn w(f: &mut std::fmt::Formatter<'_>, bs: &[i8]) -> std::fmt::Result {
485 write!(f, "{0},{1},{2}", bs[0], bs[1], bs[2])
486 }
487 let bs = &self.0;
488 f.write_str("[")?;
489 w(f, &bs[0..3])?;
490 f.write_str("|")?;
491 w(f, &bs[3..6])?;
492 f.write_str("|")?;
493 w(f, &bs[6..9])?;
494 f.write_str("]")
495 }
496}
497
498impl PartialOrd for PatternBits {
499 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
500 Some(self.cmp(other))
501 }
502}
503
504impl Ord for PatternBits {
505 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
506 self.center_terrain_count()
507 .cmp(&other.center_terrain_count())
508 .reverse()
509 .then_with(|| {
510 self.unique_terrain_count()
511 .cmp(&other.unique_terrain_count())
512 })
513 .then_with(|| self.0.cmp(&other.0))
514 }
515}
516
517#[inline]
519fn nine_position_to_index(position: Vector2<usize>) -> usize {
520 if position.y > 2 || position.x > 2 {
521 panic!("Illegal terrain bit position: {position:?}");
522 }
523 bit_pos(position.x, position.y)
524}
525
526impl std::ops::Index<Vector2<usize>> for PatternBits {
527 type Output = i8;
528
529 fn index(&self, index: Vector2<usize>) -> &Self::Output {
530 &self.0[nine_position_to_index(index)]
531 }
532}
533
534impl std::ops::IndexMut<Vector2<usize>> for PatternBits {
535 fn index_mut(&mut self, index: Vector2<usize>) -> &mut Self::Output {
536 &mut self.0[nine_position_to_index(index)]
537 }
538}
539
540impl TilePattern for PatternBits {
541 type Offset = Vector2Offset;
542 type Diagonal = Vector2Diagonal;
543 fn is_legal(&self, offset: &Vector2Offset, to: &Self) -> bool {
544 offset
545 .peering_bits()
546 .zip((-*offset).peering_bits())
547 .all(|(a, b)| self.0[a] == to.0[b])
548 }
549 fn is_legal_diagonal(&self, diagonal: &Vector2Diagonal, to: &Self) -> bool {
550 self.0[diagonal.peering_bit()] == to.0[(-*diagonal).peering_bit()]
551 }
552}
553
554#[cfg(test)]
555mod tests {
556 use std::cmp::Ordering;
557
558 use rand::SeedableRng;
559
560 use PatternBits as Bits;
561
562 use super::*;
563
564 fn make_rng(seed: u64) -> rand::rngs::StdRng {
565 rand::rngs::StdRng::seed_from_u64(seed)
566 }
567
568 #[test]
569 fn probability_set_0() {
570 let set = ProbabilitySet::<u32>::default();
571 assert_eq!(set.get_random(&mut make_rng(0)), None);
572 }
573 #[test]
574 fn probability_set_1() {
575 let mut set = ProbabilitySet::<u32>::default();
576 set.add(0.65, 27);
577 let mut rng = make_rng(0);
578 assert_eq!(set.get_random(&mut rng), Some(&27));
579 assert_eq!(set.get_random(&mut rng), Some(&27));
580 assert_eq!(set.get_random(&mut rng), Some(&27));
581 }
582 #[test]
583 fn probability_set_2() {
584 let mut set = ProbabilitySet::<u32>::default();
585 set.add(0.5, 1);
586 set.add(1.0, 2);
587 let mut rng = make_rng(0);
588 let mut results = FxHashMap::<Option<u32>, usize>::default();
589 for _ in 0..75 {
590 *results
591 .entry(set.get_random(&mut rng).cloned())
592 .or_default() += 1;
593 }
594 let result_1 = results.get(&Some(1)).copied().unwrap_or_default();
595 let result_2 = results.get(&Some(2)).copied().unwrap_or_default();
596 assert_eq!(results.get(&None).copied().unwrap_or_default(), 0, "None");
597 assert!((21..27).contains(&result_1), "1: {result_1}");
598 assert!((45..55).contains(&result_2), "2: {result_2}");
599 assert_eq!(results.values().sum::<usize>(), 75, "Sum");
600 }
601 #[test]
602 fn probability_set_3() {
603 let mut set = ProbabilitySet::<u32>::default();
604 set.add(2.0, 1);
605 set.add(2.0, 2);
606 set.add(2.0, 3);
607 let mut rng = make_rng(0);
608 let mut results = FxHashMap::<Option<u32>, usize>::default();
609 for _ in 0..750 {
610 *results
611 .entry(set.get_random(&mut rng).cloned())
612 .or_default() += 1;
613 }
614 let result_1 = results.get(&Some(1)).copied().unwrap_or_default();
615 let result_2 = results.get(&Some(2)).copied().unwrap_or_default();
616 let result_3 = results.get(&Some(2)).copied().unwrap_or_default();
617 assert_eq!(results.get(&None).copied().unwrap_or_default(), 0, "None");
618 assert!((210..270).contains(&result_1), "1: {result_1}");
619 assert!((210..270).contains(&result_2), "2: {result_2}");
620 assert!((210..270).contains(&result_3), "3: {result_3}");
621 assert_eq!(results.values().sum::<usize>(), 750, "Sum");
622 }
623 #[test]
624 fn terrain_ord_1() {
625 let a = Bits([0, 0, 0, 0, 0, 0, 0, 0, 0]);
626 let b = Bits([1, 0, 0, 0, 0, 0, 0, 0, 0]);
627 assert_eq!(a.cmp(&b), Ordering::Less);
628 }
629 #[test]
630 fn terrain_ord_2() {
631 let a = Bits([0, 1, 0, 0, 0, 0, 0, 0, 0]);
632 let b = Bits([0, 1, 0, 0, 0, 0, 0, 0, 0]);
633 assert_eq!(a.cmp(&b), Ordering::Equal);
634 }
635 #[test]
636 fn terrain_ord_3() {
637 let a = Bits([0, 1, 0, 0, 0, 0, 0, 0, 0]);
638 let b = Bits([1, 0, 1, 1, 0, 0, 0, 0, 0]);
639 assert_eq!(a.cmp(&b), Ordering::Less);
640 }
641 #[test]
642 fn terrain_ord_4() {
643 let a = Bits([0, 1, 0, 1, 0, 1, 2, 0, 0]);
644 let b = Bits([1, 0, 1, 1, 0, 0, 0, 0, 0]);
645 assert_eq!(a.cmp(&b), Ordering::Greater);
646 }
647 #[test]
648 fn terrain_ord_ne() {
649 let a = Bits([0, 1, 0, 1, 0, 1, 0, 0, 0]);
650 let b = Bits([1, 0, 1, 1, 0, 0, 0, 0, 0]);
651 assert_ne!(a.cmp(&b), Ordering::Equal);
652 }
653 #[test]
654 fn tile_pattern_up() {
655 let a = Bits([-1, -2, -3, -4, -5, -6, 1, 2, 3]);
656 let b = Bits([1, 2, 3, 4, 5, 6, 7, 8, 9]);
657 let offset = Vector2Offset::DOWN;
658 assert!(b.is_legal(&offset, &a), "{b:?} {offset:?} {a:?}");
659 }
660 #[test]
661 fn tile_pattern_down() {
662 let a = Bits([-1, -2, -3, -4, -5, -6, 1, 2, 3]);
663 let b = Bits([1, 2, 3, 4, 5, 6, 7, 8, 9]);
664 let offset = Vector2Offset::UP;
665 assert!(a.is_legal(&offset, &b), "{b:?} {offset:?} {a:?}");
666 }
667 #[test]
668 fn tile_pattern_right() {
669 let a = Bits([1, 2, 1, 4, 5, 2, 7, 8, 3]);
670 let b = Bits([1, -2, -3, 2, -5, -6, 3, -2, -3]);
671 let offset = Vector2Offset::RIGHT;
672 assert!(a.is_legal(&offset, &b), "{a:?} {offset:?} {b:?}");
673 }
674 #[test]
675 fn tile_pattern_right2() {
676 let a = Bits([3, 3, 0, 3, 3, 0, 3, 3, 0]);
677 let b = Bits([0, 0, 0, 0, 0, 0, 0, 0, 0]);
678 let offset = Vector2Offset::RIGHT;
679 assert!(a.is_legal(&offset, &b), "{a:?} {offset:?} {b:?}");
680 }
681 #[test]
682 fn tile_pattern_left() {
683 let a = Bits([1, 2, 3, 2, 3, 4, 3, 8, 5]);
684 let b = Bits([-1, -2, 1, -2, -5, 2, -3, -2, 3]);
685 let offset = Vector2Offset::LEFT;
686 assert!(a.is_legal(&offset, &b), "{a:?} {offset:?} {b:?}");
687 }
688 #[test]
689 fn tile_pattern_left2() {
690 let a = Bits([0, 3, 3, 0, 3, 3, 0, 3, 3]);
691 let b = Bits([0, 0, 0, 0, 0, 0, 0, 0, 0]);
692 let offset = Vector2Offset::LEFT;
693 assert!(a.is_legal(&offset, &b), "{a:?} {offset:?} {b:?}");
694 }
695 #[test]
696 fn tile_pattern_left_up() {
697 let a = Bits([1, 2, 1, 2, 1, 4, 3, 8, 5]);
698 let b = Bits([-1, -2, 3, -2, -5, -2, -3, -2, -1]);
699 let offset = Vector2Diagonal::LEFT_UP;
700 assert!(a.is_legal_diagonal(&offset, &b), "{a:?} {offset:?} {b:?}");
701 }
702 #[test]
703 fn tile_pattern_right_up() {
704 let a = Bits([1, 2, 1, 2, 1, 4, 1, 8, 3]);
705 let b = Bits([3, -2, -1, -2, -5, -2, -3, -2, -1]);
706 let offset = Vector2Diagonal::RIGHT_UP;
707 assert!(a.is_legal_diagonal(&offset, &b), "{a:?} {offset:?} {b:?}");
708 }
709 #[test]
710 fn tile_pattern_left_down() {
711 let a = Bits([3, 2, 1, 2, 1, 4, 1, 8, 5]);
712 let b = Bits([-1, -2, -3, -2, -5, -2, -3, -2, 3]);
713 let offset = Vector2Diagonal::LEFT_DOWN;
714 assert!(a.is_legal_diagonal(&offset, &b), "{a:?} {offset:?} {b:?}");
715 }
716 #[test]
717 fn tile_pattern_right_down() {
718 let a = Bits([1, 2, 3, 2, 1, 4, 1, 8, 1]);
719 let b = Bits([-3, -2, -1, -2, -5, -2, 3, -2, -1]);
720 let offset = Vector2Diagonal::RIGHT_DOWN;
721 assert!(a.is_legal_diagonal(&offset, &b), "{a:?} {offset:?} {b:?}");
722 }
723}