I'm developing a 2D map editor for a game and I need a way to increase or decrease the size of the grid/map uniformly in all directions.
Suppose you have a 3x3 map with a sort of "cross" symbol.
(arrays are zero-indexed. They start with 0)
Like this:
0,1,0
1,1,1
0,1,0
The array would look like this:
map = [0,1,0,1,1,1,0,1,0]
So, tile index 4 would be the center of the map.
I'd like to increase the size from 3x3 to 5x5 for example. So I end up with this:
0,0,0,0,0
0,0,1,0,0
0,1,1,1,0
0,0,1,0,0
0,0,0,0,0
The new map array should end up like this:
map = [0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0]
What's a good way of doing this?
Here are two functions for increase and decrease. The parameter arr is your one-dimensional map and xWidth is the width (and of course the height) of your grid.
I had a question with a similar background here on Stackoverflow so many thanks to willywonka_dailyblah who helped me on the j and i indices.
public int[] increase_grid(int[] arr, int xWidth)
{
int newWidth = (xWidth+2);
int[] result = new int[newWidth * newWidth];
int count=0;
while(count<newWidth)
{
result[count++] = 0;
}
for (int i=0;i<xWidth;i++)
{
result[count++] = 0;
for (int j=0;j<xWidth;j++)
{
result[count++] = arr[i * xWidth + j];
}
result[count++] = 0;
}
while(count<(newWidth*newWidth))
{
result[count++] = 0;
}
return result;
}
public int[] decrease_grid(int[] arr, int xWidth)
{
int newWidth = (xWidth-2);
int[] result = new int[newWidth*newWidth];
for(int i=0; i< newWidth;i++)
{
for (int j=0;j< newWidth;j++)
{
result[i* newWidth + j] = arr[(i+1) * xWidth + (j+1)];
}
}
return result;
}
And I have this print function:
public void print_arr(int[] a, int xWidth)
{
for(int i=0;i<xWidth;i++)
{
for(int j=0;j<xWidth;j++)
{
System.out.print(a[i * xWidth + j]+" ");
}
System.out.println();
}
System.out.println();
}
You call these functions like:
int[] map = new int[]{0,1,0,1,1,1,0,1,0};
print_arr(map, 3);
map = increase_grid(map, 3);
print_arr(map, 5);
map = increase_grid(map, 5);
print_arr(map, 7);
map = decrease_grid(map, 7);
print_arr(map, 5);
So you have to pass the current size of your map and either call increase or decrease. Beware, that the these functions include a nested for-loop. Thus, they are less scale-able on greater grid sizes. I think there may be a solution to wrap even this into a loop-sequence, which runs without nesting.
Related
Does anyone have any suggestions on what might be going wrong with this code? I'm trying to load tiles of images into a large array and then display them. Later on I'll shuffle the pieces. The issue I'm running into is seen near the bottom. I have a for loop that should plug the value of i into the output array and display the relevant image at that index value. Instead I get a null pointer exception. If I replace the letter i with an integer it works perfectly. What could be preventing processing from passing that value if i into the array? Any thoughts? Thanks.
int tileSize = 100;
PImage out; PImage sample;
PImage img;
PImage img2;
String[] imageNames = {"arctic_fox.jpg", "bbridge_in_the_am.jpg", "Kali2.jpg"};
PImage[] images = new PImage[imageNames.length];
//PImage[] output = new PImage[((1440/tileSize)*imageNames.length)*(900/tileSize)];
PImage[] output = new PImage[2000];
int tintScale = 200;
void setup() {
fullScreen();
for (int i=0; i < imageNames.length; i++) {
String imageName = imageNames[i];
images[i] = loadImage(imageName);
}
out = createImage(width, height, RGB);
noLoop();
println("test");
}
void draw() {
background(0);
println(width, height);
println(output.length);
int counter=0;
for (int i = 0; i < imageNames.length; i++) {
img = loadImage(imageNames[i]);
img.resize(0,900);
for (int y=0; y<img.height; y+=tileSize) {
for (int x=0; x<img.width; x+=tileSize/3) {
sample = img.get(x, y, tileSize, tileSize);
output[counter] = sample;
tint(255, tintScale);
counter++;
//println(counter);
//image(out, random(0, width-img_x), random(0, height-img_y));
}
//image(output[i],30,30);
}
}
for (int i=0;i<output.length;i++){
image(output[30],i*tileSize,i*tileSize);
}
//for (int y=0; y<out.height; y+=tileSize) {
// for (int x=0; x<out.width; x+=tileSize) {
// i = 800;
// //tint(255, tintScale);
// image(output[i], x, y);
// }
//}
}
I hope you solved it, but this is the problem:
PImage[] output = new PImage[2000];
You are initializing the array with 2000 null values, and then enter less then 300 tiles. That's why you get a null pointer error. You have to calculate how large your array will be before you initialize it. Or perhaps better, use an arraylist:
ArrayList<PImage> output = new ArrayList<PImage>();
//to add a tile:
output.add(sample);
//to draw all tile:
for(int i = 0; i< output.size();i++)
{
image(output[i],i*tileSize,i*tileSize);
}
You can read more about arraylists here
Final note: as Kevin Workman says, loadImage() and this process of dividing into tiles does not belong in 'void draw()'. It should be in setup() or in a separate function, called from setup().
Here is one task, i was trying to solve. You must write the function
void merge(ArrayList a, ArrayList b) {
// code
}
The function recieves two ArrayLists with equal size as input parameters [a1, a2, ..., an], [b1, b2, ..., bn]. The execution result is the 1st ArrayList must contain elements of both lists, and they alternate consistently ([a1, b1, a2, b2, ..., an, bn]) Please read the bold text twice =)
Code must work as efficiently as possible.
Here is my solution
public static void merge(ArrayList a, ArrayList b) {
ArrayList result = new ArrayList();
int i = 0;
Iterator iter1 = a.iterator();
Iterator iter2 = b.iterator();
while ((iter1.hasNext() || iter2.hasNext()) && i < (a.size() + b.size())) {
if (i % 2 ==0) {
result.add(iter1.next());
} else {
result.add(iter2.next());
}
i++;
}
a = result;
}
I know it's not perfect at all. But I can't understand how to merge in the 1st list without creating tmp list.
Thanks in advance for taking part.
Double ArrayList a's size. Set last two elements of a to the last element of the old a and the last element of b. Keep going, backing up each time, until you reach the beginnings of a and b. You have to do it from the rear because otherwise you will write over the original a's values.
In the end i got this:
public static void merge(ArrayList<Integer> arr1, ArrayList<Integer> arr2) {
int indexForArr1 = arr1.size() - 1;
int oldSize = arr1.size();
int newSize = arr1.size() + arr2.size();
/*
decided not to create new arraylist with new size but just to fill up old one with nulls
*/
fillWithNulls(arr1, newSize);
for(int i = (newSize-1); i >= 0; i--) {
if (i%2 != 0) {
int indexForArr2 = i%oldSize;
arr1.set(i,arr2.get(indexForArr2));
oldSize--; // we reduce the size because we don't need tha last element any more
} else {
arr1.set(i, arr1.get(indexForArr1));
indexForArr1--;
}
}
}
private static void fillWithNulls(ArrayList<Integer> array, int newSize) {
int delta = newSize - array.size();
for(int i = 0; i < delta; i++) {
array.add(null);
}
}
Thanks John again for bright idea!
I have an array that I would like to iterate in random order. That is, I would like my iteration to visit each element only once in a seemingly random order.
Would it be possible to implement an iterator that would iterate elements like this without storing the order or other data in a lookup table first?
Would it be possible to do it for N-dimensional arrays where N>1?
UPDATE: Some of the answers mention how to do this by storing indices. A major point of this question is how to do it without storing indices or other data.
I decided to solve this, because it annoyed me to death not remembering the name of solution that I had heard before. I did however remember in the end, more on that in the bottom of this post.
My solution depends on the mathematical properties of some cleverly calculated numbers
range = array size
prime = closestPrimeAfter(range)
root = closestPrimitiveRootTo(range/2)
state = root
With this setup we can calculate the following repeatedly and it will iterate all elements of the array exactly once in a seemingly random order, after which it will loop to traverse the array in the same exact order again.
state = (state * root) % prime
I implemented and tested this in Java, so I decided to paste my code here for future reference.
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class PseudoRandomSequence {
private long state;
private final long range;
private final long root;
private final long prime;
//Debugging counter
private int dropped = 0;
public PseudoRandomSequence(int r) {
range = r;
prime = closestPrimeAfter(range);
root = modPow(generator(prime), closestPrimeTo(prime / 2), prime);
reset();
System.out.println("-- r:" + range);
System.out.println(" p:" + prime);
System.out.println(" k:" + root);
System.out.println(" s:" + state);
}
// https://en.wikipedia.org/wiki/Primitive_root_modulo_n
private static long modPow(long base, long exp, long mod) {
return BigInteger.valueOf(base).modPow(BigInteger.valueOf(exp), BigInteger.valueOf(mod)).intValue();
}
//http://e-maxx-eng.github.io/algebra/primitive-root.html
private static long generator(long p) {
ArrayList<Long> fact = new ArrayList<Long>();
long phi = p - 1, n = phi;
for (long i = 2; i * i <= n; ++i) {
if (n % i == 0) {
fact.add(i);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) fact.add(n);
for (long res = 2; res <= p; ++res) {
boolean ok = true;
for (long i = 0; i < fact.size() && ok; ++i) {
ok &= modPow(res, phi / fact.get((int) i), p) != 1;
}
if (ok) {
return res;
}
}
return -1;
}
public long get() {
return state - 1;
}
public void advance() {
//This loop simply skips all results that overshoot the range, which should never happen if range is a prime number.
dropped--;
do {
state = (state * root) % prime;
dropped++;
} while (state > range);
}
public void reset() {
state = root;
dropped = 0;
}
private static boolean isPrime(long num) {
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
private static long closestPrimeAfter(long n) {
long up;
for (up = n + 1; !isPrime(up); ++up)
;
return up;
}
private static long closestPrimeBefore(long n) {
long dn;
for (dn = n - 1; !isPrime(dn); --dn)
;
return dn;
}
private static long closestPrimeTo(long n) {
final long dn = closestPrimeBefore(n);
final long up = closestPrimeAfter(n);
return (n - dn) > (up - n) ? up : dn;
}
private static boolean test(int r, int loops) {
final int array[] = new int[r];
Arrays.fill(array, 0);
System.out.println("TESTING: array size: " + r + ", loops: " + loops + "\n");
PseudoRandomSequence prs = new PseudoRandomSequence(r);
final long ct = loops * r;
//Iterate the array 'loops' times, incrementing the value for each cell for every visit.
for (int i = 0; i < ct; ++i) {
prs.advance();
final long index = prs.get();
array[(int) index]++;
}
//Verify that each cell was visited exactly 'loops' times, confirming the validity of the sequence
for (int i = 0; i < r; ++i) {
final int c = array[i];
if (loops != c) {
System.err.println("ERROR: array element #" + i + " was " + c + " instead of " + loops + " as expected\n");
return false;
}
}
//TODO: Verify the "randomness" of the sequence
System.out.println("OK: Sequence checked out with " + prs.dropped + " drops (" + prs.dropped / loops + " per loop vs. diff " + (prs.prime - r) + ") \n");
return true;
}
//Run lots of random tests
public static void main(String[] args) {
Random r = new Random();
r.setSeed(1337);
for (int i = 0; i < 100; ++i) {
PseudoRandomSequence.test(r.nextInt(1000000) + 1, r.nextInt(9) + 1);
}
}
}
As stated in the top, about 10 minutes after spending a good part of my night actually getting a result, I DID remember where I had read about the original way of doing this. It was in a small C implementation of a 2D graphics "dissolve" effect as described in Graphics Gems vol. 1 which in turn is an adaption to 2D with some optimizations of a mechanism called "LFSR" (wikipedia article here, original dissolve.c source code here).
You could collect all possible indices in a list and then remove a random indece to visit. I know this is sort of like a lookup table, but i don't see any other option than this.
Here is an example for a one-dimensional array (adaption to multiple dimensions should be trivial):
class RandomIterator<T> {
T[] array;
List<Integer> remainingIndeces;
public RandomIterator(T[] array) {
this.array = array;
this.remainingIndeces = new ArrayList<>();
for(int i = 0;i<array.length;++i)
remainingIndeces.add(i);
}
public T next() {
return array[remainingIndeces.remove((int)(Math.random()*remainingIndeces.size()))];
}
public boolean hasNext() {
return !remainingIndeces.isEmpty();
}
}
On a side note: If this code is performance relevant, this method would perform worse by far, as the random removing from the list triggers copies if you use a list backed by an array (a linked-list won't help either, as indexed access is O(n)). I would suggest a lookup-structure (e.g. HashSet in Java) that stores all visited indices to circumvent this problem (though that's exactly what you did not want to use)
EDIT: Another approach is to copy said array and use a library function to shuffle it and then traverse it in linear order. If your array isn't that big, this seems like the most readable and performant option.
You would need to create a pseudo random number generator that generates values from 0 to X-1 and takes X iterations before repeating the cycle, where X is the product of all the dimension sizes. I don't know if there is a generic solution to doing this. Wiki article for one type of random number generator:
http://en.wikipedia.org/wiki/Linear_congruential_generator
Yes, it is possible. Imagine 3D array (you not likely use anything more than that). This is like a cube and where all 3 lines connect is a cell. You can enumerate your cells 1 to N using a dictionary, you can do this initialization in loops, and create a list of cells to use for random draw
Initialization
totalCells = ... (xMax * yMax * zMax)
index = 0
For (x = 0; x < xMax ; x++)
{
For (y = 0; y < yMax ; y++)
{
For (z = 0; z < zMax ; z++)
{
dict.Add(i, new Cell(x, y, z))
lst.Add(i)
i++
}
}
}
Now, all you have to do is iterate randomly
Do While (lst.Count > 0)
{
indexToVisit = rand.Next(0, lst.Count - 1)
currentCell = dict[lst[indexToVisit]]
lst.Remove(indexToVisit)
// Do something with current cell here
. . . . . .
}
This is pseudo code, since you didn't mention language you work in
Another way is to randomize 3 (or whatever number of dimensions you have) lists and then just nested loop through them - this will be random in the end.
I'm trying to make this function create X number of variables using an array. I know that this is technically wrong because I need a constant as my array's value (currently 'x'), but excluding that, what am I missing? Looked at so many code samples and can't figure it out, but I know it's got to be simple...
void variables()
{
int i;
int bars = 10;
int x = 1;
for (i = 1; i <= bars+1; i++)
{
int variables[bars] = { x };
x++;
if (i >= bars+1)
{
break;
}
}
void variables()
{
int bars = 10;
if(bars >= Bars) bars = Bars - 1;
// to be able to set array size based on variable,
// make a dynamically sized array
double highvalues[];
ArrayResize(highvalues, bars);
for (int i = 0 /*Note: Array index is zero-based, 0 is first*/; i <= bars; i++)
{
highvalues[i] = iHigh(NULL, 0, i);
// or
highvalues[i] = High[i];
}
}
It is hard to tell what do you want to achieve.
If you want to fill an array with a value ArrayFill() fill help you.
I want to make a group of array fade out until the last array in this group was appended. for example, I use append to create zoog[0], zoog[1], zoog[2], and I want these three objects not fadeout until zoog[2] is created and wait for a second, the same situation with zoog[3], zoog[4],zoog[5], these three objects don't fadeout until zoog[5] is created. But now what I can do is make each object fadeout as soon as it is created.
Zoog[]zoog = new Zoog[1];
float count=0;
int xpos =0;
int ypos =0;
String message="haha";
int ntextsize = 20;
int nopacity =200;
int thistime = 0;
int thiscount = 0;
//Zoog zoog;
void setup() {
size(400, 400);
xpos = int(random(width/2-200, width/2+40));
ypos = int(random(height/2, height/2-40));
zoog[0] = new Zoog(xpos,ypos,message,nopacity);
}
void draw(){
background(255,255,255);
for(int i=0; i<zoog.length; i++){
// if(millis()-thistime>4000){
// zoog[i].disappear();
// }
zoog[i].jiggle();
zoog[i].display();
}
}
void mousePressed(){
count = count + 1;
// int thiscount = 0;
if(count%3 ==0){
xpos=int(random(30, width-30));
ypos=int(random(10, height-10));
}
else{
ypos = ypos+50;
// thiscount = thiscount +1;
// thistime = millis();
// }
}
nopacity = int(random(100,255));
// text(message, xpos, ypos);
Zoog b = new Zoog(xpos,ypos,message,nopacity);
zoog =(Zoog[]) append(zoog,b);
}
Zoog class
class Zoog {
int x;
int y;
String thatmessage;
int opaci =0;
Zoog(int xpo, int ypo, String thismessage, int opa) {
x = xpo;
y = ypo;
thatmessage = thismessage;
opaci = opa;
}
void jiggle() {
x = x+int(random(-2, 2));
y = y+int(random(-2, 2));
}
void display() {
fill(0, opaci);
text(thatmessage, x, y);
print("x position is "+ x);
print("y position is "+y);
}
void disappear() {
for (int j=0; j<255; j++) {
opaci = opaci -j;
}
}
}
If I understand correctly you want to make 3 zoogs and then start fading those three out until they're gone. If this is correct there are a couple of ways I'd go about doing this.
First, I wouldn't use an array especially if you're dynamically updating the amount inside it. If you want to do that I'd use, arraylists. Here's the javadocs reference. Basically you'd initialize an arraylist of Zoogs and put the zoog.add(new Zoog...) in the mousepressed. The good thing about arraylists is that they have a number of member functions that can help you manipulate them. For instance, you can check the size of the arraylist in your draw function instead of the time. Once you're above 3 start fading the first 3 out until they're dead (using a Zoog member function to say they're dead). You can check that "isDead" member function in your draw loop and remove the correct dead Zoog while in your for loop.
Here's a rough implementation, assuming you created an isDead function in your Zoog class that just returns whether the opacity is greater than 0:
void Draw()
{
for (Zoog zoog : zoogs) //for each statement simplifying the code -
//says for each Zoog in zoogs do
{
zoog.jiggle();
zoog.display();
}
if(zoogs.size() >= 3) {
for(int i = 0; i < 3; i++) {
zoogs.get(i).disappear();
}
}
if (zoogs.get(0).isDead() && zoogs.get(1).isDead() && zoogs.get(2).isDead()) {
zoogs.remove(2);
zoogs.remove(1);
zoogs.remove(0);
}
}
This is by no means a perfect example but it shows how to remove 3 zoogs at a time by lessening their opacity and checking whether they are dead. If you're clicking a million times then it will take a while for each chain of three to die.