Funktionierender Prototyp des Serious Games zur Vermittlung von Wissen zu Software-Engineering-Arbeitsmodellen.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

game.py 10KB

1 year ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. from django.db import models
  2. from .names import WorkerNames, OrderNames
  3. from .timer import Timer
  4. from .timer import Timer
  5. from .company import Company
  6. from .order import Order
  7. # from .action import Action
  8. from .offer import Offer
  9. from ..initialdatabase import InitialDatabase
  10. from .engineeringmodel import (
  11. ModelChaotic,
  12. ModelScrum,
  13. ModelSpiral,
  14. ModelV,
  15. ModelWaterfall,
  16. ModelHeyJoe,
  17. )
  18. # Spielklasse kontrollier das gamegeschehen
  19. class Game(models.Model):
  20. name = models.CharField(default="Game", max_length=20)
  21. gamemaster = models.CharField(max_length=20)
  22. running = models.BooleanField(default=False)
  23. participants = models.ManyToManyField(Company)
  24. maxRounds = models.IntegerField(default=10)
  25. currentRound = models.IntegerField(default=1)
  26. ordermarket = models.ManyToManyField(Order)
  27. actionpool = models.ManyToManyField("Action")
  28. timer = models.ForeignKey(Timer, default=1, on_delete=models.CASCADE)
  29. acceptedOffers = models.ManyToManyField(Offer, blank=True)
  30. ordermarketsize = models.IntegerField(default=5)
  31. def __str__(self):
  32. return self.name
  33. # Standard Datenbankeinträge generieren die hart codiert sind (in initialdatabase.py)
  34. def initializeDatabase(self):
  35. data = InitialDatabase()
  36. self.createWorkernames(data)
  37. self.createOrdernames(data)
  38. self.createEngineeringmodels(data)
  39. def createWorkernames(self, data):
  40. for name in data.workernames:
  41. WorkerNames.objects.get_or_create(name=name)
  42. def createOrdernames(self, data):
  43. for name in data.ordernames:
  44. OrderNames.objects.get_or_create(name=name)
  45. def createEngineeringmodels(self, data):
  46. ModelV.objects.get_or_create(
  47. name=data.engineeringmodelnames[0],
  48. description=data.engineeringmodeldescription[0],
  49. pros=data.engineeringmodelprocon[0][0],
  50. cons=data.engineeringmodelprocon[0][1],
  51. )
  52. ModelSpiral.objects.get_or_create(
  53. name=data.engineeringmodelnames[1],
  54. description=data.engineeringmodeldescription[1],
  55. pros=data.engineeringmodelprocon[1][0],
  56. cons=data.engineeringmodelprocon[1][1],
  57. )
  58. ModelWaterfall.objects.get_or_create(
  59. name=data.engineeringmodelnames[2],
  60. description=data.engineeringmodeldescription[2],
  61. pros=data.engineeringmodelprocon[2][0],
  62. cons=data.engineeringmodelprocon[2][1],
  63. )
  64. ModelScrum.objects.get_or_create(
  65. name=data.engineeringmodelnames[3],
  66. description=data.engineeringmodeldescription[3],
  67. pros=data.engineeringmodelprocon[3][0],
  68. cons=data.engineeringmodelprocon[3][1],
  69. )
  70. ModelChaotic.objects.get_or_create(
  71. name=data.engineeringmodelnames[4],
  72. description=data.engineeringmodeldescription[4],
  73. pros=data.engineeringmodelprocon[4][0],
  74. cons=data.engineeringmodelprocon[4][1],
  75. )
  76. ModelHeyJoe.objects.get_or_create(
  77. name=data.engineeringmodelnames[5],
  78. description=data.engineeringmodeldescription[5],
  79. pros=data.engineeringmodelprocon[5][0],
  80. cons=data.engineeringmodelprocon[5][1],
  81. )
  82. # -----------------------------------------------------------------------------------
  83. # Bearbeitung des Gameablaufs mit diesen Funktionen kontrollieren:
  84. def startGame(self):
  85. # klarmachen dass workernames ordernames engineeringmodels und spezialorders
  86. # alle definiert sind -> sonst datenbankeinträge generieren
  87. self.setDefault()
  88. self.initializeDatabase()
  89. # spiel auf running stellen
  90. self.running = True
  91. self.save()
  92. # runde starten
  93. self.startRound()
  94. # timer starten
  95. self.runTimer()
  96. def setDefault(self):
  97. self.currentRound = 1
  98. self.save()
  99. for company in self.participants.all():
  100. for worker in company.workers.all():
  101. worker.delete()
  102. for order in company.orders.all():
  103. order.delete()
  104. company.money = 300000
  105. company.customersatisfaction = 100
  106. company.workersatisfaction = 100
  107. company.save()
  108. def endGame(self):
  109. # game running False stellen
  110. self.running = False
  111. self.save()
  112. def startRound(self):
  113. # ordermarket generieren
  114. self.generateOrdermarket()
  115. # companys ihren workermarket generieren lassen
  116. self.generateWorkermarket()
  117. def processGameround(self):
  118. # events von LETZTER RUNDE clearen()
  119. self.clearEvents()
  120. # arbeiter bezahlen
  121. self.paySalary()
  122. # schauen ob worker quittet (zufällig mit steigender wahrscheinlichkeit je niedriger)
  123. self.checkWorkerQuit()
  124. # companyOrder verbleibende Workload neu berechnen
  125. self.calculateOrderWorkload()
  126. # alle Aktionen ausführen und clearen
  127. self.executeActions()
  128. # Krankheit zufällig generieren
  129. self.calculateSick()
  130. # unlock locked workers wenn countdown auf 0; dann zähle countdown runter
  131. self.countdownLockedWorkers()
  132. # recalculate der models auf orders anwenden
  133. self.modelsRecalculateOrders()
  134. # SpecialOrders passieren lassen()
  135. self.specialordersOccure()
  136. # beste offer für jede order auf ordermarket rausfinden
  137. self.calculateBestOffers()
  138. # offers an beste berechnete company verteilen
  139. self.distributeBestOffers()
  140. # passive regeln anpassen
  141. self.passiveGamerules()
  142. # checken ob es letzte runde ist
  143. gameend = self.checkLastRound()
  144. # runde hochzählen
  145. self.increaseRound()
  146. # nächste Runde starten
  147. self.startRound()
  148. # gameende signalisieren
  149. return gameend
  150. # -----------------------------------------------------------------------------------
  151. def passiveGamerules(self):
  152. for company in self.participants.all():
  153. company.calculateWorkerSatisfaction(2)
  154. company.calculateCustomerSatisfaction(2)
  155. for worker in company.workers.all():
  156. worker.calculateHappyness(1)
  157. # Spielexecution Funktionen die Funktionen zur Spielkontorlle implementieren
  158. # adde 5 elemente zu ordermarket
  159. def generateOrdermarket(self):
  160. self.clearOrdermarket()
  161. for x in range(self.ordermarketsize):
  162. order = Order.createRandom()
  163. self.addOrder(order)
  164. def generateWorkermarket(self):
  165. for company in self.participants.all():
  166. company.generateWorkermarket()
  167. def clearParticipants(self, username):
  168. for player in self.participants.all():
  169. # alle comapnys ausser gamemaster company kicken
  170. if not (player.user == username):
  171. self.participants.remove(player)
  172. def clearEvents(self):
  173. for company in self.participants.all():
  174. company.clearEvents()
  175. def callbackTimerCompleted(self):
  176. gameend = self.processGameround()
  177. if gameend:
  178. self.timer.stop()
  179. def runTimer(self):
  180. self.timer.start(callback=self.callbackTimerCompleted)
  181. def getRemainingTimer(self):
  182. return self.timer.remainingtimer
  183. def checkWorkerQuit(self):
  184. for company in self.participants.all():
  185. company.checkWorkerQuit()
  186. def countdownLockedWorkers(self):
  187. for company in self.participants.all():
  188. for worker in company.workers.all():
  189. # unlocken wenn locked und countdown = 0 und setze sick false
  190. if worker.lockedRounds <= 0 and worker.status == 3:
  191. worker.setStatus(1)
  192. worker.setSick(False)
  193. # countdown lockedRounds wenn größer 0
  194. elif worker.lockedRounds > 0:
  195. rounds = worker.lockedRounds - 1
  196. worker.setLockedRounds(rounds)
  197. def calculateSick(self):
  198. for company in self.participants.all():
  199. for worker in company.workers.all():
  200. worker.calculateSick()
  201. def executeActions(self):
  202. for company in self.participants.all():
  203. for action in company.actions.all():
  204. action.execute()
  205. for action in company.actions.all():
  206. action.delete()
  207. def calculateOrderWorkload(self):
  208. for company in self.participants.all():
  209. company.calculateOrderWorkload()
  210. def calculateBestOffers(self):
  211. for order in self.ordermarket.all():
  212. bestoffer = order.calculateBestOffer()
  213. self.acceptedOffers.add(bestoffer)
  214. def modelsRecalculateOrders(self):
  215. for company in self.participants.all():
  216. for order in company.orders.all():
  217. order.recalculate(company)
  218. def distributeBestOffers(self):
  219. for acceptedoffer in self.acceptedOffers.all():
  220. acceptedoffer.order.setStatus(1)
  221. self.ordermarket.remove(acceptedoffer.order)
  222. acceptedoffer.company.addOrder(acceptedoffer.order)
  223. acceptedoffer.offerAcceptedEvent()
  224. # offers deleten da nicht mehr gebraucht
  225. acceptedoffer.delete()
  226. def specialordersOccure(self):
  227. for company in self.participants.all():
  228. for order in company.orders.all():
  229. order.specialorder.occure(company=company)
  230. def increaseRound(self):
  231. self.currentRound += 1
  232. self.save()
  233. def checkLastRound(self):
  234. if self.maxRounds <= self.currentRound:
  235. self.endGame() # beende spiel
  236. return True
  237. return False
  238. def addOrder(self, order):
  239. self.ordermarket.add(order)
  240. def removeOrder(self, order):
  241. self.ordermarket.remove(order)
  242. def clearOrdermarket(self):
  243. for order in self.ordermarket.all():
  244. if order.status == 0:
  245. order.delete()
  246. self.ordermarket.clear()
  247. def paySalary(self):
  248. for company in self.participants.all():
  249. company.paySalary()
  250. def createLeaderboard(self):
  251. tuples = []
  252. for company in self.participants.all():
  253. tuples.append((company.money, company))
  254. tuples = sorted(tuples, key=lambda x: x[0], reverse=True)
  255. # companys aus den tuples ziehen
  256. leaderboard = []
  257. i = 1
  258. for element in tuples:
  259. leaderboard.append((i, element[1]))
  260. i = i + 1
  261. return leaderboard