作业
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>