มีวิธีในการสร้างประวัติศาสตร์ของโลกแบบเป็นขั้นตอนหรือไม่?


28

ฉันค่อนข้างทึ่งกับแผนภาพที่พบที่นี่ซึ่งแสดงถึงประวัติศาสตร์ทางวัฒนธรรมที่ยาวนานถึง 1,800 ปีในโลกจินตนาการที่ผู้ชายบางคนสร้างขึ้น

ป้อนคำอธิบายรูปภาพที่นี่

สิ่งนี้ดูเหมือนว่าจะมีแอพพลิเคชั่นที่แข็งแกร่งสำหรับการพัฒนาเกมตราบเท่าที่การออกแบบระดับโลก

ดูเหมือนว่าเขาทำแผนภาพนี้ด้วยมือ สิ่งที่ฉันสนใจคือการดูว่ามีวิธีในการสร้างแผนภาพประเภทนี้แบบเป็นโปรแกรมหรือไม่

หากคุณได้รับมอบหมายให้สร้างไดอะแกรมในรูปแบบข้างต้นจากค่าสุ่มคุณจะทำอย่างไร มีโครงสร้างข้อมูลหรืออัลกอริทึมเฉพาะที่คุณต้องการพิจารณาหรือไม่?


5
พิจารณาดูที่ป้อมแคระ แหล่งข้อมูลไม่พร้อมใช้งานและกระบวนการสร้างโลกไม่มีเอกสาร (ซึ่งฉันทำไมฉันไม่ตอบคำถามนี้) แต่คุณสามารถตรวจสอบประวัติโลกที่สร้างขึ้นโดยไม่ต้องเรียนรู้ที่จะเล่นเกมจริง ๆ และอาจทำให้คุณมีความคิด ในสิ่งที่คุณสามารถทำได้
Josh

ทรัพยากรอื่นและไม่ใช่คำตอบอาจพบได้ที่: www-cs-students.stanford.edu/~amitp/game-programming/นี่เป็นบทความสำหรับการสร้างสภาพแวดล้อม แต่มันจะไปสัมผัสกับสภาพแวดล้อมที่สามารถ ใช้เพื่อกำหนดขอบเขตของภูมิภาคสำหรับอาณาจักรบนพื้นฐานของทรัพยากร (เช่นน้ำดินแดนที่น่าอยู่ ฯลฯ ) ที่อาจถูกโยนลงไปผสมเมื่อผู้คนเข้าสู่สงครามเหนือสิ่งที่และที่ไหนหรือชอบ .. อีกครั้งเพียงแค่ทรัพยากรไม่ใช่คำตอบ
James

1
แผนภาพนี้มีลักษณะคล้ายกับกราฟพลังงานในอารยธรรม 3 คุณอาจต้องการดูซีรี่ส์สำหรับแนวคิดบางอย่าง
WildWeazel

คำตอบ:


15

คุณต้องการแม่นยำแค่ไหน? ทางเลือกที่ดี แต่ซับซ้อนจะเป็นการจำลองประวัติศาสตร์ทั้งหมด:

  1. สร้างรายการภูมิภาคแบบสุ่มและ adjacencies ระหว่างภูมิภาคเหล่านี้
  2. สร้างอารยธรรมสุ่มที่มีลักษณะเช่นประชากรสงครามและเทคโนโลยี ... และเติมภูมิภาค
  3. จำลองประวัติศาสตร์เป็นเวลาหลายปีตามที่คุณต้องการโดยพิจารณาผลลัพธ์ตามลักษณะอารยธรรม

เช่นอารยธรรมคู่สงครามที่อยู่ติดกันมีความน่าจะเป็นสูงในการเริ่มสงครามซึ่งกันและกันซึ่งนำไปสู่การลดจำนวนประชากรในช่วงเวลาหนึ่ง อารยธรรมผู้ค้ามีทรัพยากรที่สูงกว่า แต่เป็นเป้าหมายที่ยอดเยี่ยมสำหรับการรุกราน คนที่มีประชากรสูงจะเติบโตเร็วขึ้น แต่ก็มีโอกาสหิวมาก วัฒนธรรม - ต่างกัน civs มีโอกาสน้อยกว่าในสงครามภายใน (ซึ่งอาจนำไปสู่การสลาย) และอื่น ๆ ... ผลลัพธ์ก็จะปรับเปลี่ยนลักษณะอารยธรรม: เทคโนโลยีที่สูงกว่านำไปสู่การซื้อขายที่ดีกว่าอาวุธที่แข็งแกร่ง ฯลฯ

วิธีนี้ช่วยให้การเล่านิทานเกี่ยวกับขั้นตอนบางอย่างเกินไป: คุณสามารถส่งออกไม่เพียง แต่แผนภาพอาณาเขต แต่ยังอธิบายรายละเอียดเกี่ยวกับใจความของประวัติศาสตร์ตลอดเวลา คุณสามารถทำให้ระบบนี้ซับซ้อนตามที่คุณต้องการ


แก้ไข:ความท้าทายที่นี่ไม่ใช่เรื่องทางเทคนิค แต่เป็นการปรับฮิวริสติกสำหรับการสร้างประวัติศาสตร์ที่สมจริงและน่าสนใจ ลองมองให้ใกล้ขึ้นและคิดถึงจุดที่กล่าวถึง 3 ข้อ ... นั่นเป็นคำอธิบายทางเทคนิคของคุณ! แปลเป็นลูป (การวนซ้ำแต่ละครั้งสามารถแทนเวลาได้มากเท่าที่คุณต้องการ 1 ปีครึ่งปี 1 เดือน ... ) และนั่นก็คือ คุณจะต้องทำงานกับผู้ที่อยู่ภายใน (โครงสร้างข้อมูลการวิเคราะห์พฤติกรรม) และปรับให้เข้ากับปัญหาและความต้องการเฉพาะของคุณ นั่นเป็นส่วนที่ยากที่นี่และไม่มีใครสามารถช่วยคุณได้เพราะมันเกี่ยวกับจินตนาการการลองผิดลองถูก

ไม่มีโครงสร้างข้อมูลทั่วไปสำหรับปัญหานี้นอกจากสิ่งที่คุณจะใช้สำหรับเกือบทุกปัญหา: รายการคิวต้นไม้ ... และสิ่งเหล่านี้จะถูกผูกไว้สำหรับการใช้งานเฉพาะของคุณ(ฉันต้องการต้นไม้ลำดับวงศ์ตระกูลหรือไม่รายการอารยธรรม เมื่ออยู่ในสงครามคิวงานสำหรับแต่ละเมือง?)แน่นอนว่าคุณต้องการรายชื่ออารยธรรมด้วย ตัวเลือกนั้นชัดเจนและสามัญสำนึกมาก

การจำลองเป็นเรื่องของโอกาส / ความน่าจะเป็นและคุณสามารถสร้างได้หลายวิธีด้วยตัวเลขสุ่ม ลองนึกถึงเกมอื่น ๆ ที่การจำลองมีส่วนเกี่ยวข้องเช่นผู้จัดการฟุตบอล, เกม RPG (หลังจากทั้งหมด, hitpoints / stats เป็นเพียงการต่อสู้แบบจำลอง ), เกมกลยุทธ์ ... มันเป็นลักษณะเฉพาะ (ดังนั้นคุณจะต้องมีวิธีเก็บคุณสมบัติและข้อมูลอารยธรรม) และสุ่มผลลัพธ์ขึ้นอยู่กับสถิติ (ดังนั้นคุณจะต้องเปลี่ยนสถานะการจำลองตามลักษณะเหล่านี้)

นั่นคือสาระสำคัญของอัลกอริทึมของคุณ: ยากต่อการปรับฮิวริสติก: การกระจายลักษณะเฉพาะที่จุดเริ่มต้นของการจำลองสำหรับแต่ละอารยธรรมและวิธีการเปลี่ยนสถานะการจำลองตามสถิติ

กล่าวโดยย่อ:อัลกอริธึมของคุณเป็นเพียงการวนรอบที่ใช้เวลาจำลองกับการเพิ่มขึ้นที่ต้องการ การเพิ่มที่สั้นลงนำไปสู่การจำลองประวัติศาสตร์ที่ละเอียดยิ่งขึ้น แต่จะใช้เวลานานขึ้นอย่างเห็นได้ชัด ภายในลูปของคุณจะมีฮิวริสติกมากมาย (ประมาณ):

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()

หลังจากงานนี้ทั้งหมด (หรือระหว่างนั้นหากคุณไม่ต้องการจัดเก็บข้อมูล) คุณต้องตีความสถานะการจำลองทั้งหมดเป็นรูปแบบที่มนุษย์อ่านได้เช่นข้อความรูปภาพหรือสิ่งที่คุณต้องการ นี่คือการลองผิดลองถูกและเฉพาะเจาะจงมากสำหรับการติดตั้งของคุณ

คำถามของคุณโดยเฉพาะ:ในการสร้างไดอะแกรมเช่นเดียวกับคำถามของคุณคุณจะต้องติดตามภูมิภาคโลก (ด้านบนของแผนภาพแกน x นั่นคือจุดที่ 1: สร้างรายการภูมิภาคในคำตอบของฉัน) และอารยธรรมของพวกเขา แผนภาพจุดที่ 2 ) เวลา (แกน y วงวนการจำลองในจุดที่ 3 )

เครื่องรัฐค่อนข้างดีในการจำลองหัวข้อคร่าว ๆ (ตัวอย่างโค้ดข้างต้นเป็นการประมาณค่าของเครื่องสถานะแบบตายตัว) - ดังนั้นคุณอาจเริ่มต้นด้วยการใช้กรอบงานเครื่องรัฐแบบง่าย ๆ ซึ่งง่ายต่อการปรับแต่ง แต่ละอารยธรรมจะเริ่มต้นด้วยหนึ่งในเครื่องจักรของรัฐเหล่านี้และการจำลองจะใช้เครื่องของรัฐในแต่ละรอบ กลไกของรัฐแต่ละรัฐจะต้องสามารถโต้ตอบกับกลไกรัฐอื่น ๆ ได้ตัวอย่างเช่นการเริ่มต้นสงครามจะส่งผลกระทบต่อกลไกรัฐของพลเรือนอื่นอาจมีผลลัพธ์ที่แตกต่างกันตามสถานะภายในของพวกเขาเช่นถ้าพวกเขาอยู่ในสถานะ ต้องการเจรจาสันติภาพ แต่อารยธรรม 'มองหาปัญหา' น่าจะตอบโต้ แต่ละรัฐในเครื่องจะมีผลกระทบที่มีความหมายต่ออารยธรรม ' ตัวชี้วัดที่ระบุไว้ด้านบนในระหว่าง 'เฟรม' แต่ละอัน (ความมั่งคั่งการทำสงครามประชาชน ฯลฯ ) สิ่งสำคัญที่สุดคือคุณไม่จำเป็นต้องเปลี่ยนสถานะในทุก ๆ เฟรม - เมื่อมีโอกาสและ / หรือโอกาสสุ่มเกิดขึ้น: สิ่งนี้ช่วยให้เหตุการณ์ที่ยืดเยื้อ (เช่นสงคราม) เกิดขึ้น


ขอบคุณสำหรับคำตอบที่ดีมากแม้ว่ามันจะไม่ได้สัมผัสกับประเด็นทางเทคนิคที่ฉันกังวล
pdusen

@pdusen ความคิดเห็นค่อนข้างยาวดังนั้นฉันจึงอัปเดตคำตอบของฉันภายใต้เครื่องหมาย "แก้ไข"
kaoD

2
ฉันจะเพิ่มคำตอบนี้ถ้าคุณไม่รังเกียจ
Jonathan Dickinson

@ JonathanDickinson แน่นอนเอาเลย :)
kaoD

@pdusen ฉันเพิ่มรายละเอียดเฉพาะของการติดตั้งเพิ่มเติม
Jonathan Dickinson

8

ใช่แล้ว นี่คือเครื่องกำเนิดประวัติศาสตร์ที่เรียบง่าย:

#!/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])))

ซึ่งผลิตผลลัพธ์เช่นนี้

ป้อนคำอธิบายรูปภาพที่นี่

ปรับฮิวริสติกเพื่อสร้างกราฟที่แตกต่างกัน

วิธีที่ง่ายที่สุดในการทำเช่นนี้คือการเปลี่ยนfunc = random.choice([merge, split, revolt, conquest])บรรทัดให้มีฟังก์ชันมากกว่าหนึ่งฟังก์ชันในชื่อเดียวกัน ตัวอย่างเช่นfunc = random.choice([merge, split, revolt, conquest, merge, merge])จะนำไปสู่การรวมประชาชาติบ่อยขึ้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.