Search code examples
javaarraylistjava-stream

Generate a Point object randomly excluding certain values


I have an ArrayList which contains some Point objects.

private List<Point> snakeXY = Arrays.asList(new Point(10,5), new Point(11,5), new Point(12,5),new Point(13,5) );

I want to generate a Point object ( new Point(x, y) ) randomly with x and y between 1 and 30 (exclude) and that is different from any Point object present in the snakeXY ArrayList. For example you can have a Point object with the values (14,5) or (15,29) or (5,12) but not (12,5) or (13,5) because they are already present in snakeXY.

I have the feeling that I have to use streams but I don't see how?


Solution

  • I don't really see an alternative to creating a pool of candidate points, which will hold all possible points on the 30x30 grid minus the points already in snakeXY, and selecting a random point from this pool. You can minimize the cost by using the int encoding of point position, rather than actually creating Point objects.

    We first build a Set of point positions to exclude:

    List<Point> snakeXY = Arrays.asList(new Point(10,5), new Point(11,5), new Point(12,5),new Point(13,5) );
    
    int min = 2;
    int max = 30;
    int n = max - min;
    Set<Integer> exclude = new HashSet<>();
    for(Point p : snakeXY)
        exclude.add((p.y-min)*n + (p.x-min));
    

    We then use a list to hold a pool of possible point positions:

    List<Integer> pool = new ArrayList<>();
    for(int i=0; i<n*n; i++) 
        if(!exclude.contains(i)) pool.add(i);
    

    Now we simply select a random position from our pool and create the corresponding Point object:

    Random rand = new Random();
    int p = rand.nextInt(pool.size());
    int pi = pool.get(p);
    Point pt = new Point(min + (pi % n), min + (pi / n));
    System.out.println(pt);
    

    If we want to generate multiple points we need to remove the selected point position from the pool.

    for(int i=0; i<5; i++)
    {
        int p = rand.nextInt(pool.size());
        int pi = pool.remove(p);
        Point pt = new Point(min + (pi % n), min + (pi / n));
        System.out.println(pt);
    }