Come posso mantenere una formazione rettangolare quando le unità vengono aggiunte o rimosse?


18

Ho dei robot in una formazione rettangolare con file e colonne. Un problema sorge quando un bot viene aggiunto o rimosso dalla formazione. Quando ciò accade, i robot devono riorganizzarsi in modo tale che la formazione rettangolare abbia ancora approssimativamente le stesse proporzioni ed sia il più rettangolare possibile. Come fare questo?

Qualche idea:

  • Quando un bot viene aggiunto o rimosso, utilizzare il nuovo numero totale di bot e le proporzioni costanti desiderate per calcolare la nuova larghezza e altezza della formazione che si adattano maggiormente a tali proporzioni. Quindi in qualche modo rimescola i robot per adattarli alle nuove dimensioni.

  • Quando un bot viene rimosso, sposta il bot che si trovava dietro di esso al suo posto e continua fino a raggiungere la fine della formazione. Quindi uniforma il rango posteriore il più possibile mescolando in qualche modo i robot nel rango posteriore.

  • Un'altra idea completamente diversa è quella di imitare il modo in cui le strutture molecolari stanno insieme. Fai in modo che ogni bot voglia essere circondato da altri quattro robot attirando i quattro robot più vicini e respingendo il resto. Respingi tutti i bot (inclusi i quattro) che sono troppo vicini per garantire la separazione usando la legge del quadrato inverso. Avresti anche bisogno di una forza aggiuntiva per modellare l'intera struttura. Ma questo suona molto computazionalmente costoso.

AGGIORNAMENTO : Quindi, esaminando la risposta di Sarah, ho trovato una buona funzione generale che dà buone dimensioni.

Per prima cosa ho risolto l'equazione simultanea di seguito per larghezza e altezza, quindi ho arrotondato le risposte.

width/height=aspect ratio of your choice
width*height=number of bots

Questo ti dà il rettangolo intero più vicino a quell'aspect ratio per il tuo numero di bot. Il rettangolo più vicino sarà metà del tempo troppo grande e metà del tempo troppo piccolo (ovviamente a volte sarà giusto, ma a chi importa di quelli). Nei casi in cui il rettangolo è un po ' troppo grande, non è necessario fare nulla. Il back rank finirà per essere quasi pieno, il che è l'ideale. Nei casi in cui il rettangolo è un po ' troppo piccolo, hai problemi perché quel piccolo trabocco adolescente dovrà andare al suo stesso rango creato un rango con solo pochi robot su di esso, che non sembra carino. Ci sono anche casi in cui la differenza è grande(maggiore della metà della larghezza), nel qual caso aggiungere o sottrarre un rango per ridurre la differenza. Quindi, quando il rettangolo è troppo piccolo, aggiungi una colonna per ingrandirla leggermente. Dopo aver fatto ciò, sembra che il back rank avrà sempre almeno la metà del numero di bot degli altri ranghi.

AGGIORNARE

Dopo aver ottenuto le dimensioni, confrontale con le dimensioni correnti. Se la facciata della nuova dimensione è più grande, per ogni rango, fai scoppiare i robot dal rango sottostante e spingili sul rango corrente fino a quando il numero di bots su quel rango è uguale al frontage. Continua quell'algoritmo fino a raggiungere il rango posteriore. Utilizzando questo algoritmo, i robot si sposteranno per adattarsi in modo efficiente alla nuova dimensione. Dopodiché, spingo semplicemente il nuovo vecchio sul rango posteriore. L'algoritmo è leggermente diverso per i casi in cui la nuova facciata è più piccola, ma puoi capirla!

Ci sono altri due problemi dopo. Eliminazione e un metodo di aggiunta più flessibile in cui i nuovi robot non sono necessariamente assegnati al back rank ma a seconda della posizione più vicina a loro nel momento in cui vengono aggiunti.


Qual è il numero massimo di bot in un'unità? Se è relativamente piccolo, potresti codificare quante righe e colonne ha una formazione per un certo numero di bot.
Exilyth,

3
Puoi pubblicare un'immagine di formazioni valide o non valide? Ho qualche problema a capire cosa stai cercando. Sono consentite righe / colonne incomplete?
MichaelHouse

3
Ti rendi conto che questo non funzionerà con i numeri primi? ad es. con 7 robot, dovresti creare un'unità 3x2 con un solo bot nella parte posteriore.
Exilyth,

1
Beh, questo è imbarazzante. Mi ero completamente dimenticato dei numeri primi. Quindi forse la cosa migliore sarebbe consentire solo righe e colonne che sono QUASI riempite. Un Bot di fila non sembra giusto, ma un Bot di fila in meno non sarebbe male.
Tiby312,

3
I numeri primi non sono i soli che causeranno problemi: la scelta della dimensione della formazione tramite il factoring potrebbe dare formazioni irragionevolmente lunghe e magre. Ad esempio, se hai 14 bot, l'unica formazione rettangolare perfetta è 7x2, mentre potrebbe sembrare migliore avere una formazione 3x4 con una fila aggiuntiva di 2 bot.
Nathan Reed,

Risposte:


16

Un'altra tecnica è quella di imitare quella usata dai battaglioni napoleonici (e probabilmente fino alle falangi greche se non oltre).

La facciata è generalmente mantenuta costante, e quando un uomo cade (in qualsiasi grado eccetto la schiena) viene sostituito dall'uomo direttamente dietro di lui che si fa avanti. Il rango posteriore viene mischiato dagli NCO per garantire alcuni uomini all'estremo di ogni fianco e altrimenti riempire uniformemente.

La facciata viene ridotta solo quando il rango posteriore scende al di sotto delle densità predefinite. Allo stesso modo, quando il rango posteriore è troppo pieno, gli extra iniziano a riempire un rango aggiuntivo da entrambi i lati, quindi la facciata viene aumentata.

Quando si cambia la facciata, suggerisco di estrarre il file dei bot dal rango posteriore ad entrambi i fianchi quando si aumenta la facciata e di archiviare da entrambi i fianchi al rango posteriore per ridurre la facciata.

Se ho ragione a dedurre che stai cercando un'impressione "militare" e che le tue organizzazioni di bot assomiglino a falangi, credo che questa riorganizzazione ordinata sia un modo migliore per raggiungere questo scopo.

Aggiornamento :
un modo semplice per gestire la fila posteriore è dividere le unità della fila posteriore in tre squadre: una su ciascun fianco e una al centro. A seconda che la facciata sia pari o dispari e che il numero di unità di fila posteriore sia congruente a 0,1 o 2 mod 3, ci sono esattamente sei casi da gestire.

Come miglioramento di quanto sopra, considera la spaziatura delle ultime unità di ciascuna squadra di fila posteriore una volta che il riempimento scende al di sotto di una soglia, in questo modo:
xxx.x .... x.xxx.x .... x. xxx
o questo:
xx.xx..x.xxx.x ... xxxx
Un po 'più di lavoro, per un aspetto ancora migliore.

Aggiornamento n. 2 :
un'ulteriore riflessione sulla profondità della formazione. L'impatto del tiro al volo, combinato con la moderna baionetta, rese la profondità di 3 o 4 adeguata alla fine del 18 ° e all'inizio del 19 ° secolo. (Gli inglesi raramente combatterono in 2 ranghi, contrariamente alla credenza popolare, fino a tardi in una battaglia; per uno, fece le loro linee troppo lunghe per formare rapidamente il quadrato.) Prima di allora era comune avere profondità maggiori, forse fino a 8 o 10 per una falange greca equipaggiata con Sarissa. Scegli una profondità che crea l'impressione che desideri.

Gli eserciti nella vita reale cercano di mantenere il fronte delle unità il più a lungo possibile, a scapito della maggiore fragilità delle unità, in quanto ciò semplifica la creazione di un campo di battaglia. Cesare a Farsalo ridusse deliberatamente la profondità della sua unità per aumentare la facciata in modo che corrispondesse a quella delle forze di Pompeo. Come dice la citazione: "Oggi vinciamo o moriamo; gli uomini di Pompeo hanno altre scelte". (che Cesare aveva sapientemente e accuratamente assicurato, ovviamente).


Sembra una soluzione molto più elegante. Non c'è bisogno di preoccuparsi dei numeri primi o delle proporzioni, eppure evita comunque qualsiasi riga che abbia un numero insolitamente basso di bot, e l'unica condizione che deve essere controllata è quanto sia pieno il backrank!
Tiby312,

Ma aspetta. Supponiamo che il rango posteriore contenga solo 3 robot e sia nelle colonne 1, 2 e 3. E rimuovo qualcuno dalla quinta colonna qualcuno vicino al fronte. Finirei con un posto libero nella penultima riga della quinta colonna senza bot dietro per prendere il suo posto. Chi dovrebbe riempire questo posto?
Tiby312,

Presumibilmente, il bot più vicino nel back rank (cioè quello nella colonna 3) dovrebbe essere eseguito per riempirlo. Oppure potresti risparmiare un po 'di tempo facendo in modo che i robot nelle colonne 3 e 4 del penultimo rango ogni passo di una colonna verso l'alto, spostando il gap sulla colonna 3, e quindi il robot alla colonna 3 passi avanti per riempire esso. (IMO, la strategia dall'aspetto più "naturale" sarebbe probabilmente una combinazione euristica dei due, possibilmente con una certa casualità.)
Ilmari Karonen,

1
Se il rango posteriore ha troppi membri (diciamo meno del 50% degli altri ranghi) e si aumenta la facciata, questo è garantito per risolvere il problema o è possibile che il rango posteriore abbia ancora pochi membri dopo aver aumentato la facciata che richiede di essere ripetuta o qualcosa del genere?
Tiby312,

1
@ Tiby312: credo che tu ci stia pensando troppo.
Provalo

7

Supponendo che un'unità sia una struttura di dati lineare (ad esempio un elenco ) di robot.

Innanzitutto, è necessario aggiungere / rimuovere il bot nella / dalla struttura dati e determinare il nuovo numero di bot nell'unità.

Quindi, devi determinare la nuova quantità di righe e colonne usando https://en.wikipedia.org/wiki/Integer_factorization .

Naturalmente, ciò non è sempre possibile a causa dei numeri primi . Quando la nuova dimensione dell'unità è un numero primo, è necessario utilizzare la successiva dimensione dell'unità più grande che non lo è.

Quindi, basta scorrere la struttura dati, assegnando i robot in ordine alle righe e alle colonne.

Per posizionare i robot, basta scorrere la struttura dati, assegnando a ciascun bot un offset di posizione dalla posizione delle unità di un importo determinato dalla riga e dalla colonna in cui si trova il bot (oppure, impostare quel punto come obiettivo per il movimento dei robot).

Per creare un'unità con il centro in un angolo , viene data la posizione di un bot

unitPosition + intestazione * * ColumnNumber botSeparationDistance + rightVector * * RowNumber botSeparationDistance

Per creare un'unità con il centro al centro , viene data la posizione di un bot

unitPosition + voce * (* ColumnNumber unitSeparationDistance - 0.5 * (* numberOfColumns botSeparationDistance) + rightVector * * RowNumber botSeparationDistance - 0.5 * (* numberOfRows botSeparationDistance)

dove intestazione è un vettore che punta nella direzione dell'unità sta affrontando e rightVector è un vettore ortogonale a voce .

botSeparationDistance può essere ottimizzato per rendere i robot più distanti o più vicini.

Se ti senti di fantasia, è possibile compensare l' ultima fila di bot dal rightVector * 0.5 * (numberOfColumns - actualNumberOfBotsInRow) per centrare loro sulla formazione .


Questo è molto vicino a quello che sto cercando! La mia unica riserva è che quando si assegnano nuove posizioni, un Bot all'estrema destra di una riga, potrebbe essere assegnato all'estrema sinistra della riga successiva nel nuovo rettangolo, facendo sì che il Bot abbia il viaggio a lunga distanza e nei processi intralciare altri robot che cercano di raggiungere la nuova posizione assegnata. Temo che quando un bot viene aggiunto o rimosso, l'intera formazione sarebbe un frastuono mentre i robot si affrettano a raggiungere la loro destinazione lontana.
Tiby312,

2
Puoi sempre calcolare le nuove posizioni, quindi spostare il bot più vicino in quella posizione invece di eseguire un'iterazione lineare.
Exilyth,

Come fare questo senza finire con un calcolo al quadrato? Dovrei trovare la posizione più vicina nell'array 2d dalla loro posizione corrente nell'array 2d, per ciascun Bot, se lo capisco correttamente.
Tiby312,

In ogni iterazione, verrebbe assegnata un'unità (e quindi non è necessario considerarla su ulteriori iterazioni), quindi il tempo di esecuzione sarebbe O (n!). Che, tuttavia, non è molto buono. Inoltre, la costruzione di una [struttura di ottimizzazione di scelta] e l'esecuzione di query n range non è neanche veloce. L'unica cosa che mi viene in mente in questo momento è spostare gli ultimi robot di fila verso il retro o riempire gli ultimi posti di fila con i robot da dietro.
Exilyth,

Cosa ne pensi di questo. Supponiamo che la nuova formazione abbia dimensioni di riga inferiori. Quindi su ogni riga, hai un bot in più. Assegni quel bot uno in basso e uno a sinistra. Quindi nella riga successiva in basso, hai due robot senza posto. Assegni quei due uno in basso e uno a sinistra. Quindi hai 3 robot senza posto. Continua fino a quando non hai una riga in più in fondo. Sto solo sputando palla qui. Non ci ho pensato fino in fondo, ma sembra che funzionerà ed è veloce.
Tiby312,

2

Vorrei memorizzare le possibili posizioni in un grafico con valori più grandi che sono rettangoli più piccoli.

[4][3][2][1]
[3][3][2][1]
[2][2][2][1]
[1][1][1][1]

Ogni volta che un robot viene rimosso, cerca tutti gli altri robot e trova quello in un nodo con il valore più piccolo. Usa A * o un algoritmo BST per trovare un percorso dal valore più piccolo allo spazio vuoto. Se non esiste un robot con un valore inferiore a quello rimosso, non fare nulla.

Dovresti anche essere in grado di controllare come il rettangolo decade in questo modo. Ad esempio, nel grafico sotto, quando un robot lascia quello inferiore dal lato verrebbe a riempire il suo posto.

[4.9][3.8][2.7][1.0]
[4.8][3.7][2.6][1.0]
[3.9][3.6][2.5][1.0]
[3.5][3.4][2.4][1.0]
[2.9][2.8][2.3][1.0]
[2.0][2.1][2.2][1.0]
[1.9][1.8][1.7][1.0]
[1.6][1.5][1.4][1.0]

Qui quello a 3.8 viene rimosso così quello a 2.5 viene e riempie il suo posto.

[o][x][o][ ]
[o][o][o][ ]
[o][o][r][ ]
[o][o][ ][ ]
[o][o][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]

Un altro esempio. Qui 2.8 viene rimosso in modo che il nodo 2.2 più piccolo arrivi e riempia il suo posto.

[o][o][o][ ]
[o][o][o][ ]
[o][o][o][ ]
[o][o][o][ ]
[o][x][r][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]
[ ][ ][ ][ ]

Probabilmente vuoi un anello di nodi con valore 0 che non popoli mai all'esterno per far trovare il buco al tuo algoritmo di pathfinding.

[0.0][0.0][0.0][0.0][0.0][0.0]
[0.0][4.9][3.8][2.7][1.0][0.0]
[0.0][4.8][3.7][2.6][1.0][0.0]
[0.0][3.9][3.6][2.5][1.0][0.0]
[0.0][3.5][3.4][2.4][1.0][0.0]
[0.0][2.9][2.8][2.3][1.0][0.0]
[0.0][2.0][2.1][2.2][1.0][0.0]
[0.0][1.9][1.8][1.7][1.0][0.0]
[0.0][1.6][1.5][1.4][1.0][0.0]
[0.0][0.0][0.0][0.0][0.0][0.0]

Un buon tutorial su A * può essere trovato qui .


Questa è una dolce idea, ma se lo capisco correttamente, stai permettendo formazioni che non sono rettangoli perfetti. Le righe e le colonne sui bordi potrebbero non essere piene. Stavo pensando che avrei potuto farlo in modo che avesse sempre un bordo rettangolare e invece cambiare un po 'le proporzioni per soddisfare questo requisito cambiando il numero di righe e colonne. Posso già calcolare la nuova larghezza e altezza che lo farebbero, ma poi c'è un modo complicato di riassegnare i robot al punto più vicino ... Penso.
Tiby312,

@ Tiby312 Come pensi di realizzare un rettangolo perfetto con diciamo ... 7 robot?
ClassicThunder

NEVERMIND Ho dimenticato i numeri primi. Scusa. Ma sto ancora pensando che la regolazione del numero di righe e colonne potrebbe evitare che una riga o una colonna contenga un numero insolitamente basso di bot.
Tiby312,

@ Tiby312 Penso che tu stia meglio puntando a proporzioni coerenti (cioè sempre 4: 3 o 8: 5) piuttosto che cercare di renderlo sempre un rettangolo perfetto.
corsiKa
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.