Last active
June 2, 2017 14:28
-
-
Save expalmer/541ac417ec5e17a51b40e90bd4ab42b6 to your computer and use it in GitHub Desktop.
IA
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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