"""
3*3游戏盘,每个位置有0和1两种状态。
每次行动可以选择点击(?)一个位置,之后该位置与它相邻的4个位置(如果有)0/1状态变换
引入随机初始化功能、自定义初始化功能,引入行动可撤销一次机制,引入记录日志功能
"""
import random
import time
print("\nPlaceGame_进阶版1\n仍为3*3,引入随机初始化、自定义初始化功能,引入行动可撤销一次机制,引入记录日志功能(输入r撤销上次行动)")
main_dic = {(i, j): random.randint(0, 1) for i in range(1, 4) for j in range(1, 4)} # 生成随机游戏盘
timer = 0 # 记录行动次数
xr = 0
yr = 0 # 这两个是用来记录上一次行动的坐标,用于单次撤销
flag1_undo = True # 确保不会再同一个记录点多次撤销
flag3_save = False
file_journal = open("PlaceGame1_journal.txt", mode="a", encoding="utf-8")
file_journal.write("\n" + time.asctime() + "\n")
# file_save = open("PlaceGame1_save.txt", mode="w", encoding="utf-8")
def show_str():
"""把棋盘 main_dic 的数据以九宫格形式字符串返回。用来展示棋盘
其实也可以每次都复制粘贴这个字符串,但是太长了不美观"""
# global main_dic # 这里只是读取main_dic所以不用global
show_main_str = f" 1 2 3\n1 {main_dic[1, 1]} {main_dic[2, 1]} {main_dic[3, 1]}\n2 {main_dic[1, 2]} {main_dic[2, 2]} {main_dic[3, 2]}\n3 {main_dic[1, 3]} {main_dic[2, 3]} {main_dic[3, 3]}"
return show_main_str
def choose_action():
"""将用户输入、行动(或撤销)写在一整个函数里"""
global timer
global flag1_undo
global xr
global yr # 引入4个全局变量。这四个因为都涉及记录,不可以每次调用函数就重置一次,所以在全局定义然后引入局部
x = 0
y = 0
change_lst = list()
# 初始化完成。后面是输入/判断
while not (0 < x < 4 and 0 < y < 4):
index_lst = input(f"[Input][第{timer+1}次行动]请输入坐标(示例:2,3)>>>").split(",")
if len(index_lst) == 2: # 首先确保用户输入了两个数(我有过输了一个然后不小心按了回车的情况)
if index_lst[0].isdigit() and index_lst[1].isdigit(): # 再确保这两个都是数!不是别的
x = int(index_lst[0])
y = int(index_lst[1])
xr = x
yr = y # 把本次行动位置记录在xr,yr
print(f"[Action]翻转 x={x}, y={y}")
file_journal.write(f"/action(x={x}, y={y}), time={timer}\n")
change_lst = [(x - 1, y), (x, y), (x + 1, y), (x, y - 1), (x, y + 1)] # 这是(可能)要翻转的所有格子
flag1_undo = True # 本次已行动,获得撤销机会*1(bushi
elif index_lst[0] == "r":
if flag1_undo:
print("[Undo]撤销成功")
file_journal.write("/undo\n")
timer -= 2 # 一次是抵消函数结尾的+=1,一个是抵消上次的+=1,回到上次行动的timer
change_lst = [(xr - 1, yr), (xr, yr), (xr + 1, yr), (xr, yr - 1), (xr, yr + 1)] # 按上次记录的位置再翻一次
flag1_undo = False # 撤销机会已使用
break
else:
print("[Error]只能撤销一次。")
# elif index_lst[0] == "s":
# flag3_save = True
# break
for index1 in change_lst:
if index1 in main_dic.keys(): # 如果坐标在游戏盘上(如果选择的位置在游戏盘边缘就不是翻转5个了)
main_dic[index1] = 1 - main_dic[index1] # 1-1=0,1-0=1,用1减一次相当于转换
print(show_str())
file_journal.write(f" {show_str()}\n")
timer += 1
mode_rand = "Z"
while mode_rand.upper() != 'A' and mode_rand.upper() != 'B' and mode_rand.upper() != 'C':
mode_rand = input("[Choice]请选择如何初始化游戏盘:A.随机 B.全为0 C.自定义\n>>>")
file_journal.write(f"mode_rand={mode_rand.upper()}\n")
if mode_rand.upper() == "B":
main_dic = {(i, j): 0 for i in range(1, 4) for j in range(1, 4)} # 用推导式产生全为0的游戏盘
elif mode_rand.upper() == "C":
selfSet_lst = list()
while True: # 自定义游戏盘
selfSet_lst = input("[Input]请输入从左至右、从上至下的数字初始值(0或1),以英文逗号分隔\n>>>").split(",")
flag2_isint_len = True # 用来检查用户有没有输入奇怪的(不是1/0的)东西或者输入个数不对
# 注意,因为这个flag2必须要在每次重新输入之后重置为True,所以如果写在while True外面,就会发生只要输错一次就永远是False的问题
if "" in selfSet_lst:
selfSet_lst.remove("")
for i in selfSet_lst:
if i != "1" and i != "0": # 是数字但是不是0或1,flag标记为False并跳出for循环
flag2_isint_len = False
print(f"[Error]输入了1、0以外的其他项。请重新输入。")
break
if len(selfSet_lst) != 9:
flag2_isint_len = False
print(f"[Error]输入数字个数错误,应输入 9 个,实际输入 {len(selfSet_lst)} 个。请重新输入。")
if flag2_isint_len:
break # 只有3道检查都过关了才能跳出while True循环
for i in range(9):
selfSet_lst[i] = int(selfSet_lst[i])
for j in range(1, 4):
for i in range(1, 4):
main_dic[i, j] = selfSet_lst[i - 1 + 3 * (j - 1)]
print(f"初始游戏盘如下。\n{show_str()}")
file_journal.write(f"initial=\n {show_str()}\n")
mode_end = 'Z'
while mode_end.upper() != 'A' and mode_end.upper() != 'B':
mode_end = input("[Choice]请选择模式:A.全部翻转(全部变为1)即结束游戏 B.自由模式\n>>>")
file_journal.write(f"mode_end={mode_end.upper()}\n")
if mode_end.upper() == "A":
while 0 in main_dic.values():
choose_action()
print(f"[End]已全部翻转。共进行了{timer}次行动。")
file_journal.close()
else:
while True:
choose_action()
或许可以将不同功能(包括Choose_Action和输入判断部分)写进不同文件里然后import,现在的结构不够清晰