public static List <IItem> AvailableToBuy(this ItemManager manager, StructFlag <BuyGroup> filter)
 {
     return(manager.Keys()
            .Select(manager.Get)
            .Where(item => item?.Price != null && item.Group.Intersects(filter))
            .ToList());
 }
        public void CompareDifferentProperties()
        {
            // Bigger by health, smaller by mana, equal by intelligence
            var a = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 5 },
                { StatsProperty.Mana, 3 },
                { StatsProperty.Intelligence, 1 }
            });

            // Smaller by health, bigger by mana, equal by intelligence
            var b = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 3 },
                { StatsProperty.Mana, 5 },
                { StatsProperty.Intelligence, 1 }
            });

            var health = new StructFlag <StatsProperty>(StatsProperty.Health);

            Assert.Equal(-1, StatsEffect.Compare(health, a, b));

            var mana = new StructFlag <StatsProperty>(StatsProperty.Mana);

            Assert.Equal(1, StatsEffect.Compare(mana, a, b));

            var intelligence = new StructFlag <StatsProperty>(StatsProperty.Intelligence);

            Assert.Equal(0, StatsEffect.Compare(intelligence, a, b));
        }
Exemple #3
0
        private void Shop(User user, ReceivedMessage message)
        {
            var items     = GetAllItems();
            var flag      = new StructFlag <BuyGroup>(BuyGroup.Merchant, BuyGroup.Market);
            var available = items.Keys()
                            .Select(id => items.Get(id))
                            .Where(item => item?.Price != null && item.Group.Intersects(flag))
                            .ToArray();

            foreach (var item in available)
            {
                SendMessage(user, $"<b>{item.Name}</b> (x{ItemCount}) [{item.Price * ItemCount}]\n{item.Description}");
            }

            SendMessage(
                user,
                "— За звонкую монету можно приобрести все, что угодно!",
                available
                .Select(item => new[] { item.Name })
                .Concat(new[] { new[] { "Ничего" } })
                .ToArray()
                );

            SwitchAction(user, Shop2);
        }
        private static IReadOnlyDictionary <StructFlag <StatsProperty>, MustBeOrderedList <ItemInfo> > GroupByStats(
            IEnumerable <ItemInfo> items)
        {
            var result = new Dictionary <StructFlag <StatsProperty>, List <ItemInfo> >();

            foreach (var item in items)
            {
                var combined = new StructFlag <StatsProperty>();
                Debug.Assert(item.Item.Effect != null, "item.Item.Effect != null");
                foreach (var effectKey in item.Item.Effect.Effect.Keys)
                {
                    combined = new StructFlag <StatsProperty>(combined.Values.Add(effectKey));
                }

                if (result.TryGetValue(combined, out var list))
                {
                    list.Add(item);
                }
                else
                {
                    result[combined] = new List <ItemInfo> {
                        item
                    };
                }
            }

            return(result.ToDictionary(
                       kv => kv.Key,
                       kv => new MustBeOrderedList <ItemInfo>(kv.Value
                                                              .OrderBy(i => i.Item.Effect, StatsEffect.CreateComparer(kv.Key)))
                       ));
        }
        public void CompareDifferent()
        {
            var props = new StructFlag <StatsProperty>(StatsProperty.Health);

            var comparer = StatsEffect.CreateComparer(props);

            // Bigger
            var a = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 5 }
            });

            // Smaller
            var b = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 3 }
            });

            // Bigger first
            Assert.Equal(-1, comparer.Compare(a, b));
            Assert.Equal(-1, StatsEffect.Compare(props, a, b));

            // Smaller first
            Assert.Equal(1, comparer.Compare(b, a));
            Assert.Equal(1, StatsEffect.Compare(props, b, a));
        }
Exemple #6
0
        private void EditStats(User user, RecivedMessage message)
        {
            var splitted = message.Text.Split(' ');

            if (splitted[0] == "Закончить")
            {
                SwitchAction(user, null);
                SendMessage(user, "Тебе надоело рыться в карманах", GetButtons(user));
                return;
            }

            // Handle change
            var reverse = Stats.Emojis.ToDictionary(kv => kv.Value, kv => kv.Key);
            var changed = false;

            var flag = new StructFlag <StatsProperty>();

            foreach (var propEmoji in splitted[0].Split(','))
            {
                if (reverse.TryGetValue(propEmoji, out var prop))
                {
                    flag |= new StructFlag <StatsProperty>(prop);
                }
            }

            var count = 0;

            if (!flag.Values.IsEmpty && int.TryParse(splitted[1], out count))
            {
                user.ActiveItemsManager.ChangeProportion(flag, count);
                changed = true;
            }

            // Show current stats
            ShowStats(user);

            // Show current proportions
            var current = new StringBuilder().AppendLine("Текущее распределение:");

            foreach (var proportion in user.ActiveItemsManager.ActiveProportions)
            {
                var emoji = string.Join(",", proportion.Key.Values.Select(k => Stats.Emojis[k]));
                current.Append(emoji).Append(": ").Append(proportion.Value);
                if (changed && flag.Equals(proportion.Key))
                {
                    current.Append($" _({count:+#.##;-#.##;0})_");
                }

                current.AppendLine();
            }

            SendMessage(user, current.ToString(), EditButtons(user));

            // Show how many available
            var used  = user.ActiveItemsManager.ActiveProportions.Select(kv => kv.Value).Sum();
            var total = user.ActiveItemsManager.ActiveLimit;

            SendMessage(user, $"Распределено {used} из {total}. Доступно {total - used} активных предметов");
        }
        public static int Compare(StructFlag<StatsProperty> props, StatsEffect self, StatsEffect other)
        {
            var result = 0m;
            foreach (var property in props.Values)
            {
                result += other.Effect.GetValueOrDefault(property) - self.Effect.GetValueOrDefault(property);
            }

            return Math.Sign(result);
        }
        private bool DetectUseSet(StructFlag <StatsProperty> prop,
                                  IDictionary <ChangeType, MustBeOrderedList <ItemInfo> > items)
        {
            if (items.TryGetValue(ChangeType.Set, out var setItems))
            {
                // Returns is best "set" item better than BaseStats
                return(StatsEffect.Compare(prop, User.Info.BaseStats, TakeBest(1, setItems).First().Item.Effect) == 1);
            }

            return(false);
        }
        public void CompareSame()
        {
            var props = new StructFlag <StatsProperty>(StatsProperty.Health);

            var comparer = StatsEffect.CreateComparer(props);

            var a = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 5 }
            });
            var b = new StatsEffect(ChangeType.Add, new Dictionary <StatsProperty, decimal>
            {
                { StatsProperty.Health, 5 }
            });

            Assert.Equal(0, comparer.Compare(a, b));
            Assert.Equal(0, StatsEffect.Compare(props, a, b));
        }
        public void ChangeProportion(StructFlag <StatsProperty> property, int count)
        {
            var currentSum = ActiveProportions.Values.Sum();
            var available  = ActiveLimit - currentSum;
            var toAdd      = Math.Min(count, available); // User cannot add more items than ActiveLimit

            var currentValue = ActiveProportions.GetValueOrDefault(property);

            var newValue = currentValue + toAdd;

            if (newValue <= 0)
            {
                Proportions.Remove(property);
            }
            else
            {
                Proportions[property] = newValue;
            }

            RecalculateActive();
        }
 public static List <ItemInfo> AvailableToSell(this IEnumerable <ItemInfo> items, StructFlag <BuyGroup> filter)
 {
     return(items
            .Where(item => item.Item.Price != null && item.Item.Group.Intersects(filter))
            .ToList());
 }
 public static IComparer<StatsEffect> CreateComparer(StructFlag<StatsProperty> props)
 {
     return Comparer<StatsEffect>.Create((a, b) => Compare(props, a, b));
 }
        private List <ItemInfo> ActivateItems(StructFlag <StatsProperty> prop, MustBeOrderedList <ItemInfo> items)
        {
            if (!ActiveProportions.TryGetValue(prop, out var limit))
            {
                return(new List <ItemInfo>());
            }

            var groups = GroupByChangeType(items);
            var useSet = DetectUseSet(prop, groups);

            var max = limit;

            if (useSet)
            {
                max--;
            }

            var selectedItems = new List <ItemInfo>();

            if (useSet)
            {
                selectedItems.AddRange(TakeBest(1, groups[ChangeType.Set]));
            }

            if (!groups.ContainsKey(ChangeType.Add) && !groups.ContainsKey(ChangeType.Multiply))
            {
                // No multiplication and addition. Only set, maybe.
                // So just do nothing, because DetectUseSet() will handle set.
                return(selectedItems);
            }

            if (!groups.ContainsKey(ChangeType.Add))
            {
                // Only multiplication (and set, maybe)
                selectedItems.AddRange(TakeBest(max, groups[ChangeType.Multiply]));
                return(selectedItems);
            }

            if (!groups.ContainsKey(ChangeType.Multiply))
            {
                // Only addition (and set, maybe)
                selectedItems.AddRange(TakeBest(max, groups[ChangeType.Add]));
                return(selectedItems);
            }

            // Both multiplication and addition (and set, maybe)

            /*
             * Наилучшая комбинация будет если сначала складывать, а потом умножать, т.к. (x + a) * b > (x * b) + a
             * Этот алгоритм сначала пробует взять максимальное количество умножения,
             * потом в каждой итерации добавляет одно сложение. В конце концов пробует только сложения.
             * Работает за O(N^2), где N -- max (ActiveProportions[prop])
             */
            var selectedItemsBase = selectedItems.ToList();
            var bestStats         = User.Info.BaseStats;
            var bestItems         = new List <ItemInfo>();

            for (var addCount = 0; addCount < max; addCount++)
            {
                selectedItems = selectedItemsBase.ToList();

                var mulCount = max - addCount;
                selectedItems.AddRange(TakeBest(addCount, groups[ChangeType.Add]));
                selectedItems.AddRange(TakeBest(mulCount, groups[ChangeType.Multiply]));

                var currentStats = UserInfo.ApplyItems(User.Info.BaseStats, selectedItems);

                if (StatsEffect.Compare(prop, bestStats, currentStats) == 1)
                {
                    bestStats = currentStats;
                    bestItems = selectedItems.ToList();
                }
            }

            return(bestItems);
        }