From a2aca09a5479ecc4f11e5e82ecd0f99ae4ea7ef5 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 01:59:12 -0500 Subject: [PATCH 01/10] Implemented doublily linked list --- src/linkedlist.js | 67 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 src/linkedlist.js diff --git a/src/linkedlist.js b/src/linkedlist.js new file mode 100644 index 0000000..e98dfba --- /dev/null +++ b/src/linkedlist.js @@ -0,0 +1,67 @@ + + +var LinkedList = function() { + this.head = null; + this.tail = null; +} + +LinkedList.prototype.push = function(value) { + var node = { + value: value, + next: null, + prev: null + } + + if (this.head === null) { + // First element + this.head = node; + this.tail = node; + } else { + // Add to end of list + node.prev = this.tail; + this.tail.next = node; + this.tail = node; // Update tail + } +} + +LinkedList.prototype.pop = function(value) { + // 0 Elements + if (this.head === null) { + return null; + } + + // 1 Element + else if (this.tail === this.head) { + var node = this.head; + + this.head = null; + this.tail = null; + + return node; + } + + // 2+ Elements + else { + var node = this.tail; + this.tail = this.tail.prev; + this.tail.next = null; + + return node; + } +} + +LinkedList.prototype.toString = function() { + if (this.head === null) { + return 'empty'; + } else { + var curr = this.head; + var result = ''; + + while (curr !== null) { + result += curr.value; + curr = curr.next; + } + + return result; + } +} \ No newline at end of file From 87f3d43d7c11325ee4febace1a48a3aa3cfffaf6 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 02:04:19 -0500 Subject: [PATCH 02/10] altered LL clasS --- src/linkedlist.js | 112 ++++++++++++++++++++++++---------------------- src/lsystem.js | 2 + 2 files changed, 60 insertions(+), 54 deletions(-) diff --git a/src/linkedlist.js b/src/linkedlist.js index e98dfba..9f63e94 100644 --- a/src/linkedlist.js +++ b/src/linkedlist.js @@ -1,67 +1,71 @@ +export default class LinkedList { + constructor() { + this.head = null; + this.tail = null; + } + // Pushes node with value into the LL + push() = function(value) { + var node = { + value: value, + next: null, + prev: null + } -var LinkedList = function() { - this.head = null; - this.tail = null; -} - -LinkedList.prototype.push = function(value) { - var node = { - value: value, - next: null, - prev: null + if (this.head === null) { + // First element + this.head = node; + this.tail = node; + } else { + // Add to end of list + node.prev = this.tail; + this.tail.next = node; + this.tail = node; // Update tail + } } - if (this.head === null) { - // First element - this.head = node; - this.tail = node; - } else { - // Add to end of list - node.prev = this.tail; - this.tail.next = node; - this.tail = node; // Update tail - } -} + // Pops node off of the LL + pop() = function() { + // 0 Elements + if (this.head === null) { + return null; + } -LinkedList.prototype.pop = function(value) { - // 0 Elements - if (this.head === null) { - return null; - } + // 1 Element + else if (this.tail === this.head) { + var node = this.head; + + this.head = null; + this.tail = null; - // 1 Element - else if (this.tail === this.head) { - var node = this.head; - - this.head = null; - this.tail = null; + return node; + } + + // 2+ Elements + else { + var node = this.tail; + this.tail = this.tail.prev; + this.tail.next = null; - return node; + return node; + } } - // 2+ Elements - else { - var node = this.tail; - this.tail = this.tail.prev; - this.tail.next = null; + // Returns a string version of the LL + toString() = function() { + if (this.head === null) { + return ''; + } else { + var curr = this.head; + var result = ''; + + while (curr !== null) { + result += curr.value; + curr = curr.next; + } - return node; + return result; + } } } -LinkedList.prototype.toString = function() { - if (this.head === null) { - return 'empty'; - } else { - var curr = this.head; - var result = ''; - - while (curr !== null) { - result += curr.value; - curr = curr.next; - } - - return result; - } -} \ No newline at end of file diff --git a/src/lsystem.js b/src/lsystem.js index e643b6d..d9af174 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -1,3 +1,5 @@ +import LinkedList from './linkedlist.js' + // A class that represents a symbol replacement rule to // be used when expanding an L-system grammar. function Rule(prob, str) { From 0c29fa8fd7252d1a87f35fa989ed04e64ef80ed7 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 14:48:52 -0500 Subject: [PATCH 03/10] Untested lsystem functions --- src/linkedlist.js | 19 +++--- src/lsystem.js | 143 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 150 insertions(+), 12 deletions(-) diff --git a/src/linkedlist.js b/src/linkedlist.js index 9f63e94..6b8c486 100644 --- a/src/linkedlist.js +++ b/src/linkedlist.js @@ -2,10 +2,10 @@ export default class LinkedList { constructor() { this.head = null; this.tail = null; - } + }; // Pushes node with value into the LL - push() = function(value) { + push(value) { var node = { value: value, next: null, @@ -22,10 +22,10 @@ export default class LinkedList { this.tail.next = node; this.tail = node; // Update tail } - } + }; // Pops node off of the LL - pop() = function() { + pop() { // 0 Elements if (this.head === null) { return null; @@ -49,10 +49,10 @@ export default class LinkedList { return node; } - } + }; // Returns a string version of the LL - toString() = function() { + toString() { if (this.head === null) { return ''; } else { @@ -66,6 +66,11 @@ export default class LinkedList { return result; } - } + }; + + // Clones the LL + clone() { + return JSON.parse(JSON.stringify(this)); + }; } diff --git a/src/lsystem.js b/src/lsystem.js index d9af174..1f7089e 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -7,28 +7,161 @@ function Rule(prob, str) { this.successorString = str; // The string that will replace the char that maps to this Rule } -// TODO: Implement a linked list class and its requisite functions +// Implement a linked list class and its requisite functions // as described in the homework writeup +// See linkedlist.js -// TODO: Turn the string into linked list +// Turn the string into linked list export function stringToLinkedList(input_string) { // ex. assuming input_string = "F+X" // you should return a linked list where the head is // at Node('F') and the tail is at Node('X') var ll = new LinkedList(); + + for (var i = 0; i < input_string.length; i++) { + ll.push(input_string.charAt(i)); + } + return ll; } -// TODO: Return a string form of the LinkedList +// Return a string form of the LinkedList export function linkedListToString(linkedList) { // ex. Node1("F")->Node2("X") should be "FX" - var result = ""; - return result; + return linkedList.toString(); } // TODO: Given the node to be replaced, // insert a sub-linked-list that represents replacementString function replaceNode(linkedList, node, replacementString) { + if (linkedList === null || linkedList.head === null || node === null) { + // If LL doesn't exist or is empty just return + return; + } + + var curr = linkedList.head; + + // Replacement string is empty + // Basically remove node at evey appearance + if (!replacementString || replacementString.length == 0) { + // Delete the node at every appearance + while (curr != null) { + if (linkedList.head == linkedList.tail) { + // 1 Element Case + + if (linkedList.head.value == node.value) { + linkedList.pop(); // remove + } + + return; + } + + + // Current is the head + else if (curr == linkedList.head) { + if (curr.value == node.value) { + linkedList.head = linkedList.head.next; + curr = linkedList.head; + } + } + + // Current is the tail + else if (curr == linkedList.tail) { + if (curr.value == node.value) { + linkedList.tail = linkedList.tail.prev; + } + + return; + } + + // Current is a middle node + else if (curr.value == node.value) { + var before = curr.prev; + var after = curr.next; + + // Drop reference to current node + before.next = after; + after.prev = before; + + curr = after; + } + + // Move on + else { + curr = curr.next; + } + } + + // ReplacementString is not empty + } else { + // Create LL of replacementString + var rsll = stringToLinkedList(replacementString); + + if (linkedList.head == linkedList.tail) { + // 1 Element Case + // Replace LL with RSLL + if (linkedList.head.value == node.value) { + linkedList = rsll; + } + + return; + } + + + // 2+ Element cases + // Curr is currently equal to the head + if (curr.value == node.value) { + var copy = rsll.clone(); + + copy.tail.next = linkedList.head.next; + linkedList.head = copy.head; + } + + // Loop through the LL + while(curr !== null) { + + // Current is the tail + else if (curr == linkedList.tail) { + if (curr.value == node.value) { + linkedList.tail = linkedList.tail.prev; + } + + return; + } + + // Current is a middle node + else if (curr.value == node.value) { + var before = curr.prev; + var after = curr.next; + + // Drop reference to current node + before.next = after; + after.prev = before; + + curr = after; + } + + if (curr.value == node.value) { + // Replace + var before = curr.prev; + var after = curr.next; + + // Copy the replacementString LinkedList + var copy = rsll.clone(); + copy.head.prev = before; + copy.tail.next = after; + + before.next = copy.head; + after.prev = copy.tail; + + // Update current + curr = after; + } else { + // Keep going otherwise + curr = curr.next; + } + } + } } export default function Lsystem(axiom, grammar, iterations) { From 2211bdda45687d5d36e25bac5a0ccbee68ab2f40 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 16:23:41 -0500 Subject: [PATCH 04/10] Redid replaceNode --- src/lsystem.js | 180 +++++++++++++++++++++---------------------------- 1 file changed, 77 insertions(+), 103 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index 1f7089e..21fde2a 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -31,136 +31,103 @@ export function linkedListToString(linkedList) { return linkedList.toString(); } -// TODO: Given the node to be replaced, +// Given the node to be replaced, // insert a sub-linked-list that represents replacementString +// WASN'T SUPPOSED TO GO THROUGH THE ENTIRE LOOP I THINK. +// WHAT HAVE YOU DONE ELLEN LMAO. function replaceNode(linkedList, node, replacementString) { if (linkedList === null || linkedList.head === null || node === null) { // If LL doesn't exist or is empty just return return; } - - var curr = linkedList.head; // Replacement string is empty // Basically remove node at evey appearance if (!replacementString || replacementString.length == 0) { // Delete the node at every appearance - while (curr != null) { - if (linkedList.head == linkedList.tail) { - // 1 Element Case - - if (linkedList.head.value == node.value) { - linkedList.pop(); // remove - } - - return; - } - - - // Current is the head - else if (curr == linkedList.head) { - if (curr.value == node.value) { - linkedList.head = linkedList.head.next; - curr = linkedList.head; - } - } - - // Current is the tail - else if (curr == linkedList.tail) { - if (curr.value == node.value) { - linkedList.tail = linkedList.tail.prev; - } - - return; - } - - // Current is a middle node - else if (curr.value == node.value) { - var before = curr.prev; - var after = curr.next; - - // Drop reference to current node - before.next = after; - after.prev = before; - - curr = after; - } - - // Move on - else { - curr = curr.next; - } + + // 1 Element Case + if (linkedList.head == linkedList.tail && linkedList.head == node) { + linkedList.pop(); // remove + } + + // Node is the head + else if (node == linkedList.head) { + linkedList.head = linkedList.head.next; + linkedList.head.prev = null; + } + + // Node is the tail + else if (node == linkedList.tail) { + linkedList.tail = linkedList.tail.prev; + linkedList.next = null; } + // Node is a middle node + // Or doesn't exist in the linked list, but well hopefully the function + // is used properly. And I mean, I'm going to used it properly... + else { + var before = node.prev; + var after = node.next; + + // Drop reference to node + before.next = after; + after.prev = before; + } // ReplacementString is not empty } else { // Create LL of replacementString var rsll = stringToLinkedList(replacementString); - if (linkedList.head == linkedList.tail) { - // 1 Element Case + // 1 Element Case + if (linkedList.head == linkedList.tail && linkedList.head == node) { // Replace LL with RSLL - if (linkedList.head.value == node.value) { - linkedList = rsll; - } - + linkedList = rsll; return; } // 2+ Element cases - // Curr is currently equal to the head - if (curr.value == node.value) { - var copy = rsll.clone(); + // If node is the head + if (node == linkedList.head) { + var after = linkedList.head.next; - copy.tail.next = linkedList.head.next; - linkedList.head = copy.head; - } + // Attach copied RSLL, skipping head + rsll.tail.next = after; + after.prev = rsll.tail; // update prev + + // Update LL head + linkedList.head = rsll.head; // prev is already null + } + + // If node is the tail + else if (node == linkedList.tail) { + var before = linkedList.tail.prev; + + // remove node (which is the tail) and add pointer to next + before.next = rsll.head; + rsll.head.prev = before; - // Loop through the LL - while(curr !== null) { - - // Current is the tail - else if (curr == linkedList.tail) { - if (curr.value == node.value) { - linkedList.tail = linkedList.tail.prev; - } - - return; - } - - // Current is a middle node - else if (curr.value == node.value) { - var before = curr.prev; - var after = curr.next; - - // Drop reference to current node - before.next = after; - after.prev = before; - - curr = after; - } - - if (curr.value == node.value) { - // Replace - var before = curr.prev; - var after = curr.next; - - // Copy the replacementString LinkedList - var copy = rsll.clone(); - copy.head.prev = before; - copy.tail.next = after; - - before.next = copy.head; - after.prev = copy.tail; - - // Update current - curr = after; - } else { - // Keep going otherwise - curr = curr.next; - } + // Update tail pointer + linkedList.tail = rsll.tail; } + + // Node is a middle node + // Or doesn't exist in the linked list, but well hopefully the function + // is used properly. And I mean, I'm going to used it properly... + else { + // Replace + var before = node.prev; + var after = node.next; + + // rsll the replacementString LinkedList + rsll.head.prev = before; + rsll.tail.next = after; + + // update the pointers in the linked list + before.next = rsll.head; + after.prev = rsll.tail; + } } } @@ -206,6 +173,13 @@ export default function Lsystem(axiom, grammar, iterations) { // list of the axiom. this.doIterations = function(n) { var lSystemLL = StringToLinkedList(this.axiom); + + // Iterate n times + for (var i = 0; i < n; i++) { + // replaceNode(lSystemLL, node, replacementString); + // Go through each of the + } + return lSystemLL; } } \ No newline at end of file From 760683edee5018220fd4744941b7fe7d21c96da5 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 18:13:08 -0500 Subject: [PATCH 05/10] better lsystem --- src/lsystem.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index 21fde2a..9bae640 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -172,12 +172,26 @@ export default function Lsystem(axiom, grammar, iterations) { // The implementation we have provided you just returns a linked // list of the axiom. this.doIterations = function(n) { + // If there isn't an axiom, then just return + if (this.axiom == null || this.axiom.length <= 0) { + return; + } + var lSystemLL = StringToLinkedList(this.axiom); // Iterate n times for (var i = 0; i < n; i++) { - // replaceNode(lSystemLL, node, replacementString); - // Go through each of the + var curr = lSystemLL.head; + + while (curr != null) { + var curr_grammar = this.grammer[curr.value]; + + if (curr_grammar) { + replaceNode(lSystemLL, curr, curr_grammar); + } + + curr = curr.next; + } } return lSystemLL; From fe7a320584ec818b6bed36caf3ed3f64080efd27 Mon Sep 17 00:00:00 2001 From: eldu Date: Tue, 7 Feb 2017 20:19:27 -0500 Subject: [PATCH 06/10] Finished base lsystem and tested --- src/lsystem.js | 44 ++++++++++++++++++++++++++++++-------------- src/main.js | 4 ++-- src/turtle.js | 2 +- 3 files changed, 33 insertions(+), 17 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index 9bae640..99a57b4 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -35,8 +35,9 @@ export function linkedListToString(linkedList) { // insert a sub-linked-list that represents replacementString // WASN'T SUPPOSED TO GO THROUGH THE ENTIRE LOOP I THINK. // WHAT HAVE YOU DONE ELLEN LMAO. +// Returns the next node to work on function replaceNode(linkedList, node, replacementString) { - if (linkedList === null || linkedList.head === null || node === null) { + if (linkedList === null || node === null) { // If LL doesn't exist or is empty just return return; } @@ -49,18 +50,21 @@ function replaceNode(linkedList, node, replacementString) { // 1 Element Case if (linkedList.head == linkedList.tail && linkedList.head == node) { linkedList.pop(); // remove + return linkedList.head; } // Node is the head else if (node == linkedList.head) { linkedList.head = linkedList.head.next; linkedList.head.prev = null; + return linkedList.head; } // Node is the tail else if (node == linkedList.tail) { linkedList.tail = linkedList.tail.prev; linkedList.next = null; + return null; } // Node is a middle node @@ -73,6 +77,8 @@ function replaceNode(linkedList, node, replacementString) { // Drop reference to node before.next = after; after.prev = before; + + return after; } // ReplacementString is not empty } else { @@ -82,8 +88,9 @@ function replaceNode(linkedList, node, replacementString) { // 1 Element Case if (linkedList.head == linkedList.tail && linkedList.head == node) { // Replace LL with RSLL - linkedList = rsll; - return; + linkedList.head = rsll.head; + linkedList.tail = rsll.tail; + return null; } @@ -98,6 +105,8 @@ function replaceNode(linkedList, node, replacementString) { // Update LL head linkedList.head = rsll.head; // prev is already null + + return after; } // If node is the tail @@ -110,6 +119,8 @@ function replaceNode(linkedList, node, replacementString) { // Update tail pointer linkedList.tail = rsll.tail; + + return null; } // Node is a middle node @@ -127,17 +138,22 @@ function replaceNode(linkedList, node, replacementString) { // update the pointers in the linked list before.next = rsll.head; after.prev = rsll.tail; + + return after; } } } export default function Lsystem(axiom, grammar, iterations) { // default LSystem - this.axiom = "FX"; + this.axiom = "F"; this.grammar = {}; - this.grammar['X'] = [ - new Rule(1.0, '[-FX][+FX]') - ]; + // this.grammar['X'] = [ + // new Rule(1.0, '[-FX][+FX]') + // ]; + this.grammar['F'] = [ + new Rule(1.0, 'FF') + ]; this.iterations = 0; // Set up the axiom string @@ -166,7 +182,6 @@ export default function Lsystem(axiom, grammar, iterations) { } } - // TODO // This function returns a linked list that is the result // of expanding the L-system's axiom n times. // The implementation we have provided you just returns a linked @@ -177,23 +192,24 @@ export default function Lsystem(axiom, grammar, iterations) { return; } - var lSystemLL = StringToLinkedList(this.axiom); + var lSystemLL = stringToLinkedList(this.axiom); // Iterate n times for (var i = 0; i < n; i++) { var curr = lSystemLL.head; while (curr != null) { - var curr_grammar = this.grammer[curr.value]; + var curr_grammar = this.grammar[curr.value][0]; - if (curr_grammar) { - replaceNode(lSystemLL, curr, curr_grammar); + if (curr_grammar && Math.random() <= curr_grammar.probability) { + curr = replaceNode(lSystemLL, curr, curr_grammar.successorString); + } else { + curr = curr.next; } - - curr = curr.next; } } + console.log(lSystemLL.toString()); return lSystemLL; } } \ No newline at end of file diff --git a/src/main.js b/src/main.js index f0c6600..b24dc6c 100644 --- a/src/main.js +++ b/src/main.js @@ -34,7 +34,7 @@ function onLoad(framework) { }); gui.add(lsys, 'axiom').onChange(function(newVal) { - lsys.UpdateAxiom(newVal); + lsys.updateAxiom(newVal); doLsystem(lsys, lsys.iterations, turtle); }); @@ -54,7 +54,7 @@ function clearScene(turtle) { } function doLsystem(lsystem, iterations, turtle) { - var result = lsystem.DoIterations(iterations); + var result = lsystem.doIterations(iterations); turtle.clear(); turtle = new Turtle(turtle.scene); turtle.renderSymbols(result); diff --git a/src/turtle.js b/src/turtle.js index 1db2723..614e1f4 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -96,7 +96,7 @@ export default class Turtle { // Look in the Turtle's constructor for examples of how to bind // functions to grammar symbols. renderSymbol(symbolNode) { - var func = this.renderGrammar[symbolNode.character]; + var func = this.renderGrammar[symbolNode.value]; if (func) { func(); } From fe45c233650fa34795441da622705de04cd5633b Mon Sep 17 00:00:00 2001 From: eldu Date: Wed, 8 Feb 2017 20:23:03 -0500 Subject: [PATCH 07/10] Basic Snowflake --- src/lsystem.js | 16 ++++++++-------- src/turtle.js | 23 ++++++++++++++++++++--- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index 99a57b4..e981777 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -146,14 +146,14 @@ function replaceNode(linkedList, node, replacementString) { export default function Lsystem(axiom, grammar, iterations) { // default LSystem - this.axiom = "F"; - this.grammar = {}; - // this.grammar['X'] = [ - // new Rule(1.0, '[-FX][+FX]') - // ]; - this.grammar['F'] = [ - new Rule(1.0, 'FF') - ]; + this.axiom = "F-F-F-F-F"; + this.grammar = { + 'F': [ new Rule(1.0, 'F-F++F+F-F-F') ], + '[': [ new Rule(1.0, '[') ], + ']': [ new Rule(1.0, ']') ], + '-': [ new Rule(1.0, '-') ], + '+': [ new Rule(1.0, '+') ] + }; this.iterations = 0; // Set up the axiom string diff --git a/src/turtle.js b/src/turtle.js index 614e1f4..f72a61c 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -16,14 +16,17 @@ export default class Turtle { constructor(scene, grammar) { this.state = new TurtleState(new THREE.Vector3(0,0,0), new THREE.Vector3(0,1,0)); this.scene = scene; + this.stateStack = []; // TODO: Start by adding rules for '[' and ']' then more! // Make sure to implement the functions for the new rules inside Turtle if (typeof grammar === "undefined") { this.renderGrammar = { - '+' : this.rotateTurtle.bind(this, 30, 0, 0), - '-' : this.rotateTurtle.bind(this, -30, 0, 0), - 'F' : this.makeCylinder.bind(this, 2, 0.1) + '+' : this.rotateTurtle.bind(this, 72, 0, 0), + '-' : this.rotateTurtle.bind(this, -72, 0, 0), + 'F' : this.makeCylinder.bind(this, 2, 0.1), + '[' : this.pushState.bind(this), + ']' : this.popState.bind(this) }; } else { this.renderGrammar = grammar; @@ -91,6 +94,20 @@ export default class Turtle { //Scoot the turtle forward by len units this.moveForward(len/2); }; + + // Add state into the stack + pushState() { + this.stateStack.push(cloneState()); + }; + + // Restore state to the LIFO + popState() { + this.state = this.stateStack.pop(); + }; + + cloneState() { + return JSON.parse(JSON.stringify(this.state)); + }; // Call the function to which the input symbol is bound. // Look in the Turtle's constructor for examples of how to bind From 85760e7b1c528069af5019e035b2c61daa1bf476 Mon Sep 17 00:00:00 2001 From: eldu Date: Wed, 8 Feb 2017 20:36:38 -0500 Subject: [PATCH 08/10] Terrible README --- README.md | 67 +------------------------------------------------------ 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/README.md b/README.md index 5ca56be..e4fa961 100644 --- a/README.md +++ b/README.md @@ -1,67 +1,2 @@ -The objective of this assignment is to create an L System parser and generate interesting looking plants. Start by forking and then cloning this repository: [https://github.com/CIS700-Procedural-Graphics/Project3-LSystems](https://github.com/CIS700-Procedural-Graphics/Project3-LSystems) - -# L-System Parser - -lsystem.js contains classes for L-system, Rule, and LinkedList. Here’s our suggested structure: - -**The Symbol Nodes/Linked List:** - -Rather than representing our symbols as a string like in many L-system implementations, we prefer to use a linked list. This allows us to store additional information about each symbol at time of parsing (e.g. what iteration was this symbol added in?) Since we’re adding and replacing symbols at each iteration, we also save on the overhead of creating and destroying strings, since linked lists of course make it easy to add and remove nodes. You should write a Linked List class with Nodes that contain at least the following information: - -- The next node in the linked list -- The previous node in the linked list -- The grammar symbol at theis point in the overal string - -We also recommend that you write the following functions to interact with your linked list: - -- A function to symmetrically link two nodes together (e.g. Node A’s next is Node B, and Node B’s prev is Node A) -- A function to expand one of the symbol nodes of the linked list by replacing it with several new nodes. This function should look at the list of rules associated with the symbol in the linked list’s grammar dictionary, then generate a uniform random number between 0 and 1 in order to determine which of the Rules should be used to expand the symbol node. You will refer to a Rule’s probability and compare it to your random number in order to determine which Rule should be chosen. - -**Rules:** - -These are containers for the preconditions, postconditions and probability of a single replacement operation. They should operate on a symbol node in your linked list. - -**L-system:** - -This is the parser, which will loop through your linked list of symbol nodes and apply rules at each iteration. - -Implement the following functions in L-System so that you can apply grammar rules to your axiom given some number of iterations. More details and implementation suggestions about functions can be found in the TODO comments - -- `stringToLinkedList(input_string)` -- `linkedListToString(linkedList)` -- `replaceNode(linkedList, node, replacementString)` -- `doIterations(num)` - -## Turtle - -`turtle.js` has a function called renderSymbol that takes in a single node of a linked list and performs an operation to change the turtle’s state based on the symbol contained in the node. Usually, the turtle’s change in state will result in some sort of rendering output, such as drawing a cylinder when the turtle moves forward. We have provided you with a few example functions to illustrate how to write your own functions to be called by renderSymbol; these functions are rotateTurtle, moveTurtle, moveForward, and makeCylinder. If you inspect the constructor of the Turtle class, you can see how to associate an operation with a grammar symbol. - -- Modify turtle.js to support operations associated with the symbols `[` and `]` - - When you parse `[` you need to store the current turtle state somewhere - - When you parse `]` you need to set your turtle’s state to the most recently stored state. Think of this a pushing and popping turtle states on and off a stack. For example, given `F[+F][-F]`, the turtle should draw a Y shape. Note that your program must be capable of storing many turtle states at once in a stack. - -- In addition to operations for `[` and `]`, you must invent operations for any three symbols of your choosing. - - -## Interactivity - -Using dat.GUI and the examples provided in the reference code, make some aspect of your demo an interactive variable. For example, you could modify: - -1. the axiom -2. Your input grammer rules and their probability -3. the angle of rotation of the turtle -4. the size or color or material of the cylinder the turtle draws, etc! - -## L-System Plants - -Design a grammar for a new procedural plant! As the preceding parts of this assignment are basic computer science tasks, this is where you should spend the bulk of your time on this assignment. Come up with new grammar rules and include screenshots of your plants in your README. For inspiration, take a look at Example 7: Fractal Plant in Wikipedia: https://en.wikipedia.org/wiki/L-system Your procedural plant must have the following features - -1. Grow in 3D. Take advantage of three.js! -2. Have flowers or leaves that are added as a part of the grammar -3. Variation. Different instances of your plant should look distinctly different! -4. A twist. Broccoli trees are cool and all, but we hope to see sometime a little more surprising in your grammars - -# Publishing Your code - -Running `npm run deploy` will automatically build your project and push it to gh-pages where it will be visible at `username.github.io/repo-name`. NOTE: You MUST commit AND push all changes to your MASTER branch before doing this or you may lose your work. The `git` command must also be available in your terminal or command prompt. If you're using Windows, it's a good idea to use Git Bash. \ No newline at end of file +This is an Lsystem that creates a basic snowflake. My apologies. From 9c3ba216bb76c7b31f68b460add54768334df35b Mon Sep 17 00:00:00 2001 From: eldu Date: Wed, 8 Feb 2017 20:43:05 -0500 Subject: [PATCH 09/10] Added rule --- src/turtle.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/turtle.js b/src/turtle.js index f72a61c..c02bb96 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -26,7 +26,8 @@ export default class Turtle { '-' : this.rotateTurtle.bind(this, -72, 0, 0), 'F' : this.makeCylinder.bind(this, 2, 0.1), '[' : this.pushState.bind(this), - ']' : this.popState.bind(this) + ']' : this.popState.bind(this), + '|' : this.rotateTutle.bind(this, 180, 0, 0) }; } else { this.renderGrammar = grammar; From 1f7101351eb17df4773a2b56885a1432dfe11dc7 Mon Sep 17 00:00:00 2001 From: eldu Date: Wed, 8 Feb 2017 20:50:16 -0500 Subject: [PATCH 10/10] got rid of print statements --- src/lsystem.js | 1 - src/turtle.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lsystem.js b/src/lsystem.js index e981777..d4bb59e 100644 --- a/src/lsystem.js +++ b/src/lsystem.js @@ -209,7 +209,6 @@ export default function Lsystem(axiom, grammar, iterations) { } } - console.log(lSystemLL.toString()); return lSystemLL; } } \ No newline at end of file diff --git a/src/turtle.js b/src/turtle.js index c02bb96..b1f5aa0 100644 --- a/src/turtle.js +++ b/src/turtle.js @@ -27,7 +27,7 @@ export default class Turtle { 'F' : this.makeCylinder.bind(this, 2, 0.1), '[' : this.pushState.bind(this), ']' : this.popState.bind(this), - '|' : this.rotateTutle.bind(this, 180, 0, 0) + '|' : this.rotateTurtle.bind(this, 180, 0, 0) }; } else { this.renderGrammar = grammar;