Passa un elenco di scelte con argomenti diversi per ciascuna scelta

5

Sto scrivendo un gioco di carte, in cui ho separato la "Core Logic" del gioco dall'interfaccia utente. La comunicazione con il lettore dalla parte logica principale viene eseguita tramite i callback che l'interfaccia utente implementa e gestisce (in un thread separato se necessario). La libreria logica di base chiama questi callback, l'interfaccia utente li gestisce, passa un oggetto che rappresenta i dati che devono essere restituiti e lo restituisce.

Ciò di cui sono attualmente bloccato è l'implementazione della capacità della Core Logic di dare al giocatore una "scelta" tra le possibili azioni. Ad esempio, la logica di base potrebbe richiedere al giocatore di selezionare tra le seguenti 3 azioni di gioco:

  • Disegna 5 carte dal mazzo A
  • Disegna 2 carte dal Deck B
  • Assegna 4 punti nel secchio 1

Il punto è che ogni azione può essere molto diversa dall'altra. Come posso rappresentare queste informazioni come un oggetto in C #? Posso pensare a 4 modi brutti ...

  1. Basta passare un elenco di stringhe contenenti il testo di scelta all'interfaccia utente e visualizzare l'interfaccia utente, quindi l'utente seleziona tra di esse:

Questo è l'approccio più semplice (e molto allettante), ma sarebbe quello di mescolare l'interfaccia utente con la logica principale, che va contro l'idea principale alla base del progetto.

  1. Passa un oggetto contenente un enum e un oggetto, il cui tipo effettivo dipende dal valore dell'enum (l'enum è qualcosa come Draw, Allocate, ecc., e l'oggetto che contiene cose come il numero di carte e quale mazzo per la scelta Disegna e il numero di punti e quale bucket per il comando Allocazione)

Ma ciò implica un sacco di istruzioni if e typecasting e reflection, tra gli altri problemi, che è brutto. Significa anche che dovrei fare una classe separata per quasi tutti i tipi di enum di scelta, che è anche brutto perché ogni classe sarebbe solo una lista di valori.

  1. Passa un dizionario che contenga le chiavi e i valori delle stringhe, il contenuto del dizionario in base al tipo di scelta che puoi fare.

Ciò comporterà ancora un sacco di typecasting e perderò anche la sicurezza del tipo, ma almeno non avrei dovuto creare una classe per ogni singola scelta.

  1. Passa un oggetto contenente un enum e un oggetto dinamico contenente un tipo anonimo i cui campi dipendono dal valore dell'enumerazione.

Questo rende la gestione delle cose nell'interfaccia utente molto più semplice e non avrei bisogno di creare più classi, ma poi perdo sicurezza di tipo e controlli di base durante la compilazione ..

C'è qualche tipo di schema che le persone solitamente usano quando si affronta questo problema, o dovrei semplicemente scegliere il mio veleno e andare a prenderlo? Forse dovrei ripensare al mio intero approccio all'intera faccenda?

In C, probabilmente utilizzerei un'unione di strutture per questo genere di cose. Non sono sicuro di come lo farei in C #. Forse sto pensando troppo a C?

    
posta 9a3eedi 08.11.2015 - 16:41
fonte

2 risposte

2

Sono per 2, ma con leggera modifica. Non userei enum . Puoi altrettanto bene usare GetType() . Se dovessi aggiungere enum al mix, duplicherebbe le informazioni sul tipo contenute all'interno dell'oggetto.

Inoltre, creo un visitatore per la classe Choice . Ciò eliminerà la necessità di riflessione e fornirà il modo sicuro per l'interfaccia utente per creare una rappresentazione testuale per ciascuna scelta. Garantirà inoltre che quando si aggiunge un nuovo tipo di scelta, il compilatore imporrà l'implementazione di tutto il codice correlato, come la creazione di una rappresentazione testuale per esso. E non vedo come avere molte classi sia cattivo. In realtà è una cosa buona, purché quelle classi siano coese.

E non credo che quegli oggetti conterranno solo dati. Possono benissimo essere oggetti che fanno l'azione reale. Metti solo il metodo Execute() su di loro, e possono essere quelli che pescano le carte dai mazzi o che assegnano i punti ai secchi.

    
risposta data 09.11.2015 - 08:35
fonte
2

Vorrei utilizzare una classe base con classi ereditate o un'interfaccia con implementazioni concrete per distinguere il tipo di scelta che l'utente può fare. Le interfacce avrebbero più senso se fosse necessario eseguire qualche tipo di operazione sulla scelta, ma poiché ciò non rientra nell'ambito della domanda, ecco un esempio della precedente opzione che utilizza una classe base con ereditarietà.

public class ChoiceOption
{
}

public class DrawChoiceType : ChoiceOption
{
    public int NumberToDraw { get; set; }
    public Deck DrawFrom { get; set; }
}

public class AllocatePointsChoiceType : ChoiceOption
{
    public int PointsToAllocate { get; set; }
    public Bucket AllocatePointsTo { get; set; }
}

Con questa struttura, il tuo motore di gioco passerà l'elenco delle scelte al giocatore e gestirà la scelta fatta in questo modo:

List<ChoiceOption> choicesAvailableToPlayer = new List<ChoiceOption>();
choicesAvailableToPlayer.Add(new DrawChoiceType() { DrawFrom = Decks.DeckA, NumberToDraw = 5 });
choicesAvailableToPlayer.Add(new DrawChoiceType() { DrawFrom = Decks.DeckB, NumberToDraw = 2 });
choicesAvailableToPlayer.Add(new AllocatePointsChoiceType () { AllocatedPointsTo = Buckets.Bucket1, PointsToAllocate = 4 });
ChoiceOption playerChose = player.Callback(choicesAvailableToPlayer);
if (playerChose is DrawChoiceType)
{
    //Do whatever needs to be done in the game engine for this selection.
}
else if (playerChose is AllocatePointsChoiceType)
{
     //Do whatever needs to be done in the game engine for this selection.
}

Non sono sicuro di come il tuo codice UI stia visualizzando queste opzioni di scelta all'utente, ma sarebbe molto semplice guidare l'interfaccia utente da questa struttura.

    
risposta data 10.11.2015 - 09:45
fonte