Last active
June 1, 2017 03:56
-
-
Save taylorsmithgg/c3d234b37c823be7695e to your computer and use it in GitHub Desktop.
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
// https://github.com/taylorsmithgg | |
// A few code snippets from a current CMS project that I am developing for Detroit Labs that showcase using Angular | |
// to interact with RESTful services to populate a map dynamically. | |
// In lieu of Express, I am currently using Meteor, which supports 3-way data bindings. | |
// I am also using Angular Material for its directives and Babel for polyfill support | |
$scope.$on('mapInitialized', function(event, evtMap) { | |
map = evtMap; | |
map.singleInfoWindow = true; | |
}); | |
$scope.mapClick = function(event, showInfoWindow, item) { | |
var info = item.post_name + '_info'; | |
showInfoWindow(map, info, event.latLng); | |
$scope.setResult(item); | |
}; | |
$scope.closeResult = function(){ | |
$scope.showResult = false; | |
$scope.selectedResult = undefined; | |
var latLng = new window.google.maps.LatLng(44, -83); | |
map.setZoom(6); | |
map.setCenter(latLng); | |
}; | |
$scope.setResult = function(result){ | |
map.setZoom(15); | |
var latLng = new window.google.maps.LatLng(result.meta[0].gpsLatitude, result.meta[0].gpsLongitude); | |
console.log(latLng.lat(), latLng.lng()); | |
console.log(typeof latLng.lat(), typeof latLng.lng()); | |
map.setCenter(latLng); | |
$scope.selectedResult = result; | |
$scope.showResult = true; | |
$location.hash('top'); | |
$anchorScroll(); | |
}; | |
// Simple factory example of CPLEX operations using glpk.js for optimizing daily fantasy football statistics | |
// I am currently in the process of rewriting this with React + Ionic with the intention of shipping for browser | |
// and native mobile. | |
app.factory('optimize', [function(){ | |
return { | |
run: function(playerList, jsonConfig, salary, prevLineups, teams){ | |
$('.throbber-loader').show(); | |
var self = this; | |
var order = {QB: 1, RB: 2, WR: 3, TE: 4, FLEX: 5, K: 6,DST: 7}; | |
var chooChoo = myHeartWillGoOn(playerList, prevLineups); | |
if(chooChoo.length == playerList.length){ | |
return findTeam(jsonConfig.objective, playerList, jsonConfig); | |
} else { | |
return self.run(chooChoo, jsonConfig, salary, prevLineups, teams); | |
} | |
function findTeam(objective, playerList, config) { | |
var result = []; | |
var exclude = ""; // This is important for previous team removal! | |
var m = buildMaximize(objective, playerList); | |
var s = buildSubjectTo(salary, jsonConfig, playerList, prevLineups); | |
var b = buildBounds(playerList); | |
var g = buildGenerals(playerList); | |
try { | |
// This is important for previous team removal! | |
$.each(prevLineups, function (index, lineup) { | |
$.each(lineup, function (i, l) { | |
$.each(l.players, function (num, player) { | |
exclude += "+1 x" + player.id + "\n"; | |
}); | |
exclude += "<=" + ((l.players.length) - 1) + "\n"; | |
}); | |
}); | |
var cplex = m + s + exclude + b + g; | |
var prob = glp_create_prob(); | |
glp_read_lp_from_string(prob, null, cplex); | |
glp_scale_prob(prob, GLP_SF_AUTO); | |
var simplex = new SMCP({ | |
presolve: GLP_ON | |
}); | |
glp_simplex(prob, simplex); | |
glp_intopt(prob); | |
//var p = glp_mip_obj_val(prob); | |
// glp_simplex(prob, simplex), glp_intopt(prob), p = glp_mip_obj_val(prob), q = 1; | |
for (var q = 1; q <= glp_get_num_cols(prob); q++) { | |
if (glp_mip_col_val(prob, q) > 0) { | |
var playerResult = playerList.filter(function (player) { | |
return 'x' + player.id == glp_get_col_name(prob, q); | |
})[0]; | |
playerResult ? result.push(playerResult) : ''; | |
} | |
} | |
} catch(e) { | |
return {players: [], cplex: cplex}; | |
} | |
return sortTeam({players: result, cplex: cplex}, config); | |
} | |
function sortTeam(team, config) { | |
var lineup = team.players; | |
var rosterspots = config.rosterspots; | |
$.each(lineup, function (i, player) { | |
if (rosterspots[player.position].min < 0) { | |
player.position = 'FLEX'; | |
} | |
}); | |
return {players: lineup, cplex: team.cplex}; | |
} | |
function myHeartWillGoOn(playerList, prevLineups) { | |
prevLineups.length > 0 ? $.map(prevLineups, function(lineup){ | |
return $.map(lineup, function(l){ | |
$.each(l.players, function (index, player) { | |
var freq = frequency(prevLineups, player).number; | |
if(player.limit <= freq){ | |
playerList.splice(playerList.indexOf(player), 1); | |
} | |
}); | |
}); | |
}) : ''; | |
return playerList; | |
} | |
function buildMaximize(objective, players) { | |
var m = "Maximize\n"; | |
$.each(players, function (idx, player) { | |
var objectiveValue = player[objective.value]; | |
m += (parseFloat(objectiveValue) >= 0 ? '+ ' : '- ') + Math.abs(player[objective.value]).toString() + "\tx" + player.id + "\n"; | |
}); | |
m += '\n'; | |
return m; | |
} | |
function buildSubjectTo(salary, config, players, resultSets) { | |
var s = "Subject To\n"; | |
s += buildSubjectToSalary(salary, players, config); | |
s += buildSubjectToSpotCount(config, players, resultSets); | |
s += buildSubjectToTeamLimit(teams, config); | |
s += '\n'; | |
return s; | |
} | |
function buildSubjectToSalary(salary, players, config) { | |
var sals = ""; | |
var minSalary = salary.min; | |
var maxSalary = salary.max > config.salarycap ? config.salarycap : salary.max; | |
$.each(players, function (idx, player) { | |
sals += '+ ' + player.salary + ' x' + player.id + '\n'; | |
}); | |
return (minSalary > 0 ? sals + "=> " + minSalary + "\n" : "") + sals + "<= " + maxSalary + "\n\n"; | |
} | |
//pos | |
function buildSubjectToSpotCount(config, players, resultSets) { | |
var s = ""; | |
$.each(config.rosterspots, function (spot, info) { | |
var p = "\\* Position: " + spot + " *\\\n"; | |
$.each(info.Positions, function (i, pos) { | |
var playersByPos = players.filter(function(player){ | |
return player.position == pos; | |
}); | |
$.each(playersByPos, function (i, player) { | |
p += '+ 1 ' + 'x' + player.id + '\n'; | |
}); | |
}); | |
(info.min == info.max) ? s += p + "=" + info.min + "\n\n" : s += p + "=>" + info.min + "\n" + p + "<=" + info.max + "\n\n"; | |
}); | |
return s; | |
} | |
function frequency(resultSets, player){ | |
var percentMap = $.map(resultSets, function(resultSet){ | |
var mappedPlayers = $.map(resultSet, function(lineup){ | |
var players = lineup.players || []; | |
return players.filter(function(resultPlayer){ | |
return resultPlayer.id == player.id; | |
}); | |
}); | |
return mappedPlayers; | |
}); | |
var results = {percent: (percentMap.length / (resultSets.length == 0 ? 1 : resultSets.length) * 100).toFixed(1), number: percentMap.length}; | |
return results; | |
} | |
//team | |
function buildSubjectToTeamLimit(teams, config) { | |
var s = ""; | |
$.each(teams, function (index, team) { | |
s += "\\* Team: " + team.short + " *\\\n"; | |
var count = 0; | |
$.each(team.players, function(index, player){ | |
s += '+ 1 ' + 'x' + player.id + '\n'; | |
}); | |
s += "<=" + config.max_per_team + "\n"; | |
}); | |
return s; | |
} | |
function buildBounds(players) { | |
var b = "Bounds\n"; | |
$.each(players, function(idx, player) { | |
if (player.locked) { | |
b += 'x' + player.id + ' = 1\n'; | |
} else { | |
b += "0 <= " + 'x' + player.id + " <= 1\n"; | |
} | |
}); | |
return b; | |
} | |
function buildGenerals(players) { | |
var g = "Generals\n"; | |
$.each(players, function (idx, player) { | |
g += 'x' + player.id + "\n"; | |
}); | |
return g + "END\n"; | |
} | |
} | |
} | |
}]); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment