Skip to content

Instantly share code, notes, and snippets.

@expalmer
Last active June 2, 2017 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save expalmer/541ac417ec5e17a51b40e90bd4ab42b6 to your computer and use it in GitHub Desktop.
Save expalmer/541ac417ec5e17a51b40e90bd4ab42b6 to your computer and use it in GitHub Desktop.
IA
const Box = x => (
{
map: f => Box(f(x)),
fold: f => f(x)
}
);
const splitEvery = (list, n) => {
const result = [];
let idx = 0;
while (idx < list.length) {
result.push(list.slice(idx, idx += n, list));
}
return result;
}
const random = (len, v) => {
v = v || -1;
const n = Math.floor(Math.random() * len);
return n !== v ? n : random(len, v);
}
const n = {
a: { b: 10, c: 153, d: 42, e: 37, f: 920, g: 410, h: 13 },
b: { a: 10, c: 8 , d: 27, e: 93, f: 45 , g: 21 , h: 18 },
c: { a: 153, b: 8 , d: 3 , e: 21, f: 97 , g: 410, h: 38 },
d: { a: 42, b: 27, c: 3 , e: 22, f: 45 , g: 81 , h: 6 },
e: { a: 37, b: 93, c: 21 , d: 22, f: 19 , g: 80 , h: 13 },
f: { a: 920, b: 45, c: 97 , d: 45, e: 19, g: 18 , h: 23 },
g: { a: 410, b: 21, c: 410, d: 81, e: 80, f: 18 , h: 5 },
h: { a: 13, b: 18, c: 38 , d: 6 , e: 13, f: 23 , g: 5 }
};
const initialCromos = [
[ 'a', 'e', 'd', 'h', 'b', 'f', 'c', 'g' ],
[ 'h', 'f', 'c', 'g', 'e', 'a', 'b', 'd' ],
[ 'c', 'g', 'h', 'f', 'e', 'a', 'd', 'b' ],
[ 'a', 'h', 'b', 'g', 'c', 'f', 'd', 'e' ]
];
function distance(a, b) {
return n[a][b];
}
function identity(id) {
console.log(id)
return id;
}
function orderEndToEnd(cromo) {
const idx = cromo.indexOf('a');
const res = cromo.slice(idx).concat(cromo.slice(0, idx));
res.push('a');
return res;
}
function calculeDistance(index) {
return cromo =>
cromo.slice(1)
.reduce((acc, x) => {
acc.res.total += distance(acc.prev, x);
acc.prev = x;
return acc;
}, { prev: cromo[0], res: { total: 0, index } })
}
function getTotalByCromo(cromos) {
return Box(cromos)
.map(cromos =>
cromos
.map((cromo, index) =>
Box(cromo)
.map(orderEndToEnd)
.map(calculeDistance(index))
.fold(x => x.res)
)
)
.map(total =>
total.sort((a, b) => a['total'] < b['total'] ? -1 : a['total'] > b['total'] ? 1 : 0)
)
.fold(sorted => sorted);
}
function fix(mask, child, mom) {
return Box(
mom.reduce((acc, x) => {
if (child.indexOf(x) === -1) {
acc.push(x);
}
return acc;
}, []))
.fold(orfan =>
mask.map((i, idx) => {
if (i === 1 ) {
if ( child.join('').match(new RegExp(child[idx], 'g')).length >= 2) {
child[idx] = orfan.shift();
}
}
return child[idx];
})
)
}
function xmen(cromo) {
const a = random(8);
const b = random(8, a);
const aux = cromo[a];
cromo[a] = cromo[b];
cromo[b] = aux;
return cromo;
}
function mutation(cromos) {
return Box(cromos)
.fold(cromos => cromos.map(xmen));
}
const mask1 = [0, 1, 0, 1, 0, 1, 0, 1];
const mask2 = [0, 0, 0, 0, 1, 1, 1, 1];
function born(dad, mom) {
let child1 = Box(
mask1.map((i, idx) => (i === 0 ? dad[idx] : mom[idx]))
)
.fold(child => fix(mask1, child, mom));
let child2 = Box(
mask2.map((i, idx) => (i === 0 ? dad[idx] : mom[idx]))
)
.fold(child => fix(mask2, child, mom));
return [ child1, child2];
}
function getNewCromos(total, cromos) {
return Box(total)
.map(total => total.map(i => cromos[i.index]))
.map(cromos => splitEvery(cromos, 2))
.map(chunks => chunks
.reduce((acc, chunk, index) => {
const children = chunk.reduce((a,b) => born(a, b));
return acc.concat(children);
}, []))
.map(mutation)
.fold(cromos => cromos);
}
function run(cromos, obj, times) {
if (times ===0) {
console.log("\x1b[31m", "END")
return obj;
}
console.log("\x1b[2m", `===> ${times}`);
const res = getTotalByCromo(cromos);
if (res[0].total < obj.total) {
obj = { cromo: cromos[res[0].index], total: res[0].total };
}
const nextCromos = getNewCromos(res, cromos);
return run(nextCromos, obj, times - 1);
}
const res = run(initialCromos, { cromo: [], total: 20000 }, 2000);
console.log(res);
/*
CHAMAR O PROGRAMA
cubo times
node index.js 3 100
*/
const TIMES = process.argv[3] || 10;
const SQUARE = process.argv[2] || 3;
const MATRIZ = SQUARE * SQUARE;
const MAGIC = ((n) => n * ((n*n + 1)/2))(SQUARE);
const Box = x => (
{
map: f => Box(f(x)),
fold: f => f(x)
}
);
const log = (...args) => { console.log(args.toString()) };
function identity(id) {
console.log(id)
return id;
}
const splitEvery = (list, n) => {
const result = [];
let idx = 0;
while (idx < list.length) {
result.push(list.slice(idx, idx += n, list));
}
return result;
}
const random = (min, max) => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
const randomNotRepeat = (min, max, v) => {
const n = random(min, max);
if (n === v) return randomNotRepeat(min, max, v);
return n;
}
// const mask = (a, b) => Array(MATRIZ).fill(1).map((i,k,z) => k < Math.abs(z.length/2) ? a : b );
const mask = (a, b) => Array(MATRIZ).fill(1).map(() => random(0,1));
const mask1 = mask(0,1);
const mask2 = mask(1,0);
const getInitialCromos = (len, arr) => {
if (arr.length === len) {
return arr;
}
const n = random(1, len);
if (arr.indexOf(n) === -1) {
arr.push(n);
}
return getInitialCromos(len, arr);
};
const initialCromos = [0, 0, 0, 0].map(() => getInitialCromos(MATRIZ, []));
const sum = (a, b) => a + b;
function sumEvery(arr, len, every) {
let i = 0;
let res = [];
while (i < len) {
res[i] = res[i] || [];
res[i].push() = res[i][i] + arr[i + every];
i++;
}
return res;
}
function calculeOneCromo(arr, index) {
return Box(arr)
// .map(identity)
.map(arr => {
const rows = splitEvery(arr, SQUARE);
const lines = rows.slice(0).reduce((acc, y) => {
y.forEach((i, iIDX) => {
acc[iIDX] = acc[iIDX] || [];
acc[iIDX].push(i);
});
return acc;
}, []);
const crossLeft = rows.slice(0).reduce((acc, z, zIndex) => {
acc.push(z[zIndex]);
return acc;
}, []);
const crossRight = rows.slice(0).reduce((acc, w, wIndex, list) => {
let i = (w.length - 1) - wIndex;
acc.push(w[i]);
return acc;
}, []);
return rows.concat(lines).concat([crossLeft, crossRight]);
})
.map(arr =>
arr.reduce((acc, i, idx) => {
const total = i.reduce(sum);
// log(i, '=>', total, '-', MAGIC);
if (total === MAGIC) {
acc.total += 1;
}
return acc;
}, { total: 0, index: index, perfect: false }))
.fold(x => x);
}
function getTotalByCromo(cromos) {
return Box(cromos)
.map(cromos => cromos.map(calculeOneCromo))
.map(total =>
total.sort((a, b) => a['total'] < b['total'] ? -1 : a['total'] > b['total'] ? 1 : 0).reverse()
)
.fold(x => x);
}
function getIndexIfIsPerfect(obj) {
return Object.keys(obj)
.reduce((acc, key) => {
if (obj[key].perfect) {
acc.index = obj[key].index;
}
return acc;
}, { index: -1 });
}
function fix(mask, child, mom) {
return Box(
mom.reduce((acc, x) => {
if (child.indexOf(x) === -1) {
acc.push(x);
}
return acc;
}, []))
.fold(orfan =>
mask.map((i, idx) => {
if (i === 1 ) {
if ( child.join('').match(new RegExp(child[idx], 'g')).length >= 2) {
child[idx] = orfan.shift();
}
}
return child[idx];
})
)
}
function getNewCromos(total, cromos) {
return Box(total)
.map(total => total.map(i => cromos[i.index]))
.map(i => splitEvery(i, 2))
.map(chunks => chunks
.reduce((acc, chunk, index) => {
const children = chunk.reduce((a, b) => born(a, b));
return acc.concat(children);
}, []))
.map(children => children.map(mutation))
.fold(x => x);
}
function born(dad, mom) {
let child1 = Box(
mask1.map((i, idx) => (i === 0 ? dad[idx] : mom[idx]))
)
.fold(child => fix(mask1, child, mom));
let child2 = Box(
mask2.map((i, idx) => (i === 0 ? dad[idx] : mom[idx]))
)
.fold(child => fix(mask2, child, mom));
return [child1, child2];
}
function mutation(cromo) {
const a = random(0, MATRIZ - 1);
const b = randomNotRepeat(0, MATRIZ - 1, a);
const aux = cromo[a];
cromo[a] = cromo[b];
cromo[b] = aux;
return cromo;
}
function run(cromos, obj, times) {
const res = getTotalByCromo(cromos);
const done = getIndexIfIsPerfect(res);
if (done.index !== -1) {
console.log("\x1b[31m", "ACHEI")
return;
}
if (times === 0) {
console.log("\x1b[31m", "NAO ACHEI");
return;
}
if (res[0].total > obj.total) {
obj = { cromo: cromos[res[0].index], total: res[0].total };
}
console.log(times);
console.log('total', res[0].total, cromos[res[0].index]);
const nextCromos = getNewCromos(res, cromos);
return run(nextCromos, obj, times - 1);
}
run(initialCromos, { cromo: [], total: 0 }, TIMES);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment