main.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. #!/usr/bin/python3
  2. import os, sys
  3. import json
  4. import random
  5. from PyQt5.QtWidgets import QApplication, QWidget, QMessageBox
  6. from PyQt5.QtCore import Qt
  7. from PyQt5.QtGui import QPixmap, QIcon
  8. from PyQt5 import uic
  9. from enum import Enum
  10. os.environ['QT_STYLE_OVERRIDE'] = 'fusion'
  11. main_dir = os.path.abspath(__file__)[:-7]
  12. os.chdir(main_dir)
  13. class releaseData(Enum):
  14. VERSION = '0.1.1'
  15. PRODUCT_NAME = 'Count!'
  16. DEVELOPER = 'thm'
  17. EMAIL = 'highsierra.2007@mail.ru'
  18. WEBSITE = 'https://thm-unix.github.io/'
  19. class App(QWidget):
  20. def __init__(self):
  21. super().__init__()
  22. self.readConfig('config.json')
  23. self.prepareUI()
  24. self.setContextMenuActions()
  25. self.setPushButtonsActions()
  26. self.setOtherActions()
  27. self.setLocaleStrings()
  28. def readConfig(self, configPath):
  29. with open(configPath, 'r') as configReader:
  30. self.config = json.load(configReader)
  31. def prepareUI(self):
  32. # load UI
  33. self.window = uic.loadUi('ui/main.ui')
  34. self.settings = uic.loadUi('ui/settings.ui')
  35. self.about = uic.loadUi('ui/about.ui')
  36. # set style
  37. if self.config['theme'] == 'dark':
  38. stylesheetReader = open('styles/dark.qss')
  39. else:
  40. stylesheetReader = open('styles/light.qss')
  41. self.stylesheet = stylesheetReader.read()
  42. stylesheetReader.close()
  43. self.window.setStyleSheet(self.stylesheet)
  44. self.settings.setStyleSheet(self.stylesheet)
  45. self.about.setStyleSheet(self.stylesheet)
  46. # set locale
  47. localePath = 'locales/' + self.config['locale'] + '.json'
  48. with open(localePath, 'r') as localeReader:
  49. self.localeStrings = json.load(localeReader)
  50. # hide all objects for now
  51. self.window.questionLabel.hide()
  52. self.window.answerTextEdit.hide()
  53. self.window.skipPushButton.hide()
  54. self.window.submitPushButton.hide()
  55. self.window.statusLabel.setText('Ready')
  56. # set icon of application
  57. # does it even work?
  58. self.window.setWindowIcon(QIcon('assets/icon.png'))
  59. self.settings.setWindowIcon(QIcon('assets/icon.png'))
  60. self.about.setWindowIcon(QIcon('assets/icon.png'))
  61. self.about.iconLabel.setPixmap(QPixmap('assets/icon.png'))
  62. # set version
  63. self.about.softwareNameLabel.setText(releaseData.PRODUCT_NAME.value)
  64. self.about.versionLabel.setText('v.' + releaseData.VERSION.value)
  65. self.about.developerNameLabel.setText(self.localeStrings['wasBroughtToYou'] + releaseData.DEVELOPER.value)
  66. self.about.developerEmailLabel.setText(releaseData.EMAIL.value)
  67. self.about.developerWebsiteLabel.setText(releaseData.WEBSITE.value)
  68. # show UI
  69. self.window.show()
  70. def setLocaleStrings(self):
  71. self.window.menuFile.setTitle(self.localeStrings['menuFile'])
  72. self.window.newGameAction.setText(self.localeStrings['newGameAction'])
  73. self.window.settingsAction.setText(self.localeStrings['settingsAction'])
  74. self.window.exitAction.setText(self.localeStrings['exitAction'])
  75. self.window.menuInformation.setTitle(self.localeStrings['menuInformation'])
  76. self.window.aboutAction.setText(self.localeStrings['aboutAction'])
  77. self.window.answerTextEdit.setPlaceholderText(self.localeStrings['answerTextEdit'])
  78. self.window.statusLabel.setText(self.localeStrings['statusLabel_ready'])
  79. self.window.skipPushButton.setText(self.localeStrings['skipPushButton'])
  80. self.window.submitPushButton.setText(self.localeStrings['submitPushButton'])
  81. self.settings.languageGroupBox.setTitle(self.localeStrings['languageGroupBox'])
  82. self.settings.themeGroupBox.setTitle(self.localeStrings['themeGroupBox'])
  83. self.settings.lightRadioButton.setText(self.localeStrings['lightRadioButton'])
  84. self.settings.darkRadioButton.setText(self.localeStrings['darkRadioButton'])
  85. self.settings.difficultyGroupBox.setTitle(self.localeStrings['difficultyGroupBox'])
  86. self.settings.easyRadioButton.setText(self.localeStrings['easyRadioButton'])
  87. self.settings.mediumRadioButton.setText(self.localeStrings['mediumRadioButton'])
  88. self.settings.hardRadioButton.setText(self.localeStrings['hardRadioButton'])
  89. self.settings.tasksAmountGroupBox.setTitle(self.localeStrings['tasksAmountGroupBox'])
  90. self.settings.cancelPushButton.setText(self.localeStrings['cancelPushButton'])
  91. self.settings.savePushButton.setText(self.localeStrings['savePushButton'])
  92. def quit(self):
  93. exit()
  94. def generateRandomTask(self, difficulty):
  95. if difficulty == 1:
  96. operands = ['+', '-']
  97. numbers = [i for i in range(0, 30)]
  98. randomA = numbers[random.randint(0, len(numbers)-1)]
  99. randomB = numbers[random.randint(0, len(numbers)-1)]
  100. randomOperand = random.randint(0, 1)
  101. return (randomA, operands[randomOperand], randomB)
  102. elif difficulty == 2:
  103. operands = ['+', '-', '*', '/']
  104. numbersGeneral = [i for i in range(0, 70)]
  105. numbersMultiply = [i for i in range(2, 10)]
  106. numbersDivision = [i for i in range(1, 50)]
  107. self.randomOperand = random.randint(0, 3)
  108. if self.randomOperand in range(0,2):
  109. self.randomA = numbersGeneral[random.randint(0, len(numbersGeneral)-1)]
  110. self.randomB = numbersGeneral[random.randint(0, len(numbersGeneral)-1)]
  111. elif self.randomOperand == 2:
  112. self.randomA = numbersMultiply[random.randint(0, len(numbersMultiply)-1)]
  113. self.randomB = numbersMultiply[random.randint(0, len(numbersMultiply)-1)]
  114. elif self.randomOperand == 3:
  115. self.randomA = numbersDivision[random.randint(0, len(numbersDivision)-1)]
  116. self.randomB = numbersDivision[random.randint(0, len(numbersDivision)-1)]
  117. while self.randomA % self.randomB != 0 or self.randomA == self.randomB:
  118. self.randomA = numbersDivision[random.randint(0, len(numbersDivision)-1)]
  119. self.randomB = numbersDivision[random.randint(0, len(numbersDivision)-1)]
  120. return (self.randomA, operands[self.randomOperand], self.randomB)
  121. elif difficulty == 3:
  122. operands = ['+', '-', '*', '/', '^']
  123. numbers = [i for i in range(20, 100)]
  124. numbersPow = [i for i in range(2, 6)]
  125. self.randomOperand = random.randint(0, 4)
  126. if self.randomOperand in range(0,3):
  127. self.randomA = numbers[random.randint(0, len(numbers)-1)]
  128. self.randomB = numbers[random.randint(0, len(numbers)-1)]
  129. elif self.randomOperand == 3:
  130. self.randomA = numbers[random.randint(0, len(numbers)-1)]
  131. self.randomB = numbers[random.randint(0, len(numbers)-1)]
  132. while self.randomA % self.randomB != 0 or self.randomA == self.randomB:
  133. self.randomA = numbers[random.randint(0, len(numbers)-1)]
  134. self.randomB = numbers[random.randint(0, len(numbers)-1)]
  135. elif self.randomOperand == 4:
  136. self.randomA = numbersPow[random.randint(0, len(numbersPow)-1)]
  137. self.randomB = numbersPow[random.randint(0, len(numbersPow)-1)]
  138. return (self.randomA, operands[self.randomOperand], self.randomB)
  139. def showNewTask(self):
  140. # self.window.statusLabel.setText('Generating new task...')
  141. self.myTask = self.generateRandomTask(self.config['difficulty'])
  142. self.taskShownInUI = str(self.myTask[0]) + ' ' + str(self.myTask[1]) + ' ' + \
  143. str(self.myTask[2]) + ' = ?'
  144. self.window.questionLabel.setText(self.taskShownInUI)
  145. # self.window.statusLabel.setText('Waiting for answer...')
  146. self.tasksShownCount += 1
  147. def newGame(self):
  148. self.tasksShownCount = 0
  149. self.correctTasksCount = 0
  150. self.window.questionLabel.show()
  151. self.window.answerTextEdit.show()
  152. self.window.skipPushButton.show()
  153. self.window.submitPushButton.show()
  154. self.window.statusLabel.setText(self.localeStrings['statusLabel_start'])
  155. self.showNewTask()
  156. def openSettingsWindow(self):
  157. self.settings.show()
  158. # set switches in current position
  159. if self.config['locale'] == 'us':
  160. self.settings.englishRadioButton.toggle()
  161. elif self.config['locale'] == 'ru':
  162. self.settings.russianRadioButton.toggle()
  163. if self.config['theme'] == 'dark':
  164. self.settings.darkRadioButton.toggle()
  165. else:
  166. self.settings.lightRadioButton.toggle()
  167. if self.config['difficulty'] == 1:
  168. self.settings.easyRadioButton.toggle()
  169. elif self.config['difficulty'] == 2:
  170. self.settings.mediumRadioButton.toggle()
  171. elif self.config['difficulty'] == 3:
  172. self.settings.hardRadioButton.toggle()
  173. self.settings.tasksDial.setValue(self.config['tasks'])
  174. self.settings.tasksLCD.display(self.config['tasks'])
  175. def changeLCDValue(self, value):
  176. self.settings.tasksLCD.display(value)
  177. def saveSettingsToConfig(self):
  178. self._locale,self._theme,self._difficulty,self._tasks = '','',0,0
  179. if self.settings.englishRadioButton.isChecked():
  180. self._locale = 'us'
  181. elif self.settings.russianRadioButton.isChecked():
  182. self._locale = 'ru'
  183. self._theme = 'dark' if self.settings.darkRadioButton.isChecked() else 'light'
  184. if self.settings.easyRadioButton.isChecked():
  185. self._difficulty = 1
  186. elif self.settings.mediumRadioButton.isChecked():
  187. self._difficulty = 2
  188. elif self.settings.hardRadioButton.isChecked():
  189. self._difficulty = 3
  190. self._tasks = self.settings.tasksDial.value()
  191. configData = {
  192. 'difficulty': self._difficulty,
  193. 'tasks': self._tasks,
  194. 'theme': self._theme,
  195. 'locale': self._locale
  196. }
  197. with open('config.json', 'w') as configWriter:
  198. json.dump(configData, configWriter)
  199. QMessageBox.information(self, self.localeStrings['informationTitle'], \
  200. self.localeStrings['restartCountMessage'], QMessageBox.Ok)
  201. exit()
  202. def showResults(self):
  203. QMessageBox.information(self, self.localeStrings['informationTitle'], \
  204. self.localeStrings['solvedMessage'] + str(self.correctTasksCount) + '/' + \
  205. str(self.tasksShownCount), QMessageBox.Ok)
  206. self.window.answerTextEdit.clear()
  207. self.window.questionLabel.hide()
  208. self.window.answerTextEdit.hide()
  209. self.window.skipPushButton.hide()
  210. self.window.submitPushButton.hide()
  211. self.window.statusLabel.setText('Ready')
  212. def skipTask(self):
  213. if self.tasksShownCount < self.config['tasks']:
  214. self.showNewTask()
  215. else:
  216. self.showResults()
  217. def checkAnswer(self, userAnswer, task):
  218. correctString = self.localeStrings['statusLabel_correct']
  219. incorrectString = self.localeStrings['statusLabel_incorrect']
  220. a = self.myTask[0]
  221. operand = self.myTask[1]
  222. b = self.myTask[2]
  223. if operand == '+':
  224. if userAnswer == str(a + b):
  225. self.correctTasksCount += 1
  226. if self.tasksShownCount < self.config['tasks']:
  227. self.window.statusLabel.setText(correctString)
  228. self.showNewTask()
  229. self.window.answerTextEdit.clear()
  230. else:
  231. self.showResults()
  232. else:
  233. if self.tasksShownCount < self.config['tasks']:
  234. self.window.statusLabel.setText(incorrectString)
  235. self.showNewTask()
  236. self.window.answerTextEdit.clear()
  237. else:
  238. self.showResults()
  239. elif operand == '-':
  240. if userAnswer == str(a - b):
  241. self.correctTasksCount += 1
  242. if self.tasksShownCount < self.config['tasks']:
  243. self.window.statusLabel.setText(correctString)
  244. self.showNewTask()
  245. self.window.answerTextEdit.clear()
  246. else:
  247. self.showResults()
  248. else:
  249. if self.tasksShownCount < self.config['tasks']:
  250. self.window.statusLabel.setText(incorrectString)
  251. self.showNewTask()
  252. self.window.answerTextEdit.clear()
  253. else:
  254. self.showResults()
  255. elif operand == '*':
  256. if userAnswer == str(a * b):
  257. self.correctTasksCount += 1
  258. if self.tasksShownCount < self.config['tasks']:
  259. self.window.statusLabel.setText(correctString)
  260. self.showNewTask()
  261. self.window.answerTextEdit.clear()
  262. else:
  263. self.showResults()
  264. else:
  265. if self.tasksShownCount < self.config['tasks']:
  266. self.window.statusLabel.setText(incorrectString)
  267. self.showNewTask()
  268. self.window.answerTextEdit.clear()
  269. else:
  270. self.showResults()
  271. elif operand == '/':
  272. if userAnswer == str(a // b):
  273. self.correctTasksCount += 1
  274. if self.tasksShownCount < self.config['tasks']:
  275. self.window.statusLabel.setText(correctString)
  276. self.showNewTask()
  277. self.window.answerTextEdit.clear()
  278. else:
  279. self.showResults()
  280. else:
  281. if self.tasksShownCount < self.config['tasks']:
  282. self.window.statusLabel.setText(incorrectString)
  283. self.showNewTask()
  284. self.window.answerTextEdit.clear()
  285. else:
  286. self.showResults()
  287. elif operand == '^':
  288. if userAnswer == str(a ** b):
  289. self.correctTasksCount += 1
  290. if self.tasksShownCount < self.config['tasks']:
  291. self.window.statusLabel.setText(correctString)
  292. self.showNewTask()
  293. self.window.answerTextEdit.clear()
  294. else:
  295. self.showResults()
  296. else:
  297. if self.tasksShownCount < self.config['tasks']:
  298. self.window.statusLabel.setText(incorrectString)
  299. self.showNewTask()
  300. self.window.answerTextEdit.clear()
  301. else:
  302. self.showResults()
  303. def setContextMenuActions(self):
  304. self.window.exitAction.triggered.connect(lambda:self.quit())
  305. self.window.newGameAction.triggered.connect(lambda:self.newGame())
  306. self.window.settingsAction.triggered.connect(
  307. lambda:self.openSettingsWindow())
  308. self.window.aboutAction.triggered.connect(
  309. lambda:self.about.show())
  310. def setPushButtonsActions(self):
  311. self.window.submitPushButton.clicked.connect(lambda:self.checkAnswer(
  312. self.window.answerTextEdit.toPlainText(), self.myTask))
  313. self.window.skipPushButton.clicked.connect(lambda:self.skipTask())
  314. self.settings.cancelPushButton.clicked.connect(lambda:self.settings.hide())
  315. self.settings.savePushButton.clicked.connect(lambda:self.saveSettingsToConfig())
  316. def setOtherActions(self):
  317. self.settings.tasksDial.valueChanged.connect(
  318. lambda:self.changeLCDValue(
  319. self.settings.tasksDial.value()))
  320. if __name__ == '__main__':
  321. app = QApplication(sys.argv)
  322. ex = App()
  323. app.exec_()