How would I sort/align two serparate arrays? - p5.js

I have two sets of arrays loaded in from .txt documents, one of the files has three values on every line; an ID, an x co-ordinate and a y co-ordinate, the second file only has the ID but sorted in order of when I need call the x and y.
First file looks like this
1 565.0 575.0
2 25.0 185.0
3 345.0 750.0
4 945.0 685.0
5 845.0 655.0
Second looks like this:
5
1
4
3
2
I'll try demonstrate what I've done below without using my exact code as it's for a class project:
let fileData = {id: [], x: [], y: []};
let data = [];
function preload() {
tempFileName = loadStrings('address/to.txt');
tempFileName2 = loadStrings('address/to/other.txt');
}
function setup() {
createCanvas(750, 750);
loadFile(tempFileName);
}
function draw() {
background(0);
}
function loadFile(filename) {
probData = new Array(filename.length);
for (let i = 0; i < probData.length; i++) {
data[i] = splitTokens(filename[i]);
fileData.id.push(data[i][0]);
fileData.x.push(data[i][1]);
fileData.y.push(data[i][2]);
}
}
This has allowed me to draw dots on the screen using fileData.x and fileData.y as points in a separate function I have made, but now I need to write another function that draws lines from the x and y co-ordinates that match the ID in the second file, problem is I cannot find a way to align the two arrays, and I'd need to do this without changing the code I have already (unless there is a better way to split the data and use it)

I think a lot of the confusion you have is to do with how you're storing the id, x and y. You're currently storing them all in their own arrays, it would make more sense to store them as an array of objects.
And then when you're looping through the array and drawing the dots, you can use that index to find which other dot you're supposed to line up to.
The example below should point you in the right direction. Also, here's a link to the p5.js sketch to see it running.
let dots = [];
let dotsData;
let orderData;
function preload() {
dotsData = loadStrings('./dots.txt');
orderData = loadStrings('./orderFile.txt');
}
function setup() {
createCanvas(1000, 1000);
createDots(dotsData);
}
function draw() {
background(220);
fill(255, 100, 200);
for (let i = 0; i < dots.length; i++) {
circle(dots[i].x, dots[i].y, 20);
let goalDot = dots.find(e => e.id == orderData[i]);
if (goalDot) {
line(dots[i].x, dots[i].y, goalDot.x, goalDot.y);
}
}
}
function createDots(filename) {
const probData = new Array(filename.length);
for (let i = 0; i < probData.length; i++) {
dotsData[i] = splitTokens(filename[i]);
dots.push({
id: dotsData[i][0],
x: dotsData[i][1],
y: dotsData[i][2]
})
}
}

Related

Can this appscript run faster/be rewritten to run faster when I have 200 rows?

1. Code description: I wrote this app script that for each row, colors the cell in column A the same color as the last cell of that row with text in it. Additionally, I use an onEdit trigger, so whenever I edit a row, the script runs. This worked alright when I had about 20 rows and 20 columns (2-3 seconds).
2. Problem: I now have a sheet with about 200 rows and 20 columns and the code is extremely slow (3-4 minutes or more).
3. QUESTION: How to make it run faster, or, given what I need, should I write this task in another way?
4. Solutions I thought about but don't like:
split my sheet into several sheets (not as helpful for my use case)
add a button to run the app only when I make an edit (not as nice as an onEdit)
5. Code:
function colorFirstCell() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('courseX');
var lastRow = sheet.getLastRow();
var lastColumn = sheet.getLastColumn();
var columnFirstCells = 1; // column of cell to be colored
var dataRange = sheet.getRange(1,1, lastRow, lastColumn + 1).getValues();
for(var i = 0; i < lastRow; i++)
{
for(var j = 0; j < lastColumn; j++) {
if(dataRange[i][j] != '' && dataRange[i][j+1] == '') { // cell not empty and cell to the right is empty
var backgroundColor = sheet.getRange(i + 1, j + 1).getBackground(); // get color
sheet.getRange(i + 1, columnFirstCells).setBackground(backgroundColor); // set color
of first col cell
}
}
}
}
I believe your goal is as follows.
You want to reduce the process cost of your script.
In this case, how about the following modification?
Modified script:
function colorFirstCell2() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('courseX');
var range = sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());
var backgrounds = range.getBackgrounds();
var colors = range.getDisplayValues().map((r, i) => {
for (var j = r.length - 1; j >= 0; j--) {
if (r[j] != "") {
return [backgrounds[i][j]];
}
}
return [null];
});
sheet.getRange(1, 1, colors.length).setBackgrounds(colors);
}
In this case, first, the values and background colors are retrieved from the data range. And then, an array including the background colors is created. And, the created array is put to the column "A".
References:
map()
setBackgrounds(color)

p5.js Recursive Bubble Sort

I'm trying to modify this solution to work for Bubble Sort, but I'm a bit out of my depth, especially with the whole async function business. The code works up to a point, but does not follow the exact pattern I would expect for Bubble Sort, and only partially sorts the array.
Can anyone help me out please?
let values = [];
let startSort = true;
function bubbleSort( a ) {
// create copy of the array
clone = a.slice();
// asynchronous sort the copy
recursiveBubbleSort( clone, clone.length );
return;
}
//Recursive Bubble Sort
async function recursiveBubbleSort( arr, n ) {
//If there is only single element
//the return the array
if ( n === 1 ) {
return arr;
}
await recursiveBubbleSort( arr, n - 1 );
//Swap the elements by comparing them
for ( let j = 0; j < n - 1; j++ ) {
if ( arr[j] > arr[j + 1] ) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
// copy back the current state of the sorting
values = arr.slice();
// slow down
await sleep( 500 );
}
async function sleep( ms ) {
return new Promise( resolve => setTimeout( resolve, ms ) );
}
function setup() {
createCanvas( 600, 190 );
frameRate( 60 );
}
let numOfRects = 15;
let rectWidth;
function draw() {
if ( startSort ) {
startSort = false;
rectWidth = floor( width / numOfRects );
values = new Array( floor( width / rectWidth ) );
for ( let i = 0; i < values.length; i++ ) {
values[i] = random( height );
}
bubbleSort( values );
}
background( 23 );
stroke( 0 );
fill( 255 );
for ( let i = 0; i < values.length; i++ ) {
rect( i * rectWidth, height - values[i], rectWidth, values[i] );
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
In this answer I will not focus on how async and await work because that doesn't seem to be your goal. I'll show you how to make a working version of the bubble sort instead.
First let's get rid of this startSort variable you have: You use it to initialize your values and a better way to do it is to use the setup() function used by p5:
function setup() {
createCanvas(600, 190);
rectWidth = floor(width / numOfRects);
// Generate the values
values = new Array(floor(width / rectWidth));
for (let i = 0; i < values.length; i++) {
values[i] = random(height);
}
// The number of iterations is equal to the number of values
n = values.length;
}
We first we fill your array with random values and define a global variable n which will hold the remaining number of iterations do to (which is the same as the number of values).
Then let's modify your bubble sort function. Here we don't need it to be recursive because, as I'll show later on, we will simply call it several times until we have done all the iterations.
// Bubble Sort
function bubbleSort(arr, n) {
// If there is no remaining iterations do nothing
if (n <= 1) {
return 0;
}
// Swap the elements by comparing them
for (let j = 0; j < n - 1; j++) {
if (arr[j] > arr[j + 1]) {
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
}
}
// We did one more iteration return the remaining number of iterations
return n - 1;
}
There are 3 important things here:
The function modifies the arr in place: so when you call the function with an array you will have the result in the same array.
The function returns the remaining number of iterations do it (each call to the function is one iteration)
If you call it with n the number of remaining of iterations at 1 or 0 it will simply do nothing. Otherwise it will make one pass on the array.
Now you can change your draw() function. This function is called automatically by p5 X times by seconds (by default 60). So each time it is ran it will call the bubble sort function, updating the array and the number of remaining iterations:
function draw() {
// Define the "speed" at which we do the iterations
frameRate(10);
background(23);
stroke(0);
fill(255);
// Show the values
for (let i = 0; i < values.length; i++) {
rect(i * rectWidth, height - values[i], rectWidth, values[i]);
}
// Make one new iteration
n = bubbleSort(values, n);
}
Note how we used frameRate() to call it less often to let the user see the different steps of the sort.
All you need is to declare your global variables at the beginning of your sketch, put everything together and you are good to go.
let values = [];
let numOfRects = 15;
let rectWidth;
let n;
You can see the complete code here you will notice that I did to more things in this implementation:
I extracted the code which puts new values in the array in it's own function resetArray()
I call this function in the setup() function to initialize the animation but also in draw() when n===0 so that when the array is sorted we generate new values to have an infinite animation.
A note about async and await. These functions are used to create asynchronous code in javascript. This is a whole topic which is not trivial for someone new to programming, you can read the doc here. Basically async is used to say that a function will take time to be executed and await is used to say to wait for the function to finish it's execution.
In the function you go inspiration from, this asynchronous code is used to put a delay between two calls to the bubbleSort function so that the user can see the different iterations. Here you don't really need it because p5 gives you the mechanism of draw() and frameRate() to handle that more easily.

Loops and iterations

Is there a way that a function has 2 options of return and the option of return is chosen after a certain interval of iterations?
example:
a function that swaps from "a" to "b" and "b" to "a" after 4 iterations returns:
a
a
a
a
b
b
b
b
a
a
a
a
b
b
b
b
.
.
.
Edit I did something like this to solve the problem:
var counter = 0;
var state = true;
var changeState = function(){
var x = 0
while(x != 12){
if(counter == 4){
counter = 0;
state = !state;
}
if (state){
console.log("a");
} else {
console.log("b")
}
counter += 1;
x += 1
}
}
changeState();
You will need to have a stateful function, as it needs to somehow remember something from previous call(s) that were made to it. This is a so-called side effect, and means that the function is not pure.
For the example you have given, the function would need to know (i.e. have a state with) the number of previous calls (modulo 8), or the previous four returned values, or some mix of this information.
How such a function is implemented, depends on the programming language.
In object oriented programming languages you would create a class with the function as method, and a property reflecting that state. When the function is called, it also updates the state. For instance, in Java:
class MyClass {
int callCount = 0;
char myFunction() {
return "aaaabbbb".charAt(this.callCount++ % 8);
}
}
You would call the function repeatedly like so:
MyClass obj = new MyClass();
for (int i = 0; i < 10; i++) {
System.out.println(obj.myFunction());
}
In JavaScript you could do the same, or you could create a closure:
function createFunction() {
let callCount = 0;
return function myFunction() {
return "aaaabbbb"[callCount++ % 8];
}
}
let myFunction = createFunction();
for (let i = 0; i < 10; i++) {
console.log(myFunction());
}
In Python you can do the same, but it allows also to use default arguments (which are only initialised at function definition time), and so you could define an argument that is an object holding a counter:
def myFunction(counter=[0]):
counter[0] += 1
return "aaaabbbb"[counter[0] % 8]
for _ in range(10):
print(myFunction())
This is of course not an exhaustive list of possibilities, but the essence is that programming languages offer their own ways to construct such stateful functions.
Iterators
Some languages offer a different approach: iterators. This means the function produces a stream of return values. The function can run to produce the first value after which the running state is saved until a new value is requested from it. The function's execution context is then restored to run until it can produce the next value, ...etc.
Here is how that design would look in JavaScript:
function * myIterator() {
let callCount = 0;
while (true) {
yield "aaaabbbb"[callCount++ % 8];
// ^^^^^ a language construct for yielding back to the caller
}
}
let iter = myIterator();
for (let i = 0; i < 10; i++) {
console.log(iter.next().value);
}
When a programming language offers this possibility, it is often preferred over the other alternatives listed earlier.

How to set up if statements so that loop goes forward and then in reverse? Processing

int x = 31;
int y = 31;
int x_dir = 4;
int y_dir = 0;
void setup ()
{
size (800, 800);
}
void draw ()
{
background (150);
ellipse (x,y,60, 60);
if (x+30>=width)
{
x_dir =-4;
y_dir = 4;
}
if (y+30>=height)
{
x_dir=4;
y_dir = 0;
}
if (x+30>=width)
{
x_dir = -4;
}
x+=x_dir;
y+=y_dir;
println(x,y);
}
Hi,
I have to create this program in processing which produces an animation of a ball going in a Z pattern (top left to top right, diagonal top right to bottom left, and then straight from bottom left to bottom right) which then goes backwards along the same path it came.
While I have the code written out for the forward direction, I don't know what 2 if or else statements I need to write for the program so that based on one condition it goes forwards, and based on another condition it will go backwards, and it will continue doing so until it terminates.
If I am able to figure out which two if statements I need to write, all I need to do is copy and reverse the x_dir and y_dir signs on the forward loop.
There are a ton of different ways you can do this.
One approach is to keep track of which "mode" you're in. You could do this using an int variable that's 0 when you're on the first part of the path, 1 when you're on the second part of the path, etc. Then just use an if statement to decide what to do, how to move the ball, etc.
Here's an example:
int x = 31;
int y = 31;
int mode = 0;
void setup ()
{
size (800, 800);
}
void draw ()
{
background (150);
ellipse (x, y, 60, 60);
if (mode == 0) {
x = x + 4;
if (x+30>=width) {
mode = 1;
}
} else if (mode == 1) {
x = x - 4;
y = y + 4;
if (y+30>=height) {
mode = 2;
}
} else if (mode == 2) {
x = x + 4;
if (x+30>=width) {
mode = 3;
}
} else if (mode == 3) {
x = x - 4;
y = y - 4;
if (y-30 < 0) {
mode = 2;
}
}
}
Like I said, this is only one way to approach the problem, and there are some obvious improvements you could make. For example, you could store the movement speeds and the conditions that change the mode in an array (or better yet, in objects) and get rid of all of the if statements.

Generate several random numbers, one of which must be the correct answer to a sum?

I have created a Space Invaders game in which the player must shoot an asteroid which displays a random number. A sum will also be randomly generated at the start of the scene. Once the player shoots an asteroid the scene reloads, with points awarded for correct answers.
The problem I am having is that I need at least one asteroid to display the correct answer. I am currently achieving this by reloading the scene until an asteroids number matches the answer to the sum. This can take quite a few reloads and looks really bad. Is there a better way to achive this which will look better and be more efficient. I have included my effort below. I appreciate any comments. Thanks!
Script for checking the correct answer and reloading the scene.
#pragma strict
function Start ()
{
}
{
if (
Asteroid1_Script.asteroid1Value != (Sum_Script.sumA - Sum_Script.sumB) &&
Asteroid2_Script.asteroid2Value != (Sum_Script.sumA - Sum_Script.sumB) &&
Asteroid3_Script.asteroid3Value != (Sum_Script.sumA - Sum_Script.sumB) &&
Asteroid4_Script.asteroid4Value != (Sum_Script.sumA - Sum_Script.sumB) &&
Asteroid5_Script.asteroid5Value != (Sum_Script.sumA - Sum_Script.sumB)
)
{
Application.LoadLevel("L1");
}
}
Script for randomly generating the sum.
#pragma strict
static var sumA :int = 0;
static var sumB :int = 0;
function Start ()
{
var newSumA = Random.Range(6,10);
sumA = newSumA;
var newSumB = Random.Range(1,6);
sumB = newSumB;
}
function Update () {
//Question Output.
guiText.text = sumA.ToString() + " - " + sumB.ToString()+ " =";
}
Script for generating an asteroids random number.
#pragma strict
var mainCam: Camera;
static var asteroid1Value : int = 0;
var asteroid1 : Transform;
var Asteroid1Style : GUIStyle;
function Start ()
{
var newAsteroid1Value = Random.Range(0,10);
asteroid1Value = newAsteroid1Value;
asteroid1.position.x = mainCam.ScreenToWorldPoint (new Vector3 (160f, 0f, 0f)).x;
asteroid1.position.y = mainCam.ScreenToWorldPoint (new Vector3 (0f, 450f, 0f)).y;
}
function OnGUI()
{
var point = Camera.main.WorldToScreenPoint(transform.position);
GUI.Label(new Rect(point.x, Screen.currentResolution.height - point.y - 530, 110, 100), asteroid1Value.ToString(), Asteroid1Style);
}
function OnCollisionEnter(col : Collision)
{
if(asteroid1Value == (Sum_Script.sumA - Sum_Script.sumB))
{
Destroy(gameObject);
Score_Script.score ++;
}
if(asteroid1Value != (Sum_Script.sumA - Sum_Script.sumB))
{
Score_Script.score --;
}
}
Do as you are doing, generate 5 random numbers for your asteroids.
Then generate a random number between 1 and 5, this is your random asteroid, and then set its value to the answer. (sumA - sumB)
You just need to abstract your logic.
The best argument I can make is, simply put, build your random numbers before you build your asteroids.
That way, you always have a correct one.
I would simply code:
function start(){
var x = 5 //X being whatever number of asteroids you wish.
var a = new Array();
for(var i=0; i<x; i++){
a[i] = Random.Range(0,10);
}
for( i in a){ buildAsteroid(a[i]) }
}
And... if the number matches, success.

Resources