I would go with a recursive version, but here was the correct implementation of the Stream version:
var board: TicTacToeBoard = new TicTacToeBoard
def start() { def initialBoard: TicTacToeBoard = new TicTacToeBoard def initialGameState: GameState = new XMovesNext def gameIterator = Stream.iterate(initialBoard -> initialGameState) _ def game: Stream[GameState] = { val (moves, end) = gameIterator { case (board, gameState) => val position: Int = getSelectionFromUser val updatedBoard = board.updated(position, gameState.nextTurn) (updatedBoard, getGameState(board)) }.span { case (_, gameState) => !gameState.isGameFinished } (moves ::: end.take(1)) map { case (_, gameState) => gameState } } game foreach outputState }
It looks weirder than necessary. Ideally, I would use takeWhile and then map after that, but it will not work, as the last case will be left out!
If the gameβs progress can be discarded, then dropWhile followed by head will work. If I had a side effect ( outputState ) instead of Stream , I could go through this route, but having a side effect inside Stream much worse than a var with a while .
So, I use a span that gives me both takeWhile and dropWhile , but makes me save intermediate results - which can be very bad if the memory is troubling, as the whole game will be stored in memory, because moves points to the Stream head . So I had to encapsulate it all in another method, game . That way, when I foreach through the results of the game , nothing will point to the Stream head .
Another alternative would be to get rid of another side effect that you have: getSelectionFromUser . You can get rid of this with Iteratee , and then you can save the last move and reapply it.
OR ... you can write takeTo and use this.