Come dividere la griglia esadecimale uniformemente tra n giocatori?


15

Sto realizzando un semplice gioco a griglia esadecimale e voglio che la mappa sia divisa equamente tra i giocatori. La mappa viene creata in modo casuale e voglio che i giocatori abbiano circa la stessa quantità di celle, con aree relativamente piccole. Ad esempio, se ci sono quattro giocatori e 80 celle nella mappa, ognuno di essi avrebbe circa 20 celle (non deve essere preciso al punto). Inoltre, ogni giocatore non dovrebbe avere più di quattro celle adiacenti. Vale a dire, quando viene generata la mappa, i più grandi "blocchi" non possono essere più di quattro celle ciascuno.

So che questo non è sempre possibile per due o tre giocatori (in quanto ricorda il problema "colorare la mappa"), e sto bene con altre soluzioni per quelli (come la creazione di mappe che invece risolvono il problema). Ma, per 4-8 giocatori, come potrei affrontare questo problema?


Gli automi cellulari sono un modo semplice, simile a questo: una semplice mappa, quattro biomi e come distribuirli
MichaelHouse

Risposte:


3

Questo è quello che vorrei fare:

  1. Assegna tutte le celle a giocatori casuali. Sulle grandi mappe dovrebbe essere molto probabile che produca un numero abbastanza uniforme di tessere per tutti i giocatori, su mappe più piccole probabilmente dovrai fare alcune correzioni.
  2. Rompere pezzi che sono troppo grandi. La cosa più semplice da fare sarebbe prendere tutte le tessere in blocchi e assegnare di nuovo ogni tessera a caso.
  3. In caso di un numero sbilanciato di celle (ad es. Il giocatore A ha 24 celle, il giocatore B ne ha 16), riassegnare un paio di celle da giocatori sovrarappresentati a giocatori sottorappresentati.
  4. Controlla ancora per i pezzi. Se il passaggio 3 ha introdotto nuovi blocchi, tornare al passaggio 2. In caso contrario, bella mappa!

PS Non penso che questo problema sia mai impossibile, il problema di colorazione della mappa è abbastanza diverso (per prima cosa è il contrario, forme-> colori invece di colori-> assegnazioni di piastrelle).
Junuxx,

Mi piace un po 'questo approccio, ma non esiste la possibilità che funzioni a lungo, cercando di bilanciare le dimensioni dell'area?
Manabreak,

1
@manabreak: ho fatto qualcosa per provarlo. Con una piccola modifica al passaggio 2 (riassegnare scorrendo tutti i giocatori invece di riassegnare in modo casuale) funziona abbastanza bene. Proverò a scriverlo quando avrò tempo.
Junuxx,

1
Sembra esattamente quello che stavo cercando. :)
manabreak,

1

Supponendo che tu abbia una mappa esadecimale di ncelle e pgiocatori, in cui p <= nil modo migliore per affrontarlo è attraverso la distribuzione round-robin tramite automi cellulari (CA).

Inizializzazione

Casualmente (e / o usando alcuni o altri euristici, come la distanza dal centro della mappa) scegli una cella iniziale per ogni giocatore. Da allora p <= n, questo non dovrebbe essere un problema.

Automi cellulari

È necessaria una connettività completa tra le celle esadecimali. Vorrei suggerire un array di 6 vicini per cella:

class Cell
{
   //... other members...
   Cell[6] neighbours = new Cell[6];
}

L'uso di matrici di dimensioni fisse consente l'esistenza del concetto di direzioni topografiche tra celle, cosa che un elenco o un vettore non avrebbe. Lo consiglio, poiché potrebbe rendere più semplici alcune operazioni di navigazione.

Puoi anche archiviare la tua hexmap in un array 2D, con offset per riga. Questo può tuttavia essere leggermente meno intuitivo rispetto alla memorizzazione di un array vicino per cella, solo a causa dell'offset geometrico su ogni altra riga.

Assicurati che ogni cella sia connessa a tutto ciò che è vicino. Puoi eseguire questa riga per riga, cella per cella mentre generi l'esagono completo. PS Se alla fine desideri una hexmap delimitata in modo non rettangolare, puoi semplicemente rimuovere singole celle e riferimenti a tali celle, per formare spazi negativi, che ti consentono di creare un contorno organico della mappa.

Distribuzione round-robin

pseudocodice:

count number of neutral cells in entire map, minus those starting cells taken by players
while neutral cells remain (or while true)
   for each player
      if player has not yet reached expected territory size in cells
         for each cell already constituting this player's territory
           if territory can grow by one cell into a neutral neighbour
              grow into neighbour
              reduce neutral cell count for entire map by one
              if no more neutral cells remain in map
                 break out of outermost while loop immediately
              else
                 continue to next player immediately
begin game

Questo algoritmo darà a ogni giocatore la possibilità di far crescere il proprio territorio di uno, in modo round robin, a condizione che il territorio del giocatore abbia ancora spazio di crescita valido. Se certi giocatori sono bloccati di crescere ulteriormente, l'algoritmo nonostante questo continuano a crescere i territori di giocatori che non hanno ancora spazio di crescita valida. Puoi limitare facilmente ogni giocatore allo stesso numero di celle non appena uno di loro raggiunge un limite, ma dovrebbe essere abbastanza facile da capire, se lo desideri.

Ciò fornirà "territori d'origine" di dimensioni massime per ciascun giocatore. Se si desidera avere anche territori "insulari", al fine di soddisfare la quota di conteggio delle celle per quel giocatore, una volta che un giocatore ha esaurito lo spazio locale per crescere, è quindi possibile selezionare una nuova cella iniziale dall'elenco di celle neutre e procedere con lo stesso processo di "crescita", da lì. In questo modo, finirai con insiemi di isole di dimensioni adeguate e coerenti per ogni giocatore, piuttosto che rumore casuale.


Sebbene tu fornisca eccellente documentazione e pseudocodice per il tuo algoritmo, non sono sicuro che corrisponda a ciò che l'interrogante chiede. La domanda menziona "i più grandi" blocchi "non può essere più di quattro celle ciascuno", mentre l'algoritmo crea un gruppo il più grande possibile connesso.
fnord,

@fnord No, non è così. Non hai letto correttamente la mia risposta. Ho messo esplicitamente un limite nello pseudocodice: "se il giocatore non ha ancora raggiunto la dimensione del territorio prevista nelle celle". Rimuovi il tuo voto negativo. Sentiti libero di controllare la cronologia delle revisioni sulla domanda per accertarti che questo fosse il caso da prima del tuo commento e del tuo voto negativo.
Ingegnere,

La domanda chiede di avere "non più di quattro celle adiacenti", ma per ogni utente di avere una porzione prevista della mappa. Questo, per me, implica che stiamo cercando qualcosa di più simile a come i giochi a rischio assegnano casualmente la mappa a tutti i giocatori. La tua risposta divide la mappa in "territori d'origine" di dimensioni massime ". È vero, il tuo algoritmo si interrompe quando viene raggiunto il limite di dimensione del territorio previsto, ma non vedo un modo per quel giocatore di ottenere nuove "isole", anche se lo menzionerai nel testo successivo.
fnord,

@fnord La tua logica è in errore. Nella tua frase finale, ammetti che il mio algoritmo si interrompe alle dimensioni dell'isola ne, successivamente, ti contraddici dicendo che "non vedi un modo", ma che io "cito [come ottenere isole] nel testo successivo". Ho o non ho risposto alla domanda? Questo algoritmo generalizzato può essere usato per disperdere le celle (limitando na 1) o per creare isole (impostando n> 1). Quindi hai, in un singolo algoritmo, non solo la possibilità di disperdere, ma anche di raggruppare. In che modo ciò non risponde alla domanda del PO? Com'è degno di un downvote?
Ingegnere,

Vorrei modificare il mio commento sopra, ma è troppo tardi. "Non vedo un modo nel tuo algoritmo ". sebbene menzioni il concetto nel testo successivo.
fnord,

0

Un altro approccio sarebbe quello di iniziare con una distribuzione "giusta" ma regolare, e quindi utilizzare una valutazione simile alla ricottura simulata per rompere la regolarità senza perdere l'equità:

  • Inizia assegnando i colori a tutte le celle della griglia in modo regolare (ad esempio, presenta un motivo "123412341234" ripetuto nella prima riga, seguito da "341234123412" nella successiva, ecc.). Questo può portare a una distribuzione non uniforme dei colori se la tua mappa è particolarmente mal modellata, ma presumo che tu stia iniziando con una mappa fissa, quindi dovresti essere in grado di trovare una colorazione equidistribuita di essa.
  • Quindi ripeti quanto segue per tutti i passaggi che desideri (non esiste un vero criterio di "doneness", quindi la sperimentazione ti dirà qual è un numero minimo ragionevole di passaggi):
    • Scegli due elementi della griglia a caso
    • Se hanno lo stesso colore, riprova (altrimenti non ha senso, dato che lo scambio sarà vietato. Hai solo 1/4 possibilità di colpire lo stesso colore e 1/16 possibilità di colpire lo stesso colore due volte di fila, quindi non dovresti mai riprovare troppo)
    • Scambia provvisoriamente i colori di questi due elementi
    • Testare le dimensioni delle regioni appena formate nelle posizioni degli elementi dopo lo scambio:
      • eseguire un semplice riempimento alluvione verso l'esterno dal nuovo punto di ciascun elemento per determinare la dimensione di una regione di quel colore che lo scambio farebbe.
    • Se una di queste due aree è maggiore della soglia, annulla lo swap provvisorio; in caso contrario, "finalizzare" lo scambio dei colori dei due elementi.

Le chiavi qui sono che il fatto che stai scambiando due punti significa che non sbilanci mai i colori, e allo stesso modo il test che fai prima di finalizzare lo scambio ti assicura che non crei mai aree troppo grandi. Se hai qualche mezzo per visualizzare la tua griglia, potresti persino visualizzare questo processo per vedere come "costruisce" le sue regioni attraverso gli swap ripetuti.

Se non puoi iniziare con una colorazione regolare equidistribuita, per inciso, dovresti comunque essere in grado di fare qualcosa di simile per equidistribuire la colorazione: mentre la tua colorazione non è equidistribuita, scegli un elemento a caso; quindi, se si tratta di uno dei colori sovrarappresentati, imposta provvisoriamente il suo colore su uno dei colori sottorappresentati e verifica che non crei una regione troppo grande del nuovo colore.


Gli approcci stocastici sono inefficienti. Per un approccio come il mio che prende in considerazione i passaggi, il runtime si avvicina a O (n) per n celle della mappa. Per il tuo algoritmo, è O (n * m), dove m è il numero di celle desiderate per isola (in realtà, per ciascuna isola potenziale). Sempre meglio puntare su algoritmi che hanno un runtime facilmente stimabile. Invece di correggere una mappa generata a casaccio, meglio generare una mappa che non è rotta o casualmente in primo luogo, in n passaggi, mantenendo così un processo controllato ed efficiente.
Ingegnere,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.