Skip to content

Commit

Permalink
Move to package:more for Multiset
Browse files Browse the repository at this point in the history
  • Loading branch information
eseidel committed Jul 26, 2023
1 parent 72b2e60 commit b2ecd94
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 93 deletions.
8 changes: 4 additions & 4 deletions packages/cli/bin/debug_mount.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ Future<void> command(FileSystem fs, List<String> args) async {
logger.info('No mounts needed for ${ship.symbol}.');
continue;
}
for (final mountSymbol in needed.keys) {
final units = needed[mountSymbol]!;
for (final mountSymbol in needed.distinct) {
final units = needed[mountSymbol];
logger.info('Need $units $mountSymbol for ${ship.symbol}.');
}
}
Expand All @@ -32,8 +32,8 @@ Future<void> command(FileSystem fs, List<String> args) async {
logger.info('No mounts needed.');
return;
}
for (final mountSymbol in mounts.keys) {
final units = mounts[mountSymbol]!;
for (final mountSymbol in mounts.distinct) {
final units = mounts[mountSymbol];
logger.info('Need $units $mountSymbol.');
}
}
Expand Down
10 changes: 10 additions & 0 deletions packages/cli/lib/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -666,3 +666,13 @@ ConnectedSystem connectedSystemFromSystem(System system, int distance) {
y: system.y,
);
}

/// Compute the trade symbol for the given mount symbol.
TradeSymbol? tradeSymbolForMountSymbol(ShipMountSymbolEnum mountSymbol) {
return TradeSymbol.fromJson(mountSymbol.value);
}

/// Compute the mount symbol for the given trade symbol.
ShipMountSymbolEnum? mountSymbolForTradeSymbol(TradeSymbol tradeSymbol) {
return ShipMountSymbolEnum.fromJson(tradeSymbol.value);
}
70 changes: 26 additions & 44 deletions packages/cli/lib/behavior/central_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'package:cli/printing.dart';
import 'package:cli/trading.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:more/collection.dart';

// Central command sets behavior for all ships.
// Groups ships into squads.
Expand Down Expand Up @@ -74,19 +75,20 @@ class ShipTemplate {
final ShipFrameSymbolEnum frameSymbol;

/// Mounts that this template has.
final Map<ShipMountSymbolEnum, int> mounts;
final Multiset<ShipMountSymbolEnum> mounts;
}

// According to SAF:
// Surveyor with 2x mk2s and miners with 2x mk2 + 1x mk1

final _templates = [
const ShipTemplate(
ShipTemplate(
frameSymbol: ShipFrameSymbolEnum.MINER,
mounts: {
ShipMountSymbolEnum.MINING_LASER_II: 2,
ShipMountSymbolEnum.SURVEYOR_I: 1,
},
mounts: Multiset.from([
ShipMountSymbolEnum.MINING_LASER_II,
ShipMountSymbolEnum.MINING_LASER_II,
ShipMountSymbolEnum.SURVEYOR_I
]),
)
];

Expand Down Expand Up @@ -150,21 +152,16 @@ class CentralCommand {
}

/// Add up all mounts needed for current ships based on current templating.
Map<ShipMountSymbolEnum, int> mountsNeededForAllShips() {
final needed = <ShipMountSymbolEnum, int>{};
Multiset<ShipMountSymbolEnum> mountsNeededForAllShips() {
final totalNeeded = Multiset<ShipMountSymbolEnum>();
for (final ship in _shipCache.ships) {
final template = templateForShip(ship);
if (template == null) {
continue;
}
for (final entry in mountsNeededForShip(ship, template).entries) {
final mountSymbol = entry.key;
final neededCount = entry.value;
final existingCount = needed[mountSymbol] ?? 0;
needed[mountSymbol] = existingCount + neededCount;
}
totalNeeded.addAll(mountsNeededForShip(ship, template));
}
return needed;
return totalNeeded;
}

/// Check if the given behavior is globally disabled.
Expand Down Expand Up @@ -366,8 +363,8 @@ class CentralCommand {
}

/// Returns the counts of mounts already claimed.
Map<ShipMountSymbolEnum, int> claimedMounts() {
final claimed = <ShipMountSymbolEnum, int>{};
Multiset<ShipMountSymbolEnum> claimedMounts() {
final claimed = Multiset<ShipMountSymbolEnum>();
for (final state in _behaviorCache.states) {
final behavior = state.behavior;
if (behavior != Behavior.changeMounts) {
Expand All @@ -377,52 +374,37 @@ class CentralCommand {
if (mountSymbol == null) {
continue;
}
claimed[mountSymbol] = (claimed[mountSymbol] ?? 0) + 1;
claimed.add(mountSymbol);
}
return claimed;
}

/// Returns the number of mounts available at the waypoint.
Map<ShipMountSymbolEnum, int> unclaimedMountsAt(WaypointSymbol waypoint) {
Multiset<ShipMountSymbolEnum> unclaimedMountsAt(WaypointSymbol waypoint) {
// Get all the ships at that symbol
final ships = _shipCache.ships
.where((s) => s.waypointSymbol == waypoint && !s.isInTransit);

// That have behavior delivery.
final counts = <ShipMountSymbolEnum, int>{};
final available = Multiset<ShipMountSymbolEnum>();
for (final ship in ships) {
final state = _behaviorCache.getBehavior(ship.shipSymbol);
if (state == null || state.behavior != Behavior.deliver) {
continue;
}
final inventory = countMountsInInventory(ship);
for (final entry in inventory.entries) {
final mountSymbol = entry.key;
final count = entry.value;
final existingCount = counts[mountSymbol] ?? 0;
counts[mountSymbol] = existingCount + count;
}
available.addAll(countMountsInInventory(ship));
}
// Get all the claimed mounts out of other ships states.
final claimed = claimedMounts();
for (final entry in claimed.entries) {
final mountSymbol = entry.key;
final count = entry.value;
final existingCount = counts[mountSymbol] ?? 0;
final remaining = existingCount - count;
if (remaining <= 0) {
if (remaining < 0) {
logger.warn(
'More mounts claimed than available: '
'$mountSymbol $existingCount - $count',
);
}
counts.remove(mountSymbol);
} else {
counts[mountSymbol] = remaining;
// Unclear where this warning belongs.
for (final symbol in claimed.distinct) {
if (claimed[symbol] > available[symbol]) {
logger.warn(
'More mounts claimed than available at $waypoint: '
'${claimed[symbol]} > ${available[symbol]}',
);
}
}
return counts;
return available.difference(claimed);
}

/// Sets the deliver state for the given ship.
Expand Down
14 changes: 5 additions & 9 deletions packages/cli/lib/behavior/change_mounts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,14 @@ import 'package:cli/logger.dart';
import 'package:cli/nav/navigation.dart';
import 'package:cli/net/actions.dart';
import 'package:collection/collection.dart';
import 'package:more/collection.dart';

ShipMountSymbolEnum? _pickMountFromAvailable(
Map<ShipMountSymbolEnum, int> available,
Map<ShipMountSymbolEnum, int> needed,
Multiset<ShipMountSymbolEnum> available,
Multiset<ShipMountSymbolEnum> needed,
) {
for (final mount in needed.keys) {
final availableCount = available[mount] ?? 0;
if (availableCount > 0) {
return mount;
}
}
return null;
// We could do something more sophisticated here.
return needed.firstWhereOrNull((mount) => available[mount] > 0);
}

/// Change mounts on a ship.
Expand Down
50 changes: 14 additions & 36 deletions packages/cli/lib/behavior/deliver.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:cli/net/actions.dart';
import 'package:cli/trading.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:more/collection.dart';
// Go buy and deliver.
// Used for modules.

Expand Down Expand Up @@ -87,56 +88,33 @@ class DeliverJob {
}
}

/// Compute the trade symbol for the given mount symbol.
TradeSymbol? tradeSymbolForMountSymbol(ShipMountSymbolEnum mountSymbol) {
return TradeSymbol.fromJson(mountSymbol.value);
}

/// Compute the mount symbol for the given trade symbol.
ShipMountSymbolEnum? mountSymbolForTradeSymbol(TradeSymbol tradeSymbol) {
return ShipMountSymbolEnum.fromJson(tradeSymbol.value);
}

/// Compute the mounts in the given ship's inventory.
Map<ShipMountSymbolEnum, int> countMountsInInventory(Ship ship) {
final counts = <ShipMountSymbolEnum, int>{};
Multiset<ShipMountSymbolEnum> countMountsInInventory(Ship ship) {
final counts = Multiset<ShipMountSymbolEnum>();
for (final item in ship.cargo.inventory) {
final mountSymbol = mountSymbolForTradeSymbol(item.tradeSymbol);
// Will be null if the item isn't a mount.
if (mountSymbol == null) {
continue;
}
final count = counts[mountSymbol] ?? 0;
counts[mountSymbol] = count + item.units;
counts.add(mountSymbol, item.units);
}
return counts;
}

/// Compute the mounts mounted on the given ship.
Map<ShipMountSymbolEnum, int> countMountedMounts(Ship ship) {
final counts = <ShipMountSymbolEnum, int>{};
for (final mount in ship.mounts) {
final count = counts[mount.symbol] ?? 0;
counts[mount.symbol] = count + 1;
}
return counts;
Multiset<ShipMountSymbolEnum> countMountedMounts(Ship ship) {
return Multiset<ShipMountSymbolEnum>.fromIterable(
ship.mounts.map((m) => m.symbol),
);
}

/// Compute the mounts needed to make the given ship match the given template.
Map<ShipMountSymbolEnum, int> mountsNeededForShip(
Multiset<ShipMountSymbolEnum> mountsNeededForShip(
Ship ship,
ShipTemplate template,
) {
final needed = <ShipMountSymbolEnum, int>{};
final existing = countMountedMounts(ship);
for (final mountSymbol in template.mounts.keys) {
final templateCount = template.mounts[mountSymbol]!;
final existingCount = existing[mountSymbol] ?? 0;
final neededMounts = templateCount - existingCount;
if (neededMounts > 0) {
needed[mountSymbol] = neededMounts;
}
}
return needed;
return template.mounts.difference(countMountedMounts(ship));
}

class _BuyRequest {
Expand All @@ -149,14 +127,14 @@ class _BuyRequest {
final int units;
}

_BuyRequest? _buyRequestFromNeededMounts(Map<ShipMountSymbolEnum, int> needed) {
_BuyRequest? _buyRequestFromNeededMounts(Multiset<ShipMountSymbolEnum> needed) {
if (needed.isEmpty) {
return null;
}
// Check each of the needed mounts for availability and affordability.

final mountSymbol = needed.keys.first;
final units = needed[mountSymbol]!;
final mountSymbol = needed.first;
final units = needed[mountSymbol];
final tradeSymbol = tradeSymbolForMountSymbol(mountSymbol)!;
return _BuyRequest(tradeSymbol: tradeSymbol, units: units);
}
Expand Down
16 changes: 16 additions & 0 deletions packages/cli/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
Expand Down Expand Up @@ -209,6 +217,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.3.0"
more:
dependency: "direct main"
description:
name: more
sha256: "74d7379587be84284e9e1a15b4c296351bfdac0370bf2e55de996f13c93a2dc3"
url: "https://pub.dev"
source: hosted
version: "4.0.0"
node_preamble:
dependency: transitive
description:
Expand Down
1 change: 1 addition & 0 deletions packages/cli/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ dependencies:
intl: ^0.17.0
mason_logger: ^0.2.5
meta: ^1.9.1
more: ^4.0.0
openapi:
path: ../openapi
scoped:
Expand Down

0 comments on commit b2ecd94

Please sign in to comment.