宁夏建设学院官方网站代做预算网站
前文提到了 5宫格(25格子,1-12空格散开,12和13是棋盘样式,13以后不明显)
1.(越往后实际可以排序的答案样式也越多。预设答案只是其中一种)
2.超过一半的关卡时,空格就不是分散的了(超过一半数量),不容易做。
【教学类-52-17】20250803动物数独_空格尽量分散(N宫格通用版3-10宫格)0图、1图、2图、6图、有答案、无答案 组合版24套-CSDN博客文章浏览阅读521次,点赞11次,收藏2次。【教学类-52-17】20250803动物数独_空格尽量分散(N宫格通用版3-10宫格)0图、1图、2图、6图、有答案、无答案 组合版24套https://blog.csdn.net/reasonsummer/article/details/149878582?spm=1011.2415.3001.5331
所以我不想做全部关卡,就做一半。
一、棋盘测试
可以看到,这是分散样式,类似棋盘,这是空格最多的棋盘样式。
用Python做棋盘,了解1-10宫格中每种最多的棋盘样式
'''
python制作数独宫格的棋盘样式宫格1-宫格10
deepseek,阿夏
20250803
'''
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.gridspec import GridSpecdef create_chessboard(n, top_left_white=True):"""创建n x n的棋盘,返回矩阵和白色格子数量"""board = np.zeros((n, n))white_count = 0for i in range(n):for j in range(n):if (i + j) % 2 == (0 if top_left_white else 1):board[i, j] = 1 # 白色white_count += 1else:board[i, j] = 0 # 黑色return board, white_count# 创建一个大图来显示所有棋盘
plt.figure(figsize=(15, 12))
plt.suptitle("Chessboards from 1x1 to 10x10 with Maximum White Squares", fontsize=16)# 使用GridSpec来布局子图
gs = GridSpec(4, 5, width_ratios=[1]*5, height_ratios=[1]*4)max_white_counts = []for size in range(1, 11):# 计算两种排列方式的白格子数量board1, white_count1 = create_chessboard(size, True)board2, white_count2 = create_chessboard(size, False)# 选择白格子数量较多的排列方式if white_count1 >= white_count2:board = board1white_count = white_count1top_left_color = "White"else:board = board2white_count = white_count2top_left_color = "Black"max_white_counts.append((size, white_count))# 添加子图ax = plt.subplot(gs[(size-1)//3, (size-1)%3 + ((size-1)//3)*2])ax.imshow(board, cmap='binary', vmin=0, vmax=1)ax.set_title(f"{size}x{size}\nWhite: {white_count}", pad=10)ax.set_xticks([])ax.set_yticks([])# 在左上角标记颜色ax.text(0, 0, top_left_color[0], ha='center', va='center', color='red' if top_left_color == "White" else 'blue',fontsize=10, fontweight='bold')plt.tight_layout()
plt.show()# 打印最大白格子数量表
print("\nMaximum white squares for each board size:")
print("-" * 40)
print("| Size | White Squares (max) | Formula |")
print("-" * 40)
for size, count in max_white_counts:if size % 2 == 0:formula = f"n²/2 = {size*size//2}"else:formula = f"(n²+1)/2 = {(size*size+1)//2}"print(f"| {size}x{size:<3} | {count:<19} | {formula:<13} |")
print("-" * 40)
结果显示:
奇数宫格的最大数量是:"(奇数*奇数+1)/2
偶数宫格的最大数量是:"(偶数*偶数)/2
修改代码
把原来的动物数独代码与奇偶规律合并。
测试了一上午,deepseek写了20多条,终于可以用了
# -*- coding:utf-8 -*-'''
制作动物/脸谱数独N宫格通用版(3-10的黏贴关卡 A4 1图2图6图的所有组合 还有一个限定A4大小的0图(3-6宫格)
1.无答案:9种3:3,两两组合
2.有答案:27种 3:3:3,三三组合(实际需要其中9种)
3.横竖两个不能都是空格,空格尽量分散排列,如9格,目前1-5可以分散,空额不相连,6-9不行)
4.奇数宫格:(奇数*奇数+1)/2;偶数宫格:(偶数*偶数+1)/2
作者:AI对话大师,deepseek、阿夏
时间:2025年08月03日
'''import os
import time
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docxtpl import DocxTemplate
import pandas as pd
from docx2pdf import convert
from win32com.client import constants, gencache
from win32com.client.gencache import EnsureDispatch
from datetime import datetime
import random
import shutil
import xlwt
import xlrd
from PyPDF2 import PdfMerger
from docx.shared import Pt, Cm, RGBColor
from docx.oxml.shared import qnnum=1
hsall=int(input('几宫格?(3-10)\n'))
start=0
end=hsall
start_time = datetime.now()
hs=hsallpath=fr'C:\Users\jg2yXRZ\OneDrive\桌面\20250803动物数独N宫格原始6图'A4size=[6.5,4.88,3.9,3.25,2.79,2.44,2.17]
A4gz=[3,4,5,6,7,8,9]
A4pg=[3,4,5,6,7,8,9]
A4gzs=[3,4,5,6,7,8,9]psize=[19.6,14.1,9.39]
gzsize=[6.4,4.8,3.84,3.2,2.74,2.39,2.12,1.91]
gzsgg=list(range(3, 10))
pg=[1,2,6]
gzs=[1,2,2]print('-----第一板块、动物操作卡(大图片卡一页1图、1页2图 一页6图)-------')# Get page settings based on hs value
for w in range(len(A4gz)):if hs == A4gz[w]:psize.append(A4size[w])pg = [1, 2, 6, A4pg[w]]gzs = [1, 2, 2, A4gzs[w]]k = ['1图关卡', '2图关卡', '6图关卡', f'A4的{hs}图卡片']
print(k)for pt in range(len(pg)):# Create temp folderstemp_word_path = os.path.join(path, '零时Word')temp_pdf_path = os.path.join(path, '05操作卡pdf')os.makedirs(temp_word_path, exist_ok=True)os.makedirs(temp_pdf_path, exist_ok=True)# Load template documentdoc = Document(os.path.join(path, f'动物数独({k[pt]}).docx'))table = doc.tables[0]# Get animal imagespic_folder = os.path.join(path, '02动物图片')pic_list = [os.path.join(pic_folder, f) for f in os.listdir(pic_folder)][start:end] * hs# Group images based on layoutgroup_size = pg[pt]*pg[pt] if pt == 3 else pg[pt]groups = [pic_list[i:i + group_size] for i in range(0, len(pic_list), group_size)]for group_idx, group in enumerate(groups):doc = Document(os.path.join(path, f'动物数独({k[pt]}).docx'))table = doc.tables[0]for cell_idx, img_file in enumerate(group):row = int(cell_idx / gzs[pt])col = cell_idx % gzs[pt]cell = table.cell(row, col)cell.paragraphs[0].clear()if os.path.exists(img_file):run = cell.paragraphs[0].add_run()run.add_picture(img_file, width=Cm(psize[pt]), height=Cm(psize[pt]))cell.paragraphs[0].alignment = 1# Add title for A4 layoutif pt == 3:title_table = doc.tables[1]title_cell = title_table.cell(0, 0)title_cell.text = f'动物数独 {hs}*{hs} 操作卡'para = title_cell.paragraphs[0]para.alignment = WD_ALIGN_PARAGRAPH.CENTERrun = para.runs[0]run.font.name = '黑体'run.font.size = Pt(35)run.font.color.rgb = RGBColor(0, 0, 0)run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')# Save and convert to PDFdoc.save(os.path.join(temp_word_path, f'{group_idx+1:02d}页.docx'))convert(os.path.join(temp_word_path, f'{group_idx+1:02d}页.docx'), os.path.join(temp_word_path, f'{group_idx+1:02d}页.pdf'))time.sleep(2.5)# Merge PDFspdf_files = sorted([os.path.join(temp_word_path, f) for f in os.listdir(temp_word_path) if f.endswith('.pdf')])merger = PdfMerger()for pdf in pdf_files:merger.append(pdf)output_name = "03 0图关卡图操作卡片.pdf" if pt == 3 else f"03 {k[pt]}图操作卡片.pdf"merger.write(os.path.join(temp_pdf_path, output_name))merger.close()# Clean upshutil.rmtree(temp_word_path)print('-----第二板块、动物任务卡和答案卡一套,只要JPG-------')import random
from win32com.client import constants, gencache
from win32com.client import genpy
from win32com.client.gencache import EnsureDispatch
from docx import Document
from docx.shared import Pt, RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
from docx.enum.text import WD_ALIGN_PARAGRAPH
import docxtpl
import pandas as pd
from docx2pdf import convert
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
import copyprint('------3-1、生成指定数量的关卡(按最大空缺数限制)------')n = hsall # 宫格数(例如3)
g = n * n # 总格子数(例如9)# 根据宫格数确定最大空缺数
if n % 2 == 1: # 奇数宫格max_empty = (g + 1) // 2 # 例如3宫格:(9+1)/2=5
else: # 偶数宫格max_empty = g // 2 # 例如4宫格:16/2=8# 只生成1到max_empty关(例如3宫格只生成5关)
a = []
for empty in range(1, max_empty + 1): # 直接按空缺数生成# 计算对应的百分比(四舍五入)percentage = round(empty * 100 / g)print(f'{n}宫格,难度{percentage:03d},抽取{percentage:03d}%:实际有{empty:03d}空,已有图案{g-empty:03d}')a.append(f'{n}宫格,难度{percentage:03d},抽取{percentage:03d}%:实际有{empty:03d}空,已有图案{g-empty:03d}')# 去重和排序(虽然现在应该已经是有序且不重复的)
b = []
for element in a:parts = element.split(":")info = parts[1]b.append(info)
b = list(set(b))
b.sort(reverse=False)f = []
for d in range(len(b)):for c in a:if c[-15:] == b[d]:f.append(c)break# 移除第一个(空0的无效项)如果有的话
if f and int(f[0][20:23]) == g: # 检查是否全满(空0)f.pop(0)print(f'实际生成关卡数:{len(f)}')# 提取空缺数和已有图案数
empty_counts = []
filled_counts = []
for p in f:empty_counts.append(int(p[20:23]))filled_counts.append(int(p[12:15]))print('空缺数序列:', empty_counts)
print('已有图案数:', filled_counts)print('------2、制作宫格随机数字------')def generate_non_adjacent_blanks(hs, num_blanks):"""生成不连续的空格位置"""max_blanks = (hs*hs + 1)//2 if hs % 2 == 1 else (hs*hs)//2num_blanks = min(num_blanks, max_blanks) # 确保不超过最大空格数positions = list(range(hs*hs))blanks = []# 尝试生成不连续的空格max_attempts = 1000attempts = 0while len(blanks) < num_blanks and attempts < max_attempts:temp_blanks = []remaining_positions = positions.copy()while len(temp_blanks) < num_blanks and remaining_positions:pos = random.choice(remaining_positions)row = pos // hscol = pos % hs# 检查是否与已有空格相邻valid = Truefor blank in temp_blanks:blank_row = blank // hsblank_col = blank % hs# 检查是否在同一行或同一列且相邻if (row == blank_row and abs(col - blank_col) == 1) or \(col == blank_col and abs(row - blank_row) == 1):valid = Falsebreakif valid:temp_blanks.append(pos)# 移除相邻位置adjacent_positions = []if col > 0: adjacent_positions.append(pos-1)if col < hs-1: adjacent_positions.append(pos+1)if row > 0: adjacent_positions.append(pos-hs)if row < hs-1: adjacent_positions.append(pos+hs)for adj_pos in adjacent_positions:if adj_pos in remaining_positions:remaining_positions.remove(adj_pos)remaining_positions.remove(pos) if pos in remaining_positions else Noneif len(temp_blanks) == num_blanks:blanks = temp_blanksbreakattempts += 1# 如果无法生成不连续的空格,则返回随机空格if len(blanks) < num_blanks:blanks = random.sample(positions, num_blanks)return blanks# 修改这里 - 使用empty_counts而不是g
for kk in range(len(empty_counts)): # 遍历每个空缺数ll=['{}'.format(hs)]mm=['11']nn=['36']for r in range(len(ll)):if hs ==int(ll[r]):db=int(mm[r][0]) cb=int(mm[r][1])size=int(nn[r])imagePath=path+r'\\零时Word'os.makedirs(imagePath,exist_ok=True) imagePatha=path+r'\06答案卡'imagePathq=path+r'\07任务卡'os.makedirs(imagePatha,exist_ok=True)os.makedirs(imagePathq,exist_ok=True)db_size = hs*dbcb_size= hs*cbprint('{}宫格排列底{}侧{}共{}套,底边格子数{}'.format(hs,db,cb,db*cb,db_size))print('{}宫格排列底{}侧{}共{}套,侧边格子数{}'.format(hs,db,cb,db*cb,cb_size))bgszm=[]for a in range(0,cb_size,hs):for b in range(0,db_size,hs):bgszm.append('{}{}'.format('%02d'%a,'%02d'%b))print(bgszm)start_coordinates = [(int(s[0:2]), int(s[2:4])) for s in bgszm]cell_coordinates = []for start_coord in start_coordinates:i, j = start_coordsubgrid_coordinates = []for x in range(hs):for y in range(hs):subgrid_coordinates.append((i + x, j + y))cell_coordinates.append(subgrid_coordinates)bg=[]for coordinates in cell_coordinates:for c in coordinates:print(c)s = ''.join(str(num).zfill(2) for num in c)print(str(s))bg.append(s)print(bg)P=[] for z in range(num): P.clear()for j in range(db*cb):def generate_sudoku_board():board = [[0] * hs for _ in range(hs)]def filling_board(row, col):if row == hs:return Truenext_row = row if col < hs-1 else row + 1next_col = (col + 1) % hsimport mathr = int(math.sqrt(hs))print(r)box_row = row // rbox_col = col // rnumbers = random.sample(range(1, hs+1), hs)for num in numbers:if hs==4 or hs==9:if num not in board[row] and all(board[i][col] != num for i in range(hs)) and all(num != board[i][j] for i in range(box_row*r, box_row*r+r) for j in range(box_col*r, box_col*r+r)):board[row][col] = numif filling_board(next_row, next_col):return Trueboard[row][col] = 0else:if num not in board[row] and all(board[i][col] != num for i in range(hs)) and all(num != board[i][j] for i in range(box_row, box_row) for j in range(box_col, box_col)):board[row][col] = numif filling_board(next_row, next_col):return Trueboard[row][col] = 0return Falsefilling_board(0, 0)return boardboard1 = generate_sudoku_board()def create_board1(): return board1def create_board2():global board1board2 = copy.deepcopy(board1)# 使用empty_counts[kk]获取当前关卡的空缺数num_blanks = empty_counts[kk]# 使用新方法生成不连续的空格blanks = generate_non_adjacent_blanks(hs, num_blanks)for i in blanks:row = i // hscol = i % hsboard2[row][col] = 0return board2v1 = create_board1() v2 = create_board2()v=v1+v2print(v)P = ['' if a2 == 0 else a2 for a1 in v for a2 in a1]print(P)print(len(P))half_len = int(len(P) // 2)Q = [P[i:i+half_len] for i in range(0, len(P), half_len)]print(Q)time.sleep(2.5) print('------答案卡和题目卡------') title=['答案卡','任务卡']imagePath1=path+r'\答案卡1'imagePath2=path+r'\任务卡1'os.makedirs(imagePath1,exist_ok=True)os.makedirs(imagePath2,exist_ok=True)ti=[path+r'\答案卡1',path+r'\任务卡1'] for tt in range(len(Q)): doc = Document(path+fr'\动物数独(横板{hs}宫格).docx') table = doc.tables[0]for b1 in range(0,1):cell_00 = table.cell(0, b1)cell_00_paragraph = cell_00.paragraphs[0]cell_00_paragraph.text =f"动物数独 {hs}*{hs} 第 {kk+1} 关 {title[tt]}"cell_00_paragraph.style.font.bold = Truecell_00_paragraph.style.font.size = Pt(24)cell_00_paragraph.style.font.name = "黑体"cell_00_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTERtable = doc.tables[1]for t in range(0,len(bg)):pp=int(bg[t][0:2])qq=int(bg[t][2:4])k=str(Q[tt][t])print(pp,qq,k)run=table.cell(pp,qq).paragraphs[0].add_run(k)run.font.name = '黑体'run.font.size = Pt(size)run.font.color.rgb = RGBColor(0,0,0)run.bold=Truer = run._elementr.rPr.rFonts.set(qn('w:eastAsia'), '黑体')table.cell(pp,qq).paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTERdoc.save(ti[tt]+fr'\{z+1:02d}.docx')time.sleep(2.5)print('------4、每张word转为pdf----') from docx import Documentfrom docx.shared import Cmanimal_path = path+r'\02动物图片'file_paths = [os.path.join(animal_path, file_name) for file_name in os.listdir(animal_path)]print(file_paths)file_paths=file_paths[start:end]doc = Document(ti[tt]+fr'\{z+1:02d}.docx')tables = doc.tablesfor table in tables:for i, row in enumerate(table.rows):for j, cell in enumerate(row.cells):cell_text = cell.textfor x in range(0,hs):if cell_text == f'{x+1}':cell.text = ''run = cell.paragraphs[0].add_run()for n in range(len(gzsgg)):if hs==gzsgg[n]:run.add_picture(file_paths[x], width=Cm(gzsize[n]), height=Cm(gzsize[n]))run.alignment = WD_PARAGRAPH_ALIGNMENT.CENTERcell.vertical_alignment = WD_ALIGN_PARAGRAPH.CENTERcell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTERdoc.save(ti[tt]+fr'\{z+1:02d}.docx')time.sleep(2.5)from docx2pdf import convertinputFile = ti[tt]+fr'\{z+1:02d}.docx'outputFile =ti[tt]+fr'\{z+1:02d}.pdf'f1 = open(outputFile, 'w')f1.close()convert(inputFile, outputFile)time.sleep(2.5) print('----------更改pdf新名字------------') tii=[path+r'\06答案卡',path+r'\07任务卡']for t3 in range(len(tii)):pdf_lst = [f for f in os.listdir(ti[t3]) if f.endswith('.pdf')]pdf_path = os.path.join(ti[t3], pdf_lst[0]) print(pdf_path) # 修改这里 - 使用empty_counts[kk]而不是w[kk]new_file_name = f"{title[t3]} 动物拼图{hs}宫格 难度{kk+1:02d} 空{empty_counts[kk]:03d}格({db}乘{cb}等于{num}份{db*cb}张).pdf" output_path = os.path.join(tii[t3], new_file_name)print(output_path)os.rename(pdf_path, output_path)time.sleep(2.5) shutil.rmtree(ti[t3])time.sleep(2.5)print('----------第4步:把都有16管PDF关卡变png------------')from win32com.client import Dispatch
import os
import re
import fitzwdFormatPDF = 17
zoom_x=2
zoom_y=2
rotation_angle=0li=[path+r'\06答案卡',path+r'\07任务卡']
for l in li:for root, dirs, files in os.walk(l):for file in files:if re.search('\.pdf$', file):filename = os.path.abspath(root + "\\" + file)print(filename)pdf = fitz.open(filename)for pg in range(0, pdf.pageCount):page = pdf[pg]trans = fitz.Matrix(zoom_x, zoom_y).preRotate(rotation_angle)pm = page.getPixmap(matrix=trans, alpha=True)pm.writePNG(filename.replace('.pdf', '') + str(pg+1) + ".png")pdf.close()for parent, dirnames, filenames in os.walk(l):for fn in filenames:if fn.lower().endswith('.pdf'):os.remove(os.path.join(parent, fn))print('-----第三板块、把动物任务卡和答案卡一套分别做成1页1份,1页2份,1页6份的pdf-------')psize=[9.39,9.39,14.1,14.1,19.6,19.6]
pg=[6,6,2,2,1,1]
gzs=[2,2,2,2,1,1]
nh=[1,2,1,2,1,2]for x in range(len(pg)):imagePath11=path+r'\08答案卡pdf'imagePath22=path+r'\09任务卡pdf'os.makedirs(imagePath11,exist_ok=True)os.makedirs(imagePath22,exist_ok=True)tiii=[path+r'\08答案卡pdf',path+r'\09任务卡pdf',path+r'\08答案卡pdf',path+r'\09任务卡pdf',path+r'\08答案卡pdf',path+r'\09任务卡pdf']tii=[path+r'\06答案卡',path+r'\07任务卡',path+r'\06答案卡',path+r'\07任务卡',path+r'\06答案卡',path+r'\07任务卡']title=['答案卡','任务卡','答案卡','任务卡','答案卡','任务卡']imagePath=path+r'\\零时Word'os.makedirs(imagePath,exist_ok=True)doc = Document(path +fr'\动物数独({pg[x]}图关卡).docx')tables = doc.tables[0]file_paths = [os.path.join(tii[x], file) for file in os.listdir(tii[x])]pic_list_six = [file_paths[i:i+int(pg[x])] for i in range(0, len(file_paths), int(pg[x]))]print(pic_list_six)print(len(pic_list_six))for group_index, group in enumerate(pic_list_six):doc = Document(path + fr'\动物数独({pg[x]}图关卡).docx')for cell_index, image_file in enumerate(group):cc=float(psize[x])table = doc.tables[0]cell = table.cell(int(cell_index /gzs[x]), cell_index % gzs[x])cell_paragraph = cell.paragraphs[0]cell_paragraph.clear()run = cell_paragraph.add_run()run.add_picture(os.path.join(image_file), width=Cm(cc), height=Cm(cc))cell_paragraph.alignment = 1doc.save(imagePath + fr'\{group_index + 1:02d}页.docx')inputFile = imagePath + fr'\{group_index + 1:02d}页.docx'outputFile = imagePath + fr'\{group_index + 1:02d}页.pdf'convert(inputFile, outputFile)time.sleep(2.5)pdf_lst = [f for f in os.listdir(imagePath) if f.endswith('.pdf')]pdf_lst = [os.path.join(imagePath, filename) for filename in pdf_lst]pdf_lst.sort()file_merger = PdfMerger()for pdf in pdf_lst:print(pdf)file_merger.append(pdf)file_merger.write(tiii[x]+ fr"\{nh[x]:02} {pg[x]:02}图{title[x]}.pdf")time.sleep(1)file_merger.close()shutil.rmtree(imagePath)print('-----第四板块、交叉合并有答案6套,无答案6套(1-1-1、1-1,1-2-2,1-2,2-1-1,2-1……----')newgz=path+fr'\(打印)动物数独{hs}宫格24套'
os.makedirs(newgz,exist_ok=True)address=[]
all=['09任务卡pdf','05操作卡pdf']
for y in all:new=path+fr'\{y}' file_new = [os.path.join(new, f) for f in os.listdir(new)]address.append(file_new)combinations = [[x, y] for x in address[0] for y in address[1]]
print(combinations)import PyPDF2
for files in combinations:print(files)pdf_merger = PyPDF2.PdfFileMerger()for file in files:pdf_merger.append(file)output_file = newgz+fr"\动物数独{hs}宫格(无答案) {files[0][-9:-4] } {files[1][-13:-4] }.pdf"pdf_merger.write(output_file)pdf_merger.close()address=[]
all=['08答案卡pdf','09任务卡pdf','05操作卡pdf']
for y in all:new=path+fr'\{y}' file_new = [os.path.join(new, f) for f in os.listdir(new)]address.append(file_new)combinations = []
for i in address[0]:for j in address[1]:for k in address[2]:combinations.append([i, j, k])import PyPDF2
for files in combinations:print(files)pdf_merger = PyPDF2.PdfFileMerger()for file in files:pdf_merger.append(file)output_file = newgz+fr"\动物数独{hs}宫格(有答案) {files[0][-9:-4] } {files[1][-9:-4]} {files[2][-13:-4]}.pdf"pdf_merger.write(output_file)pdf_merger.close()import os
import shutil
for file_name in os.listdir(newgz):if file_name.endswith(".pdf"):if f"动物数独{hs}宫格(有答案)" in file_name:if hs<10:if file_name[13] == file_name[19]:print(f"保留文件:{file_name}")else:os.remove(os.path.join(newgz, file_name))print(f"删除文件:{file_name}")imagePath11=path+r'\08答案卡pdf'
imagePath22=path+r'\09任务卡pdf'
imagePatha=path+r'\06答案卡'
imagePathq=path+r'\07任务卡'
imagePathpaste=path+r'\05操作卡pdf'shutil.rmtree(imagePath11)
shutil.rmtree(imagePath22)
shutil.rmtree(imagePatha)
shutil.rmtree(imagePathq)
shutil.rmtree(imagePathpaste)end_time = datetime.now()
elapsed_time = end_time - start_timeprint(f"动物数独{hs}宫格程序开始时间:{start_time}")
print(f"动物数独{hs}宫格程序结束时间:{end_time}")
print("程序运行时间:", elapsed_time)
这个代码只能生成一个,如3宫格、4宫格。我希望一次性生成3-6宫格。(由于操作卡的0图有标题,所以操作部分不能通用)
# -*- coding:utf-8 -*-'''
制作动物/脸谱数独N宫格通用版(3-10的黏贴关卡 A4 1图2图6图的所有组合 还有一个限定A4大小的0图(3-6宫格)
1.无答案:9种3:3,两两组合
2.有答案:27种 3:3:3,三三组合(实际需要其中9种)
3.横竖两个不能都是空格,空格尽量分散排列,如9格,目前1-5可以分散,空额不相连,6-9不行)
4.奇数宫格:(奇数*奇数+1)/2;偶数宫格:(偶数*偶数+1)/2
5.一次性生成3-6宫格
作者:AI对话大师,deepseek、阿夏
时间:2025年08月03日
'''import os
import time
from docx import Document
from docx.shared import Cm, Pt, RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.oxml.ns import qn
from docxtpl import DocxTemplate
import pandas as pd
from docx2pdf import convert
from win32com.client import constants, gencache
from win32com.client.gencache import EnsureDispatch
from datetime import datetime
import random
import shutil
import xlwt
import xlrd
from PyPDF2 import PdfMerger
from docx.shared import Pt, Cm, RGBColor
from docx.oxml.shared import qn
import math
import fitz
from PyPDF2 import PdfFileMerger
import copystart_time = datetime.now()
# 改为循环处理多个宫格数
hsall_list = [3, 4, 5, 6] # 要生成的宫格数列表for hsall in hsall_list:start = 0end = hsall=hs # 为每个宫格数创建独立的文件夹path = fr'C:\Users\jg2yXRZ\OneDrive\桌面\20250803动物数独N宫格原始6图'os.makedirs(path, exist_ok=True)# A4尺寸设置A4size = [6.5, 4.88, 3.9, 3.25, 2.79, 2.44, 2.17]A4gz = [3, 4, 5, 6, 7, 8, 9]A4pg = [3, 4, 5, 6, 7, 8, 9]A4gzs = [3, 4, 5, 6, 7, 8, 9]psize = [19.6, 14.1, 9.39]gzsize = [6.4, 4.8, 3.84, 3.2, 2.74, 2.39, 2.12, 1.91]gzsgg = list(range(3, 10))pg = [1, 2, 6]gzs = [1, 2, 2]print('-----第一板块、动物操作卡(大图片卡一页1图、1页2图 一页6图)-------')# 根据宫格数获取页面设置for w in range(len(A4gz)):if hs == A4gz[w]:psize.append(A4size[w])pg = [1, 2, 6, A4pg[w]]gzs = [1, 2, 2, A4gzs[w]]k = ['1图关卡', '2图关卡', '6图关卡', f'A4的{hs}图卡片']print(k)for pt in range(len(pg)):# 创建临时文件夹temp_word_path = os.path.join(path, '零时Word')temp_pdf_path = os.path.join(path, '05操作卡pdf')os.makedirs(temp_word_path, exist_ok=True)os.makedirs(temp_pdf_path, exist_ok=True)# 加载模板文档doc = Document(os.path.join(path, f'动物数独({k[pt]}).docx'))table = doc.tables[0]# 获取动物图片pic_folder = os.path.join(path, '02动物图片')pic_list = [os.path.join(pic_folder, f) for f in os.listdir(pic_folder)][start:end] * hs# 根据布局分组图片group_size = pg[pt]*pg[pt] if pt == 3 else pg[pt]groups = [pic_list[i:i + group_size] for i in range(0, len(pic_list), group_size)]for group_idx, group in enumerate(groups):doc = Document(os.path.join(path, f'动物数独({k[pt]}).docx'))table = doc.tables[0]for cell_idx, img_file in enumerate(group):row = int(cell_idx / gzs[pt])col = cell_idx % gzs[pt]cell = table.cell(row, col)cell.paragraphs[0].clear()if os.path.exists(img_file):run = cell.paragraphs[0].add_run()run.add_picture(img_file, width=Cm(psize[pt]), height=Cm(psize[pt]))cell.paragraphs[0].alignment = 1# 为A4布局添加标题if pt == 3:title_table = doc.tables[1]title_cell = title_table.cell(0, 0)title_cell.text = f'动物数独 {hs}*{hs} 操作卡'para = title_cell.paragraphs[0]para.alignment = WD_ALIGN_PARAGRAPH.CENTERrun = para.runs[0]run.font.name = '黑体'run.font.size = Pt(35)run.font.color.rgb = RGBColor(0, 0, 0)run._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')# 保存并转换为PDFdoc.save(os.path.join(temp_word_path, f'{group_idx+1:02d}页.docx'))convert(os.path.join(temp_word_path, f'{group_idx+1:02d}页.docx'), os.path.join(temp_word_path, f'{group_idx+1:02d}页.pdf'))time.sleep(3)# 合并PDFpdf_files = sorted([os.path.join(temp_word_path, f) for f in os.listdir(temp_word_path) if f.endswith('.pdf')])merger = PdfMerger()for pdf in pdf_files:merger.append(pdf)output_name = "03 0图关卡图操作卡片.pdf" if pt == 3 else f"03 {k[pt]}图操作卡片.pdf"merger.write(os.path.join(temp_pdf_path, output_name))merger.close()# 清理临时文件shutil.rmtree(temp_word_path)print('-----第二板块、动物任务卡和答案卡一套,只要JPG-------')print('------3-1、生成指定数量的关卡(按最大空缺数限制)------')n = hsall # 宫格数g = n * n # 总格子数# 根据宫格数确定最大空缺数if n % 2 == 1: # 奇数宫格max_empty = (g + 1) // 2 # 例如3宫格:(9+1)/2=5else: # 偶数宫格max_empty = g // 2 # 例如4宫格:16/2=8# 只生成1到max_empty关a = []for empty in range(1, max_empty + 1): # 直接按空缺数生成percentage = round(empty * 100 / g)print(f'{n}宫格,难度{percentage:03d},抽取{percentage:03d}%:实际有{empty:03d}空,已有图案{g-empty:03d}')a.append(f'{n}宫格,难度{percentage:03d},抽取{percentage:03d}%:实际有{empty:03d}空,已有图案{g-empty:03d}')# 去重和排序b = []for element in a:parts = element.split(":")info = parts[1]b.append(info)b = list(set(b))b.sort(reverse=False)f = []for d in range(len(b)):for c in a:if c[-15:] == b[d]:f.append(c)break# 移除第一个(空0的无效项)如果有的话if f and int(f[0][20:23]) == g: # 检查是否全满(空0)f.pop(0)print(f'实际生成关卡数:{len(f)}')# 提取空缺数和已有图案数empty_counts = []filled_counts = []for p in f:empty_counts.append(int(p[20:23]))filled_counts.append(int(p[12:15]))print('空缺数序列:', empty_counts)print('已有图案数:', filled_counts)print('------2、制作宫格随机数字------')def generate_non_adjacent_blanks(hs, num_blanks):"""生成不连续的空格位置"""max_blanks = (hs*hs + 1)//2 if hs % 2 == 1 else (hs*hs)//2num_blanks = min(num_blanks, max_blanks) # 确保不超过最大空格数positions = list(range(hs*hs))blanks = []# 尝试生成不连续的空格max_attempts = 1000attempts = 0while len(blanks) < num_blanks and attempts < max_attempts:temp_blanks = []remaining_positions = positions.copy()while len(temp_blanks) < num_blanks and remaining_positions:pos = random.choice(remaining_positions)row = pos // hscol = pos % hs# 检查是否与已有空格相邻valid = Truefor blank in temp_blanks:blank_row = blank // hsblank_col = blank % hs# 检查是否在同一行或同一列且相邻if (row == blank_row and abs(col - blank_col) == 1) or \(col == blank_col and abs(row - blank_row) == 1):valid = Falsebreakif valid:temp_blanks.append(pos)# 移除相邻位置adjacent_positions = []if col > 0: adjacent_positions.append(pos-1)if col < hs-1: adjacent_positions.append(pos+1)if row > 0: adjacent_positions.append(pos-hs)if row < hs-1: adjacent_positions.append(pos+hs)for adj_pos in adjacent_positions:if adj_pos in remaining_positions:remaining_positions.remove(adj_pos)remaining_positions.remove(pos) if pos in remaining_positions else Noneif len(temp_blanks) == num_blanks:blanks = temp_blanksbreakattempts += 1# 如果无法生成不连续的空格,则返回随机空格if len(blanks) < num_blanks:blanks = random.sample(positions, num_blanks)return blanksdef generate_valid_sudoku(hs):"""生成有效的数独棋盘"""board = [[0 for _ in range(hs)] for _ in range(hs)]def is_valid(num, row, col):# 检查行if num in board[row]:return False# 检查列for i in range(hs):if board[i][col] == num:return False# 检查宫box_size = int(math.sqrt(hs))box_row = (row // box_size) * box_sizebox_col = (col // box_size) * box_sizefor i in range(box_size):for j in range(box_size):if board[box_row + i][box_col + j] == num:return Falsereturn Truedef backtrack(row, col):if row == hs:return Truenext_row = row if col < hs-1 else row + 1next_col = (col + 1) % hsif board[row][col] != 0:return backtrack(next_row, next_col)for num in random.sample(range(1, hs+1), hs):if is_valid(num, row, col):board[row][col] = numif backtrack(next_row, next_col):return Trueboard[row][col] = 0return Falsebacktrack(0, 0)return board# 修改这里 - 使用empty_counts而不是gfor kk in range(len(empty_counts)): # 遍历每个空缺数ll = ['{}'.format(hs)]mm = ['11']nn = ['36']for r in range(len(ll)):if hs == int(ll[r]):db = int(mm[r][0]) cb = int(mm[r][1])size = int(nn[r])imagePath = path + r'\\零时Word'os.makedirs(imagePath, exist_ok=True) imagePatha = path + r'\06答案卡'imagePathq = path + r'\07任务卡'os.makedirs(imagePatha, exist_ok=True)os.makedirs(imagePathq, exist_ok=True)db_size = hs * dbcb_size = hs * cbprint('{}宫格排列底{}侧{}共{}套,底边格子数{}'.format(hs, db, cb, db*cb, db_size))print('{}宫格排列底{}侧{}共{}套,侧边格子数{}'.format(hs, db, cb, db*cb, cb_size))bgszm = []for a in range(0, cb_size, hs):for b in range(0, db_size, hs):bgszm.append('{}{}'.format('%02d' % a, '%02d' % b))print(bgszm)start_coordinates = [(int(s[0:2]), int(s[2:4])) for s in bgszm]cell_coordinates = []for start_coord in start_coordinates:i, j = start_coordsubgrid_coordinates = []for x in range(hs):for y in range(hs):subgrid_coordinates.append((i + x, j + y))cell_coordinates.append(subgrid_coordinates)bg = []for coordinates in cell_coordinates:for c in coordinates:print(c)s = ''.join(str(num).zfill(2) for num in c)print(str(s))bg.append(s)print(bg)num = 1P = [] for z in range(num): P.clear()for j in range(db * cb):# 生成有效的数独棋盘board1 = generate_valid_sudoku(hs)def create_board2():board2 = copy.deepcopy(board1)# 使用empty_counts[kk]获取当前关卡的空缺数num_blanks = empty_counts[kk]# 使用新方法生成不连续的空格blanks = generate_non_adjacent_blanks(hs, num_blanks)for i in blanks:row = i // hscol = i % hsboard2[row][col] = 0return board2v1 = board1 v2 = create_board2()v = v1 + v2print(v)P = ['' if a2 == 0 else a2 for a1 in v for a2 in a1]print(P)print(len(P))half_len = int(len(P) // 2)Q = [P[i:i+half_len] for i in range(0, len(P), half_len)]print(Q)time.sleep(3) print('------答案卡和题目卡------') title = ['答案卡', '任务卡']imagePath1 = path + r'\答案卡1'imagePath2 = path + r'\任务卡1'os.makedirs(imagePath1, exist_ok=True)os.makedirs(imagePath2, exist_ok=True)ti = [path + r'\答案卡1', path + r'\任务卡1'] for tt in range(len(Q)): doc = Document(path + fr'\动物数独(横板{hs}宫格).docx') table = doc.tables[0]for b1 in range(0, 1):cell_00 = table.cell(0, b1)cell_00_paragraph = cell_00.paragraphs[0]cell_00_paragraph.text = f"动物数独 {hs}*{hs} 第 {kk+1} 关 {title[tt]}"cell_00_paragraph.style.font.bold = Truecell_00_paragraph.style.font.size = Pt(24)cell_00_paragraph.style.font.name = "黑体"cell_00_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTERtable = doc.tables[1]for t in range(0, len(bg)):pp = int(bg[t][0:2])qq = int(bg[t][2:4])k = str(Q[tt][t])print(pp, qq, k)run = table.cell(pp, qq).paragraphs[0].add_run(k)run.font.name = '黑体'run.font.size = Pt(size)run.font.color.rgb = RGBColor(0, 0, 0)run.bold = Truer = run._elementr.rPr.rFonts.set(qn('w:eastAsia'), '黑体')table.cell(pp, qq).paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTERdoc.save(ti[tt] + fr'\{z+1:02d}.docx')time.sleep(3)print('------4、每张word转为pdf----') from docx import Documentfrom docx.shared import Cmanimal_path = path + r'\02动物图片'file_paths = [os.path.join(animal_path, file_name) for file_name in os.listdir(animal_path)]print(file_paths)file_paths = file_paths[start:end]doc = Document(ti[tt] + fr'\{z+1:02d}.docx')tables = doc.tablesfor table in tables:for i, row in enumerate(table.rows):for j, cell in enumerate(row.cells):cell_text = cell.textfor x in range(0, hs):if cell_text == f'{x+1}':cell.text = ''run = cell.paragraphs[0].add_run()for n in range(len(gzsgg)):if hs == gzsgg[n]:run.add_picture(file_paths[x], width=Cm(gzsize[n]), height=Cm(gzsize[n]))run.alignment = WD_PARAGRAPH_ALIGNMENT.CENTERcell.vertical_alignment = WD_ALIGN_PARAGRAPH.CENTERcell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTERdoc.save(ti[tt] + fr'\{z+1:02d}.docx')time.sleep(3)from docx2pdf import convertinputFile = ti[tt] + fr'\{z+1:02d}.docx'outputFile = ti[tt] + fr'\{z+1:02d}.pdf'f1 = open(outputFile, 'w')f1.close()convert(inputFile, outputFile)time.sleep(3) print('----------更改pdf新名字------------') tii = [path + r'\06答案卡', path + r'\07任务卡']for t3 in range(len(tii)):pdf_lst = [f for f in os.listdir(ti[t3]) if f.endswith('.pdf')]pdf_path = os.path.join(ti[t3], pdf_lst[0]) print(pdf_path) # 修改这里 - 使用empty_counts[kk]而不是w[kk]new_file_name = f"{title[t3]} 动物拼图{hs}宫格 难度{kk+1:02d} 空{empty_counts[kk]:03d}格({db}乘{cb}等于{num}份{db*cb}张).pdf" output_path = os.path.join(tii[t3], new_file_name)print(output_path)os.rename(pdf_path, output_path)time.sleep(3) shutil.rmtree(ti[t3])time.sleep(3)print('----------第4步:把都有16管PDF关卡变png------------')li = [path + r'\06答案卡', path + r'\07任务卡']for l in li:for root, dirs, files in os.walk(l):for file in files:if file.endswith('.pdf'):filename = os.path.abspath(root + "\\" + file)print(filename)pdf = fitz.open(filename)for pg in range(0, pdf.pageCount):page = pdf[pg]trans = fitz.Matrix(2, 2).preRotate(0)pm = page.getPixmap(matrix=trans, alpha=True)pm.writePNG(filename.replace('.pdf', '') + str(pg+1) + ".png")pdf.close()for parent, dirnames, filenames in os.walk(l):for fn in filenames:if fn.lower().endswith('.pdf'):os.remove(os.path.join(parent, fn))print('-----第三板块、把动物任务卡和答案卡一套分别做成1页1份,1页2份,1页6份的pdf-------')psize = [9.39, 9.39, 14.1, 14.1, 19.6, 19.6]pg = [6, 6, 2, 2, 1, 1]gzs = [2, 2, 2, 2, 1, 1]nh = [1, 2, 1, 2, 1, 2]for x in range(len(pg)):imagePath11 = path + r'\08答案卡pdf'imagePath22 = path + r'\09任务卡pdf'os.makedirs(imagePath11, exist_ok=True)os.makedirs(imagePath22, exist_ok=True)tiii = [path + r'\08答案卡pdf', path + r'\09任务卡pdf', path + r'\08答案卡pdf', path + r'\09任务卡pdf', path + r'\08答案卡pdf', path + r'\09任务卡pdf']tii = [path + r'\06答案卡', path + r'\07任务卡', path + r'\06答案卡', path + r'\07任务卡', path + r'\06答案卡', path + r'\07任务卡']title = ['答案卡', '任务卡', '答案卡', '任务卡', '答案卡', '任务卡']imagePath = path + r'\\零时Word'os.makedirs(imagePath, exist_ok=True)doc = Document(path + fr'\动物数独({pg[x]}图关卡).docx')tables = doc.tables[0]file_paths = [os.path.join(tii[x], file) for file in os.listdir(tii[x])]pic_list_six = [file_paths[i:i+int(pg[x])] for i in range(0, len(file_paths), int(pg[x]))]print(pic_list_six)print(len(pic_list_six))for group_index, group in enumerate(pic_list_six):doc = Document(path + fr'\动物数独({pg[x]}图关卡).docx')for cell_index, image_file in enumerate(group):cc = float(psize[x])table = doc.tables[0]cell = table.cell(int(cell_index / gzs[x]), cell_index % gzs[x])cell_paragraph = cell.paragraphs[0]cell_paragraph.clear()run = cell_paragraph.add_run()run.add_picture(os.path.join(image_file), width=Cm(cc), height=Cm(cc))cell_paragraph.alignment = 1doc.save(imagePath + fr'\{group_index + 1:02d}页.docx')inputFile = imagePath + fr'\{group_index + 1:02d}页.docx'outputFile = imagePath + fr'\{group_index + 1:02d}页.pdf'convert(inputFile, outputFile)time.sleep(3)pdf_lst = [f for f in os.listdir(imagePath) if f.endswith('.pdf')]pdf_lst = [os.path.join(imagePath, filename) for filename in pdf_lst]pdf_lst.sort()file_merger = PdfMerger()for pdf in pdf_lst:print(pdf)file_merger.append(pdf)file_merger.write(tiii[x] + fr"\{nh[x]:02} {pg[x]:02}图{title[x]}.pdf")time.sleep(1)file_merger.close()shutil.rmtree(imagePath)print('-----第四板块、交叉合并有答案6套,无答案6套(1-1-1、1-1,1-2-2,1-2,2-1-1,2-1……----')newgz = path + fr'\(打印)动物数独{hs}宫格24套 共{len(empty_counts)}关'os.makedirs(newgz, exist_ok=True)address = []all = ['09任务卡pdf', '05操作卡pdf']for y in all:new = path + fr'\{y}' file_new = [os.path.join(new, f) for f in os.listdir(new)]address.append(file_new)combinations = [[x, y] for x in address[0] for y in address[1]]print(combinations)for files in combinations:print(files)pdf_merger = PdfFileMerger()for file in files:pdf_merger.append(file)output_file = newgz + fr"\动物数独{hs}宫格(无答案) 共{len(empty_counts)}关 {files[0][-9:-4]} {files[1][-13:-4]}.pdf"pdf_merger.write(output_file)pdf_merger.close()address = []all = ['08答案卡pdf', '09任务卡pdf', '05操作卡pdf']for y in all:new = path + fr'\{y}' file_new = [os.path.join(new, f) for f in os.listdir(new)]address.append(file_new)combinations = []for i in address[0]:for j in address[1]:for k in address[2]:combinations.append([i, j, k])for files in combinations:print(files)pdf_merger = PdfFileMerger()for file in files:pdf_merger.append(file)output_file = newgz + fr"\动物数独{hs}宫格(有答案) 共{len(empty_counts)}关 {files[0][-9:-4]} {files[1][-9:-4]} {files[2][-13:-4]}.pdf"pdf_merger.write(output_file)pdf_merger.close()import osimport shutilfor file_name in os.listdir(newgz):if file_name.endswith(".pdf"):if f"动物数独{hs}宫格(有答案)" in file_name:if hs<10:# 动物数独3宫格(有答案) 共5关 1图答案卡 1图任务卡 0图关卡图操作卡片if file_name[17] == file_name[23]:print(f"保留文件:{file_name}")elif file_name[18] == file_name[24]:print(f"保留文件:{file_name}")else:os.remove(os.path.join(newgz, file_name))print(f"删除文件:{file_name}")# 清理临时文件夹imagePath11 = path + r'\08答案卡pdf'imagePath22 = path + r'\09任务卡pdf'imagePatha = path + r'\06答案卡'imagePathq = path + r'\07任务卡'imagePathpaste = path + r'\05操作卡pdf'shutil.rmtree(imagePath11)shutil.rmtree(imagePath22)shutil.rmtree(imagePatha)shutil.rmtree(imagePathq)shutil.rmtree(imagePathpaste)end_time = datetime.now()
elapsed_time = end_time - start_timeprint(f"动物数独{hs}宫格程序开始时间:{start_time}")
print(f"动物数独{hs}宫格程序结束时间:{end_time}")
print("程序运行时间:", elapsed_time)