diff --git a/README.md b/README.md index 10a3436..20c40e1 100644 --- a/README.md +++ b/README.md @@ -1,34 +1,34 @@ -# Version 0.9 Beta -Тестовая версия для GNU Linux и OS Windows (x64).
-Для запуска программы требуется **python 3.6+**!!!
-В релизных версиях есть файл для запуска с консолью (для отладки) и стандартный файл
-Код писался под **OS Windows x64**, однако, в теории код работает и с GNU Linux, однако, автор **не гарантирует** 100% работу под Linux. -## Советы для работы с ядром -**Не запускайте скомпилированное ядро!! это может привести к некорректной работе игры!!!**
-Ниже приведён пример конфигурационного файла ядра. -```json - { - "pythonRun": true, # Запуск ядра при помощи python - "pythonPath_win32": "python ", # Путь к python на OS Windows x64 - "pythonPath_unix": "python3 ", # Путь к python на GNU Linux - "max_responseTime": 15, # Время ожидания отклика ядра (сек) - "core_file": "gamecore.py", # Файл ядра - "log_enable": false # Включить логгирование - } -``` -## Методы ядра -Запросы принимаются через файл **gamestat.json** -```json -{ - "status": "method" # Метод - "request": [] # Тело запроса -} -``` -После выполнения запроса, ядро высылает ответ в файле **response.json** -```json -{ - "response": [] # Тело ответа - "response_randomID": [] # random ID -} -``` -Подробнее читайте в документации. +# Version 0.9 Beta +Тестовая версия для GNU Linux и OS Windows (x64).
+Для запуска программы требуется **python 3.6+**!!!
+В релизных версиях есть файл для запуска с консолью (для отладки) и стандартный файл
+Код писался под **OS Windows x64**, однако, в теории код работает и с GNU Linux, однако, автор **не гарантирует** 100% работу под Linux. +## Советы для работы с ядром +**Не запускайте скомпилированное ядро!! это может привести к некорректной работе игры!!!**
+Ниже приведён пример конфигурационного файла ядра. +```json + { + "pythonRun": true, # Запуск ядра при помощи python + "pythonPath_win32": "python ", # Путь к python на OS Windows x64 + "pythonPath_unix": "python3 ", # Путь к python на GNU Linux + "max_responseTime": 15, # Время ожидания отклика ядра (сек) + "core_file": "gamecore.py", # Файл ядра + "log_enable": false # Включить логгирование + } +``` +## Методы ядра +Запросы принимаются через файл **gamestat.json** +```json +{ + "status": "method" # Метод + "request": [] # Тело запроса +} +``` +После выполнения запроса, ядро высылает ответ в файле **response.json** +```json +{ + "response": [] # Тело ответа + "response_randomID": [] # random ID +} +``` +Подробнее читайте в документации. diff --git a/SQLEasy.py b/SQLEasy.py new file mode 100644 index 0000000..f349ecb --- /dev/null +++ b/SQLEasy.py @@ -0,0 +1,192 @@ +import sqlite3 + + +class SQLiteEasyException(Exception): + pass + + +def compareKey(DBlist, key, type_of_key=lambda x: x): + if not(type(DBlist) is list): + raise SQLiteEasyException(f"function compareKey need List object, unsupported type: {type(DBlist)}") + + if len(DBlist) > 0: + if key not in DBlist[0]: + raise SQLiteEasyException(f"key '{key}' not founded.") + DB_Dictonary = dict() + for BD in sorted(DBlist, key=lambda List: List[key]): + comparedBD = dict() + for Key in BD: + if not(Key == key): + comparedBD[Key] = BD[Key] + DB_Dictonary[type_of_key(BD[key])] = comparedBD + + return DB_Dictonary + + +class database: + def dict_factory(self, cursor, row): + dictDB = {} + for idx, col in enumerate(cursor.description): + dictDB[col[0]] = row[idx] + return dictDB + + def encodeSQLiteType(self, objectum, all_as_str=False): + if type(objectum) is str: + return "'%s'" % objectum.replace('\'', '\\\'') + elif objectum is None and all_as_str: + return "''" + elif objectum is None: + return 'NULL' + elif type(objectum) is bool and objectum and all_as_str: + return "'TRUE'" + elif type(objectum) is bool and objectum: + return 'TRUE' + elif type(objectum) is bool and not(objectum) and all_as_str: + return "'FALSE'" + elif type(objectum) is bool and not(objectum): + return 'FALSE' + elif all_as_str and True in [type(objectum) is int, type(objectum) is float]: + return "'%s'" % objectum + elif not(all_as_str) and True in [type(objectum) is int, type(objectum) is float]: + return objectum + else: + raise SQLiteEasyException(f"Unsupported type: {type(objectum)}") + + def __init__(self, PATH, DatabaseName=None): + self.ConnectedFile = sqlite3.connect(PATH) + self.databaseChoosed = DatabaseName + self.ConnectedFile.row_factory = self.dict_factory + self.act_commit = True + + def toggleCommit(self, value=None): + if value in (False, True): + self.act_commit = value + else: + if self.act_commit: + self.act_commit = False + else: + self.act_commit = True + + def commit(self): + self.ConnectedFile.commit() + + def getBase(self, DatabaseName=None, elementsFromDB='*'): + elementsFromDB = str(elementsFromDB) + if DatabaseName is None and self.databaseChoosed is None: + raise SQLiteEasyException("Database is not choosed") + elif DatabaseName is None and not(self.databaseChoosed is None): + dbCursore = self.ConnectedFile.cursor() + dbCursore.execute(f"select {elementsFromDB} from {self.databaseChoosed}") + return dbCursore.fetchall() + else: + dbCursore = self.ConnectedFile.cursor() + dbCursore.execute(f"select {elementsFromDB} from {DatabaseName}") + self.databaseChoosed = DatabaseName + return dbCursore.fetchall() + + def pop(self, key, value, DatabaseName=None): + if type(value) is str: + value = f"'%s'" % value.replace('\'', '\\\'') + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + dbCursore = self.ConnectedFile.cursor() + dbCursore.execute('DELETE FROM %s\n\nWHERE %s == %s;' % (DatabaseName, key, value)) + if self.act_commit: + self.ConnectedFile.commit() + + def setItem(self, key, newValue, indexKey, value, DatabaseName=None): + newValue = self.encodeSQLiteType(newValue) + value = self.encodeSQLiteType(value) + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + dbCursore = self.ConnectedFile.cursor() + if value is None: + dbCursore.execute('UPDATE %s SET %s = %s WHERE %s is NULL;' % (DatabaseName, key, newValue, indexKey)) + else: + dbCursore.execute('UPDATE %s SET %s = %s WHERE %s = %s;' % (DatabaseName, key, newValue, indexKey, value)) + if self.act_commit: + self.ConnectedFile.commit() + + def add(self, values, DatabaseName=None): + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + + keys = [str(key) for key in values] + values = [self.encodeSQLiteType(values[key], all_as_str=True) for key in values] + + dbCursore = self.ConnectedFile.cursor() + dbCursore.execute('INSERT INTO %s (%s) VALUES (%s)' % (DatabaseName, ', '.join(keys), ', '.join(values))) + if self.act_commit: + self.ConnectedFile.commit() + + def uploadFiles(self, binary, DatabaseName=None): # Uwaga! Может работать с ошибками. + if not(type(binary) is bytes or type(binary) is bytearray): + raise SQLiteEasyException('You can upload only byte or bytearray types!!') + dbCursore = self.ConnectedFile.cursor() + binary = sqlite3.Binary(binary) + + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + # (!) Дописать + + def chooseDataBase(self, DatabaseName): + self.getBase(DatabaseName) + self.databaseChoosed = DatabaseName + + def currentIndex(self, key, value, DatabaseName=None): + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + + DB = self.getBase(DatabaseName) + + ID = 0 + for Dictonary in sorted(DB, key=lambda dictonary: dictonary[key]): + if Dictonary[key] == value: + return ID + ID += 1 + + def currentValue(self, key, value, DatabaseName=None): + if DatabaseName is None and not(self.databaseChoosed is None): + DatabaseName = self.databaseChoosed + elif DatabaseName is None: + raise SQLiteEasyException("Database is not choosed") + + DB = self.getBase(DatabaseName) + + for Dictonary in sorted(DB, key=lambda dictonary: dictonary[key]): + if Dictonary[key] == value: + return Dictonary + + def getTables(self): + dbCursore = self.ConnectedFile.cursor() + dbCursore.execute('SELECT name from sqlite_master where type= "table"') + return [item['name'] for item in dbCursore.fetchall()] + + def getDict(self): + dictonary = dict() + tables = self.getTables() + for table in tables: + dictonary[table] = self.getBase(table) + return dictonary + + +def formingTable(dictonary, path): + pass # В разработке \ No newline at end of file diff --git a/Theory/scheme.png b/Theory/scheme.png new file mode 100644 index 0000000..fd7dc80 Binary files /dev/null and b/Theory/scheme.png differ diff --git a/Theory/scheme_noBg.png b/Theory/scheme_noBg.png new file mode 100644 index 0000000..57da036 Binary files /dev/null and b/Theory/scheme_noBg.png differ diff --git a/corelib.py b/corelib.py new file mode 100644 index 0000000..3453c62 --- /dev/null +++ b/corelib.py @@ -0,0 +1,168 @@ +import os, sys, json + +import threading, Gamecore.guiDrawWaiting +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtWidgets import * +from PyQt5.Qt import * + +with open('Gamecore/config.json', 'r', encoding='utf-8') as cfg: + cfg = json.loads(cfg.read()) + +if cfg["pythonRun"]: + if sys.platform == 'win32': + runCoreApp = cfg["pythonPath_win32"] + else: + runCoreApp = cfg["pythonPath_unix"] +else: + if sys.platform == 'win32': + runCoreApp = 'start ' + else: + runCoreApp = './' + + +class tool: + def __init__(self): + def showGUI(): + class coreGUI(threading.Thread): + def run(self): + class app_win(QMainWindow): + def __init__(self): + super(app_win, self).__init__() + self.ui = Gamecore.guiDrawWaiting.Ui_Form() + self.ui.setupUi(self) + self.show() + + self.app = QApplication([]) + self.application = app_win() + self.app.exec() + + def stop(self): + self.application.hide() + del self + + thrObj = coreGUI() + thrObj.start() + return thrObj + + def noneGUI(*args, **kwargs): + pass + + def stopGUI(thrObj): + thrObj.stop() + + self.showGUI = showGUI + self.noneGUI = noneGUI + self.stopGUI = stopGUI + + self.wait = self.noneGUI + self.resp = self.noneGUI + + def showGUI_wait(self, show=True): + if show: + print('WARNING! You will be using GUI corelib!!!') + self.wait = self.showGUI + self.resp = self.stopGUI + else: + self.wait = self.noneGUI + self.resp = self.noneGUI + + def response(self, resp): + waitObj = self.wait() + + respf = open('Gamecore/gamestat.json', 'wt', encoding='utf-8') + respf.write(json.dumps(resp, indent="\t", ensure_ascii=False)) + respf.close() + + shellScript = open('runCore.sh', 'wt', encoding='utf-8') + print(f"cd Gamecore\n{runCoreApp}{cfg['core_file']}") + shellScript.write(f"cd Gamecore\n{runCoreApp}{cfg['core_file']}") + shellScript.close() + if sys.platform != 'win32': + os.system("./runCore.sh") + else: + os.system("runCore.sh") + + output = open('Gamecore/response.json', 'r', encoding='utf-8') + outp = output.read() + output.close() + + returnObj = json.loads(outp) + self.resp(waitObj) + return returnObj + + +tool = tool() + + +def newGame(ID, mines=25, fieldsize=10): + return tool.response({ + "status": "newGame", + "request": { + "ID": ID, + "Mines": mines, + "size": fieldsize + } + }) + + +def openItem(gamesession, X, Y): + return tool.response({ + "status": "openItem", + "request": { + "gamesession": gamesession, + "X": X, + "Y": Y + } + }) + + +def getGameSession(gamesession): + return tool.response({ + "status": "getGameSession", + "request": { + "gamesession": gamesession + } + }) + + +def toggleFlag(gamesession, X, Y): + return tool.response({ + "status": "toggleFlag", + "request": { + "gamesession": gamesession, + "X": X, + "Y": Y + } + }) + + +class Method: + def __init__(self, method, **kwargs): + self.method = method + self.kwargs = kwargs + + def start(self): + return eval(self.method)(**kwargs) + + +class multiMethod: + def __init__(self, *methods): + self.methods = list(methods) + + def append(self, method): + self.methods.append(method) + + def pop(self, index): + self.methods.pop(index) + + def __len__(self): + return len(self.methods) + + def start(self): + request = {"status": 'multiMethod', 'requests': list()} + for method in self.methods: + request['requests'].append({ + "status": method.method, + "request": method.kwargs + }) + return tool.response(request) \ No newline at end of file diff --git a/game.py b/game.py new file mode 100644 index 0000000..3af9e11 --- /dev/null +++ b/game.py @@ -0,0 +1,951 @@ +from PyQt5 import QtCore, QtGui, QtWidgets +from PyQt5.QtWidgets import * +from PyQt5.Qt import * +import SQLEasy, json, os, random, corelib +import launcher # Интерфейс + + +def game(gameStyle, databaseObj, gamerID, gamehash, muzicOn=True, MINES=random.randint(25, 55)): + MINES_COMPR = False + import pygame + + corelib.tool.showGUI_wait() + + databaseObj.setItem('lastGame', gameStyle, 'ID', gamerID, DatabaseName='users') + # Импорт конфига + with open(f"source/{gameStyle}/about.json", 'r', encoding='utf-8') as gameconfig: + gameconfig = json.loads(gameconfig.read()) + # Функции + + + def checkEnd(field): + endgame = True + for r in field: + for c in r: + if c in ('M:O', 'M', 'M:F'): + return True + if 'R' in c and ':O' not in c: + endgame = False + return endgame + + + def checkWin(field, endgamecheck=False): + fieldCheck = list() + endgame = True + for r in field: + for c in r: + fieldCheck.append(c) + if 'R' in c and ':O' not in c: + endgame = False + if endgamecheck: + return 'M:O' not in fieldCheck and endgame + else: + return 'M:O' not in fieldCheck + + + def compareFields(old_field, field): + if checkWin(field, True): + return + + class emptySound: + def play(self): + pass + + sounds = [ + emptySound(), + pygame.mixer.Sound(f"source/{gameStyle}/openCell.wav"), + pygame.mixer.Sound(f"source/{gameStyle}/flag.wav") + ] + + actID = 0 + + comlete = False + + for rowID in range(len(field)): + for cellID in range(len(field[rowID])): + if field[rowID][cellID] != old_field[rowID][cellID]: + if ':F' in field[rowID][cellID]: + actID = 2 + comlete = True + break + elif ':O' in field[rowID][cellID] and field[rowID][cellID] != 'M:O': + actID = 1 + comlete = True + break + if comlete: + break + + sounds[actID].play() + # Классы игровых объектов + + + class controlBanner(pygame.sprite.Sprite): + def __init__(self, X, Y, platform='XBox', info_contentID=0): + infocontent = ['openCell', 'flagCell', 'restart'] + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((228, 77)) + self.platform = platform + self.info_contentID = info_contentID + self.image = pygame.image.load(f"source/{gameStyle}/{platform}_{infocontent[info_contentID]}.png") + self.rect = self.image.get_rect() + self.rect.x = X + self.rect.y = Y + + def changePlatform(self, platform): + infocontent = ['openCell', 'flagCell', 'restart'] + self.platform = platform + self.image = pygame.image.load(f"source/{gameStyle}/{platform}_{infocontent[self.info_contentID]}.png") + + + class Border(pygame.sprite.Sprite): + def __init__(self, X, Y, borderType='Left'): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((228, 77)) + self.animationFrameTime = 0 + self.borderType = borderType + self.image = pygame.image.load(f"source/{gameStyle}/score_end{borderType}(0).png") + self.rect = self.image.get_rect() + self.rect.x = X + self.rect.y = Y + + def update(self): + self.animationFrameTime += 1 + if self.animationFrameTime >= 45: + self.animationFrameTime = 0 + self.image = pygame.image.load(f"source/{gameStyle}/score_end{self.borderType}({self.animationFrameTime // 15}).png") + + + class resetButton(pygame.sprite.Sprite): + def __init__(self, X, Y): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((228, 77)) + self.hide = 'noHover' + self.endStatus = '' + self.image = pygame.image.load(f"source/{gameStyle}/resetButton_{self.endStatus}_{self.hide}.png") + self.rect = self.image.get_rect() + self.x = X + self.y = Y + + self.rect.x = X + self.rect.y = Y + + def editCond(self, hide=None, endStatus=None): + if not(hide is None): + self.hide = hide + if not(endStatus is None): + self.endStatus = endStatus + + self.image = pygame.image.load(f"source/{gameStyle}/resetButton_{self.endStatus}_{self.hide}.png") + + def check_myself_Location(self, X, Y): + if X >= self.x and X <= self.x + 32 and Y >= self.y and Y <= self.y + 32: + return self + + + class timerCell(pygame.sprite.Sprite): + def __init__(self, X, Y, value='off'): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((228, 77)) + self.value = value + self.image = pygame.image.load(f"source/{gameStyle}/score_{value}.png") + self.rect = self.image.get_rect() + self.rect.x = X + self.rect.y = Y + + def editValue(self, value='off'): + self.value = value + self.image = pygame.image.load(f"source/{gameStyle}/score_{self.value}.png") + + def update(self): + self.image = pygame.image.load(f"source/{gameStyle}/score_{self.value}.png") + + + class tablet(pygame.sprite.Sprite): + def __init__(self, X, Y): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((228, 77)) + self.image = pygame.image.load(f"source/{gameStyle}/Tablet.png") + self.rect = self.image.get_rect() + self.rect.x = X + self.rect.y = Y + + + class fieldCursor(pygame.sprite.Sprite): + def __init__(self, X, Y): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((32, 32)) + self.image = pygame.image.load(f"source/{gameStyle}/Cursor.png") + self.cellPos = (X, Y) + self.rect = self.image.get_rect() + self.rect.x = 93 + X * 31 + self.rect.y = 133 + Y * 31 + + def setCell_coord(self, X, Y): + self.rect.x = 93 + X * 31 + self.rect.y = 133 + Y * 31 + self.cellPos = (X, Y) + + + class cell(pygame.sprite.Sprite): + def __init__(self, X, Y, coords, condition='CLOSED'): + pygame.sprite.Sprite.__init__(self) + self.image = pygame.Surface((32, 32)) + self.image = pygame.image.load(f"source/{gameStyle}/closed_cell.png") + self.rect = self.image.get_rect() + self.rect.x = X + self.rect.y = Y + self.cellPosition = { + "X": coords[0], + "Y": coords[1] + } + + self.condition = condition + self.animationFrameS = 0 + + def getCondition(self): + return self.condition + + def update(self): + if self.condition == 'CLOSED': + self.image.blit(pygame.image.load(f"source/{gameStyle}/closed_cell.png"), (0, 0)) + elif 'num_' in self.condition: + number = int(self.condition.split('_')[-1]) + self.animationFrameS += 1 + if self.animationFrameS >= 40: + self.animationFrameS = 0 + self.image.blit(pygame.image.load(f"source/{gameStyle}/mines_{number}({self.animationFrameS // 20}).png"), (0, 0)) + elif self.condition == 'OPENED': + self.animationFrameS += 1 + if self.animationFrameS >= 40: + self.animationFrameS = 0 + self.image.blit(pygame.image.load(f"source/{gameStyle}/open_cell_{self.animationFrameS // 20}.png"), (0, 0)) + elif self.condition == 'FLAG': + self.animationFrameS += 1 + if self.animationFrameS >= 40: + self.animationFrameS = 0 + self.image.blit(pygame.image.load(f"source/{gameStyle}/flag_{self.animationFrameS // 20}.png"), (0, 0)) + elif self.condition == 'BOMB': + self.animationFrameS += 1 + if self.animationFrameS >= 40: + self.animationFrameS = 0 + self.image.blit(pygame.image.load(f"source/{gameStyle}/mine_bombed({self.animationFrameS // 20}).png"), (0, 0)) + elif self.condition == 'DEFUSE': + self.animationFrameS += 1 + if self.animationFrameS >= 40: + self.animationFrameS = 0 + self.image.blit(pygame.image.load(f"source/{gameStyle}/mine_finded({self.animationFrameS // 20}).png"), (0, 0)) + + def setCondition(self, value): + self.condition = value + + + class sceneGame(pygame.sprite.Group): + def __init__(self, platform): + pygame.sprite.Group.__init__(self) + # Sounds + self.bombSound = pygame.mixer.Sound(f"source/{gameStyle}/bomb.wav") + self.winSound = pygame.mixer.Sound(f"source/{gameStyle}/win.wav") + + self.soundNotPlayed = True + + self.PLATFORM = platform + self.cells = list() + for row in range(10): + self.cells.append(list()) + for _cell in range(10): + addCell = cell(93 + _cell * 31, 133 + row * 31, (_cell, row)) + self.add(addCell) + self.cells[-1].append({ + "cellObject": addCell, + "coord_start": [93 + _cell * 31, 133 + row * 31], + "coord_last": [93 + (_cell + 1) * 31, 133 + (row + 1) * 31], + "coords_in_field": (_cell, row) + }) + self.add(tablet(130, 14)) + self.positionCursor = (0, 0) + self.cursor = fieldCursor(*self.positionCursor) + self.add(self.cursor) + self.add(Border(166, 93)) + self.timeCells = list() + for i in range(3): + timerCellObj = timerCell(198 + i * 32, 93) + self.add(timerCellObj) + self.timeCells.append(timerCellObj) + self.add(Border(294, 93, 'Right')) + self.resetButton = resetButton(228, 448) + self.add(self.resetButton) + + self.InfoTables = list() + + for i in range(3): + control_banner = controlBanner(0, 404 + i * 32, platform, i) + self.add(control_banner) + self.InfoTables.append(control_banner) + + def changePlatform(self, PLATFORM): + self.PLATFORM = PLATFORM + for tableObj in self.InfoTables: + tableObj.changePlatform(PLATFORM) + + def setScoreBoard_value(self, value=None): + if not(value is None): + value = str(value) + if len(value) == 1: + value = '00' + value + elif len(value) == 2: + value = '0' + value + + for numID in range(len(value)): + self.timeCells[numID].editValue(int(value[numID])) + else: + for cellT in self.timeCells: + cellT.editValue() + + def getCell_intoCoords(self, x, y): + for row in self.cells: + for _cell in row: + if (x >= _cell["coord_start"][0] and x <= _cell["coord_last"][0]) and (y >= _cell["coord_start"][1] and y <= _cell["coord_last"][1]): + return _cell["cellObject"] + + def cursorMove(self, x, y): + self.positionCursor = (x, y) + self.cursor.setCell_coord(x, y) + + def get_cursorPos(self): + return list(self.positionCursor) + + def updateField(self, field, gamefinished=None): + global MINES_COMPR + + listcells = list() + for r in field: + for c in r: + listcells.append(c) + if gamefinished is None: + gamefinished = 'M:O' in listcells + + for rowId in range(len(field)): + row = field[rowId] + for cellID in range(len(field[rowId])): + _cell = field[rowId][cellID] + + actCell = self.cells[rowId][cellID]["cellObject"] + if ':O' in _cell: + if not(gamefinished): + gamefinished = _cell == 'M:O' + + if _cell == 'M:O': + actCell.setCondition('BOMB') + else: + SeeUp = rowId != 0 + SeeDown = rowId != len(field) - 1 + SeeLeft = cellID != 0 + SeeRight = cellID != len(field) - 1 + + mines = 0 + frontire = False + if SeeUp: + if field[rowId - 1][cellID] in ('M', 'M:F', 'M:O'): + mines += 1 + if not(frontire): + frontire = _cell != field[rowId - 1][cellID] and ':O' not in field[rowId - 1][cellID] + if SeeDown: + if field[rowId + 1][cellID] in ('M', 'M:F', 'M:O'): + mines += 1 + if not(frontire): + frontire = _cell != field[rowId + 1][cellID] and ':O' not in field[rowId + 1][cellID] + if SeeLeft: + if field[rowId][cellID - 1] in ('M', 'M:F', 'M:O'): + mines += 1 + if not(frontire): + frontire = _cell != field[rowId][cellID - 1] and ':O' not in field[rowId][cellID - 1] + if SeeRight: + if field[rowId][cellID + 1] in ('M', 'M:F', 'M:O'): + mines += 1 + if not(frontire): + frontire = _cell != field[rowId][cellID + 1] and ':O' not in field[rowId][cellID + 1] + # Диагонали + if SeeUp and SeeLeft: + if field[rowId - 1][cellID - 1] in ('M', 'M:F', 'M:O'): + mines += 1 + if SeeUp and SeeRight: + if field[rowId - 1][cellID + 1] in ('M', 'M:F', 'M:O'): + mines += 1 + if SeeDown and SeeLeft: + if field[rowId + 1][cellID - 1] in ('M', 'M:F', 'M:O'): + mines += 1 + if SeeDown and SeeRight: + if field[rowId + 1][cellID + 1] in ('M', 'M:F', 'M:O'): + mines += 1 + + if mines > 0: + actCell.setCondition('num_%s' % mines) + elif frontire: + actCell.setCondition('num_1') + else: + actCell.setCondition('OPENED') + elif ':F' in _cell: + if gamefinished and _cell == 'M:F': + actCell.setCondition('DEFUSE') + else: + actCell.setCondition('FLAG') + else: + actCell.setCondition('CLOSED') + if not(gamefinished): + self.resetButton.editCond(endStatus='') + elif checkWin(field): + MINES_COMPR = True + self.resetButton.editCond(endStatus='win') + self.winSound.play() + minesDefused = 0 + scores = 0 + + for row in field: + for _cell in row: + if _cell == 'M:F': + minesDefused += 1 + + for row in field: + for _cell in row: + if _cell == 'M:F': + if (minesDefused // 5) ** 2 > 15: + scores += (minesDefused // 5) ** 2 > 10 + else: + scores += 15 + + databaseObj.setItem( + 'minesDefuse', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['minesDefuse'] + minesDefused, + 'ID', + gamerID, + DatabaseName='users' + ) + + databaseObj.setItem( + 'points', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['points'] + scores, + 'ID', + gamerID, + DatabaseName='users' + ) + else: + MINES_COMPR = True + self.resetButton.editCond(endStatus='lose') + self.bombSound.play() + + minesDefused = 0 + scores = 0 + + for row in field: + for _cell in row: + if _cell == 'M:F': + minesDefused += 1 + scores += 10 + + databaseObj.setItem( + 'minesDefuse', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['minesDefuse'] + minesDefused, + 'ID', + gamerID, + DatabaseName='users' + ) + + databaseObj.setItem( + 'points', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['points'] + scores, + 'ID', + gamerID, + DatabaseName='users' + ) + + + # код игры + logicGame = corelib.getGameSession(gamehash)['response'] + gamesession = logicGame["gamesession"] + field = logicGame["map"] + + if gamesession not in SQLEasy.compareKey(databaseObj.getBase('gamehashes'), 'hash'): + databaseObj.add({ + "hash": gamesession, + "userID": gamerID, + "mines": MINES, + "game": gameStyle, + "fieldJSON": json.dumps(field, indent="\t", ensure_ascii=False) + }, 'gamehashes') + + pygame.init() + + screen = pygame.display.set_mode((500, 500)) + + pygame.display.set_caption(gameconfig['title']) + pygame.display.set_icon(pygame.image.load(f"source/{gameStyle}/gameico.png")) + bg = pygame.image.load(f"source/{gameStyle}/bg.png") + screen.blit(bg, (0, 0)) + + PLATFORM = 'XBox' # (!) Сделать проверку + # Прорисовка полей + sceneGame = sceneGame(PLATFORM) + + pygame.display.flip() + + program_running = True + + cursor_moveUp = False + cursor_moveDown = False + cursor_moveLeft = False + cursor_moveRight = False + + # Muzic + pygame.mixer.music.load(f"source/{gameStyle}/muzic.wav") + if muzicOn: + pygame.mixer.music.play() + pygame.mixer.Sound(f"source/{gameStyle}/resetField.wav").play() + databaseObj.setItem( + 'games', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['games'] + 1, + 'ID', + gamerID, + DatabaseName='users' + ) + + sceneGame.updateField(field) + + while program_running: + pygame.time.Clock().tick(60) # max FPS + for event in pygame.event.get(): + if event.type == pygame.QUIT: + program_running = False + break + elif event.type == pygame.MOUSEMOTION: + POSITION = event.pos + cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1])) + + resetButtonSel = sceneGame.resetButton.check_myself_Location(int(POSITION[0]), int(POSITION[1])) + if not(cellSel is None): + sceneGame.cursorMove(cellSel.cellPosition["X"], cellSel.cellPosition["Y"]) + del POSITION, cellSel + if not(resetButtonSel is None): + resetButtonSel.editCond(hide='hover') + else: + sceneGame.resetButton.editCond(hide='noHover') + elif event.type == pygame.KEYDOWN: + cursor_moveUp = event.key == 1073741906 + cursor_moveDown = event.key == 1073741905 + cursor_moveLeft = event.key == 1073741904 + cursor_moveRight = event.key == 1073741903 + + cursor_coords = sceneGame.get_cursorPos() + if cursor_moveUp: + cursor_coords[1] -= 1 + if cursor_moveDown: + cursor_coords[1] += 1 + if cursor_moveLeft: + cursor_coords[0] -= 1 + if cursor_moveRight: + cursor_coords[0] += 1 + + if cursor_coords[0] <= -1: + cursor_coords[0] = 9 + if cursor_coords[0] >= 10: + cursor_coords[0] = 0 + if cursor_coords[1] <= -1: + cursor_coords[1] = 9 + if cursor_coords[1] >= 10: + cursor_coords[1] = 0 + + sceneGame.cursorMove(*cursor_coords) + elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: + POSITION = event.pos + cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1])) + + resetButtonSel = sceneGame.resetButton.check_myself_Location(int(POSITION[0]), int(POSITION[1])) + if not(cellSel is None): + corelib.openItem(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"]) + respObj = corelib.getGameSession(gamesession)['response'] + old_field = field + field = respObj['map'] + compareFields(old_field, field) + sceneGame.updateField(field, gamefinished=not(respObj['continue'])) + del POSITION, cellSel + if not(resetButtonSel is None): + pygame.mixer.Sound(f"source/{gameStyle}/resetField.wav").play() + MINES = random.randint(25, 55) + logicGame = corelib.newGame(gamerID, mines=MINES)['response'] + gamesession = logicGame["gamesession"] + sceneGame.updateField(logicGame["map"]) + if muzicOn: + pygame.mixer.music.play() + MINES_COMPR = False + + databaseObj.setItem( + 'games', + SQLEasy.compareKey(databaseObj.getBase('users'), 'ID')[gamerID]['games'] + 1, + 'ID', + gamerID, + DatabaseName='users') + + databaseObj.add({ + "hash": gamesession, + "userID": gamerID, + "game": gameStyle, + "mines": MINES, + "fieldJSON": json.dumps(field, indent="\t", ensure_ascii=False) + }, 'gamehashes') + elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3: + POSITION = event.pos + cellSel = sceneGame.getCell_intoCoords(int(POSITION[0]), int(POSITION[1])) + if not(cellSel is None): + if MINES > 0 and cellSel.getCondition() == 'CLOSED' and not(MINES_COMPR): + if 'response' in corelib.toggleFlag(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"]): + MINES -= 1 + respObj = corelib.getGameSession(gamesession)['response'] + old_field = field + field = respObj['map'] + compareFields(old_field, field) + sceneGame.updateField(field, gamefinished=not(respObj['continue'])) + del POSITION, cellSel + elif cellSel.getCondition() == 'FLAG' and not(MINES_COMPR): + if 'response' in corelib.toggleFlag(gamesession, X=cellSel.cellPosition["X"], Y=cellSel.cellPosition["Y"]): + MINES += 1 + respObj = corelib.getGameSession(gamesession)['response'] + old_field = field + field = respObj['map'] + compareFields(old_field, field) + sceneGame.updateField(field, gamefinished=not(respObj['continue'])) + del POSITION, cellSel + databaseObj.setItem( + 'mines', + MINES, + 'hash', + gamesession, + DatabaseName='gamehashes' + ) + + sceneGame.setScoreBoard_value(MINES) + + sceneGame.draw(screen) + sceneGame.update() + pygame.display.flip() + + pygame.quit() + + +def getGamesDict(): + listGames = dict() + for directory in [f for f in os.listdir('source') if len(f.split('.')) == 1]: + if 'about.json' in os.listdir(f"source/{directory}"): + f = open(f"source/{directory}/about.json", 'r', encoding='utf-8') + content = json.loads(f.read()) + listGames[directory] = { + "gamename": content['title'], + "path": f"source/{directory}" + } + return listGames + + +def getGameName(name): + if name in getGamesDict(): + return getGamesDict()[name]["gamename"] + else: + return 'Game not founded.' + + +class app_win(QMainWindow): + def __init__(self): + super(app_win, self).__init__() + self.ui = launcher.Ui_Form() + self.ui.setupUi(self) + + self.database = SQLEasy.database('gameDataBase.db') + + # Во-первых, наполним список игроков + self.ui.StatTable.removeRow(0) + rowPosition = 0 + for user in self.database.getBase(DatabaseName='users'): + self.ui.StatTable.insertRow(rowPosition) + self.ui.StatTable.setItem(rowPosition, 0, QTableWidgetItem(user["username"])) + self.ui.StatTable.setItem(rowPosition, 1, QTableWidgetItem(str(user["points"]))) + self.ui.StatTable.setItem(rowPosition, 2, QTableWidgetItem(str(user["minesDefuse"]))) + if user["games"] != 0: + st = str(user["minesDefuse"] // user["games"]) + else: + st = '0' + self.ui.StatTable.setItem(rowPosition, 3, QTableWidgetItem(st)) + self.ui.StatTable.setItem(rowPosition, 4, QTableWidgetItem(getGameName(user["lastGame"]))) + + rowPosition += 1 + self.ui.usernamesList.clear() + self.accs = list() + for user in self.database.getBase(DatabaseName='users'): # Обновляем во вкладке Профили + self.ui.usernamesList.addItem(user["username"]) + self.accs.append(user) + + # Заполним список вариаций сапёра + self.ui.gameList.clear() + for gameDir in getGamesDict(): + item = QtWidgets.QListWidgetItem(getGamesDict()[gameDir]['gamename']) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(f"source/{gameDir}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + item.setIcon(icon1) + self.ui.gameList.addItem(item) + + self.show() + + self.ui.usernamesList.doubleClicked.connect(self.importLogin) + self.ui.regButton.clicked.connect(self.register) + self.ui.loginButton.clicked.connect(self.logIn) + self.ui.play.clicked.connect(self.play) + self.ui.logOut.clicked.connect(self.logOut) + self.ui.updateGames.clicked.connect(self.upDate_sapers) + self.ui.loadGame.clicked.connect(self.LoadGame) + # Список сохранений... + self.ui.SaveList.clear() + self.savedGames = list() + + multiMethod = corelib.multiMethod() + + for save in self.database.getBase('gamehashes'): + if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']: + multiMethod.append(corelib.Method('getGameSession', gamesession=save['hash'])) + + resp = multiMethod.start()['responses'] + respID = -1 + + for save in self.database.getBase('gamehashes'): + if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']: + respID += 1 + if 'response' in resp[respID]: + if resp[respID]['response']['continue']: + item = QtWidgets.QListWidgetItem( + f"{getGamesDict()[save['game']]['gamename']}, мин: {save['mines']}" + ) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(f"source/{save['game']}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + item.setIcon(icon1) + self.ui.SaveList.addItem(item) + self.savedGames.append([ + save['hash'], + save['mines'], + save['game'] + ]) + + # Сделаем таймер + + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self.timerVoid) + self.timer.start(1) + + def upDate_sapers(self): + self.ui.gameList.clear() + for gameDir in getGamesDict(): + item = QtWidgets.QListWidgetItem(getGamesDict()[gameDir]['gamename']) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(f"source/{gameDir}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + item.setIcon(icon1) + self.ui.gameList.addItem(item) + + def logOut(self): + self.database.setItem( + 'activeprofile', + '-', + 'ID', + 1, + DatabaseName='gamedata') + self.ui.SaveList.clear() + QMessageBox.information(self, 'Успех!', 'Вы успешно вышли!!!', QMessageBox.Ok) + + def logIn(self): + if self.ui.loginUsernameLine.text() in [user['username'] for user in self.database.getBase('users')]: + if SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['password'] is None: + self.database.setItem( + 'activeprofile', + SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['ID'], + 'ID', + 1, + DatabaseName='gamedata') + QMessageBox.information(self, 'Успех!', 'Вы успешно вошли!!!', QMessageBox.Ok) + elif SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['password'] == self.ui.loginHasloLine.text(): + self.database.setItem( + 'activeprofile', + SQLEasy.compareKey(self.database.getBase('users'), key='username')[self.ui.loginUsernameLine.text()]['ID'], + 'ID', + 1, + DatabaseName='gamedata') + QMessageBox.information(self, 'Успех!', 'Вы успешно вошли!!!', QMessageBox.Ok) + else: + QMessageBox.critical(self, 'Упс...', 'Неверный пароль!', QMessageBox.Ok) + else: + QMessageBox.critical(self, 'Упс...', 'Такого пользователя просто нет :(', QMessageBox.Ok) + + self.ui.SaveList.clear() + self.savedGames = list() + + multiMethod = corelib.multiMethod() + + for save in self.database.getBase('gamehashes'): + if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']: + multiMethod.append(corelib.Method('getGameSession', gamesession=save['hash'])) + + resp = multiMethod.start()['responses'] + respID = -1 + + for save in self.database.getBase('gamehashes'): + if save['game'] in getGamesDict() and save['userID'] == self.database.getBase('gamedata')[0]['activeprofile']: + respID += 1 + if 'response' in resp[respID]: + if resp[respID]['response']['continue']: + item = QtWidgets.QListWidgetItem( + f"{getGamesDict()[save['game']]['gamename']}, мин: {save['mines']}" + ) + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(f"source/{save['game']}/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + item.setIcon(icon1) + self.ui.SaveList.addItem(item) + self.savedGames.append([ + save['hash'], + save['mines'], + save['game'] + ]) + + def register(self): + if self.ui.regLoginLine.text() in [user['username'] for user in self.database.getBase('users')]: + QMessageBox.critical(self, 'Упс...', 'Есть такой пользователь, ЕСТЬ!!!', QMessageBox.Ok) + return + if len(self.ui.regHasloLine.text()) > 0: + if len(self.ui.regHasloLine.text()) >= 65: + QMessageBox.warning(self, 'Warning!', 'Too many symbols on password!', QMessageBox.Ok) + return + + if len(self.ui.regLoginLine.text()) >= 65: + QMessageBox.warning(self, 'Warning!', 'Too many symbols on login!', QMessageBox.Ok) + return + + self.database.add({ + "ID": len(self.database.getBase('users')), + "username": self.ui.regLoginLine.text() + }, 'users') + QMessageBox.information(self, 'Успех!', 'Профиль создан!', QMessageBox.Ok) + + self.ui.usernamesList.clear() + self.accs = list() + for user in self.database.getBase(DatabaseName='users'): # Обновляем во вкладке Профили + self.ui.usernamesList.addItem(user["username"]) + self.accs.append(user) + + def importLogin(self): + if self.ui.usernamesList.currentRow() >= 0 and self.ui.usernamesList.currentRow() < len(self.ui.usernamesList): + user = self.accs[self.ui.usernamesList.currentRow()] + self.ui.loginUsernameLine.setText(user['username']) + + def LoadGame(self): + global game + + self.hide() + hashK = self.savedGames[self.ui.SaveList.currentRow()][0] + mines = self.savedGames[self.ui.SaveList.currentRow()][1] + + game( + self.savedGames[self.ui.SaveList.currentRow()][2], + gamerID=self.database.getBase('gamedata')[0]['activeprofile'], + databaseObj=self.database, + gamehash=hashK, + MINES=mines, + muzicOn=self.ui.soundOn.isChecked() + ) + os.abort() + del self + + + def play(self): + global game + + self.hide() + hashK = corelib.newGame(ID=self.database.getBase('gamedata')[0]['activeprofile'], mines=25, fieldsize=10)['response'] + mines = random.randint(25, 55) + + game( + [k for k in getGamesDict()][self.ui.gameList.currentRow()], + gamerID=self.database.getBase('gamedata')[0]['activeprofile'], + databaseObj=self.database, + gamehash=hashK['gamesession'], + MINES=mines, + muzicOn=self.ui.soundOn.isChecked() + ) + os.abort() + del self + + def timerVoid(self): + def getCoorectLogin(string): + login = '' + for symbol in string: + if symbol in '0123456789qwertyuiopasdfghjklzxcvbnm_-.' + 'qwertyuiopasdfghjklzxcvbnm'.upper(): + login += symbol + if len(login) > 64: + login = login[:64] + return login + + self.ui.play.setEnabled( + self.ui.gameList.currentRow() >= 0 and + self.ui.gameList.currentRow() < len(self.ui.gameList) and + not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-') + ) + + self.ui.logOut.setEnabled(not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-')) + self.ui.loadGame.setEnabled(len(self.ui.SaveList) > 0) + + if not(self.database.getBase('gamedata')[0]['activeprofile'] is None or self.database.getBase('gamedata')[0]['activeprofile'] == '-'): + nickname = SQLEasy.compareKey(self.database.getBase('users'), 'ID') + nickname = nickname[self.database.getBase('gamedata')[0]['activeprofile']]['username'] + self.ui.gameinfo.setText(f"Добро пожаловать, {nickname}!") + else: + self.ui.gameinfo.setText("Войдите или зарегайте профиль, чтобы играть!") + + self.ui.loginButton.setEnabled( + len(self.ui.loginUsernameLine.text()) > 8 and (len(self.ui.loginHasloLine.text()) > 8 or len(self.ui.loginHasloLine.text()) == 0) + ) + self.ui.regButton.setEnabled( + len(self.ui.regLoginLine.text()) > 8 and (len(self.ui.regHasloLine.text()) > 8 or len(self.ui.regHasloLine.text()) == 0) + ) + + if self.ui.loginUsernameLine.text() != getCoorectLogin(self.ui.loginUsernameLine.text()): + self.ui.loginUsernameLine.setText(getCoorectLogin(self.ui.loginUsernameLine.text())) + if self.ui.regLoginLine.text() != getCoorectLogin(self.ui.regLoginLine.text()): + self.ui.regLoginLine.setText(getCoorectLogin(self.ui.regLoginLine.text())) + if self.ui.loginHasloLine.text() != getCoorectLogin(self.ui.loginHasloLine.text()): + self.ui.loginHasloLine.setText(getCoorectLogin(self.ui.loginHasloLine.text())) + if self.ui.regHasloLine.text() != getCoorectLogin(self.ui.regHasloLine.text()): + self.ui.regHasloLine.setText(getCoorectLogin(self.ui.regHasloLine.text())) + + if self.ui.logPasShow.isChecked(): + self.ui.loginHasloLine.setEchoMode(QtWidgets.QLineEdit.Normal) + else: + self.ui.loginHasloLine.setEchoMode(QtWidgets.QLineEdit.Password) + + if self.ui.regPasShow.isChecked(): + self.ui.regHasloLine.setEchoMode(QtWidgets.QLineEdit.Normal) + else: + self.ui.regHasloLine.setEchoMode(QtWidgets.QLineEdit.Password) + + # Запрещаем редактировать стату + self.ui.StatTable.setRowCount(0) + rowPosition = 0 + for user in sorted(self.database.getBase(DatabaseName='users'), key=lambda x: x['points'], reverse=True): + self.ui.StatTable.insertRow(rowPosition) + self.ui.StatTable.setItem(rowPosition, 0, QTableWidgetItem(user["username"])) + self.ui.StatTable.setItem(rowPosition, 1, QTableWidgetItem(str(user["points"]))) + self.ui.StatTable.setItem(rowPosition, 2, QTableWidgetItem(str(user["minesDefuse"]))) + + if user["games"] != 0: + st = str(user["minesDefuse"] // user["games"]) + else: + st = '0' + self.ui.StatTable.setItem(rowPosition, 3, QTableWidgetItem(st)) + self.ui.StatTable.setItem(rowPosition, 4, QTableWidgetItem(getGameName(user["lastGame"]))) + + rowPosition += 1 + + +app = QApplication([]) +application = app_win() +app.exec() +os.abort() \ No newline at end of file diff --git a/gameDataBase.db b/gameDataBase.db new file mode 100644 index 0000000..d53e4e8 Binary files /dev/null and b/gameDataBase.db differ diff --git a/icon.ico b/icon.ico new file mode 100644 index 0000000..42325c2 Binary files /dev/null and b/icon.ico differ diff --git a/launcher.py b/launcher.py new file mode 100644 index 0000000..2c763d3 --- /dev/null +++ b/launcher.py @@ -0,0 +1,210 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'launcher.ui' +# +# Created by: PyQt5 UI code generator 5.15.1 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_Form(object): + def setupUi(self, Form): + Form.setObjectName("Form") + Form.resize(460, 341) + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap("source/gameico.ico"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + Form.setWindowIcon(icon) + self.tabWidget = QtWidgets.QTabWidget(Form) + self.tabWidget.setGeometry(QtCore.QRect(10, 10, 441, 281)) + self.tabWidget.setObjectName("tabWidget") + self.Launcher = QtWidgets.QWidget() + self.Launcher.setObjectName("Launcher") + self.gameList = QtWidgets.QListWidget(self.Launcher) + self.gameList.setGeometry(QtCore.QRect(20, 30, 391, 171)) + self.gameList.setObjectName("gameList") + item = QtWidgets.QListWidgetItem() + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap("source/sys admin/gameico.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + item.setIcon(icon1) + self.gameList.addItem(item) + self.play = QtWidgets.QPushButton(self.Launcher) + self.play.setGeometry(QtCore.QRect(180, 220, 75, 23)) + self.play.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.play.setObjectName("play") + self.soundOn = QtWidgets.QCheckBox(self.Launcher) + self.soundOn.setGeometry(QtCore.QRect(310, 230, 121, 21)) + self.soundOn.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.soundOn.setChecked(True) + self.soundOn.setObjectName("soundOn") + self.updateGames = QtWidgets.QPushButton(self.Launcher) + self.updateGames.setGeometry(QtCore.QRect(20, 210, 75, 23)) + self.updateGames.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.updateGames.setObjectName("updateGames") + self.tabWidget.addTab(self.Launcher, "") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.StatTable = QtWidgets.QTableWidget(self.tab) + self.StatTable.setGeometry(QtCore.QRect(10, 0, 421, 231)) + self.StatTable.setObjectName("StatTable") + self.StatTable.setColumnCount(5) + self.StatTable.setRowCount(1) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setVerticalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setHorizontalHeaderItem(1, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setHorizontalHeaderItem(2, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setHorizontalHeaderItem(3, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setHorizontalHeaderItem(4, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setItem(0, 0, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setItem(0, 1, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setItem(0, 2, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setItem(0, 3, item) + item = QtWidgets.QTableWidgetItem() + self.StatTable.setItem(0, 4, item) + self.tabWidget.addTab(self.tab, "") + self.saves = QtWidgets.QWidget() + self.saves.setObjectName("saves") + self.SaveList = QtWidgets.QListWidget(self.saves) + self.SaveList.setGeometry(QtCore.QRect(10, 10, 411, 211)) + self.SaveList.setObjectName("SaveList") + item = QtWidgets.QListWidgetItem() + item.setIcon(icon1) + self.SaveList.addItem(item) + self.loadGame = QtWidgets.QPushButton(self.saves) + self.loadGame.setGeometry(QtCore.QRect(10, 230, 75, 23)) + self.loadGame.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.loadGame.setObjectName("loadGame") + self.tabWidget.addTab(self.saves, "") + self.profiles = QtWidgets.QWidget() + self.profiles.setObjectName("profiles") + self.groupBox = QtWidgets.QGroupBox(self.profiles) + self.groupBox.setGeometry(QtCore.QRect(0, 10, 171, 121)) + self.groupBox.setObjectName("groupBox") + self.loginUsernameLine = QtWidgets.QLineEdit(self.groupBox) + self.loginUsernameLine.setGeometry(QtCore.QRect(10, 20, 151, 20)) + self.loginUsernameLine.setObjectName("loginUsernameLine") + self.loginHasloLine = QtWidgets.QLineEdit(self.groupBox) + self.loginHasloLine.setGeometry(QtCore.QRect(10, 50, 151, 20)) + self.loginHasloLine.setEchoMode(QtWidgets.QLineEdit.Password) + self.loginHasloLine.setObjectName("loginHasloLine") + self.loginButton = QtWidgets.QPushButton(self.groupBox) + self.loginButton.setGeometry(QtCore.QRect(90, 90, 75, 23)) + self.loginButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.loginButton.setObjectName("loginButton") + self.logPasShow = QtWidgets.QCheckBox(self.groupBox) + self.logPasShow.setGeometry(QtCore.QRect(10, 90, 70, 17)) + self.logPasShow.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.logPasShow.setObjectName("logPasShow") + self.usernamesList = QtWidgets.QListWidget(self.profiles) + self.usernamesList.setGeometry(QtCore.QRect(185, 10, 231, 201)) + self.usernamesList.setObjectName("usernamesList") + item = QtWidgets.QListWidgetItem() + self.usernamesList.addItem(item) + self.groupBox_2 = QtWidgets.QGroupBox(self.profiles) + self.groupBox_2.setGeometry(QtCore.QRect(0, 130, 171, 121)) + self.groupBox_2.setObjectName("groupBox_2") + self.regLoginLine = QtWidgets.QLineEdit(self.groupBox_2) + self.regLoginLine.setGeometry(QtCore.QRect(10, 20, 151, 20)) + self.regLoginLine.setObjectName("regLoginLine") + self.regHasloLine = QtWidgets.QLineEdit(self.groupBox_2) + self.regHasloLine.setGeometry(QtCore.QRect(10, 50, 151, 20)) + self.regHasloLine.setEchoMode(QtWidgets.QLineEdit.Password) + self.regHasloLine.setObjectName("regHasloLine") + self.regButton = QtWidgets.QPushButton(self.groupBox_2) + self.regButton.setGeometry(QtCore.QRect(90, 90, 75, 23)) + self.regButton.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.regButton.setObjectName("regButton") + self.regPasShow = QtWidgets.QCheckBox(self.groupBox_2) + self.regPasShow.setGeometry(QtCore.QRect(10, 90, 70, 17)) + self.regPasShow.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.regPasShow.setObjectName("regPasShow") + self.logOut = QtWidgets.QPushButton(self.profiles) + self.logOut.setEnabled(False) + self.logOut.setGeometry(QtCore.QRect(330, 230, 75, 23)) + self.logOut.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) + self.logOut.setObjectName("logOut") + self.tabWidget.addTab(self.profiles, "") + self.gameinfo = QtWidgets.QLabel(Form) + self.gameinfo.setGeometry(QtCore.QRect(20, 300, 411, 31)) + self.gameinfo.setObjectName("gameinfo") + + self.retranslateUi(Form) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(Form) + + def retranslateUi(self, Form): + _translate = QtCore.QCoreApplication.translate + Form.setWindowTitle(_translate("Form", "Сапёр игровой лаунчер")) + __sortingEnabled = self.gameList.isSortingEnabled() + self.gameList.setSortingEnabled(False) + item = self.gameList.item(0) + item.setText(_translate("Form", "Системный администратор")) + self.gameList.setSortingEnabled(__sortingEnabled) + self.play.setText(_translate("Form", "Играть")) + self.soundOn.setText(_translate("Form", "Включить музыку")) + self.updateGames.setText(_translate("Form", "Обновить")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.Launcher), _translate("Form", "Игра")) + item = self.StatTable.verticalHeaderItem(0) + item.setText(_translate("Form", "1")) + item = self.StatTable.horizontalHeaderItem(0) + item.setText(_translate("Form", "Никнейм")) + item = self.StatTable.horizontalHeaderItem(1) + item.setText(_translate("Form", "Очки")) + item = self.StatTable.horizontalHeaderItem(2) + item.setText(_translate("Form", "Обезврежено мин")) + item = self.StatTable.horizontalHeaderItem(3) + item.setText(_translate("Form", "Среднее количество обезвреженных мин")) + item = self.StatTable.horizontalHeaderItem(4) + item.setText(_translate("Form", "Последняя запущена игра...")) + __sortingEnabled = self.StatTable.isSortingEnabled() + self.StatTable.setSortingEnabled(False) + item = self.StatTable.item(0, 0) + item.setText(_translate("Form", "Игрок")) + item = self.StatTable.item(0, 1) + item.setText(_translate("Form", "0")) + item = self.StatTable.item(0, 2) + item.setText(_translate("Form", "0")) + item = self.StatTable.item(0, 3) + item.setText(_translate("Form", "0")) + item = self.StatTable.item(0, 4) + item.setText(_translate("Form", "0")) + self.StatTable.setSortingEnabled(__sortingEnabled) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("Form", "Статистика")) + __sortingEnabled = self.SaveList.isSortingEnabled() + self.SaveList.setSortingEnabled(False) + item = self.SaveList.item(0) + item.setText(_translate("Form", "User, 22.09.2003 14:50, Системный администратор (не закончено)")) + self.SaveList.setSortingEnabled(__sortingEnabled) + self.loadGame.setText(_translate("Form", "Загрузить")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.saves), _translate("Form", "Сохранения")) + self.groupBox.setTitle(_translate("Form", "Войти")) + self.loginUsernameLine.setPlaceholderText(_translate("Form", "Логин")) + self.loginHasloLine.setPlaceholderText(_translate("Form", "Пароль")) + self.loginButton.setText(_translate("Form", "Войти")) + self.logPasShow.setText(_translate("Form", "Показать")) + __sortingEnabled = self.usernamesList.isSortingEnabled() + self.usernamesList.setSortingEnabled(False) + item = self.usernamesList.item(0) + item.setText(_translate("Form", "Игрок")) + self.usernamesList.setSortingEnabled(__sortingEnabled) + self.groupBox_2.setTitle(_translate("Form", "Зарегистрировать профиль")) + self.regLoginLine.setPlaceholderText(_translate("Form", "Логин")) + self.regHasloLine.setPlaceholderText(_translate("Form", "Пароль")) + self.regButton.setText(_translate("Form", "Регистрация")) + self.regPasShow.setText(_translate("Form", "Показать")) + self.logOut.setText(_translate("Form", "Выйти")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.profiles), _translate("Form", "Профили")) + self.gameinfo.setText(_translate("Form", "Войдите или зарегайте профиль, чтобы играть!")) diff --git a/launcher.ui b/launcher.ui new file mode 100644 index 0000000..e0c8fd5 --- /dev/null +++ b/launcher.ui @@ -0,0 +1,421 @@ + + + Form + + + + 0 + 0 + 460 + 341 + + + + Сапёр игровой лаунчер + + + + source/gameico.icosource/gameico.ico + + + + + 10 + 10 + 441 + 281 + + + + 0 + + + + Игра + + + + + 20 + 30 + 391 + 171 + + + + + Системный администратор + + + + source/sys admin/gameico.pngsource/sys admin/gameico.png + + + + + + + 180 + 220 + 75 + 23 + + + + PointingHandCursor + + + Играть + + + + + + 310 + 230 + 121 + 21 + + + + PointingHandCursor + + + Включить музыку + + + true + + + + + + 20 + 210 + 75 + 23 + + + + PointingHandCursor + + + Обновить + + + + + + Статистика + + + + + 10 + 0 + 421 + 231 + + + + + 1 + + + + + Никнейм + + + + + Очки + + + + + Обезврежено мин + + + + + Среднее количество обезвреженных мин + + + + + Любимая игра + + + + + Игрок + + + + + 0 + + + + + 0 + + + + + 0 + + + + + 0 + + + + + + + Сохранения + + + + + 10 + 10 + 411 + 211 + + + + + User, 22.09.2003 14:50, Системный администратор (не закончено) + + + + source/sys admin/gameico.pngsource/sys admin/gameico.png + + + + + + + 10 + 230 + 75 + 23 + + + + PointingHandCursor + + + Загрузить + + + + + + Профили + + + + + 0 + 10 + 171 + 121 + + + + Войти + + + + + 10 + 20 + 151 + 20 + + + + Логин + + + + + + 10 + 50 + 151 + 20 + + + + QLineEdit::Password + + + Пароль + + + + + + 90 + 90 + 75 + 23 + + + + PointingHandCursor + + + Войти + + + + + + 10 + 90 + 70 + 17 + + + + PointingHandCursor + + + Показать + + + + + + + 185 + 10 + 231 + 201 + + + + + Игрок + + + + + + + 0 + 130 + 171 + 121 + + + + Зарегистрировать профиль + + + + + 10 + 20 + 151 + 20 + + + + Логин + + + + + + 10 + 50 + 151 + 20 + + + + QLineEdit::Password + + + Пароль + + + + + + 90 + 90 + 75 + 23 + + + + PointingHandCursor + + + Регистрация + + + + + + 10 + 90 + 70 + 17 + + + + PointingHandCursor + + + Показать + + + + + + false + + + + 330 + 230 + 75 + 23 + + + + PointingHandCursor + + + Выйти + + + + + + + + 20 + 300 + 411 + 31 + + + + Войдите или зарегайте профиль, чтобы играть! + + + + + + diff --git a/runCore.sh b/runCore.sh new file mode 100644 index 0000000..0f95607 --- /dev/null +++ b/runCore.sh @@ -0,0 +1,2 @@ +cd Gamecore +start gamecore.exe \ No newline at end of file diff --git a/testgame.py b/testgame.py new file mode 100644 index 0000000..398f964 --- /dev/null +++ b/testgame.py @@ -0,0 +1,109 @@ +import corelib, os, termcolor, colorama +colorama.init() + +clear = lambda: os.system('cls') +gamedata = corelib.newGame(ID=0, mines=25, fieldsize=10)['response'] +gamedata['continue'] = True +clear() + + +def getuserfield(field, gamefinnised=False): + maxFieldCoord = len(field) - 1 + # ░ свободная клетка + # █ Не открытая клетка + # F Помечена флагом + # 1..4 Мины рядом + # X Минa взорвана + # S Минa обезврежена + retfield = list() + for row in field: + X = field.index(row) + retfield.append(list()) + for cell in row: + Y = field[X].index(cell) + if ':O' in cell and cell != 'M:O': + mines = 0 + # Проверим наличие мин + upCoord = Y != 0 + downCoord = Y != maxFieldCoord + leftCoord = X != 0 + rightCoord = X != maxFieldCoord + + if upCoord and field[X][Y - 1] != cell and ':O' not in field[X][Y - 1]: + mines += 1 + if downCoord and field[X][Y + 1] != cell and ':O' not in field[X][Y + 1]: + mines += 1 + if leftCoord and field[X - 1][Y] != cell and ':O' not in field[X - 1][Y]: + mines += 1 + if rightCoord and field[X + 1][Y] != cell and ':O' not in field[X + 1][Y]: + mines += 1 + if mines == 0: + if upCoord and field[X][Y - 1] != cell: + mines = 1 + elif downCoord and field[X][Y + 1] != cell: + mines = 1 + elif leftCoord and field[X - 1][Y] != cell: + mines = 1 + elif rightCoord and field[X + 1][Y] != cell: + mines = 1 + + if mines == 0: + retfield[-1].append('░') + elif mines >= 3: + retfield[-1].append(termcolor.colored(f"{mines}", "red")) + elif mines == 2: + retfield[-1].append(termcolor.colored(f"{mines}", "yellow")) + elif mines == 1: + retfield[-1].append(termcolor.colored(f"{mines}", "green")) + elif cell == 'M:F': + if gamefinnised: + retfield[-1].append('S') + else: + retfield[-1].append('F') + elif ':F' in cell: + retfield[-1].append('F') + elif cell == 'M': + if gamefinnised: + retfield[-1].append('X') + else: + retfield[-1].append('█') + else: + retfield[-1].append('█') + + return retfield + + +clear() +while gamedata['continue']: + print('Y/X| 0123456789\n---|=============') + i = 0 + for row in getuserfield(gamedata['map'], gamefinnised=not(gamedata['continue'])): + print(f"{i}|. ", ''.join(row)) + i += 1 + + while True: + try: + X = int(input('Введите X: ')) + break + except: + pass + while True: + try: + Y = int(input('Введите Y: ')) + break + except: + pass + if input('Введите 0 если хотите поставить флаг: ') == '0': + corelib.toggleFlag(gamedata['gamesession'], X, Y) + else: + corelib.openItem(gamedata['gamesession'], X, Y) + + gamedata = corelib.getGameSession(gamedata['gamesession'])['response'] + clear() + +print('Y/X| 0123456789\n---|=============') +i = 0 +for row in getuserfield(gamedata['map'], gamefinnised=not(gamedata['continue'])): + print(f"{i}|. ", ''.join(row)) + i += 1 +print('Игра окончена!') \ No newline at end of file diff --git a/update.bat b/update.bat new file mode 100644 index 0000000..0c1dff0 --- /dev/null +++ b/update.bat @@ -0,0 +1,3 @@ +git add . +git commit -m "Up-Date repository" +git push \ No newline at end of file