1
0

cgame.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. #!/usr/bin/env python
  2. """
  3. Carcassonne score keeping system.
  4. """
  5. import re as _re
  6. import sys as _sys
  7. from datetime import datetime as _datetime
  8. import numpy as _np
  9. class cgame:
  10. """
  11. Carcassonne game object
  12. """
  13. def __init__(self):
  14. """
  15. Initialize some variables and set up a game
  16. """
  17. self.commands = [('n', 'next round'),
  18. ('r', 'record score and advance turn'),
  19. ('t', 'advance turn, no score'),
  20. ('b', 'additional turn for a player due to a builder'),
  21. ('e', 'end game (or play if already in postgame scoring'),
  22. ('s', '(current) score and game status'),
  23. ('?', 'print help')]
  24. setupGame()
  25. def showCommands(self):
  26. """
  27. Print out a list of valid commands for in-game play.
  28. """
  29. _sys.stderr.write('Possible commands:\n')
  30. for entry in self.commands:
  31. _sys.stderr.write('\t' + entry[0] + ': ' + entry[1] + '\n')
  32. def setupGame(self):
  33. """
  34. Initialize a game
  35. """
  36. # check to see if there's a game which has not yet been finished (i.e., has a starttime but no endtime). If there is, resume it. Otherwise:
  37. # generate a new game ID and enter a start time
  38. # get a list of players (from database list)
  39. # have user input which expansions are being used
  40. time = _datetime.utcnow().strftime("%Y-%m-%dT%H:%M")
  41. # insert this into the database
  42. # general information
  43. self.gameID =
  44. # array of tuples with playerID and name from DB
  45. self.players =
  46. self.expansionIDs =
  47. # game state information
  48. self.state = 0 # 0 for main game, 1 for postgame, 2 for ended game
  49. self.ntile = 1 # number of tiles played
  50. self.nbuilder = 0 # number of tiles placed due to builders
  51. def recordScore(gameID, playerIDs, expansionIDs, cround, state):
  52. """
  53. Record a score event in the game
  54. """
  55. if state:
  56. ingame = 0
  57. pname = getPlayerNames(playerIDs)
  58. # for i, pname in enumerate(pname):
  59. pID = input("")
  60. # if the builder was used
  61. BUILDERUSED = True
  62. advanceTurn(cmdtime, gameID, playerID, nturn, builder=BUILDERUSED)
  63. return 0
  64. def advanceTurn(self, builder=False):
  65. """
  66. Make a new entry in the turns table
  67. """
  68. command = '''INSERT INTO turns VALUES ({0:d}, {1:d}, '''.format(self.gameID, self.nturn)
  69. command = command + cmdtime
  70. if builder:
  71. bID = 1
  72. else:
  73. bID = 0
  74. # compute playerID based on the turn number minus nbuilders / number of players
  75. playerID = playerIDs[(nturns - nbuilder) / lnen(playerIDs)]
  76. command = command + ', {0:d}, {1:d})'.format(bID, playerID)
  77. c.execute(command)
  78. self.nturn += 1
  79. if builder:
  80. self.nbuilder += 1
  81. def runGame(self):
  82. """
  83. Main routine for entering games
  84. """
  85. # here wait for input for scores, advancing to next round, or completion of game
  86. # for each step of entry, present a series of options, based on the list
  87. # of playerIDs and expansions
  88. while self.state < 2:
  89. # set up prompt based on current round
  90. if self.state:
  91. prompt = "postgame > "
  92. else:
  93. prompt = "round: {0:d}, turn: {1:d} > ".format(1 + _np.floor((self.nturn-self.nbuilder) / len(self.playerIDs)),
  94. self.nturn-self.nbuilder)
  95. try:
  96. text = input(prompt)
  97. except (EOFError, KeyboardInterrupt):
  98. _sys.stderr.write('Improper input. Please retry\n')
  99. showCommands()
  100. if _re.match('e', cmd, _re.IGNORECASE):
  101. advanceState()
  102. elif _re.match('s', cmd, _re.IGNORECASE):
  103. printStatus(tilestats=True)
  104. elif _re.match('n', cmd, _re.IGNORECASE):
  105. advanceTurn()
  106. elif _re.match('r', cmd, _re.IGNORECASE):
  107. recordScore()
  108. elif _re.match('t', cmd, _re.IGNORECASE):
  109. advanceTurn(builder=False)
  110. elif _re.match('b', cmd, _re.IGNORECASE):
  111. advanceTurn(builder=True)
  112. elif _re.match('?'. cmd, _re.IGNORECASE):
  113. showCommands()
  114. else:
  115. _sys.stderr.write('Command not understood. Please try again.\n')
  116. showCommands()
  117. if state == 2:
  118. #game is over. write end time to the games table
  119. time = _datetime.utcnow().strftime("%Y-%m-%dT%H:%M")
  120. c.execute('''UPDATE games SET endtime = "''' + time + '''" WHERE gameID = ''' + str(gameID))
  121. conn.commit()
  122. printStatus(tilestats=False)
  123. #### Is there a way to capture "ineffective" uses? For example,
  124. #### meeples that don't score points because they end up in a meadow that's
  125. #### controled by someone else?
  126. return 0
  127. def printStatus(self, tilestats=False):
  128. """
  129. Print the total score (current or final) for the specified gameID
  130. """
  131. for playerID in self.playerIDs:
  132. pname = c.execute('SELECT name FROM players WHERE playerID={0:d}'.format(playerID[0])).fetchall()[0]
  133. a = c.execute('SELECT points FROM scores WHER gameID={0:d} and playerID={1:d}'.format(self.gameID, playerID[0]))
  134. res = a.fetchall()
  135. score = _np.sum(res)
  136. print(pname + ': {0:d}'.format(score))
  137. print("{0:d} tiles played out of {1:d} total ({2:d} remaining).".format(self.ntiles,
  138. self.totaltiles,
  139. self.totaltiles - self.ntiles)