diff --git a/package.json b/package.json
index 6f4087f..d8c58fc 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,8 @@
"author": "Yuu6883",
"license": "MIT",
"devDependencies": {
+ "@swc-node/register": "^1.5.1",
+ "@swc/core": "^1.7.26",
"@types/ace": "^0.0.48",
"@types/file-saver": "^2.0.5",
"@types/react": "^18.0.14",
@@ -44,8 +46,6 @@
"webpack-dev-server": "^4.9.2"
},
"dependencies": {
- "@swc-node/register": "^1.5.1",
- "canvas": "^2.11.2",
- "seedrandom": "^3.0.5"
+ "canvas": "^2.11.2"
}
}
diff --git a/src/helpers/helper.ts b/src/helpers/helper.ts
index df13941..b069dfc 100644
--- a/src/helpers/helper.ts
+++ b/src/helpers/helper.ts
@@ -1,4 +1,4 @@
-import { PRNG } from "seedrandom";
+import { Random } from "../random";
interface WritableArray {
readonly length: number;
@@ -111,7 +111,7 @@ export class Helper {
public static shuffleFill>(
array: T,
- rng: PRNG
+ rng: Random
) {
for (let i = 0; i < array.length; i++) {
const j = range(rng, i + 1);
@@ -120,7 +120,7 @@ export class Helper {
}
}
- public static pick>(array: T, rng: PRNG) {
+ public static pick>(array: T, rng: Random) {
return array[range(rng, array.length)];
}
@@ -191,7 +191,7 @@ export class Helper {
}
// exclusive
-export const range = (rng: PRNG, upper: number) => Math.floor(rng() * upper);
+export const range = (rng: Random, upper: number) => Math.floor(rng.nextDouble() * upper);
export type vec3 = [number, number, number];
export type vec4 = [number, number, number, number];
diff --git a/src/interpreter.ts b/src/interpreter.ts
index 49eca46..b38f2f5 100644
--- a/src/interpreter.ts
+++ b/src/interpreter.ts
@@ -1,4 +1,4 @@
-import seedrandom, { PRNG } from "seedrandom";
+import { Random } from "./random";
import { Grid } from "./grid";
import { vec3 } from "./helpers/helper";
import { SymmetryHelper } from "./helpers/symmetry";
@@ -14,7 +14,7 @@ export class Interpreter {
public startgrid: Grid;
origin: boolean;
- public rng: PRNG;
+ public rng: Random;
public time = 0;
public readonly changes: vec3[] = [];
@@ -62,7 +62,7 @@ export class Interpreter {
seed: number,
steps: number
): Generator<[Uint8Array, string, number, number, number]> {
- this.rng = seedrandom(seed.toString());
+ this.rng = new Random(seed);
this.grid = this.startgrid;
this.grid.clear();
diff --git a/src/mj-nodes/all.ts b/src/mj-nodes/all.ts
index 4f5cc94..f884d22 100644
--- a/src/mj-nodes/all.ts
+++ b/src/mj-nodes/all.ts
@@ -107,7 +107,7 @@ export class AllNode extends RuleNode {
firstHeuristic = heuristic;
firstHeuristicComputed = true;
}
- const u = this.ip.rng.double();
+ const u = this.ip.rng.nextDouble();
list.push([
m,
this.temperature > 0
diff --git a/src/mj-nodes/convchain.ts b/src/mj-nodes/convchain.ts
index 313c32a..3210360 100644
--- a/src/mj-nodes/convchain.ts
+++ b/src/mj-nodes/convchain.ts
@@ -144,7 +144,7 @@ export class ConvChainNode extends Node {
continue;
}
if (temperature != 1) q = Math.pow(q, 1.0 / temperature);
- if (q > ip.rng.double()) this.toggle(state, r);
+ if (q > ip.rng.nextDouble()) this.toggle(state, r);
}
this.counter++;
diff --git a/src/mj-nodes/convolution.ts b/src/mj-nodes/convolution.ts
index aa28fe7..32b6a90 100644
--- a/src/mj-nodes/convolution.ts
+++ b/src/mj-nodes/convolution.ts
@@ -143,7 +143,7 @@ export class ConvolutionNode extends Node {
if (
input == rule.input &&
rule.output != grid.state[i] &&
- (rule.p == 1.0 || this.ip.rng.double() < rule.p)
+ (rule.p == 1.0 || this.ip.rng.nextDouble() < rule.p)
) {
let success = true;
if (rule.sums != null) {
diff --git a/src/mj-nodes/one.ts b/src/mj-nodes/one.ts
index 5270311..b3d3d1b 100644
--- a/src/mj-nodes/one.ts
+++ b/src/mj-nodes/one.ts
@@ -1,4 +1,4 @@
-import { PRNG } from "seedrandom";
+import { Random } from "../random";
import { Field } from "../field";
import { Grid } from "../grid";
import { BoolArray2D } from "../helpers/datastructures";
@@ -61,7 +61,7 @@ export class OneNode extends RuleNode {
}
}
- randomMatch(rng: PRNG): vec4 {
+ randomMatch(rng: Random): vec4 {
const { grid, matchMask, matches } = this;
if (this.potentials) {
@@ -112,7 +112,7 @@ export class OneNode extends RuleNode {
firstHeuristic = heuristic;
firstHeuristicComputed = true;
}
- const u = rng.double();
+ const u = rng.nextDouble();
const key =
this.temperature > 0
? Math.pow(
diff --git a/src/mj-nodes/overlap.ts b/src/mj-nodes/overlap.ts
index 7e3ce82..4a95d96 100644
--- a/src/mj-nodes/overlap.ts
+++ b/src/mj-nodes/overlap.ts
@@ -1,4 +1,3 @@
-import { alea } from "seedrandom";
import { Grid } from "../grid";
import { Loader } from "../loader";
import { Array2D } from "../helpers/datastructures";
@@ -6,10 +5,12 @@ import { Helper } from "../helpers/helper";
import { SymmetryHelper } from "../helpers/symmetry";
import { WFCNode } from ".";
+import { Random } from "../random";
// A bit slower than C# (130ms vs 90ms, WaveFlower, ryzen 5800x)
export class OverlapNode extends WFCNode {
- protected static state_rng = alea("", { entropy: true });
+ // protected static state_rng = alea("", { entropy: true });
+ protected static state_rng = new Random();
private patterns: Array2D;
private votes: Array2D;
@@ -245,7 +246,7 @@ export class OverlapNode extends WFCNode {
const offset = i * cols;
for (let c = 0; c < cols; c++) {
- const value = buf[offset + c] + 0.1 * rng.double();
+ const value = buf[offset + c] + 0.1 * rng.nextDouble();
if (value > max) {
argmax = c;
max = value;
diff --git a/src/mj-nodes/parallel.ts b/src/mj-nodes/parallel.ts
index 8af5e93..2a42842 100644
--- a/src/mj-nodes/parallel.ts
+++ b/src/mj-nodes/parallel.ts
@@ -19,7 +19,7 @@ export class ParallelNode extends RuleNode {
const grid = this.grid;
const rule = this.rules[r];
- if (ip.rng.double() > rule.p) return;
+ if (ip.rng.nextDouble() > rule.p) return;
this.last |= 1 << r;
rule.jit_apply_kernel(
grid.state,
diff --git a/src/mj-nodes/path.ts b/src/mj-nodes/path.ts
index b8c16a1..1d7e4ce 100644
--- a/src/mj-nodes/path.ts
+++ b/src/mj-nodes/path.ts
@@ -1,4 +1,4 @@
-import seedrandom, { PRNG } from "seedrandom";
+import { Random } from "../random";
import { Grid } from "../grid";
import { Helper, vec3, vec4 } from "../helpers/helper";
@@ -92,7 +92,7 @@ export class PathNode extends Node {
)
return RunState.FAIL;
- const local = seedrandom(this.ip.rng.int32().toString());
+ const local = new Random(this.ip.rng.next());
let min = MX * MY * MZ,
max = -1;
let argmin: vec3 = [-1, -1, -1];
@@ -102,7 +102,7 @@ export class PathNode extends Node {
const g = generations[px + py * MX + pz * MX * MY];
if (g == -1) continue;
const dg = g;
- const noise = 0.1 * local.double();
+ const noise = 0.1 * local.nextDouble();
if (dg + noise < min) {
min = dg + noise;
@@ -159,7 +159,7 @@ export class PathNode extends Node {
dy: number,
dz: number,
generations: Int32Array,
- rng: PRNG
+ rng: Random
): vec3 {
const candidates: vec3[] = [];
const { grid, vertices, edges, inertia } = this;
@@ -217,7 +217,7 @@ export class PathNode extends Node {
if (inertia && (dx != 0 || dy != 0 || dz != 0)) {
let maxScalar = -4;
for (const [cx, cy, cz] of candidates) {
- const noise = 0.1 * rng.double();
+ const noise = 0.1 * rng.nextDouble();
const cos =
(cx * dx + cy * dy + cz * dz) /
Math.sqrt(
diff --git a/src/mj-nodes/rule.ts b/src/mj-nodes/rule.ts
index 3228737..e20d942 100644
--- a/src/mj-nodes/rule.ts
+++ b/src/mj-nodes/rule.ts
@@ -282,7 +282,7 @@ export abstract class RuleNode extends Node {
this instanceof AllNode,
this.limit,
this.depthCoefficient,
- this.ip.rng.int32(),
+ this.ip.rng.next(),
true // viz
).run()
: Search.run(
@@ -296,7 +296,7 @@ export abstract class RuleNode extends Node {
this instanceof AllNode,
this.limit,
this.depthCoefficient,
- this.ip.rng.int32(),
+ this.ip.rng.next(),
true // viz
);
}
diff --git a/src/mj-nodes/tile.ts b/src/mj-nodes/tile.ts
index 34eaf5b..dab15c9 100644
--- a/src/mj-nodes/tile.ts
+++ b/src/mj-nodes/tile.ts
@@ -1,4 +1,3 @@
-import { alea } from "seedrandom";
import { Grid } from "../grid";
import { Loader } from "../loader";
import { Array2D, Array3Dflat, BoolArray3D } from "../helpers/datastructures";
@@ -6,11 +5,13 @@ import { Helper } from "../helpers/helper";
import { SymmetryHelper } from "../helpers/symmetry";
import { WFCNode } from ".";
+import { Random } from "../random";
const FALSE = (_) => false;
export class TileNode extends WFCNode {
- protected static state_rng = alea("", { entropy: true });
+ // protected static state_rng = alea("", { entropy: true });
+ protected static state_rng = new Random();
private tiledata: Uint8Array[];
@@ -480,7 +481,7 @@ export class TileNode extends WFCNode {
let max = -1.0;
let argmax = 0xff;
for (let c = 0; c < v.length; c++) {
- const vote = v[c] + 0.1 * rng.double();
+ const vote = v[c] + 0.1 * rng.nextDouble();
if (vote > max) {
argmax = c;
max = vote;
diff --git a/src/mj-nodes/wfc.ts b/src/mj-nodes/wfc.ts
index 1da3d8c..f1e4d95 100644
--- a/src/mj-nodes/wfc.ts
+++ b/src/mj-nodes/wfc.ts
@@ -1,4 +1,4 @@
-import seedrandom, { PRNG } from "seedrandom";
+import { Random } from "../random";
import { Grid } from "../grid";
import { Array3D, BoolArray2D } from "../helpers/datastructures";
import { Helper } from "../helpers/helper";
@@ -34,7 +34,7 @@ export abstract class WFCNode extends Branch {
public name: string;
private firstgo = true;
- protected rng: PRNG;
+ protected rng: Random;
public override async load(
elem: Element,
@@ -121,7 +121,7 @@ export abstract class WFCNode extends Branch {
const goodseed = this.goodSeed();
if (goodseed === null) return RunState.FAIL;
- this.rng = seedrandom(goodseed.toString());
+ this.rng = new Random(goodseed);
this.stacksize = 0;
this.wave.copyFrom(this.startwave, this.shannon);
this.firstgo = false;
@@ -147,8 +147,8 @@ export abstract class WFCNode extends Branch {
goodSeed(): number {
for (let k = 0; k < this.tries; k++) {
let obs = 0;
- const seed = this.ip.rng.int32();
- this.rng = seedrandom(seed.toString());
+ const seed = this.ip.rng.next();
+ this.rng = new Random(seed);
this.stacksize = 0;
this.wave.copyFrom(this.startwave, this.shannon);
@@ -178,7 +178,7 @@ export abstract class WFCNode extends Branch {
return null;
}
- nextUnobservedNode(rng: PRNG) {
+ nextUnobservedNode(rng: Random) {
const { grid, wave, periodic, shannon } = this;
const { MX, MY, MZ } = grid;
@@ -197,7 +197,7 @@ export abstract class WFCNode extends Branch {
? wave.entropies[i]
: remainingValues;
if (remainingValues > 1 && entropy <= min) {
- const noise = 1e-6 * rng.double();
+ const noise = 1e-6 * rng.nextDouble();
if (entropy + noise < min) {
min = entropy + noise;
argmin = i;
@@ -207,11 +207,11 @@ export abstract class WFCNode extends Branch {
return argmin;
}
- observe(node: number, rng: PRNG) {
+ observe(node: number, rng: Random) {
const w = this.wave.data.row(node);
for (let t = 0; t < this.P; t++)
this.distribution[t] = w.get(t) ? this.weights[t] : 0;
- const r = Helper.sampleWeights(this.distribution, rng.double());
+ const r = Helper.sampleWeights(this.distribution, rng.nextDouble());
for (let t = 0; t < this.P; t++)
if (w.get(t) !== (t === r)) this.ban(node, t);
}
diff --git a/src/node/program.ts b/src/node/program.ts
index 9277f21..a4796bd 100644
--- a/src/node/program.ts
+++ b/src/node/program.ts
@@ -1,4 +1,4 @@
-import seedrandom from "seedrandom";
+import { Random } from "./random";
import * as path from "path";
import * as fs from "fs";
@@ -45,7 +45,7 @@ export class Program {
public static palette: Map = new Map();
- public static meta = seedrandom();
+ public static meta = new Random();
public static loadPalette() {
const ep = Loader.xmlParse(PaletteXML);
@@ -248,7 +248,7 @@ export class Model {
}
public randomize() {
- this._seed = Math.abs(Program.meta.int32());
+ this._seed = Math.abs(Program.meta.next());
}
private scaleTime(t: number) {
diff --git a/src/random.ts b/src/random.ts
new file mode 100644
index 0000000..5b91374
--- /dev/null
+++ b/src/random.ts
@@ -0,0 +1,124 @@
+/**
+ * Original Code:
+ * https://github.com/microsoft/referencesource/blob/master/mscorlib/system/random.cs
+ * https://github.com/dotnet/runtime/blob/main/src/libraries/System.Private.CoreLib/src/System/Random.cs
+ * Converted to TypeScript By: x2nie
+ * Date: 2023-11-19
+ *
+ */
+
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+const Int32 = {
+ MinValue: Math.pow(2, 31) * -1,
+ MaxValue: Math.pow(2, 31) - 1
+}
+const MBIG = Int32.MaxValue;
+const MSEED = 161803398;
+
+export class Random {
+ //
+ // Member Variables
+ //
+ private inext: number;
+ private inextp: number;
+ //private int[] SeedArray = new int[56];
+ private SeedArray: Int32Array;
+
+ // public Random(Seed:number) {}
+ constructor(seed: number | undefined = undefined) {
+ this.inext = 0;
+ this.inextp = 21;
+ this.SeedArray = new Int32Array(56);
+ this.SeedArray.fill(0);
+
+ if (seed === undefined) {
+ //this(Environment.TickCount);
+ seed = Math.floor(Math.random() * MBIG);
+ }
+ seed = Math.floor(seed); // = int()Seed
+
+ let ii: number;
+ let mj: number, mk: number;
+ //Initialize our Seed array.
+ //This algorithm comes from Numerical Recipes in C (2nd Ed.)
+ let subtraction = (seed == Int32.MinValue) ? Int32.MaxValue : Math.abs(seed);
+ mj = MSEED - subtraction;
+ this.SeedArray[55] = mj;
+ mk = 1;
+ for (let i = 1; i < 55; i++) { //Apparently the range [1..55] is special (Knuth) and so we're wasting the 0'th position.
+ ii = (21 * i) % 55;
+ this.SeedArray[ii] = mk;
+ mk = mj - mk;
+ if (mk < 0) mk += MBIG;
+ mj = this.SeedArray[ii];
+ }
+ for (let k = 1; k < 5; k++) {
+ for (let i = 1; i < 56; i++) {
+ this.SeedArray[i] -= this.SeedArray[1 + (i + 30) % 55];
+ if (this.SeedArray[i] < 0) this.SeedArray[i] += MBIG;
+ }
+ }
+ }
+
+ public next(maxValue: number = 0): number {
+ if (maxValue == 0)
+ return this.internalSample()
+
+ if (maxValue < 0) {
+ throw new Error("ArgumentOutOfRange_MustBePositive");
+ }
+ return Math.floor(this.sample() * maxValue);
+ }
+
+ public nextDouble(): number {
+ return this.sample();
+ }
+
+ protected sample(): number { //Float.double
+ //Including this division at the end gives us significantly improved
+ //random number distribution.
+
+ //? C# :
+ // return (this.InternalSample()*(1.0/MBIG));
+
+ //? however, it actually produces identical result with C# (tested on Chrome | Ubuntu 24.04 x64 | .NET v8.0.108 | 2024-09-28)
+ return this.internalSample() * (1.0 / MBIG);
+
+ //? Old Implementation & Slow :
+ // const jsFloat = this.internalSample() * (1.0 / MBIG);
+ // const csharpDouble = jsFloat.toPrecision(15); //got string
+ // return Number(csharpDouble); // will identical to C# value
+
+ //? Faster JavaScript & identical to C# :
+ // const f32arr = new Float32Array(1)
+ // f32arr[0] = this.internalSample()*(1.0/MBIG);
+ // return f32arr[0]
+
+ //? same as above, but with reuse, like its fastest, but is not thread-safe
+ // CLAMPER[0] = this.internalSample()*OneBIGth;
+ // return CLAMPER[0]
+ }
+
+ private internalSample(): number { // int
+ let retVal: number;
+ let locINext = this.inext;
+ let locINextp = this.inextp;
+
+ if (++locINext >= 56) locINext = 1;
+ if (++locINextp >= 56) locINextp = 1;
+
+ retVal = this.SeedArray[locINext] - this.SeedArray[locINextp];
+
+ if (retVal == MBIG) retVal--;
+ if (retVal < 0) retVal += MBIG;
+
+ this.SeedArray[locINext] = retVal;
+
+ this.inext = locINext;
+ this.inextp = locINextp;
+
+ return retVal;
+ }
+}
\ No newline at end of file
diff --git a/src/search.ts b/src/search.ts
index bb0c517..5477fc1 100644
--- a/src/search.ts
+++ b/src/search.ts
@@ -1,4 +1,4 @@
-import seedrandom, { PRNG } from "seedrandom";
+import { Random } from "./random";
import { Array2D, HashMap, PriorityQueue } from "./helpers/datastructures";
import { Helper } from "./helpers/helper";
import { Observation } from "./observation";
@@ -124,7 +124,7 @@ export class Search {
const frontier = new PriorityQueue<{ p: number; v: number }>(
({ p: p1 }, { p: p2 }) => p1 <= p2
);
- const rng = seedrandom(seed.toString());
+ const rng = new Random(seed);
frontier.enqueue({ v: 0, p: rootBoard.rank(rng, depthCoefficient) });
let record = rootBackwardEstimate + rootForwardEstimate;
@@ -504,14 +504,14 @@ class Board {
this.forwardEstimate = forwardEstimate;
}
- public rank(rng: PRNG, depthCoefficient: number) {
+ public rank(rng: Random, depthCoefficient: number) {
const result =
depthCoefficient < 0.0
? 1000 - this.depth
: this.forwardEstimate +
this.backwardEstimate +
2.0 * depthCoefficient * this.depth;
- return result + 0.0001 * rng.double();
+ return result + 0.0001 * rng.nextDouble();
}
// Path trace
diff --git a/src/wasm/search.ts b/src/wasm/search.ts
index eb85527..e6b0205 100644
--- a/src/wasm/search.ts
+++ b/src/wasm/search.ts
@@ -1,4 +1,4 @@
-import seedrandom from "seedrandom";
+import { Random } from "../random";
import { WasmInstance } from ".";
import { HashMap, PriorityQueue } from "../helpers/datastructures";
import { Rule } from "../rule";
@@ -70,7 +70,7 @@ export class NativeSearch {
seed,
viz,
} = this;
- const rng = seedrandom(seed.toString());
+ const rng = new Random(seed);
lib.reset();
@@ -197,7 +197,7 @@ export class NativeSearch {
const push_board = (ptr: number) =>
frontier.enqueue({
v: ptr,
- p: board_rank(ptr, rng.double(), dcoeff),
+ p: board_rank(ptr, rng.nextDouble(), dcoeff),
});
const root_board = new_board(elem);
diff --git a/src/web/center.tsx b/src/web/center.tsx
index 8b4b368..cc09e18 100644
--- a/src/web/center.tsx
+++ b/src/web/center.tsx
@@ -31,7 +31,13 @@ export const ControlPanel = observer(() => {
? `${model.MX}x${model.MY}x${model.MZ}`
: `${model.MX}x${model.MY}`}
{" "}
- seed: {model.seed}
+
+ seed: {
+ model.set_seed(ev.target.value)
+ }} />
{model.loading ? (
loading...
diff --git a/src/web/program.ts b/src/web/program.ts
index a15c2a7..805eb22 100644
--- a/src/web/program.ts
+++ b/src/web/program.ts
@@ -1,4 +1,4 @@
-import seedrandom from "seedrandom";
+import { Random } from "../random";
import {
action,
computed,
@@ -53,6 +53,42 @@ const Render3DTypes = {
voxel: VoxelPathTracer,
};
+class DebugLineHighlighter implements ace.Ace.MarkerLike {
+ range: ace.Ace.Range;
+ type: string;
+ renderer?: ace.Ace.MarkerRenderer;
+ clazz: string = 'debug-line';
+ inFront: boolean;
+ id: number;
+ lineNo: number = -1;
+ public setLineNo(lineNo, editor:ace.Ace.Editor) {
+ if(lineNo != this.lineNo){
+ this.lineNo = lineNo;
+ this.range = new ace.Range(this.lineNo,0, this.lineNo+1, 0);
+ //@ts-ignore
+ editor.session._emit("changeBackMarker");
+ }
+ }
+ //constructor(editor: ace.Ace.edit)
+ public update (html, markerLayer, session:ace.Ace.EditSession, config) {
+ if(this.lineNo<0) return;
+
+ // let y = getRandomInt(26)
+ let dynR = new ace.Range(this.lineNo,0, this.lineNo+1, 10);
+ // dynR=range3
+ //range2 = dynR;
+ const w = dynR.clipRows(config.firstRow, config.lastRow);
+ if(w.isEmpty()) return;
+ debugger
+
+ // var rangeToAddMarkerTo = dynR.toScreenRange(session);
+ // var rangeAsString = rangeToAddMarkerTo.toString();
+ // console.log(config.firstRow, config.lastRow);
+ //console.log('halo',rangeAsString)// JSON.stringify({html, markerLayer, session, config}, null, 3))
+ markerLayer.drawSingleLineMarker(html, dynR, 'debug-line', config)
+ }
+}
+
export class Program {
@observable.ref
public static instance: Model = null;
@@ -63,7 +99,7 @@ export class Program {
@observable
public static palette: Map = new Map();
- public static meta = seedrandom();
+ public static meta = new Random();
public static readonly editor = ace.edit(null, {
wrap: true,
@@ -73,6 +109,9 @@ export class Program {
mode: "ace/mode/xml",
});
+ public static readonly debugLineHighlighter = new DebugLineHighlighter();
+
+
@action
public static loadPalette() {
const ep = Loader.xmlParse(PaletteXML);
@@ -225,6 +264,25 @@ export class Model {
Program.editor.setValue(this.modelXML);
Program.editor.clearSelection();
+ Program.editor.session.clearBreakpoints();
+ if(!Program.debugLineHighlighter.id){
+ Program.editor.session.addDynamicMarker(Program.debugLineHighlighter, false);
+ //@ts-ignore
+ Program.editor.on("guttermousedown", (ev) => {
+ const row = ev.getDocumentPosition().row;
+ // const node = this.nodes.find((node,i) =>{
+ // return node.state.node.source.lineNumber == row
+ // })
+ const nodeIndex = this.nodes.findIndex((node,i) =>{
+ return node.state.node.source.lineNumber == row +1
+ })
+ // console.log('gutter.row:', row, 'nodeIndex:', nodeIndex)
+ if(nodeIndex >=0){
+ this.toggleBreakpoint(nodeIndex)
+ }
+ })
+ }
+ Program.debugLineHighlighter.setLineNo(-1, Program.editor);
const seedString = emodel.getAttribute("seeds");
const seeds = seedString?.split(" ").map((s) => parseInt(s));
@@ -254,7 +312,7 @@ export class Model {
const qsSeed = parseInt(qs.get("seed"));
this._seed = isNaN(qsSeed)
- ? seeds?.[0] || Program.meta.int32()
+ ? seeds?.[0] || Program.meta.next()
: qsSeed;
});
@@ -310,6 +368,11 @@ export class Model {
return this._seed;
}
+ @action
+ public set_seed(seed:number|string) {
+ this._seed = Number(seed)
+ }
+
@action
public start(params?: ProgramParams) {
try {
@@ -357,7 +420,7 @@ export class Model {
@action
public randomize() {
- this._seed = Program.meta.int32();
+ this._seed = Program.meta.next();
}
private scaleTime(t: number) {
@@ -470,6 +533,8 @@ export class Model {
}
console.log(`Time: ${this._timer.toFixed(2)}ms`);
+ console.log(`Steps(maybe): ${this.rendered} ${state.length}`);
+ this.rendered = 0;
} else {
if (!once)
this._delay
@@ -504,7 +569,7 @@ export class Model {
);
for (let i = 0; i < runs; i++) {
- const seed = rng_seed ? Program.meta.int32() : this._seed;
+ const seed = rng_seed ? Program.meta.next() : this._seed;
const iter = ip?.run(seed, this._steps);
const start = performance.now();
@@ -554,13 +619,18 @@ export class Model {
@action
public toggleBreakpoint(index: number) {
const node = this.nodes[index];
+ // console.log('Breakpoint: nodeIndex:',index, 'Node:',node)
if (!node) return;
node.breakpoint = !node.breakpoint;
+ const editor = Program.editor.session;
+ const lineNo = node.state.node.source.lineNumber -1
if (node.breakpoint) {
this.breakpoints.add(node.state.node);
+ editor.setBreakpoint(lineNo, 'debug-breakpoint')
} else {
this.breakpoints.delete(node.state.node);
+ editor.clearBreakpoint(lineNo)
}
}
diff --git a/src/web/right.tsx b/src/web/right.tsx
index 9ba8fcc..c14ed33 100644
--- a/src/web/right.tsx
+++ b/src/web/right.tsx
@@ -557,21 +557,26 @@ const StateTree = observer(() => {
if (xml) {
const node = model.nodes[model.curr_node_index];
- Program.editor.clearSelection();
-
+ // Program.editor.clearSelection();
+
if (node) {
const source = node.state.node.source;
// index starts at 1 really @xmldom
- Program.editor.moveCursorTo(
- source.lineNumber - 1,
- source.columnNumber - 1
- );
+ Program.debugLineHighlighter.setLineNo(source.lineNumber -1, Program.editor);
+ //@ts-ignore
+ // Program.editor.session._emit("changeBackMarker");
+ // Program.editor.moveCursorTo(
+ // source.lineNumber - 1,
+ // source.columnNumber - 1
+ // );
const lines =
Program.editor.container.querySelectorAll(
"div.ace_line_group"
);
elem = lines[source.lineNumber] as HTMLDivElement;
+ } else {
+ Program.debugLineHighlighter.setLineNo(-1, Program.editor);
}
} else {
elem = list.children[model.curr_node_index] as HTMLDivElement;
diff --git a/src/web/style/index.css b/src/web/style/index.css
index acbbf9c..7f8562d 100644
--- a/src/web/style/index.css
+++ b/src/web/style/index.css
@@ -240,6 +240,9 @@ input[type="text"] {
border: none;
transition: background-color 0.25s linear;
}
+input.seed {
+ width: 80px;
+}
input[type="text"]:focus {
background-color: #000;
@@ -334,6 +337,7 @@ input[type="color"]::-webkit-color-swatch {
.node-state[data-highlight="true"] {
--color: cornflowerblue !important;
+ background: rgba(255, 255, 0, 0.2);
}
.node-state[data-highlight="true"][data-breakpoint="true"] {
@@ -705,3 +709,27 @@ button.danger:hover {
.ace-tm .ace_marker-layer .ace_selection {
background-color: #264f78;
}
+.debug-line {
+ background-color: yellow;
+ position: absolute;
+ left: 0!important;
+ opacity: 0.2;
+}
+.debug-breakpoint {
+ /* background-color: pink; */
+ position: absolute;
+ /* left: 0!important; */
+ /* opacity: 0.2; */
+}
+.debug-breakpoint::before {
+ content: '';
+ margin: 0;
+ width: 12px;
+ height: 12px;
+ background-color: crimson;
+ border-radius: 50%;
+ position: absolute;
+ left: 4px;
+ top: 1px;
+ cursor: pointer;
+}
\ No newline at end of file