# File lib/libttc.rb, line 379
  def apply_move!(move, player = @current_player)
    # Check the move is a valid one
    raise(InvalidMoveError, "Piece #{move.piece} does not exist") unless @pieces.has_key?(move.piece.name)
    raise(InvalidMoveError, "Player #{player} moving piece #{move.piece}") unless move.piece.colour == player
    raise(InvalidMoveError, "Attempting to move captured piece #{move.piece}") if move.piece.captured
    raise(InvalidMoveError, "Attempting to move #{move.piece} onto or via base without captured pieces") if move.via_base? and move.piece.contains.empty?
    if move.destination.safe?
      if (@pieces.find_all {|k, p| p.position == move.destination}).length >= 3
        raise(InvalidMoveError, "Attempting to move #{move.piece} onto safe position #{move.destination} when there are already three or more pieces there")
      end
    end
    if move.via_base?
      moved_distance = board.distance_between[move.piece.position.place][player] +
        board.distance_between[player][move.destination.place]
    else
      moved_distance = board.distance_between[move.piece.position.place][move.destination.place]
    end
    raise(InvalidMoveError, "Attempting to move piece #{move.piece} #{moved_distance} places (from #{move.piece.position} to #{move.destination})") if moved_distance < 1 or moved_distance > 6

    # Apply this move
    move.piece.move_to(move.destination)

    # Capture anything already there (unless it's a safe place or a base, 
    # or our own colour, or already captured)
    unless move.destination.safe? or move.destination.base?
      @pieces.each do |name, target_piece|
        if target_piece.position == move.destination and 
            target_piece != move.piece and
            not move.piece.contains.member?(target_piece) and
            target_piece.colour != player and
            not target_piece.captured
          move.piece.capture(target_piece)
        end
      end
    end
    
    # If the move was via our base, drop all captured pieces
    if move.via_base?
      capturers_base = board.positions[move.piece.colour]
      move.piece.contains.each do |captured_piece|
        captured_piece.move_to capturers_base
        captured_piece.captured = false if captured_piece.colour == move.piece.colour
      end
      move.piece.contains = []
    end
    
    # Record the new stae
    this_game_state = GameState.new(move, player, @pieces)
    @history << this_game_state

    # Retain only players that have uncaptured pieces.  
    # If there's only one player with uncaptured pieces, declare a win.
    potential_players = []
    @players.each do |p|
      if (@pieces.values.select {|piece| piece.colour == p}).any? {|piece| not piece.captured}
        potential_players << p
      end
      #      potential_players << p if (@pieces.values.select {|p| p.colour == @current_player}).any? {|p| not p.captured}
    end
    if potential_players.length <= 1
      raise(GameWonNotice, "Game won by #{potential_players[0]}")
    end
    @players = potential_players.sort
  end