Browse files

Factor out and document odd-shape-generating code

  • Loading branch information...
1 parent d518edd commit cfa53885132fff27b2b04f0b5fb95b885b2f2e9d @beneater beneater committed Jun 15, 2012
Showing with 187 additions and 190 deletions.
  1. +11 −97 exercises/area_1.html
  2. +37 −93 exercises/perimeter_1.html
  3. +139 −0 utils/graphie-geometry.js
View
108 exercises/area_1.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html data-require="math graphie word-problems interactive subhints">
+<html data-require="math graphie graphie-geometry word-problems interactive subhints">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Area 1</title>
@@ -159,96 +159,13 @@
<div class="vars">
<var id="WIDTH">randRange(5, 10)</var>
<var id="HEIGHT">randRange(5, 10)</var>
- <var id="SIDES, SQUARES"
- data-ensure="SIDES.length > 4 && SQUARES.length < 15">
- (function() {
- var sides = [];
- var squares = [];
-
- var left = randRange(0, WIDTH - 1);
- var right = randRange(left + 1, WIDTH);
-
- sides.push({
- start: [left, HEIGHT - 1],
- end: [right, HEIGHT - 1],
- length: right - left,
- labelPos: "above"
- });
- var leftStart = HEIGHT - 1;
- var rightStart = HEIGHT - 1;
-
- _(right - left).times(function(dx) {
- squares.push([HEIGHT - 1, left + dx]);
- });
-
- _(HEIGHT - 3).times(function(y) {
- var prevLeft = left;
- var prevRight = right;
- left = randRangeWeighted(0, prevRight - 1,
- prevLeft, 0.7);
- right = randRangeWeighted(max(left, prevLeft)
- + 1, WIDTH, prevRight, 0.7);
- _(right - left).times(function(dx) {
- squares.push([HEIGHT - y - 2, left + dx]);
- });
- if (left !== prevLeft) {
- sides.push({
- start: [prevLeft, leftStart],
- end: [prevLeft, HEIGHT - y - 2],
- length: leftStart - (HEIGHT - y - 2),
- labelPos: "left"
- });
- sides.push({
- start: [prevLeft, HEIGHT - y - 2],
- end: [left, HEIGHT - y - 2],
- length: abs(left - prevLeft),
- labelPos: "center"
- });
- leftStart = HEIGHT - y - 2;
- }
- if (right !== prevRight) {
- sides.push({
- start: [prevRight, rightStart],
- end: [prevRight, HEIGHT - y - 2],
- length: rightStart - (HEIGHT - y - 2),
- labelPos: "right"
- });
- sides.push({
- start: [prevRight, HEIGHT - y - 2],
- end: [right, HEIGHT - y - 2],
- length: abs(right - prevRight),
- labelPos: "center"
- });
- rightStart = HEIGHT - y - 2;
- }
- });
-
- sides.push({
- start: [left, leftStart],
- end: [left, 1],
- length: leftStart - 1,
- labelPos: "left"
- });
- sides.push({
- start: [right, rightStart],
- end: [right, 1],
- length: rightStart - 1,
- labelPos: "right"
- });
- sides.push({
- start: [left, 1],
- end: [right, 1],
- length: right - left,
- labelPos: "below"
- });
-
- return [sides, squares];
- })()
+ <var id="SHAPE" data-ensure="
+ SHAPE.numSides > 4 &&
+ SHAPE.area < 15">createOddShape({
+ width: WIDTH,
+ height: HEIGHT
+ })
</var>
- <var id="PERIMETER">_.reduce(SIDES, function(m, v) {
- return m + v.length;
- }, 0)</var>
- <var id="AREA">SQUARES.length</var>
</div>
<p class="question">
@@ -270,14 +187,14 @@
stroke: "#bbb" });
});
- _.each(SIDES, function(side) {
+ _.each(SHAPE.sides, function(side) {
path([side.start, side.end], {stroke: BLUE});
});
</div>
</div>
<div class="solution" data-type="multiple">
- <span class="sol"><var>AREA</var></span>
+ <span class="sol"><var>SHAPE.area</var></span>
square <var>plural(UNIT_TEXT)</var>
</div>
@@ -288,15 +205,12 @@
</p>
<div>
<div class="graphie" data-update="area">
- _.each(SQUARES, function(square, n) {
- label([square[1] + 0.5, square[0] - 0.5], n + 1,
- "center", false);
- });
+ SHAPE.labelSquares();
</div>
<p>Count the number of squares covered.</p>
</div>
<p>
- The area is <code><var>AREA</var></code> square
+ The area is <code><var>SHAPE.area</var></code> square
<var>plural(UNIT_TEXT)</var>.
</p>
</div>
View
130 exercises/perimeter_1.html
@@ -1,5 +1,5 @@
<!DOCTYPE html>
-<html data-require="math graphie word-problems interactive subhints">
+<html data-require="math graphie graphie-geometry word-problems interactive subhints">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Perimeter 1</title>
@@ -226,85 +226,19 @@
<div class="vars">
<var id="WIDTH">randRange(5, 10)</var>
<var id="HEIGHT">randRange(5, 10)</var>
- <var id="SIDES" data-ensure="SIDES.length <= 10 && SIDES.length > 4">(function() {
- var sides = [];
-
- var left = randRange(0, WIDTH - 1);
- var right = randRange(left + 1, WIDTH);
-
- sides.push({
- start: [left, HEIGHT - 1],
- end: [right, HEIGHT - 1],
- length: right - left,
- labelPos: "above"
- });
- var leftStart = HEIGHT - 1;
- var rightStart = HEIGHT - 1;
-
- _(HEIGHT - 3).times(function(y) {
- var prevLeft = left;
- var prevRight = right;
- left = randRangeWeighted(0, prevRight - 1, prevLeft, 0.7);
- right = randRangeWeighted(max(left, prevLeft) + 1, WIDTH, prevRight, 0.7);
- if (left !== prevLeft) {
- sides.push({
- start: [prevLeft, leftStart],
- end: [prevLeft, HEIGHT - y - 2],
- length: leftStart - (HEIGHT - y - 2),
- labelPos: "left"
- });
- sides.push({
- start: [prevLeft, HEIGHT - y - 2],
- end: [left, HEIGHT - y - 2],
- length: abs(left - prevLeft),
- labelPos: "center"
- });
- leftStart = HEIGHT - y - 2;
- }
- if (right !== prevRight) {
- sides.push({
- start: [prevRight, rightStart],
- end: [prevRight, HEIGHT - y - 2],
- length: rightStart - (HEIGHT - y - 2),
- labelPos: "right"
- });
- sides.push({
- start: [prevRight, HEIGHT - y - 2],
- end: [right, HEIGHT - y - 2],
- length: abs(right - prevRight),
- labelPos: "center"
- });
- rightStart = HEIGHT - y - 2;
- }
- });
-
- sides.push({
- start: [left, leftStart],
- end: [left, 1],
- length: leftStart - 1,
- labelPos: "left"
- });
- sides.push({
- start: [right, rightStart],
- end: [right, 1],
- length: rightStart - 1,
- labelPos: "right"
- });
- sides.push({
- start: [left, 1],
- end: [right, 1],
- length: right - left,
- labelPos: "below"
- });
-
- return sides;
- })()</var>
- <var id="PERIMETER">_.reduce(SIDES, function(m, v) { return m + v.length; }, 0)</var>
+ <var id="SHAPE"
+ data-ensure="SHAPE.numSides <= 10 && SHAPE.numSides > 4">
+ createOddShape({
+ width: WIDTH,
+ height: HEIGHT
+ })
+ </var>
+ <var id="SIDES">SHAPE.sides</var>
</div>
<p class="question">
- What is the perimeter of the shape? Each square in the grid is a <code>1 \times 1</code>
- <var>UNIT_TEXT</var> square.
+ What is the perimeter of the shape? Each square in the grid is
+ a <code>1 \times 1</code> <var>UNIT_TEXT</var> square.
</p>
<div class="problem">
@@ -313,41 +247,51 @@
var shape = [];
_(WIDTH + 1).times(function(i) {
- line([i, 0], [i, HEIGHT], { "stroke-width": 1, stroke: "#bbb" });
+ line([i, 0], [i, HEIGHT], { "stroke-width": 1,
+ stroke: "#bbb" });
});
_(HEIGHT + 1).times(function(i) {
- line([0, i], [WIDTH, i], { "stroke-width": 1, stroke: "#bbb" });
+ line([0, i], [WIDTH, i], { "stroke-width": 1,
+ stroke: "#bbb" });
});
-
- _.each(SIDES, function(side) {
+ _.each(SHAPE.sides, function(side) {
path([side.start, side.end], {stroke: BLUE});
});
-
-
</div>
</div>
<div class="solution" data-type="multiple">
- <span class="sol"><var>PERIMETER</var></span> <var>plural(UNIT_TEXT)</var>
+ <span class="sol"><var>SHAPE.perimeter</var></span>
+ <var>plural(UNIT_TEXT)</var>
</div>
<div class="hints">
<p>
- The perimeter is the total length of all the sides of the shape added together.
+ The perimeter is the total length of all the sides of the
+ shape added together.
</p>
<div>
<div class="graphie" data-update="perimeter">
- _.each(SIDES, function(side) {
- label([(side.start[0] + side.end[0]) / 2,
- (side.start[1] + side.end[1]) / 2], side.length,
- side.labelPos);
- });
+ SHAPE.labelSides();
</div>
- <p>Add up the lengths of all <var>SIDES.length</var> sides.</p>
- <p><code>\qquad<var>_.map(SIDES, function(v) { return v.length; }).join("+")</var> = \text{ ?}</code></p>
+ <p>
+ Add up the lengths of all <var>SHAPE.numSides</var>
+ sides.
+ </p>
+ <p><code>\qquad
+ <var>
+ _.map(SHAPE.sides, function(v) {
+ return v.length;
+ }).join("+")
+ </var>
+ = \text{ ?}
+ </code></p>
</div>
- <p>The perimeter is <code><var>PERIMETER</var></code> <var>plural(UNIT_TEXT)</var>.</p>
+ <p>
+ The perimeter is <code><var>SHAPE.perimeter</var></code>
+ <var>plural(UNIT_TEXT)</var>.
+ </p>
</div>
</div>
View
139 utils/graphie-geometry.js
@@ -707,3 +707,142 @@ function newKite(center) {
var angC = 360 - angB - 2 * angA;
return new Quadrilateral(center, randomQuadAngles.kite(), 1 , "", 2);
}
+
+$.extend(KhanUtil, {
+
+ // Creates a representation of a weird blocky shape that you can find
+ // the perimeter or area of
+ createOddShape: function(options) {
+ shape = $.extend({
+ width: 10,
+ height: 10,
+ squares: [],
+ sides: []
+ }, options);
+
+ // Start at the top of the shape and pick a random left and right
+ // edge for the top row.
+ var y = shape.height - 1;
+ var left = KhanUtil.randRange(0, shape.width - 1);
+ var right = KhanUtil.randRange(left + 1, shape.width);
+
+ // Add the top side
+ shape.sides.push({
+ start: [left, y],
+ end: [right, y],
+ length: right - left,
+ labelPos: "above"
+ });
+ // The y-positions where the next vertical line on the left and
+ // right sides of the figure starts.
+ var leftStart = y;
+ var rightStart = y;
+
+ // Add each square in the top row
+ _(right - left).times(function(dx) {
+ shape.squares.push([left + dx, y]);
+ });
+
+ // Iterate through each subsequent row
+ while (y > 2) {
+ y -= 1;
+ // Pick a new left and right edge for each row, with a 70%
+ // probability of continuing on the same row as the row above
+ var prevLeft = left;
+ var prevRight = right;
+ left = KhanUtil.randRangeWeighted(0, prevRight - 1, prevLeft, 0.7);
+ right = KhanUtil.randRangeWeighted(Math.max(left, prevLeft) + 1,
+ shape.width, prevRight, 0.7);
+
+ // Add each square in this row
+ _(right - left).times(function(dx) {
+ shape.squares.push([left + dx, y]);
+ });
+
+ // If the left side isn't the same as the row above,
+ // add a new vertical and horizontal side
+ if (left !== prevLeft) {
+ shape.sides.push({
+ start: [prevLeft, leftStart],
+ end: [prevLeft, y],
+ length: leftStart - y,
+ labelPos: "left"
+ });
+ shape.sides.push({
+ start: [prevLeft, y],
+ end: [left, y],
+ length: Math.abs(left - prevLeft),
+ labelPos: "center"
+ });
+ // record where the next vertical side on the left starts
+ leftStart = y;
+ }
+
+ // If the right side isn't the same as the row above,
+ // add a new vertical and horizontal side
+ if (right !== prevRight) {
+ shape.sides.push({
+ start: [prevRight, rightStart],
+ end: [prevRight, y],
+ length: rightStart - y,
+ labelPos: "right"
+ });
+ shape.sides.push({
+ start: [prevRight, y],
+ end: [right, y],
+ length: Math.abs(right - prevRight),
+ labelPos: "center"
+ });
+ // record where the next vertical side on the right starts
+ rightStart = y;
+ }
+ }
+
+ // Add the last left and right vertical sides
+ shape.sides.push({
+ start: [left, leftStart],
+ end: [left, 1],
+ length: leftStart - 1,
+ labelPos: "left"
+ });
+ shape.sides.push({
+ start: [right, rightStart],
+ end: [right, 1],
+ length: rightStart - 1,
+ labelPos: "right"
+ });
+
+ // Add the bottom side
+ shape.sides.push({
+ start: [left, 1],
+ end: [right, 1],
+ length: right - left,
+ labelPos: "below"
+ });
+
+ shape.perimeter = _.reduce(shape.sides, function(perimeter, side) {
+ return perimeter + side.length;
+ }, 0);
+
+ shape.area = shape.squares.length;
+
+ shape.numSides = shape.sides.length;
+
+ shape.labelSquares = function() {
+ _.each(shape.squares, function(square, n) {
+ KhanUtil.currentGraph.label([square[0] + 0.5, square[1] - 0.5],
+ n + 1, "center", false);
+ });
+ };
+
+ shape.labelSides = function() {
+ _.each(shape.sides, function(side) {
+ KhanUtil.currentGraph.label([(side.start[0] + side.end[0]) / 2,
+ (side.start[1] + side.end[1]) / 2], side.length,
+ side.labelPos);
+ });
+ };
+
+ return shape;
+ }
+});

0 comments on commit cfa5388

Please sign in to comment.