|

楼主 |
发表于 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
复制代码 |
|