def moves (player : Player) means that moves accepts a player for this Game .
Game#Player is the type of player of any Game . Thus, moves (player) is a type mismatch.
Here is a simple example that shows why this should be a mismatch. Suppose this is not the case and see what happens next:
class Game2 extends DummyGame { override type Player = Boolean override type Move = Boolean override def moves(player : Boolean) = new Iterator[Boolean] {...} } val game2: DummyGame = new Game2 // game2.Player is Boolean val dummyGameAi = new DummyAi[DummyGame](game2) // DummyGame#Player == Unit, so the type of genMove for Ai[DummyGame] is // def genMove (player : Unit) : Unit dummyGameAi.genMove(()) // this calls game2.moves(()), which doesn't typecheck
For this to work, we can change the genMove type. If we pass the game as an argument (and that makes sense anyway), we can use path-dependent types:
abstract class Ai[Game <: AGame] { def genMove (game : Game)(player : game.Player) : game.Move // now game.moves (player) typechecks }
source share