@afshin/life
Advanced tools
Comparing version 0.2.0 to 0.3.0
@@ -1,19 +0,62 @@ | ||
import { DataGrid, DataModel } from '@phosphor/datagrid'; | ||
import '../style/index.css'; | ||
import { DataGrid, DataModel } from '@lumino/datagrid'; | ||
/** | ||
* A namespace for `Life`. | ||
*/ | ||
export declare namespace Life { | ||
interface IStyle { | ||
/** | ||
* The `Life` style type. | ||
*/ | ||
type Style = { | ||
alive?: string; | ||
empty?: string; | ||
size?: number; | ||
} | ||
}; | ||
/** | ||
* The minimum size of a cell in a `Life` grid. | ||
*/ | ||
const MINIMUM_SIZE = 4; | ||
/** | ||
* A Lumino `DataGrid` data model for Conway's Game of Life. | ||
*/ | ||
class Model extends DataModel { | ||
/** | ||
* Instantiate a new life model. | ||
*/ | ||
constructor(options?: Model.IOptions); | ||
/** | ||
* The model's refresh interval. | ||
*/ | ||
get interval(): number; | ||
set interval(interval: number); | ||
/** | ||
* Whether the model has been disposed. | ||
*/ | ||
get isDisposed(): boolean; | ||
/** | ||
* The current state of the universe. | ||
*/ | ||
state: Model.Bit[][]; | ||
get state(): Model.Bit[][]; | ||
set state(state: Model.Bit[][]); | ||
/** | ||
* The model's tick function. | ||
*/ | ||
get tick(): Model.Tick; | ||
set tick(tick: Model.Tick); | ||
/** | ||
* Get the row count for a region in the life data model. | ||
*/ | ||
rowCount(region: DataModel.RowRegion): number; | ||
/** | ||
* Get the column count for a region in the life data model. | ||
*/ | ||
columnCount(region: DataModel.ColumnRegion): number; | ||
/** | ||
* Get the data for a cell in the life data model. | ||
*/ | ||
data(region: DataModel.CellRegion, row: number, column: number): any; | ||
/** | ||
* Dispose the model. | ||
*/ | ||
dispose(): void; | ||
/** | ||
* Start ticking the life widget, rendering each generation. | ||
@@ -26,7 +69,7 @@ */ | ||
stop(): void; | ||
private _interval; | ||
private _data; | ||
private _swap; | ||
private _started; | ||
private _columnCount; | ||
private _rowCount; | ||
private _state; | ||
private _tick; | ||
private _ticker; | ||
} | ||
@@ -44,3 +87,3 @@ /** | ||
*/ | ||
type Tick = (prev: Bit[][], next: Bit[][], fluctuation?: number) => void; | ||
type Tick = (current: Bit[][], fluctuation?: number) => Bit[][]; | ||
/** | ||
@@ -59,3 +102,3 @@ * The instantiation options for a life widget. | ||
/** | ||
* A function used to calculate generations, defaults to `LifeWidget.tick`. | ||
* A function to calculate each generation, defaults to `Life.Model.tick`. | ||
*/ | ||
@@ -79,6 +122,4 @@ tick?: Tick; | ||
* | ||
* @param input - The current state of the world. | ||
* @param current - The current state of the world. | ||
* | ||
* @param output - An array that will be populated with the next generation. | ||
* | ||
* @param fluctuation - An optional value between 0 and 1 that indicates the | ||
@@ -89,9 +130,18 @@ * likelihood that a bit will flip, contravening the rules. | ||
* Instead of accepting a single state array, this function takes an `input` | ||
* and an `output` array to faciliate swapping back and forth between | ||
* and an `output` array to facilitate swapping back and forth between | ||
* generation arrays without needing to reallocate memory. The `input` and | ||
* `output` arrays must have the same dimensions. | ||
*/ | ||
function tick(input: Bit[][], output: Bit[][], fluctuation?: number): void; | ||
function tick(input: Bit[][], fluctuation?: number): Bit[][]; | ||
} | ||
function create(model: Model, style?: IStyle): DataGrid; | ||
/** | ||
* Create a `DataGrid` to render a `Life.Model`. | ||
* | ||
* @param model - The `Life` model. | ||
* | ||
* @param style - The `Life` style. | ||
* | ||
* @returns A `DataGrid` that renders the `Life` model. | ||
*/ | ||
function create(model: Model, style?: Style): DataGrid; | ||
} |
276
lib/index.js
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
@@ -12,13 +15,53 @@ extendStatics(d, b); | ||
})(); | ||
var __assign = (this && this.__assign) || Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
return t; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var datagrid_1 = require("@phosphor/datagrid"); | ||
require("../style/index.css"); | ||
exports.Life = void 0; | ||
var datagrid_1 = require("@lumino/datagrid"); | ||
var polling_1 = require("@lumino/polling"); | ||
/** | ||
@@ -40,14 +83,70 @@ * The default likelihood that a random cell is alive. | ||
var INTERVAL = 250; | ||
/** | ||
* A namespace for `Life`. | ||
*/ | ||
var Life; | ||
(function (Life) { | ||
/** | ||
* The minimum size of a cell in a `Life` grid. | ||
*/ | ||
Life.MINIMUM_SIZE = 4; | ||
/** | ||
* A Lumino `DataGrid` data model for Conway's Game of Life. | ||
*/ | ||
var Model = /** @class */ (function (_super) { | ||
__extends(Model, _super); | ||
/** | ||
* Instantiate a new life model. | ||
*/ | ||
function Model(options) { | ||
if (options === void 0) { options = {}; } | ||
var _this = _super.call(this) || this; | ||
_this._interval = options.interval || INTERVAL; | ||
_this._tick = options.tick || Model.tick; | ||
_this._tick = Model.tick; | ||
_this._ticker = new polling_1.Poll({ | ||
auto: false, | ||
factory: function () { return __awaiter(_this, void 0, void 0, function () { | ||
return __generator(this, function (_a) { | ||
this.state = this.tick(this.state); | ||
this.emitChanged({ | ||
type: 'cells-changed', | ||
rowSpan: this._rowCount, | ||
columnSpan: this._columnCount, | ||
region: 'body', | ||
row: 0, | ||
column: 0 | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}); }, | ||
}); | ||
_this.interval = options.interval || INTERVAL; | ||
_this.state = options.initial || Model.random(); | ||
_this.tick = options.tick || Model.tick; | ||
return _this; | ||
} | ||
Object.defineProperty(Model.prototype, "interval", { | ||
/** | ||
* The model's refresh interval. | ||
*/ | ||
get: function () { | ||
return this._ticker.frequency.interval; | ||
}, | ||
set: function (interval) { | ||
if (this.interval !== interval) { | ||
this._ticker.frequency = __assign(__assign({}, this._ticker.frequency), { interval: interval }); | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Model.prototype, "isDisposed", { | ||
/** | ||
* Whether the model has been disposed. | ||
*/ | ||
get: function () { | ||
return this._ticker.isDisposed; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Model.prototype, "state", { | ||
@@ -58,49 +157,58 @@ /** | ||
get: function () { | ||
return this._data; | ||
return this._state; | ||
}, | ||
set: function (state) { | ||
if (this._started) { | ||
this.stop(); | ||
if (this.state !== state) { | ||
this._columnCount = state[0].length; | ||
this._rowCount = state.length; | ||
this._state = state; | ||
} | ||
this._data = state; | ||
this._swap = JSON.parse(JSON.stringify(state)); | ||
}, | ||
enumerable: true, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Model.prototype, "tick", { | ||
/** | ||
* The model's tick function. | ||
*/ | ||
get: function () { | ||
return this._tick; | ||
}, | ||
set: function (tick) { | ||
if (this.tick !== tick) { | ||
this._tick = tick; | ||
} | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
/** | ||
* Get the row count for a region in the life data model. | ||
*/ | ||
Model.prototype.rowCount = function (region) { | ||
return this._data.length; | ||
return this._rowCount; | ||
}; | ||
/** | ||
* Get the column count for a region in the life data model. | ||
*/ | ||
Model.prototype.columnCount = function (region) { | ||
return this._data[0].length; | ||
return this._columnCount; | ||
}; | ||
/** | ||
* Get the data for a cell in the life data model. | ||
*/ | ||
Model.prototype.data = function (region, row, column) { | ||
return this._data[row][column]; | ||
return this.state[row][column]; | ||
}; | ||
/** | ||
* Dispose the model. | ||
*/ | ||
Model.prototype.dispose = function () { | ||
this._ticker.dispose(); | ||
}; | ||
/** | ||
* Start ticking the life widget, rendering each generation. | ||
*/ | ||
Model.prototype.start = function () { | ||
var _this = this; | ||
var swap = false; | ||
if (this._started) { | ||
this.stop(); | ||
} | ||
this._started = window.setInterval(function () { | ||
// Use a pointer to swap lists back so their names make semantic sense. | ||
if (swap = !swap) { | ||
var swapped = _this._data; | ||
_this._data = _this._swap; | ||
_this._swap = swapped; | ||
} | ||
_this._tick(_this._swap, _this._data); | ||
_this.emitChanged({ | ||
type: 'cells-changed', | ||
rowSpan: _this._data.length, | ||
columnSpan: _this._data[0].length, | ||
region: 'body', | ||
rowIndex: 0, | ||
columnIndex: 0 | ||
}); | ||
}, this._interval); | ||
void this._ticker.start(); | ||
}; | ||
@@ -111,6 +219,3 @@ /** | ||
Model.prototype.stop = function () { | ||
if (this._started) { | ||
window.clearInterval(this._started); | ||
this._started = 0; | ||
} | ||
void this._ticker.stop(); | ||
}; | ||
@@ -142,6 +247,6 @@ return Model; | ||
var row = []; | ||
data.push(row); | ||
for (var j = 0; j < columns; j += 1) { | ||
row[j] = Math.random() < likelihood ? 1 : 0; | ||
} | ||
data.push(row); | ||
} | ||
@@ -154,6 +259,4 @@ return data; | ||
* | ||
* @param input - The current state of the world. | ||
* @param current - The current state of the world. | ||
* | ||
* @param output - An array that will be populated with the next generation. | ||
* | ||
* @param fluctuation - An optional value between 0 and 1 that indicates the | ||
@@ -164,7 +267,7 @@ * likelihood that a bit will flip, contravening the rules. | ||
* Instead of accepting a single state array, this function takes an `input` | ||
* and an `output` array to faciliate swapping back and forth between | ||
* and an `output` array to facilitate swapping back and forth between | ||
* generation arrays without needing to reallocate memory. The `input` and | ||
* `output` arrays must have the same dimensions. | ||
*/ | ||
function tick(input, output, fluctuation) { | ||
function tick(input, fluctuation) { | ||
if (fluctuation === void 0) { fluctuation = 0; } | ||
@@ -175,3 +278,5 @@ var rows = input.length; | ||
var lastRow = rows - 1; | ||
var output = new Array(rows); | ||
for (var i = 0; i < rows; i += 1) { | ||
output[i] = new Array(columns); | ||
for (var j = 0; j < columns; j += 1) { | ||
@@ -195,3 +300,3 @@ var alive = input[i][j]; | ||
// Any live cell with more than three live neighbors dies. | ||
// Any dead cell with exactly three live neighbors becomes a live cell. | ||
// Any dead cell with exactly three live neighbors comes to life. | ||
if (alive && neighbors < 2) { | ||
@@ -213,27 +318,60 @@ cell = 0; | ||
} | ||
output[i][j] = cell; // Record the tick value. | ||
output[i][j] = cell; | ||
} | ||
} | ||
return output; | ||
} | ||
Model.tick = tick; | ||
})(Model = Life.Model || (Life.Model = {})); | ||
/** | ||
* Create a `DataGrid` to render a `Life.Model`. | ||
* | ||
* @param model - The `Life` model. | ||
* | ||
* @param style - The `Life` style. | ||
* | ||
* @returns A `DataGrid` that renders the `Life` model. | ||
*/ | ||
function create(model, style) { | ||
if (style === void 0) { style = {}; } | ||
var size = Math.max(Life.MINIMUM_SIZE, style.size || 20); | ||
var alive = style.alive || "rgb(0, 0, 0)"; | ||
var empty = style.empty || "rgb(50, 185, 25)"; | ||
var grid = new datagrid_1.DataGrid({ | ||
baseColumnSize: style.size || 9, | ||
baseRowSize: style.size || 9, | ||
defaultSizes: { | ||
rowHeaderWidth: size, | ||
rowHeight: size, | ||
columnHeaderHeight: size, | ||
columnWidth: size | ||
}, | ||
headerVisibility: 'none', | ||
style: __assign({}, datagrid_1.DataGrid.defaultStyle, { gridLineColor: "rgba(255, 255, 255, 0.5)", voidColor: 'transparent' }) | ||
}); | ||
var renderer = new datagrid_1.TextRenderer({ | ||
backgroundColor: function (_a) { | ||
var value = _a.value; | ||
return value === 1 ? style.alive || "rgb(0, 0, 0)" | ||
: style.empty || "rgb(50, 185, 25)"; | ||
minimumSizes: { | ||
rowHeight: Life.MINIMUM_SIZE, | ||
columnWidth: Life.MINIMUM_SIZE, | ||
rowHeaderWidth: Life.MINIMUM_SIZE, | ||
columnHeaderHeight: Life.MINIMUM_SIZE | ||
}, | ||
format: function () { return ''; } | ||
style: __assign(__assign({}, datagrid_1.DataGrid.defaultStyle), { gridLineColor: "rgba(255, 255, 255, 0.5)", voidColor: 'transparent' }) | ||
}); | ||
grid.model = model; | ||
grid.addClass('ad-Life'); | ||
grid.cellRenderers.set('body', {}, renderer); | ||
grid.dataModel = model; | ||
grid.addClass('atd-Life'); | ||
grid.disposed.connect(function () { model.dispose(); }); | ||
var Renderer = /** @class */ (function (_super) { | ||
__extends(Renderer, _super); | ||
function Renderer() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
Renderer.prototype.paint = function (gc, config) { | ||
_super.prototype.drawBackground.call(this, gc, __assign(__assign({}, config), { height: size, width: size })); | ||
}; | ||
return Renderer; | ||
}(datagrid_1.TextRenderer)); | ||
grid.cellRenderers.update({ | ||
'body': new Renderer({ | ||
backgroundColor: function (_a) { | ||
var value = _a.value; | ||
return value === 1 ? alive : empty; | ||
} | ||
}) | ||
}); | ||
return grid; | ||
@@ -240,0 +378,0 @@ } |
{ | ||
"name": "@afshin/life", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "An implementation of Conway's Game of Life", | ||
"main": "lib/index.js", | ||
"files": [ | ||
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}", | ||
"style/**/*.{css,eot,gif,html,jpg,json,png,svg,woff2,ttf}" | ||
"lib/*.{d.ts,js,js.map}" | ||
], | ||
"scripts": { | ||
"build": "npm run clean && tsc", | ||
"build:example": "npm run build && cd example && webpack", | ||
"clean": "rimraf lib && rimraf example/dist && rimraf example/lib", | ||
"build": "tsc && webpack", | ||
"clean": "rimraf dist docs lib node_modules", | ||
"docs": "typedoc src --out docs", | ||
"prepublish": "npm run build", | ||
"watch": "npm run clean && tsc --watch", | ||
"watch:example": "npm run build && cd example && webpack --watch" | ||
"watch": "webpack --watch" | ||
}, | ||
"author": "Afshin Darian", | ||
"author": "Afshin T. Darian", | ||
"license": "MIT", | ||
"devDependencies": { | ||
"css-loader": "^0.28.10", | ||
"rimraf": "^2.6.2", | ||
"style-loader": "^0.20.3", | ||
"ts-loader": "^4.0.1", | ||
"typedoc": "^0.11.1", | ||
"typescript": "^2.7.2", | ||
"webpack": "^4.1.1", | ||
"webpack-cli": "^2.0.11" | ||
"css-loader": "^5.0.1", | ||
"eslint": "^7.27.0", | ||
"html-loader": "^2.1.2", | ||
"rimraf": "~3.0.0", | ||
"style-loader": "~2.0.0", | ||
"ts-loader": "^9.1.2", | ||
"typedoc": "~0.20.0-beta.27", | ||
"typescript": "~4.1.3", | ||
"webpack": "^5.3.1", | ||
"webpack-cli": "^4.1.0" | ||
}, | ||
"dependencies": { | ||
"@phosphor/datagrid": "^0.1.5", | ||
"@phosphor/widgets": "^1.5.0" | ||
"@lumino/datagrid": "^0.20.0", | ||
"@lumino/disposable": "^1.7.0", | ||
"@lumino/polling": "^1.6.0", | ||
"@lumino/widgets": "^1.19.0" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21785
7
526
4
10
+ Added@lumino/datagrid@^0.20.0
+ Added@lumino/disposable@^1.7.0
+ Added@lumino/polling@^1.6.0
+ Added@lumino/widgets@^1.19.0
+ Added@lumino/algorithm@1.9.2(transitive)
+ Added@lumino/collections@1.9.3(transitive)
+ Added@lumino/commands@1.21.1(transitive)
+ Added@lumino/coreutils@1.12.1(transitive)
+ Added@lumino/datagrid@0.20.1(transitive)
+ Added@lumino/disposable@1.10.4(transitive)
+ Added@lumino/domutils@1.8.2(transitive)
+ Added@lumino/dragdrop@1.14.5(transitive)
+ Added@lumino/keyboard@1.8.2(transitive)
+ Added@lumino/messaging@1.10.3(transitive)
+ Added@lumino/polling@1.11.4(transitive)
+ Added@lumino/properties@1.8.2(transitive)
+ Added@lumino/signaling@1.11.1(transitive)
+ Added@lumino/virtualdom@1.14.3(transitive)
+ Added@lumino/widgets@1.37.2(transitive)
+ Addedcrypto@1.0.1(transitive)
- Removed@phosphor/datagrid@^0.1.5
- Removed@phosphor/widgets@^1.5.0
- Removed@phosphor/algorithm@1.2.0(transitive)
- Removed@phosphor/collections@1.2.0(transitive)
- Removed@phosphor/commands@1.7.2(transitive)
- Removed@phosphor/coreutils@1.3.1(transitive)
- Removed@phosphor/datagrid@0.1.11(transitive)
- Removed@phosphor/disposable@1.3.1(transitive)
- Removed@phosphor/domutils@1.1.4(transitive)
- Removed@phosphor/dragdrop@1.4.1(transitive)
- Removed@phosphor/keyboard@1.1.3(transitive)
- Removed@phosphor/messaging@1.3.0(transitive)
- Removed@phosphor/properties@1.1.3(transitive)
- Removed@phosphor/signaling@1.3.1(transitive)
- Removed@phosphor/virtualdom@1.2.0(transitive)
- Removed@phosphor/widgets@1.9.3(transitive)