Skip to content

Instantly share code, notes, and snippets.

@mischa
Created January 11, 2012 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mischa/1596773 to your computer and use it in GitHub Desktop.
Save mischa/1596773 to your computer and use it in GitHub Desktop.
KA
diff --git a/javascript/exercises/time_differences_1.js b/javascript/exercises/time_differences_1.js
new file mode 100644
--- /dev/null
+++ b/javascript/exercises/time_differences_1.js
@@ -0,0 +1,272 @@
+/*
+* Time Differences 1
+* Author: Mischa Fierer
+* Date: 2011-05-14
+*
+* Problem spec: http://vimeo.com/23539196
+* How much time passes between X and Y
+* Every now and then, give a time that is the next day
+*
+* TODO: for fun change to how much time spent watching a movie, sleeping, riding bike, etc.
+*
+*/
+
+function TimeDifferencesExercise() {
+ var start = null,
+ end = null,
+ totalMinutes = null;
+
+ this.init = function() {
+ generateProblem();
+ showProblem();
+ generateHints();
+ }
+
+ function generateProblem() {
+ var times = [randomTime(), randomTime()].sort(function(a, b) { return a.date > b.date})
+
+ if(get_random() % 4 == 0) { // Span multiple days
+ times.reverse()[1].date.setDate(2);
+ }
+
+ start = times[0];
+ end = times[1];
+ setCorrectAnswer(start.timeTo(end));
+ }
+
+ function randomTime() {
+ return new TimelineTime(getRandomIntRange(0, 60), getRandomIntRange(0, 24));
+ }
+
+ function showProblem() {
+ var next = '';
+ if(start.date.getDay() < end.date.getDay()){
+ next = ' the next day';
+ }
+
+ write_text('How much time passes between <strong>' + start.pretty() + '</strong> and <strong>' + end.pretty() + next + '</strong>?');
+ }
+
+ function generateHints() {
+ var timeline = new Timeline(start, end, print),
+ firstHour = new TimelineTime(0, start.date.getHours() + 1),
+ lastHour = new TimelineTime(0, end.date.getHours());
+
+ lastHour.date.setDate(end.date.getDate());
+
+ Exercise.hints = [];
+ Exercise.timeline = timeline;
+ Exercise.hints.push(timeline.drawStartAndEnd);
+ Exercise.hints.push(timeline.addHour.partial(firstHour, 'first'));
+ Exercise.hints.push(timeline.addHour.partial(lastHour, 'last'));
+
+ Exercise.hints.push(timeline.addThresholds)
+ Exercise.hints.push(timeline.close)
+ Exercise.hints.push(showSum)
+ }
+
+ function print(hours, minutes, color, firstTime, secondTime) {
+ var time = firstTime.timeTo(secondTime, Timeline.timeInWords),
+ from = ' from ' + firstTime.pretty() + ' to ' + secondTime.pretty();
+ $(function(){
+ $('ul#hints').append('<li style="color:' + color + '">' + time + from + '</li>');
+ });
+ }
+
+ function showSum() {
+ var answer = start.timeTo(end) + " total time passes.";
+ $(function(){
+ $('ul#hints').append("<li class='answer'> " + answer + "</li>");
+ });
+ }
+}
+
+function Timeline(start, end, printCallback) {
+ start.timeline = this;
+ end.timeline = this;
+
+ this.printCallback = printCallback;
+ this.WIDTH = 680;
+ this.PADDING = 80;
+ this.MARGIN = 40;
+
+ this.paper = Raphael(20, 350, this.WIDTH, 200);
+ this.start = start;
+ this.end = end;
+ this.times = [];
+ this.hourWidth = (this.WIDTH - this.PADDING*2 - this.MARGIN*2) / ((end.date - start.date) / 1000 / 60 / 60);
+ this.colors = ['salmon', 'purple', 'red', 'green', 'orange', 'blue'];
+}
+
+Timeline.prototype.drawTime = function(time, left, above) {
+ this.paper.path("M" + left + " 25L" + left + " " + 80);
+ if(above !== 'above') {
+ this.paper.text(left, 100, time.pretty()).attr('font-size', 20);
+ } else {
+ this.paper.text(left, 10, time.pretty()).attr('font-size', 20);
+ }
+
+ time.left = left;
+ this.times.push(time)
+ this.times = this.times.sort(function(a, b) { return a.date > b.date});
+}
+
+Timeline.prototype.drawStartAndEnd = function () {
+ this.paper.path("M0 50L" + this.WIDTH + " 50");
+ this.drawTime(this.start, this.MARGIN);
+ this.drawTime(this.end, this.WIDTH - this.MARGIN);
+}
+
+Timeline.prototype.addHour = function(time, firstOrLast) {
+ if(firstOrLast === 'first') {
+ this.drawTime(time, this.MARGIN + this.PADDING, 'above');
+ this.connect(this.start, time);
+ }
+ else {
+ this.drawTime(time, this.WIDTH - this.MARGIN - this.PADDING, 'above');
+ this.connect(time, this.end);
+ }
+}
+
+Timeline.prototype.connect = function(first, second) {
+ var distanceInMinutes = (second.date - first.date) / 1000 / 60, color;
+ this.paper.text((first.left + second.left) / 2, 35, first.timeTo(second, this.timeInWords));
+ color = this.colors.pop();
+ this.paper.path("M" + first.left + " 45L " + second.left + " 45").attr('stroke', color);
+ this.printCallback(Math.floor(distanceInMinutes / 60), distanceInMinutes % 60, color, first, second);
+}
+
+Timeline.prototype.addThresholds = function() {
+ var noon = new TimelineTime(0, 12),
+ secondNoon = new TimelineTime(0, 12),
+ midnight = new TimelineTime(0, 24),
+ previousTime = this.times[1],
+ hours = 0,
+ noThreshold = true;
+
+ // E.g. 3pm to 5pm the next day has 2 noons
+ secondNoon.date.setDate(this.end.date.getDate());
+ midnight.date.setDate(this.start.date.getDate() + 1);
+
+ if((this.start.date < noon.date) && (this.end.date > noon.date)){
+ hours = (noon.date - previousTime.date) / 1000 / 60 / 60;
+ this.drawTime(noon, (hours * this.hourWidth) + previousTime.left);
+ this.connect(this.times[this.times.indexOf(previousTime)], noon);
+ previousTime = noon;
+ noThreshold = false;
+ }
+
+ if((this.start.date > noon.date) && (this.end.date > midnight.date )) {
+ hours = (midnight.date - previousTime.date) / 1000 / 60 / 60;
+ this.drawTime(midnight, (hours * this.hourWidth) + previousTime.left);
+ this.connect(this.times[this.times.indexOf(midnight) - 1], midnight);
+ previousTime = midnight;
+ noThreshold = false;
+
+ if(this.end.date > secondNoon.date) {
+ hours = (secondNoon.date - previousTime.date) / 1000 / 60 / 60;
+ this.drawTime(secondNoon, (hours * this.hourWidth) + previousTime.left);
+ this.connect(midnight, secondNoon);
+ }
+ }
+
+ if(noThreshold){
+ nextHint();
+ }
+
+
+}
+
+Timeline.prototype.close = function() {
+ this.connect(this.times[this.times.length - 3], this.times[this.times.length - 2]);
+}
+
+function TimelineTime(minutes, hours) {
+ this.date = new Date(1987, 1, 1, (hours || 0), (minutes || 0), 0, 0);
+ this.left = null; // Distance in pixels from the side
+}
+
+TimelineTime.prototype.timeTo = function(otherTime, printer) {
+ var minutes = (otherTime.date - this.date) / 1000 / 60,
+ hours = Math.floor(minutes / 60);
+
+ printer = printer || this.digitalClock;
+ return printer.call(this, minutes % 60, hours);
+}
+
+TimelineTime.prototype.pretty = function(){
+ var hours = this.date.getHours(),
+ minutes = this.date.getMinutes(),
+ m = 'am';
+
+ if(hours >= 12) {
+ hours -= 12;
+ m = 'pm';
+ }
+
+ if(hours === 0) {
+ hours = '12';
+ }
+
+ return this.digitalClock(minutes, hours, m)
+}
+
+Timeline.prototype.timeInWords = function(minutes, hours) {
+ var output = [];
+
+ if(minutes > 0) {
+ output.push(minutes + ' minutes');
+ }
+
+ if(hours > 0) {
+ output.push(hours + ' hours');
+ }
+
+ return output.join(' and ');
+}
+
+TimelineTime.prototype.digitalClock = function(minutes, hours, m) {
+ if(minutes.toString().length < 2) {
+ minutes = '0' + minutes;
+ }
+ if(hours.toString().length < 2) {
+ hours = '0' + hours;
+ }
+
+ return hours + ':' + minutes + (m || '');
+}
+
+
+Function.prototype.partial = function(){
+ var fn = this, args = Array.prototype.slice.call(arguments);
+ return function(){
+ var arg = 0;
+ for ( var i = 0; i < args.length && arg < arguments.length; i++ )
+ if ( args[i] === undefined )
+ args[i] = arguments[arg++];
+ return fn.apply(this, args);
+ };
+};
+
+Exercise.checkAnswer = function() {
+ var answer = $('#answer').val();
+ highlight_answer();
+
+ if(!answer.match(/^\d+:\d+$/)) {
+ window.alert("Your answer should be hours:minutes. For example, for 3 hours and 4 minutes answer 3:04.");
+ return Answer.INVALID;
+ }
+
+ if(answer === correctAnswer) {
+ return Answer.CORRECT;
+ }
+ else {
+ return Answer.INCORRECT;
+ }
+}
+
+nextHint = function(){
+ if(Exercise.hints.length > 0) {
+ Exercise.hints.shift().call(Exercise.timeline)
+ }
+}
diff --git a/time_differences_1.html b/time_differences_1.html
new file mode 100644
--- /dev/null
+++ b/time_differences_1.html
@@ -0,0 +1,32 @@
+{% extends arithmetic_template %}
+
+{% block maincode %}
+<script src="/javascript/exercises/time_differences_1.js?{{App.version}}"></script>
+<style>
+ ul#hints {
+ margin: 180px 0 100px 40px;
+ font-size: 15px;
+ }
+
+ li.answer {
+ font-weight: bold;
+ font-size: 16px;
+ }
+</style>
+{% endblock maincode %}
+
+{% block maincell %}
+
+<script>
+ var exercise = new TimeDifferencesExercise();
+ exercise.init();
+</script>
+
+<ul id="hints">
+</ul>
+{% endblock maincell %}
+
+{% block hintfunction %}
+nextHint()
+{% endblock hintfunction%}
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment