Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
215
Task/Knights-tour/JavaScript/knights-tour-1.js
Normal file
215
Task/Knights-tour/JavaScript/knights-tour-1.js
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
class KnightTour {
|
||||
constructor() {
|
||||
this.width = 856;
|
||||
this.height = 856;
|
||||
this.cellCount = 8;
|
||||
this.size = 0;
|
||||
this.knightPiece = "\u2658";
|
||||
this.knightPos = {
|
||||
x: 0,
|
||||
y: 0
|
||||
};
|
||||
this.ctx = null;
|
||||
this.step = this.width / this.cellCount;
|
||||
this.lastTime = 0;
|
||||
this.wait;
|
||||
this.delay;
|
||||
this.success;
|
||||
this.jumps;
|
||||
this.directions = [];
|
||||
this.visited = [];
|
||||
this.path = [];
|
||||
document.getElementById("start").addEventListener("click", () => {
|
||||
this.startHtml();
|
||||
});
|
||||
this.init();
|
||||
this.drawBoard();
|
||||
}
|
||||
|
||||
drawBoard() {
|
||||
let a = false, xx, yy;
|
||||
for (let y = 0; y < this.cellCount; y++) {
|
||||
for (let x = 0; x < this.cellCount; x++) {
|
||||
if (a) {
|
||||
this.ctx.fillStyle = "#607db8";
|
||||
} else {
|
||||
this.ctx.fillStyle = "#aecaf0";
|
||||
}
|
||||
a = !a;
|
||||
xx = x * this.step;
|
||||
yy = y * this.step;
|
||||
this.ctx.fillRect(xx, yy, xx + this.step, yy + this.step);
|
||||
}
|
||||
if (!(this.cellCount & 1)) a = !a;
|
||||
}
|
||||
if (this.path.length) {
|
||||
const s = this.step >> 1;
|
||||
this.ctx.lineWidth = 3;
|
||||
this.ctx.fillStyle = "black";
|
||||
this.ctx.beginPath();
|
||||
this.ctx.moveTo(this.step * this.knightPos.x + s, this.step * this.knightPos.y + s);
|
||||
let a, b, v = this.path.length - 1;
|
||||
for (; v > -1; v--) {
|
||||
a = this.path[v].pos.x * this.step + s;
|
||||
b = this.path[v].pos.y * this.step + s;
|
||||
this.ctx.lineTo(a, b);
|
||||
this.ctx.fillRect(a - 5, b - 5, 10, 10);
|
||||
}
|
||||
this.ctx.stroke();
|
||||
}
|
||||
}
|
||||
|
||||
createMoves(pos) {
|
||||
const possibles = [];
|
||||
let x = 0,
|
||||
y = 0,
|
||||
m = 0,
|
||||
l = this.directions.length;
|
||||
for (; m < l; m++) {
|
||||
x = pos.x + this.directions[m].x;
|
||||
y = pos.y + this.directions[m].y;
|
||||
if (x > -1 && x < this.cellCount && y > -1 && y < this.cellCount && !this.visited[x + y * this.cellCount]) {
|
||||
possibles.push({
|
||||
x,
|
||||
y
|
||||
})
|
||||
}
|
||||
}
|
||||
return possibles;
|
||||
}
|
||||
|
||||
warnsdorff(pos) {
|
||||
const possibles = this.createMoves(pos);
|
||||
if (possibles.length < 1) return [];
|
||||
const moves = [];
|
||||
for (let p = 0, l = possibles.length; p < l; p++) {
|
||||
let ps = this.createMoves(possibles[p]);
|
||||
moves.push({
|
||||
len: ps.length,
|
||||
pos: possibles[p]
|
||||
});
|
||||
}
|
||||
moves.sort((a, b) => {
|
||||
return b.len - a.len;
|
||||
});
|
||||
return moves;
|
||||
}
|
||||
|
||||
startHtml() {
|
||||
this.cellCount = parseInt(document.getElementById("cellCount").value);
|
||||
this.size = Math.floor(this.width / this.cellCount)
|
||||
this.wait = this.delay = parseInt(document.getElementById("delay").value);
|
||||
this.step = this.width / this.cellCount;
|
||||
this.ctx.font = this.size + "px Arial";
|
||||
document.getElementById("log").innerText = "";
|
||||
document.getElementById("path").innerText = "";
|
||||
this.path = [];
|
||||
this.jumps = 1;
|
||||
this.success = true;
|
||||
this.visited = [];
|
||||
const cnt = this.cellCount * this.cellCount;
|
||||
for (let a = 0; a < cnt; a++) {
|
||||
this.visited.push(false);
|
||||
}
|
||||
const kx = parseInt(document.getElementById("knightx").value),
|
||||
ky = parseInt(document.getElementById("knighty").value);
|
||||
this.knightPos = {
|
||||
x: (kx > this.cellCount || kx < 0) ? Math.floor(Math.random() * this.cellCount) : kx,
|
||||
y: (ky > this.cellCount || ky < 0) ? Math.floor(Math.random() * this.cellCount) : ky
|
||||
};
|
||||
this.mainLoop = (time = 0) => {
|
||||
const dif = time - this.lastTime;
|
||||
this.lastTime = time;
|
||||
this.wait -= dif;
|
||||
if (this.wait > 0) {
|
||||
requestAnimationFrame(this.mainLoop);
|
||||
return;
|
||||
}
|
||||
this.wait = this.delay;
|
||||
let moves;
|
||||
if (this.success) {
|
||||
moves = this.warnsdorff(this.knightPos);
|
||||
} else {
|
||||
if (this.path.length > 0) {
|
||||
const path = this.path[this.path.length - 1];
|
||||
moves = path.m;
|
||||
if (moves.length < 1) this.path.pop();
|
||||
this.knightPos = path.pos
|
||||
this.visited[this.knightPos.x + this.knightPos.y * this.cellCount] = false;
|
||||
this.jumps--;
|
||||
this.wait = this.delay;
|
||||
} else {
|
||||
document.getElementById("log").innerText = "Can't find a solution!";
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.drawBoard();
|
||||
const ft = this.step - (this.step >> 3);
|
||||
this.ctx.fillStyle = "#000";
|
||||
this.ctx.fillText(this.knightPiece, this.knightPos.x * this.step, this.knightPos.y * this.step + ft);
|
||||
if (moves.length < 1) {
|
||||
if (this.jumps === this.cellCount * this.cellCount) {
|
||||
document.getElementById("log").innerText = "Tour finished!";
|
||||
let str = "";
|
||||
for (let z of this.path) {
|
||||
str += `${1 + z.pos.x + z.pos.y * this.cellCount}, `;
|
||||
}
|
||||
str += `${1 + this.knightPos.x + this.knightPos.y * this.cellCount}`;
|
||||
document.getElementById("path").innerText = str;
|
||||
return;
|
||||
} else {
|
||||
this.success = false;
|
||||
}
|
||||
} else {
|
||||
this.visited[this.knightPos.x + this.knightPos.y * this.cellCount] = true;
|
||||
const move = moves.pop();
|
||||
this.path.push({
|
||||
pos: this.knightPos,
|
||||
m: moves
|
||||
});
|
||||
this.knightPos = move.pos
|
||||
this.success = true;
|
||||
this.jumps++;
|
||||
}
|
||||
requestAnimationFrame(this.mainLoop);
|
||||
};
|
||||
this.mainLoop();
|
||||
}
|
||||
|
||||
init() {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.id = "cv";
|
||||
canvas.width = this.width;
|
||||
canvas.height = this.height;
|
||||
this.ctx = canvas.getContext("2d");
|
||||
document.getElementById("out").appendChild(canvas);
|
||||
this.directions = [{
|
||||
x: -1,
|
||||
y: -2
|
||||
}, {
|
||||
x: -2,
|
||||
y: -1
|
||||
}, {
|
||||
x: 1,
|
||||
y: -2
|
||||
}, {
|
||||
x: 2,
|
||||
y: -1
|
||||
},
|
||||
{
|
||||
x: -1,
|
||||
y: 2
|
||||
}, {
|
||||
x: -2,
|
||||
y: 1
|
||||
}, {
|
||||
x: 1,
|
||||
y: 2
|
||||
}, {
|
||||
x: 2,
|
||||
y: 1
|
||||
}
|
||||
];
|
||||
}
|
||||
}
|
||||
new KnightTour();
|
||||
294
Task/Knights-tour/JavaScript/knights-tour-2.js
Normal file
294
Task/Knights-tour/JavaScript/knights-tour-2.js
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
(() => {
|
||||
'use strict';
|
||||
|
||||
// knightsTour :: Int -> [(Int, Int)] -> [(Int, Int)]
|
||||
const knightsTour = rowLength => moves => {
|
||||
const go = path => {
|
||||
const
|
||||
findMoves = xy => difference(knightMoves(xy), path),
|
||||
warnsdorff = minimumBy(
|
||||
comparing(compose(length, findMoves))
|
||||
),
|
||||
options = findMoves(path[0]);
|
||||
return 0 < options.length ? (
|
||||
go([warnsdorff(options)].concat(path))
|
||||
) : reverse(path);
|
||||
};
|
||||
|
||||
// board :: [[(Int, Int)]]
|
||||
const board = concatMap(
|
||||
col => concatMap(
|
||||
row => [
|
||||
[col, row]
|
||||
],
|
||||
enumFromTo(1, rowLength)),
|
||||
enumFromTo(1, rowLength)
|
||||
);
|
||||
|
||||
// knightMoves :: (Int, Int) -> [(Int, Int)]
|
||||
const knightMoves = ([x, y]) =>
|
||||
concatMap(
|
||||
([dx, dy]) => {
|
||||
const ab = [x + dx, y + dy];
|
||||
return elem(ab, board) ? (
|
||||
[ab]
|
||||
) : [];
|
||||
}, [
|
||||
[-2, -1],
|
||||
[-2, 1],
|
||||
[-1, -2],
|
||||
[-1, 2],
|
||||
[1, -2],
|
||||
[1, 2],
|
||||
[2, -1],
|
||||
[2, 1]
|
||||
]
|
||||
);
|
||||
return go(moves);
|
||||
};
|
||||
|
||||
// TEST -----------------------------------------------
|
||||
// main :: IO()
|
||||
const main = () => {
|
||||
|
||||
// boardSize :: Int
|
||||
const boardSize = 8;
|
||||
|
||||
// tour :: [(Int, Int)]
|
||||
const tour = knightsTour(boardSize)(
|
||||
[fromAlgebraic('e5')]
|
||||
);
|
||||
|
||||
// report :: String
|
||||
const report = '(Board size ' +
|
||||
boardSize + '*' + boardSize + ')\n\n' +
|
||||
'Route: \n\n' +
|
||||
showRoute(boardSize)(tour) + '\n\n' +
|
||||
'Coverage and order: \n\n' +
|
||||
showCoverage(boardSize)(tour) + '\n\n';
|
||||
return (
|
||||
console.log(report),
|
||||
report
|
||||
);
|
||||
}
|
||||
|
||||
// DISPLAY --------------------------------------------
|
||||
|
||||
// algebraic :: (Int, Int) -> String
|
||||
const algebraic = ([x, y]) =>
|
||||
chr(x + 96) + y.toString();
|
||||
|
||||
// fromAlgebraic :: String -> (Int, Int)
|
||||
const fromAlgebraic = s =>
|
||||
2 <= s.length ? (
|
||||
[ord(s[0]) - 96, parseInt(s.slice(1))]
|
||||
) : undefined;
|
||||
|
||||
// showCoverage :: Int -> [(Int, Int)] -> String
|
||||
const showCoverage = rowLength => xys => {
|
||||
const
|
||||
intMax = xys.length,
|
||||
w = 1 + intMax.toString().length
|
||||
return unlines(map(concat,
|
||||
chunksOf(
|
||||
rowLength,
|
||||
map(composeList([justifyRight(w, ' '), str, fst]),
|
||||
sortBy(
|
||||
mappendComparing([
|
||||
compose(fst, snd),
|
||||
compose(snd, snd)
|
||||
]),
|
||||
zip(enumFromTo(1, intMax), xys)
|
||||
)
|
||||
)
|
||||
)
|
||||
));
|
||||
};
|
||||
|
||||
// showRoute :: Int -> [(Int, Int)] -> String
|
||||
const showRoute = rowLength => xys => {
|
||||
const w = 1 + rowLength.toString().length;
|
||||
return unlines(map(
|
||||
xs => xs.join(' -> '),
|
||||
chunksOf(
|
||||
rowLength,
|
||||
map(compose(justifyRight(w, ' '), algebraic), xys)
|
||||
)
|
||||
));
|
||||
};
|
||||
|
||||
|
||||
// GENERIC FUNCTIONS ----------------------------------
|
||||
|
||||
|
||||
// Tuple (,) :: a -> b -> (a, b)
|
||||
const Tuple = (a, b) => ({
|
||||
type: 'Tuple',
|
||||
'0': a,
|
||||
'1': b,
|
||||
length: 2
|
||||
});
|
||||
|
||||
// chr :: Int -> Char
|
||||
const chr = x => String.fromCodePoint(x);
|
||||
|
||||
// chunksOf :: Int -> [a] -> [[a]]
|
||||
const chunksOf = (n, xs) =>
|
||||
enumFromThenTo(0, n, xs.length - 1)
|
||||
.reduce(
|
||||
(a, i) => a.concat([xs.slice(i, (n + i))]),
|
||||
[]
|
||||
);
|
||||
|
||||
// compare :: a -> a -> Ordering
|
||||
const compare = (a, b) =>
|
||||
a < b ? -1 : (a > b ? 1 : 0);
|
||||
|
||||
// comparing :: (a -> b) -> (a -> a -> Ordering)
|
||||
const comparing = f =>
|
||||
(x, y) => {
|
||||
const
|
||||
a = f(x),
|
||||
b = f(y);
|
||||
return a < b ? -1 : (a > b ? 1 : 0);
|
||||
};
|
||||
|
||||
// compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
|
||||
const compose = (f, g) => x => f(g(x));
|
||||
|
||||
// composeList :: [(a -> a)] -> (a -> a)
|
||||
const composeList = fs =>
|
||||
x => fs.reduceRight((a, f) => f(a), x, fs);
|
||||
|
||||
// concat :: [[a]] -> [a]
|
||||
// concat :: [String] -> String
|
||||
const concat = xs =>
|
||||
0 < xs.length ? (() => {
|
||||
const unit = 'string' !== typeof xs[0] ? (
|
||||
[]
|
||||
) : '';
|
||||
return unit.concat.apply(unit, xs);
|
||||
})() : [];
|
||||
|
||||
// concatMap :: (a -> [b]) -> [a] -> [b]
|
||||
const concatMap = (f, xs) =>
|
||||
xs.reduce((a, x) => a.concat(f(x)), []);
|
||||
|
||||
|
||||
// difference :: Eq a => [a] -> [a] -> [a]
|
||||
const difference = (xs, ys) => {
|
||||
const s = new Set(ys.map(str));
|
||||
return xs.filter(x => !s.has(str(x)));
|
||||
};
|
||||
|
||||
// elem :: Eq a => a -> [a] -> Bool
|
||||
const elem = (x, xs) => xs.some(eq(x))
|
||||
|
||||
|
||||
// enumFromThenTo :: Int -> Int -> Int -> [Int]
|
||||
const enumFromThenTo = (x1, x2, y) => {
|
||||
const d = x2 - x1;
|
||||
return Array.from({
|
||||
length: Math.floor(y - x2) / d + 2
|
||||
}, (_, i) => x1 + (d * i));
|
||||
};
|
||||
|
||||
// enumFromTo :: Int -> Int -> [Int]
|
||||
const enumFromTo = (m, n) =>
|
||||
Array.from({
|
||||
length: 1 + n - m
|
||||
}, (_, i) => m + i);
|
||||
|
||||
// eq (==) :: Eq a => a -> a -> Bool
|
||||
const eq = a => b => {
|
||||
const t = typeof a;
|
||||
return t !== typeof b ? (
|
||||
false
|
||||
) : 'object' !== t ? (
|
||||
'function' !== t ? (
|
||||
a === b
|
||||
) : a.toString() === b.toString()
|
||||
) : (() => {
|
||||
const kvs = Object.entries(a);
|
||||
return kvs.length !== Object.keys(b).length ? (
|
||||
false
|
||||
) : kvs.every(([k, v]) => eq(v)(b[k]));
|
||||
})();
|
||||
};
|
||||
|
||||
// fst :: (a, b) -> a
|
||||
const fst = tpl => tpl[0];
|
||||
|
||||
// justifyRight :: Int -> Char -> String -> String
|
||||
const justifyRight = (n, cFiller) => s =>
|
||||
n > s.length ? (
|
||||
s.padStart(n, cFiller)
|
||||
) : s;
|
||||
|
||||
|
||||
// length :: [a] -> Int
|
||||
const length = xs =>
|
||||
(Array.isArray(xs) || 'string' === typeof xs) ? (
|
||||
xs.length
|
||||
) : Infinity;
|
||||
|
||||
// map :: (a -> b) -> [a] -> [b]
|
||||
const map = (f, xs) =>
|
||||
(Array.isArray(xs) ? (
|
||||
xs
|
||||
) : xs.split('')).map(f);
|
||||
|
||||
// mappendComparing :: [(a -> b)] -> (a -> a -> Ordering)
|
||||
const mappendComparing = fs =>
|
||||
(x, y) => fs.reduce(
|
||||
(ordr, f) => (ordr || compare(f(x), f(y))),
|
||||
0
|
||||
);
|
||||
|
||||
// minimumBy :: (a -> a -> Ordering) -> [a] -> a
|
||||
const minimumBy = f => xs =>
|
||||
xs.reduce((a, x) => undefined === a ? x : (
|
||||
0 > f(x, a) ? x : a
|
||||
), undefined);
|
||||
|
||||
// ord :: Char -> Int
|
||||
const ord = c => c.codePointAt(0);
|
||||
|
||||
// reverse :: [a] -> [a]
|
||||
const reverse = xs =>
|
||||
'string' !== typeof xs ? (
|
||||
xs.slice(0).reverse()
|
||||
) : xs.split('').reverse().join('');
|
||||
|
||||
// snd :: (a, b) -> b
|
||||
const snd = tpl => tpl[1];
|
||||
|
||||
// sortBy :: (a -> a -> Ordering) -> [a] -> [a]
|
||||
const sortBy = (f, xs) =>
|
||||
xs.slice()
|
||||
.sort(f);
|
||||
|
||||
// str :: a -> String
|
||||
const str = x => x.toString();
|
||||
|
||||
// take :: Int -> [a] -> [a]
|
||||
// take :: Int -> String -> String
|
||||
const take = (n, xs) =>
|
||||
xs.slice(0, n);
|
||||
|
||||
// unlines :: [String] -> String
|
||||
const unlines = xs => xs.join('\n');
|
||||
|
||||
// Use of `take` and `length` here allows for zipping with non-finite
|
||||
// lists - i.e. generators like cycle, repeat, iterate.
|
||||
|
||||
// zip :: [a] -> [b] -> [(a, b)]
|
||||
const zip = (xs, ys) => {
|
||||
const lng = Math.min(length(xs), length(ys));
|
||||
const bs = take(lng, ys);
|
||||
return take(lng, xs).map((x, i) => Tuple(x, bs[i]));
|
||||
};
|
||||
|
||||
// MAIN ---
|
||||
return main();
|
||||
})();
|
||||
Loading…
Add table
Add a link
Reference in a new issue