Skip to content

Instantly share code, notes, and snippets.

@stariqmi
Created May 15, 2016 17:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stariqmi/9726563242a47b361d8c149c42ddd3a0 to your computer and use it in GitHub Desktop.
Save stariqmi/9726563242a47b361d8c149c42ddd3a0 to your computer and use it in GitHub Desktop.
Shopify Coding Challenge
/*
Author: Salman Tariq Mirza
node/JavaScript solution to the Shopify Internship Coding Challenge
Assumptions:
- No duplicates, a flat list of the variants of all the products maintains uniqueness.
- For each computer there should be a keyboard.
- However if all computers/keyboards are purchased and there is still money left,
then spares need to be purchased of the remaining type.
Difficulties:
- Tried to use the product_type filter for Computer/Keyboard. Did not work,
returned products that were not Computers and Keyboards
Notes:
- hackathon.hardware.basic represents the pair of Computer/Keyboard pairs that need to be purchased
- Once shopicruit runs out of either computers or keyboards, we need to purchase spares of the remaining
type within the budget. This is represented by hackathon.hardware.spares
*/
// npm modules
var request = require('sync-request');
var _ = require('lodash');
// Initial state
var hackathon = {
shopicruit: {
url: 'http://shopicruit.myshopify.com/products.json',
keyboards: [],
computers: []
},
weights: {
regular: 0,
spare: 0
},
hardware: { // Purchase list
basic: [], // Pairs of computers/keyboards
spares: { // Spare parts
keyboards: [],
computers: [],
category: ''
},
},
budget: 1000.00
};
/**
* Function to purchase a pair of computer and keyboard. Stack like behavior.
* @param object hackathon reference object that stores the state of the hackathon
* @return boolean indicates wether Alice was able to purchase a pair or not
*/
function purchaseHardware(hackathon) {
var store = hackathon.shopicruit;
var hardware = hackathon.hardware;
var weights = hackathon.weights;
// Check that both have something left
if (store.computers.length > 0 && store.keyboards.length > 0) {
var c = store.computers.shift();
var k = store.keyboards.shift();
// Check if we still have money left
hackathon.budget -= (parseFloat(c.price) + parseFloat(k.price));
// If we don't, we stop buying
if (hackathon.budget < 0) return false;
hardware.basic.push({computer: c, keyboard: k});
weights.regular += (c.grams + k.grams);
return true;
}
return false;
}
/**
* Function to purchase spare parts
* @param object hackathon reference object that stores the state of the hackathon
*/
function purchaseSpares(hackathon) {
var spareCategory = (hackathon.shopicruit.keyboards.length === 0) ? 'computers' : 'keyboards';
hackathon.hardware.spares.category = spareCategory;
while(hackathon.budget > 0) {
var c = hackathon.shopicruit[spareCategory].shift();
hackathon.budget -= parseFloat(c.price);
if (hackathon.budget < 0) hackathon.budget = 0;
else {
hackathon.hardware.spares[spareCategory].push(c);
hackathon.weights.spare += c.grams;
}
}
}
/**
* Function to fetch products of type from shopicruit
* @param object hackathon reference object that stores the state of the hackathon
* @param integer page page number to search
*/
function getProducts(hackathon, page) {
var hasProducts = true;
var store = hackathon.shopicruit;
var reqUrl = hackathon.shopicruit.url + '?page=' + page + '&limit=' + 250;
var res = request('GET', reqUrl);
// Shopify is not happy!
if (res.statusCode !== 200) throw(new Error('Request failed with status code ' + res.statusCode + '.\nResponse: ' + res.getBody()));
var products = JSON.parse(res.getBody()).products;
// No more products
if (products.length === 0) hasProducts = false;
_.each(products, function(product) {
var variants = _.filter(product.variants, function(v) {
return v.available;
});
switch (product.product_type) {
case 'Computer':
store.computers.push.apply(store.computers, variants);
break;
case 'Keyboard':
store.keyboards.push.apply(store.keyboards, variants);
break;
default:
// Alice needs to learn that hackers need more than just Computers and Keyboards
}
});
return hasProducts;
}
try {
// hackathon.hardware identifies the entire purchase list
// Get all products from the store
var page = 1;
while (getProducts(hackathon, page)){
page++;
}
var store = hackathon.shopicruit;
// Sort them by price - ascending
store.keyboards = _.sortBy(store.keyboards, function(keyboard) {
return parseFloat(keyboard.price);
});
store.computers = _.sortBy(store.computers, function(computer) {
return parseFloat(computer.price);
});
// Make purchase list
while(purchaseHardware(hackathon)) {
// We just wait till Alice adds to her list
}
purchaseSpares(hackathon);
// console.log(hackathon);
console.log('Total Computer/Keyboard pairs: ' + hackathon.hardware.basic.length);
console.log('Their weight: ' + hackathon.weights.regular + ' g');
console.log('Spare ' + hackathon.hardware.spares.category + ': ' + hackathon.hardware.spares[hackathon.hardware.spares.category].length);
console.log('Their weight: ' + hackathon.weights.spare + ' g');
console.log('Total weight: ' + (hackathon.weights.regular + hackathon.weights.spare) + ' g');
}
catch(err) {
console.log(err);
console.log('Oops, something wen\'t wrong. Please contact Shopify support');
}
{
"name": "shopify_challenge",
"version": "1.0.0",
"description": "Solution for Shopify challenge",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [
"shopify",
"challenge"
],
"author": "Salman Tariq Mirza",
"license": "MIT",
"dependencies": {
"lodash": "^4.12.0",
"sync-request": "^3.0.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment