|
@@ -38,6 +38,14 @@ impl Coord {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ pub fn rotate60(&self) -> Coord {
|
|
|
+ Coord {
|
|
|
+ a: 1 - self.c,
|
|
|
+ b: 1 - self.a,
|
|
|
+ c: 1 - self.b
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
/**
|
|
|
* Flip coordinate at the y-axis
|
|
@@ -58,7 +66,7 @@ impl Coord {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn to_cartesian(&self) -> (i8, i8) {
|
|
|
+ pub fn to_cartesian(&self) -> (i8, i8) {
|
|
|
(self.a - self.c + 1, 1 - self.b)
|
|
|
//let y : i8 = 1 - self.b;
|
|
|
//let x_offset : i8 = (self.b - 1).abs() / 2;
|
|
@@ -69,13 +77,36 @@ impl Coord {
|
|
|
//return (x, y);
|
|
|
}
|
|
|
|
|
|
- fn translate_x(&self, x: i8) -> Coord {
|
|
|
+ pub fn translate_x(&self, x: i8) -> Coord {
|
|
|
Coord::from_ab(self.a + x, self.b, self.upright())
|
|
|
}
|
|
|
|
|
|
- fn translate_y(&self, y: i8) -> Coord {
|
|
|
- Coord::from_ab(self.a + y, self.b - 2 * y, self.upright())
|
|
|
+ pub fn translate_y(&self, y: i8, origin_upright: bool) -> Coord {
|
|
|
+ //let m = Coord::from_ab(self.a + y, self.b - 2 * y, self.upright());
|
|
|
+ //let k = Coord::from(self.a + y, self.b - 2 * y, self.c + y);
|
|
|
+
|
|
|
+ //assert_eq!(m,k);
|
|
|
+ //k
|
|
|
+ if origin_upright {
|
|
|
+ Coord::from_ab(self.a + (y + 1) / 2, self.b - y, self.upright())
|
|
|
+ } else {
|
|
|
+ Coord::from_ab(self.a + y / 2, self.b - y, self.upright())
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ //pub fn translate_hy(&self, y: i8) -> Coord {
|
|
|
+ // let t = self.translate_y(y / 2);
|
|
|
+ // if y % 2 == 0 {
|
|
|
+ // t
|
|
|
+ // } else {
|
|
|
+ // Coord {
|
|
|
+ // a: self.a,
|
|
|
+ // b: self.b - 1,
|
|
|
+ // c: self.c + 1,
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ //}
|
|
|
}
|
|
|
impl std::ops::Add<Coord> for Coord {
|
|
|
type Output = Coord;
|
|
@@ -189,8 +220,17 @@ where F: FnMut(i8, i8) -> bool
|
|
|
let mut coord : Coord = if flipped { coordinate.flip() } else { coordinate.clone() };
|
|
|
coord = coord.rotate(rotations);
|
|
|
|
|
|
- let world_pos = coord.translate_x(x / 2).translate_y(y / 2);
|
|
|
- let (wx, wy) = world_pos.to_cartesian();
|
|
|
+
|
|
|
+ let origin_upright = (x + y) % 2 == 0;
|
|
|
+ //println!("origin_upright: {}", origin_upright);
|
|
|
+ if !origin_upright {
|
|
|
+ coord = coord.rotate60();
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ coord = coord.translate_y(y, origin_upright).translate_x(x / 2);
|
|
|
+
|
|
|
+ let (wx, wy) = coord.to_cartesian();
|
|
|
|
|
|
if in_bound(wx, wy) == false {
|
|
|
return false;
|
|
@@ -222,7 +262,7 @@ pub fn check_part(map: &Map, part: &Part, x: i8, y: i8, rotations: u8, flipped:
|
|
|
//println!("Testing {},{},{},{}", x, y, rotation.to_int(), flipped);
|
|
|
let success = for_each_triangle(part, x, y, rotations, flipped, |x, y| {
|
|
|
if !in_bound(x,y) {
|
|
|
- return false;
|
|
|
+ return true; // TODO: switch this to false as opt
|
|
|
}
|
|
|
|
|
|
let prev = map[y as usize][x as usize];
|
|
@@ -248,16 +288,16 @@ pub fn place_part(map: &mut Map, id: PartID, part: &Part, x: i8, y: i8, rotation
|
|
|
//println!("Placing {},{},{},{}", x, y, rotation.to_int(), flipped);
|
|
|
for_each_triangle(part, x, y, rotations, flipped, |x, y| {
|
|
|
if !in_bound(x,y) {
|
|
|
- panic!();
|
|
|
+ return true
|
|
|
}
|
|
|
//println!("placing {},{}", x, y);
|
|
|
|
|
|
- let prev = map[y as usize][x as usize];
|
|
|
- if let Cell::Occupied(i) = prev {
|
|
|
- assert_eq!(id, i);
|
|
|
- } else {
|
|
|
- assert!(prev.is_empty());
|
|
|
- }
|
|
|
+ //let prev = map[y as usize][x as usize];
|
|
|
+ //if let Cell::Occupied(i) = prev {
|
|
|
+ // assert_eq!(id, i);
|
|
|
+ //} else {
|
|
|
+ // assert!(prev.is_empty());
|
|
|
+ //}
|
|
|
|
|
|
map[y as usize][x as usize] = Cell::Occupied(id);
|
|
|
|
|
@@ -267,44 +307,51 @@ pub fn place_part(map: &mut Map, id: PartID, part: &Part, x: i8, y: i8, rotation
|
|
|
|
|
|
///* If a part is not placed right, we might need to remove it from the map again
|
|
|
// */
|
|
|
-//fn erase_part(map: &mut Map, part: &Part, x: u8, y: u8, rotation: Edge, flipped: bool) {
|
|
|
-// for_each_triangle(part, x, y, rotation, flipped, |x, y| {
|
|
|
-// assert!(in_bound(x, y));
|
|
|
-//
|
|
|
-// map[y as usize][x as usize] = Cell::Empty;
|
|
|
-// true
|
|
|
-// });
|
|
|
-//}
|
|
|
-//
|
|
|
-pub fn solve(map: Map, parts: &[(PartID, &Part)]) -> Option<()>{
|
|
|
+fn erase_part(map: &mut Map, part: &Part, x: i8, y: i8, rotation: u8, flipped: bool) {
|
|
|
+ for_each_triangle(part, x, y, rotation, flipped, |x, y| {
|
|
|
+ assert!(in_bound(x, y));
|
|
|
+
|
|
|
+ map[y as usize][x as usize] = Cell::Empty;
|
|
|
+ true
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+pub fn solve(map: &mut Map, parts: &[(PartID, &Part)]) -> Option<()>{
|
|
|
if parts.len() == 0 {
|
|
|
return Some(());
|
|
|
}
|
|
|
|
|
|
let (id, part) = parts[0];
|
|
|
- println!("{} parts remaining", parts.len());
|
|
|
+ //println!("{} parts remaining", parts.len());
|
|
|
|
|
|
// TODO: restrict to list of non-barrier position to tighten the for loops
|
|
|
- for x in 0..MAP_WIDTH {
|
|
|
- for y in 0..MAP_HEIGHT {
|
|
|
+ for y in 0..MAP_HEIGHT {
|
|
|
+ for x in 0..MAP_WIDTH {
|
|
|
if !map[y as usize][x as usize].is_empty() {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
for rotation in [0, 1, 2] {
|
|
|
- for flipped in [true, false] {
|
|
|
+ for flipped in [false, true] {
|
|
|
//println!("Testing rotation {} and flipped={}", rotation, flipped);
|
|
|
+ //println!("x={},y={},r={},f={}", x, y,rotation,flipped);
|
|
|
let valid_position = check_part(&map, &part, x, y, rotation, flipped);
|
|
|
|
|
|
if valid_position {
|
|
|
// Place our part and try the others
|
|
|
- let mut map_copy = map.clone();
|
|
|
- place_part(&mut map_copy, id, &part, x, y, rotation, flipped);
|
|
|
- print_map(&map_copy);
|
|
|
- println!("\n");
|
|
|
- if let Some(()) = solve(map_copy, &parts[1..]) {
|
|
|
+ //println!("Placing");
|
|
|
+ place_part(map, id, &part, x, y, rotation, flipped);
|
|
|
+ //print_map(&map);
|
|
|
+
|
|
|
+ //println!("Erasing");
|
|
|
+ //erase_part(map, &part, x, y, rotation, flipped);
|
|
|
+
|
|
|
+ //println!("\n\n");
|
|
|
+ if let Some(()) = solve(map, &parts[1..]) {
|
|
|
// We have found a valid solution we can pass back!
|
|
|
return Some(());
|
|
|
+ } else {
|
|
|
+ erase_part(map, &part, x, y, rotation, flipped);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -407,107 +454,6 @@ mod test {
|
|
|
assert_eq!(Coord::from(-1,0,3), Coord::from(2,0,0).translate_x(-3));
|
|
|
assert_eq!(Coord::from(1,-1,2), Coord::from(-1,3,0).translate_y(2));
|
|
|
assert_eq!(Coord::from(2,1,-1), Coord::from(3,-1,0).translate_y(-1));
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_part1() {
|
|
|
- let part = &generate_parts()[&1];
|
|
|
- for p in part {
|
|
|
- let (x,y) = p.to_cartesian();
|
|
|
- println!("Part1: {} {}", x, y);
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
- /*
|
|
|
- #[test]
|
|
|
- fn test_part_placement() {
|
|
|
- let B = Cell::Barrier;
|
|
|
- let E = Cell::Empty;
|
|
|
-
|
|
|
- let map : Map = [
|
|
|
- [B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B],
|
|
|
- [B, B, E, E, B, B, B, B, B, B, B, B, B, B, B, B],
|
|
|
- [B, B, E, E, E, B, B, B, B, B, B, B, B, B, B, B],
|
|
|
- [B, B, E, B, B, B, B, B, B, B, B, B, B, B, B, B],
|
|
|
- [B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B],
|
|
|
- ];
|
|
|
-
|
|
|
- let parts = generate_parts();
|
|
|
- let brown_part = parts.get(&1).unwrap();
|
|
|
-
|
|
|
-
|
|
|
- assert!(check_part(&map, &brown_part, 4, 2, Edge::BOTTOMTOP, false));
|
|
|
- let mut called : usize = 0;
|
|
|
- for x in 0..MAP_WIDTH {
|
|
|
- for y in 0..MAP_HEIGHT {
|
|
|
- for rotation in [Edge::LEFT, Edge::RIGHT, Edge::BOTTOMTOP] {
|
|
|
- if check_part(&map, &brown_part, x, y, rotation, false) {
|
|
|
- assert_eq!(Edge::BOTTOMTOP, rotation);
|
|
|
- assert_eq!((4, 2), (x, y));
|
|
|
- called += 1;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- assert_eq!(1, called);
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn test_erasing() {
|
|
|
- let E = Cell::Empty;
|
|
|
- let map : Map = [
|
|
|
- [E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E],
|
|
|
- [E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E],
|
|
|
- [E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E],
|
|
|
- [E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E],
|
|
|
- [E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E],
|
|
|
- ];
|
|
|
- let parts = generate_parts();
|
|
|
- let mut cmap = map.clone();
|
|
|
-
|
|
|
- place_part(&mut cmap, 1, &parts[&1], 4, 4, Edge::BOTTOMTOP, true);
|
|
|
- assert_ne!(map, cmap);
|
|
|
- erase_part(&mut cmap, &parts[&1], 4, 4, Edge::BOTTOMTOP, true);
|
|
|
-
|
|
|
- assert_eq!(map, cmap);
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- #[test]
|
|
|
- fn halting_problem() {
|
|
|
- let B = Cell::Barrier;
|
|
|
- let E = Cell::Empty;
|
|
|
-
|
|
|
- let mut map : Map = [
|
|
|
- [B, B, E, E, E, B, E, E, E, B, B, B, B, B, B, B],
|
|
|
- [B, E, E, E, E, B, B, E, E, E, B, B, B, B, B, B],
|
|
|
- [E, E, E, E, E, B, E, E, E, E, E, E, B, B, B, B],
|
|
|
- [E, E, E, B, E, B, E, E, E, E, E, B, B, B, B, B],
|
|
|
- [B, B, B, B, B, B, B, B, B, E, B, B, B, B, B, B],
|
|
|
- ];
|
|
|
-
|
|
|
- let parts = generate_parts();
|
|
|
-
|
|
|
- let available_parts : Vec<(PartID, &Part)> = [2,3,4,5,6,7].iter()
|
|
|
- .map(|x| (*x, &parts[&x]))
|
|
|
- .collect();
|
|
|
-
|
|
|
- let result = solve(&mut map, &available_parts);
|
|
|
-
|
|
|
- assert!(result.is_some());
|
|
|
-
|
|
|
- for y in 0..MAP_HEIGHT {
|
|
|
- for x in 0..MAP_WIDTH {
|
|
|
- print!("{}", map[y as usize][x as usize]);
|
|
|
- }
|
|
|
- println!("");
|
|
|
- }
|
|
|
- assert!(false);
|
|
|
-
|
|
|
|
|
|
}
|
|
|
-*/
|
|
|
}
|