generated from Tiphereth-A/TINplate
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
4659d7d
commit b1e33d7
Showing
11 changed files
with
196 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#ifndef TIFALIBS_GAME_NPUZZLE_DATA | ||
#define TIFALIBS_GAME_NPUZZLE_DATA | ||
|
||
#include "../util/abs_constexpr.hpp" | ||
#include "../util/util.hpp" | ||
|
||
namespace tifa_libs::game { | ||
|
||
// clang-format off | ||
enum Dir4 { U, D, L, R }; | ||
// clang-format on | ||
|
||
// n = k*k-1 | ||
class NPuzzleData { | ||
u32 k, pos0; | ||
vec<u32> node_; | ||
vec<Dir4> moves_; | ||
u32 cost_; | ||
|
||
public: | ||
constexpr explicit NPuzzleData(u32 k) : k(k) {} | ||
|
||
constexpr auto const &cost() const { return cost_; } | ||
constexpr auto &node() { return node_; } | ||
constexpr auto const &node() const { return node_; } | ||
constexpr auto const &moves() const { return moves_; } | ||
|
||
constexpr bool solved() { | ||
for (u32 i = 0; i < node_.size(); ++i) | ||
if (node_[i] != i) return 0; | ||
return 1; | ||
} | ||
constexpr vec<NPuzzleData> next() { | ||
auto moves = gen_move(); | ||
vec<NPuzzleData> ans(moves.size(), *this); | ||
for (u32 i = 0; i < moves.size(); ++i) ans[i].move(moves[i]); | ||
return ans; | ||
} | ||
constexpr void move(Dir4 dir) { | ||
moves_.push_back(dir); | ||
u32 _ = pos0; | ||
switch (dir) { | ||
case U: pos0 -= k; break; | ||
case D: pos0 += k; break; | ||
case L: --pos0; break; | ||
case R: ++pos0; break; | ||
} | ||
std::swap(node_[_], node_[pos0]); | ||
cost_ = gen_cost(); | ||
} | ||
|
||
constexpr auto operator<=>(NPuzzleData const &node) const { return node_ <=> node.node_; } | ||
|
||
friend std::istream &operator>>(std::istream &is, NPuzzleData &np) { | ||
np.node_.resize(np.k * np.k); | ||
for (auto &i : np.node_) is >> i; | ||
np.pos0 = u32(std::find(np.node_.begin(), np.node_.end(), 0) - np.node_.begin()); | ||
np.cost_ = np.gen_cost(); | ||
return is; | ||
} | ||
|
||
private: | ||
constexpr vec<Dir4> gen_move() const { | ||
vec<Dir4> ans; | ||
if (pos0 / k) ans.push_back(U); | ||
if (pos0 / k != k - 1) ans.push_back(D); | ||
if (pos0 % k) ans.push_back(L); | ||
if (pos0 % k != k - 1) ans.push_back(R); | ||
return ans; | ||
} | ||
constexpr u32 gen_cost() const { | ||
u32 h1 = 0, h2 = 0; | ||
for (u32 i = 0; i < k; ++i) | ||
for (u32 j = 0; j < k; ++j) | ||
if (u32 _ = node_[k * i + j]; _ != k * i + j && _) ++h1, h2 += u32(abs((i32)i - i32(_ / k)) + abs((i32)j - i32(_ % k))); | ||
return std::max(h1, h2) + (u32)moves_.size(); | ||
} | ||
}; | ||
|
||
} // namespace tifa_libs::game | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
#ifndef TIFALIBS_OPT_ASTAR | ||
#define TIFALIBS_OPT_ASTAR | ||
|
||
#include "../util/traits.hpp" | ||
|
||
namespace tifa_libs::opt { | ||
|
||
template <class T> | ||
requires requires(T x, T y) { | ||
{ x.solved() } -> std::same_as<bool>; | ||
{ x.next() } -> iterable_c; | ||
x.cost() < y.cost(); | ||
x < y; | ||
} | ||
std::optional<T> astar(T const &s) { | ||
struct C { | ||
constexpr bool operator()(T const &a, T const &b) const { return b.cost() < a.cost(); } | ||
}; | ||
pq<T, C> pq; | ||
std::set<T> vis; | ||
|
||
pq.push(s); | ||
vis.insert(s); | ||
while (!pq.empty()) { | ||
T now = pq.top(); | ||
pq.pop(); | ||
if (now.solved()) return now; | ||
auto nxt = now.next(); | ||
for (auto i : nxt) | ||
if (!vis.count(i)) { | ||
pq.push(i); | ||
vis.insert(i); | ||
} | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
} // namespace tifa_libs::opt | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
用于求解 \(N\)-puzzle \(N=k^2-1,~k\in\mathbf{N}_{>2}\) 的数据类. | ||
|
||
\(N\)-puzzle 是一个滑块游戏. 滑块方盘的长宽均为 \(k\times k\) 个方块, 其中 \(N\) 个位置放序号打乱的方块, 剩下一个为空位. 与空位同行或同列的方块可以通过水平或垂直滑动来移动. 拼图的目标是按编号顺序排列方块 | ||
|
||
求解时需使用 \fullref{sec:a*-算法} | ||
|
||
\inputminted{cpp}{src/src/npuzzle_data_usage.txt} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
\paragraph{要求} | ||
|
||
数据类 \verb|T| 需可比较且需具有如下成员函数: | ||
|
||
\verb|bool solved()|: 返回当前状态是否满足终止条件 | ||
|
||
\verb|U next()|: 返回当前状态的所有后继, 返回类型 \verb|U| 需可迭代 | ||
|
||
\verb|W cost()|: 返回当前状态的估价, 返回类型 \verb|W| 需可比较 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
int k = 4; // 15-puzzle | ||
|
||
NPuzzleData start(k); | ||
// 读入局面 | ||
std::cin >> start; | ||
// 输出当前局面 | ||
std::cout << start.node(); | ||
// 输出操作步骤 | ||
std::cout << astar(start)->moves(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
#define PROBLEM "https://onlinejudge.u-aizu.ac.jp/courses/lesson/1/ALDS1/all/ALDS1_13_C" | ||
|
||
#include "../../code/game/npuzzle_data.hpp" | ||
#include "../../code/opt/astar.hpp" | ||
|
||
int main() { | ||
std::ios::sync_with_stdio(false); | ||
std::cin.tie(nullptr); | ||
tifa_libs::game::NPuzzleData start(4); | ||
std::cin >> start; | ||
for (auto& i : start.node()) | ||
if (i) --i; | ||
else i = 15; | ||
std::cout << tifa_libs::opt::astar(start)->moves().size() << '\n'; | ||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
#define PROBLEM "https://www.hackerrank.com/challenges/n-puzzle/problem" | ||
|
||
#include "../../code/game/npuzzle_data.hpp" | ||
#include "../../code/opt/astar.hpp" | ||
|
||
int main() { | ||
std::ios::sync_with_stdio(false); | ||
std::cin.tie(nullptr); | ||
u32 n; | ||
std::cin >> n; | ||
tifa_libs::game::NPuzzleData start(n); | ||
std::cin >> start; | ||
auto v = tifa_libs::opt::astar(start)->moves(); | ||
std::cout << v.size() << '\n'; | ||
for (auto i : v) switch (i) { | ||
case tifa_libs::game::U: std::cout << "UP\n"; break; | ||
case tifa_libs::game::D: std::cout << "DOWN\n"; break; | ||
case tifa_libs::game::L: std::cout << "LEFT\n"; break; | ||
case tifa_libs::game::R: std::cout << "RIGHT\n"; break; | ||
} | ||
return 0; | ||
} |
Empty file.
Empty file.