游戏中货币转换的麻烦

时间:2015-01-18 06:52:11

标签: c#

我正在写一个游戏货币系统的小模型,它或多或少像龙与地下城货币系统或EverquestII货币系统。基本上我有四种不同类型的货币:铜,银,黄金和白金。该系统的汇率为100,所以:

1 Platinum = 100 Gold.
1 Gold = 100 Silver.
1 Silver = 100 Copper.

但问题是,我无法弄清楚如何在彼此之间转换资金,而我的意思是,我无法解决如何将12铂金转换为铜币的问题。高昂的转换率将导致一个非常天文数字。

这是我用来拿钱的课程:

public class CurrencyData
    {
        public enum CurrencyType
        {
            Copper ,
            Silver ,
            Gold ,
            Platinum
        }
        public uint Copper { get; set; }
        public uint Silver { get; set; }
        public uint Gold { get; set; }
        public uint Platinum { get; set; }

        public CurrencyData( uint platinum , uint gold , uint silver , uint copper )
        {
            Copper = copper;
            Silver = silver;
            Gold = gold;
            Platinum = platinum;
        }
    }

我面临的一个问题是逆向交换。我的意思是假设我想“尝试”将123铜转换为银。那么,这将导致1银币,但是我们有一些无法转换的余数,因为它需要100铜制造1银币。转换后我还会剩余23枚铜币,需要加回到铜币堆中。我怎么做?一般来说,在两个方向转换资金的最佳方式是什么?

编辑:

使用下面的优秀例子,这是我不可避免地最终得到的课程。

using System;
using System.Collections.Generic;
using System.Drawing;

namespace NovaEngine4Framework.Framework.Game.Currency
{
    /// <summary>
    /// 
    /// CoinBag.cs
    /// v1.1.0
    /// Gordon Kyle Wallace, "Krythic".
    /// LordKrythic@gmail.com
    /// 
    /// This class was created with the goal of replicating a "Dungeons and
    /// Dragons" or original "Everquest" style currency system. In which there
    /// are 4 different levels of currency: Copper, Silver, Gold, and Platinum.
    /// Each coin has a different monetary worth, such that Platinum is the most
    /// expensive coin, and Copper is the least expensive. The bag holds a desired
    /// amount of money, and can be dynamically exchanged with the other denominations
    /// at user whim. Each denomination is worth 100 of the lesser, so 1 Platinum is
    /// equal to 100 Gold and so on.
    /// 
    /// </summary>
    public class CoinBag
    {
        public enum Coins
        {
            /// <summary>
            /// Copper is the lowest denominator of currency.
            /// It requires 100 Copper to make 1 Silver.
            /// </summary>
            Copper = 1 ,
            /// <summary>
            /// Silver is the second most common form of currency.
            /// It requires 100 Silver to Make 1 Gold.
            /// </summary>
            Silver = 2 ,
            /// <summary>
            /// Gold is the most common form of currency. It takes
            /// part in most expensive transactions.
            /// It requires 100 Gold to make 1 Platinum.
            /// </summary>
            Gold = 3 ,
            /// <summary>
            /// Platinum is a coin which most people never see. A single
            /// Platinum coin can purchase almost anything.
            /// 1 Platinum Coin = 100 Gold.
            /// 1 Platinum Coin = 10,000 Silver.
            /// 1 Platinum Coin = 1,000,000 Copper.
            /// </summary>
            Platinum = 4
        }
        private readonly Dictionary<Coins , long> _internalWallet;
        public const int CurrencyMinimum = 0;
        public const int CurrencyMaximum = 99999;
        public const String CopperName = "Copper";
        public const String SilverName = "Silver";
        public const String GoldName = "Gold";
        public const String PlatinumName = "Platinum";
        public const char CopperAbbreviation = 'c';
        public const char SilverAbbreviation = 's';
        public const char GoldAbbreviation = 'g';
        public const char PlatinumAbbreviation = 'p';
        public static readonly Color CopperTextColor = Color.SaddleBrown;
        public static readonly Color SilverTextColor = Color.Silver;
        public static readonly Color GoldTextColor = Color.Gold;
        public static readonly Color PlatinumTextColor = Color.SlateBlue;
        public long Copper { get { return _internalWallet[ Coins.Copper ]; } }
        public long Silver { get { return _internalWallet[ Coins.Silver ]; } }
        public long Gold { get { return _internalWallet[ Coins.Gold ]; } }
        public long Platinum { get { return _internalWallet[ Coins.Platinum ]; } }

        public CoinBag( uint platinum , uint gold , uint silver , uint copper )
        {
            _internalWallet = new Dictionary<Coins , long>
            {
                {Coins.Platinum, platinum},
                {Coins.Gold, gold},
                {Coins.Silver, silver},
                {Coins.Copper, copper}
            };
        }

        /// <summary>
        /// Increases the chosen currency field by a desired amount.
        /// </summary>
        /// <param name="amount">The amount to be added.</param>
        /// <param name="type">The type of currency that will be increased.</param>
        public void Add( uint amount , Coins type )
        {
            _internalWallet[ type ] += amount;
        }

        /// <summary>
        /// Parses the given coin type and returns the in-game
        /// text color, which will be used when drawing the name
        /// within the game world.
        /// </summary>
        /// <param name="type"></param>
        /// <returns>The color associated with the coin enum to be used for rendering.</returns>
        public static Color ParseCoinTextColor( Coins type )
        {
            switch( type )
            {
                case Coins.Copper:
                    return CopperTextColor;
                case Coins.Silver:
                    return SilverTextColor;
                case Coins.Gold:
                    return GoldTextColor;
                case Coins.Platinum:
                    return PlatinumTextColor;
                default:
                    throw new Exception( "Could not parse Coin Color: " + type );
            }
        }

        /// <summary>
        /// Retrieves the current balance of a specified coin
        /// within the bag, then returns that value with the 
        /// appended abbreviation attached to the end of it.
        /// So, Coins.Copper would return "32c" if the current
        /// balance were 32 Copper at the time of invocation.
        /// </summary>
        /// <param name="coin"></param>
        /// <returns>The abbreviated balance of the specified coin.</returns>
        public String CheckBalance( Coins coin )
        {
            switch( coin )
            {
                case Coins.Copper:
                    return "" + _internalWallet[ coin ] + CopperAbbreviation;
                case Coins.Silver:
                    return "" + _internalWallet[ coin ] + SilverAbbreviation;
                case Coins.Gold:
                    return "" + _internalWallet[ coin ] + GoldAbbreviation;
                case Coins.Platinum:
                    return "" + _internalWallet[ coin ] + PlatinumAbbreviation;
                default:
                    throw new Exception( "Could not parse Abbreviated Render text: " + coin );
            }
        }

        /// <summary>
        /// Parses the given coin type and returns the in-game
        /// string abbreviation. Coins.Copper returns 'c'; etc.
        /// </summary>
        /// <param name="type"></param>
        /// <returns>The char abbreviation associated with the coin enum.</returns>
        public static char ParseAbbreviation( Coins type )
        {
            switch( type )
            {
                case Coins.Copper:
                    return CopperAbbreviation;
                case Coins.Silver:
                    return SilverAbbreviation;
                case Coins.Gold:
                    return GoldAbbreviation;
                case Coins.Platinum:
                    return PlatinumAbbreviation;
                default:
                    throw new Exception( "Could not parse Coin Abbreviation: " + type );
            }
        }

        /// <summary>
        /// Parses the given coin type and returns the in-game
        /// string name. Coins.Copper returns "Copper"; etc.
        /// </summary>
        /// <param name="type"></param>
        /// <returns>The String name associated with the coin enum.</returns>
        public static String ParseName( Coins type )
        {
            switch( type )
            {
                case Coins.Copper:
                    return CopperName;
                case Coins.Silver:
                    return SilverName;
                case Coins.Gold:
                    return GoldName;
                case Coins.Platinum:
                    return PlatinumName;
                default:
                    throw new Exception( "Could not parse Coin Name: " + type );
            }
        }

        /// <summary>
        /// Increases the current balance of this bag with the
        /// desired currency.
        /// </summary>
        /// <param name="platinum">The amount of platinum to be added.</param>
        /// <param name="gold">The amount of gold to be added.</param>
        /// <param name="silver">The amount of silver to be added.</param>
        /// <param name="copper">The amount of copper to be added.</param>
        public void Add( uint platinum , uint gold , uint silver , uint copper )
        {
            _internalWallet[ Coins.Copper ] += copper;
            _internalWallet[ Coins.Silver ] += silver;
            _internalWallet[ Coins.Gold ] += gold;
            _internalWallet[ Coins.Platinum ] += platinum;
        }

        /// <summary>
        /// Increases the current balance of this bag with the 
        /// current balance of another.
        /// </summary>
        /// <param name="bag">The other bag.</param>
        public void Add( CoinBag bag )
        {
            _internalWallet[ Coins.Copper ] += bag.Copper;
            _internalWallet[ Coins.Silver ] += bag.Silver;
            _internalWallet[ Coins.Gold ] += bag.Gold;
            _internalWallet[ Coins.Platinum ] += bag.Platinum;
        }

        /// <summary>
        /// Subtracts the chosen currency by a desired amount.
        /// </summary>
        /// <param name="amount">The amount to subtract.</param>
        /// <param name="type">The type of money that will be subtracted.</param>
        public void Subtract( uint amount , Coins type )
        {
            _internalWallet[ type ] -= amount;
        }

        /// <summary>
        /// Subtracts the current balance of the Coinbag with
        /// the desired fields.
        /// </summary>
        /// <param name="platinum">The amount of Platinum to subtract.</param>
        /// <param name="gold">The amount of Gold to subtract.</param>
        /// <param name="silver">The amount of silver to subtract.</param>
        /// <param name="copper">The amount of copper to subtract.</param>
        public void Subtract( uint platinum , uint gold , uint silver , uint copper )
        {
            _internalWallet[ Coins.Copper ] -= copper;
            _internalWallet[ Coins.Silver ] -= silver;
            _internalWallet[ Coins.Gold ] -= gold;
            _internalWallet[ Coins.Platinum ] -= platinum;
        }

        /// <summary>
        /// Subtracts the current balance of the Coinbag with
        /// the balance of another.
        /// </summary>
        /// <param name="bag">The second bag.</param>
        public void Subtract( CoinBag bag )
        {
            _internalWallet[ Coins.Copper ] -= bag.Copper;
            _internalWallet[ Coins.Silver ] -= bag.Silver;
            _internalWallet[ Coins.Gold ] -= bag.Gold;
            _internalWallet[ Coins.Platinum ] -= bag.Platinum;
        }

        /// <summary>
        /// Completley Balances the current CoinBag by shifting
        /// over Copper->Silver->Gold->Platinum.
        /// </summary>
        public void Balance()
        {
            Exchange( Coins.Copper , Coins.Silver , Copper );
            Exchange( Coins.Silver , Coins.Gold , Silver );
            Exchange( Coins.Gold , Coins.Platinum , Gold );
        }

        /// <summary>
        /// Completely Empties the wallet of all money.
        /// </summary>
        public void Empty()
        {
            _internalWallet[ Coins.Copper ] -= 0;
            _internalWallet[ Coins.Silver ] -= 0;
            _internalWallet[ Coins.Gold ] -= 0;
            _internalWallet[ Coins.Platinum ] -= 0;
        }

        /// <summary>
        /// Exchanges one field of currency to another based
        /// upon its monetary worth. The exchange rate for
        /// all currency is 100 of the lesser.
        /// 100 Gold = 1 Platinum.
        /// 100 Silver = 1 Gold.
        /// 100 Copper = 1 Silver.
        /// </summary>
        /// <param name="fromType">The Type that will be exchanged.</param>
        /// <param name="toType">What the fromType will be exchanged to.</param>
        /// <param name="amountOfFromType">The amount to be exchanged.</param>
        public void Exchange( Coins fromType , Coins toType , long amountOfFromType )
        {
            if( fromType == toType )
                return;

            long fromTypeAmount = _internalWallet[ fromType ];
            if( amountOfFromType > fromTypeAmount )
                return; // Not enough money.
            if( fromType > toType )
            {
                _internalWallet[ toType ] += amountOfFromType * ( long )Math.Pow( 100 , ( int )fromType - ( int )toType );
            }
            else
            {
                long overflow = amountOfFromType % 100;
                amountOfFromType -= overflow;
                _internalWallet[ toType ] += amountOfFromType / ( long )Math.Pow( 100 , ( int )toType - ( int )fromType );
            }
            _internalWallet[ fromType ] -= amountOfFromType;
        }

        /// <summary>
        /// Creates a String representation for the current
        /// monetary state of the coinbag. The format is
        /// as follows:
        /// [ Platinum->Gold->Silver->Copper ]
        /// Or:
        /// [ 100p,23g,17s,780c ]
        /// </summary>
        /// <returns>A String reprsentation of the Coinbag.</returns>
        public String ToCurrencyString()
        {
            return
                "" + Platinum + PlatinumAbbreviation + "," +
                Gold + GoldAbbreviation + "," +
                Silver + SilverAbbreviation + "," +
                Copper + CopperAbbreviation;
        }
    }
}

2 个答案:

答案 0 :(得分:3)

这是我怎么做的。首先,将值分配给CurrencyType以了解具有更高价值的值并将其用于转换。

public enum CurrencyType
{
    Copper = 1,
    Silver = 2,
    Gold = 3,
    Platinum = 4
}

然后让CurrencyData类看下面的内容。如果你担心天文数字,我会用很久。

private readonly Dictionary<CurrencyType, long> data;

public long Platinum { get { return data[CurrencyType.Platinum]; } }
... properties for other currencies

public CurrencyData(long platinum, long gold, long silver, long copper)
{
    data = new Dictionary<CurrencyType, long>
    {
        { CurrencyType.Platinum, platinum },
        { CurrencyType.Gold, gold },
        { CurrencyType.Silver, silver },
        { CurrencyType.Copper, copper }
    };
}

最后,转换方法

public void Exchange(CurrencyType fromType, CurrencyType toType, long amountOfFromType)
{
    if (fromType == toType)
        return;

    var fromTypeAmount = data[fromType];
    if (amountOfFromType > fromTypeAmount)
        throw new InvalidOperationException("Not enough money");

    if (fromType > toType)
    {
        data[toType] += amountOfFromType * (long) Math.Pow(100, (int)fromType - (int)toType);               
    }
    else
    {
        var overflow = amountOfFromType % 100;
        amountOfFromType -= overflow;
        data[toType] += amountOfFromType / (long) Math.Pow(100, (int)toType - (int)fromType);                               
    }

    data[fromType] -= amountOfFromType;         
}

您可以尝试

wallet.Exchange(CurrencyType.Platinum, CurrencyType.Gold, 3);
wallet.Exchange(CurrencyType.Copper, CurrencyType.Silver, 125);

答案 1 :(得分:1)

答案很简单。使用CurrencyData对象保存结果。其余的都是数学的。而且由于你使用的是100个单位,所以它更简单,因为你使用的是基于常规的编号......

转换
简单地从上到下移动,然后乘以100 ...不知道为什么你会这样做但是就这么简单!

<强> 实施例

 //gold to silver
 this.SilverCount += this.GoldCount * 100;
 this.GoldCount = 0;

 //silver to copper
 this.CopperCount += this.SilverCount * 100;
 this.SilverCount = 0;

转换
只需从下往上移动,除以100,然后保留其余部分......

<强> 实施例

 //copper to silver
 this.SilverCount += (this.CopperCount / 100);
 this.CopperCount = this.CopperCount % 100;

 //silver to gold
 this.GoldCount += (this.SilverCount / 100);
 this.SilverCount = this.SilverCount % 100;

希望这会有所帮助......