Skip to content

Commit

Permalink
增加了个简单的排名,至此这个课设的主体内容就做完了!8说了,去复习CET6了
Browse files Browse the repository at this point in the history
  • Loading branch information
SomeBottle committed Dec 12, 2021
1 parent e49fdc4 commit a54db8a
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 42 deletions.
32 changes: 25 additions & 7 deletions src/game.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def create_area(cls):
map_w, map_h = map(lambda x: x+3, cls.map_size) # 获得地图大小
# 根据地图大小创建游戏区域,要比地图大小稍微大一点
game_area = curses.newwin(map_h, map_w, 1, 1)
msg_area = curses.newwin(7, map_w, map_h+1, 1)
msg_area = curses.newwin(8, map_w, map_h+1, 1)
game_area.keypad(True) # 支持上下左右等特殊按键
game_area.nodelay(True) # 非阻塞,用户没操作游戏要持续进行
cls.game_area = game_area
Expand Down Expand Up @@ -190,21 +190,39 @@ def draw_border(self): # 根据边界点坐标绘制游戏区域边框
def draw_score(self):
line_ins = self.get_ins('line')
score_text = f'SCORE: {self.__score} '
len_text = f'LENGTH: {len(line_ins.attrs["body_pos"])}'
self.msg_area.addstr(0, 0, score_text+len_text)
len_text = f'TAIL LEN: {len(line_ins.attrs["body_pos"])}'
self.msg_area.addstr(0, 0, score_text+' / '+len_text)

def calc_score(self): # 计算出最终得分,返回(分数,长度,总得分)
difficulty = self.all_cfg['difficulty']*0.1
line_ins = self.get_ins('line')
body_len = len(line_ins.attrs['body_pos']) # 尾巴长度
score = self.__score
multiply = score*body_len*difficulty
return (score, body_len, round(multiply, 2))

def over(self): # 游戏结束
res_ins = Res()
self.cancel_tasks() # 清除并行任务
self.tui.erase() # 擦除内容
self.game_area.erase() # 擦除游戏区域内容
over_text = Res().art_texts('gameover')[2] # 获得艺术字GAME OVER
self.tui.addstr(1, 5, Res.x_offset(
over_text, 5), curses.color_pair(4))
text_h, text_w, over_text = res_ins.art_texts(
'gameover') # 获得艺术字GAME OVER
self.tui.addstr(1, 1, Res.x_offset(
over_text, 1), curses.color_pair(4))
self.msg_area.mvwin(text_h+1, 1) # 移动一下msg区的位置
pattern = '{:-^' + str(text_w) + '}'
result_text = pattern.format('RESULT')
score, tail_len, total = map(str, self.calc_score())
score_text = 'SCORE: ' + score+'\nTAIL LENGTH: '+tail_len+'\nTOTAL SCORE: '+total
self.msg_area.addstr(0, 0, result_text)
self.msg_area.addstr(1, 0, score_text)
self.msg_area.addstr(
0, 0, 'Type: \n(R) to Replay the Game\n(B) to Return to Menu')
5, 0, 'Type: \n(R) to Replay the Game\n(B) to Return to Menu')
self.tui.refresh()
self.msg_area.refresh()
self.msg_area.nodelay(False) # 阻塞接受getch
res_ins.set_ranking(total) # 尝试计入排名
while True:
recv = self.msg_area.getch()
if recv in (ord('r'), ord('R')): # 按下R/r
Expand Down
38 changes: 36 additions & 2 deletions src/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
from os import path
from math import floor
import random
import time
import json


class Res:
def __init__(self) -> None:
self.f_path = path.dirname(__file__) # 当前程序运行所在的绝对目录
config_path = self.f_path+'/config.json'
ranking_path = self.f_path+'/ranking.json'
default_config = { # 默认配置文件
'difficulty': 1,
'tps': 10, # ticks per second
'max_rank_len': 100, # 排名最多收录多少条
'diff_cfg': { # 不同困难度对应的配置
"1": {
"map_size": (50, 15),
Expand Down Expand Up @@ -143,18 +146,25 @@ def __init__(self) -> None:
}
}
}
default_ranking = {
"rank_list": []
}

if not path.exists(config_path): # 如果没有就自动创建配置文件
with open(config_path, 'w+') as f:
f.write(json.dumps(default_config, indent=2))
if not path.exists(ranking_path): # 如果没有就自动创建排名
with open(ranking_path, 'w+') as f:
f.write(json.dumps(default_ranking))

def art_texts(self, k): # 获取艺术字,返回值(高度,长度,艺术字文本),艺术字都放在了./texts目录下
file_path = self.f_path+'/texts/'+k+'.txt'
if path.exists(file_path):
with open(file_path, 'r') as f:
lines = f.readlines()
text_height = len(lines) # 以行数为高度
text_width = max(*map(lambda x: len(x), lines)
) # 以最长的一行文本的长度为宽度
# 以最长的一行文本的长度为宽度
text_width = max(*map(lambda x: len(x), lines))
f.seek(0, 0) # readlines后文件指针指向末尾了,要拉回来!这是一个非常容易出错的点!
result = (text_height, text_width, f.read())
return result # 让with as语句块执行完后再返回
Expand All @@ -176,6 +186,30 @@ def set_config(self, key, val):
f.write(json.dumps(pre_cfg, indent=2)) # 写入修改后的配置
return True

def get_ranking(self): # 获得排名
file_path = self.f_path+'/ranking.json'
with open(file_path, 'r') as f:
get_dict = json.loads(f.read())
return get_dict

def set_ranking(self, total_score): # 加入排名
file_path = self.f_path+'/ranking.json'
config = self.get_config()
pre_ranking = self.get_ranking()
rank_list = pre_ranking['rank_list']
current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
if len(rank_list) > config['max_rank_len']: # 超出排名收录的数量了
last_one = rank_list[-1] # 找到当前排名最后的
if total_score > last_one[1]:
rank_list.pop()
rank_list.append((current_time, total_score))
else:
rank_list.append((current_time, total_score))
rank_list.sort(key=lambda x: x[1], reverse=True)
with open(file_path, 'w+') as f:
f.write(json.dumps(pre_ranking)) # 写入排名
return True

@staticmethod # 作为一个静态方法
def x_offset(string, offset):
'''搭配addstr,处理字符串的偏移。如果只用addstr的x-offset的话就第一行有偏移,其他行都是一个样,这个方法将字符串除第一行之外所有行头部都加上offset空格'''
Expand Down
30 changes: 2 additions & 28 deletions src/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,5 @@
import asyncio
import os
a=Figlet()
'''with open(os.path.dirname(__file__)+'/texts/gameover.txt', 'w') as file_object:
file_object.write(a.renderText('GAME OVER'))'''
'''
async def test():
await asyncio.sleep(2)
print('Finished waiting')
async def main(task):
for i in range(50):
print(i)
if i==10:
task.append(asyncio.create_task(test()))
await asyncio.sleep(2)
async def enter():
task=[]
task.append(asyncio.create_task(main(task)))
await asyncio.wait(task)
asyncio.run(enter())'''
class Test:
def __init__(self,h) -> None:
self.hello=h
def delete(self):
del self
test=Test('world')
test.delete()
print(test)
with open(os.path.dirname(__file__)+'/texts/ranking.txt', 'w') as file_object:
file_object.write(a.renderText('R A N K I N G'))
6 changes: 6 additions & 0 deletions src/texts/ranking.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
____ _ _ _ _ __ ___ _ _ ____
| _ \ / \ | \ | | | |/ / |_ _| | \ | | / ___|
| |_) | / _ \ | \| | | ' / | | | \| | | | _
| _ < / ___ \ | |\ | | . \ | | | |\ | | |_| |
|_| \_\ /_/ \_\ |_| \_| |_|\_\ |___| |_| \_| \____|

57 changes: 52 additions & 5 deletions src/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def create_win(self, title_txt):
title.addstr(1, 3, Res.x_offset(title_txt[2], 3)) # 打印出游戏名
title.border() # 标题旁边加个边框
# 再创建一个窗口,我们作为菜单
# 高为 3 宽为 title_offset_w,在命令行窗口的 title_offset_h+2行2列
choice_session = curses.newwin(5, title_offset_w, title_offset_h+2, 2)
# 高为 8 宽为 title_offset_w,在命令行窗口的 title_offset_h+2行2列
choice_session = curses.newwin(10, title_offset_w, title_offset_h+2, 2)
choice_session.nodelay(False) # 阻塞
choice_session.keypad(True) # 支持上下左右这种特殊按键
return (title, choice_session)
Expand All @@ -37,12 +37,14 @@ def __init__(self) -> None:
self.choice_dict = { # 几个选项
0: 'Start to line',
1: 'Set Difficulty',
2: 'Exit'
2: 'Ranking',
3: 'Exit'
}
self.choice_func = { # 上述选项对应的函数
0: self.start_game,
1: DifficultyView().show_panel,
2: self.leave
2: RankingView().show_panel,
3: self.leave
}
self.last_choice = len(self.choice_dict.keys())-1 # 最后一个选项的索引,用来封底

Expand All @@ -64,7 +66,7 @@ async def asyncio_game(self): # 开启并行任务
self.game_end_choice = game.end_choice # 把游戏结束后的值传出去

def start_game(self): # 开始游戏
asyncio.run(self.asyncio_game())
asyncio.run(self.asyncio_game()) # 开启事件循环
choice_dict = {
'restart': self.start_game,
'menu': self.menu
Expand Down Expand Up @@ -140,3 +142,48 @@ def show_panel(self):
curses.endwin() # 中止窗口,取消初始化
res_ins.set_config('difficulty', difficulty_set)
MenuView().menu() # 返回主菜单


class RankingView(BasicView):
def list_maker(self, chunk, start=0):
list_str = 'PLACE DATE SCORE\n'
for key, item in enumerate(chunk):
place = start+key+1
date, score = item
list_str += f'{place} {date} {score}\n'
list_str += '\nPress (D) for Next Page, (A) for Prev Page'
return list_str

def show_panel(self):
rank_list = Res().get_ranking()['rank_list']
title, choice_session = self.create_win(Res().art_texts('ranking'))
chunked = []
each_chunk = 6
for i in range(0, len(rank_list), each_chunk):
the_chunk = rank_list[i:i+each_chunk]
chunked.append(the_chunk) # 分片
self.tui.refresh() # 刷新总界面
title.refresh() # 刷新标题窗口
current_page = 0
max_page = len(chunked)-1
while True:
choice_session.erase() # 清除之前的显示
if len(rank_list) > 0:
current_chunk = chunked[current_page]
start_place = current_page*each_chunk
choice_session.addstr(
1, 0, self.list_maker(current_chunk, start_place))
else: # 暂无记录
choice_session.addstr(1, 1, 'NO RECORDS')
choice_session.refresh() # 刷新选项窗口,输出上面的内容
recv = choice_session.getch()
if recv in (ord('D'), ord('d')) and current_page < max_page:
current_page += 1
elif recv in (ord('A'), ord('a')) and current_page > 0:
current_page -= 1
elif recv in (10, curses.KEY_ENTER):
break
del title, choice_session # 删除窗口
self.tui.clear() # 清除屏幕
curses.endwin() # 中止窗口,取消初始化
MenuView().menu() # 返回主菜单

0 comments on commit a54db8a

Please sign in to comment.