Skip to content

Instantly share code, notes, and snippets.

@twedl
Last active August 29, 2015 14:03
Show Gist options
  • Save twedl/b0cf9bee782cc5195bc2 to your computer and use it in GitHub Desktop.
Save twedl/b0cf9bee782cc5195bc2 to your computer and use it in GitHub Desktop.
Project Euler #1

If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23. Find the sum of all the multiples of 3 or 5 below 1000.

I start with the example of N=150. The algorithm:

  1. Set sum to 0.
  2. Loop from n=1 to N.
    1. if n is divisible by 3 or 5, add n to sum.

Things to consider:

  1. Do I want to match the algorithm perfectly? Then there wouldn't be different colours or levels, just "Add" or "Ignore".
  2. Or do I want it to point out problems? E.g., if you split up Step 2.1 into two steps, "Check %3==0" and "Check %5==0", then you'll add multiples of 15 twice, hence the red colour for 15, 30, 45, etc.
  3. A cooler algorithm might be to loop through multiples of 3 (instead of 1 to N) and 5 directly, add them, then subtract multiples of (3*5), like set addition and subtraction. But that's not the easiest solution, which I think should be my goal.
  4. The way D3 handles data is more complicated than it seems.
    1. A transition applied to a dataset will affect all elements at the same time, except I want to show a loop.
    2. So the "var i = test.shift()" on line 92 is a bit hacky, but will loop through the elements of a copied version of the dataset.
    3. Then it redraws every line for every time through the loop.
    4. And after one loop is finished, it calls a transition on the transition recursively.
    5. I also don't want it to stall on the last element, so I add an invisible line to the end, because the number of loops is determined by the number of elements.

Some resources: Project Euler Problem #1, Help with SVG Labels, and many examples from Mike Bostock.

<!DOCTYPE html>
<meta charset="utf-8">
<style>
.line {
stroke: #000;
stroke-width: 1.5px;
stroke-linecap: round;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="http://d3js.org/topojson.v1.min.js"></script>
<script>
var margin = {top: 230, right: 100, bottom: 80, left: 60},
width = 960 - margin.left - margin.right,
height = 350 - margin.top - margin.bottom;
var n = 150,
array = d3.range(1,n+1),
test = array,
e = [],
sum = 0;
for (var i=0; i<n; i++) {
e.push({num: array[i], on: 0, is3: 0, is5: 0, acti: 1, vis: 1});
}
e.push({num: n+1, on: 0, is3: 0, is5:0, acti: 0, vis: 0});
test = e.slice();
var x = d3.scale.ordinal()
.domain(d3.range(0,n+1))
.rangePoints([0, width]);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var line = svg.append("g")
.attr("class", "line")
.selectAll("line")
.data(e)
.enter().append("line")
.attr("transform", transform)
.attr("y2", function(d) {
return -height*d.vis;
});
var text = svg.append("g")
.attr("class", "label")
.selectAll("text")
.data([3,5,15])
.enter().append("text")
.attr("x", function(d) { return "" + x(n) + ""; })
.attr("y", function(d) { return -height*(0.4+(+(d%3==0)) + 2*(+(d%5==0))); })
.style("fill", function(d) {
return "rgb(" + 255*(+(d%3==0))*(+(d%5==0)) + ","
+ 255*(+(d%3==0))*(1-+(d%5==0)) + ","
+ 255*(1-+(d%3==0))*(+(d%5==0)) + ")";
})
.text(function(d) { return "x%" + d + "==0"; })
.attr("font-family", "sans-serif")
.attr("font-size", "20px");
var xtext = svg.append("g")
.selectAll("text")
.data([""])
.enter().append("text")
.attr("x", width/2+32)
.attr("y", height/2+20)
.text("x = 0")
.attr("font-family", "sans-serif")
.attr("font-size", "20px");
var sumtext = svg.append("g")
.selectAll("text")
.data([""])
.enter().append("text")
.attr("x", width/2)
.attr("y", height/2+40)
.text("Sum = 0")
.attr("font-family", "sans-serif")
.attr("font-size", "20px");
var transition = d3.transition()
.duration(100)
.each("start", function start() {
var i = test.shift();
if (i.num<n+1) {
e[i.num-1].on = 1;
}
if (i.num%3==0) {
e[i.num-1].is3 = 1;
}
if (i.num%5==0) {
e[i.num-1].is5 = 1;
}
if (i.num%5==0 || i.num%3==0) {
sum+=i.num;
}
if (i.num-1>0) {
e[i.num-2].on = 0;
e[i.num-2].acti = e[i.num-2].is3 + e[i.num-2].is5;
}
transition.each(function() {
line.transition()
.attr("transform", transform)
.style("stroke", function(d) {
if (d.acti) {
return "rgb(" + 255*(1-d.on)*(d.is3)*(d.is5) + ","
+ 255*(1-d.on)*(d.is3)*(1-d.is5) + ","
+ 255*(1-d.on)*(1-d.is3)*(d.is5) + ")";
}
else if (!d.acti) {
return "rgb(221,221,221)";
}
});
xtext.transition()
.text(function(d) {
if (i.num<=n) {
console.log(d);
return "x = " + i.num;
}
});
sumtext.transition()
.text(function(d) {
console.log(d);
return "Sum = " + sum;
});
});
if (test.length) {
transition = transition.transition().each("start", start);
}
});
function transform(d, i) {
return "translate(" + x(i) + "," + height*(-d.is3-d.is5*2)*d.vis + ")";
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment