cgame.py 6.6 KB

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