727.834.1235 samuelcferrell@gmail.com Tampa Bay Area avatar github.com/samuelcferrell

Samuel Ferrell

"Yes! The Great Cthulhu requires groupies!"

About

Programming is my craft. Most of my experience is with the web, but my budding loves are 2D game development, simulation, and algorithm implementation.

A more formal resume is available upon request, but please consider my public projects and code as the canonical demonstration of my ability.

My area of residency is flexible.

Work

Chess – View Demo, Github
Written in Javascript & HTML5 Canvas
Graph – Github
Types, graphs, and algorithms like A*, written in Javascript
Leviatha – Github
Diablo 2 Database Directory written in PHP & Fat Free Framework

Personal Photos

Samuel Ferrell Rachel Ferrell Justin Rump Amanda Rump Jordan Rump Penny Pie

Links

Rachel Ferrell's Portfolio
http://www.rachferrell.com/
Amit's Game Programming
http://www-cs-students.stanford.edu/~amitp/gameprog.html
Animated Bezier Curves
http://www.jasondavies.com/animated-bezier/

Samuel Ferrell, 2012

/* A* Optimal Graph Search */ function Path(graph, start, end, heuristic) { var openSet, begin; // Out of graph bounds if (!graph.inBounds(start) || !graph.inBounds(end)) { return false; } // Heuristic function heuristic = heuristic || Path.manhattan; // Open set openSet = new BinaryHeap(function (element) { return element.fscore; }); // First node begin = graph.nodes[start]; begin.gscore = 0; begin.hscore = heuristic(begin.index, end); begin.fscore = begin.gscore + begin.hscore; openSet.push(begin); while (openSet.heap.length) { var current = openSet.pop(); if (current.index == end) { return Path.reconstruct(current); } else { current.closed = true; var neighbors = graph.neighbors(current); var i; for (i = 0; i < neighbors.length; i += 1) { var neighbor = neighbors[i]; if (neighbor.closed === true) { continue; } var cost = current.gscore + 1; var visited = neighbor.visited; if (!visited || cost < neighbor.gscore) { neighbor.visited = true; neighbor.parent = current; neighbor.hscore = heuristic(neighbor.index, end); neighbor.gscore = cost; neighbor.fscore = neighbor.hscore + neighbor.gscore; if (!visited) { openSet.push(neighbor); } else { openSet.rescoreElement(neighbor); } } } } } return false; } /* 2D Vector */ function Vec2(x, y) { this.x = x || 0; this.y = y || 0; this.magcache = Vec2.magnitude(this); } /* Addition a + b = c */ Vec2.add = function (a, b) { return new Vec2(a.x + b.x, a.y + b.y); }; /* Subtraction a - b = c */ Vec2.subtract = function (a, b) { return new Vec2(a.x - b.x, a.y - b.y); }; /* Multiplication a * t = b */ Vec2.multiply = function (a, t) { return new Vec2(round(t * a.x, 4), round(t * a.y, 4)); }; /* Direction arc tangent (a.x / a.y) */ Vec2.direction = function (a) { return round(Math.atan(a.y / a.x), 4); }; /* Distance a^2 + b^2 = c^2 */ Vec2.distance = function (a, b) { return round(Math.sqrt(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2)), 4); }; /* Negation a = -a */ Vec2.negative = function (a) { return Vec2.multiply(a, -1); }; /* Linear Interpolation t * ((b - a) + a) = c */ Vec2.interpolate = function (a, b, t) { return Vec2.multiply(Vec2.add(Vec2.subtract(b, a), a), t); }; /* Normalization a * (1 / magnitude(a)) */ Vec2.normalize = function (a) { return Vec2.multiply(a, 1 / (Vec2.magnitude(a))); }; /* Magnitude a^2 = c^2 */ Vec2.magnitude = function (a) { // Use raw object to avoid cache recursion return Vec2.distance(a, {x: 0, y: 0}); } /* Linear Vector Interpolation Tween */ return { queue: [], lerp: function (p, a, b, duration, callback, target) { if (Vec2.isEqual(a, b)) { if (typeof callback === 'function' && typeof target !== 'undefined') { callback.apply(target); } return; } this.queue.push({ p: p, a: a.clone(), b: b.clone(), duration: duration, distance: Vec2.distance(a, b), fn: callback, trgt: target, t: 0 }); }, update: function (dt) { if (this.queue.length) { var i, q, t = 0; for (i = 0; i < this.queue.length; i += 1) { // Shorthand Identifier q = this.queue[i]; // Calculate step t = 1 / (q.distance / (q.distance / (q.duration * dt))); // Offset queued step q.t += t; if ((q.t) >= 1) { // We're home q.p.place(q.b); this.queue.remove(i); if (typeof q.fn === 'function') { return q.fn.apply(q.trgt); } } else { // Not there yet q.p.place(Vec2.interpolate(q.a, q.b, q.t)); } } } } } /* Chess Board Move Generation */ function generate(piece) { var i, j, n, offsets, distance, occupying, offset, generated = [], offsets = piece.getOffsets(); distance = piece.getDistance(); for (i = 0; i < offsets.length; i += 1) { offset = offsets[i]; n = piece.position; for (j = 0; j < distance; j += 1) { n = mailbox[mailbox64[n] + offset]; // Illegal - Offboard if (n === -1) { break; } // Pawn - Movement + Capture Fixes if (piece.isType("Pawn")) { if (offset === 10 || offset === -10) { if (this.isOccupied(n)) { break; } } else { if (!this.isOccupied(n)) { break; } } } if (piece.isType("King")) { var enemy = piece.isColor("White") ? "Black" : "White"; if (_.contains(this[enemy], n)) { break; } } // Capture if (this.isOccupied(n)) { occupying = this.fetch(n); if (piece.isEnemy(occupying)) { generated.push(n); break; } break; } // Open generated.push(n); } } return generated; };