Stream.filter(...).count() didn't work [solved]

Hey, I was creating a replication of a classic game called Minesweeper.
I’m using Java 8 and Stream class to find the number of cells with mine around a cell.

Here’s a bit of the code :-


		public void reveal() {
			this.revealed = true;
			
			// Reveal current cell
			removeAll();
			this.value = (hasMine) ?  Res.MINE_ICON : Res.EMPTY_LABEL;
			add(this.value);
			setBackground(Color.WHITE);
			repaint();
			revalidate();
			
			if(hasMine(this)) return;  // Don't need to proceed since you clicked on a mine!
			
			// Reveal neighbors
			final List<Object> neighbors = Arrays.asList(grid.getNeighborsAt(row,col));
			neighbors.forEach(obj -> {
				CellPanel cell = (CellPanel) obj;
				if(!hasMine(cell) && !cell.hasRevealed())
					cell.reveal();
			});
			
			Stream<Object> mineCells = neighbors.stream().filter(CellPanel::hasMine);
			int totalMinesNearby = (int) (mineCells.count());
			System.out.println(totalMinesNearby + " mines nearby " + this);
			System.out.println(mineCells + " nearby " + this);
			setValue(totalMinesNearby);
		}

I tried that hasMine with the inverse (Exclamation mark) and it worked out just fine.
May I know what’s the problem? :slight_smile: :slight_smile:

Check if the neighbors list of empty, if it isn’t, it’s that no neighbors satisfy the condition in the filter (hasMine).

Hey, thank you.

I just found out that I just need to tweak this part a little bit :-


		public Object[] getNeighborsAt(final int row,final int col){
			final Stream<CellPanel> neighbors = cells.stream().filter(cell -> 
				(cell.getRow() == row - 1 && (cell.getCol() >= col - 1 && cell.getCol() <= col + 1) ||
				cell.getRow() == row + 1 && (cell.getCol() >= col - 1 && cell.getCol() <= col + 1) ||
				cell.getCol() == col - 1 && (cell.getRow() >= row - 1 && cell.getRow() <= row + 1) ||
				cell.getCol() == col + 1 && (cell.getRow() >= row - 1 && cell.getRow() <= row + 1)) 
				// && !CellPanel.hasMine(cell) // This part is the problem  
			);
			return neighbors.toArray();
		}

Hey

I advise you not to create a list from an array just to use it as a stream. Rather use a stream builder to build a stream or use map() and filter() directly on the stream build from grid.getNeighborsAt(row,col). You lose some performance enhancements of streams when you create lots of temporary structures to build them.

Use [icode]Arrays.stream[/icode] instead. It will become


Arrays.stream(grid.getNeighborsAt(row, col))
      .filter(CellPanel::hasMine)
      .count();

By the way, why convert the list to array in the [icode]getNeighborsAt()[/icode] method in the first place?
Use a list directly there, and use collector to collect the stream contents.


public List<CellPanel> getNeighborsAt(int row, int col) {
    return cells.stream().filter(cell ->
            (cell.getRow() == row - 1 && (cell.getCol() >= col - 1 && cell.getCol() <= col + 1) ||
            cell.getRow() == row + 1 && (cell.getCol() >= col - 1 && cell.getCol() <= col + 1) ||
            cell.getCol() == col - 1 && (cell.getRow() >= row - 1 && cell.getRow() <= row + 1) ||
            cell.getCol() == col + 1 && (cell.getRow() >= row - 1 && cell.getRow() <= row + 1))
    ).collect(Collectors.toList());
}

Should be better.

Er… this is a slightly bonkers implementation isn’t it?

Cas :slight_smile:

Yeah, wouldn’t a 2d array be a better fit? That way you can go straight to the cell you need by using its index coordinates.

[quote]Rather use a stream builder to build a stream or use map() and filter() directly on the stream build from grid.getNeighborsAt(row,col)
[/quote]
Thanks for the suggestion. I’m still new to this

[quote]why convert the list to array in the
getNeighborsAt()
method in the first place?
[/quote]
You got the point. Sorry, I’m dumb ;D

[quote]slightly bonkers implementation isn’t it
[/quote]
Please be nice. I’m still trying to learn about streams

Sorry - was a bit rude there, but the use of streams seemed to imply you are a relatively advanced programmer, which is at odds with the actual problem being discussed, which is about as trivial as can be. I think one lesson to be learned about streams is when not to use them: and this problem is one such case, where streams are like using hammer drills to squash ants. You should have a simple grid array and just look into adjacent coordinates directly; not collect a stream of neighbours. Though if you’re just getting to grips with the whole how streams work thing, it makes sense what you’re doing as an experiment in syntax and technique.

I ramble on.

Cas :slight_smile: