Related
I want to choose a random item from a set, but the chance of choosing any item should be proportional to the associated weight
Example inputs:
item weight
---- ------
sword of misery 10
shield of happy 5
potion of dying 6
triple-edged sword 1
So, if I have 4 possible items, the chance of getting any one item without weights would be 1 in 4.
In this case, a user should be 10 times more likely to get the sword of misery than the triple-edged sword.
How do I make a weighted random selection in Java?
I would use a NavigableMap
public class RandomCollection<E> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private final Random random;
private double total = 0;
public RandomCollection() {
this(new Random());
}
public RandomCollection(Random random) {
this.random = random;
}
public RandomCollection<E> add(double weight, E result) {
if (weight <= 0) return this;
total += weight;
map.put(total, result);
return this;
}
public E next() {
double value = random.nextDouble() * total;
return map.higherEntry(value).getValue();
}
}
Say I have a list of animals dog, cat, horse with probabilities as 40%, 35%, 25% respectively
RandomCollection<String> rc = new RandomCollection<>()
.add(40, "dog").add(35, "cat").add(25, "horse");
for (int i = 0; i < 10; i++) {
System.out.println(rc.next());
}
There is now a class for this in Apache Commons: EnumeratedDistribution
Item selectedItem = new EnumeratedDistribution<>(itemWeights).sample();
where itemWeights is a List<Pair<Item, Double>>, like (assuming Item interface in Arne's answer):
final List<Pair<Item, Double>> itemWeights = Collections.newArrayList();
for (Item i: itemSet) {
itemWeights.add(new Pair(i, i.getWeight()));
}
or in Java 8:
itemSet.stream().map(i -> new Pair(i, i.getWeight())).collect(toList());
Note: Pair here needs to be org.apache.commons.math3.util.Pair, not org.apache.commons.lang3.tuple.Pair.
You will not find a framework for this kind of problem, as the requested functionality is nothing more then a simple function. Do something like this:
interface Item {
double getWeight();
}
class RandomItemChooser {
public Item chooseOnWeight(List<Item> items) {
double completeWeight = 0.0;
for (Item item : items)
completeWeight += item.getWeight();
double r = Math.random() * completeWeight;
double countWeight = 0.0;
for (Item item : items) {
countWeight += item.getWeight();
if (countWeight >= r)
return item;
}
throw new RuntimeException("Should never be shown.");
}
}
139
There is a straightforward algorithm for picking an item at random, where items have individual weights:
calculate the sum of all the weights
pick a random number that is 0 or greater and is less than the sum of the weights
go through the items one at a time, subtracting their weight from your random number until you get the item where the random number is less than that item's weight
Use an alias method
If you're gonna roll a lot of times (as in a game), you should use an alias method.
The code below is rather long implementation of such an alias method, indeed. But this is because of the initialization part. The retrieval of elements is very fast (see the next and the applyAsInt methods they don't loop).
Usage
Set<Item> items = ... ;
ToDoubleFunction<Item> weighter = ... ;
Random random = new Random();
RandomSelector<T> selector = RandomSelector.weighted(items, weighter);
Item drop = selector.next(random);
Implementation
This implementation:
uses Java 8;
is designed to be as fast as possible (well, at least, I tried to do so using micro-benchmarking);
is totally thread-safe (keep one Random in each thread for maximum performance, use ThreadLocalRandom?);
fetches elements in O(1), unlike what you mostly find on the internet or on StackOverflow, where naive implementations run in O(n) or O(log(n));
keeps the items independant from their weight, so an item can be assigned various weights in different contexts.
Anyways, here's the code. (Note that I maintain an up to date version of this class.)
import static java.util.Objects.requireNonNull;
import java.util.*;
import java.util.function.*;
public final class RandomSelector<T> {
public static <T> RandomSelector<T> weighted(Set<T> elements, ToDoubleFunction<? super T> weighter)
throws IllegalArgumentException {
requireNonNull(elements, "elements must not be null");
requireNonNull(weighter, "weighter must not be null");
if (elements.isEmpty()) { throw new IllegalArgumentException("elements must not be empty"); }
// Array is faster than anything. Use that.
int size = elements.size();
T[] elementArray = elements.toArray((T[]) new Object[size]);
double totalWeight = 0d;
double[] discreteProbabilities = new double[size];
// Retrieve the probabilities
for (int i = 0; i < size; i++) {
double weight = weighter.applyAsDouble(elementArray[i]);
if (weight < 0.0d) { throw new IllegalArgumentException("weighter may not return a negative number"); }
discreteProbabilities[i] = weight;
totalWeight += weight;
}
if (totalWeight == 0.0d) { throw new IllegalArgumentException("the total weight of elements must be greater than 0"); }
// Normalize the probabilities
for (int i = 0; i < size; i++) {
discreteProbabilities[i] /= totalWeight;
}
return new RandomSelector<>(elementArray, new RandomWeightedSelection(discreteProbabilities));
}
private final T[] elements;
private final ToIntFunction<Random> selection;
private RandomSelector(T[] elements, ToIntFunction<Random> selection) {
this.elements = elements;
this.selection = selection;
}
public T next(Random random) {
return elements[selection.applyAsInt(random)];
}
private static class RandomWeightedSelection implements ToIntFunction<Random> {
// Alias method implementation O(1)
// using Vose's algorithm to initialize O(n)
private final double[] probabilities;
private final int[] alias;
RandomWeightedSelection(double[] probabilities) {
int size = probabilities.length;
double average = 1.0d / size;
int[] small = new int[size];
int smallSize = 0;
int[] large = new int[size];
int largeSize = 0;
// Describe a column as either small (below average) or large (above average).
for (int i = 0; i < size; i++) {
if (probabilities[i] < average) {
small[smallSize++] = i;
} else {
large[largeSize++] = i;
}
}
// For each column, saturate a small probability to average with a large probability.
while (largeSize != 0 && smallSize != 0) {
int less = small[--smallSize];
int more = large[--largeSize];
probabilities[less] = probabilities[less] * size;
alias[less] = more;
probabilities[more] += probabilities[less] - average;
if (probabilities[more] < average) {
small[smallSize++] = more;
} else {
large[largeSize++] = more;
}
}
// Flush unused columns.
while (smallSize != 0) {
probabilities[small[--smallSize]] = 1.0d;
}
while (largeSize != 0) {
probabilities[large[--largeSize]] = 1.0d;
}
}
#Override public int applyAsInt(Random random) {
// Call random once to decide which column will be used.
int column = random.nextInt(probabilities.length);
// Call random a second time to decide which will be used: the column or the alias.
if (random.nextDouble() < probabilities[column]) {
return column;
} else {
return alias[column];
}
}
}
}
public class RandomCollection<E> {
private final NavigableMap<Double, E> map = new TreeMap<Double, E>();
private double total = 0;
public void add(double weight, E result) {
if (weight <= 0 || map.containsValue(result))
return;
total += weight;
map.put(total, result);
}
public E next() {
double value = ThreadLocalRandom.current().nextDouble() * total;
return map.ceilingEntry(value).getValue();
}
}
A simple (even naive?), but (as I believe) straightforward method:
/**
* Draws an integer between a given range (excluding the upper limit).
* <p>
* Simulates Python's randint method.
*
* #param min: the smallest value to be drawed.
* #param max: the biggest value to be drawed.
* #return The value drawn.
*/
public static int randomInt(int min, int max)
{return (int) (min + Math.random()*max);}
/**
* Tests wether a given matrix has all its inner vectors
* has the same passed and expected lenght.
* #param matrix: the matrix from which the vectors length will be measured.
* #param expectedLenght: the length each vector should have.
* #return false if at least one vector has a different length.
*/
public static boolean haveAllVectorsEqualLength(int[][] matrix, int expectedLenght){
for(int[] vector: matrix){if (vector.length != expectedLenght) {return false;}}
return true;
}
/**
* Draws an integer between a given range
* by weighted values.
*
* #param ticketBlock: matrix with limits and weights for the drawing. All its
* vectors should have lenght two. The weights, instead of percentages, should be
* measured as integers, according to how rare each one should be draw, the rarest
* receiving the smallest value.
* #return The value drawn.
*/
public static int weightedRandomInt(int[][] ticketBlock) throws RuntimeException {
boolean theVectorsHaventAllLengthTwo = !(haveAllVectorsEqualLength(ticketBlock, 2));
if (theVectorsHaventAllLengthTwo)
{throw new RuntimeException("The given matrix has, at least, one vector with length lower or higher than two.");}
// Need to test for duplicates or null values in ticketBlock!
// Raffle urn building:
int raffleUrnSize = 0, urnIndex = 0, blockIndex = 0, repetitionCount = 0;
for(int[] ticket: ticketBlock){raffleUrnSize += ticket[1];}
int[] raffleUrn = new int[raffleUrnSize];
// Raffle urn filling:
while (urnIndex < raffleUrn.length){
do {
raffleUrn[urnIndex] = ticketBlock[blockIndex][0];
urnIndex++; repetitionCount++;
} while (repetitionCount < ticketBlock[blockIndex][1]);
repetitionCount = 0; blockIndex++;
}
return raffleUrn[randomInt(0, raffleUrn.length)];
}
I got my wave file creator working and I split it into three classes, I also made a sinewave generator that inherits from an abstract class called waveform and I can export 8 and 16 bit mono or sterio sine waves. I am trying to make a class called TriangleWave Generator to output a triangle wave tone, but I can't get the algebra from https://en.wikipedia.org/wiki/Triangle_wave#, the first formula, to work. It will only export the highest harmonic stated and not blend them together with the fundamental
Sample length: length in seconds
point: individual sample
amp limit: the highest position possible
harmonics: the number of harmonics to use to make the waveform 1 = fundamental, 2 = 1st overtone, 3 = 2nd overtone.......
frequency: fundamental frequency (Middle C = 261.63)
sample rate = 44100; (CD quality)
triangle Samples array: sample data
This is my code
public class TriangleGenerator extends Waveform {
// constants
public static final int HARMONIC_COUNT = 16;
// instance variabls
int harmonics;
int[] triangleSample;
int addCount;
// constructor
public TriangleGenerator(double amplitude, double frequency, int bitRate, double duration, int harmonics) {
super(amplitude, frequency, bitRate, duration);
// sample data
triangleSample = new int[sampleLength];
calculateAmpLimit();
this.harmonics = harmonics;
}
// one arg cunstructor
public TriangleGenerator(double frequency) {
this(AMPLITUDE, frequency, BIT_RATE, DURATION, HARMONIC_COUNT);
}
// no args constructor
public TriangleGenerator() {
this(AMPLITUDE, FREQUENCY, BIT_RATE, DURATION, HARMONIC_COUNT);
}
#Override
public int[] generateWaveForm() {
// generate the actual waveform
for (int i = 0; i < sampleLength; i++) {
point = (int)(ampLimit * ((8 / Math.pow(Math.PI, 2)) * sumnate(harmonics - 1, Math.pow(-1, addCount))
* Math.pow(harmonics, -2) * Math.sin(2 * Math.PI * frequency * harmonics * i / SAMPLE_RATE)));
triangleSample[i] = point;
}
// return the sample data
return triangleSample;
}
public double sumnate(int n, double adder) {
double sum = 0;
for (addCount = 0; addCount <= n; addCount++) {
sum += adder;
}
return sum;
}
}
In the formula for the triangle wave:
the mode number n is dependent on the harmonic label i:
This means that it must also be summed over the components
which doesn't happen in the current implementation. One possible implementation is:
public int[] generateWaveForm() {
for (int t = 0; t < sampleLength; t++) {
triangleSample[t] = (int)(ampLimit * 8.0 / Math.pow(Math.PI, 2.0) * getDataPoint(t, N));
}
return triangleSample;
}
private double getDataPoint(int t, int N) {
double sum = 0;
for (int i = 0; i <= N - 1; i++) {
sum += getHarmonicShare(t, i);
}
return sum;
}
private double getHarmonicShare(int t, int i) {
double n = 2.0 * i + 1.0;
return Math.pow(-1.0, i) * Math.pow(n, -2.0) * Math.sin(2.0 * Math.PI * frequency * (t / SAMPLE_RATE) * n);
}
Here t, i, n and N correspond to the values from the formula. frequency denotes the frequency. The remaining values correspond to the parameters of the posted code.
The curve reaches up to the value sampleLength / SAMPLE_RATE. The period is 1 / frequency and there are (sampleLength / SAMPLE_RATE) * frequency periods in the displayed frame.
Example:
sampleLength: 500
ampLimit: 100.00
SAMPLE_RATE: 44100.00
frequency: 261.63
sampleLength / SAMPLE_RATE: 0.0113378685
1 / frequency: 0.0038221916
(sampleLength / SAMPLE_RATE) * frequency: 2.9663265306
In the following the corresponding curve is shown for different N using JFreeChart:
Is there a reason you want to use sin to do this rather than produce the straight lines directly by a linear formula? There is an advantage in using sin in that you don't get harmonic distortion from aliasing, but if that's an issue then you can oversample. The issue is that sin is much slower than basic arithmetic.
Today I wrote an algorithm to compute the Fast Fourier Transform from a given array of points representing a discrete function. Now I'm trying to test it to see if it is working. I've tried about a dozen different input sets, and they seem to match up with examples I've found online. However, for my final test, I gave it the input of cos(i / 2), with i from 0 to 31, and I've gotten 3 different results based on which solver I use. My solution seems to be the least accurate:
Does this indicate a problem with my algorithm, or is it simply a result of the relatively small data set?
My code is below, in case it helps:
/**
* Slices the original array, starting with start, grabbing every stride elements.
* For example, slice(A, 3, 4, 5) would return elements 3, 8, 13, and 18 from array A.
* #param array The array to be sliced
* #param start The starting index
* #param newLength The length of the final array
* #param stride The spacing between elements to be selected
* #return A sliced copy of the input array
*/
public double[] slice(double[] array, int start, int newLength, int stride) {
double[] newArray = new double[newLength];
int count = 0;
for (int i = start; count < newLength && i < array.length; i += stride) {
newArray[count++] = array[i];
}
return newArray;
}
/**
* Calculates the fast fourier transform of the given function. The parameters are updated with the calculated values
* To ignore all imaginary output, leave imaginary null
* #param real An array representing the real part of a discrete-time function
* #param imaginary An array representing the imaginary part of a discrete-time function
* Pre: If imaginary is not null, the two arrays must be the same length, which must be a power of 2
*/
public void fft(double[] real, double[] imaginary) throws IllegalArgumentException {
if (real == null) {
throw new NullPointerException("Real array cannot be null");
}
int N = real.length;
// Make sure the length is a power of 2
if ((Math.log(N) / Math.log(2)) % 1 != 0) {
throw new IllegalArgumentException("The array length must be a power of 2");
}
if (imaginary != null && imaginary.length != N) {
throw new IllegalArgumentException("The two arrays must be the same length");
}
if (N == 1) {
return;
}
double[] even_re = slice(real, 0, N/2, 2);
double[] odd_re = slice(real, 1, N/2, 2);
double[] even_im = null;
double[] odd_im = null;
if (imaginary != null) {
even_im = slice(imaginary, 0, N/2, 2);
odd_im = slice(imaginary, 1, N/2, 2);
}
fft(even_re, even_im);
fft(odd_re, odd_im);
// F[k] = real[k] + imaginary[k]
// even odd
// F[k] = E[k] + O[k] * e^(-i*2*pi*k/N)
// F[k + N/2] = E[k] - O[k] * e^(-i*2*pi*k/N)
// Split complex arrays into component arrays:
// E[k] = er[k] + i*ei[k]
// O[k] = or[k] + i*oi[k]
// e^ix = cos(x) + i*sin(x)
// Let x = -2*pi*k/N
// F[k] = er[k] + i*ei[k] + (or[k] + i*oi[k])(cos(x) + i*sin(x))
// = er[k] + i*ei[k] + or[k]cos(x) + i*or[k]sin(x) + i*oi[k]cos(x) - oi[k]sin(x)
// = (er[k] + or[k]cos(x) - oi[k]sin(x)) + i*(ei[k] + or[k]sin(x) + oi[k]cos(x))
// { real } { imaginary }
// F[k + N/2] = (er[k] - or[k]cos(x) + oi[k]sin(x)) + i*(ei[k] - or[k]sin(x) - oi[k]cos(x))
// { real } { imaginary }
// Ignoring all imaginary parts (oi = 0):
// F[k] = er[k] + or[k]cos(x)
// F[k + N/2] = er[k] - or[k]cos(x)
for (int k = 0; k < N/2; ++k) {
double t = odd_re[k] * Math.cos(-2 * Math.PI * k/N);
real[k] = even_re[k] + t;
real[k + N/2] = even_re[k] - t;
if (imaginary != null) {
t = odd_im[k] * Math.sin(-2 * Math.PI * k/N);
real[k] -= t;
real[k + N/2] += t;
double t1 = odd_re[k] * Math.sin(-2 * Math.PI * k/N);
double t2 = odd_im[k] * Math.cos(-2 * Math.PI * k/N);
imaginary[k] = even_im[k] + t1 + t2;
imaginary[k + N/2] = even_im[k] - t1 - t2;
}
}
}
Validation
look here: slow DFT,iDFT at the end is mine slow implementation of DFT and iDFT they are tested and correct. I also used them for fast implementations validation in the past.
Your code
stop recursion is wrong (you forget to set the return element) mine looks like this:
if (n<=1) { if (n==1) { dst[0]=src[0]*2.0; dst[1]=src[1]*2.0; } return; }
so when your N==1 set the output element to Re=2.0*real[0], Im=2.0*imaginary[0] before return. Also I am a bit lost in your complex math (t,t1,t2) and to lazy to analyze.
Just to be sure here is mine fast implementation. It need too much things from class hierarchy so it will not be of another use for you then visual comparison to your code.
My Fast implementation (cc means complex output and input):
//---------------------------------------------------------------------------
void transform::DFFTcc(double *dst,double *src,int n)
{
if (n>N) init(n);
if (n<=1) { if (n==1) { dst[0]=src[0]*2.0; dst[1]=src[1]*2.0; } return; }
int i,j,n2=n>>1,q,dq=+N/n,mq=N-1;
// reorder even,odd (buterfly)
for (j=0,i=0;i<n+n;) { dst[j]=src[i]; i++; j++; dst[j]=src[i]; i+=3; j++; }
for ( i=2;i<n+n;) { dst[j]=src[i]; i++; j++; dst[j]=src[i]; i+=3; j++; }
// recursion
DFFTcc(src ,dst ,n2); // even
DFFTcc(src+n,dst+n,n2); // odd
// reorder and weight back (buterfly)
double a0,a1,b0,b1,a,b;
for (q=0,i=0,j=n;i<n;i+=2,j+=2,q=(q+dq)&mq)
{
a0=src[j ]; a1=+_cos[q];
b0=src[j+1]; b1=+_sin[q];
a=(a0*a1)-(b0*b1);
b=(a0*b1)+(a1*b0);
a0=src[i ]; a1=a;
b0=src[i+1]; b1=b;
dst[i ]=(a0+a1)*0.5;
dst[i+1]=(b0+b1)*0.5;
dst[j ]=(a0-a1)*0.5;
dst[j+1]=(b0-b1)*0.5;
}
}
//---------------------------------------------------------------------------
dst[] and src[] are not overlapping !!! so you cannot transform array to itself .
_cos and _sin are precomputed tables of cos and sin values (computed by init() function like this:
double a,da; int i;
da=2.0*M_PI/double(N);
for (a=0.0,i=0;i<N;i++,a+=da) { _cos[i]=cos(a); _sin[i]=sin(a); }
N is power of 2 (zero padded size of data set) (last n from init(n) call)
Just to be complete here is mine complex to complex slow version:
//---------------------------------------------------------------------------
void transform::DFTcc(double *dst,double *src,int n)
{
int i,j;
double a,b,a0,a1,_n,b0,b1,q,qq,dq;
dq=+2.0*M_PI/double(n); _n=2.0/double(n);
for (q=0.0,j=0;j<n;j++,q+=dq)
{
a=0.0; b=0.0;
for (qq=0.0,i=0;i<n;i++,qq+=q)
{
a0=src[i+i ]; a1=+cos(qq);
b0=src[i+i+1]; b1=+sin(qq);
a+=(a0*a1)-(b0*b1);
b+=(a0*b1)+(a1*b0);
}
dst[j+j ]=a*_n;
dst[j+j+1]=b*_n;
}
}
//---------------------------------------------------------------------------
I'd use something authoritative like Wolfram Alpha to verify.
If I evalute cos(i/2) for 0 <= i < 32, I get this array:
[1,0.878,0.540,0.071,-0.416,-0.801,-0.990,-0.936,-0.654,-0.211,0.284,0.709,0.960,0.977,0.754,0.347,-0.146,-0.602,-0.911,-0.997,-0.839,-0.476,0.004,0.483,0.844,0.998,0.907,0.595,0.137,-0.355,-0.760,-0.978]
If I give that as input to Wolfram Alpha's FFT function I get this result.
The plot that I get looks symmetric, which makes sense. The plot looks nothing like any of the ones you supplied.
The problem is to create concentric and nested squares,starting with the largest square's side given as N.Its just like drawing one square inside another ON PAPER,until no more squares are possible to be drawn, by decrementing the length of the side by 4 after each square(2 from startPos of side and 2 from endPos); And N is the size of the square to start with.
You have to draw the sides by using multiplication symbol('*').
The proportion(looks more like rectangles than squares) of the above image might not be exact, but it would give u idea about what needs to be done ..
The below code is what I have tried...
public static void main(String[] args)
{
int N=9;
int iLo=0;
int iHi=N-1;
int jLo=0;
int jHi=N-1;
for(int i=0;i<N;i++)
{
for(int j=0;j<N;j++)
{
if(i==0 || (i==N-1) || (j==0) || (j==N-1))
System.out.print('*');
else
{
if(i<=N/2)
{
if((i%2==0) && (i>=iLo) && (i<=iHi) && (j>=jLo) && (j<=jHi))
System.out.print('*');
else
if(i==iLo || i==iHi )
System.out.print('*');
else
System.out.print(' ');
}
else
{
if((i%2==0) && (i>=iLo) && (i<=iHi) && (j>=jLo) && (j<=jHi))
System.out.print('*');
else
System.out.print(' ');
}
}
}
System.out.print(" i-->"+i+" iLo-->"+iLo+" iHi-->"+iHi+" jLo-->"+jLo+" jHi-->"+jHi);
if(i%2>0)
{
if(i<=N/2)
{
jLo=jLo+2;
jHi=jHi-2;
iLo=iLo+1;
iHi=iHi-1;
}
else
{
jLo=jLo-2;
jHi=jHi+2;
iLo=iLo-1;
iHi=iHi+1;
}
}
else
{
}
System.out.println();
}
}
This could be solved either by using a for-loop that decrements by 2 each time (i -= 2) Or recursively where the base case prints a single * to the screen, or none at all. As others have posted, unless you have some space between each square, you will only have a solid square.
EDIT: It seems you might not be printing one square on top of another, but rather in place of another. The same strategy applies, however.
EDIT2: You shouldn't need to use a nested for loop with i and j. A single for loop with the length of each side as the variable i should suffice. You will need to adjust for double counting of vertices, however.
Why not try something like:
// Assumes a cartesian coordinate system, origin at bottom left.
int startingX = 0;
int startingY = 0;
while( length > 0 ){
printHorizontally(length, startingX, startingY);
printVertically(length, startingX, startingY);
startingX += 2;
startingY += 2;
length -= 4;
}
private void printHorizontally(int length, int startingX, int startingY){
// Prints length *s to the screen in a horizontal line starting at the
// given points. Define printVertically similarly.
}
Overview
This question is appropriate for Adobe because it's essentially a rendering algorithm: given a pixel and a set of rules, calculate the appearance of that pixel.
The most efficient way to do this is to come up with a test that answers "given the position (x,y) in a square of size n, should it be marked with *?", and then answer that question for each position.
We can answer this question by first making a couple of observations.
Note the symmetry of the output of this algorithm. If we cut the square along its diagnols, we are left with four triangular quadrants. Within each quadrant, notice that the triangle is simply striped.
Vertical or horizontal stripes are simple to draw; just check if the row/column is an even distance from the nearest edge and shade it if so.
So we'll do two computations per position: (1) which quandrant is this position in and (2) given this quadrant, should this position's row/column be shaded?
Example implementation (python)
def getQuadrant(i,j,n):
# 1 means top quadrant; 2 right; 3 bottom; 4 left
half_n = float(n-1)/2
x = float(i) - half_n
y = float(j) - half_n
if x > 0:
if y > 0:
if x > y:
return 3
else:
return 2
else:
if x > -1*y:
return 3
else:
return 4
else:
if y > 0:
if -1*x > y:
return 1
else:
return 2
else:
if x < y:
return 1
else:
return 4
def isPixelShaded(x,y,n):
q = getQuadrant(x,y,n)
if q == 1:
return (x % 2) == 0
elif q == 2:
return ((n-y-1) % 2) == 0
elif q == 3:
return ((n-x-1) % 2) == 0
else:
return (y % 2) == 0
def getPixelShade(x,y,n):
if isPixelShaded(x,y,n):
return ' * '
else:
return ' '
def printSquare(n):
for i in range(n):
print ''.join(map(lambda x: str(getPixelShade(i,x,n)),range(n)))
printSquare(3)
printSquare(6)
printSquare(9)
Output
* * *
* *
* * *
* * * * * *
* *
* * * *
* * * *
* *
* * * * * *
* * * * * * * * *
* *
* * * * * * *
* * * *
* * * * *
* * * *
* * * * * * *
* *
* * * * * * * * *
Other thoughts
Instead of a the rendering approach taken here, we could also take an iterative approach by "walking out squares" a in pre-allocated matrix. That approach is simpler to think about but it requires more memory. Additionally, the approach described in this answer has the benefit that to determine wither a given position is shaded, we don't need to know about its neighboring positions (which an iterative approach does). This means we could render small swatches of the final rendering at once. In other words, this approach supports parallelism, which is always a nice bonus.
The following code offers the simplest recursive solution possible---
public class SquaresInSquare {
private static char[][] arr;
public static void populate(int start,int N)
{
//System.out.println(start+" "+N);
if(N < 0 || start > N)
return;
for (int i = start; i < N; i++)
{
for (int j = start; j < N; j++)
{
if(i==start || i==N-1 || j==start || j==N-1)
arr[i][j]='*';
else
arr[i][j]=' ';
}
}
populate(start+2,N-2);
}
public static void print()
{
for (int i = 0; i < arr.length; i++)
{
for (int j = 0; j < arr.length; j++)
{
System.out.print(arr[i][j]);
}
System.out.println();
}
}
/**
* #Method :main is Personal Method Of Class-->SquaresInSquare
* #returns : void
* #param args
*/
public static void main(String[] args)
{
int N=21;
arr=new char[N][N];
populate(0,N);
print();
}
}
I have tested that my partitioning algorithm works well, but when it comes time in the implementation to make use of it, I get an array that is not sorted. Since this is for a class, there's a certain I need to write the class itself so that I can return the answer as string. My problem is most likely in the qkSort() method. Here's the code:
private static int splitterElement;
public static void main (String[] args){
System.out.println(myMethod());
}
public static String myMethod() {
String result = "";
int[] testArray = null;
testArray = populateArray(testArray, 7, 10);
result += "Before sort: \n" + printArray(testArray);
testArray = qkSort(testArray,1,testArray.length);
result += "After sort: \n" + printArray(testArray);
return result;
}
//Method to continually call the partition() method
public static int[] qkSort(int[] x, int left, int right){
if (right - left >= 1) {
//after running this method, the global variable splitterElement is assigned.
x = partition(x,left,right);
qkSort(x,left,splitterElement-1);
qkSort(x,splitterElement + 1,right);
}
//base case. if right-left = 0, then the array length is 1,
//and that is already sorted
return x;
}
/**
* Populates an integer array with random integers. Should be used only with
* non-itialized integer arrays.
*
* #param x an uninitialized array of integers and will be returned once it is populated.
* #param sizeOfArray The size that array x will be initialized to.
* #param rangeOfValues The range of values that that each element can be. This value should
* not surpass the maximum value for integers, but no error-checking is performed.
* #return
*/
public static int[] populateArray (int[] x, int sizeOfArray, int rangeOfValues){
x = new int[sizeOfArray];
for (int i = 0; i < sizeOfArray; i++){
x[i] = (int)(Math.random() * rangeOfValues); //place a random number from 0 to rangeOfValues into array.
}
return x;
}
/**
*
* #param x An integer array. It is assumed that x is initialized when the method is called.
* #param left
* #param right The length of the array can be used for the right int.
* #see #populateArray(int[], int, int)
* #return
*/
public static int[] partition (int[] x, int left, int right){
//element of the splitter
int l = (int) (Math.random() * x.length);
splitterElement = l;
x = swap (x,left,l);
//value of the splitter
int t = x[left];
int i = left;
for (int j = left + 1; j < right; j++){
if (x[j] < t){
i++;
x = swap (x,i,j);
}
}
x = swap(x,left,i);
return x;
}
/**
* Places the value at index1 in index2, and places the value at index2 in index1.
*
* #param array The array that will be worked on.
* #param index1 The first place we will switch values.
* #param index2 The second place we will switch values.
* #return
*/
public static int[] swap (int[] array, int index1, int index2){
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
return array;
}
/**
* A simple print method that prints an array.
* #param array Input.
*/
public static String printArray (int[] array){
String result = "";
for (int i = 0; i < array.length; i++){
result += array[i] + " ";
}
result += "\n";
return result;
}
}
Output:
Before sort:
8 9 7 3 4 2 6
After sort:
8 6 3 9 7 2 4
Thanks for any ideas on what my problem is!
I see several issues in your code:
1) the methods don't need to return the array, you could find a better use for the return value
2) using a global variable splitterElement doesn't work because its value can change during the first recursive call to qkSort. Method partition could return its value instead of returning the array, which is useless.
3) the first line of the partition method:
int l = (int) (Math.random() * x.length);
should be:
int l = left + (int) (Math.random() * (right - left));
because youre partitionning the range between left and right, not the whole array.