Advertisement
Guest User

battle royal

a guest
Dec 15th, 2018
213
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.53 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2.  
  3. #%%
  4. from collections import namedtuple,defaultdict
  5. from heapq import heappush,heappop
  6. from itertools import count
  7. Character=namedtuple('Character',['fraction','HP'])
  8. #%%
  9. START_HP=200
  10. ATTACK_DMG=3
  11.  
  12. #%%
  13. def getData():
  14. chars=dict()
  15. field=set()
  16. with open("/home/thoma/Documents/playground/advent15.txt","r") as f:
  17. for m,l in enumerate(f.readlines()):
  18. l=l.strip('\n')
  19. for n,c in enumerate(l):
  20. if c!="#":
  21. node=(m,n)
  22. field.add(node)
  23. if c in 'GE':
  24. chars[(m,n)]=Character(c,START_HP)
  25. return field,chars
  26. #%%
  27.  
  28. def getFracPos(frac,chars):
  29. return set(map(lambda x:x[0],filter(lambda x:x[1].fraction==frac,chars.items())))
  30.  
  31. #%%
  32. DIRECTIONS=[(-1,0),(0,-1),(0,1),(1,0)]
  33.  
  34. def getClosestEnemySpot(isGoblin,startPos,field,chars):
  35. enemies,allies='GE'
  36. if isGoblin:
  37. enemies,allies='EG'
  38. blocked=getFracPos(allies,chars)
  39. blocked.remove(startPos)
  40. enemyPos=getFracPos(enemies,chars)
  41. if len(enemyPos)==0:
  42. raise
  43. frontier=[]
  44. pred=dict()
  45. heappush(frontier,(0,startPos,startPos))
  46. while len(frontier):
  47. d,pos,oldPos=heappop(frontier)
  48. if pos in pred or pos in blocked:
  49. continue
  50. pred[pos]=oldPos
  51. m,n=pos
  52. for dm,dn in DIRECTIONS:
  53. newPos=m+dm,n+dn
  54. if newPos in enemyPos:
  55. while pred[pos]!=startPos:
  56. pos=pred[pos]
  57. return pos
  58. if newPos in field:
  59. heappush(frontier,(d+1,newPos,pos))
  60. #%%
  61.  
  62. def attackEnemy(fraction,pos,chars,power=3):
  63. px,py=pos
  64. enemies='G' if fraction=='E' else 'E'
  65. attackPower=ATTACK_DMG if fraction=='G' else power
  66. enemiesAround=[]
  67. for dx,dy in DIRECTIONS:
  68. attackPos=(px+dx,py+dy)
  69. if attackPos in chars:
  70. if chars[attackPos].fraction != enemies:
  71. continue
  72. enemiesAround.append((chars[attackPos].HP,attackPos))
  73. if not len(enemiesAround):
  74. return
  75. _,attackPos=min(enemiesAround)
  76. newHP=chars[attackPos].HP-attackPower
  77. if newHP<=0:
  78. del(chars[attackPos])
  79. else:
  80. chars[attackPos]=Character(enemies,newHP)
  81.  
  82. #%%
  83. def makeMove(pos,field,chars,power=3):
  84. ch=chars[pos]
  85. #print(ch)
  86. newPos=getClosestEnemySpot(ch.fraction=='G',pos,field,chars)
  87. if newPos:
  88. del(chars[pos])
  89. chars[newPos]=ch
  90. attackEnemy(ch.fraction,newPos,chars,power)
  91. ##%
  92. # for debugging
  93. #FX,FY=7,7
  94. #def printField(field,chars):
  95. # A=[["." for _ in range(FX)]for _ in range(FY)]
  96. # for pos,cha in chars.items():
  97. # px,py=pos
  98. # A[px][py]=cha.fraction
  99. # for a in A:
  100. # print("".join(a))
  101. #%%
  102.  
  103. def turn(chars,field,power=3):
  104. for pos in sorted(chars):
  105. if pos not in chars:
  106. continue
  107. makeMove(pos,field,chars,power)
  108.  
  109. #%%
  110. def simulate(elfAttack,part2=0):
  111. field,chars=getData()
  112. l=len(getFracPos('E',chars))
  113. for i in count():
  114. try:
  115. #print("--------")
  116. #print(i+1)
  117. turn(chars,field,elfAttack)
  118. if part2 and len(getFracPos('E',chars))<10:
  119. return -1
  120. #printField(field,chars)
  121. except:
  122. print(i*sum(map(lambda ch:ch.HP,chars.values())))
  123. break
  124. return 1
  125.  
  126.  
  127. #%%
  128. #part1
  129. simulate(3)
  130.  
  131. #%%
  132. #part2
  133. for i in range(3,1000):
  134. if simulate(i,1)==1:
  135. break
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement