Skip to content

Commit

Permalink
Closes #1377
Browse files Browse the repository at this point in the history
Further improvement in regards to #1375.

Since we have the valid logic for fair bots matching now, we can make use of it for trying to optimize the selection algorithm.

MatchEverything bots should still take priority over fair bots as long as possible, and this is why we'll need **consecutive** 20 empty matches with them before switching to fair bots next. This has the advantage of not switching to fair bots as long as it makes sense, and make the switch only at the point where matching any bots doesn't have a point anymore, and fair bots, despite their lower success chance, are preferred.

While the algorithm is not perfect, it should be good enough for achieving satisfying results, as the next step would involve per-user sets database, which is too much effort for this feature to consider.
  • Loading branch information
JustArchi committed Aug 25, 2019
1 parent 3fd72a7 commit 56420be
Showing 1 changed file with 21 additions and 5 deletions.
26 changes: 21 additions & 5 deletions ArchiSteamFarm/Statistics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@

namespace ArchiSteamFarm {
internal sealed class Statistics : IDisposable {
private const byte MaxMatchedBotsHard = 40;
private const byte MaxMatchedBotsSoft = 20;
private const byte MaxMatchingRounds = 10;
private const byte MaxMatchedBotsHard = 40; // Determines how many bots we can attempt to match in total, where match attempt is equal to analyzing bot's inventory
private const byte MaxMatchedBotsSoft = MaxMatchedBotsHard / 2; // Determines how many consecutive empty matches we need to get before we decide to skip bots from the same category
private const byte MaxMatchingRounds = 10; // Determines maximum amount of matching rounds we're going to consider before leaving the rest of work for the next batch
private const byte MinAnnouncementCheckTTL = 6; // Minimum amount of hours we must wait before checking eligibility for Announcement, should be lower than MinPersonaStateTTL
private const byte MinHeartBeatTTL = 10; // Minimum amount of minutes we must wait before sending next HeartBeat
private const byte MinItemsCount = 100; // Minimum amount of items to be eligible for public listing
Expand Down Expand Up @@ -374,16 +374,27 @@ internal sealed class Statistics : IDisposable {
return false;
}

bool skipAnyBots = false;
byte emptyMatches = 0;
byte totalMatches = 0;

HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> skippedSetsThisRound = new HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)>();

foreach (ListedUser listedUser in listedUsers.Where(listedUser => acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(listedUser => listedUser.MatchEverything).ThenByDescending(listedUser => listedUser.Score).Take(MaxMatchedBotsHard)) {
foreach (ListedUser listedUser in listedUsers.Where(listedUser => acceptedMatchableTypes.Any(listedUser.MatchableTypes.Contains) && (!triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) || (attempt.Tries < byte.MaxValue)) && !Bot.IsBlacklistedFromTrades(listedUser.SteamID)).OrderBy(listedUser => triedSteamIDs.TryGetValue(listedUser.SteamID, out (byte Tries, ISet<ulong> GivenAssetIDs, ISet<ulong> ReceivedAssetIDs) attempt) ? attempt.Tries : 0).ThenByDescending(listedUser => listedUser.MatchEverything).ThenByDescending(listedUser => listedUser.Score)) {
if (listedUser.MatchEverything && skipAnyBots) {
continue;
}

HashSet<(uint RealAppID, Steam.Asset.EType Type, Steam.Asset.ERarity Rarity)> wantedSets = ourTradableState.Keys.Where(set => !skippedSetsThisRound.Contains(set) && listedUser.MatchableTypes.Contains(set.Type)).ToHashSet();

if (wantedSets.Count == 0) {
continue;
}

if (++totalMatches > MaxMatchedBotsHard) {
break;
}

Bot.ArchiLogger.LogGenericTrace(listedUser.SteamID + "...");

HashSet<Steam.Asset> theirInventory = await Bot.ArchiWebHandler.GetInventory(listedUser.SteamID, tradable: listedUser.MatchEverything ? true : (bool?) null, wantedSets: wantedSets).ConfigureAwait(false);
Expand Down Expand Up @@ -621,7 +632,12 @@ internal sealed class Statistics : IDisposable {
}

if (++emptyMatches >= MaxMatchedBotsSoft) {
break;
if (skipAnyBots) {
break;
}

skipAnyBots = true;
emptyMatches = 0;
}

continue;
Expand Down

0 comments on commit 56420be

Please sign in to comment.