My question concerns creating an array of moving objects. The goal is to have each created "symbol" starts at x=200 when created and then moves along the x-axis. This is possible by creating individual objects, though when I try to make them appear in an array they just appear on top of each other (made the balls transparent so you can see them stack). Is there a way to create an array of individual array objects so that this doesn't happen.
int numSymbols = 100;
int symbolXPos;
int i;
Symbol[] symbols = new Symbol[numSymbols];
void setup(){
for(int i = 0; i < numSymbols; i++){
symbols[i] = new Symbol();
}
size(748,1024);
}
void draw(){
background(255,255,255);
i++;
if(i > 10){
symbols[1].addSymbol(i);
}
if(i > 100){
symbols[2].addSymbol(i);
}
if(i > 200){
symbols[3].addSymbol(i);
}
}
int symbolY = 748-2*6-89-180;
int symbolX = 200;
int symbolPos;
boolean firstLoop = true;
int xSpeed;
class Symbol{
void addSymbol(int xSpeed){
if(firstLoop == true){
symbolXPos = xSpeed;
firstLoop = false;
}else{
xSpeed = symbolX + (xSpeed - symbolXPos);
fill(0,0,0,20);
noStroke();
rect(xSpeed,symbolY, 36, 36, 18);
}
}
}
The first part that looks strange is that you have these properties that seem related to a Symbol instance, and not to the main scope:
int symbolY = 748-2*6-89-180;
int symbolX = 200;
int symbolPos;
boolean firstLoop = true;
int xSpeed;
perhaps you meant something like this:
int numSymbols = 100;
int symbolXPos;
int i;
Symbol[] symbols = new Symbol[numSymbols];
void setup() {
for (int i = 0; i < numSymbols; i++) {
symbols[i] = new Symbol();
}
size(748, 1024);
}
void draw() {
background(255, 255, 255);
i++;
if (i > 10) {
symbols[1].addSymbol(i);
}
if (i > 100) {
symbols[2].iaddSymbol(i);
}
if (i > 200) {
symbols[3].addSymbol(i);
}
}
class Symbol {
int symbolY = 748-2*6-89-180;
int symbolX = 200;
int symbolPos;
boolean firstLoop = true;
int xSpeed;
void addSymbol(int xSpeed) {
if (firstLoop == true) {
symbolXPos = xSpeed;
firstLoop = false;
} else {
xSpeed = symbolX + (xSpeed - symbolXPos);
fill(0, 0, 0, 20);
noStroke();
rect(xSpeed, symbolY, 36, 36, 18);
}
}
}
Even so, it feels like the code is more complex than it should be and there is some confusion regarding classes and objects/instances.
Let's assume you're simply going to move symbols horizontally. You could use a class as simple as this:
class Symbol{
//position
float x;
float y;
//speed
float speedX;
void updateAndDraw(){
//update position
x += speedX;
//reset to 0 if out of bounds
if(x > width) x = 0;
//draw
rect(x, y, 8, 8, 18);
}
}
It has an x,y and just a speedX for now. The x property is incremented by the speed, and the updated position is used to render the symbol on screen.
Here's a basic sketch using the above class:
int numSymbols = 100;
Symbol[] symbols = new Symbol[numSymbols];
void setup(){
size(748, 1024);
fill(0, 0, 0, 64);
noStroke();
for (int i = 0; i < numSymbols; i++) {
symbols[i] = new Symbol();
//use different speeds to easily tell the symbols appart
symbols[i].speedX = 0.01 * (i+1);
//increment y position so symbols don't overlap
symbols[i].y = 10 * i;
}
}
void draw(){
background(255);
for (int i = 0; i < numSymbols; i++) {
symbols[i].updateAndDraw();
}
}
class Symbol{
//position
float x;
float y;
//speed
float speedX;
void updateAndDraw(){
//update position
x += speedX;
//reset to 0 if out of bounds
if(x > width) x = 0;
//draw
rect(x, y, 8, 8, 18);
}
}
The key points are:
using properties related to a Symbol within the class, not outside (which would mean the global scope)
using different positions so Symbol instances don't overlap
Be sure to check out Daniel Shiffman's Objects tutorial, it provides a nice and easy intro to Object Oriented Programming
Related
I have such a struct
struct OfferBid {
string id_user;
uint qty_energy;
uint typ;
uint price_energy;
uint status;
uint t_submission;
uint ts_delivery;
uint number;
uint quality_energy;
}
and I have an array of this struct:
OfferBid[] tempOffers;
I found out how to sort tempOffers by price_energy. I use this function which creates an array of unit from the field price:
function quickSortOffersBidsPrice(Lb.Lib.OfferBid[] memory arr, bool ascending) public view returns(Lb.Lib.OfferBid[] memory) {
if(arr.length == 0) return arr;
uint[] memory prices = lib.arr_of_prices_offerbids(arr);
Lb.Lib.OfferBid[] memory sorted = get_indices_and_sort(prices,arr,ascending);
return sorted;
}
which calls these other functions:
Here I create an array of unit with the indices of the array of struct.
function get_indices_and_sort(uint[] memory values, Lb.Lib.OfferBid[] memory offers_bids, bool ascending) private pure returns(Lb.Lib.OfferBid[] memory) {
uint[] memory indices = new uint[](values.length);
for (uint z = 0; z < indices.length; z++) {
indices[z] = z;
}
Sorting.quickSort_indices(values, 0, int(values.length-1), indices);
if(!ascending){
indices = reverseArray(indices);
}
Lb.Lib.OfferBid[] memory sorted = new Lb.Lib.OfferBid[](values.length);
for (uint z = 0; z < indices.length; z++) {
sorted[z] = offers_bids[indices[z]];
}
return sorted;
}
I sort the array of prices and then at the same time the indices. Then I can sort the original array of struct
function quickSort_indices(uint[] memory arr, int left, int right, uint[] memory indices) public pure {
int i = left;
int j = right;
if (i == j) return;
uint pivot = arr[uint(left + (right - left) / 2)];
while (i <= j) {
while (arr[uint(i)] < pivot) i++;
while (pivot < arr[uint(j)]) j--;
if (i <= j) {
(arr[uint(i)], arr[uint(j)]) = (arr[uint(j)], arr[uint(i)]);
(indices[uint(i)], indices[uint(j)]) = (indices[uint(j)], indices[uint(i)]);
i++;
j--;
}
}
if (left < j)
quickSort_indices(arr, left, j, indices);
if (i < right)
quickSort_indices(arr, i, right, indices);
}
How can I sort it first by price_energy, and in case of same price_energy, sort it byqty_energy?
Since int256 has a sufficiently large dimension, you can use the composite key for ordering:
key= (price_energy<<128) | qty_energy
In addition, it may be more efficient to order the array not after its complete formation, but incrementally - as elements are added.
According to this answer. Сustomize a next sample:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Sort {
uint public total = 5;
mapping(uint => Item) private itemIdToItem;
struct Item {
uint id;
uint price;
}
constructor() {
itemIdToItem[1] = Item(1, 2);
itemIdToItem[2] = Item(2, 5);
itemIdToItem[3] = Item(3, 1);
itemIdToItem[4] = Item(4, 3);
itemIdToItem[5] = Item(5, 4);
}
/**
* #dev Returns tuple(uint256,uint256)[]: 1,2, 2,5, 3,1, 4,3, 5,4
*/
function getItems() public view returns(Item[] memory) {
uint totalMatches = 0;
Item[] memory matches = new Item[](total);
for (uint i = 1; i <= total; i++) {
Item memory e = itemIdToItem[i];
matches[totalMatches] = e;
totalMatches++;
}
return matches;
}
/**
* #dev Returns tuple(uint256,uint256)[]: 3,1, 1,2, 4,3, 5,4, 2,5
*/
function sortByPrice() public view returns(Item[] memory) {
Item[] memory items = getItems();
for (uint i = 1; i < items.length; i++)
for (uint j = 0; j < i; j++)
if (items[i].price < items[j].price) {
Item memory x = items[i];
items[i] = items[j];
items[j] = x;
}
return items;
}
}
This function should be enough to sort the array of objects/structs that contain price values. To include the other keys, we can compare them in if condition before swiping the values.
function sortByPrice() public view returns(PrintableResources[] memory) {
PrintableResources[] memory items = printableResources;
for (uint i = 1; i < items.length; i++)
for (uint j = 0; j < i; j++)
if (items[i].price < items[j].price) {
PrintableResources memory x = items[i];
items[i] = items[j];
items[j] = x;
}
return items;
}
Goal: I am trying to create a ray tracer in C. I just added in a light source that should give each of my three spheres a shading effect based on where the light is. If the light is to the left of all of them, a shadow should be cased on the right.
Problem: When changing the light intensities and position of the light, all the spheres are changed uniformly. The spheres will be more or less lit equally and there is no variation of lighting on individual pixels on the sphere.
My debugging attempts: I have tried looking through the variable outputs by printing out a lot of different info and I think the source comes from my variable
diffuse_light_intensity
which does not change much (through all the iterations on the screen the value changes twice when it should be changing quite often due to the angles of the light on the surface changing quite a bit)
My Code: (my theory is the problem lies in scene_intersect() or cast_ray())
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <math.h>
#include <limits.h>
typedef struct {
float position[3];
float intensity;
} Light;
typedef struct {
float diffuse_color[3];
} Material;
typedef struct {
float center[3];
float radius;
Material material;
} Sphere;
int arrSub(const float arr1[], const float arr2[], float subArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
subArr[i] = arr1[i] - arr2[i];
}
return 0;
}
int arrAdd(const float arr1[], const float arr2[], float addArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 + arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
addArr[i] = arr1[i] + arr2[i];
}
return 0;
}
int arrScalarMult(const float arr1[], float scalar, float newArr[], int length) {
/*
Requires 3 equally sized arrays (denoted as length),
arr1 - arr2 will result in the third array subArr
*/
for (int i = 0; i < length; i++) {
newArr[i] = arr1[i] * scalar;
}
return 0;
}
float dotProduct(const float arr1[], const float arr2[], int length) {
/*
Returns the dot product of two equal sized arrays
(treated as vectors)
a (dot) b = a1b1 + a2b2 + ... anbn
*/
float result = 0;
for (int i = 0; i < length; i++) {
result += arr1[i] * arr2[i];
}
return result;
}
int normalize(float arr[], int len) {
//Normalize a vector (array)
float sumSqr;
float norm;
for (int i = 0; i < len; i++) {
sumSqr += arr[i] * arr[i];
}
norm = sqrt(sumSqr);
for (int i = 0; i < len; i++) {
arr[i] = arr[i] / norm;
}
return 0;
}
bool ray_intersect(const float origin[], const float dir[], float t0, Sphere s) {
/*
Ray-Sphere Intersection
Vectors:
origin (the zero vector)
dir (direction vector)
L (vector from origin to center of sphere)
Scalars:
tca
d2
thc
t0
t1
*/
float L[3] = {0,0,0}; //The zero vector
arrSub(s.center, origin, L, 3); //L is now the vector from origin to the sphere's center
float tca = dotProduct(L, dir, 3); //Projection of L onto dir
float d2 = dotProduct(L, L, 3) - tca*tca;
if (d2 > s.radius * s.radius) return false; //There is no intersection, so return false.
float thc = sqrtf((s.radius*s.radius - d2));
t0 = tca - thc;
float t1 = tca + thc;
if (t0 < 0) {
t0 = t1;
}
if (t0 < 0) return false;
return true;
}
bool scene_intersect(const float origin[], const float dir[], const Sphere s[], int len, float hit[], float N[], Material * ptr_m) {
float sphere_dist = INT_MAX;
for (size_t i=0; i < len; i++) {
float dist_i;
if (ray_intersect(origin, dir, dist_i, s[i]) && dist_i < sphere_dist) {
sphere_dist = dist_i;
float dirDist[3];
arrScalarMult(dir, dist_i, dirDist, 3);
arrAdd(origin, dirDist, hit, 3);
float hitMinusCenter[3];
arrSub(hit, s[i].center, hitMinusCenter, 3);
normalize(hitMinusCenter, 3);
N[0] = hitMinusCenter[0];
N[1] = hitMinusCenter[1];
N[2] = hitMinusCenter[2];
* ptr_m = s[i].material;
}
}
return sphere_dist<1000;
}
int cast_ray(const float origin[], const float dir[], const Sphere s[], const Light l[], int l_size, unsigned char colorArr[]) {
float point[3], N[3];
Material m;
Material * ptr_m = &m;
if (!scene_intersect(origin, dir, s, 3, point, N, ptr_m)) {
//background
colorArr[0] = 5; //red
colorArr[1] = 100; //green
colorArr[2] = 250; //blue
} else {
float diffuse_light_intensity = 0;
float light_dir[3];
for (size_t i = 0; i < l_size; i++) {
arrSub(l[i].position, point, light_dir, 3);
normalize(light_dir, 3);
diffuse_light_intensity += l[i].intensity * ((0.f >= dotProduct(light_dir, N, 3) ? (0.f) : (dotProduct(light_dir, N, 3))));
}
//light up pixel
colorArr[0] = m.diffuse_color[0] * diffuse_light_intensity;
colorArr[1] = m.diffuse_color[1] * diffuse_light_intensity;
colorArr[2] = m.diffuse_color[2] * diffuse_light_intensity;
}
return 0;
}
int render(const Sphere s[], const Light l[], int l_length) {
/*
Creates image in a new color each step.
*/
const int width = 1024;
const int height = 768;
FILE *fp = fopen("fourth.ppm", "wb"); // Write in binary mode
(void) fprintf(fp, "P6\n%d %d\n255\n", width, height);
float fov = 3.1415926535/2.; // Field of View
#pragma omp parallel for
for (size_t j = 0; j < height; j++) {
for (size_t i = 0; i < width; i++) {
float x = (2*(i+.5)/(float)width - 1)*tan(fov/2.)*width/(float)height;
float y = -(2*(j+.5)/(float)height - 1)*tan(fov/2.);
float dir[] = {x,y,-1};
normalize(dir, 3);
unsigned char color[3];
const float origin[] = {0,0,0};
cast_ray(origin, dir, s, l, l_length, color);
(void) fwrite(color, 1, 3, fp);
}
}
(void) fclose(fp);
return 0;
}
int main(void) {
Material red = {255,0,0};
Material pink = {150,10,150};
Material gold = {255, 195, 0};
//Populate with spheres
Sphere s[3];
Sphere originalS = {{-3,0,-16},2,gold};
Sphere bigS = {{-1.0, -1.5, -12}, 3, red};
Sphere anotherS = {{7,5,-18},2,pink};
s[0] = originalS;
s[1] = bigS;
s[2] = anotherS;
//Add light source
Light l[1];
Light test_light = {{-20,20,20}, 1.5};
l[0] = test_light;
render(s,l, 1);
printf("Run success!\n");
return 0;
}
If any clarification is needed on my code please let me know, I am quite new to both C and stackoverflow.
There's a fundamental error in ray_intersect where you're passing the t0 variable by value, and not as a pointer, and therefore in the scene_intersect function its value is always zero.
The other problem is that you don't initialize the sumSqr in the normalize function, resulting in that function returning NaN for each vector component.
With those two fixed I get something approximating shaded balls. The errors in that image are caused by failing to ensure that your output pixel values fall in the range [0, 255].
NB: both of these first errors are detected if you turn on full compiler error checking, warning you of uninitialised variables being used.
I am trying to populate a 2D array vertically or horizontally from a given coordinate, if the indexes are in range.
Below is the program I can think about as of now.
I just want to know if there is any other optimized way to perform this logical operation.
public static void Main()
{
var arr = new string[10,10];
int x = 0;
int y = 1;
int len = 5;
string somevalue = "x";
string align = "vertical";
int i = x;
int j = y;
try
{
while(len > 0)
{
arr[i,j] = somevalue;
if(align == "vertical")
j++;
else
i++;
len--;
}
}
catch(IndexOutOfRangeException ex)
{
Console.WriteLine(ex);
}
}
I'm taking a computer science class at my high school, and we learned a lesson on selection sort today. I wrote a program (it's probably clumsy, but please bear with me, I'm learning) and it works in that it sorts, but sometimes it throws an ArrayIndexOutOfBoundsException. Only sometimes. I don't know how this is possible, because I deal with the same array throughout the entire program and arrays have a fixed length. If anyone has some insight it would be extremely helpful.
I think the error has something to do with int first = y[movedVariable];. However, I don't understand how movedVariable can be out of bounds, because I'm pretty sure I wrote my program so that it would be < the length of the array.
public class selectionSort
{
public static int[] array;
public static int movedVariable = 0;
public static void main()
{
array = new int[10];
int x;
for (int count = 0; count < array.length; count++)
{
if (count == 0)
{
x = (int)(Math.random()*100+2);
array[count] = x;
}
else
{
x = (int)(Math.random()*100+2);
for (int y = 0; y < count; y++)
{
while(x == array[y])
{
x = (int)(Math.random()*100+2);
}
}
array[count] = x;
}
}
sort(array);
}
public static void sort(int[] x)
{
int thing = 0;
for(int hello = 0; hello < x.length; hello++)
{
int part = x[thing];
for ( int count = thing; count < x.length-1; count++)
{
if( part > x[count+1] )
{
part = x[count+1];
}
}
thing++;
swap( x, part);
}
int f = 0;
String output = "";
for( int val : x )
{
if (f%10 == 0)
{output += "\n";}
output += val + " ";
f++;
}
System.out.print(output);
}
public static int[] swap(int [] y, int num)
{
int count = 0;
int index = 0;
for ( count = 0; count < y.length; count++)
{
if (y[count] == num)
{index = count;}
}
int first = y[movedVariable];
y[movedVariable] = y[index];
y[index] = first;
movedVariable++;
return y;
}
}
For fun, I ran your code for 1,000,000 iterations and no out of bounds exception, unless I did not clear the static movedVariable to 0 before each iteration.
Since movedVariable is static after the first 10 calls to swap() it will be 10 and if another call is made to swap you'll get the index out of bounds. However, this can only happen if you call sort() more than once per run. Only use static for values that need to be preserved between instances of your class. Non statics that are part of the your instance state. Local variables for everything else. Otherwise your are creating a mine field of bugs just waiting to happen.
I refactored your class to remove variables that have the same functionality. For example your thing and your movedVariable and your hello variable in sort() can be just one variable. Try to eliminate multiple variables that do the same thing, like the plague. It is a source of non obvious bugs.
Also, you are passing the value in the array to swap then looking for it in the array to get the index, this is a waste of time. Just pass in the index to swap. It also creates a problem for your sort function when you have the same value at two different places. Swap will use the last one it finds. sort() should handle duplicate values in the array. That explains why you initialized your array with unique values. You should not have to do that. Actually you should test your code with duplicates explicitly added to make sure your function works.
I moved printing of the array out of sort into its own method. It is useful for debugging at intermediate steps not just when the sort is done.
I tried to leave variable names the same and the logic unchanged so you can follow the changes.
public class Main
{
public static void sort(int[] x)
{
for (int movedVariable = 0; movedVariable < x.length; movedVariable++)
{
int part = x[movedVariable];
int index = movedVariable;
for (int count = movedVariable; count < x.length - 1; count++)
{
if (part > x[count + 1])
{
part = x[count + 1];
index = count + 1;
}
}
swap(x, index, movedVariable);
}
printArray(x);
}
private static void printArray(int[] x)
{
int f = 0;
String output = "";
for (int val : x)
{
if (f % 10 == 0)
{
output += "\n";
}
output += val + " ";
f++;
}
System.out.print(output);
}
public static int[] swap(int[] y, int index, int movedVariable)
{
int first = y[movedVariable];
y[movedVariable] = y[index];
y[index] = first;
return y;
}
public static void main(String[] args)
{
int[] array = new int[10];
int x = 0;
for (int count = 0; count < array.length; count++)
{
for (int y = count; --y >= 0; )
{
do
{
x = (int) (Math.random() * 100 + 2);
}
while (x == array[y]);
}
array[count] = x;
}
printArray(array);
sort(array);
}
}
I need an idea how to effectively find areas below marked with 0 in two-dimensional array. It should be noted that there are other areas, such as this picture shows one of two who owns coordinate (0.0) and the other owns coordinate (21.3).
00000000000111110000111
00000000001111110000111
00000000011111100000111
00000000000111000001101
00000000011100000011101
00000001111100001111001
00000111111111011111001
00000001111100001111001
00000000010000000011001
00000000000000000001111
Of course a real array will be much larger.
Recursive version that goes to all sides and stops at mark 1 or array side isn't fast enough.
It looks like you're looking for a flood-fill algorithm. The wikipedia page I linked lists a few algorithms which may be faster than the obvious recursive method.
Flood-fill will be a good match if the areas you're looking for are small compared to the entire array, and you don't need to search for all of them. If you need to know about most or all of them, then computing them all in a single shot using a union-merge based connected component labeling algorithm may be a better choice. Here's some code that implements such an algorithm (note that I've altered it to run in a single pass):
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <map>
const char *data[] = {
"00000000000111110000111",
"00000000001111110000111",
"00000000011111100000111",
"00000000000111000001101",
"00000000011100000011101",
"00000001111100001111001",
"00000111111111111111001",
"00000001111100001111001",
"00000000010000000011001",
"00000000000000000001111",
NULL
};
struct label {
private:
int index;
int rank;
label *parent;
public:
label ()
: index(-1), rank(0), parent(this)
{ }
int getIndex(int &maxIndex) {
if (parent != this)
return find()->getIndex(maxIndex);
if (index < 0)
index = maxIndex++;
return index;
}
label *find() {
if (parent == this)
return this;
parent = parent->find();
return parent;
}
label *merge(label *other)
{
label *xRoot = find();
label *yRoot = other->find();
if (xRoot == yRoot)
return xRoot;
if (xRoot->rank > yRoot->rank) {
yRoot->parent = xRoot;
return xRoot;
} else {
xRoot->parent = yRoot;
if (xRoot->rank == yRoot->rank)
yRoot->rank++;
return yRoot;
}
}
};
int width, height;
int main() {
for (int i = 0; data[0][i]; i++)
width = i + 1;
for (int i = 0; data[i]; i++) {
height = i + 1;
}
std::vector<std::vector<unsigned short> > lblinfo;
lblinfo.resize(height, std::vector<unsigned short>(width, 0));
std::vector<label *> labels;
labels.push_back(NULL); // 0 is used as an unassigned flag
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (data[y][x] == '1')
continue;
// Try to find a neighboring label
unsigned short lblid = 0;
if (x != 0 && lblinfo[y][x-1] != 0)
lblid = lblinfo[y][x-1];
// merge with cells above
if (y != 0) {
for (int x2 = x - 1; x2 <= x + 1; x2++) {
if (x2 < 0)
continue;
if (x2 >= width)
continue;
unsigned short otherid = lblinfo[y - 1][x2];
if (!otherid)
continue;
if (!lblid)
lblid = otherid;
else {
labels[lblid]->merge(labels[otherid]);
}
}
}
if (!lblid) {
// assign a new label
lblid = labels.size();
labels.push_back(new label);
}
lblinfo[y][x] = lblid;
}
}
// Assign indices to the labels by set and print the resulting sets
int maxindex = 0;
static const char chars[] = "abcefghijklmnopqrstuvwxyz";
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned short labelid = lblinfo[y][x];
if (labelid == 0) {
putchar(data[y][x]);
continue;
}
label *label = labels[labelid];
int idx = label->getIndex(maxindex);
if (idx >= sizeof(chars) - 1) {
printf("\n\n Too many labels to print!\n");
exit(1);
}
putchar(chars[idx]);
}
printf("\n");
}
return 0;
}