作业
7-1 求迷宫最短通道
java1
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; class Node{ public int x; public int y; public int step; public Node(int x,int y,int step){ this.x=x; this.y=y; this.step=step; } } public class Main { private static int[][] stepArr = new int[][] { {-1,0},{1,0},{0,-1},{0,1} }; public static int bfs(int[][] map,int[][] visit,int n) { Node node = new Node(1, 1, 0); Queue<Node> q = new LinkedList<>(); q.add(node); while (q.size() != 0) { node = q.remove(); if (node.x == n - 2 && node.y == n - 2) { return node.step; } visit[node.x][node.y] = 1; for (int i = 0; i < 4; i++) { int x = node.x + stepArr[i][0]; int y = node.y + stepArr[i][1]; if (x >= 0 && y >= 0 && x < n&&y < n&&visit[x][y] == 0 && map[x][y] == 0) { visit[x][y] = 1; Node next = new Node(x, y, node.step + 1); q.add(next); } } } return -1; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[][] map = new int[n][n]; int[][] visit = new int[n][n]; for (int i = 0;i<n;++i){ for (int j = 0;j<n;++j){ map[i][j]=scanner.nextInt(); visit[i][j]=0; } } int r = bfs(map,visit,n); System.out.println(r==-1?"No solution":r); } }
java2
import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; class Node{ public int x; public int y; public int step; public Node(int x,int y,int step){ this.x=x; this.y=y; this.step=step; } } public class Main { private static int[][] stepArr = new int[][] { {-1,0},{1,0},{0,-1},{0,1} }; private static int bfs(int[][] map, int n) { Node node = new Node(1, 1, 0); Queue<Node> q = new LinkedList<>(); q.add(node); while (q.size() != 0) { node = q.remove(); if (node.x == n - 2 && node.y == n - 2) { return node.step; } map[node.x][node.y] = 2; for (int i = 0; i < 4; i++) { int x = node.x + stepArr[i][0]; int y = node.y + stepArr[i][1]; if (x >= 0 && y >= 0 && x < n&&y < n&& map[x][y] == 0) { map[x][y] = 2; Node next = new Node(x, y, node.step + 1); q.add(next); } } } return -1; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[][] map = new int[n][n]; for (int i = 0;i<n;++i){ for (int j = 0;j<n;++j){ map[i][j]=scanner.nextInt(); } } int r = bfs(map,n); System.out.println(r==-1?"No solution":r); } }
java3
import java.util.List; import java.util.ArrayList; import java.util.Collections; import java.util.Scanner; class Node implements Comparable { public Node parent; public int x, y; public double g; public double h; Node(Node parent, int xpos, int ypos, double g, double h) { this.parent = parent; this.x = xpos; this.y = ypos; this.g = g; this.h = h; } @Override public int compareTo(Object o) { Node that = (Node) o; return (int)((this.g + this.h) - (that.g + that.h)); } } class Astar { private final List<Node> open; private final List<Node> closed; private final List<Node> path; private final int[][] maze; private Node now; private final int xstart; private final int ystart; private int xend, yend; private final boolean diag; Astar(int[][] maze, int xstart, int ystart, boolean diag) { this.open = new ArrayList<>(); this.closed = new ArrayList<>(); this.path = new ArrayList<>(); this.maze = maze; this.now = new Node(null, xstart, ystart, 0, 0); this.xstart = xstart; this.ystart = ystart; this.diag = diag; } public List<Node> findPathTo(int xend, int yend) { this.xend = xend; this.yend = yend; this.closed.add(this.now); addNeigborsToOpenList(); while (this.now.x != this.xend || this.now.y != this.yend) { if (this.open.isEmpty()) return null; this.now = this.open.get(0); this.open.remove(0); this.closed.add(this.now); addNeigborsToOpenList(); } this.path.add(0, this.now); while (this.now.x != this.xstart || this.now.y != this.ystart) { this.now = this.now.parent; this.path.add(0, this.now); } return this.path; } private static boolean findNeighborInList(List<Node> array, Node node) { return array.stream().anyMatch((n) -> (n.x == node.x && n.y == node.y)); } private double distance(int dx, int dy) { if (this.diag) { return Math.hypot(this.now.x + dx - this.xend, this.now.y + dy - this.yend); } else { return Math.abs(this.now.x + dx - this.xend) + Math.abs(this.now.y + dy - this.yend); } } private void addNeigborsToOpenList() { Node node; for (int x = -1; x <= 1; x++) { for (int y = -1; y <= 1; y++) { if (!this.diag && x != 0 && y != 0) { continue; } node = new Node(this.now, this.now.x + x, this.now.y + y, this.now.g, this.distance(x, y)); if ((x == 1 && y == 0 || x == 0 && y == 1 || x == -1 && y == 0 || x == 0 && y == -1) && this.now.x + x >= 0 && this.now.x + x < this.maze[0].length && this.now.y + y >= 0 && this.now.y + y < this.maze.length && this.maze[this.now.y + y][this.now.x + x] != -1 && !findNeighborInList(this.open, node) && !findNeighborInList(this.closed, node)) { node.g = node.parent.g + 1.; node.g += maze[this.now.y + y][this.now.x + x]; this.open.add(node); } } } Collections.sort(this.open); } } public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int N = scanner.nextInt(); int[][] maze = new int[N][N]; for (int x = 0; x < N; ++x) { for (int y = 0; y < N; ++y) { maze[x][y] = scanner.nextInt() * 100; } } Astar as = new Astar(maze, 1, 1, true); List<Node> path = as.findPathTo(N-2, N-2); if (path == null || path.get(path.size() - 1).g >= 100){ System.out.println("No solution"); } else { System.out.printf("%.0f\n", path.get(path.size() - 1).g); } } }
数独
Launcher/main.cpp
// ReSharper disable CommentTypo #include <cstdio> #include <vector> #include <string> using Row = array<int>; using Map = array<Row^>; using Maps = array<Map^>; // ReSharper disable once CppInconsistentNaming using Row_ = std::vector<int>; // ReSharper disable once CppInconsistentNaming using Map_ = std::vector<Row_>; // ReSharper disable once CppInconsistentNaming using Maps_ = std::vector<Map_>; // ReSharper disable once CppDeclaratorNeverUsed static Maps^ ToMaps(const Maps_& maps) { auto res = gcnew Maps(static_cast<int>(maps.size())); for (auto i = 0; i < maps.size(); ++i) { res[i] = gcnew Map(static_cast<int>(maps[i].size())); for (auto j = 0; j < maps[i].size(); ++j) { res[i][j] = gcnew Row(static_cast<int>(maps[i][j].size())); for (auto k = 0; k < maps[i][j].size(); ++k) { res[i][j][k] = maps[i][j][k]; } } } return res; } int main(const int argc, char* argv[]) { //#define Debug #ifndef Debug try { if (argc != 9) { throw gcnew System::Exception("parameter error"); } auto parameter = gcnew System::Collections::Generic::Dictionary<System::String^, System::String^>(); for (auto i = 1; i < argc; i += 2) { parameter->Add(gcnew System::String(argv[i]), gcnew System::String(argv[i + 1])); } Sudoku sudoku(System::Int32::Parse(parameter["-m"]), System::Int32::Parse(parameter["-n"])); sudoku.InitializeWithFilePath(parameter["-i"]); System::IO::File::WriteAllText(parameter["-o"], Sudoku::ToString(sudoku.Solve())); } catch (System::Exception^ exception) { fprintf(stderr, "Usage:\n %s -m 宫格阶级 -n 待解答盘面数目 -i 指定输入文件 -o 指定程序的输出文件\n", argv[0]); System::Console::Error->WriteLine(exception->ToString()); return EXIT_FAILURE; } #else Sudoku sudoku(9, 1); //sudoku.InitializeWithArray(ToMaps( //{ // { // {0,0,0, 0,0,0, 0,0,0}, // {0,0,0, 0,0,3, 0,8,5}, // {0,0,1, 0,2,0, 0,0,0}, // // {0,0,0, 5,0,7, 0,0,0}, // {0,0,4, 0,0,0, 1,0,0}, // {0,9,0, 0,0,0, 0,0,0}, // // {5,0,0, 0,0,0, 0,7,3}, // {0,0,2, 0,1,0, 0,0,0}, // {0,0,0, 0,4,0, 0,0,9} // } //})); //sudoku.InitializeWithArray(ToMaps( // { // { // {1,2,3}, // {2,3,0}, // {3,1,2} // } // })); //sudoku.InitializeWithArray(ToMaps( // { // { // {0,0,6,5,0,0}, // {5,0,4,0,0,1}, // {0,3,0,1,2,0}, // {0,0,0,0,0,6}, // {1,0,0,0,0,0}, // {0,0,0,0,0,0} // } // })); Maps_ mp { { { 2,0,0 }, { 0,0,1 }, { 0,0,0 } }, { { 0,0,1 }, { 0,0,0 }, { 2,0,0 } }, { { 0,0,0 }, { 0,0,0 }, { 3,3,0 } } }; sudoku.InitializeWithArray(ToMaps(mp)); System::Console::WriteLine(Sudoku::ToString(sudoku.Solve())); system("pause"); //sudoku.InitializeWithArray(ToMaps( //{ // { // {0,0,5,3,0,0,0,0,0}, // {8,0,0,0,0,0,0,2,0}, // {0,7,0,0,1,0,5,0,0}, // // {4,0,0,0,0,5,3,0,0}, // {0,1,0,0,7,0,0,0,6}, // {0,0,3,2,0,0,0,8,0}, // // {0,6,0,5,0,0,0,0,9}, // {0,0,4,0,0,0,0,3,0}, // {0,0,0,0,0,9,7,0,0} // } //})); //sudoku.InitializeWithArray(ToMaps( //{ // { // {0,0,0, 0,0,0, 0,0,0}, // {0,0,0, 0,0,3, 0,8,5}, // {0,0,1, 0,2,0, 0,0,0}, // // {0,0,0, 5,0,7, 0,0,0}, // {0,0,4, 0,0,0, 1,0,0}, // {0,9,0, 0,0,0, 0,0,0}, // // {5,0,0, 0,0,0, 0,7,3}, // {0,0,2, 0,1,0, 0,0,0}, // {0,0,0, 0,4,0, 0,0,9} // } //})); //sudoku.InitializeWithFilePath("z:\\input.txt"); //auto res = sudoku.Solve(); //System::Console::WriteLine(Sudoku::ToString(res)); //for (int i = 0; i < res->Length; ++i) //{ // if (res[i] == nullptr) // { // printf("\nNo solve\n"); // continue; // } // for (int row = 0; row < res[i]->Length; ++row) // { // for (int col = 0; col < res[i][row]->Length; ++col) // { // printf("%d", res[i][row][col]); // if ((col + 1) % 3 == 0) // { // printf("|"); // } // } // printf("\n"); // if ((row + 1) % 3 == 0) // { // printf("---+---+---\n"); // } // } // printf("\n"); //} //system("pause"); #endif }
Sudoku/Sudoku.h
#pragma once #include "pch.h" public ref class Sudoku sealed { public: using Map = array<array<int>^>; using Maps = array<Map^>; Sudoku(int m, int n); void InitializeWithFilePath(System::String^ path); void InitializeWithArray(Maps^ maps); Maps^ Solve(); static System::String^ ToString(Maps^ maps); private: using CspTerm = Microsoft::SolverFoundation::Solvers::CspTerm; Maps^ maps; int m; int n; static array<CspTerm^>^ GetSlice(array<array<CspTerm^>^>^ lp, int m, int ra, int rb, int ca, int cb); };
Sudoku/Sudoku.cpp
#include "pch.h" #include "Sudoku.h" static int M = 0; ref class Func sealed { public: static array<array<int>^>^ ChunkBySize(array<int>^ arr) { return Microsoft::FSharp::Collections::ArrayModule::ChunkBySize(M, arr); } }; Sudoku::Sudoku(const int m, const int n) :m(m), n(n) { if (m < 3 || m > 9) { throw gcnew System::Exception("M must be 3 to 9"); } if (n < 0) { throw gcnew System::Exception("N must be greater than -1"); } } void Sudoku::InitializeWithFilePath(System::String^ path) { using namespace Microsoft::FSharp::Core; using ArrayModule = Microsoft::FSharp::Collections::ArrayModule; const auto mapSp = gcnew array<System::String^>(1) { " " }; M = m; maps = ArrayModule::Take( n, ArrayModule::Map( FSharpFuncUtil::FSharpFuncUtil::ToFSharpFunc(gcnew System::Func<array<int>^, array<array<int>^>^>(Func::ChunkBySize)), ArrayModule::ChunkBySize( m * m, ArrayModule::Map( FSharpFuncUtil::FSharpFuncUtil::ToFSharpFunc(gcnew System::Func<System::String^, int>(System::Int32::Parse)), System::IO::File::ReadAllText(path) ->Replace("\n", " ") ->Replace("\r", " ") ->Split(mapSp, System::StringSplitOptions::RemoveEmptyEntries))))); if (maps->Length != n) { throw gcnew System::Exception("N size no matches"); } for (auto i = 0; i < maps->Length; ++i) { if (maps[i]->Length != m) { throw gcnew System::Exception("M size no matches"); } for (auto j = 0; j < m; ++j) { if (maps[i][j]->Length != m) { throw gcnew System::Exception("M size no matches"); } } } } void Sudoku::InitializeWithArray(Maps^ maps) { this->maps = maps; } Sudoku::Maps^ Sudoku::Solve() { using namespace Microsoft::SolverFoundation::Solvers; // 创建一个三维数组存放结果 auto res = gcnew Maps(maps->Length); for (auto i = 0; i < maps->Length; ++i) { res[i] = gcnew Map(maps[i]->Length); for (auto j = 0; j < maps[i]->Length; ++j) { res[i][j] = gcnew array<int>(maps[i][j]->Length); } } // 并行遍历每个盘面,同时调度两个线程 // #pragma omp parallel for schedule(dynamic, 2) for (auto i = 0; i < maps->Length; ++i) { // 初始化 auto map = maps[i]; auto s = ConstraintSystem::CreateSolver(); const auto z = s->CreateIntegerInterval(1, maps[i]->Length); auto lp = s->CreateVariableArray(z, "n", maps[i]->Length, maps[i]->Length); // 为每行和已知条件添加约束 for (auto row = 0; row < maps[i]->Length; ++row) { for (auto col = 0; col < maps[i]->Length; ++col) { if (map[row][col] > 0) { s->AddConstraints(s->Equal(map[row][col], lp[row][col])); } } s->AddConstraints(s->Unequal(GetSlice(lp, maps[i]->Length, row, row, 0, maps[i]->Length - 1))); } // 为每列添加约束 for (auto col = 0; col < maps[i]->Length; ++col) { s->AddConstraints(s->Unequal(GetSlice(lp, maps[i]->Length, 0, maps[i]->Length - 1, col, col))); } // 为不同盘面阶数设置宫格大小 auto stepRow = 0; auto stepCol = 0; switch (maps[i]->Length) { case 4: stepRow = 2; stepCol = 2; break; case 6: stepRow = 2; stepCol = 3; break; case 8: stepRow = 4; stepCol = 2; break; case 9: stepRow = 3; stepCol = 3; break; default:; } // 如果当前盘面阶数存在宫格,则为每个宫格添加约束 if (stepRow != 0 && stepCol != 0) { for (auto row = 0; row < maps[i]->Length; row += stepRow) { for (auto col = 0; col < maps[i]->Length; col += stepCol) { s->AddConstraints( s->Unequal( GetSlice(lp, stepCol * stepRow, row, row + stepRow - 1, col, col + stepCol - 1))); } } } // 求解 auto sol = s->Solve(); try { for (auto row = 0; row < maps[i]->Length; ++row) { for (auto col = 0; col < maps[i]->Length; ++col) { res[i][row][col] = sol->GetIntegerValue(lp[row][col]); } } } catch (System::Exception^) // 无解情况返回nullptr { res[i] = nullptr; } } return res; } System::String^ Sudoku::ToString(Maps^ maps) { auto sb = gcnew System::Text::StringBuilder(); for (auto i = 0; i < maps->Length; ++i) { if (maps[i] == nullptr) { sb->Append("Unsolvable!\n\n"); continue; } for (auto j = 0; j < maps[i]->Length; ++j) { for (auto k = 0; k < maps[i][j]->Length; ++k) { sb->Append(maps[i][j][k].ToString()); if (k < maps[i][j]->Length - 1) { sb->Append(" "); } } sb->Append("\n"); } if (i < maps->Length - 1) { sb->Append("\n"); } } return sb->ToString(); } array<Sudoku::CspTerm^>^ Sudoku::GetSlice( array<array<CspTerm^>^>^ lp, const int m, const int ra, const int rb, const int ca, const int cb) { auto slice = gcnew array<CspTerm^>(m); auto i = 0; for (auto row = ra; row <= rb; ++row) { for (auto col = ca; col <= cb; ++col) { slice[i++] = lp[row][col]; } } return slice; }
Sudoku/pch.h
// pch.h: 这是预编译标头文件。 // 下方列出的文件仅编译一次,提高了将来生成的生成性能。 // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。 // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。 // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。 #ifndef PCH_H // ReSharper disable once CppInconsistentNaming #define PCH_H // 添加要在此处预编译的标头 #include <vector> #endif //PCH_H
Sudoku/pch.cpp
// pch.cpp: 与预编译标头对应的源文件 #include "pch.h" // 当使用预编译的头时,需要使用此源文件,编译才能成功。
FSharpFuncUtil/Library1.fs
namespace FSharpFuncUtil open System.Runtime.CompilerServices [<Extension>] type public FSharpFuncUtil = [<Extension>] static member ToFSharpFunc<'a,'b> (func:System.Converter<'a,'b>) = fun x -> func.Invoke(x) [<Extension>] static member ToFSharpFunc<'a,'b> (func:System.Func<'a,'b>) = fun x -> func.Invoke(x) [<Extension>] static member ToFSharpFunc<'a,'b,'c> (func:System.Func<'a,'b,'c>) = fun x y -> func.Invoke(x,y) [<Extension>] static member ToFSharpFunc<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = fun x y z -> func.Invoke(x,y,z) static member Create<'a,'b> (func:System.Func<'a,'b>) = FSharpFuncUtil.ToFSharpFunc func static member Create<'a,'b,'c> (func:System.Func<'a,'b,'c>) = FSharpFuncUtil.ToFSharpFunc func static member Create<'a,'b,'c,'d> (func:System.Func<'a,'b,'c,'d>) = FSharpFuncUtil.ToFSharpFunc func
UnitTest/Test.cpp
using namespace Microsoft::VisualStudio::TestTools::UnitTesting; #include <vector> [TestClass] public ref class SudokuTests sealed { using Row = array<int>; using Map = array<Row^>; using Maps = array<Map^>; // ReSharper disable once CppInconsistentNaming using Row_ = std::vector<int>; // ReSharper disable once CppInconsistentNaming using Map_ = std::vector<Row_>; // ReSharper disable once CppInconsistentNaming using Maps_ = std::vector<Map_>; static Maps^ ToMaps(const Maps_& maps) { #pragma warning(disable:4267) auto res = gcnew Maps(static_cast<int>(maps.size())); for (size_t i = 0; i < maps.size(); ++i) { res[i] = gcnew Map(static_cast<int>(maps[i].size())); for (size_t j = 0; j < maps[i].size(); ++j) { res[i][j] = gcnew Row(static_cast<int>(maps[i][j].size())); for (size_t k = 0; k < maps[i][j].size(); ++k) { res[i][j][k] = maps[i][j][k]; } } } return res; } public: [TestMethod] void Sudoku3X3() { const Maps_ mp { { { 2,0,0 }, { 0,0,1 }, { 0,0,0 } }, { { 0,0,1 }, { 0,0,0 }, { 2,0,0 } }, { { 1,1,0 }, { 0,0,0 }, { 0,0,0 } } }; auto s = gcnew Sudoku(3, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(2 1 3 3 2 1 1 3 2 3 2 1 1 3 2 2 1 3 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku4X4() { const Maps_ mp { { { 0,0, 2,0 }, { 0,0, 0,4 }, { 3,0, 0,1 }, { 0,1, 0,0 } }, { { 2,0, 0,0 }, { 0,1, 0,0 }, { 0,2, 3,0 }, { 0,0, 0,4 } }, { { 1,1, 0,0 }, { 0,0, 0,0 }, { 0,0, 0,0 }, { 0,0, 0,0 } } }; auto s = gcnew Sudoku(4, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(1 4 2 3 2 3 1 4 3 2 4 1 4 1 3 2 2 4 1 3 3 1 4 2 4 2 3 1 1 3 2 4 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku5X5() { const Maps_ mp { { { 0,1,0,0,0 }, { 0,0,0,3,0 }, { 0,0,4,1,2 }, { 1,0,0,5,0 }, { 3,0,0,0,4 } }, { { 3,0,2,0,0 }, { 4,2,0,0,0 }, { 0,0,1,0,5 }, { 0,0,3,0,1 }, { 0,0,0,0,0 } }, { { 1,1,0,0,0 }, { 0,0,0,0,0 }, { 0,0,0,0,0 }, { 0,0,0,0,0 }, { 0,0,0,0,0 } } }; auto s = gcnew Sudoku(5, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(2 1 3 4 5 4 2 5 3 1 5 3 4 1 2 1 4 2 5 3 3 5 1 2 4 3 1 2 5 4 4 2 5 1 3 2 3 1 4 5 5 4 3 2 1 1 5 4 3 2 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku6X6() { const Maps_ mp { { { 5,0,0, 0,4,0 }, { 0,0,0, 0,0,3 }, { 0,6,4, 2,0,0 }, { 2,0,0, 0,6,1 }, { 6,0,0, 3,0,0 }, { 0,0,2, 6,0,4 } }, { { 0,0,0, 2,0,0 }, { 2,0,0, 0,3,0 }, { 0,5,0, 3,0,2 }, { 3,2,6, 0,1,0 }, { 0,0,1, 0,0,3 }, { 0,0,0, 5,4,0 } }, { { 1,1,0, 0,0,0 }, { 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0 } } }; auto s = gcnew Sudoku(6, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(5 2 3 1 4 6 4 1 6 5 2 3 1 6 4 2 3 5 2 3 5 4 6 1 6 4 1 3 5 2 3 5 2 6 1 4 4 1 3 2 5 6 2 6 5 1 3 4 1 5 4 3 6 2 3 2 6 4 1 5 5 4 1 6 2 3 6 3 2 5 4 1 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku7X7() { const Maps_ mp { { { 1,0,0,0,0,0,0 }, { 0,0,2,0,0,0,0 }, { 0,0,0,0,0,5,0 }, { 0,3,0,4,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,6,0 }, { 0,0,0,0,0,0,7 } }, { { 1,0,0,0,6,0,5 }, { 6,2,0,3,0,1,0 }, { 0,4,0,0,0,0,0 }, { 0,6,5,0,0,2,0 }, { 5,0,1,0,4,0,7 }, { 7,0,0,0,0,0,2 }, { 0,0,6,0,0,0,0 } }, { { 1,1,0,0,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0 } } }; auto s = gcnew Sudoku(7, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(1 5 3 6 2 7 4 5 6 2 7 1 4 3 2 1 4 3 7 5 6 7 3 6 4 5 1 2 4 2 7 1 6 3 5 3 7 5 2 4 6 1 6 4 1 5 3 2 7 1 7 2 4 6 3 5 6 2 7 3 5 1 4 2 4 3 5 1 7 6 4 6 5 1 7 2 3 5 3 1 2 4 6 7 7 1 4 6 3 5 2 3 5 6 7 2 4 1 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku8X8() { const Maps_ mp { { { 8,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 6,0 }, { 0,0, 0,3, 0,0, 0,0 }, { 0,0, 5,0, 0,0, 0,0 }, { 0,0, 0,0, 0,4, 0,0 }, { 0,0, 0,0, 2,0, 0,0 }, { 0,7, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,1 } }, { { 0,5, 0,0, 0,7, 4,0 }, { 0,0, 4,3, 2,0, 0,0 }, { 0,0, 1,0, 0,0, 0,0 }, { 7,0, 0,0, 4,0, 0,0 }, { 0,0, 0,0, 0,5, 0,2 }, { 0,0, 0,0, 6,0, 0,0 }, { 4,0, 3,0, 1,0, 0,0 }, { 6,0, 0,8, 0,0, 3,0 } }, { { 1,1, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 }, { 0,0, 0,0, 0,0, 0,0 } } }; auto s = gcnew Sudoku(8, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(8 4 6 1 3 2 7 5 1 5 4 2 7 8 6 3 6 2 7 3 1 5 8 4 7 3 5 8 4 6 1 2 5 1 3 6 8 4 2 7 4 8 1 5 2 7 3 6 3 7 2 4 6 1 5 8 2 6 8 7 5 3 4 1 2 5 8 6 3 7 4 1 1 6 4 3 2 8 5 7 8 4 1 7 5 6 2 3 7 3 5 2 4 1 6 8 3 7 6 4 8 5 1 2 5 2 7 1 6 3 8 4 4 8 3 5 1 2 7 6 6 1 2 8 7 4 3 5 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void Sudoku9X9() { const Maps_ mp { { { 0,0,5, 3,0,0, 0,0,0 }, { 8,0,0, 0,0,0, 0,2,0 }, { 0,7,0, 0,1,0, 5,0,0 }, { 4,0,0, 0,0,5, 3,0,0 }, { 0,1,0, 0,7,0, 0,0,6 }, { 0,0,3, 2,0,0, 0,8,0 }, { 0,6,0, 5,0,0, 0,0,9 }, { 0,0,4, 0,0,0, 0,3,0 }, { 0,0,0, 0,0,9, 7,0,0 } }, { { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,3, 0,8,5 }, { 0,0,1, 0,2,0, 0,0,0 }, { 0,0,0, 5,0,7, 0,0,0 }, { 0,0,4, 0,0,0, 1,0,0 }, { 0,9,0, 0,0,0, 0,0,0 }, { 5,0,0, 0,0,0, 0,7,3 }, { 0,0,2, 0,1,0, 0,0,0 }, { 0,0,0, 0,4,0, 0,0,9 } }, { { 1,1,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 } } }; auto s = gcnew Sudoku(9, 3); s->InitializeWithArray(ToMaps(mp)); Assert::AreEqual(R"(1 4 5 3 2 7 6 9 8 8 3 9 6 5 4 1 2 7 6 7 2 9 1 8 5 4 3 4 9 6 1 8 5 3 7 2 2 1 8 4 7 3 9 5 6 7 5 3 2 9 6 4 8 1 3 6 7 5 4 2 8 1 9 9 8 4 7 6 1 2 3 5 5 2 1 8 3 9 7 6 4 9 8 7 6 5 4 3 2 1 2 4 6 1 7 3 9 8 5 3 5 1 9 2 8 7 4 6 1 2 8 5 3 7 6 9 4 6 3 4 8 9 2 1 5 7 7 9 5 4 6 1 8 3 2 5 1 9 2 8 6 4 7 3 4 7 2 3 1 9 5 6 8 8 6 3 7 4 5 2 1 9 Unsolvable! )", Sudoku::ToString(s->Solve())); } [TestMethod] void FileInput() { const Maps_ mp { { { 0,0,5, 3,0,0, 0,0,0 }, { 8,0,0, 0,0,0, 0,2,0 }, { 0,7,0, 0,1,0, 5,0,0 }, { 4,0,0, 0,0,5, 3,0,0 }, { 0,1,0, 0,7,0, 0,0,6 }, { 0,0,3, 2,0,0, 0,8,0 }, { 0,6,0, 5,0,0, 0,0,9 }, { 0,0,4, 0,0,0, 0,3,0 }, { 0,0,0, 0,0,9, 7,0,0 } }, { { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,3, 0,8,5 }, { 0,0,1, 0,2,0, 0,0,0 }, { 0,0,0, 5,0,7, 0,0,0 }, { 0,0,4, 0,0,0, 1,0,0 }, { 0,9,0, 0,0,0, 0,0,0 }, { 5,0,0, 0,0,0, 0,7,3 }, { 0,0,2, 0,1,0, 0,0,0 }, { 0,0,0, 0,4,0, 0,0,9 } }, { { 1,1,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 }, { 0,0,0, 0,0,0, 0,0,0 } } }; const auto filename = gcnew System::String("FileInput.txt"); System::IO::File::WriteAllText(filename, Sudoku::ToString(ToMaps(mp))); auto sudokuArray = gcnew Sudoku(9, 3); sudokuArray->InitializeWithArray(ToMaps(mp)); auto sudokuFile = gcnew Sudoku(9, 3); sudokuFile->InitializeWithFilePath(filename); Assert::AreEqual(Sudoku::ToString(sudokuArray->Solve()), Sudoku::ToString(sudokuFile->Solve())); System::IO::File::Delete(filename); } [TestMethod] void MOutOfRange() { try { gcnew Sudoku(10, 1); } catch (System::Exception^ exception) { Assert::IsTrue(exception->ToString()->Contains("M must be 3 to 9")); } try { gcnew Sudoku(2, 1); } catch (System::Exception^ exception) { Assert::IsTrue(exception->ToString()->Contains("M must be 3 to 9")); } } [TestMethod] void NOutOfRange() { try { gcnew Sudoku(9, -1); } catch (System::Exception^ exception) { Assert::IsTrue(exception->ToString()->Contains("N must be greater than -1")); } } [TestMethod] void NSizeNoMatch() { const Maps_ mp { { { 0,0,5, 3,0,0, 0,0,0 }, { 8,0,0, 0,0,0, 0,2,0 }, { 0,7,0, 0,1,0, 5,0,0 }, { 4,0,0, 0,0,5, 3,0,0 }, { 0,1,0, 0,7,0, 0,0,6 }, { 0,0,3, 2,0,0, 0,8,0 }, { 0,6,0, 5,0,0, 0,0,9 }, { 0,0,4, 0,0,0, 0,3,0 }, { 0,0,0, 0,0,9, 7,0,0 } } }; const auto filename = gcnew System::String("FileInput.txt"); System::IO::File::WriteAllText(filename, Sudoku::ToString(ToMaps(mp))); auto sudokuFile = gcnew Sudoku(9, 2); try { sudokuFile->InitializeWithFilePath(filename); } catch (System::Exception^ exception) { Assert::IsTrue(exception->ToString()->Contains("System.InvalidOperationException")); } System::IO::File::Delete(filename); } [TestMethod] void MSizeNoMatch() { const Maps_ mp { { { 0,0,5, 3,0,0, 0,0,0 }, { 8,0,0, 0,0,0, 0,2,0 }, { 0,7,0, 0,1,0, 5,0,0 }, { 4,0,0, 0,0,5, 3,0,0 }, { 0,1,0, 0,7,0, 0,0,6 }, { 0,0,3, 2,0,0, 0,8,0 }, { 0,6,0, 5,0,0, 0,0,9 }, { 0,0,4, 0,0,0, 0,3,0 }, { 0,0,0, 0,0,9, 7,0,0 } } }; const auto filename = gcnew System::String("FileInput.txt"); System::IO::File::WriteAllText(filename, Sudoku::ToString(ToMaps(mp))->Substring(2)); auto sudokuFile = gcnew Sudoku(9, 1); try { sudokuFile->InitializeWithFilePath(filename); } catch (System::Exception^ exception) { Assert::IsTrue(exception->ToString()->Contains("M size no matches")); } System::IO::File::Delete(filename); } };
input.txt
0 0 5 3 0 0 0 0 0 8 0 0 0 0 0 0 2 0 0 7 0 0 1 0 5 0 0 4 0 0 0 0 5 3 0 0 0 1 0 0 7 0 0 0 6 0 0 3 2 0 0 0 8 0 0 6 0 5 0 0 0 0 9 0 0 4 0 0 0 0 3 0 0 0 0 0 0 9 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 8 5 0 0 1 0 2 0 0 0 0 0 0 0 5 0 7 0 0 0 0 0 4 0 0 0 1 0 0 0 9 0 0 0 0 0 0 0 5 0 0 0 0 0 0 7 3 0 0 2 0 1 0 0 0 0 0 0 0 0 4 0 0 0 9 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 3 0 0 7 0 0 0 0 6 0 0 1 9 5 0 0 0 0 9 8 0 0 0 0 6 0 8 0 0 0 6 0 0 0 3 4 0 0 8 0 3 0 0 1 7 0 0 0 2 0 0 0 6 0 6 0 0 0 0 2 8 0 0 0 0 4 1 9 0 0 5 0 0 0 0 8 0 0 7 9 0 0 0 0 4 0 0 0 0 1 2 0 0 0 0 0 7 3 0 3 0 0 0 8 0 0 0 0 0 4 0 0 0 6 0 0 0 0 0 2 0 3 0 0 0 0 0 5 0 0 0 0 0 0 0 0 6 0 9 0 5 0 0 0 7 0 0 0 0 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 8 4 0 3 0 0 0 0 0 7 0 0 0 4 0 0 0 6 0 0 0 0 0 2 0 3 0 0 0 0 0 5 0 0 0 9 0 0 0 0 6 0 9 0 5 0 0 0 7 0 0 0 0 0 2 0 0 0 0 0 5 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 3 0 0 4 0 0 5 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 3 0 6 0 0 0 0 7 0 0 0 5 8 0 0 0 0 0 6 7 0 0 0 0 1 0 0 0 4 0 0 0 5 2 0 0 0 0 0 0 0 0 0 0 2 1 0 0 0 0 0 0 7 3 0 0 0 0 0 0 5 8 0 0 0 0 0 0 4 3 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 7 6 0 0 0 0 0 0 2 5 0 0 0 0 0 0 7 3 0 0 0 0 0 0 9 8 0 0 0 7 8 9 1 2 3 4 5 6 3 0 0 0 4 0 0 0 8 5 0 0 0 9 0 0 0 1 8 0 0 0 3 0 0 0 4 1 2 3 4 5 6 7 8 9 6 0 0 0 7 0 0 0 2 9 0 0 0 1 0 0 0 5 2 0 0 0 6 0 0 0 7 1 5 6 7 8 9 1 2 3 1 0 0 2 0 0 3 0 0 2 0 0 3 0 0 4 0 0 3 0 0 4 0 0 5 0 0 4 0 0 5 0 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 3 0 0 4 0 0 5 0 0 4 0 0 5 0 0 6 0 0 5 0 0 6 0 0 7 0 0 6 0 0 7 0 0 8 0 0 0 0 0 0 0 1 0 0 0 0 0 0 2 0 0 3 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 5 0 0 4 0 1 6 0 0 0 0 0 0 0 7 1 0 0 0 0 0 0 5 0 0 0 0 2 0 0 0 0 0 0 8 0 0 4 0 0 3 0 9 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 3 0 0 4 0 0 5 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 3 0 6 0 0 0 0 7 0 0 0 5 8 0 0 0 0 0 6 7 0 0 0 0 1 0 0 0 4 0 0 0 5 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 0 1 0 0 3 0 0 0 6 0 2 0 7 0 0 0 0 0 3 0 4 0 0 0 2 1 0 0 0 0 0 9 8 0 0 0 0 0 0 0 0 0 0 0 2 5 0 6 4 0 0 0 8 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 9 0 2 0 0 0 0 4 0 0 0 0 0 5 0 0 0 2 0 0 0 3 0 0 2 0 0 0 0 0 0 0 7 0 0 0 4 5 6 0 0 0 6 0 0 0 0 0 0 0 9 0 0 7 0 0 0 8 0 0 0 3 0 0 0 0 0 4 0 0 0 0 2 0 7 0 0 0 0 0 0 6 0 3 0 0 0 0 3 0 0 1 0 0 5 0 0 0 9 0 0 0 2 0 0 7 0 0 1 0 6 0 0 9 0 2 0 0 0 0 0 8 0 1 0 0 4 0 9 0 0 3 0 0 8 0 0 0 1 0 0 0 5 0 0 9 0 0 7 0 0 0 0 7 0 4 0 0 0 1 0 2 0 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4 0 4 0 0 5 0 0 0 0 0 6 0 0 7 0 0 0 0 0 0 0 0 0 0 0 2 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 8 0 0 0 0 0 0 0 0 0 0 0 0 1 2 0 3 4 5 6 7 0 3 4 5 0 6 1 8 2 0 0 1 0 5 8 2 0 6 0 0 8 6 0 0 0 0 1 0 2 0 0 0 7 0 5 0 0 0 3 7 0 5 0 2 8 0 8 0 0 6 0 7 0 0 2 0 7 0 8 3 6 1 5 0 0 6 7 0 3 5 0 0 0 0 0 0 4 0 0 0 0 5 0 0 0 0 0 0 0 2 9 0 0 0 0 0 0 0 7 0 3 0 0 0 0 0 4 0 8 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 4 0 0 0 0 0 0 0 0 0 0 5 9 2 6 7 3 1 0 1 4 0 9 3 0 0 0 0 9 3 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5 6 0 0 0 0 0 0 4 8 9 0 0 0 0 0 2 7 0 0 0 0 0 0 0 0 0 0 0 0 2 5 0 0 1 8 0 0 0 7 4 0 0 3 2 0 0 0 5 6 0 0 3 4 0 0 0 7 8 0 0 5 6 0 0 0 0 0 0 0 0 0 1 2 0 0 0 0 0 0 0 3 4 0 0 0 0 0 6 7 0 0 0 0 0 0 0 8 9 0 0 0 0 0 0 0 0 0 4 5 0 0 2 3 0 0 0 6 7 0 0 4 5 0 0 0
师门树
index.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Parse Tree</title> <meta name="description" content="A collapsible tree layout with all of the leaf nodes at the same layer." /> <meta name="viewport" content="width=device-width, initial-scale=1"> <script src="https://unpkg.com/gojs/release/go.js"></script> <script id="code"> function init() { var $ = go.GraphObject.make; myDiagram = $(go.Diagram, "myDiagramDiv", { allowCopy: false, allowDelete: false, allowMove: false, initialAutoScale: go.Diagram.Uniform, layout: $(FlatTreeLayout, { angle: 90, compaction: go.TreeLayout.CompactionNone }), "undoManager.isEnabled": true }); myDiagram.nodeTemplate = $(go.Node, "Vertical", { selectionObjectName: "BODY" }, $(go.Panel, "Auto", { name: "BODY" }, $(go.Shape, "RoundedRectangle", new go.Binding("fill"), new go.Binding("stroke")), $(go.TextBlock, { font: "bold 12pt Arial, sans-serif", margin: new go.Margin(4, 2, 2, 2) }, new go.Binding("text")) ), $(go.Panel, { height: 17 }, $("TreeExpanderButton") ) ); myDiagram.linkTemplate = $(go.Link, $(go.Shape, { strokeWidth: 1.5 })); const color0 = 'rgba(87,124,151,90)'; const color1 = 'rgba(164,193,209,90)'; const color2 = 'rgba(178,76,71,90)'; const color3 = 'rgba(252,167,160,90)'; // 初始化 let nodeDataArray = [ { key: 1, text: "师生树", fill: color0, stroke: color0 } ]; let inArrArr = document.getElementById('input').value.split('\n\n'); let id = 1; // 对每组进行处理 inArrArr.forEach(x => { let inArr = x.split('\n'); nodeDataArray.push({ key: ++id, text: inArr[0].split(':')[1], fill: color1, stroke: color1, parent: 1 }); // 添加导师 let rootId = id; // 对每行进行处理 inArr.slice(1).sort().forEach(y => { let data = y.split(':'); nodeDataArray.push({ key: ++id, text: data[0], fill: color2, stroke: color2, parent: rootId }); // 添加级数 let subId = id; data[1].split('、').forEach(z => nodeDataArray.push({ key: ++id, text: z, fill: color3, stroke: color3, parent: subId })); // 添加学生 }); }); myDiagram.model = $(go.TreeModel, { nodeDataArray: nodeDataArray }); } // Customize the TreeLayout to position all of the leaf nodes at the same vertical Y position. function FlatTreeLayout() { go.TreeLayout.call(this); } go.Diagram.inherit(FlatTreeLayout, go.TreeLayout); FlatTreeLayout.prototype.commitLayout = function() { go.TreeLayout.prototype.commitLayout.call(this); var y = -Infinity; this.network.vertexes.each(function(v) { y = Math.max(y, v.node.position.y); }); this.network.vertexes.each(function(v) { if (v.destinationEdges.count === 0) { v.node.position = new go.Point(v.node.position.x, y); v.node.toEndSegmentLength = Math.abs(v.centerY - y); } else { v.node.toEndSegmentLength = 10; } }); }; </script> </head> <body> <div id="sample"> <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:500px"></div> <label for="input"><textarea id="input" style="width: 100%; height: 25%"></textarea></label><br/> <button onclick="init()">提交</button> </div> </body> </html>
tests.html
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>QUnit Example</title> <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.9.2.css"> </head> <body> <div id="qunit"></div> <div id="qunit-fixture"></div> <script src="https://code.jquery.com/qunit/qunit-2.9.2.js"></script> <script> function Main(x) { let nodeDataArray = [{ key: 1, text: "师生树" }]; let inArrArr = x.split('\n\n'); let id = 1; inArrArr.forEach(x => { let inArr = x.split('\n'); nodeDataArray.push({ key: ++id, text: inArr[0].split(':')[1], parent: 1 }); let rootId = id; inArr.slice(1).sort().forEach(y => { let data = y.split(':'); nodeDataArray.push({ key: ++id, text: data[0], parent: rootId }); let subId = id; data[1].split('、').forEach(z => nodeDataArray.push({ key: ++id, text: z, parent: subId })); // 添加学生 }); }); return nodeDataArray; } QUnit.test("standard1", assert => { const str = "导师:许三\n" + "2009级博士生:赵大、李六、赵三\n" + "2010级硕士生:张三、钱四、刘二\n" + "2009级硕士生:孙一、孙三、钱二\n" + "2011级博士生:孔三、刘四、吴九"; const res = "[{\"key\":1,\"text\":\"师生树\"},{\"key\":2,\"text\":\"许三\",\"parent\":1},{\"key\":3,\"text\":\"2009级博士生\",\"parent\":2},{\"key\":4,\"text\":\"赵大\",\"parent\":3},{\"key\":5,\"text\":\"李六\",\"parent\":3},{\"key\":6,\"text\":\"赵三\",\"parent\":3},{\"key\":7,\"text\":\"2009级硕士生\",\"parent\":2},{\"key\":8,\"text\":\"孙一\",\"parent\":7},{\"key\":9,\"text\":\"孙三\",\"parent\":7},{\"key\":10,\"text\":\"钱二\",\"parent\":7},{\"key\":11,\"text\":\"2010级硕士生\",\"parent\":2},{\"key\":12,\"text\":\"张三\",\"parent\":11},{\"key\":13,\"text\":\"钱四\",\"parent\":11},{\"key\":14,\"text\":\"刘二\",\"parent\":11},{\"key\":15,\"text\":\"2011级博士生\",\"parent\":2},{\"key\":16,\"text\":\"孔三\",\"parent\":15},{\"key\":17,\"text\":\"刘四\",\"parent\":15},{\"key\":18,\"text\":\"吴九\",\"parent\":15}]"; assert.equal(JSON.stringify(Main(str)), res, "Passed!"); }); QUnit.test("standard2", assert => { const str = "导师:张三\n" + "2016级博士生:天一、王二、吴五\n" + "2015级硕士生:李四、王五、许六\n" + "2016级硕士生:刘一、李二、李三\n" + "2017级本科生:刘六、琪七、司四"; const res = "[{\"key\":1,\"text\":\"师生树\"},{\"key\":2,\"text\":\"张三\",\"parent\":1},{\"key\":3,\"text\":\"2015级硕士生\",\"parent\":2},{\"key\":4,\"text\":\"李四\",\"parent\":3},{\"key\":5,\"text\":\"王五\",\"parent\":3},{\"key\":6,\"text\":\"许六\",\"parent\":3},{\"key\":7,\"text\":\"2016级博士生\",\"parent\":2},{\"key\":8,\"text\":\"天一\",\"parent\":7},{\"key\":9,\"text\":\"王二\",\"parent\":7},{\"key\":10,\"text\":\"吴五\",\"parent\":7},{\"key\":11,\"text\":\"2016级硕士生\",\"parent\":2},{\"key\":12,\"text\":\"刘一\",\"parent\":11},{\"key\":13,\"text\":\"李二\",\"parent\":11},{\"key\":14,\"text\":\"李三\",\"parent\":11},{\"key\":15,\"text\":\"2017级本科生\",\"parent\":2},{\"key\":16,\"text\":\"刘六\",\"parent\":15},{\"key\":17,\"text\":\"琪七\",\"parent\":15},{\"key\":18,\"text\":\"司四\",\"parent\":15}]"; assert.equal(JSON.stringify(Main(str)), res, "Passed!"); }); QUnit.test("multi", assert => { const str = "导师:许六\n" + "2009级博士生:赵大、李六、赵三\n" + "2010级硕士生:张三、钱四、刘二\n" + "2009级硕士生:孙一、孙三、钱二\n" + "2011级博士生:孔三、刘四、吴九\n" + "\n" + "导师:张三\n" + "2016级博士生:天一、王二、吴五\n" + "2015级硕士生:李四、王五、许六\n" + "2016级硕士生:刘一、李二、李三\n" + "2017级本科生:刘六、琪七、司四"; const res = "[{\"key\":1,\"text\":\"师生树\"},{\"key\":2,\"text\":\"许六\",\"parent\":1},{\"key\":3,\"text\":\"2009级博士生\",\"parent\":2},{\"key\":4,\"text\":\"赵大\",\"parent\":3},{\"key\":5,\"text\":\"李六\",\"parent\":3},{\"key\":6,\"text\":\"赵三\",\"parent\":3},{\"key\":7,\"text\":\"2009级硕士生\",\"parent\":2},{\"key\":8,\"text\":\"孙一\",\"parent\":7},{\"key\":9,\"text\":\"孙三\",\"parent\":7},{\"key\":10,\"text\":\"钱二\",\"parent\":7},{\"key\":11,\"text\":\"2010级硕士生\",\"parent\":2},{\"key\":12,\"text\":\"张三\",\"parent\":11},{\"key\":13,\"text\":\"钱四\",\"parent\":11},{\"key\":14,\"text\":\"刘二\",\"parent\":11},{\"key\":15,\"text\":\"2011级博士生\",\"parent\":2},{\"key\":16,\"text\":\"孔三\",\"parent\":15},{\"key\":17,\"text\":\"刘四\",\"parent\":15},{\"key\":18,\"text\":\"吴九\",\"parent\":15},{\"key\":19,\"text\":\"张三\",\"parent\":1},{\"key\":20,\"text\":\"2015级硕士生\",\"parent\":19},{\"key\":21,\"text\":\"李四\",\"parent\":20},{\"key\":22,\"text\":\"王五\",\"parent\":20},{\"key\":23,\"text\":\"许六\",\"parent\":20},{\"key\":24,\"text\":\"2016级博士生\",\"parent\":19},{\"key\":25,\"text\":\"天一\",\"parent\":24},{\"key\":26,\"text\":\"王二\",\"parent\":24},{\"key\":27,\"text\":\"吴五\",\"parent\":24},{\"key\":28,\"text\":\"2016级硕士生\",\"parent\":19},{\"key\":29,\"text\":\"刘一\",\"parent\":28},{\"key\":30,\"text\":\"李二\",\"parent\":28},{\"key\":31,\"text\":\"李三\",\"parent\":28},{\"key\":32,\"text\":\"2017级本科生\",\"parent\":19},{\"key\":33,\"text\":\"刘六\",\"parent\":32},{\"key\":34,\"text\":\"琪七\",\"parent\":32},{\"key\":35,\"text\":\"司四\",\"parent\":32}]" assert.equal(JSON.stringify(Main(str)), res, "Passed!"); }); </script> </body> </html>
C.b^fMKph/MKse1Jpc{7h.html
<html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> <script src="js/mui.min.js"></script> <link href="css/mui.min.css" rel="stylesheet" /> <link rel="stylesheet" href="css/font-awesome.css"> <link rel="stylesheet" href="css/calender.css"> <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <script type="text/javascript" charset="utf-8"> mui.init(); </script> <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> </head> <style> .mui-content{ background-color: #FFFFFF; } .mui-bar-nav { box-shadow: 0 1px 6px #ffffff; } .head{ box-shadow: 1px 1px 3px #6a6a6a; } #calicon{ font-size:24px; color:#F58A8A; position:absolute; right:20px; top:3px; } </style> <body> <nav class="mui-bar mui-bar-tab"> <a class="mui-tab-item" href="#tabbar"> <i class="fa fa-check-square" style="font-size:30px;color:#F58A8A"></i> </a> <a class="mui-tab-item mui-active" href="#tabbar-with-calender"> <i class="fa fa-calendar-o" style="font-size:30px;color:#CBC9C9"></i> </a> <a class="mui-tab-item" href="#tabbar-with-check"> <i class="fa fa-calendar-check-o" style="font-size:30px;color:#CBC9C9"></i> </a> <a class="mui-tab-item" href="#tabbar-with-perCenter"> <i class="fa fa-user" style="font-size:30px;color:#CBC9C9"></i> </a> </nav> <header class="mui-bar mui-bar-nav"> <h3 class="mui-left" style="margin-top: 10;">ToDoList</h3> <i id="calicon" class="fa fa-plus" style="margin-top: 10px;"></i> </header> <style> .fkButton { border: 0px; padding: 0px; margin: 0px; } </style> <script> let TodoList = [ {name:'番茄钟UI设计', time:'今天,12:50-13:30', fin:false}, {name:'待办2', time:'6月10日,12:00-13:00', fin:false}, {name:'图像处理', time:'昨天,10:30-11:50', fin:true}, ]; //get data from fucking database let fkButtonSquare = (b) => { // You just DO WHAT THE FUCK YOU WANT TO. let name = b.parent().contents().text().trim(); let index = TodoList.findIndex(x => x.name == name); TodoList[index].fin = (!TodoList[index].fin); UpdateList(); }; let UpdateList = () => { let tl = $('#fkTodoList'), dl = $('#fkDoneList'), tlh = '', dlh = ''; tl.html(''); dl.html(''); TodoList.forEach(x => { if(x.fin) { dlh += '<div name="fkDoneItem" class="mui-table">' + '<div class="mui-table-cell mui-col-xs-10">' + '<h4 class="mui-ellipsis" style="margin-left:15px;margin-bottom: 0;"><button class="fkButton" onclick="fkButtonSquare($(this))"><i class="fa fa-check-square"></i></button> ' + x.name + ' </h4>' + '<span class="mui-h5" style="font-size:12px;color:#808080;margin-left:37px;"> ' + x.time + ' </span>' + '</div>' + '</div>'; } else { tlh += '<li class="mui-table-view-cell">' + '<div name="fkTodoItem" class="mui-table">' + '<div class="mui-table-cell mui-col-xs-10">' + '<h4 class="mui-ellipsis"><button class="fkButton" onclick="fkButtonSquare($(this))"><i class="fa fa-square-o"></i></button> ' + x.name + ' </h4>' + '<span class="mui-h5" style="font-size:12px;color:#F58A8A;margin-left:20px;"> ' + x.time + ' </span>' + '</div>' + '<button type="button" class="mui-btn mui-btn-danger mui-btn-outlined">' + '<span class="mui-h5" style="font-size:20px;color:#F58A8A;">开始</span>' + '</button>' + '</div>' + '</li>'; } }); tl.html(tlh); dl.html(dlh); }; </script> <div class="mui-content" style="padding-bottom:0;"> <ul id="fkTodoList" class="mui-table-view" style="margin-top:3px;"> <li class="mui-table-view-cell"> <div name='fkTodoItem' class="mui-table"> <div class="mui-table-cell mui-col-xs-10"> <h4 class="mui-ellipsis"><button class="fkButton" onclick="fkButtonSquare($(this))"><i class="fa fa-square-o"></i></button> 番茄钟UI设计</h4> <span class="mui-h5" style="font-size:12px;color:#F58A8A;margin-left:20px;">今天,12:50-13:30</span> </div> <button type="button" class="mui-btn mui-btn-danger mui-btn-outlined"> <span class="mui-h5" style="font-size:20px;color:#F58A8A;">开始</span> </button> </div> </li> <li class="mui-table-view-cell"> <div name='fkTodoItem' class="mui-table"> <div class="mui-table-cell mui-col-xs-10"> <h4 class="mui-ellipsis"><i class="fa fa-square-o"></i> 待办2</h4> <span class="mui-h5" style="font-size:12px;color:#808080;margin-left:20px;">6月10日,12:00-13:00</span> </div> <button type="button" class="mui-btn mui-btn-danger mui-btn-outlined"> <span class="mui-h5" style="font-size:20px;color:#F58A8A">开始</span> </button> </div> </li> </ul> </li> <ul class="mui-table-view"> <li class="mui-table-view-cell mui-collapse" style="background-color:#f5dada;"> <a class="mui-navigate-right" href="#" style="height:18px;padding-top:2;color:#525050">已完成</a> <div id="fkDoneList" class="mui-collapse-content"> <div name="fkDoneItem" class="mui-table"> <div class="mui-table-cell mui-col-xs-10"> <h4 class="mui-ellipsis" style="margin-left:15px;margin-bottom: 0;"><i class="fa fa-check-square"></i> 图像处理</h4> <span class="mui-h5" style="font-size:12px;color:#808080;margin-left:37px;"> 昨天,10:30-11:50</span> </div> </div> </div> </li> </ul> </div> </body> </html>
C.b^fMKph/MK8[(L_h.html
<!DOCTYPE html> <html> <head style="height: 100%;"> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title> <script src="js/mui.min.js"></script> <link href="css/mui.min.css" rel="stylesheet"/> <link rel="stylesheet" href="css/font-awesome.css"> <link rel="stylesheet" href="css/calender.css"> <link rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/css/bootstrap.min.css"> <script src="https://cdn.staticfile.org/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdn.staticfile.org/twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script> <script type="text/javascript" charset="utf-8"> mui.init(); </script> </head> <body style="height: 100%;"> <div style="position: absolute; height: 100%; width: 100%; display: grid; grid-template-rows: 10% 50% 40%; height: 1hv;"> <div style="font-size: 1.5rem; display: grid; grid-template-columns: 1fr auto 1fr;"> <div style="margin-right: 1rem; color: rgb(247,200,200); vertical-align: top; font-size: 8rem; text-align: right;">“</div> <div style="transform: translateY(2.75rem); text-align: center;">开始专注咯,现在放下你的手机吧</div> <div style="margin-left: 1rem; color: rgb(247,200,200); transform: translateY(1.25rem); font-size: 8rem;">”</div> </div> <div style="background-color: rgb(255,241,241); color: rgb(247,200,200); margin: 5%; display: grid; text-align: center; grid-template-rows: 1fr 1fr;"> <div style="transform: translateY(1rem); margin: auto auto; font-size:8rem"><u>00 : 00</u></div> <div style="margin: auto auto; font-size:2rem"> <div>lesion设计</div> <div>进行中</div> </div> </div> <div style="text-align: center;"> <button style="border: 0px; visibility: visible;" class="btn btn-lg" data-toggle="modal" data-target="#pauseModal" id='pauseBtnmd' type="button"> <i style="color: rgb(247,200,200); font-size: 6rem;" class="fa fa-pause-circle-o"></i> </button> <button style="border: 0px;" class="btn btn-lg" data-toggle="modal" data-target="#stopModal" id='stopBtn' type="button"> <i style="color: rgb(247,200,200); font-size: 6rem;" class="fa fa-stop-circle-o"></i> </button> <script> var paused = false; </script> </div> <style type="text/css"> .modal-header.fxx { background-color: rgb(246,151,151); color: #FFFFFF; border-radius: 0.3rem 0.3rem 0 0; } </style> <div class="modal fade" id="abortModal" tabindex="-1" role="dialog" aria-labelledby="abortModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header fxx bg-danger"> <h4 class="modal-title" id="myModalLabel" style="text-align: center;">放弃后的任务不会标记为已完成</h4> </div> <div style="text-align: center;" class="modal-footer"> <button type="button" class="btn" data-dismiss="modal">确认放弃</button><br /> <button type="button" class="btn" data-dismiss="modal">取消</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> <div class="modal fade" id="pausedModal" tabindex="-1" role="dialog" aria-labelledby="pausedModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header fxx bg-danger"> <h4 style="text-align: center;" class="modal-title" id="myModalLabel">请选择您的操作</h4> </div> <div style="text-align: center;" class="modal-footer"> <button type="button" class="btn" data-dismiss="modal" onclick="(()=>{ paused = false; document.getElementById('pauseBtnmd').style.visibility = 'visible'; document.getElementById('stopBtn').dataset.target ='#stopModal'; })()">结束当前休息计时</button><br /> <button type="button" class="btn" data-dismiss="modal">取消</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> <div class="modal fade" id="stopModal" tabindex="-1" role="dialog" aria-labelledby="stopModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header fxx bg-danger"> <h4 style="text-align: center;" class="modal-title" id="myModalLabel">请选择您的操作</h4> </div> <div style="text-align: center;" class="modal-footer"> <button class="btn" data-toggle="modal" data-target="#abortModal" id='abortBtn' data-dismiss="modal" type="button"> 放弃计时 </button><br /> <button type="button" class="btn" data-dismiss="modal" onclick="(()=>{ paused = true; document.getElementById('pauseBtnmd').style.visibility = 'hidden'; document.getElementById('stopBtn').dataset.target = '#pausedModal'; })()">终止计时</button><br /> <button type="button" class="btn" data-dismiss="modal">取消</button> </div> </div><!-- /.modal-content --> </div><!-- /.modal-dialog --> </div> </div> </body> </html>