diff --git a/README.md b/README.md index 02f6ee1..6022bfd 100644 --- a/README.md +++ b/README.md @@ -28,3 +28,12 @@ This one is not working. Not bothering to fix it, got no git history. Functional implementation. ![fp](fp/recording.gif "Functional") + + +## Functional with RLE rules + +By Patrik Torkildsen. +Implements [Run Length Encoded (RLE)](https://conwaylife.com/wiki/Run_Length_Encoded) rules. + +![fp](fp-rle/recording.gif "Functional RLE") + diff --git a/fp-rle/ca-fp.html b/fp-rle/ca-fp.html new file mode 100644 index 0000000..50bb677 --- /dev/null +++ b/fp-rle/ca-fp.html @@ -0,0 +1,35 @@ + + + + CA + + + + + +
+ +
+ + + + diff --git a/fp-rle/ca-fp.js b/fp-rle/ca-fp.js new file mode 100644 index 0000000..535a7ef --- /dev/null +++ b/fp-rle/ca-fp.js @@ -0,0 +1,190 @@ +"use strict"; + +var patterns = { + + 'gospelgun': { + x: 36, + rle: "24bo11b22bobo11b12b2o6b2o12b2o11bo3bo4b2o12b2o2o8bo5bo3b2o14b2o8bo3bob2o4bobo11b10bo5bo7bo11b11bo3bo20b12b2o22b" +}, + + 'diamond': { + + x: 12, + rle: '4b4o4b12b2b8o2b12b12o12b2b8o2b12b4b4o4b' + + }, + + 'flammenkamp': { + x: 13, + rle: '7b2o4b7bobo3b2bo4bob2o2bb2o5bo4bo2bo9b3o10b23b3o9bo2bo4bo5b2ob2b2obo4bo2b3bobo7b4b2o7b' + }, + + 'c2ship': { + x: 13, + rle: '1o12b4o9b2b2o9b5b1o7b6o7b6b1o1b1o4bobob6o3bob2o5b2o2b4b2o4b2ob5o4b2o2b13b5o4b2o2b4b2o4b2obob2o5b2o2bobob6o3b6b1o1b1o4b6o7b5b1o7b2b2o9b4o9bo12b' + } + +}; + + + +function curry(fn) { + return function(...args) { + if(fn.length > args.length) { + var arg = args; + return function(...args) {return fn.apply(null, arg.concat(args));}; + } + return fn.apply(null, args); + }; +} + + +function compose(f,g) { + return function(x) { return f(g(x)); }; +} + + +function pipe(...fns) { + return fns.reduce(compose); +} + +var getEle = curry(function(ele) { + return (document.querySelectorAll(ele).length === 1) ? document.querySelector(ele) : [...document.querySelectorAll(ele)]; +}); + +var map = curry(function(fn,arr) { + return Array.prototype.map.call(arr, fn); +}); + +var get = curry(function(what,x) { + return x[what]; +}); + + +var forEach = curry(function(fn,arr) { + return Array.prototype.forEach.call(arr, fn); + +}); + + +var log = function(x) { + console.log(x); return x; +}; + + +var calcRules = function(ele, index, arr) { + +var gridLength = Math.sqrt(arr.length); + +var r = Math.floor(index/gridLength); + +var neighbours = + arr[(index-1+arr.length)%arr.length]+ + arr[(index - gridLength+arr.length)%arr.length]+ + arr[(index + gridLength+arr.length)%arr.length]+ + arr[(index+1+arr.length)%arr.length]+ + arr[(index - gridLength - 1+arr.length)%arr.length]+ + arr[(index - gridLength + 1+arr.length)%arr.length]+ + arr[(index + gridLength - 1+arr.length)%arr.length]+ + arr[(index + gridLength + 1+arr.length)%arr.length]; + +if((ele === 1 && neighbours < 2) || (ele === 1 && neighbours > 3)) { + return 0; +} + +if((ele === 1 && neighbours === 2) || (ele === 1 && neighbours === 3)) { + return 1; +} + +if(ele === 0 && neighbours === 3) { + return 1; +} + +else { + return ele; +} + +}; + + +var getCanvas = curry(function(type, id) { + return HTMLCanvasElement.prototype.getContext.call(getEle(id), type); +}); + + + +var draw = curry(function(ctx, arr) { + ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); + forEach((ele, index)=>{ + if(ele === 1) { + var gridLength = Math.sqrt(arr.length); + var r = Math.floor(index/gridLength); + ctx.fillStyle = "#000000"; + ctx.fillRect(index%gridLength*ctx.canvas.width/gridLength+0.5, + r*ctx.canvas.height/gridLength+0.5, + ctx.canvas.width/gridLength-0.5, + ctx.canvas.height/gridLength-0.5); + ctx.fillStyle = "#cccccc"; + ctx.fillRect(index%gridLength*ctx.canvas.width/gridLength+1.0, + r*ctx.canvas.height/gridLength+1.0, + ctx.canvas.width/gridLength-1.0, + ctx.canvas.height/gridLength-1.0); + } + + },arr); + + var fps = setTimeout(()=>{ + clearTimeout(fps); + newState(arr); + + },1000/60); +}); + +var decodeRLE = function(str) { + return str.replace(/(\d+)(\w)/g, + function(m,n,c){ + return new Array( parseInt(n,10)+1 ).join(c); + }); +}; + +var arrayPattern = function(ele) { return ele==="b"?0:1; }; + +var generateGrid = function(initPattern) { + //var size = 512; + var size = 256; + var grid = []; + while(grid.length < size*size) { + if(initPattern.length && grid.length%size === (size/2) - Math.ceil(initPattern[0].length/2) + && grid.length/size > (size/2) - Math.ceil(initPattern.length/2)) { + grid.push(...initPattern.shift()); + } else { + grid.push(0); + } + + } + + return grid; +}; + +var rleArray = compose(map(arrayPattern), decodeRLE); + +var to2dArr = function(pattern) { + var arr = rleArray(patterns[pattern].rle); + var result = []; + var chunk = patterns[pattern].x; + while(arr.length !== 0) { + result.push(arr.splice(0, chunk)); + } + return result; +}; + +var newState = compose(draw(getCanvas('2d', '#board')), map(calcRules)); + +var setInitGrid = compose(generateGrid, to2dArr); + +var render = compose(newState, setInitGrid); + +render('gospelgun'); +//render('diamond'); +//render('flammenkamp'); +//render('c2ship'); diff --git a/fp-rle/recording.gif b/fp-rle/recording.gif new file mode 100644 index 0000000..feaf3a7 Binary files /dev/null and b/fp-rle/recording.gif differ