I've created a plugin for Raphael JS. It basically allows you to call
paper.connect(obj1,obj2,colour)
That draws a line between the two objects and maintains the line when the objects are animated.
This is what I've come up with so far. It works but its not very performant, any suggestions on what else I could do to achieve the same thing.
Raphael.fn.connect = function(obj1, obj2, colour) {
// list of paths each object has
obj1.connections = []
obj2.connections = []
// get the bounding box of each object
var box1 = obj1.getBBox()
var box2 = obj2.getBBox()
// create a line/path from object 1 to object 2
var p = this.path("M" + (box1.x + box1.width / 2) + ","
+ (box1.y + box1.height / 2) + "L" + (box2.x + box2.width / 2)
+ "," + (box2.y + box2.height / 2))
// adjust attributes of the path
p.attr({
stroke : colour,
"stroke-linecap" : "round",
"stroke-opacity" : Math.max(obj1.attr('opacity'), obj2.attr('opacity'))
})
// set the start and end element for this path
p.startElement = obj1;
p.endElement = obj2;
// add the path to each of the object
obj1.connections.push(p)
obj2.connections.push(p)
// mark each object as being connected
obj1.connected = true;
obj2.connected = true;
// listen for the Raphael frame event
eve.on("raphael.anim.frame.*", function(obj) {
// if the object the frame event is fired on is connected
if (this.connected) {
// for each connection on this object
for ( var c in this.connections) {
var path = this.connections[c]; // temp path
var b1 = path.startElement.getBBox(); // get the current
// location of start
// element
var b2 = path.endElement.getBBox();// get the current location
// of end element
// move the path to the new locations
path.attr({
path : "M " + (b1.x + b1.width / 2) + " "
+ (b1.y + b1.height / 2) + "L "
+ (b2.x + b2.width / 2) + " "
+ (b2.y + b2.height / 2),
opacity : Math.max(path.startElement.attr('opacity'),
path.endElement.attr('opacity'))
});
}
}
});
}
Not convinced this is the best way at all, but this is my first time using Raphael so I just did all that from looking at the Raphael source code...
In our app we have a line tool. We drop a line with 2 movable end points onto our paper.
All shapes in our app have an associated VisualModel that contains all the geometric data inside of them. These VisualModels also double as Actors. Any Actor can subscribe to any other Actor and when changes occur all interested parties respond.
A system like this allows for a line's path to change via a redraw function that gets called anytime the 2 connected objects modify their X/Y coordinates.
connecting_line.js (redraw)
redraw: function() {
var x1 = this.shapeView1.visualModel.get('x'),
y1 = this.shapeView1.visualModel.get('y'),
x2 = this.shapeView2.visualModel.get('x'),
y2 = this.shapeView2.visualModel.get('y'),
pathData;
pathData = 'M' + x1 + ',' + y1 + 'L' + x2 + ',' + y2;
this.line.attr({
path: pathData,
fill: '#000000',
stroke: LineConstants.COLOR,
'stroke-width': LineConstants.THICKNESS
});
}
We created "movable" mixin. This mixin would allow you to add movability to your shapes. This mixin would update the x/y coordinates in and in turn trigger a 'change' event that your line class would pick up.
movable.js
handleDraggging: function(delta) {
this.shape.move(delta);
}
move: function(delta) {
//... compute movement based on delta
this.visualModel.set('x', xPosition);
this.visualModel.set('y', yPosition);
}
connecting_line.js
initialize: function(shapeView1, shapeView2) {
// ...
this.shapeView1 = shapeView1;
this.shapeView2 = shapeView2;
this.listenTo(shapeView1.visualModel, 'change:x change:y', this.redraw);
this.listenTo(shapeView2.visualModel, 'change:x change:y', this.redraw);
}
Performance for this is great. You can take a look at it in action by going to eventbrite.com, create an event, enabling reserved seating (step 2), add a new map, click 'objects' on the left and drop a line on the paper.
Related
[EDIT] I ended up solving it as I was writing this question, so see below for the answer.
I have a graph that has time periods on the x-axis, and scores on the y-axis, and at each point I'd like the tooltip to give the difference in y values between the current point and the previous one (within the same series).
Reproducible example:
library(highcharter)
hchart(df,
type="line",
hcaes(x = period, y = value, group = group)
) %>%
hc_tooltip(pointFormat = "Score: {point.y} ({previous.point.y})")
Ideally, on hovering for example over the second point for series B, I'd like it to say Score: 5 (+1). This will probably require some formatter=JS() JavaScript instead of just pointFormat, but not sure how to do that.
Courtesy of this related answer, I managed to access all y values, after which I figured out that using this.point.x allows us to hone in on specific y values. Here's the JS:
function () {
if (this.point.x == 0) { // there's no previous point, so set to '0'
var thisDiff = 0;
} else { // use 'this.point.x' to get current position, and do '-1' to get previous position
var thisDiff = ( this.series.points[this.point.x].y - this.series.points[this.point.x - 1].y );
if (thisDiff > 0) {
thisDiff = '+' + thisDiff; // pretty print a '+' sign if difference is positive
}
}
var s = '<b>Series ' + this.series.name + ', period ' + this.point.name + ': </b>';
s += 'mean score ' + this.point.y + ' (' + thisDiff + ')';
return(s);
}
To get it to work in highcharteR we just need to wrap this in quotation marks and pass to hc_tooltip(formatter = JS()
I have a pdf From which a user needs to fill out. There will need to be a replication of the fields based on a number entered into an earlier field (see screenshot below)
For example, if a user enters the number 3 in the voyages box, I want to be able to create 3 'copies' of the complete table below it.
Is this something that is able to be done with Javascript within the pdf? MY thinking is that it should be possible, but i cant find anything on the adobe forums that indicates how.
You can duplicate form fields in a PDF using JavaScript (Acrobat DC SDK) like this (example shows creating a button on each page):
var aPage = this.getPageBox();
var w = 45; // Width of each button
var h = 12 // Height of each button
var nNavi = 4; // Number of buttons to be placed
var g = 6; // Gap between buttons
var totalWidth = nNavi * w + (nNavi - 1) * g; // total width of navi bar
var widthPage = aPage[2] - aPage[0];
// Horizontal offset to center navi bar
var hoffset = (widthPage - totalWidth) / 2;
var voffset = 12; // vertical offset from bottom
for (var nPage = 0; nPage < this.numPages; nPage++) {
// Create the fields
var pp = this.addField("PrevPage", "button", nPage,
[ hoffset, voffset, hoffset + w, voffset + h ] );
pp.buttonSetCaption(pp.name);
pp.fillColor=color.ltGray;
pp.setAction("MouseUp", "this.pageNum--");
var np = this.addField("NextPage", "button", nPage,
[ hoffset + w + g, voffset, hoffset + 2*w + g, voffset + h ] );
np.buttonSetCaption(np.name);
np.fillColor=color.ltGray;
np.setAction("MouseUp", "this.pageNum++");
var pv = this.addField("PrevView", "button", nPage,
[ hoffset + 2*w + 2*g, voffset, hoffset + 3*w + 2*g, voffset + h ] );
pv.buttonSetCaption(pv.name);
pv.fillColor=color.ltGray;
pv.setAction("MouseUp", "app.goBack()");
var nv = this.addField("NextView", "button", nPage,
[ hoffset + 3*w + 3*g, voffset, hoffset + 4*w + 3*g, voffset + h ] );
nv.buttonSetCaption(nv.name);
nv.fillColor=color.ltGray;
nv.setAction("MouseUp", "app.goForward()");
}
[Source]
The documentation also notes the following:
Multiple customized forms within a form based on user input
Subforms may also be subject to conditions. For example, form fields for dependent children would become visible if the user checks a box indicating that there are dependent children. In addition, XFA allows multiple form fields with the same name and multiple copies of the same form.
This page lists XFA specific methods that you may find useful in this effort.
I am trying to figure out how to get the color of one defined Pixel.
In my imagination its shoud look like:
color = get.color.Pixel(x,y);
Maybe someone can help me with this piece of code?
Photoshop's JavaScript API doesn't provide a mechanism like you imagine in your question.
You'll need to utilize the Document.colorSamplers.add([x, y]) method, then read each component color value via its properties:
The following gist shows how to obtain either rgb or cmyk values for a given x,y coordinate:
#target photoshop
// Define the x and y coordinates for the pixel to sample.
var x = 1;
var y = 1;
// Add a Color Sampler at a given x and y coordinate in the image.
var pointSample = app.activeDocument.colorSamplers.add([(x - 1),(y - 1)]);
// Obtain array of RGB values.
var rgb = [
pointSample.color.rgb.red,
pointSample.color.rgb.green,
pointSample.color.rgb.blue
];
// Obtain array of rounded CMYK values.
var cmyk = [
Math.round(pointSample.color.cmyk.cyan),
Math.round(pointSample.color.cmyk.magenta),
Math.round(pointSample.color.cmyk.yellow),
Math.round(pointSample.color.cmyk.black)
];
// Remove the Color Sampler.
pointSample.remove();
// Display the complete RGB values and each component color.
alert('RGB: ' + rgb)
alert('red: ' + rgb[0])
alert('green: ' + rgb[1])
alert('blue: ' + rgb[2])
// Display the complete CMYK values and each component color.
alert('CMYK: ' + cmyk)
alert('cyan: ' + cmyk[0])
alert('magenta: ' + cmyk[1])
alert('yellow: ' + cmyk[2])
alert('black: ' + cmyk[3])
Here's a simple script using a ColorSampler. It's set up to return RGB values.
function PixelSampler(doc) {
this.doc = doc
this.doc.colorSamplers.removeAll();
this.sampler = this.doc.colorSamplers.add([0, 0]);
}
// Return an array of R, G, B pixel values for a particular coordinate.
PixelSampler.prototype.get = function (x, y) {
this.sampler.move([x, y]);
const R = this.sampler.color.rgb.red;
const G = this.sampler.color.rgb.green;
const B = this.sampler.color.rgb.blue;
return [R, G, B];
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
const p = new PixelSampler(app.activeDocument);
alert("Pixel 0 =\n\n" + p.get(0, 0));
$.hiresTimer;
var n = 1000; //p.width * p.height;
for (var i = 0; i < n; i++) p.get(i, 0);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000) + " kilopixels in " + sec.toFixed(2) + " seconds.");
This gives me pixel values at about 100 pixels per second on my machine.
I found this and cleaned up the script a bit. Basically, the idea is to:
Save the current image as a raw bitmap.
Read it back in, but on the javascript side.
Do all access to pixels on the javascript side.
This gives me pixel values at about 72,000 pixels per second, not including the overhead of writing the raw data to disk and reading it back in. It has the added benefit that you can set pixel values, too.
// Adapted from https://community.adobe.com/t5/photoshop/get-index-of-each-pixel/td-p/10022899?page=1
// The purpose is to query (and change) pixel values quickly.
//
// The secret to speed is doing everything on the script side rather than ask Photoshop to do things.
// We use files on disk as an intermediary; on the script side, we read / write it as a binary file; on the
// Photoshop side, we save / open it as a raw bitmap.
//
// Only works on RGB 8bpp images, but this could be easily extended to support others.
function RawPixels(doc) {
this.doc = doc;
const currentActiveDoc = app.activeDocument;
// Obtain the width and height in pixels of the desired document.
const currentRulerUnits = app.preferences.rulerUnits;
app.preferences.rulerUnits = Units.PIXELS;
app.activeDocument = doc;
this.width = Number(doc.width.value);
this.height = Number(doc.height.value);
this.length = this.width * this.height;
this.pixelData = "";
// Return the ruler to its previous state.
app.preferences.rulerUnits = currentRulerUnits;
try {
// We're going to save this document as a raw bitmap to be able to read back in the pixel values
// themselves.
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
// Set up the save action.
// See https://helpx.adobe.com/photoshop/using/file-formats.html#photoshop_raw_format for some info,
// and more technical at https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/
var rawFormat = new ActionDescriptor();
rawFormat.putString(stringIDToTypeID("fileCreator"), "8BIM");
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
var saveAction = new ActionDescriptor();
saveAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
saveAction.putPath(stringIDToTypeID("in"), file);
saveAction.putBoolean(stringIDToTypeID("copy"), false);
executeAction(stringIDToTypeID("save"), saveAction, DialogModes.NO);
// File is saved; now read it back in as raw bytes.
file.open("r");
file.encoding = "BINARY";
this.pixelData = file.read();
const err = file.error;
file.close();
file.remove();
file = null;
if (err) alert(err);
}
catch (e) { alert(e); }
// Return focus to whatever the user had.
app.activeDocument = currentActiveDoc;
}
// Calculate offset from x, y coordinates. Does not check for valid bounds.
getOffset = function(x, y) {
if (y == undefined) {
// allow linear indices too
y = Math.floor(x / this.width);
x = x - y * this.width;
}
return (y * this.width + x) * 3;
}
// Return an array of R, G, B pixel values for a particular coordinate.
RawPixels.prototype.get = function (x, y) {
const off = getOffset(x, y);
const R = this.pixelData.charCodeAt(off + 0);
const G = this.pixelData.charCodeAt(off + 1);
const B = this.pixelData.charCodeAt(off + 2);
return [R, G, B];
}
// Set the pixel at x, y to the values in RGB.
RawPixels.prototype.set = function (RGB, x, y) {
const off = getOffset(x, y);
// note: note checking that length of p = 3!
const R = String.fromCharCode(RGB[0]);
const G = String.fromCharCode(RGB[1]);
const B = String.fromCharCode(RGB[2]);
this.pixelData = this.pixelData.substr(0, off) + R + G + B + this.pixelData.substr(off + 3);
}
// If any changes were made to the pixels, we need to save them to disk and have Photoshop read that file back in.
// We do that by creating a new layer in the desired document.
RawPixels.prototype.create_layer = function () {
try {
const file = new File(Folder.temp.fsName + "/" + Math.random().toString().substr(2) + ".raw");
file.open("w");
file.encoding = "BINARY";
file.write(this.pixelData);
const err = file.error;
file.close();
if (err) { file.remove(); alert(err); return; }
var rawFormat = new ActionDescriptor();
rawFormat.putInteger(stringIDToTypeID("width"), this.width);
rawFormat.putInteger(stringIDToTypeID("height"), this.height);
rawFormat.putInteger(stringIDToTypeID("channels"), 3);
rawFormat.putBoolean(stringIDToTypeID("channelsInterleaved"), true);
rawFormat.putInteger(stringIDToTypeID("depth"), 8);
var openAction = new ActionDescriptor();
openAction.putPath(stringIDToTypeID("null"), file);
openAction.putObject(stringIDToTypeID("as"), stringIDToTypeID("rawFormat"), rawFormat);
executeAction(stringIDToTypeID("open"), openAction, DialogModes.NO);
file.remove();
// The new active document is the file we just opened. Duplicate its contents into
// a new layer in our desired document, then close this temporary file.
app.activeDocument.activeLayer.duplicate(this.doc.layers[0], ElementPlacement.PLACEBEFORE);
const tempDoc = app.activeDocument;
app.activeDocument = this.doc;
this.doc.layers[0].name = "Pixels";
app.activeDocument = tempDoc;
app.activeDocument.close(SaveOptions.DONOTSAVECHANGES);
app.activeDocument = this.doc;
}
catch (e) { alert(e); }
}
////////////////////////////////////////////////////////
/// SOME TESTS /////////////////////////////////////////
////////////////////////////////////////////////////////
$.hiresTimer;
const p = new RawPixels(app.activeDocument);
var sec = ($.hiresTimer / 1000 / 1000);
alert("Init RawPixels in " + sec.toFixed(2) + " seconds");
alert("Pixel 0 =\n\n" + p.get(0));
var a = new Array();
for (var i = 0; i < 100; i++) a.push(p.get(i));
alert("Pixel 0-99 = \n\n" + a.toSource());
p.set(0, [1, 200, 3]);
alert("New Pixel 0=\n\n" + p.get(0));
$.hiresTimer;
var n = p.width * p.height;
for (var i = 0; i < n; i++) p.get(i);
sec = ($.hiresTimer / 1000 / 1000);
alert("Got " + (n / 1000 / 1000) + " megapixels in " + sec.toFixed(2) + " seconds.");
$.hiresTimer;
n = 10;
for (var i = 0; i < n; i++) p.set([255, i * 20, i * 10], 1 + i * 2);
sec = ($.hiresTimer / 1000 / 1000);
//alert("Set " + n + " pixels in " + sec.toFixed(2) + " seconds");
p.create_layer();
alert("New layer created with new pixels");
Things you need to know about my Program
I have created a program in JavaScript that executes Robot instruction that you give. per Robot Object.
The robot is inside a rectangle shaped area. It moves with (x,y) points. Such that (0 <= x <= 50) and (0 <= y <= 50)
The instructions are in Strings of continuous of three repeated letters - There are Three letter that represent the movement of the robot
The program runs each letter and moves the robot according to the letter.
If the program finds out the the robot is out of the surface. Then the robot is lost and the coordinates of that particular robot is kept in array of lists called Lost_Robot
My Question:
I don't know how to prevent a new robot from going to the same coordinates that a previous robot got lost (because of out of Rectangle surface).
How can I achieve from preventing another new robot (when I say new Robot, I mean new Robot Object) from jumping to the same location that a previous robot went and got lost.
I have an array of (x,y) of robots that got lost. But how can I use this array from letting a new robot going to this point?
I tried to use for loop that runs the array to see the coordinates, but doesn't do anything.
Also
While your working on my problem, can you also give me few hints on how can I simplify my code yet doing the same functionality, but more efficiently.
=
var orientation = ["N", "E", "S", "W"];
var instruction = ["L", "R", "F"];
var lost_Robot_Scent = [];
// function created for assigning coordinates and an orientation
function Robot_Coordinatation(x, y, orientation) {
// coordinate (x,y) must be located at (0,0) at the initial state of the program
this.x = 0;
this.y = 0;
// orientation assigned
this.orientation = orientation;
// this is printed for the purpose of tidiness
document.write("============================" + "<br />");
// | ( x,y) | e.g(S)
document.write("| ( " + x + ", " + y + " ) | " + orientation + "<br />");
// We have a nested function here that will determine the movement/instruction of the robot
this.Robot_Instruction = function(instruct_The_Robot) {
// We are making sure here that the length of the instruction is less than 100
if (instruct_The_Robot.length <= 100) {
// if...statement - if x & y is bigger than or equal to 0 and smaller than or equal to 50 -> If its true then go inside the if statment.
// Essentiallly, what this statement is actually doing is that its creating the rectangular grid.
if ((x <= 50 && x >= 0) && (y <= 50 && y >= 0)) {
// itterate the array of the instruct_The_Robot
for (var i = 0; i < instruct_The_Robot.length; i++) {
// if any value of instruct_The_Robot is strictly equal to "L", then go inside this if statement. refer to line: 10
if (instruct_The_Robot[i] === instruction[0]) {
// variable Left declared and instantiated with -90°
var Left = -90 + "°";
// variable result instantiated with value (x,y) & orientation
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Left + "<br />";
// however, if the if...statment at line: 33 is not true, then follow this : if the value of instruct_The_Robot is equal to "R"...
} else if (instruct_The_Robot[i] === instruction[1]) {
// variable Right instantiated with 90°
var Right = 90 + "°";
// variable result instantiated
var result = " | ( " + x + ", " + y + " ) " + " | " + orientation + " " + Right + "<br />";
// however, if the if...statment at line: 33 & elseif at line: 39 is not true, then if instruct_The_Robot is equal to "F"...
} else if (instruct_The_Robot[i] === instruction[2]) {
// variable y_Plus_One is instantiated with the current value of y and moves y one point forward
var y_Plus_One = y += 1;
// if the negation of x & y_Plus_One is smaller than 50 and bigger the 0, then...
if (!((x <= 50 && x >= 0) && (y_Plus_One <= 50 && y_Plus_One >= 0))) {
// then print " lost! "
document.write("LOST!" + "<br />");
// & keep the record of the x and y_Plus_One value to the lost_Robot_Scent array
lost_Robot_Scent.push([x, y]);
// and return false - this stops printing "Lost!" more than one times
return false;
// Otherwise, if the above doesn't satisfy, then...
} else {
// variable result instantiated with the updated coordinates (y_Plus_One)
var result = " | ( " + x + ", " + y_Plus_One + " ) " + " | " + orientation + " " + "<br />";
}
}
}
//print the result
document.write(result);
// if none of the if...statement above satisfy, then...
} else {
// variale lost instantiated with "Lost!" message
var lost = "LOST!" + "<br />";
// push the robot to the lost_Robot_Scent
lost_Robot_Scent.push("| ( " + x + ", " + y + " ) " + "<br />");
}
} else {
alert("There is alot of of instructions given. Please make sure that the instruction is less than 100 instructions");
}
}
}
// new Robot object initialised
var one = new Robot_Coordinatation(50, 50, orientation[1]);
one.Robot_Instruction("LRLRLRLRLRLLRRLRLRLLRLLRRLL");
var two = new Robot_Coordinatation(20, 30, orientation[3]);
two.Robot_Instruction("FFFLLFLRLFLRFLRLLLFRL");
var two = new Robot_Coordinatation(30, 7, orientation[3]);
two.Robot_Instruction("FFFFLRLFLRFLRL");
Maintaining lost_Robot_Scent
I can help you with keeping a collection of locations where your robots get lost (your lost_Robot_Scent array). I suggest using a Set instead on an Array. Sets provide O(1) insertion and O(1) lookup. This probably isn't a big deal in this situation, but it's good to know about Set anyway.
The main problem you'll run into is that array equality is pointer equality: for example, [1, 1] === [1, 1] returns false. One workaround is using toString() on the arrays and storing that in the Set. For example:
var lost_Robot_Scent = new Set();
lost_Robot_Scent.add( [1, 1].toString() );
lost_Robot_Scent.has( [1, 1].toString() ); // -> true
lost_Robot_Scent.has( [2, 2].toString() ); // -> false
I don't know if this is the cleanest solution, but it works. If you want to use an Array instead of a Set, just use push instead of add and includes (or indexOf) instead of has, e.g.
var lost_Robot_Scent = [];
lost_Robot_Scent.push( [1, 1].toString() );
lost_Robot_Scent.includes( [1, 1].toString() ); // -> true
lost_Robot_Scent.includes( [2, 2].toString() ); // -> false
If you are worried about performance, you can test these two methods against each other in specific contexts.
Improve The Code
One thing you can do to simplify your code is to lessen the nested if statements. For example, the first if in your Robot_Instruction function could be
if (instruct_The_Robot.length > 100) {
alert("Too many instructions! Please limit to 100."
return;
}
// continue...
Perhaps this is a bit off-topic, but you should only use comments for things are aren't obvious. For example, variable Left declared and instantiated with -90° is unnecessary.
One last thing: you can simplify the "instructions" loop using a switch statement instead of if/else blocks. Or, if you want to make is super-readable, you can use a JavaScript object like so:
var move = {
L: function() {
// turn left
},
R: function() {
// turn right
},
F: function() {
// move forward
},
};
// then, in the "instructions" loop, you can just do
for (var i = 0; i < instruct_The_Robot.length; i++) {
move[ instruct_The_Robot[i] ]();
}
That's a pretty neat trick.
How to prevent a new robots from getting lost in the same places as old robots
Assuming you've fixed your bugs, and robots are moving. When you determine that a robot is moving forward, you have to determine if the new coordinates are already in the lost_Robot_Scent array. You can do this using something like the following:
var robotLostAtSameLocation = false;
for (var i = 0; i < lost_Robot_Scent.length; i++) {
var lostRobotLocation = lost_Robot_Scent[i];
if(lostRobotLocation[0] === x && lostRobotLocation[1] === y) {
robotLostAtSameLocation = true;
break;
}
}
if (robotLostAtSameLocation) {
// whatever you want to do in this case
}
else {
// whatever you want to do in this case
}
Simple optimization
Note that you can get rid of this loop if you change the lost_Robot_Scent array from containing [x,y] to containing something like 'x:y'. So rather than an array that contains other arrays looking like this: [[39,51], [51,15], [-1,11]], it will be an array containing strings looking like: ['39:51', '51:15', '-1:11']. What this buys you is that you can then just say var robotLostAtSameLocation = lost_Robot_Scent.indexOf(x + ':" + y) > -1;
Recommendation
Change var instruction = ["L", "R", "F"]; into something more like var INSTRUCTIONS = {LEFT: 'L', RIGHT: 'R', FORWARD: 'F'};. This turns lines like instruct_The_Robot[i] === instruction[0] into instruct_The_Robot[i] === INSTRUCTIONS.LEFT, improving readability.
Bugs
You are never updating x, y, or orientation. Your robots are never moving. You are only outputting a string.
You are only checking if the y-coordinate is out of bounds. You are forgetting to check if the x-coordinate is out of bounds.
You are pushing [x,y] into the lost_Robot_Scent array on one line, then pushing "| ( " + x + ", " + y + " ) " + "<br />" into the same array on another line. Don't do that. It's hard to reason about a program when it is not consistent.
There may be other issues - I can't take the time to fully digest it at the moment.
I'm practising writing Javascript by making a Roguelike dungeon game but there is a problem when I want to create monsters. I have written a while loop such as:
this.getRandomCoordinatesInRoom = function(roomNumber) {
var validLocationFound = false;
while (!validLocationFound){
// Generate co-ords in room first
x = Math.floor(Math.random() * (this.roomList[roomNumber].width) + (this.roomList[roomNumber].posX));
y = Math.floor(Math.random() * (this.roomList[roomNumber].height) + (this.roomList[roomNumber].posY));
// Find location of (x,y) in Dungeon Array
//alert(arrayLocation);
var tmpX = ((this.roomList[roomNumber]).posX + x);
var tmpY = ((this.roomList[roomNumber]).posY + y);
var arrayLocation = ((tmpY * 80) + tmpX);
//var arrayLocation = ((this.roomList[roomNumber].posX + x) + (80 * (this.roomList[roomNumber].posY + y)));
if (this.dungeonArray[(tmpY + tmpX)] === "floor") {
validLocationFound = true;
};
if ((x<this.roomList[roomNumber].posX) || (x>(this.roomList[roomNumber].posX + this.roomList[roomNumber].width))){
alert("x out of bounds");
};
if ((y<this.roomList[roomNumber].posY) || (y>(this.roomList[roomNumber].posY + this.roomList[roomNumber].height))){
alert("y out of bounds");
};
writeToScreen("Room upper left corner = " + (this.roomList[roomNumber].posX).toString() + "," + (this.roomList[roomNumber].posY).toString(),10);
return [x,y];
if (!(getTileAt(arrayLocation) === "floor")){
alert("It messed up");
}
};
The code randomly generates an x,y coordinate and converts it to a single number (My dungeon array is one dimensional, 0-79 across and then 80 is a new row). however, even when the code generates a coordinate that isn't valid (!= "floor"), it still finishes the function as though it returned true. Why is this?
Your function returns [x,y] from inside the while loop. Declare the variables outside of the loop and then return the value from outside the loop. Or else, return is when validLocationFound is true.
var x, y ;
while(...) {
...
}
return [x, y];