Skip to content

Instantly share code, notes, and snippets.

@robotlolita
Created May 22, 2015 00:14
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 robotlolita/f82ef83d4a044d7a93eb to your computer and use it in GitHub Desktop.
Save robotlolita/f82ef83d4a044d7a93eb to your computer and use it in GitHub Desktop.
(function () {
'use strict';
var $send = Mermaid['$send'];
var $methods = Mermaid['$methods'].clone();
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['\nYou have 100 doors in a row that are all initially closed.\n\nYou make 100 passes by the doors. The first time through,\nyou visit every door and toggle the door (if the door is closed,\nyou open it; if it is open, you close it). The second time you\nonly visit every 2nd door (door #2, #4, #6, ...).\nThe third time, every 3rd door (door #3, #6, #9, ...),\netc, until you only visit the 100th door.\n']);
var _Door = Mermaid.$make({
'new:': Mermaid.$fn(function (_index) {
return $send(this, 'clone:', $methods, [{
'index': Mermaid.$fn(function () {
return _index;
}, {
'name': 'index',
'documentation': '',
'arguments': []
})
}]);
}, {
'name': 'new:',
'documentation': 'Constructs a new Door. New objects are constructed just by cloning\n existing objects, and giving them new behaviours. In this case we\'re\n cloning the target of this message and giving it an `index` behaviour,\n which will answer where that door is located at.',
'arguments': ['index']
}),
'open?': Mermaid.$fn(function () {
return $send(Mermaid, 'False', $methods, []);
}, {
'name': 'open?',
'documentation': 'Whether the door is open.',
'arguments': []
}),
'closed?': Mermaid.$fn(function () {
return $send(Mermaid, 'False', $methods, []);
}, {
'name': 'closed?',
'documentation': 'Whether the door is closed.',
'arguments': []
})
});
var _Open$45_Door = $send(_Door, 'clone:', $methods, [{
'as-string': Mermaid.$fn(function () {
return $send($send('Door ', '+', $methods, [$send($send(this, 'index', $methods, []), 'as-string', $methods, [])]), '+', $methods, [' is open.']);
}, {
'name': 'as-string',
'documentation': 'A textual representation of this door.',
'arguments': []
}),
'as-emoji': Mermaid.$fn(function () {
return '_';
}, {
'name': 'as-emoji',
'documentation': 'An emoji representation of this door.',
'arguments': []
}),
'open?': Mermaid.$fn(function () {
return $send(Mermaid, 'True', $methods, []);
}, {
'name': 'open?',
'documentation': 'Open doors are, of course, open.',
'arguments': []
})
}]);
var _Closed$45_Door = $send(_Door, 'clone:', $methods, [{
'as-string': Mermaid.$fn(function () {
return $send($send('Door ', '+', $methods, [$send($send(this, 'index', $methods, []), 'as-string', $methods, [])]), '+', $methods, [' is closed.']);
}, {
'name': 'as-string',
'documentation': 'A textual representation of this door.',
'arguments': []
}),
'as-emoji': Mermaid.$fn(function () {
return '\uD83D\uDEAA';
}, {
'name': 'as-emoji',
'documentation': 'An emoji representation of this door.',
'arguments': []
}),
'closed?': Mermaid.$fn(function () {
return $send(Mermaid, 'True', $methods, []);
}, {
'name': 'closed?',
'documentation': 'Closed doors are, of course, closed.',
'arguments': []
})
}]);
var _Doors = Mermaid.$make({
'state': Mermaid.$fn($send($send(Mermaid, 'lazy', $methods, []), 'call:', $methods, [function () {
return $send($send($send(1, '...', $methods, [100]), 'as-array', $methods, []), 'map:', $methods, [function (_i) {
return $send($send($send(_i, 'square-root', $methods, []), '===', $methods, [$send($send(_i, 'square-root', $methods, []), 'round', $methods, [])]), 'then:else:', $methods, [
function () {
return $send(_Open$45_Door, 'new:', $methods, [_i]);
}['bind'](this),
function () {
return $send(_Closed$45_Door, 'new:', $methods, [_i]);
}['bind'](this)
]);
}['bind'](this)]);
}]), {
'name': 'state',
'documentation': 'Returns an array of Doors with the correct states.',
'arguments': []
}),
'open': Mermaid.$fn(function () {
return $send($send($send(this, 'state', $methods, []), 'filter:', $methods, [function ($_) {
return $send($_, 'open?', $methods, []);
}.bind(this)]), 'map:', $methods, [function ($_1) {
return $send($_1, 'index', $methods, []);
}.bind(this)]);
}, {
'name': 'open',
'documentation': 'Returns an array of the indexes where doors are open.',
'arguments': []
}),
'closed': Mermaid.$fn(function () {
return $send($send($send(this, 'state', $methods, []), 'filter:', $methods, [function ($_2) {
return $send($_2, 'closed?', $methods, []);
}.bind(this)]), 'map:', $methods, [function ($_3) {
return $send($_3, 'index', $methods, []);
}.bind(this)]);
}, {
'name': 'closed',
'documentation': 'Returns an array of the indexes where the doors are closed.',
'arguments': []
})
});
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['\n']);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['What state are the doors in after the last pass?']);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, [$send($send($send(_Doors, 'state', $methods, []), 'map:', $methods, [function ($_4) {
return $send($_4, 'as-emoji', $methods, []);
}.bind(this)]), 'join:', $methods, [''])]);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['\n']);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['Which are open?']);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, [$send($send(_Doors, 'open', $methods, []), 'join:', $methods, [', '])]);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['\n']);
$send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, ['Which are closed?']);
return $send($send(Mermaid, 'Console', $methods, []), 'log:', $methods, [$send($send(_Doors, 'closed', $methods, []), 'join:', $methods, [', '])]);
}());
Console log: """
You have 100 doors in a row that are all initially closed.
You make 100 passes by the doors. The first time through,
you visit every door and toggle the door (if the door is closed,
you open it; if it is open, you close it). The second time you
only visit every 2nd door (door #2, #4, #6, ...).
The third time, every 3rd door (door #3, #6, #9, ...),
etc, until you only visit the 100th door.
""";
(* So, first, we need to have a Door, in order to be able to talk about them. A
door is something that can be either open or closed, and also has an
associated index. *)
let Door = {
def new: index
(* Constructs a new Door. New objects are constructed just by cloning
existing objects, and giving them new behaviours. In this case we're
cloning the target of this message and giving it an `index` behaviour,
which will answer where that door is located at. *)
this { def index = index }
(* Conventionally, Mermaid uses a suffix `?` for predicates *)
def open?
(* Whether the door is open. *)
False
def closed?
(* Whether the door is closed. *)
False
};
(* Now that we have our base door, we can define the states it can be in.
Our door can be either in the Open or Closed state, and each of these
states have different representations. They also respond differently to
the `open?` and `closed?` messages. *)
let Open-Door = Door {
def as-string
(* A textual representation of this door. *)
"Door " + this index as-string + " is open."
def as-emoji
(* An emoji representation of this door. *)
"_"
def open?
(* Open doors are, of course, open. *)
True
(* We don't need to re-define `new:` and `closed?`, since they're inherited
from the base `Door` object. *)
};
let Closed-Door = Door {
def as-string
(* A textual representation of this door. *)
"Door " + this index as-string + " is closed."
def as-emoji
(* An emoji representation of this door. *)
"🚪"
def closed?
(* Closed doors are, of course, closed. *)
True
};
(* At last, we can define the problem. It asks us three questions:
- Which state the doors are in?
- Which ones are closed?
- Which ones are open?
So we're going to define behaviours that respond to those questions
accordingly. *)
let Doors = {
@lazy; (* This is a pure function so we can memoise its result *)
def state
(* Returns an array of Doors with the correct states. *)
(1 ... 100) (* A range that goes from 1 to 100, inclusive *)
as-array (* Converted to an array *)
map: { i | (i square-root === i square-root round) then: { Open-Door new: i }
else: { Closed-Door new: i } }
(* Then transformed such that each index holds a door's state *)
def open
(* Returns an array of the indexes where doors are open. *)
this state filter: _ open? (* We only want the doors that are Open *)
>> map: _ index (* And while we're at it, only their indexes *)
def closed
(* Returns an array of the indexes where the doors are closed. *)
this state filter: _ closed? (* We only want the doors that are Closed *)
>> map: _ index (* And while we're at it, only their indexes *)
};
(* Finally, we can start answering the questions posed to us: *)
Console log: "\n";
Console log: "What state are the doors in after the last pass?";
Console log: (Doors state map: _ as-emoji >> join: "");
Console log: "\n";
Console log: "Which are open?";
Console log: (Doors open join: ", ");
Console log: "\n";
Console log: "Which are closed?";
Console log: (Doors closed join: ", ")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment