Skip to content

cgeorg/todomvp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

26 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

TODO: Minimum Viable Pizza

Let's face it: todo lists are overdone. We know what we need to do - we need to order pizza. But how much?

The TODO: MVP algorithm accepts the following inputs:

  • A standard "slice" size
  • Total number of slices that the group desires
  • The pizza sizes and prices of the pizza shop

The TODO: MVP algorithm will in turn recommend several pizza ordering options that will satisfy the group's cravings.

What can I do with it?

Well, you could use it to figure out what pizza to order. You could also use it instead of TodoMVC to try out a new library/framework/etc.

How does the MVP algorithm work?

It just generates permutations of all of the pizza configurations that order enough pizza, without ordering an extra pizza, and then ranks and sorts them on several axes.

Reference Implementation

var _ = require('lodash');

function mvp(numServings, servingSize, pizzas, sortBy) {
  var totalSize = numServings * servingSize;

  pizzas = _.sortBy(pizzas, 'diameter').reverse();

  function updateTotal(option) {
    option.total = _(option.pizzas)
      .map('diameter')
      .map(d => d / 2)
      .map(r => r * r)
      .map(r2 => r2 * Math.PI)
      .reduce((sum, area) => area + sum);
  }

  function addPizza(option, options, index) {
    index = index || 0;
    if (option.total > totalSize) {
      options.push(option);
    } else {
      for (let i = index; i < pizzas.length; ++i) {
        var newOp = {pizzas: _.clone(option.pizzas)};
        newOp.pizzas.push(pizzas[i]);
        updateTotal(newOp);
        addPizza(newOp, options, i);
      }
    }
    return options;
  }

  return _(addPizza({pizzas: [], total: 0}, []))
    .flatten()
    .tap(options => console.log(`Found ${options.length} options`))
    .forEach(option => {
      option.cost = _(option.pizzas)
        .map('cost')
        .reduce((sum, cost) => sum + cost);
      option.ratio = option.cost / option.total;
    })
    .sortBy('ratio')
    .forEach((option, index) => option.order = index + 1)
    .sortBy('total')
    .forEach((option, index) => option.order += index)
    .sortBy(sortBy)
    .take(10)
    .sortBy('total')
    .tap(options => options[options.length - 1].special = 'Most pizza! ')
    .sortBy('ratio')
    .tap(options => options[0].special = (options[0].special ? options[0].special : '') + 'Best deal!')
    .sortBy(sortBy)
    .value();
}

var topTenPizzas = mvp(20 /*slices of pizza*/, 20 /*square inches per slice*/, [
  {name: 'Large', diameter: 16, cost: 12.95},
  {name: 'Medium', diameter: 14, cost: 9.95},
  {name: 'Small', diameter: 12, cost: 8.95}
] /* Monte Cellos' pizza menu */, 'order' /* sort by PizzaRank */);

About

Minimum Viable Pizza

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages