91 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			91 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
////////////////////////////////////////
 | 
						||
// Programming project code
 | 
						||
// UniBw M, 2022, 2023, 2024
 | 
						||
// www.unibw.de/inf2
 | 
						||
// (c) Mark Minas (mark.minas@unibw.de)
 | 
						||
////////////////////////////////////////
 | 
						||
 | 
						||
package pp.util;
 | 
						||
 | 
						||
import java.util.HashMap;
 | 
						||
import java.util.Iterator;
 | 
						||
import java.util.Map;
 | 
						||
import java.util.NoSuchElementException;
 | 
						||
import java.util.Random;
 | 
						||
 | 
						||
/**
 | 
						||
 * An iterator that creates a random permutation of positions (x, y) where x and y are integer values
 | 
						||
 * in the range {0, ..., width-1} x {0, ..., height-1}. All permutations are uniformly distributed
 | 
						||
 * using the Fisher–Yates shuffle (also known as Knuth shuffle).
 | 
						||
 *
 | 
						||
 * @param <T> the type of elements returned by this iterator
 | 
						||
 */
 | 
						||
public class RandomPositionIterator<T> implements Iterator<T> {
 | 
						||
    private final Random random = new Random();
 | 
						||
    private final int height;
 | 
						||
    private final Map<Integer, T> movedMap = new HashMap<>();
 | 
						||
    private int remaining;
 | 
						||
    private final Creator<T> creator;
 | 
						||
 | 
						||
    /**
 | 
						||
     * Functional interface to create instances of type T.
 | 
						||
     *
 | 
						||
     * @param <T> the type of elements created by this creator
 | 
						||
     */
 | 
						||
    public interface Creator<T> {
 | 
						||
        T create(int x, int y);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * Creates a RandomPositionIterator for Position instances with float coordinates.
 | 
						||
     *
 | 
						||
     * @param width  the width of the rectangle
 | 
						||
     * @param height the height of the rectangle
 | 
						||
     * @return a RandomPositionIterator for Position instances
 | 
						||
     */
 | 
						||
    public static RandomPositionIterator<Position> floatPoints(int width, int height) {
 | 
						||
        return new RandomPositionIterator<>(FloatPoint::new, width, height);
 | 
						||
    }
 | 
						||
 | 
						||
    /**
 | 
						||
     * Creates a new permutation iterator generating a random permutation of positions (x, y)
 | 
						||
     * where x and y are integer values in the range {0, ..., width-1} x {0, ..., height-1}.
 | 
						||
     *
 | 
						||
     * @param creator the creator to create instances of type T
 | 
						||
     * @param width   the width of the rectangle
 | 
						||
     * @param height  the height of the rectangle
 | 
						||
     */
 | 
						||
    public RandomPositionIterator(Creator<T> creator, int width, int height) {
 | 
						||
        this.height = height;
 | 
						||
        this.remaining = width * height;
 | 
						||
        this.creator = creator;
 | 
						||
    }
 | 
						||
 | 
						||
    @Override
 | 
						||
    public boolean hasNext() {
 | 
						||
        return remaining > 0;
 | 
						||
    }
 | 
						||
 | 
						||
    @Override
 | 
						||
    public T next() {
 | 
						||
        if (hasNext()) {
 | 
						||
            final int idx = random.nextInt(remaining--); // note that remaining is decremented
 | 
						||
            final T result = getWhere(idx);
 | 
						||
            if (idx < remaining)
 | 
						||
                movedMap.put(idx, getWhere(remaining));
 | 
						||
            movedMap.remove(remaining);
 | 
						||
            return result;
 | 
						||
        }
 | 
						||
        throw new NoSuchElementException();
 | 
						||
    }
 | 
						||
 | 
						||
    private T getWhere(int idx) {
 | 
						||
        final T movedWhere = movedMap.get(idx);
 | 
						||
        if (movedWhere != null)
 | 
						||
            return movedWhere;
 | 
						||
        final int x = idx / height;
 | 
						||
        final int y = idx % height;
 | 
						||
        return creator.create(x, y);
 | 
						||
    }
 | 
						||
}
 |