改变(虚构)钱

时间:2010-07-19 23:29:01

标签: c#

在使用古老的铜,银,金和白金货币体系的游戏中,每个面额的100个单位等于下一个最高面额的1个单位,这是一种可接受的“分类”或'在输入时改变'值?


public struct Coinage
{
    private int _copper;
    private int _silver;
    private int _gold;
    private int _platinum;

    public int Copper
    {
        get { return _copper; }
        set
        {
            int val = value;
            while (val > 99) { val -= 100; Silver ++; }
            _copper += val;
        }
    }
    public int Silver 
    { 
        get { return _silver; } 
        set 
        {
            int val = value;
            while (val > 99) { val -= 100; Gold ++; }
            _silver += val;
        } 
    }
    public int Gold
    {
        get { return _gold; }
        set
        {
            int val = value;
            while (val > 99) { val -= 100; Platinum ++; }
            _gold += val;
        }
    }
    public int Platinum { get { return _platinum; } set { _platinum = value; } }
}

因此,无论我输入的任何面额(低于白金)多少,它都会正确地改变我的钱?链接像这样的属性的set方法是一个坏主意吗?有没有更有效的方法在单一方法中执行此操作?

感谢。

7 个答案:

答案 0 :(得分:4)

不,这太可怕了。你不需要循环,你只需要除法和模数。

我也同意Christopherous5000;只需将所有内容存储为最小的货币,然后按照您的喜好显示它。更容易。

编辑:哦,看看那个;我的代码上面有一个严重的错误[删除],看看你是否能发现它。更多证据表明你应该将所有东西都存储为最小的货币,这样就容易多了。

答案 1 :(得分:4)

最简单,通常的方法是将它全部存储为一个大整数(铜的数量),然后使用modulo和division来提取每个“字段”。这被魔兽世界等游戏使用(这就是为什么你在该游戏中的黄金限制高峰为214748g 36s 47c - 2147483647是你可以存储在32位整数中的最高数字)。

例如,假设你有12345铜。这相当于1g,23s,45c(我们暂时忽略铂金,因为它的原理相同)。您可以按如下方式获取每个字段:

gold = money / 10000; //integer division
silver = (money % 10000) / 100; //first remove the part that was used for the gold, then do the division
copper = money % 100

考虑到你达到铂金水平(每铂金100万铜),在这种情况下选择64位整数(long)可能是个好主意。

答案 2 :(得分:4)

好的 - 所以我评论说我会把它存储为一个值并显示你想要的。下面是一个快速而肮脏的实现,以实现这个想法。我没有费心去检查否定或优化 - 只是希望得到这个想法。

public class Coinage
    {
        public long Copper { get; set; }

        public override string ToString()
        {
            long change = Copper;

            var denominations = new[] {"Gold", "Silver"};

            int numberOfDenominations = denominations.Count();

            var result = new StringBuilder();

            foreach (var denomination in denominations)
            {
                int coppersToCurrentDenomination = ((int) Math.Pow(100, numberOfDenominations));

                long currentAmount = change / coppersToCurrentDenomination;
                result.AppendFormat("{0}:{1}", denomination, currentAmount);
                change -= (currentAmount * coppersToCurrentDenomination);

                numberOfDenominations--;
            }

            result.AppendFormat("Copper:{0}", change);

            return result.ToString();
        }
    }

答案 3 :(得分:3)

您的代码违反了最少惊喜的原则。财产不应该改变另一个财产的价值。

你应该有一个Add方法,它为每个面额采用一个参数,然后执行你的每个检查。

如前所述,您不需要循环

silver += copper / 100;
copper = copper % 100;
gold += silver / 100;
silver = silver % 100;
//etc..

答案 4 :(得分:2)

好吧,首先,您的代码不起作用。如果我将Silver设置为1000000,则无效。

造币是以这样的方式完成的,即用数学方法很容易。忘记所有这些差异直到最后一分钟。

public struct Coinage
{
    private int _val;

    public int Copper
    {
        get { return _val % 100; }
        set { _val += value }
    }
    public int Silver 
    { 
        get { return (_val % 10000) / 100; } 
        set { _val += value * 100; }
    }
    public int Gold
    {
        get { return (_val % 1000000) / 10000; }
        set { _val += value * 10000; }
    }
    public int Platinum 
    {
        get { return (_val % 100000000) / 1000000; }
        set { _val += value * 1000000; }
    }
}

答案 5 :(得分:0)

我还建议你让struct永久不变。 DateTime是我如何设计它的一个很好的例子。

public Coinage AddCopper(int amount)
{
    return new Coinage(_value + amount);
}

public Coinage AddSilver(int amount)
{
    return new Coinage(_value + (amount * 100));
}

答案 6 :(得分:0)

关于存储最小货币并在显示时向上计算的想法:

我自己捅了一下,这就是我想出来的。如果我更勤奋,我会创建一个名为“货币”的单独类,它具有名称和铜值并使用货币集合,而不是使用字符串数组和铜值数组。此外,您可以将AddCurrency(int value)方法放在该类中一次,而不是为每种不同类型的货币写出来。

如果您打算使用更多货币,那就是我建议实施的方式。唯一的目标是确保所有货币的价值从最有价值到最低价。

public class Coinage
{
    // Total number of liquidated copper coins 
    private int _value = 0;

    // Conversion ratios for each currency type
    private const int PLATINUM_VALUE = 1000;
    private const int GOLD_VALUE = 100;
    private const int SILVER_VALUE = 10;
    private const int COPPER_VALUE = 1;

    // Array of other denominations
    private string[] _currencyNames = { "Platinum", "Gold", "Silver", "Copper" };
    private int[] _currencyValues = { PLATINUM_VALUE, GOLD_VALUE, SILVER_VALUE, COPPER_VALUE };

    // Constructor
    public Coinage(int value)
    {
        _value = value;
    }

    public override string ToString()
    {
        string output = "";
        int value = _value;

        for (int i = 0; i < _currencyValues.Length; i++)
        {
            output += string.Format("{0}: " + (value / _currencyValues[i]) + "\n", _currencyNames[i]);
            value = value % _currencyValues[i];
        }
        return output;
    }

    public void AddCopper(int copper)
    {
        _value += copper;
    }

    public void AddSilver(int silver)
    {
        _value += silver * 10;
    }

    public void AddGold(int gold)
    {
        _value += gold * 100;
    }

    public void AddPlatinum(int platinum)
    {
        _value += platinum * 1000;
    }
}