Prosedürel olarak bir dünya tarihini oluşturmanın bir yolu var mı?


28

Burada , bir insanın yarattığı hayali bir dünyada 1800 yıllık kültürel tarihi temsil eden şemada biraz ilgileniyorum .

enter image description here

Bu tür bir şey, dünya tasarımı kadar, oyun geliştirme için güçlü uygulamalara sahip görünüyor.

Bu diyagramı elle yapmış gibi görünüyor. İlgilendiğim şey, bu tür bir diyagramı programlı olarak oluşturmanın bir yolu olup olmadığını görmek.

Eğer yukarıdaki tarzda rastgele değerlerden diyagramlar oluşturmakla görevlendirilseydiniz, nasıl yapardınız? Göz önünde bulundurmanız gereken belirli veri yapıları veya algoritmaları var mı?


5
Cüce Kalesine bir göz atmayı düşün . Kaynak kullanılamıyor ve dünya üretim süreci belgelenmemiş (bu yüzden neden bir cevap vermiyorum?), Ancak oyunu oynamayı öğrenmek zorunda kalmadan oluşturulan dünya tarihini inceleyebilirsiniz ve bu size tür hakkında bir fikir verebilir. Yapabileceğin şeyler.
Josh,

Başka bir kaynak var ve bir cevap bulunmuyor olabilir: www-cs-students.stanford.edu/~amitp/game-programming/… Bu, bir çevre oluşturmak için bir makaledir, ancak çevrenin nasıl olabileceğine değinmeye devam eder. krallığın bölgesel sınırlarını tanımlamak için kullanılan, insanların neye ve neye ya da neye yattıkları için savaşa girdiklerinde karışıma atılabilecek kaynaklara (su, yaşanabilir topraklar vb.) dayanıyordu. Yine, sadece bir kaynak, bir cevap değil.
James,

1
Bu şema Uygarlık 3'teki güç grafiğine çok benziyor. Bu seriyi bazı fikirler için incelemek isteyebilirsiniz.
WildWeazel

Yanıtlar:


15

Ne kadar doğru olmak istiyorsun? İyi ama karmaşık bir seçim tüm bu tarihi taklit eder:

  1. Bu bölgeler arasında rastgele bir bölge listesi ve bitişler oluşturun.
  2. Nüfus, savaş, teknoloji ... gibi özelliklere sahip rastgele medeniyetler oluşturun ve bölgeleri doldurun.
  3. Medeniyet özelliklerine dayanan sonuçları belirleyerek istediğiniz kadar tarihin simülasyonunu yapın.

Örn: iki komşu savaşçı medeniyetin birbiriyle savaş etme olasılığı daha yüksektir, bu da zamanla nüfusun azalmasına neden olur. Ticari medeniyetlerin kaynakları daha yüksektir, ancak istilalar için mükemmel bir hedeftir. Yüksek nüfuslu olanlar daha hızlı büyüyecek fakat daha fazla açlık şansına sahip olacaklar. Kültürel olarak heterojen olan sivillerin daha az iç savaş şansı vardır (bu da ayrılıklara yol açabilir.) Ve bunun gibi ... Sonuçlar medeniyet özelliklerini de değiştirir: yüksek teknoloji daha iyi ticaret, daha güçlü silahlar vb.

Bu aynı zamanda bazı ussal hikaye anlatımlarına da izin verir: yalnızca bir bölge şemasını değil, aynı zamanda geçmiş zamanın metinsel tanımlarını da çıkartabilirsiniz. Bu sistemi istediğiniz kadar karmaşık yapabilirsiniz.


EDIT: Buradaki zorluk teknik değil, gerçekçi ve ilginç tarih üretimi için sezgisel özellikleri ayarlıyor. Daha yakından bir göz atın ve bahsettiğiniz 3 konuyu düşünün ... bu teknik açıklamanızdan çok daha fazlası! Bunu bir döngüye çevirin (her yineleme istediğiniz kadar zaman, 1 yıl, yarım yıl, 1 ay ... olarak gösterebilir) ve hepsi bu kadar. İç çamaşırları (veri yapıları, sezgisel taramalar) çalışmak zorunda kalacaksınız ve bunu kendi probleminize ve ihtiyaçlarınıza göre uyarlayacaksınız. Buradaki zor kısım ve hayal gücü, deneme ve yanılma yüzünden kimse size yardım edemez.

Neredeyse herhangi bir sorun için kullanacağınız yanı sıra, bu sorun için ortak veri yapıları yoktur: listeler, sıralar, ağaçlar ... ve bunlar sizin özel uygulamanıza bağlanır (bir soy ağacına ihtiyacım var mı? Savaşta? Her vatandaş için bir görev sırası?) Tabii ki bir medeniyet listesine de ihtiyacınız var. Seçenekler açık ve neredeyse çok sağduyulu.

Simülasyon bir şans / olasılık meselesidir ve rastgele sayılarla bin farklı şekilde yapabilirsiniz. Simülasyonun futbol menajerleri, RPG'ler (sonuç olarak, hit puanlar / istatistikler sadece savaş simülasyonu ), strateji oyunları gibi rol oynadığı herhangi bir oyunu düşünün ... Bu sadece özelliklerdir (medeniyet özelliklerini ve verilerini depolamak için bir yola ihtiyacınız olacak) ve bunlara dayalı istatistiksel olarak rasgele sonuçlar (bu nedenle bu özellikleri temel alarak simülasyon durumunu rastgele değiştirmek zorunda kalacaksınız.)

Algoritmanızın özü budur: Sezgiyi ayarlamak zordur: Her medeniyet için simülasyonun başlangıcında özelliklerin nasıl dağıtılacağı ve simülasyon durumunun bunlara göre istatistiksel olarak nasıl değiştirileceği.

Kısacası: algoritmanız sadece simüle edilmiş zamanı herhangi bir artışla değişen bir döngüdür. Daha kısa artışlar daha ince tarihsel simülasyonlara neden olur, ancak açıkça daha uzun sürecektir. Döngünüzün içinde (kabaca) gibi bir grup buluşma olacak:

for each civilization
  if civ.isAtWar
    civ.population -= civ.population * 0.05;
    civ.wealth -= 1000.0;
    civ.belligerence += 1.0;
  if civ.population < 100
    civ.negotiatePeace()

Tüm bu çalışmalardan sonra (veya verileri saklamak istemiyorsanız), tüm simülasyon durumunu metin, görüntüler veya istediğiniz gibi insan tarafından okunabilir bir formata çevirmelisiniz. Bu, deneme yanılmadır ve uygulamanız için çok özeldir.

Sorunuza özgü : Sorunuzdaki gibi bir diyagram oluşturmak için dünya bölgelerini (diyagramın üst kısmı, x ekseni, bu nokta 1: benim cevabımda bölge listesi oluştur) ve uygarlıklarını (medeniyetindeki renkler) izlemek zorundasınız . diyagram, nokta 2 ) zamana kadar (y ekseni, 3. noktadaki simülasyon döngüsü )

Devlet makinelerigeniş konuları simüle etmede oldukça iyidir (yukarıdaki kod örneği, sabit kodlu bir durum makinesinin yaklaşık bir değeridir) - bu nedenle, genel olarak ayarlanması kolay olan basit bir durum makinesi çerçevesi uygulayarak başlayabilirsiniz. Her medeniyet, bu devlet makinelerinden biriyle başlayacak ve simülasyon, her devlet makinesini her bir tur için yürütecektir. Her bir devlet makinesinin başka bir devlet makinesiyle etkileşime girmesi gerekebilir: örneğin bir savaş başlatmak, başka bir medeniyetin devlet makinesini etkileyebilir, muhtemelen kendi iç devletlerine dayanarak farklı sonuçlar doğurabilir - örneğin 'kıtlık' durumundaysa, muhtemelen Barışı müzakere etmek istiyorum, ancak 'bela arayan' bir medeniyet muhtemelen misilleme yapacak. Makinedeki her devletin medeniyet üzerinde anlamlı etkileri olur ' Her bir “çerçeve” sırasında yukarıda belirtilen metrikler (zenginlik, savaşçılık, nüfus vb.). En önemlisi, her çerçevede durumları değiştirmenize gerek yoktur - sadece fırsat ve / veya rastgele bir şans ortaya çıktığında: bu, uzun süreli olayların (savaş gibi) ortaya çıkmasına izin verir.


Çok güzel bir cevap için teşekkür ederim, endişelendiğim teknik
konulara değmemesine rağmen

@pdusen yorumu oldukça uzadı, bu yüzden cevabımı "EDIT" işareti altında güncelledim.
12'de

2
Sakıncası yoksa bu cevaba ekleyeceğim?
Jonathan Dickinson,


@pdusen Biraz daha uygulamaya özel detay ekledim.
Jonathan Dickinson

8

Evet var. İşte kir-basit bir tarih üreteci:

#!/usr/bin/env python
# to create a visualisation, run like this:
#    ./timeline.py --dot | dot -Tpng > filename.png
import sys
import random
from pprint import pprint
# Names is a newline separated list of nation names.
file = "names.txt"
names = open(file, "r").read().split("\n") 
history = []
dot = False
if len(sys.argv) > 1 and sys.argv[1] == "--dot":
  dot = True

def wrap(str, wrap='"'):
  return wrap+str+wrap

def merge(states, names):
  number = random.randint(2,3)
  mergers = [] 
  if number < len(states):
    mergers = random.sample(states, number)
    new_name = random.choice(names)
    states = list(set(states).difference(set(mergers)))
    states.append(new_name)
    names.remove(new_name)
    if dot:
      for state in mergers:
        print '"%s" -> "%s"'%(state, new_name)
      print '{rank=same; %s }'%wrap(new_name)
    else:
      print "MERGE %s ==> '%s'"%( ", ".join(map(wrap,mergers)), new_name)
  return states, names 


def split(states, names):
  number = random.randint(2,3)
  if number < len(names):
    splitter = random.choice(states)
    states.remove(splitter)
    new_states = random.sample(names, number)
    names = list(set(names).difference(set(new_states)))
    states = list(set(states).union(set(new_states)))
    if dot:
      for state in new_states:
        print '"%s" -> "%s"'%(splitter, state)
      print '{rank=same; %s }'%("; ".join(map(wrap, new_states)))
    else:
      print "SPLIT '%s' ==> %s"%(splitter, ", ".join(map(wrap,new_states)))
  return states, names

def revolt(states, names):
  old = random.choice(states)
  new = random.choice(names)
  names.remove(new)
  states.remove(old)
  states.append(new)
  if dot:
    print '"%s" -> "%s"'%(old, new)
    print '{rank=same; "%s"}'%new
  else:
    print "REVOLT '%s' ==> '%s'"%(old, new)
  return states, names

def conquest(states, names):
  if len(states) > 1:
    loser = random.choice(states)
    states.remove(loser)
    winner = random.choice(states)
    if dot:
      print '"%s" -> "%s" [label="conquered by"]'%(loser, winner)
    else:
      print "CONQUEST '%s' conquered '%s'"%(winner, loser)
  return states, names


#ignore empty names
names = [name for name in names if name] #yes, really.

origin = random.sample(names, random.randint(1,3))
names = list(set(names).difference(set(origin)))
history.append(origin) #random starting states

if dot:
  print "digraph g {"
  print "{rank=same; %s}"%("; ".join(map(wrap,origin)))
else:
  print("BEGIN %s"%(", ".join(map(wrap,history[0]))))

while names:
  func = random.choice([merge, split, revolt, conquest])
  states, names = func(history[-1], names)
  history.append(states)

if dot:
  print '{rank=same; %s}'%("; ".join(map(wrap,history[-1])))
  print "}"
else:
  print "END %s"%(", ".join(map(wrap,history[-1])))

Bunun gibi çıktı üreten:

enter image description here

Farklı grafikleri oluşturmak için sezgisel bilgileri ayarlayın.

Bunu yapmanın en basit yolu func = random.choice([merge, split, revolt, conquest]), aynı ismin birden fazla fonksiyonuna sahip olması için hattı değiştirmek olacaktır . Örneğin func = random.choice([merge, split, revolt, conquest, merge, merge])milletlerin daha sık birleşmesine yol açacaktır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.