Imrpove Puzzle 23-01 by modelling top row correctly.

Previously we modelled the top row as a connected series of nodes and allowed them to connect to each other directly.  This ignored the rule that you have to move directly to the place you want on the top row and then back out of it.

However, that was fine as the lowest cost would imply that.  But it does slow down and give more states to consider.

Instead, model the nodes on the top row as being directly connected to the nodes in the second row.  Add some rules about when you can move from one to the other and use those.

This reduces the number of states we have to consider in total.  And hopefully speeds up the process.
This commit is contained in:
2021-12-24 12:34:00 +00:00
parent cca3a22a43
commit a5fc32ed07

View File

@@ -14,27 +14,32 @@
// #l#m#n#o#
// #########
//
// a -1- b -2- c -2- d -2- e -2- f -1- g
// 0 -1- 1 -2- 2 -2- 3 -2- 4 -2- 5 -1- 6
// \ / \ / \ / \ /
// 2 2 2 2 2 2 2 2
// + + + +
// h i j k
// 7 8 9 10
// | | | |
// 1 1 1 1
// | | | |
// l m n o
// 11 12 13 14
// Actually : {0-6} can go to any of {7-10} at varying cost but there are move restritions.
using Position = char;
using UInt = int;
using Type = char;
std::multimap<Position, std::pair<Position, UInt>> valid_moves{
{0, {1, 1}}, {1, {0, 1}}, {1, {2, 2}}, {1, {7, 2}}, {2, {1, 2}}, {2, {3, 2}},
{2, {7, 2}}, {2, {8, 2}}, {3, {2, 2}}, {3, {4, 2}}, {3, {8, 2}}, {3, {9, 2}},
{4, {3, 2}}, {4, {5, 2}}, {4, {9, 2}}, {4, {10, 2}}, {5, {4, 2}}, {5, {6, 1}},
{5, {10, 2}}, {6, {5, 1}}, {7, {1, 2}}, {7, {2, 2}}, {7, {11, 1}}, {8, {2, 2}},
{8, {3, 2}}, {8, {12, 1}}, {9, {3, 2}}, {9, {4, 2}}, {9, {13, 1}}, {10, {4, 2}},
{10, {5, 2}}, {10, {14, 1}}, {11, {7, 1}}, {12, {8, 1}}, {13, {9, 1}}, {14, {10, 1}}};
{0, {7, 3}}, {0, {8, 5}}, {0, {9, 7}}, {0, {10, 9}}, {1, {7, 2}}, {1, {8, 4}}, {1, {9, 6}},
{1, {10, 8}}, {2, {7, 2}}, {2, {8, 2}}, {2, {9, 4}}, {2, {10, 6}}, {3, {7, 4}}, {3, {8, 2}},
{3, {9, 2}}, {3, {10, 4}}, {4, {7, 6}}, {4, {8, 4}}, {4, {9, 2}}, {4, {10, 2}}, {5, {7, 8}},
{5, {8, 6}}, {5, {9, 4}}, {5, {10, 2}}, {6, {7, 9}}, {6, {8, 7}}, {6, {9, 5}}, {6, {10, 3}},
{7, {0, 3}}, {7, {1, 2}}, {7, {2, 2}}, {7, {3, 4}}, {7, {4, 6}}, {7, {5, 8}}, {7, {6, 9}},
{7, {11, 1}}, {8, {0, 5}}, {8, {1, 4}}, {8, {2, 2}}, {8, {3, 2}}, {8, {4, 4}}, {8, {5, 6}},
{8, {6, 7}}, {8, {12, 1}}, {9, {0, 7}}, {9, {1, 6}}, {9, {2, 4}}, {9, {3, 2}}, {9, {4, 2}},
{9, {5, 4}}, {9, {6, 5}}, {9, {13, 1}}, {10, {0, 9}}, {10, {1, 8}}, {10, {2, 6}}, {10, {3, 4}},
{10, {4, 2}}, {10, {5, 2}}, {10, {6, 3}}, {10, {14, 1}}, {11, {7, 1}}, {12, {8, 1}}, {13, {9, 1}},
{14, {10, 1}}};
std::map<Type, UInt> multipliers{{'A', 1}, {'B', 10}, {'C', 100}, {'D', 1000}};
@@ -48,6 +53,18 @@ struct State
bool check_move(unsigned from, unsigned to)
{
if (from < 7) {
assert(to > 6 && to < 11);
}
else if (from > 6 & from < 11) {
assert(to < 7 || (to > 10 && to < 15));
}
else if (from > 10 && from < 15) {
assert(to > 6 && to < 11);
}
else {
assert(false);
}
if (nodes_[from] == '.' || nodes_[to] != '.') {
return false;
}
@@ -60,15 +77,69 @@ struct State
// Only move into bottom position if we're moving the correct piece.
return nodes_[from] == finished_[to];
}
// Moving to top row - anything allowed.
// Moving to top row
if (to == 0 && nodes_[1] != '.') {
return false;
}
if (to < 2 && from > 7 && nodes_[2] != '.') {
return false;
}
if (to < 3 && from > 8 && nodes_[3] != '.') {
return false;
}
if (to < 4 && from > 9 && nodes_[4] != '.') {
return false;
}
if (to == 6 && nodes_[5] != '.') {
return false;
}
if (to > 4 && from < 10 && nodes_[4] != '.') {
return false;
}
if (to > 3 && from < 9 && nodes_[3] != '.') {
return false;
}
if (to > 2 && from < 8 && nodes_[2] != '.') {
return false;
}
return true;
}
if (from < 7) {
if (to < 7) {
return true;
}
// Can only move down if we're the right type.
return nodes_[from] == finished_[to];
if (nodes_[from] != finished_[to]) {
return false;
}
// Now encode the rules about moving along the top.
if (from == 0 && nodes_[1] != '.') {
return false;
}
if (from < 2 && to > 7 && nodes_[2] != '.') {
return false;
}
if (from < 3 && to > 8 && nodes_[3] != '.') {
return false;
}
if (from < 4 && to > 9 && nodes_[4] != '.') {
return false;
}
if (from == 6 && nodes_[5] != '.') {
return false;
}
if (from > 4 && to < 10 && nodes_[4] != '.') {
return false;
}
if (from > 3 && to < 9 && nodes_[3] != '.') {
return false;
}
if (from > 2 && to < 8 && nodes_[2] != '.') {
return false;
}
return true;
}
abort();
}