Advertisement
Hellerick_Ferlibay

Dynasty generator

Dec 25th, 2013
1,591
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.37 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. from random import randint, random, choice
  3. from math import exp, log
  4.  
  5. # The variable 'folder' defines the directory where the program
  6. # is located. The file of the program is supposed to be named
  7. # 'Dy27u.py'.
  8.  
  9. folder = '' #'/media/ToshikHD/Dropbox/Programming/Python/Dy/'
  10.  
  11. # Its value can be changed to an empty string ('') when the
  12. # program is called from this folder.
  13. #
  14. # Within the same folder these three text files should also be
  15. # located:
  16. #
  17. # * FemaleNames.txt
  18. # * MaleNames.txt
  19. # * LastNames.txt
  20. #
  21. # They are simple list with each line containing one name. For
  22. # the files FemaleNames.txt and MaleNames.txt popularity of a
  23. # name depends on its position within the list: the earlier
  24. # names are more popular than the later names.
  25. #
  26. # After the program is run, it generates a family tree for a
  27. # royal dynasty like this:
  28. # o Edward Campbell (1053-1102) #4
  29. # ├o HENRY I Campbell (1081-1149) <1134-1149> #111
  30. # └o Edmund Campbell (1085-1135) #124
  31. #  ├o HENRY II Campbell (1111-1173) <1149-1173> #228
  32. #  └o EDWARD I Campbell (1114-1176) <1173-1176> #243
  33. #
  34. # The last number in each line is the personal id. Using the
  35. # p(id) function you get more information about any person. E.g.
  36. # if you enter 'p(243)' while being in python shell mode, it
  37. # will tell you:
  38. #
  39. # EDWARD I Campbell                 - name
  40. # m (1114-1176) <1173-1176>         - sex, life, and reign
  41. # Father: [124], Mother: [109]      - parents' IDs
  42. # Spouse(s): [274]                  - spouses' IDs
  43. # Child(ren): [437, 462, 483, 492]  - chilren's IDs
  44. # <cce>                             - dynasty code
  45. #
  46. # The dynsasty code shows the position of the person within the
  47. # dynasty. E.g. <cce> means 'fifth child of the third child of
  48. # the third person from the original generation'.
  49. #
  50. # The next variables are used to choose when the first dynasty
  51. # would be founded, in what year to stop the calculation, and
  52. # how many people there would be in the original generation.
  53.  
  54. startyear = 1066
  55. endyear = 2014
  56. persons = 64
  57.  
  58. # After one run of the program it can be called again from
  59. # the python shell with the command 'run()' -- a new family
  60. # tree will be generated.
  61.  
  62. def run():
  63.     execfile(folder+'Dy27u.py')
  64.  
  65. person = []
  66. living = set()
  67. name = [0, 0, 0]
  68. free = [set(),set()] # sets of free females; males
  69. zipfsequence = {}
  70. storksequence = {}
  71. kingnameorder = {}
  72. index = 'abcdefghijklmnopqrstuvwxyz'
  73. king = []
  74. succindex = {}
  75.  
  76. def roman(number):
  77.     rnc = {1:'I', 5:'V', 10:'X', 50:'L', 100:'C', 500:'D', 1000:'M'}
  78.     s = ''
  79.     order = 1
  80.     while number>0:
  81.         digit = number%10
  82.         number = number//10
  83.         if digit == 1:
  84.             s = rnc[order] + s
  85.         elif digit == 2:
  86.             s = rnc[order]*2 + s
  87.         elif digit == 3:
  88.             s = rnc[order]*3 + s
  89.         elif digit == 4:
  90.             s = rnc[order] + rnc[order*5] + s
  91.         elif digit == 5:
  92.             s = rnc[order*5] + s
  93.         elif digit == 6:
  94.             s = rnc[order*5] + rnc[order] + s
  95.         elif digit == 7:
  96.             s = rnc[order*5] + rnc[order]*2 + s
  97.         elif digit == 8:
  98.             s = rnc[order*5] + rnc[order]*3 + s
  99.         elif digit == 9:
  100.             s = rnc[order] + rnc[order*10] + s
  101.         order *= 10
  102.     return s
  103.  
  104. class a_person:
  105.     parent = [0, 0] # mother; father
  106.     child = []
  107.     firstname = ""
  108.     lastname = ""
  109.     gender = 0 # 0 for females, 1 for males
  110.     born = 0
  111.     died = 0
  112.     marriage = []
  113.     wealth = 0.0
  114.     rank = 0
  115.     succ = '' # successionindex
  116.  
  117. class a_marriage:
  118.     spouse = [0, 0] # wife; husband
  119.     child = []
  120.     start = startyear
  121.     end = startyear
  122.  
  123. class a_king:
  124.     person = 0
  125.     start = startyear
  126.     order = 0
  127.  
  128. class a_familytreeline:
  129.     def __init__self():
  130.         pid = 0      # Personal ID
  131.         succ = 0     # Succession code
  132.         pseudo = u'' # Tree line pseodographics
  133.         desc = ''    # Short description of the person
  134.  
  135. def loadnames():
  136.     global name
  137.     global names # number of female names, male names, last names
  138.     fileF = open(folder+'FemaleNames.txt', 'r')
  139.     fileM = open(folder+'MaleNames.txt', 'r')
  140.     fileL = open(folder+'LastNames.txt', 'r')
  141.     name = [\
  142.     ''.join(fileF.read().split('\r')).split('\n'),\
  143.     ''.join(fileM.read().split('\r')).split('\n'),\
  144.     ''.join(fileL.read().split('\r')).split('\n')]
  145.     fileF.close()
  146.     fileM.close()
  147.     fileL.close()
  148.     if name[0][-1]=='': name[0]=name[0][0:-1]
  149.     if name[1][-1]=='': name[1]=name[1][0:-1]
  150.     if name[2][-1]=='': name[2]=name[2][0:-1]
  151.     names = [len (name[0]), len (name[1]), len (name[2])]
  152.  
  153. def zipf (values):
  154.     if not (values in zipfsequence):
  155.         zipfsequence[values] = []
  156.         for i in range (values):
  157.             zipfsequence[values] += [1.0/(i+1)]
  158.             if i > 0: zipfsequence[values][i] += zipfsequence[values][i-1]
  159.         maxi = zipfsequence[values][-1]
  160.         for i in range (values):
  161.             zipfsequence[values][i] = zipfsequence[values][i] / maxi
  162.     r = random()
  163.     i = 0
  164.     while r > zipfsequence[values][i]: i += 1
  165.     return i
  166.  
  167. def spreadwealth (personid, wealth):
  168.     person[personid].wealth = wealth
  169.     children = len (person[personid].child)
  170.     if children > 0:
  171.         for i in range(children):
  172.             spreadwealth(person[personid].child[i], wealth - log(i+1))
  173.  
  174. def chooseking():
  175.     global person, king, year, kingnameorder
  176.     kingsucc = '~'
  177.     for i in living:
  178.         if (person[i].succ != '') and (person[i].succ < kingsucc) and person[i].gender != 0:
  179.             kingsucc = person[i].succ
  180.             newking = i
  181.     if not person[newking].firstname in kingnameorder:
  182.         kingnameorder[person[newking].firstname] = 1
  183.     else:
  184.         kingnameorder[person[newking].firstname] += 1
  185.     if kingsucc == '~':
  186.         print ('No royal lines left. '+str(year))
  187.     king += [a_king()]
  188.     king[-1].person = newking
  189.     king[-1].start = year
  190.     king[-1].order = kingnameorder[person[newking].firstname]
  191.     spreadwealth(newking, 0.0)
  192.     print ('NEW KING: '+str(year)+' <'+person[newking].succ+'> '+person[newking].firstname+' '+roman(kingnameorder[person[newking].firstname])+' '+person[newking].lastname+' ['+str(newking)+'] rank:'+str(person[newking].rank))
  193.  
  194. def givename (gender):
  195.     global name, names
  196.     return name [gender][zipf(names[gender])]
  197.  
  198. def createfirstgeneration():
  199.     global person, year, living, free, king, succindex
  200.     succorder = 0
  201.     for i in range(1,persons+1):
  202.         person += [a_person()]
  203.         person[i].born = startyear - randint (10, 30)
  204.         person[i].gender = randint (0, 1)
  205.         person[i].wealth = 0.0 - log(i)
  206.         person[i].lastname = name[2][randint(0,names[2]-1)]
  207.         person[i].firstname = givename(person[i].gender)
  208.         if person[i].gender == 1:
  209.             if succorder < len(index):
  210.                 person[i].succ = index[succorder]
  211.                 succindex[person[i].succ] = i
  212.             succorder += 1
  213.         living |= {i}
  214.         free[person[i].gender] |= {i}
  215.     chooseking()
  216.  
  217. def rankthemall():
  218.     global person, persons, living
  219.     for i in living:
  220.         person[i].rank = 1
  221.         for j in living:
  222.             if person[j].wealth > person[i].wealth:
  223.                 person[i].rank += 1
  224.  
  225. def try_marriage():
  226.     global free, year, person, marriage
  227.     marriage_happens = False
  228.     for m in free[1]:
  229.         for i in range (max(int(len(free[0])/person[m].rank),52)):
  230.             f = choice(list(free[0]))
  231.             if ((set(person[f].parent)&set(person[m].parent)-set([0])) == set()) and ((set([f])&set(person[m].parent)-set([0])) == set()) and ((set(person[f].parent)&set([m])-set([0])) == set()):
  232.                 wealthparity = 1.0/(((person[f].rank-person[m].rank)**2+1))**0.5
  233.                 ageparity = (1/(1+(((year-person[f].born)**0.0046-17.5**0.0046)**2+((year-person[m].born)**0.0046-22.5**0.0046)**2)*404))**650
  234.                 if random() < 0.05*wealthparity*ageparity: ## 0.05
  235.                     marriage_happens = True
  236.                     newlywed = [f, m]
  237.                     break
  238.         if marriage_happens: break
  239.     if marriage_happens:
  240.         #print ('MARRIED: '+person[m].firstname+' '+person[m].lastname+' ('+str(year-person[m].born)+') to '+person[f].firstname+' '+person[f].lastname+' ('+str(year-person[f].born)+') ('+str(person[m].rank)+'/'+str(person[f].rank)+')')
  241.         free[0] -= {newlywed[0]}
  242.         free[1] -= {newlywed[1]}
  243.         marriage += [a_marriage()]
  244.         marriage[-1].spouse = newlywed
  245.         marriage[-1].start = year
  246.         person[newlywed[0]].marriage = person[newlywed[0]].marriage + [len(marriage)-1]
  247.         person[newlywed[1]].marriage = person[newlywed[1]].marriage + [len(marriage)-1]
  248.         try_marriage()
  249.  
  250. def try_birth():
  251.     global marriage, year, storksequence, person, living, free, succindex
  252.     for m in marriage[1:]:
  253.         mothersage = year - person[m.spouse[0]].born
  254.         if mothersage > 13:
  255.             if not (mothersage in storksequence):
  256.                 storksequence[mothersage] = 0.3*exp(-((abs((abs(mothersage-14.38))**0.3865-(abs(23.35-14.38))**0.3865))**3.072))
  257.             if random() < storksequence[mothersage]:
  258.                 children = max(1, int(random()**12.4*3.6))
  259.                 for i in range (children):
  260.                     person += [a_person()]
  261.                     m.child += [len(person)-1]
  262.                     person[m.spouse[0]].child = person[m.spouse[0]].child + [len(person)-1]
  263.                     person[m.spouse[1]].child = person[m.spouse[1]].child + [len(person)-1]
  264.                     person[-1].born = year
  265.                     person[-1].gender = randint (0, 1)
  266.                     person[-1].wealth = max(person[m.spouse[0]].wealth,person[m.spouse[1]].wealth)-log(len(m.child))
  267.                     person[-1].lastname = person[m.spouse[1]].lastname
  268.                     person[-1].firstname = givename(person[-1].gender)
  269.                     person[-1].parent = [m.spouse[0],m.spouse[1]]
  270.                     living |= {len(person)-1}
  271.                     free[person[-1].gender] |= {len(person)-1}
  272.                     #print ('BORN: '+person[-1].firstname+' '+person[-1].lastname+' to '+person[m.spouse[1]].firstname+' '+person[m.spouse[1]].lastname+' and '+person[m.spouse[0]].firstname+' '+person[m.spouse[0]].lastname)
  273.                     if person[m.spouse[1]].succ != '':
  274.                         c = index[len(person[m.spouse[1]].child)-1]
  275.                         person[-1].succ = person[m.spouse[1]].succ + c
  276.                         succindex[person[-1].succ] = len(person)-1
  277.  
  278. def try_death():
  279.     global living, year, person, marriage, king
  280.     died = set()
  281.     for p in living:
  282.         age = year - person[p].born
  283.         if random() < 7.25/exp(exp(-age**2/4360.0+age/208+2.092)):
  284.             died |= {p}
  285.             person[p].died = year
  286.             if person[p].marriage != []:
  287.                 free[(person[p].gender+1)%2] |= {marriage[person[p].marriage[-1]].spouse[(person[p].gender+1)%2]}&living
  288.                 marriage[person[p].marriage[-1]].end = year
  289.             #print ('DIED: '+person[p].firstname+' '+person[p].lastname+' ('+str(year-person[p].born)+')')
  290.     living -= died
  291.     free[0] -= died
  292.     free[1] -= died
  293.     if king[-1].person in died:
  294.         chooseking()
  295.  
  296. def str0(integer):
  297.     if integer == 0:
  298.         s = ''
  299.     else:
  300.         s = str(integer)
  301.     return s
  302.  
  303. def p(pid):
  304.     global person, king
  305.     ordinal = ''
  306.     reign = ''
  307.     for i in king:
  308.         if i.person == pid:
  309.             ordinal = roman(i.order)+' '
  310.             reign = ' <' + str(i.start) + '-' + str0(person[pid].died) + '>'
  311.     print (person[pid].firstname+' '+ordinal+person[pid].lastname)
  312.     print ('fm'[person[pid].gender]+' ('+str(person[pid].born)+'-'+str0(person[pid].died)+')'+reign)
  313.     spouseset = []
  314.     for m in person[pid].marriage:
  315.         spouseset += [marriage[m].spouse[not person[pid].gender]]
  316.     print ('Father: ['+str(person[pid].parent[1])+'], Mother: ['+str(person[pid].parent[0])+']')
  317.     if spouseset != []:
  318.         print ('Spouse(s): '+str(spouseset))
  319.     if person[pid].child != []:
  320.         print ('Child(ren): '+str(person[pid].child))
  321.     print ('<'+person[pid].succ+'>')
  322.  
  323. def onelinedesc(pid):
  324.     global person, king
  325.     ordinal = ''
  326.     reign = ''
  327.     for i in king:
  328.         if i.person == pid:
  329.             ordinal = roman(i.order)+' '
  330.             reign = ' <' + str(i.start) + '-' + str0(person[pid].died) + '>'
  331.     if ordinal != '':
  332.         person[pid].firstname = person[pid].firstname.upper()
  333.     return (person[pid].firstname+' '+ordinal+person[pid].lastname+' ('+str(person[pid].born)+'-'+str0(person[pid].died)+')'+reign+' #'+str(pid))
  334.  
  335. def createtree():
  336.     global person, king
  337.     global tree, l
  338.     tree = []
  339.     for i in king:
  340.         tree += [a_familytreeline()]
  341.         tree[-1].pid = i.person
  342.         tree[-1].succ = person[i.person].succ
  343.         tree[-1].pseudo = '+'*len(tree[-1].succ)
  344.         tree[-1].desc = onelinedesc(i.person)
  345.     l = len(tree)-1
  346.     while l>0:
  347.         L = len (tree[l].succ)
  348.         if tree[l].succ[0:L-1] != tree[l-1].succ[0:L-1]:
  349.             tree = tree[:l] + [a_familytreeline()] + tree[l:]
  350.             tree[l].pid = person[tree[l+1].pid].parent[1]
  351.             tree[l].succ = person[tree[l].pid].succ
  352.             tree[l].pseudo = '+'*(len(tree[l].succ))
  353.             tree[l].desc = onelinedesc(tree[l].pid)
  354.             l += 1
  355.         l -= 1
  356.     tree[-1].pseudo = ' '*(len(tree[-1].pseudo)-1)+u'└'
  357.     for l in range (len(tree)-2,-1,-1):
  358.         if len(tree[l].pseudo) == len(tree[l+1].pseudo):
  359.             tree[l].pseudo = tree[l+1].pseudo[:-1]+u'├'
  360.         elif len(tree[l].pseudo) > len(tree[l+1].pseudo):
  361.             tree[l].pseudo = tree[l+1].pseudo[:-1]+u'│'+' '*(len(tree[l].pseudo)-len(tree[l+1].pseudo)-1)+u'└'
  362.         else:
  363.             if tree[l+1].pseudo[-2] == ' ':
  364.                 tree[l].pseudo = tree[l+1].pseudo[:-2]+u'└'
  365.             else:
  366.                 tree[l].pseudo = tree[l+1].pseudo[:-2]+u'├'
  367.     print ('\nTree:')
  368.     for i in tree:
  369.         print (i.pseudo[1:]+'o '+onelinedesc(i.pid))
  370.  
  371. # Main program
  372.  
  373. person = [a_person()] # Default person, everyone's ancestor
  374. marriage = [a_marriage()]
  375. loadnames()
  376. year = startyear
  377. createfirstgeneration()
  378. for year in range (startyear, endyear):
  379.     #print (str(year)+', pop.: '+str(len(living)))
  380.     rankthemall()
  381.     try_marriage()
  382.     try_birth()
  383.     try_death()
  384. createtree()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement