Функция для анимированного отображения автомобилей на карте

Требуется реализовать метод displayCars, который отвечает за визуализацию машин на карте. Метод получает массив объектов Car. Каждый объект Car содержит уникальный идентификатор, координаты и угол поворота. Необходимо:

Короткий ответ

Что ответить на собеседовании

Требуется реализовать метод displayCars, который отвечает за визуализацию машин на карте. Метод получает массив объектов Car. Каждый объект Car содержит уникальный идентификатор, координаты и угол поворота. Необходимо:

Подробный разбор

Ответ с пояснениями

Условие

Требуется реализовать метод displayCars, который отвечает за визуализацию машин на карте. Метод получает массив объектов Car. Каждый объект Car содержит уникальный идентификатор, координаты и угол поворота. Необходимо:

  • добавить новые автомобили, которых ещё нет на карте;
  • переместить уже отображённые машины к их новым координатам с плавной анимацией (для этого используется вызов updatePlacemark);
  • удалить с карты те автомобили, которые присутствуют в текущем наборе маркеров, но отсутствуют в полученном списке.

Никакой «грубой» реализации без анимации не допускается – нельзя просто удалить все маркеры и заново их добавить.

class MapController {
  // можно дописать fields если необходимо
  final MapPlugin plugin;

  MapController(this.plugin);

  void displayCars(List<Car> cars) {
    /// Необходимо написать функцию анимированного движения машинок по карте.
    /// Анимированное перемещение осуществляется вызовом updatePlacemark
    /// Наивное решение без анимации — удалить все ранее добавленные машинки и отобразить новые.
  }

  // считаем, что функция реализована
  Geometry _createGeometry(Car car) {/*...*/}
}

typedef MapPlacemarkId = int;

abstract class MapPlugin {
  // считаем, что функция реализована
  MapPlacemarkId addPlacemark(Geometry geometry);

  // считаем, что функция реализована
  void removePlacemark(MapPlacemarkId placemark);

  // считаем, что функция реализована
  void updatePlacemark(MapPlacemarkId placemark, Geometry geometry);
}

typedef CarId = String;

class Car {
  final CarId id;

  // getters [coordinate.x], [coordinate.y]
  final math.Point<double> coordinate;
  final double course;

  const Car({
    required this.id,
    required this.coordinate,
    required this.course,
  });
}

class Geometry {
  final double lat;
  final double lon;
  final double course;
  final String image;

  const Geometry({
    required this.lat,
    required this.lon,
    required this.course,
    required this.image,
  });
}

Решение

Храните соответствие CarId → MapPlacemarkId. Для нового ID создавайте маркер, для существующего вызывайте updatePlacemark, а отсутствующие в новом списке ID удаляйте.

Добавьте поле в MapController и замените тело метода:

final Map<CarId, MapPlacemarkId> _markers = {};

void displayCars(List<Car> cars) {
  final current = {for (final car in cars) car.id: car};

  for (final car in current.values) {
    final geometry = _createGeometry(car);
    final marker = _markers[car.id];
    if (marker == null) {
      _markers[car.id] = plugin.addPlacemark(geometry);
    } else {
      plugin.updatePlacemark(marker, geometry);
    }
  }

  final removed = _markers.keys
      .where((id) => !current.containsKey(id))
      .toList();
  for (final id in removed) {
    plugin.removePlacemark(_markers[id]!);
    _markers.remove(id);
  }
}

Копия списка удаляемых ID позволяет не менять Map во время обхода её ключей. Пустой список удаляет все маркеры; при повторяющихся ID берётся последняя запись. В среднем обработка занимает O(n + m), где n — новый список, m — число старых маркеров. Анимацию обеспечивает updatePlacemark по условию задачи.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку