<html>
<head>
<script src="https://code.jquery.com/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular-cookies.min.js"></script>
<meta charset="utf-8">
<title>Ænigma #19</title>
</head>
<body ng-app="app" ng-controller="gridder" class="well">
<div class="body">
<h1>
Ænigma #19
<small class="btn btn-warning"
ng-click="persist.clear();">
Clear
</small>
</h1>
<h1 ng-hide="true">
playing with cookies
<small ng-click="state.save();" class="btn btn-default">save</small>
<small ng-click="state.load();" class="btn btn-default">load</small>
</h1>
<div>
<div id="puzzle-container">
<div ng-repeat="row in verticals" class="row" ng-init="rowIndex = $index;">
<div ng-repeat="state in row track by $index"
class="vertical-container"
ng-click="row[$index] = nextState[state];
persist.save();"
ng-style="{
top: (rowIndex * spacing + vOffset) + 'px',
left: ($index * spacing + hOffset) + 'px',
height: spacing + 'px',
}">
<div class="vertical" ng-class="state"></div>
</div>
</div>
<div ng-repeat="row in horizontals" class="row" ng-init="rowIndex = $index;">
<div ng-repeat="state in row track by $index"
class="horizontal-container"
ng-click="row[$index] = nextState[state];
persist.save();"
ng-style="{
top: (rowIndex * spacing + vOffset - 6) + 'px',
left: ($index * spacing + hOffset + 6) + 'px',
width: spacing + 'px',
}">
<div class="horizontal" ng-class="state"></div>
</div>
</div>
<img src="http://www.pavelspuzzles.com/adas/19/grid.png">
</div>
<div>
<h1>
<a href="http://www.pavelspuzzles.com/adas/19/" target="_blank">
Adalogical Ænigma #19
</a>
</h1>
<p>
A simple playable web version of Pavel's most recent puzzle. Hover and click on the path segments at left to build up a single path. All rights reserved to Pavel Curtis. Also, as this is a jsBin (similar to jsFiddle, CodePen, etc.), you can hack this up as much as you like.
</p>
</div>
</div>
<h4>Some other fun things to do...</h4>
<ul>
<li>Add another color for "guessing"</li>
<li>keyboard navigation and shortcuts</li>
<li>touch support</li>
<li>highlight rule mistakes (e.g. going straight through black)</li>
<li>history: undo, redo, replay previous steps (e.g. would be great to demonstrate the example puzzle)</li>
<li>validate when puzzle is done</li>
<li>can modify or add colors</li>
</ul>
<h4>Changes & Fixes</h4>
<ul>
<li>Scrolling no longer moves the grid off the background puzzle image</li>
<li>Save to browser cookie for persistent play</li>
</ul>
</div>
</body>
</html>
angular
.module('app', ['ngCookies'])
.controller('gridder', ['$scope', '$cookies', function($scope, $cookies) {
var numColumns = 20;
var numRows = 11;
$scope.vOffset = 13;
$scope.hOffset = 8;
$scope.spacing = 28;
var nextState = {
blank: 'green',
green: 'blank',
//green: 'gray',
//gray: 'blank'
};
var compactStateLookup = {
blank: 0,
green: 1
};
var uncompactStateLookup = [
'blank',
'green'
];
$scope.nextState = nextState;
function generateStates(x, y) {
var states = [];
while (x >= 0) {
states[x] = [];
var y_copy = y;
while (y_copy >= 0) {
// states[x][y_copy] = 'blank';
states[x][y_copy] = 'blank';
y_copy--;
}
x--;
}
return states;
}
var persistentState = {
save: function() {
console.log('saving state');
var state = { time: new Date() };
['horizontals', 'verticals'].forEach(function(type) {
state[type] = persistentState.transform(compactStateLookup, $scope[type]);
});
$cookies.state = JSON.stringify(state);
//persistentState.load();
},
load: function() {
// var data = $cookies.state && JSON.parse($cookies.state);
var data = $cookies.state;
data = data && JSON.parse(data);
if (!data) {return;}
console.log('loading data');
['horizontals', 'verticals'].forEach(function(type) {
if (!data[type]) {return;}
$scope[type] = persistentState.transform(uncompactStateLookup, data[type]);
});
},
transform: function(lookup, rows) {
return rows.map(function(row) {
return row.map(function(val) {
return persistentState.apply(lookup, val);
});
});
},
apply: function(lookup, value) {
return lookup[value];
},
clear: function() {
var sure = confirm('Are you sure you want to clear current puzzle progress?');
if (!sure) { return; }
delete $cookies.state;
delete $scope.horizontals;
delete $scope.verticals;
setUpBoard();
}
};
persistentState.load(); // load data if it exists
$scope.persist = persistentState;
function setUpBoard() {
$scope.verticals = $scope.verticals || generateStates(numRows-1, numColumns);
$scope.horizontals = $scope.horizontals || generateStates(numRows, numColumns-1);
}
setUpBoard();
}]);
Output
You can jump to the latest bin by adding /latest
to your URL
Keyboard Shortcuts
Shortcut | Action |
---|---|
ctrl + [num] | Toggle nth panel |
ctrl + 0 | Close focused panel |
ctrl + enter | Re-render output. If console visible: run JS in console |
Ctrl + l | Clear the console |
ctrl + / | Toggle comment on selected lines |
ctrl + ] | Indents selected lines |
ctrl + [ | Unindents selected lines |
tab | Code complete & Emmet expand |
ctrl + shift + L | Beautify code in active panel |
ctrl + s | Save & lock current Bin from further changes |
ctrl + shift + s | Open the share options |
ctrl + y | Archive Bin |
Complete list of JS Bin shortcuts |
JS Bin URLs
URL | Action |
---|---|
/ | Show the full rendered output. This content will update in real time as it's updated from the /edit url. |
/edit | Edit the current bin |
/watch | Follow a Code Casting session |
/embed | Create an embeddable version of the bin |
/latest | Load the very latest bin (/latest goes in place of the revision) |
/[username]/last | View the last edited bin for this user |
/[username]/last/edit | Edit the last edited bin for this user |
/[username]/last/watch | Follow the Code Casting session for the latest bin for this user |
/quiet | Remove analytics and edit button from rendered output |
.js | Load only the JavaScript for a bin |
.css | Load only the CSS for a bin |
Except for username prefixed urls, the url may start with http://jsbin.com/abc and the url fragments can be added to the url to view it differently. |