发新话题
打印

關於在RPG地圖中最佳攻擊力購買方案的探討

關於在RPG地圖中最佳攻擊力購買方案的探討

在wesnoth的RPG地圖中,經常要去商店購買攻擊力,同樣的錢,如果選購方式不同,獲得的總攻擊力也可能不同。在給定錢幣的前提下,怎麼買到最高的攻擊力呢?一種笨方法是窮舉比較。當然,這樣的事交給計算機去做是最好不過的了。下面是實現這個功能的程序:[gsm@fedora ~]$ cat wesnoth_shopping.c
/**************************************************************************
* wesnoth_shopping.c : 找出在wesnoth中給定錢幣下所可購買到的最大攻擊力時所
* 對應的剩餘最多錢幣的購買方案。
* 版權 (C) 2011 石仔<guoshimin57@gmail.com>
* 本程序為自由軟件:你可以依據自由軟件基金會所發布的第三版GNU通用公共許可證
* 重新發布、修改本程序。
* 雖然基于使用目的而發布本程序,但不負任何擔保責任,亦不包含適銷性或特定目
* 標之適用性的擔保。詳見GNU通用公共許可證。
* 你應該已經收到一份附隨此程序的GNU通用公共許可證副本。否則,請參閱
* <http://www.gnu.org/licenses/&gt;。
* ***********************************************************************/
#include <stdio.h>
#include <stdlib.h>

#define DEFAULT_MIXED_DAMAGE 4
#define DEFAULT_MIXED_STRIKE 1

int main(int argc, char **argv)
{
    if(argc != 9)
    {
        printf("用法:%s <當前錢幣數量> <當前攻擊力> <當前攻擊數量> "
               "<攻擊力單價> <攻擊數量單價> <混合模式的單價> "
               "<混合模式下的攻擊力> <混合模式下的攻擊數量>\n"
               "備註:攻擊力是指damage,攻擊數量是指strike。\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int total_golds=atoi(argv[1]), remanent_golds, max_remanent_golds=0,
        current_damage=atoi(argv[2]),
        current_strike=atoi(argv[3]),
        damage_price=atoi(argv[4]),
        strike_price=atoi(argv[5]),
        mixed_price=atoi(argv[6]),
        mixed_damage=atoi(argv[7]),
        mixed_strike=atoi(argv[8]),
        mixed_saved_golds=mixed_damage*damage_price+mixed_strike*strike_price-mixed_price,
        total_saved_golds,
        max_damage=total_golds/damage_price,
        max_strike=total_golds/strike_price,
        output, max_output=1,
        mixed_num, alone_damage, alone_strike,
        i, j;

    if(damage_price==0 || strike_price==0 || mixed_price==0)
    {
        printf("用法:%s <當前錢幣數量> <當前攻擊力> <當前攻擊數量> "
               "<攻擊力單價> <攻擊數量單價> <混合模式的單價> "
               "<混合模式下的攻擊力> <混合模式下的攻擊數量>\n"
               "備註:攻擊力是指damage,攻擊數量是指strike。\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if(mixed_damage == 0)
        mixed_price=DEFAULT_MIXED_DAMAGE;
    if(mixed_strike == 0)
        mixed_strike=DEFAULT_MIXED_STRIKE;

    printf("當前錢幣數量:%d, 當前攻擊力:%d, 當前攻擊數量:%d\n"
           "攻擊力單價:%d,攻擊數量單價:%d,混合模式的單價:%d,"
           "混合模式下的攻擊力:%d,混合模式下的攻擊數量:%d\n",
           total_golds, current_damage, current_strike,
           damage_price, strike_price, mixed_price,
           mixed_damage, mixed_strike);

    /* 找出所可購買到的最大攻擊力 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            mixed_num = (i/mixed_damage > j/max_strike ? i/mixed_damage : j/max_strike);
            total_saved_golds=mixed_num*mixed_saved_golds;
            remanent_golds=total_golds-i*damage_price-j*strike_price+total_saved_golds;
            if(remanent_golds < 0)
                break;
            output=(current_damage+i*damage_price)*(current_strike+j*strike_price);
            if(output > max_output)
                max_output=output;
        }
    }

    /* 找出所可購買到的最大攻擊力所對應的最大剩餘錢幣數量 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            mixed_num = (i/mixed_damage > j/max_strike ? i/mixed_damage : j/max_strike);
            total_saved_golds=mixed_num*mixed_saved_golds;
            remanent_golds=total_golds-i*damage_price-j*strike_price+total_saved_golds;
            if(remanent_golds < 0)
                break;
            output=(current_damage+i*damage_price)*(current_strike+j*strike_price);
            if(output == max_output)
                if(remanent_golds > max_remanent_golds)
                    max_remanent_golds=remanent_golds;
        }
    }

    /* 找出在所可購買到的最大攻擊力時所對應的剩餘最多錢幣的購買方案 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            mixed_num = (i/mixed_damage > j/max_strike ? i/mixed_damage : j/max_strike);
            total_saved_golds=mixed_num*mixed_saved_golds;
            remanent_golds=total_golds-i*damage_price-j*strike_price+total_saved_golds;
            if(remanent_golds < 0)
                break;
            alone_damage=i-mixed_num*mixed_damage;
            alone_strike=j-mixed_num*mixed_strike;
            output=(current_damage+i*damage_price)*(current_strike+j*strike_price);
            if(output == max_output && remanent_golds == max_remanent_golds)
                printf("---------------------------------\n最佳選購方案:\n"
                       "購買混合攻擊數量:%d,"
                       "單獨購買攻擊力數量:%d,單獨購買攻擊數量:%d\n"
                       "攻擊力總量:%d,攻擊總量:%d,剩餘錢幣:%d,"
                       "購買混合攻擊所節省的錢幣數量:%d\n",
                       mixed_num, alone_damage, alone_strike,
                       i, j, remanent_golds, total_saved_golds);
        }
    }

    return EXIT_SUCCESS;
}
[gsm@fedora ~]$ gcc wesnoth_shopping.c -std=c99 -O3 -Wall -o wesnoth_shopping
[gsm@fedora ~]$ ./wesnoth_shopping
用法:./wesnoth_shopping <當前錢幣數量> <當前攻擊力> <當前攻擊數量> <攻擊力單價> <攻擊數量單價> <混合模式的單價> <混合模式下的攻擊力> <混合模式下的攻擊數量>
備註:攻擊力是指damage,攻擊數量是指strike。

[gsm@fedora ~]$ ./wesnoth_shopping 500 200 3 40 150 305 4 1
當前錢幣數量:500, 當前攻擊力:200, 當前攻擊數量:3
攻擊力單價:40,攻擊數量單價:150,混合模式的單價:305,混合模式下的攻擊力:4,混合模式下的攻擊數量:1
---------------------------------
最佳選購方案:
購買混合攻擊數量:1,單獨購買攻擊力數量:1,單獨購買攻擊數量:1
攻擊力總量:5,攻擊總量:2,剩餘錢幣:5,購買混合攻擊所節省的錢幣數量:5

源代碼也可以從這裏下載。

TOP

以上源代碼有些邏輯錯誤,已修正如下:
[gsm@fedora ~]$ cat wesnoth_shopping.c
/**************************************************************************
* wesnoth_shopping.c : 找出在wesnoth中給定錢幣下所可購買到的最大攻擊力時所
* 對應的剩餘最多錢幣的購買方案。
* 版權 (C) 2011 石仔<guoshimin57@gmail.com>
* 本程序為自由軟件:你可以依據自由軟件基金會所發布的第三版GNU通用公共許可證
* 重新發布、修改本程序。
* 雖然基于使用目的而發布本程序,但不負任何擔保責任,亦不包含適銷性或特定目
* 標之適用性的擔保。詳見GNU通用公共許可證。
* 你應該已經收到一份附隨此程序的GNU通用公共許可證副本。否則,請參閱
* <http://www.gnu.org/licenses/&gt;。
* ***********************************************************************/
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    if(argc != 9)
    {
        printf("用法:%s <當前錢幣數量> <當前攻擊力> <當前攻擊數量> "
               "<攻擊力單價> <攻擊數量單價> <混合模式的單價> "
               "<混合模式下的攻擊力> <混合模式下的攻擊數量>\n"
               "備註:攻擊力是指damage,攻擊數量是指strike。\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    int total_golds=atoi(argv[1]), remanent_golds, max_remanent_golds=0,
        current_damage=atoi(argv[2]),
        current_strike=atoi(argv[3]),
        damage_price=atoi(argv[4]),
        strike_price=atoi(argv[5]),
        mixed_price=atoi(argv[6]),
        mixed_damage=atoi(argv[7]),
        mixed_strike=atoi(argv[8]),
        max_mixed_num=total_golds/mixed_price,
        mixed_saved_golds=mixed_damage*damage_price
            +mixed_strike*strike_price-mixed_price,
        total_saved_golds,
        max_alone_damage=(total_golds-max_mixed_num*mixed_price)/damage_price,
        max_alone_strike=(total_golds-max_mixed_num*mixed_price)/strike_price,
        max_damage = damage_price<strike_price ? total_golds/damage_price :
            max_alone_damage+max_mixed_num*mixed_damage,
        max_strike = strike_price>damage_price ? total_golds/strike_price :
            max_alone_strike+max_mixed_num*mixed_strike,
        output, max_output=1,
        i, j;

    if(damage_price==0 || strike_price==0 || mixed_price==0)
    {
        printf("用法:%s <當前錢幣數量> <當前攻擊力> <當前攻擊數量> "
               "<攻擊力單價> <攻擊數量單價> <混合模式的單價> "
               "<混合模式下的攻擊力> <混合模式下的攻擊數量>\n"
               "備註:攻擊力是指damage,攻擊數量是指strike。\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    printf("當前錢幣數量:%d, 當前攻擊力:%d, 當前攻擊數量:%d\n"
           "攻擊力單價:%d,攻擊數量單價:%d,混合模式的單價:%d,"
           "混合模式下的攻擊力:%d,混合模式下的攻擊數量:%d\n",
           total_golds, current_damage, current_strike,
           damage_price, strike_price, mixed_price,
           mixed_damage, mixed_strike);

    /* 找出所可購買到的最大攻擊力 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            max_mixed_num = i/mixed_damage<j/mixed_strike
                ? i/mixed_damage : j/mixed_strike;
            total_saved_golds=max_mixed_num*mixed_saved_golds;
            remanent_golds=total_golds+total_saved_golds
                -i*damage_price-j*strike_price;
            if(remanent_golds < 0)
                break;
            output=(current_damage+i)*(current_strike+j);
            if(output > max_output)
                max_output=output;
        }
    }

    /* 找出所可購買到的最大攻擊力所對應的最大剩餘錢幣數量 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            max_mixed_num = i/mixed_damage<j/mixed_strike
                ? i/mixed_damage : j/mixed_strike;
            total_saved_golds=max_mixed_num*mixed_saved_golds;
            remanent_golds=total_golds+total_saved_golds
                -i*damage_price-j*strike_price;
            if(remanent_golds < 0)
                break;
            output=(current_damage+i)*(current_strike+j);
            if(output == max_output)
                if(remanent_golds > max_remanent_golds)
                    max_remanent_golds=remanent_golds;
        }
    }

    /* 找出在所可購買到的最大攻擊力時所對應的剩餘最多錢幣的購買方案 */
    for(i=0; i<=max_damage; i++)
    {
        for(j=0; j<=max_strike; j++)
        {
            max_mixed_num = i/mixed_damage<j/mixed_strike
                ? i/mixed_damage : j/mixed_strike;
            total_saved_golds=max_mixed_num*mixed_saved_golds;
            remanent_golds=total_golds+total_saved_golds
                -i*damage_price-j*strike_price;
            if(remanent_golds < 0)
                break;
            max_alone_damage=i-max_mixed_num*mixed_damage;
            max_alone_strike=j-max_mixed_num*mixed_strike;
            output=(current_damage+i)*(current_strike+j);
            if(output==max_output && remanent_golds==max_remanent_golds)
                printf("---------------------------------\n最佳選購方案:\n"
                       "購買混合攻擊數量:%d,"
                       "單獨購買攻擊力數量:%d,單獨購買攻擊數量:%d\n"
                       "攻擊力總量:%d,攻擊總量:%d,最大傷害輸出值:%d\n"
                       "剩餘錢幣:%d,購買混合攻擊所節省的錢幣數量:%d\n",
                       max_mixed_num, max_alone_damage, max_alone_strike,
                       i, j, max_output, remanent_golds, total_saved_golds);
        }
    }

    return EXIT_SUCCESS;
}



[gsm@fedora ~]$ ./wesnoth_shopping 660 8 3 40 150 305 4 1
當前錢幣數量:660, 當前攻擊力:8, 當前攻擊數量:3
攻擊力單價:40,攻擊數量單價:150,混合模式的單價:305,混合模式下的攻擊力:4,混合模式下的攻擊數量:1
---------------------------------
最佳選購方案:
購買混合攻擊數量:2,單獨購買攻擊力數量:1,單獨購買攻擊數量:0
攻擊力總量:9,攻擊總量:2,最大傷害輸出值:85
剩餘錢幣:10,購買混合攻擊所節省的錢幣數量:10
[gsm@fedora ~]$ ./wesnoth_shopping 660 20 3 40 150 305 4 1
當前錢幣數量:660, 當前攻擊力:20, 當前攻擊數量:3
攻擊力單價:40,攻擊數量單價:150,混合模式的單價:305,混合模式下的攻擊力:4,混合模式下的攻擊數量:1
---------------------------------
最佳選購方案:
購買混合攻擊數量:1,單獨購買攻擊力數量:1,單獨購買攻擊數量:2
攻擊力總量:5,攻擊總量:3,最大傷害輸出值:150
剩餘錢幣:15,購買混合攻擊所節省的錢幣數量:5



[ 本帖最后由 guoshimin 于 2011-10-6 14:58 编辑 ]

TOP

石头辛苦了,不过这玩意儿怎么用?

TOP

編譯好之後,在命令行執行該程序就OK了--當然要帶參數,參數的含義可以查幫助信息。不帶參數運行程序就能顯示幫助信息了。

TOP

有空的話,我會在LINUX下交叉編譯出各主流操作系統平臺的程序出來,附在附件裏。

TOP

发新话题