""" Course: Programming practice Students: Qu Qian /Tan Zhengyuan """ """ Safafi Chess Game/SFF Chess Game (Animal Chess Game) Main code for run the game it handle user input and GUI """ import colorsys import json from multiprocessing import connection import pygame as pg import sys import socket import SafariChess_backend as backend import SafariChess_AI as AI from SafariChess_Classes import Button, DropDown from threading import Thread, Lock from itertools import count, cycle import time import random #设置棋盘的参数 WIDTH = 1000 HEIGHT = 800 BOARD_WIDTH = 800 BOARD_HEIGHT = 600 SCREEN_WIDTH = 800 SCREEN_HEIGHT = 600 MOVE_LOG_PANEL_WIDTH = 0 MOVE_LOG_PANEL_HEIGHT = BOARD_HEIGHT DIMENSION = 8 DIMENSION_ROWS = 7 DIMENSION_COLUMNS = 9 SIZE = 64 IMAGES = {} bias_top = 100 #棋盘的上边距 bias_left = 20 #棋盘的左边距 #网络道具 general_countdown = 40 client = None networkMsg = None server = None port = None addr = None connection = None DEPTH = 3 #网络版更新需要注意多线程的问题? server_died_message = 'fucking server died and quit' #尝试写一个函数分配一个新线程供监听 def startNewThread(target): thread = Thread(target=target) thread.daemon =True thread.start() def listenFromServer(): global networkMsg try: while True: recvMsg = client.recv(1024).decode('utf-8') if len(recvMsg) != 0: networkMsg = json.loads(recvMsg) #print('receive thread catch: ',networkMsg) except socket.error as e: #print('Error encountered in connection. Quit.') print(e) return False def startNetworkServices(): global client,server,port,addr,connection client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server = '192.168.43.115' port = 50005 addr = (server,port) connection = client.connect(addr) startNewThread(target=listenFromServer) #等待敌人移动 def loadImages():#加载图片,a,b双方分别有象狮豹狼狐鹰鼠七个角色 pieces = ["r7", "r6", "r5", "r4", "r3", "r2", "r1", "b7", "b6", "b5", "b4", "b3", "b2", "b1", ] for piece in pieces:#字典的形式存储图片 IMAGES[piece] = pg.transform.scale(pg.image.load("./Image/pieces/pieces_rb/" + piece + ".png"), (SIZE - 10, SIZE - 10)) tools = ["trap", "home1","home2"] for tool in tools: IMAGES[tool] = pg.transform.scale(pg.image.load("./Image/tools/" + tool + ".jpg"), (SIZE-10, SIZE-10)) #screen = pg.display.set_mode((BOARD_WIDTH + MOVE_LOG_PANEL_WIDTH, BOARD_HEIGHT))#设置窗口大小 #screen.fill(pg.Color("white")) def drawBoard(screen):#绘制棋盘:格子,河流,陷阱,巢穴 #colors = [(255, 255, 255), (0, 0, 0)] for row in range(DIMENSION_ROWS): for column in range(DIMENSION_COLUMNS): pg.draw.rect(screen, pg.Color(199,237,204), pg.Rect(bias_left+column * SIZE, bias_top+row * SIZE, SIZE, SIZE)) pg.draw.rect(screen, pg.Color(90,150,75), pg.Rect((column * SIZE) + bias_left+3, (row * SIZE) + 3+bias_top, SIZE - 4, SIZE - 4)) #画河流 for row in [1,2,4,5]: for column in [3,4,5]: pg.draw.rect(screen, pg.Color(67,142,219),pg.Rect((column * SIZE) +bias_left+2, (row * SIZE) +bias_top +3, SIZE-2,SIZE-2)) #画陷阱 for row in [2,4]: for column in [0,8]: screen.blit(IMAGES["trap"], pg.Rect((column * SIZE) +bias_left+6, (row * SIZE) +bias_top +6, SIZE ,SIZE )) for column in [1,7]: screen.blit(IMAGES["trap"], pg.Rect((column * SIZE) +bias_left+6, (3 * SIZE) +bias_top +6, SIZE ,SIZE )) #画巢穴 screen.blit(IMAGES["home1"], pg.Rect((bias_left+6, (3 * SIZE) +bias_top +6, SIZE ,SIZE ))) screen.blit(IMAGES["home2"], pg.Rect( 8*SIZE+bias_left+6, (3 * SIZE) +bias_top +6, SIZE ,SIZE )) def drawPieces(screen,board): #画棋子的位置 for row in range(DIMENSION_ROWS): for column in range(DIMENSION_COLUMNS): piece = board[row][column] if piece != "00": screen.blit(IMAGES[piece], pg.Rect((column * SIZE) + bias_left + 5, (row * SIZE) + bias_top + 5, SIZE - 10, SIZE - 10)) # square_selected 是当前选中的可以移动的棋子的位置 def protrudeSquares(screen,game_state,square_selected,valid_moves): #高亮选中的棋子接下来可行的位置 if square_selected != (): row = square_selected[0] column = square_selected[1] if game_state.board[row][column][0] == ('r' if game_state.red_to_move else 'b'): # highlight selected square s = pg.Surface((SIZE, SIZE)) s.set_alpha(100) s.fill(pg.Color('blue')) screen.blit(s, (column *SIZE + bias_left, row * SIZE + bias_top)) # highlight moves from that square s.fill(pg.Color('yellow')) for move in valid_moves: if move.start_row == row and move.start_col == column: screen.blit(s, (move.end_col * SIZE + bias_left, move.end_row * SIZE + bias_top)) def ShowGameState(screen,game_state,valid_moves,square_selected):#游戏状态 drawBoard(screen) protrudeSquares(screen,game_state,square_selected,valid_moves) drawPieces(screen,game_state.board) #待开发 def drawMovelog(screen):#绘制移动日志 pass def startGamePage(mode = 1):#开始游戏界面,Human/AI startpage = (''' WELCOME TO ____ ____________ _____ _ / __/ ___/ __ | / __ \ | |__| |___| |__| | | / / |___ ___ ___ ___ \__ | ___| _ / | | | _ \/ _ \/ __/ __| __| | | | | \ \ | \__/\ | | | __/\__ \__ | |____/_| |_| \__| \_____/_| |_|\___||___/___/ ################################################################ Please type one of the numbers below to choose a playing mode: ( 1 ) - 单机游戏 ( 2 ) - 网络对战 ( 3 ) - 人机对战 ( 4 ) - AI代打 ################################################################ Current Mode is: %s '''%['单机游戏','网络对战','人机对战','AI代打'][mode-1]) print(startpage) # 选择游戏模式 not_selected = True p1 , p2 = 0, 0 while not_selected: try: #mode = int(input()) #mode = 1 if mode in [1,2,3,4]: if mode == 1: p1 = 1 p2 = 1 ##其余版本还未写 not_selected = False else: print("Please type one of the numbers below to choose a playing mode:") print(" ( 1 ) - 单机游戏") print(" ( 2 ) - 网络对战") print(" ( 3 ) - 人机对战") print(" ( 4 ) - 退出游戏") except ValueError: print("Wrong Input") return p1, p2, mode def showGameOverText(screen, text): #游戏结束,出现的文字 text是字符串“Left Win”或“Right Win” font = pg.font.SysFont("comicsansms", 32) text_object = font.render(text, True, pg.Color("grey")) text_location = pg.Rect(0, 0, BOARD_WIDTH, BOARD_HEIGHT).move(BOARD_WIDTH / 2 - text_object.get_width() / 2, BOARD_HEIGHT / 2 - text_object.get_height() / 2) screen.blit(text_object, text_location) text_object = font.render(text, False, pg.Color('red')) screen.blit(text_object, text_location.move(-2 , -2)) pg.display.flip() def MainMenu(): #显示主菜单 pg.init() mainClock = pg.time.Clock() #ui screen = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pg.display.set_caption("SafariChess by ZY&&DQ") bg = pg.transform.scale(pg.image.load("Image/MenuBg.bmp"), (SCREEN_WIDTH, SCREEN_HEIGHT)) bt1 = pg.transform.scale(pg.image.load("Image/button1.jpg"),(150,40)) bt2 = pg.transform.scale(pg.image.load("Image/button2.jpg"),(150,40)) bt3 = pg.transform.scale(pg.image.load("Image/button3.jpg"),(150,40)) bt4 = pg.transform.scale(pg.image.load("Image/button4.jpg"),(150,40)) music_settings = pg.transform.scale(pg.image.load("Image/music.bmp"),(100,40)) #按钮设置 #主菜单包含如下按钮: #单机游戏,双人游戏,人机对战,退出游戏 button_1 = Button(bt1,(300,350)) button_2 = Button(bt2,(300,400)) button_3 = Button(bt3,(300,450)) button_4 = Button(bt4,(300,500)) music_button = Button(music_settings,(700,0)) #音乐设置 file=r'./Image/music1.mp3' #要播放的歌曲本地地址 pg.mixer.init() #mixer的初始化 music = pg.mixer.music.load(file) #载入一个音乐文件用于播放 pg.mixer.music.play(-1) #播放音乐,-1表示循环播放 pg.mixer.music.set_volume(0) COLOR_INACTIVE = (255, 108, 0) COLOR_ACTIVE = (255, 208, 0) COLOR_LIST_INACTIVE = (0, 143, 90) COLOR_LIST_ACTIVE = (3, 252, 140) # music_ops = DropDown([COLOR_INACTIVE, COLOR_ACTIVE],[COLOR_LIST_INACTIVE, COLOR_LIST_ACTIVE], # 600,30, 100, 20, # pg.font.SysFont("Courier", 20), # "Music", # music_lists) mode = -1 run = True while run: mainClock.tick(60) mode = 0 events = pg.event.get() for event in events: if event.type == pg.QUIT: pg.quit() sys.exit() if event.type == pg.KEYDOWN: if event.key == pg.K_ESCAPE: pg.quit() sys.exit() if event.type == pg.MOUSEBUTTONDOWN: if event.button == 1: #左键 if button_1.rect.collidepoint(event.pos): mode = 1 run = False if button_2.rect.collidepoint(event.pos): activate_AI = input("activate_AI? y/[n]: ") mode = 2 if activate_AI == 'y': mode = 4 run = False if button_3.rect.collidepoint(event.pos): mode = 3 run = False if button_4.rect.collidepoint(event.pos): pg.quit() sys.exit() if music_button.rect.collidepoint(event.pos): if pg.mixer.music.get_volume() == 0: pg.mixer.music.set_volume(0.5) else: pg.mixer.music.set_volume(0) pg.display.flip() screen.blit(bg, (0, 0)) screen.blit(button_1.image, button_1.rect) screen.blit(button_2.image, button_2.rect) screen.blit(button_3.image, button_3.rect) screen.blit(button_4.image, button_4.rect) screen.blit(music_button.image, music_button.rect) pg.display.flip() return mode #绘制Text在屏幕上 def showText(screen,fontObj,text,x,y): textSurfaceObj = fontObj.render(text, True, pg.Color('red'),pg.Color('white'))# 配置要显示的文字 textRectObj = textSurfaceObj.get_rect()# 获得要显示的对象的rect textRectObj.center = (x, y)# 设置显示对象的坐标 screen.blit(textSurfaceObj, textRectObj)# 绘制字体 def drawButton22(screen): ##一些按钮的实例化 button_stop = Button(pg.transform.scale(pg.image.load("Image/叫停.bmp"),(100,50)),(400,0)) screen.blit(button_stop.image, button_stop.rect) button_quit = Button(pg.transform.scale(pg.image.load("Image/退出.bmp"),(100,50)),(300,0)) screen.blit(button_quit.image, button_quit.rect) button_fail = Button(pg.transform.scale(pg.image.load("Image/认输.bmp"),(100,50)),(500,0)) screen.blit(button_fail.image, button_fail.rect) button_restart = Button(pg.transform.scale(pg.image.load("Image/restart.bmp"),(100,50)),(100,0)) screen.blit(button_restart.image, button_restart.rect) def main(mode): global networkMsg networkMsg = None pg.init() screen = pg.display.set_mode((BOARD_WIDTH + MOVE_LOG_PANEL_WIDTH, BOARD_HEIGHT)) pg.display.set_caption("Safari Chess Game") clock = pg.time.Clock() screen.fill(pg.Color("white")) loadImages() drawBoard(screen) isOnline = bool(mode == 2 or mode == 4) game_state=backend.GameState() #* cancelled args: MySide=True if not isOnline else bool(NewPlayerMessage['side']),game_id=NewPlayerMessage['game_id'] valid_moves=game_state.getAllMoves() running = True other_joined = False #network element other_stage = False #network element game_id = None #network element MySide = None #network element time_out_side = None #network element foul = None #network element mademove = False game_over = False square_selected = () #刚开始没有选择任何一个棋子 click_queue = [] #点击队列,记录第一次点击和第二次点击位置,方便移动棋子 ##音乐按钮,均有 button_music = Button(pg.transform.scale(pg.image.load("Image/music.bmp"),(80,40)),(650,0)) screen.blit(button_music.image, button_music.rect) pg.display.update() startGamePage(mode) #游戏进入前,可以进一步优化一些显示细节 if mode == 1 or mode == 3: if mode == 3: AI_side = random.randint(0,1) print('AI side:{}'.format('b' if AI_side == 1 else 'r')) while running: for e in pg.event.get(): #接下来处理游戏中的事件 if e.type == pg.QUIT: pg.quit() sys.exit() elif e.type == pg.MOUSEBUTTONDOWN: #鼠标点击事件:用于选择棋子,移动棋子 if not game_over: mouse_loc = pg.mouse.get_pos() row = int((mouse_loc[1] - bias_top) / SIZE) col = int((mouse_loc[0] - bias_left) / SIZE) #* get position of mouse click if square_selected == (row,col) or col >=DIMENSION_COLUMNS or row >= DIMENSION_ROWS: square_selected = () click_queue = [] else: square_selected = (row,col) click_queue.append(square_selected) if(len(click_queue) == 2): cur_piece_loc = click_queue[0] nxt_piece_loc = click_queue[1] move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board) if move in valid_moves: game_state.makeMove(move) mademove = True square_selected = () click_queue = [] valid_moves = game_state.getAllMoves() else: click_queue = [square_selected] elif e.type == pg.KEYDOWN: #设置某些按键用于悔棋,重新开始游戏,机器提示,退出游戏等功能 if e.key == pg.K_z: # undo when 'z' is pressed game_state.undoMove() mademove = True game_over = False if mademove: valid_moves = game_state.getAllMoves() mademove = False if not game_over and mode == 3: if AI_side == 1 and not game_state.red_to_move: ai_move = AI.find_BestMove(game_state,valid_moves,DEPTH) if ai_move is not None: game_state.makeMove(ai_move) mademove = True else: ai_move = AI.find_GreadyMove(game_state,valid_moves) game_state.makeMove(ai_move) mademove = True elif AI_side == 0 and game_state.red_to_move: ai_move = AI.find_BestMove(game_state,valid_moves,DEPTH) if ai_move is not None: game_state.makeMove(ai_move) mademove = True else: ai_move = AI.find_GreadyMove(game_state,valid_moves) game_state.makeMove(ai_move) mademove = True ShowGameState(screen,game_state,valid_moves,square_selected) if game_state.conquer(): showGameOverText(screen,"player "+game_state.win_person+" wins") game_over = True clock.tick(60) pg.display.flip() elif mode == 2 or mode == 4: counts=general_countdown #双方倒计时 startNetworkServices() #! start login myPlayerData = { 'type': 0, # game state type ? 'msg': { 'name': 'myName' } } login_packet = json.dumps(myPlayerData) if (sys.version[:1] == '3'): login_packet = login_packet.encode('utf-8') lastNetworkMsg = networkMsg client.send(login_packet) login_font = pg.font.SysFont("comicsansms", 32) text_object = login_font.render('waiting 4 connection...', True, pg.Color("grey")) login_text_location = pg.Rect(0, 0, BOARD_WIDTH, BOARD_HEIGHT).move(BOARD_WIDTH / 2 - text_object.get_width() / 2,BOARD_HEIGHT / 2 - text_object.get_height() / 2) while networkMsg == None: for event in pg.event.get(): if event.type == pg.QUIT: pg.quit() sys.exit() screen.blit(text_object,login_text_location) clock.tick(20) pg.display.update() pg.display.flip() #! end login # 自定义计时事件-----计时器实现 COUNTS = pg.USEREVENT +1 # 每隔1秒发送一次自定义事件 pg.time.set_timer(COUNTS,1000) #以毫秒为单位 bigfont = pg.font.SysFont("Consolas", 20) minfont = pg.font.SysFont("Courier", 18) showText(screen,bigfont,"RemainTime:",680,200) #650,250为时间,650,350为对方轮数 showText(screen,minfont,"Turn:",650,300) clock = pg.time.Clock() clock.tick(60) #drawButton22(screen) button_stop = Button(pg.transform.scale(pg.image.load("Image/叫停.bmp"), (100, 50)), (400, 0)) screen.blit(button_stop.image, button_stop.rect) button_quit = Button(pg.transform.scale(pg.image.load("Image/退出.bmp"), (100, 50)), (300, 0)) screen.blit(button_quit.image, button_quit.rect) button_fail = Button(pg.transform.scale(pg.image.load("Image/认输.bmp"), (100, 50)), (500, 0)) screen.blit(button_fail.image, button_fail.rect) button_restart = Button(pg.transform.scale(pg.image.load("Image/restart.bmp"), (100, 50)), (100, 0)) screen.blit(button_restart.image, button_restart.rect) while running: #! 特别注意:红方是0,蓝方是1 #print('current moving color: ',game_state.color()) if lastNetworkMsg != networkMsg:#handle #! 无法解决的问题:判断延迟导致无法同时接收来自服务器的两条转发消息。 #! 尝试让输方发送消息解决上述问题。 print('handling new msg: ',networkMsg) lastNetworkMsg = networkMsg #networkMsg中保存当前字典 if 'status' in networkMsg.keys(): #Login_handler if networkMsg['status'] == 1: #Finished Login process if other_joined == False: other_joined = True print('Game start 2 play!') game_id = networkMsg['game_id'] MySide = networkMsg['side'] print('my side:{}'.format('b' if MySide==1 else 'r')) other_stage = True if networkMsg['side']==1 else False #一开始如果我是蓝方则other_stage为真 if(other_stage == True): print('waiting for other player to move...') #state_game_handler elif networkMsg['status'] == 2 : # Stopping request print('other player returned special message: ',networkMsg['request']) if networkMsg['request']=='quit': other_joined = False elif networkMsg['request'] == 'stop': game_state.win_person = 'b' if networkMsg['side'] == 1 else 'r' elif networkMsg['request'] == 'report': foul = MySide otherQuitJson = { 'type': 3, 'side': MySide } client.send(json.dumps(otherQuitJson).encode('utf-8')) game_over = True #timeout handler elif networkMsg['status'] == 3 : time_out_side = networkMsg['side'] otherQuitJson = { 'type': 3, 'side': MySide } client.send(json.dumps(otherQuitJson).encode('utf-8')) game_over = True #Move handler elif 'src' and 'dst' in networkMsg.keys():# 接受对手行棋 theMove = backend.Move([networkMsg['src']['y'],networkMsg['src']['x']],[networkMsg['dst']['y'],networkMsg['dst']['x']],game_state.board) #print(theMove) violate_175 = game_state.seventeen_five_violation(goal=theMove.get_goal(),color=theMove.get_turn(), showTrace= True) violate_73 = game_state.seventy_three_violation(goal=theMove.get_goal(), color=theMove.get_turn(), showTrace= True) if not type(violate_175) == bool: print("player {} foul 17-5".format(theMove.get_turn())) print("Recent Moves: {}".format(violate_175)) reportJson = { "type": 2, "msg": { "request": "report", "game_id": game_id, "side": MySide } } client.send(json.dumps(reportJson).encode('utf-8')) foul = theMove.get_turn() if not type(violate_73) == bool: print("player {} foul 7-3".format(theMove.get_turn())) print("Recent Moves: {}".format(violate_73)) reportJson = { "type": 2, "msg": { "request": "report", "game_id": game_id, "side": MySide } } client.send(json.dumps(reportJson).encode('utf-8')) foul = theMove.get_turn() game_state.makeMove(theMove) valid_moves = game_state.getAllMoves() other_stage = not other_stage counts=general_countdown thisMove = None for e in pg.event.get(): #接下来处理游戏中的事件 if e.type == pg.QUIT: quitJson = { "type": 2, "msg": { "request": "quit", "game_id": game_id, "side": MySide } } client.send(json.dumps(quitJson).encode('utf-8')) pg.quit() sys.exit() elif e.type == pg.MOUSEBUTTONDOWN: #鼠标点击事件:用于选择棋子,移动棋子 if game_over and other_joined: if e.button == 1: if button_quit.rect.collidepoint(e.pos): quitJson = { "type": 2, "msg": { "request": "quit", "game_id": game_id, "side": MySide } } client.send(json.dumps(quitJson).encode('utf-8')) pg.quit() sys.exit() if not game_over and not other_stage and other_joined: if e.button == 1: if button_quit.rect.collidepoint(e.pos): quitJson = { "type": 2, "msg": { "request": "quit", "game_id": game_id, "side": MySide } } client.send(json.dumps(quitJson).encode('utf-8')) pg.quit() sys.exit() if button_stop.rect.collidepoint(e.pos): winJson = { 'type': 2, 'msg': { 'request': 'stop', 'game_id': game_id, 'side': MySide } } client.send(json.dumps(winJson).encode("utf-8")) if button_fail.rect.collidepoint(e.pos): quitJson = { "type": 2, "msg": { "request": "quit", "game_id": game_id, "side": MySide } } client.send(json.dumps(quitJson).encode('utf-8')) if button_restart.rect.collidepoint(e.pos): reportJson = { "type": 2, "msg": { "request": "report", "game_id": game_id, "side": MySide } } client.send(json.dumps(reportJson).encode('utf-8')) mouse_loc = pg.mouse.get_pos() row = int((mouse_loc[1] - bias_top) / SIZE) col = int((mouse_loc[0] - bias_left) / SIZE) #* get position of mouse click if square_selected == (row,col) or col >=DIMENSION_COLUMNS or row >= DIMENSION_ROWS: square_selected = () click_queue = [] else: square_selected = (row,col) click_queue.append(square_selected) if(len(click_queue) == 2): cur_piece_loc = click_queue[0] nxt_piece_loc = click_queue[1] move = backend.Move(cur_piece_loc,nxt_piece_loc,game_state.board) thisMove = move if move in valid_moves: game_state.makeMove(move) mademove = True square_selected = () click_queue = [] else: click_queue = [square_selected] elif e.type == COUNTS:# 判断事件是否为计时事件 if not other_stage and counts > 0 and not game_over: counts -= 1 text = str(counts).rjust(3) showText(screen,bigfont,text,650,250) pg.display.update() if not game_over and mode == 4: #! 特别注意:红方是0,蓝方是1 if MySide == 1 and not game_state.red_to_move: thisMove = AI.find_BestMove(game_state,valid_moves,DEPTH) if thisMove is not None: game_state.makeMove(thisMove) mademove = True else: thisMove = AI.find_GreadyMove(game_state,valid_moves) game_state.makeMove(thisMove) mademove = True elif MySide == 0 and game_state.red_to_move: thisMove = AI.find_BestMove(game_state,valid_moves,DEPTH) if thisMove is not None: game_state.makeMove(thisMove) mademove = True else: thisMove = AI.find_GreadyMove(game_state,valid_moves) game_state.makeMove(thisMove) mademove = True square_selected = () click_queue = [] if mademove: #print(thisMove) valid_moves = game_state.getAllMoves() mademove = False if isOnline: print('waiting for the other player to move...') other_stage = not other_stage thisMoveJson = { 'type': 1, 'msg': { "game_id": game_id, "side": MySide, "chessman": int(thisMove.cur_piece[1:])-1, "src": { "y": thisMove.start_row, "x": thisMove.start_col }, "dst": { "y": thisMove.end_row, "x": thisMove.end_col } } } client.send(json.dumps(thisMoveJson).encode('utf-8')) #思路变成:定时对敌方进行扫描,若收到更新相关包则进行局面更新。 ShowGameState(screen,game_state,valid_moves,square_selected) if game_state.conquer() and not game_over: print("GAME OVER!") # if game_state.win_person == ('r' if MySide == 1 else 'b'): #测试:我输了再发 winJson = { 'type': 2, 'msg': { 'request': 'stop', 'game_id': game_id, 'side': MySide } } client.send(json.dumps(winJson).encode("utf-8")) print('i lost, and game over message sent.') game_over = True #print('game over label confirmed.') if time_out_side != None: showGameOverText(screen,"player "+ ("b" if time_out_side==1 else "r")+" timed out") #超时了 elif foul is not None: showGameOverText(screen,"foul play") game_over = True elif game_over and other_joined: if (game_state.win_person == ''): game_state.conquer() showGameOverText(screen,"player "+game_state.win_person+" wins") elif game_over and not other_joined: showGameOverText(screen,"player "+ ("b" if MySide==0 else "r") + " quitted the game") #对手退出了 showText(screen,bigfont,game_state.color(),700,350) clock.tick(240) pg.display.flip() if __name__ == '__main__': #print("Loading...") #print("Initialing game...") mode = MainMenu() # mode = 4 main(mode)