Bagaimana cara menjalankan operasi dengan karakter / item dalam biner dengan operasi konkret?

8

Saya punya masalah selanjutnya.

Item dapat memiliki banyak status:

NORMAL  = 0000000
DRY     = 0000001
HOT     = 0000010
BURNING = 0000100
WET     = 0001000
COLD    = 0010000
FROZEN  = 0100000
POISONED= 1000000

Suatu item dapat memiliki beberapa status pada saat yang bersamaan tetapi tidak semuanya

  • Tidak mungkin kering dan basah pada saat yang sama.
  • Jika Anda DINGIN item WET, itu berubah menjadi BEKU.
  • Jika Anda HOT item WET, itu berubah menjadi NORMAL
  • Item dapat BURNING dan RACUN

Dll

Saya telah mencoba mengatur bendera biner ke status, dan menggunakan DAN untuk menggabungkan berbagai status, memeriksa sebelumnya apakah mungkin atau tidak melakukannya, atau mengubah ke status lain.

Apakah ada pendekatan konkret untuk menyelesaikan masalah ini secara efisien tanpa harus beralih tanpa henti yang memeriksa setiap negara bagian dengan setiap negara bagian yang baru?

Ini relatif mudah untuk memeriksa 2 keadaan yang berbeda, tetapi jika ada keadaan ketiga itu tidak sepele untuk dilakukan.

vgonisanz
sumber
Saya tidak mengerti mengapa Anda berpikir keadaan ke-3 membuatnya tidak sepele seperti seharusnya semudah memeriksa 2. Bisakah Anda memposting contoh bagaimana Anda saat ini melakukannya dan sebuah contoh menggunakan 3 negara.
John
Mungkin Anda dapat memeriksa solusi terbaik untuk menyelesaikan deklarasi jika memiliki banyak status: stackoverflow.com/q/13385744/1077364
vgonisanz

Jawaban:

6

Ketika saya perlu menggunakan flag, saya biasanya melakukan sesuatu di sepanjang baris ini.

enum obj_state
{
    NORMAL      = 0x00000;
    DRY         = 0x00002;
    HOT         = 0x00004;
    BURNING     = 0x00008;
    WET         = 0x00010;
    COLD        = 0x00020;
    FROZEN      = 0x00040;
    POISONED    = 0x00080;
};

int objFlags;

void DryOn() { objFlags |= DRY; }
void HotOn() { objFlags |= HOT; }
// etc...

void DryOff() { if (FlagOn(DRY)) objFlags ^= DRY; }
void HotOff() { if (FlagOn(HOT)) objFlags ^= HOT; }
// etc...

bool isDryOn() { return FlagOn(DRY); }
bool isHotOn() { return FlagOn(HOT); }
// etc...


// If the given Bit is on this will return true.
bool FlagOn(obj_state s) { return (objFlags & s) == s; }

// returns -1 if failed, 1 if successful
int apply_cold(Object obj)
{
    if (obj.isWetOn())
    {
        obj.ColdOff();
        obj.WetOff();
        obj.FrozenOn();
    }
    else
        return -1;

    return 1;
}


//---------------------------------
// alt way of doing DryOn and WetOn
// since these conditions can not be
// active at the same time.
void DryOn() 
{ 
    if (isWetOn()) 
        return;
    else
        objFlags |= DRY; 
}

void WetOn() 
{ 
    if (isDryOn())
        return;
    else;
        objFlags |= WET; 
}

Ini membuat menggunakannya untuk hal-hal seperti apply_cold () sangat mudah dan Anda jelas dapat membangun dalam kondisi Anda seperti kering dan basah.

Feltope
sumber
Mungkin Anda dapat memeriksa solusi terbaik untuk menyelesaikan deklarasi jika memiliki banyak status: stackoverflow.com/q/13385744/1077364
vgonisanz
7

Dua pengamatan:

  1. Sistem kondisi Anda tampaknya memiliki dua sumbu ortogonal: suhu dan racun. Mewakili mereka seperti itu.
  2. Saat memikirkan ini, Anda harus memisahkan transisi dari status .COLDdan HOTtransisi dalam cara Anda menyebutkannya, bukan negara.

Menggabungkan pengamatan itu akan menghasilkan sesuatu seperti ini:

// These is the representation of the two axes.
int temperature; // can be between -2 and +2, 0 is normal, 1 is hot, 2 is burning, -1 is cold, -2 is frozen
bool poisoned;

// These methods represent state transitions.
void applyHeat() {
    if ( temperature <= 2 ) {
        ++temperature;
    }
}

void applyCold() {
    if ( temperature >= -2 ) {
        --temperature;
    }
}

void applyPoison() {
    poisoned = true;
}

void removePoison() {
    poisoned = false;
}
Eric
sumber
Intinya adalah, saya akan menambahkan lebih banyak negara bukan orthogonals, apakah mungkin untuk dilakukan? PANAS juga suatu keadaan, normal = 30 ºC, panas = 70 ºC dingin = 5 ºC. Tetapi jika menambahkan panas dan panas, itu akan berubah menjadi terbakar.
vgonisanz
Bagaimana kalau Anda memodelkan suhu sebagai nilai integer dalam derajat Celcius alih-alih boolean yang mengatakan "panas" atau "dingin"?
Philipp
Tentu saja Anda dapat menambahkan lebih banyak kondisi suhu, seperti yang Anda lihat dalam jawaban saya, saya sebenarnya sudah mewakili kondisi panas. Apa yang dikatakan Philipp berarti memandang setiap derajat Celcius sebagai keadaan, yang baik-baik saja, meskipun perhatikan ini mungkin bukan yang Anda inginkan dari perspektif desain game: lebih banyak simulasi tidak memerlukan permainan yang lebih dalam, per se.
Eric
3

Merepresentasikan status Anda sebagai bitmask seperti yang Anda tulis, Anda bisa menerjemahkan deskripsi kendala ke dalam kode:

if ( (state & HOT) && (state & COLD) ) {
    state &= ~HOT;
    state &= ~COLD;   // reset both HOT and COLD flags if both are set
}

if ( (state & COLD) && (state & WET) ) {
    state &= ~WET;    // cold items can't be wet
    state |= FROZEN;  // instead, they're frozen
}

if ( (state & HOT) && (state & WET) ) {
    state &= ~WET;    // hot and wet items dry up...
    state &= ~HOT;    // ...and cool down
}

// add other constraints here...

Anda bisa membungkusnya menjadi suatu makeStateConsistent()yang dapat Anda panggil sebelum menguji bit negara untuk memastikan bahwa negara masuk akal.

Namun, satu batasan dari pendekatan ini adalah tidak dapat menjelaskan urutan perubahan negara. Misalnya, jika Anda ingin memiliki hasil berbeda untuk item panas yang menjadi basah daripada untuk item basah yang menjadi panas, Anda tidak bisa melakukannya seperti ini: semuamakeStateConsistent() metode yang dilihat adalah objek panas dan basah, tanpa informasi tentang cara Pasti seperti itu.

Sebaliknya, apa yang bisa Anda lakukan yaitu membuat negara item yang swasta (setidaknya konseptual) dan memanipulasinya melalui serangkaian metode seperti coolItem(), heatItem(), wetItem(), dryItem()dan sebagainya. Dengan begitu, metode perubahan negara sendiri dapat menangani setiap perubahan tambahan. Misalnya, heatItem()metode ini mungkin terlihat seperti ini:

if ( state & COLD ) {
    state &= ~COLD;    // cold items become normal temp when heated
    if ( state & FROZEN ) {
        state &= ~FROZEN;  // ...and melt if they were frozen
        state |= WET;
    }
} else if ( state & WET ) {
    state &= ~WET;    // wet items dry up when heated, stay normal temp
} else {
    state |= HOT;     // dry normal temp items become hot
}

Tentu saja, Anda mungkin masih ingin memiliki makeStateConsistent() metode sebagai cadangan, kalau-kalau Anda memiliki bug dalam metode perubahan negara Anda.

Juga, dalam beberapa kasus Anda mungkin dapat menyederhanakan kode Anda dengan menghilangkan status yang tidak perlu. Sebagai contoh, apakah Anda benar-benar memerlukan FROZENkeadaan terpisah , atau apakah itu cukup untuk hanya memperlakukan barang-barang dingin dan basah sebagai beku?

Ilmari Karonen
sumber