|
楼主 |
发表于 2024-6-22 14:49:54
|
显示全部楼层
代码已优化:
main.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Auth :Ray
"""
此工具仅适用于《Dorfrmantik》(中文名:筑梦颂)游戏。
一、游戏介绍:
随机给玩家一个六边形板块,玩家根据自己的选择放置到地图上,从而组成独特的乡村风景。
六边形上的地形分为:
空地、房屋、农田、森林、铁路、河流
其中河流、铁路只能和对应的板块连接,其他地形无特殊要求,可以随意连接
游戏没有时间限制,但是系统提供的板块有个数限制,放置完之后游戏结束!
每放置一个板块会有对应的分数,完成特殊的任务有板块奖励和额外分数,所以尽可能多的放置板块就可以获得更高的分数,组成的乡村也会更大!
二、游戏奖励机制:
1.开场系统给玩家40个板块,可以随意放置到地图上;
2.放置时六边形每有一边地形与旁边一致加10分,最多(六个方向的地形均一致)可加60分;
3.当一个六边形板块的六个地形均与旁边一致时,达成“完美拼接”,奖励一块新板块;(得高分的重点)
4.系统会随机给任务“地形图标加数字”,表示要求相同地形连续出现N次或N+次,达成目标后奖励5块板块,获得100分;(快速获得板块,优先级最高)
5.地图上随机出现旗帜,表示要求此地形形成封闭状态,达成目标后奖励5块板块;
6.成就系统,系统会给各种特殊的任务,完成后奖励分数和特殊板块(风车、水车、火车等);
7.隐藏地块,地图上未到达的地区会随机出现隐藏板块,当放置板块接近后会获得新的成就任务;
三、游戏得分点:
1.当插入的地形与已有地形相同时,才能得10分,否则是0分;
2.当板块六个方向的地形均与相邻板块一致时,奖励60分和一个新板块;
四、工具实现内容:
1.记录原始板块的地形组合与顺序,保证与游戏内一致;(新游戏默认是一个六边空地)
2.用户输入下一个要插入板块的地形,计算出与之完美匹配的所有地形组合;
3.在原始地块中搜索并提示用户可以插入哪些位置;
4.用户输入实际插入板块的位置;
5.自动计算插入新板块后的地形组合及顺序;
五、工具优缺点:
优点:能保证每一次插入新板块都是最优解,比人工去找要方便很多,特别是后期大量板块需要人工比对;
缺点:操作费时费力,无法自动获取板块组成和插入位置,计算出来的最优地形太多,用户选择有困难
"""
from plate import *
import json
if __name__ == '__main__':
# 游戏初始界面
welcome = eg.buttonbox(msg='Dorfromantik游戏开始,请选择是否是新游戏!', title='Dorfromantik Game Start!Welcome!',
choices=['是', '不是'])
# 判断是否是新游戏,如果是新游戏则初始化板块
# 各个地形缩写:空地:K 房屋:F 农田:N 森林:S 铁路:T 河流:H
# plate_init_out元组代表外围一圈的地形可插入最优解地形,例如'KKF'表示此板块可以插入的地形为:‘空地+空地+房屋’
# plate_init_in集合代表内圈的地形和与之相关联的外圈地形,一般是五地形和六地形空板块,例如{'KKFKK': 'NXF'}
if welcome == '是':
plate_init_out = tuple('KKKKKK') # 新游戏起始板块周边的空板块六边均为空地
plate_init_in = {} # 新游戏起始没有内圈空板块
else:
# 继续游戏时,从上次运行时保存的文件中读取外圈和内圈空板块数据
with open('plate_last_out.txt', 'r') as file_last_out:
plate_init_out = eval(file_last_out.read().strip())
with open('plate_last_in.json', 'r', encoding='utf-8') as file_last_in:
plate_init_in = json.load(file_last_in)
# 游戏循环开始
while True:
# 显示初始板块(废弃不用)
# file_plate_out(plate_init_out) # 将初始化外部地形写入plate_out.txt
# with open('plate_out.txt') as file_1:
# eg.textbox(msg='当前外圈板块为:\n(空地:K 房屋:F 农田:N 森林:S 铁路:T 河流:H)\n第一列:空白板块编号\n第二列:可适配地形', text=file_1.read(),
# title='Dorfromantik Tool!')
# eg.msgbox(msg=f'当前内圈板块为:\n{plate_init_in}', title='Dorfromantik Tool!')
# 请用户输入下一个要插入的板块,逆时针输入
plate_next = enter_plate()
# 枚举新板块适合的所有板块地形
plate_fit = fit_plate(plate_next)
# 计算新板块最完美的拼接位置是哪里
best_plate = find_num(plate_fit, plate_init_out, plate_init_in)
# 请用户输入实际插入板块的位置是哪里
plate_num, new_num = enter_num(plate_init_out, plate_init_in, plate_next, best_plate)
# 显示插入新板块后的总地块
plate_next = tuple(plate_next)
plate_final = final_plate(plate_init_out, plate_init_in, plate_next, plate_num, new_num)
# 更新初始地块
plate_init_out = plate_final[0]
plate_init_in = copy.deepcopy(plate_final[2])
plate_init_in.update(plate_final[1])
# 用户确认插入后的结果是否正确
y_n_out = eg.ynbox(msg=f'插入新板块后外圈板块为:\n(空地:K 房屋:F 农田:N 森林:S 铁路:T 河流:H)\n{plate_init_out}', title='Dorfromantik Tool!')
y_n_in = eg.ynbox(msg=f'插入新板块后内圈板块为:\n(空地:K 房屋:F 农田:N 森林:S 铁路:T 河流:H)\n{plate_init_in}', title='Dorfromantik Tool!')
if not y_n_out or not y_n_in:
eg.msgbox(msg='游戏出错,请重新开始插入此板块!', title='Dorfromantik Tool!')
with open('plate_last_out.txt', 'r') as file_last_out:
plate_init_out = eval(file_last_out.read().strip())
with open('plate_last_in.json', 'r', encoding='utf-8') as file_last_in:
plate_init_in = json.load(file_last_in)
continue
# 备份上次游戏的结果
with open('plate_last_out.txt', 'w') as file_last_out:
file_last_out.write(repr(plate_init_out))
with open('plate_last_in.json', 'w', encoding='utf-8') as f:
json.dump(plate_init_in, f, ensure_ascii=False, indent=4)
plate.py:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Auth :Ray
import easygui as eg
import re
import copy
def file_plate_out(plate_init_out):
"""初始化板块"""
with open('plate_out.txt', 'w') as file_init:
for index, element in enumerate(plate_init_out):
file_init.write(f'{index}\t{element}\n')
def enter_plate():
"""新板块插入"""
eg_enter = eg.enterbox(msg='请输入下一个要插入的板块是(逆时针):\n(空地K 房屋F 农田N 森林S 铁路T 河流H)',
title='Dorfromantik Tool!')
while True:
# 判断输入是否正确,否则重新要求用户输入
try:
if len(eg_enter) != 6 or not re.fullmatch(r'[KFNSTH]+', eg_enter):
eg_enter = eg.enterbox(
msg=f'输入的板块格式不对,请重新输入:\n(空地K 房屋F 农田N 森林S 铁路T 河流H)\n您上次输入的是:{eg_enter}',
title='Dorfromantik Tool!')
else:
break
except TypeError:
eg_enter = eg.enterbox(
msg=f'输入的板块格式不对,请重新输入:\n(空地K 房屋F 农田N 森林S 铁路T 河流H)\n您上次输入的是:{eg_enter}',
title='Dorfromantik Tool!')
return eg_enter
def fit_plate(plate):
"""枚举新板块适合的所有板块地形"""
"""例如插入板块是'SKKKKK',适合的所有地形为:('K', 'KK', 'KKK', 'KKKK', 'KKKKK', 'KKKKKS', 'KKKKS', 'KKKKSK', 'KKKS',
'KKKSK', 'KKKSKK', 'KKS', 'KKSK', 'KKSKK', 'KKSKKK', 'KKXK', 'KKXS', 'KS', 'KSK', 'KSKK', 'KSKKK', 'KSKKKK',
'KSXK', 'KXK', 'KXKK', 'KXKS', 'KXS', 'KXSK', 'S', 'SK', 'SKK', 'SKKK', 'SKKKK', 'SKKKKK', 'SKXK', 'SXK', 'SXKK')"""
result = []
for i in range(0, len(plate)):
plate_1 = plate[i:] + plate[:i]
for j in range(1, len(plate_1) + 1):
result.append(plate_1[:j])
result.append(plate_1[:1] + 'X' + plate_1[2])
result.append(plate_1[:1] + 'X' + plate_1[2:4])
result.append(plate_1[:2] + 'X' + plate_1[3])
return tuple(sorted(list(set(result))))
def find_num(plate_fit, plate_init_out, plate_init_in):
"""计算哪些板块最适合插入"""
"""与外圈、内圈板块比对,若一致则返回对应位置及板块名称"""
result = []
j = 6
while j > 0:
if j > 4:
for i in plate_fit:
if len(i) == j:
if i in plate_init_in:
result.append({i: plate_init_in[i]})
else:
for i in plate_fit:
if len(i) == j:
for key, value in enumerate(plate_init_out):
if value == i:
result.append({key: value})
j -= 1
return result
def enter_num(plate_init_out, plate_init_in, plate_next, best_plate):
"""用户输入要插入新板块的位置"""
while True:
a = eg.enterbox(
msg=f'请输入在哪个位置插入新板块:\n(空地K 房屋F 农田N 森林S 铁路T 河流H)\n新板块是:{plate_next}\n建议插入位置:\n{best_plate}',
title='Dorfromantik Tool!')
try:
plate_num = int(a)
break
except (ValueError, TypeError):
if a in plate_init_in.keys():
plate_num = a
break
else:
eg.msgbox(msg=f'输入无效,请重新输入要插入的位置!', title='Dorfromantik Tool!')
while True:
try:
if type(plate_num) is str:
s = plate_num
else:
s = plate_init_out[plate_num]
b = eg.enterbox(
msg=f'请输入新板块要对接的位置:\n(空地K 房屋F 农田N 森林S 铁路T 河流H)\n待插入的地形是:{s}\n新板块是:{plate_next}',
title='Dorfromantik Tool!')
new_num = int(b)
if 0 <= new_num <= 5:
break
else:
eg.msgbox(msg=f'超出新板块范围,请重新输入要对接的位置(0-5)!', title='Dorfromantik Tool!')
continue
except (ValueError, TypeError):
eg.msgbox(msg=f'输入无效,请重新输入要对接的位置(0-5)!', title='Dorfromantik Tool!')
return plate_num, new_num
def final_plate(plate_init_out, plate_init_in, plate_next, plate_num, new_num):
"""计算插入后的板块"""
plate_finnal_out = []
plate_finnal_in = {}
plate_init_in_temp = copy.deepcopy(plate_init_in)
# 当待插入的地块为五地形和六地形时,plate_num为字符串 plate_init_in = {"KKSKK": "SXF"} SKKKKK
if type(plate_num) is str:
if len(plate_num) == 5:
k = plate_init_in[plate_num] # SXF
plate_finnal_out = list(plate_init_out)
plate_finnal_out_1 = list(plate_init_out)
for key, value in enumerate(plate_finnal_out_1):
if value == k:
y_or_n = eg.ynbox(
msg=f'当前地形为:\n{plate_finnal_out_1}\n请确认要插入五地形地块对应的{k}位置是否为{key}?',
title='Dorfromantik Tool!')
if y_or_n:
plate_finnal_out[key] = plate_finnal_out_1[key].replace('X', plate_next[new_num - 1])
del plate_init_in[plate_num]
if len(plate_num) == 6:
del plate_init_in[plate_num]
plate_finnal_out = list(plate_init_out)
# 当待插入的地块为单地形到四地形时
else:
len_p = len(plate_init_out[plate_num])
if len_p in (1, 2, 3, 4):
# 当待插入的板块是带X时,对应的五地形板块需修改为六地形
if 'X' in plate_init_out[plate_num]:
x_index = plate_init_out[plate_num].index('X')
for key, value in plate_init_in.items():
if value == plate_init_out[plate_num]:
y_or_n = eg.ynbox(msg=f'请确认要插入的{plate_init_out[plate_num]}是否对应{key}?',
title='Dorfromantik Tool!')
if y_or_n:
key_new = key + plate_next[new_num + x_index - 6]
del plate_init_in_temp[key]
plate_init_in_temp[key_new] = None
plate_init_in = copy.deepcopy(plate_init_in_temp)
if 'X' in plate_init_out[plate_num - len(plate_init_out) + 1]:
for key, value in plate_init_in.items():
if value == plate_init_out[plate_num+1]:
y_or_n = eg.ynbox(msg=f'请确认要插入的{plate_init_out[plate_num + 1]}是否对应{key}?',
title='Dorfromantik Tool!')
if y_or_n:
value_new = (plate_next[new_num - 6 + len_p] + plate_init_out[plate_num - len(plate_init_out) + 1])
plate_init_in_temp[key] = value_new
plate_init_in = copy.deepcopy(plate_init_in_temp)
if 'X' in plate_init_out[plate_num - 1]:
for key, value in plate_init_in.items():
if value == plate_init_out[plate_num-1]:
y_or_n = eg.ynbox(msg=f'请确认要插入的{plate_init_out[plate_num - 1]}是否对应{key}?',
title='Dorfromantik Tool!')
if y_or_n:
value_new = (plate_init_out[plate_num - 1] + plate_next[new_num - 1])
plate_init_in_temp[key] = value_new
plate_init_in = copy.deepcopy(plate_init_in_temp)
plate_finnal_out.append(plate_init_out[plate_num - 1] + plate_next[new_num - 1])
i = 2
while i < 6 - len_p:
plate_finnal_out.append(plate_next[new_num - i])
i += 1
plate_finnal_out.append(
(plate_next[new_num - 6 + len_p] + plate_init_out[plate_num - len(plate_init_out) + 1]))
j = len(plate_init_out) - 2
while j > 1:
plate_finnal_out.append(plate_init_out[plate_num - j])
j -= 1
# 当plate_finnal中存在五地形和六地形时,需要特殊处理
for i in plate_finnal_out:
if len(i) == 5:
index_i = plate_finnal_out.index(i)
# 把五地形板块从地形列表中取出来,并将前后板块合并
plate_finnal_out.pop(index_i)
plate_finnal_out[index_i] = plate_finnal_out[index_i - 1] + 'X' + plate_finnal_out[index_i]
plate_finnal_out.pop(index_i - 1)
# 单独把五地形放入另一个字典里
if index_i != 0:
plate_finnal_in[i] = plate_finnal_out[index_i - 1]
else:
plate_finnal_in[i] = plate_finnal_out[index_i]
return tuple(plate_finnal_out), plate_finnal_in, plate_init_in
|
|