<!DOCTYPE html>

< html ng-app = "myApp" >

< head >

< link rel = "stylesheet" href = "http://getbootstrap.com/dist/css/bootstrap.css" / >

< title > Endless plane generator < / title >

< style >

html, body { height: 100%; }

body { max-width: 960px; margin: auto; padding: 2em 0; }

.row { margin-bottom: 1em; }

.center { text-align: center; }

< / style >

< script src = "http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js" >< / script >

< / head >

< body ng-controller = "MainCtrl" >

< div class = "row form-group" >

< div class = "col-md-4" >< h3 > Dimensions < / h3 >< / div >

< div class = "col-md-1" > Rows < / div >

< div class = "col-md-3" >

< input type = "number" min = "1" max = "10" ng-model = "rows" ng-change = "start()" class = "form-control" / >

< / div >

< div class = "col-md-1" > Columns < / div >

< div class = "col-md-3" >

< input type = "number" min = "1" max = "10" ng-model = "cols" ng-change = "start()" class = "form-control" / >

< / div >

< / div >

< div class = "row form-group" >

< div class = "col-md-4" >< h3 > Name < / h3 >< / div >

< div class = "col-md-8" >

< input type = "text" ng-model = "name" ng-change = "start()" class = "form-control" / >

< / div >

< / div >

< div class = "row form-group" >

< div class = "col-md-4" >

< h3 > Properties < / h3 >

< br / >

< button ng-click = "addProp()" class = "btn" > New property < / button >

< / div >

< div class = "col-md-8" >

< div ng-repeat = "prop in props" class = "row" >

< div class = "col-md-6 input-group" >

< input type = "text" ng-model = "prop.first" ng-change = "change()" class = "form-control" / >

< span class = "input-group-addon" >

< input type = "radio" name = "default-{{$index}}" value = "0" checked = "checked" ng-click = "setDefault($index, 0)" / >

< / span >

< / div >

< div class = "col-md-6 input-group" >

< input type = "text" ng-model = "prop.second" ng-change = "change()" class = "form-control" / >

< span class = "input-group-addon" >

< input type = "radio" name = "default-{{$index}}" value = "1" ng-click = "setDefault($index, 1)" / >

< / span >

< / div >

< / div >

< / div >

< / div >

< div class = "row" >

< div class = "col-md-12" >

< table class = "table" >

< tbody >

< tr ng-repeat = "r in data.visitable" >

< td ng-repeat = "c in r" ng-click = "toggle($parent.$index, $index)" ng- class = "data.class[$parent.$index][$index]" class = "center" > {{data.names[$parent.$index][$index]}} < / td >

< / tr >

< / tbody >

< / table >

< / div >

< / div >

< div class = "row" >

< div class = "col-md-12" >

< textarea rows = "15" class = "col-md-12" >

{{proptext}}

{{text}}

< / textarea >

< / div >

< / div >

< script >

Array.prototype.uniq = function () {

var b = this;

return b.reverse().filter(function (g, f, d) { return d.indexOf(g, f + 1) === -1 }).reverse()

};

function ex(e, d, f) {

if (d >= 0 && d < e.length && e[d][f]) return true;

return false;

}

var app = angular.module('myApp', []);

app.controller('MainCtrl', function ($scope) {

$scope.rows = 3;

$scope.cols = 3;

$scope.name = 'Room';

$scope.text = '';

$scope.data = {

visitable: [],

names: [],

class: [],

directions: []

};

$scope.props = [];

$scope.proplist = [];

$scope.proptext = '';

$scope.build = function () {

var i, j, k, l, m, n, o = [];

$scope.text = '';

for (i = 0, k = $scope.data.visitable.length; i < k; i++ ) {

for ( j = 0 , l = $scope. data .visitable [ i ] .length; j < l; j++ ) {

if ( $scope. data .visitable [ i ] [ j ] ) {

$scope. data .directions [ i ] [ j ] = [ ] ;

if ( ex ( $scope. data .visitable, i, j - 1 ) ) $scope. data .directions [ i ] [ j ] .push ( 'east of ' + $scope. data .names [ i ] [ j - 1 ] ) ;

if ( ex ( $scope. data .visitable, i + 1 , j ) ) $scope. data .directions [ i ] [ j ] .push ( 'north of ' + $scope. data .names [ i + 1 ] [ j ] ) ;

if ( ex ( $scope. data .visitable, i + 1 , j - 1 ) ) $scope. data .directions [ i ] [ j ] .push ( 'northeast of ' + $scope. data .names [ i + 1 ] [ j - 1 ] ) ;

if ( ex ( $scope. data .visitable, i + 1 , j + 1 ) ) $scope. data .directions [ i ] [ j ] .push ( 'northwest of ' + $scope. data .names [ i + 1 ] [ j + 1 ] ) ;

$scope. data .directions [ i ] [ j ] = $scope. data .directions [ i ] [ j ] .length ? $scope. data .directions [ i ] [ j ] : [ 'a room' ] ;

$scope. data .directions [ i ] [ j ] = $scope. data .directions [ i ] [ j ] .uniq ( ) .join ( ' and ' ) ;

$scope. text + = $scope. data .names [ i ] [ j ] + ' is ' + $scope. data .directions [ i ] [ j ] ;

$scope. text + = '. The printed name is "' + $scope. name + '".' ;

$scope. text + = '. The description is "[' + $scope. name .toLowerCase ( ) .replace ( / \s+ / gi, '-' ) + '-description]".' ;

if ( $scope.proplist.length ) {

for ( n = 0 ; n < $scope.proplist.length; n++ ) {

if ( Math.floor ( Math.random ( ) * 2 ) == 1 ) {

m = $scope.props [ Math.floor ( Math.random ( ) * $scope.proplist.length ) ] ;

$scope. text + = ' ' + $scope. data .names [ i ] [ j ] + ' is ' ;

$scope. text + = m.default == 0 ? m.second : m.first;

$scope. text + = '.' ;

}

}

}

$scope. text + = '

' ;

}

}

}

}

$scope.toggle = function ( r, c ) {

$scope. data .visitable [ r ] [ c ] = !$scope. data .visitable [ r ] [ c ] ;

$scope. data . class [ r ] [ c ] = $scope. data .visitable [ r ] [ c ] ? "alert alert-success" : "alert alert-danger" ;

var ct = 1 ;

for ( i = 0 ; i < $scope. rows ; i++ ) {

for ( j = 0 ; j < $scope. cols ; j++ ) {

$scope. data .names [ i ] [ j ] = $scope. data .visitable [ i ] [ j ] ? $scope. name + ' ' + ct++ : '' ;

}

}

$scope. text = '' ;

$scope.change ( ) ;

}

$scope. start = function ( ) {

var r, c, ct = 1 ;

$scope. data .visitable = [ ] ;

$scope. data .names = [ ] ;

$scope. data . class = [ ] ;

$scope. data .directions = [ ] ;

for ( r = 0 ; r < $scope. rows ; r++ ) {

$scope. data .visitable [ r ] = [ ] ;

$scope. data .names [ r ] = [ ] ;

$scope. data . class [ r ] = [ ] ;

$scope. data .directions [ r ] = [ ] ;

for ( c = 0 ; c < $scope. cols ; c++ ) {

$scope. data .visitable [ r ] [ c ] = true;

$scope. data .names [ r ] [ c ] = $scope. name + ' ' + ct++;

$scope. data . class [ r ] [ c ] = "alert alert-success" ;

}

}

$scope. text = '' ;

$scope.change ( ) ;

}

$scope.addProp = function ( ) {

$scope.props.push ( { first: '' , second: '' , default: 0 } ) ;

}

$scope.change = function ( ) {

var i, t;

$scope.proplist = [ ] ;

for ( i = 0 ; i < $scope.props.length; i++ ) {

if ( $scope.props [ i ] .first && $scope.props [ i ] .second ) {

t = '' ;

t + = 'A room can be ' ;

t + = $scope.props [ i ] .first;

t + = ' or ' ;

t + = $scope.props [ i ] .second;

t + = '. A room is usually ' ;

t + = $scope.props [ i ] .default == 0 ? $scope.props [ i ] .first : $scope.props [ i ] .second;

t + = '.' ;

$scope.proplist.push ( t ) ;

}

}

$scope.proptext = $scope.proplist.join ( '

' ) ;

$scope.build ( ) ;

}

$scope.setDefault = function ( index, which ) {

$scope.props [ index ] .default = which;

$scope.change ( ) ;

}

$scope. start ( ) ;

} ) ;

< / script >

< / body >