作品展示:合并打印(难度10%-90%,一共9份)
背景需求
前期两个代码完成了4宫格基本样式的制作
【教学类-52-01】20240411动物数独(4宫格)宫格图https://mp.csdn.net/mp_blog/creation/editor/137679361【教学类-52-01】20240411动物数独(4宫格)宫格图-CSDN博客文章浏览阅读700次,点赞19次,收藏3次。【教学类-52-01】20240411动物数独(4宫格)宫格图https://blog.csdn.net/reasonsummer/article/details/137679361
但是在打印前,我仔细这些正方形的数独题,只有图纸没有记号,有巨大的问题:
1、打印后,要通过点数空格数,才能知道那一份是简单的(空格少)那一份是最难的(空格多)
2、幼儿操作时没法确定简单和困难,会反复询问老师解题方法,也很麻烦。
因此,我认为还是要给图片加上一定的记号(数字或星号),来区分图片的难度。
素材准备:
这些宫格图并非图片,因此我将docx竖版改成横版,并在宫格图上方加入一个独立的1行2列表格,作为标题栏。
代码修改
代码展示:
# 测试11*11格,2*2一共4套3*3 宫格
'''
目的:动物数独01 a4竖版 2个4*4宫格(连在一起的)套抽一半(数字替换成图片) 难度1-9,横版加标题
作者:「Vaeeeeeee」,AI对话大师,阿夏
时间:2024年4月12日 13:35
'''
import random,time
from win32com.client import constants,gencache
from win32com.client.gencache import EnsureDispatch
from win32com.client import constants # 导入枚举常数模块
import os,time
import docx
from docx import Document
from docx.shared import Pt
from docx.shared import RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import qn
from docxtpl import DocxTemplate
import pandas as pd
from docx2pdf import convert
from docx.shared import RGBColor
from docx import Document
from docx.shared import Cm
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_PARAGRAPH_ALIGNMENT
from docx.oxml.ns import nsdecls
from docx.oxml import parse_xml
# 生成题库
import random
import copy
num=int(input('生成几份\n'))
# 制作"单元格"# 几宫格
hsall=int(input('请输入4或9\n'))
hs=hsall
# kk=int(input('空格数量,输入5,就是50%,就是空一半)\n'))
for kk in range(1,10):
# 因为有3-9的不同word模板,其中3-4模板一页生成9套,5-9模板一页生成6套,这里直接生成边长
ll=['4','9'] # 如果输入345
mm=['21','32']# 3对应的套数是1*2套
nn=['24','24']# 3对应的写入单元格的数字大小36磅
for r in range(len(ll)):
if hsall ==int(ll[r]):
# 底边几套.底边看有2份
db=int(mm[r][0])
# int(input('底边几套? 3\n'))
# 侧边几套 侧边看也是2份
print(db )
cb=int(mm[r][1])
# int(input('侧边几套? 2\n'))
print(cb)
size=int(nn[r])
print(size) # 写入单元格数字的大小(撑满格子)
path=r'C:\Users\jg2yXRZ\OneDrive\桌面\动物数独'
# 新建一个”装N份word和PDF“的临时文件夹
imagePath=path+r'\\零时Word'
if not os.path.exists(imagePath): # 判断存放图片的文件夹是否存在
os.makedirs(imagePath) # 若图片文件夹不存在就创建
# 计算不同模板中的单元格坐标,放在bg里
# 棋盘格子数量,
# 如果正方形:底边2*侧边2,就是3*3宫格 2*2=4套,底边边格子数量就是3*2+1=7,侧边格子数量就是3*2+1=7,
# 如果长方形:底边3*侧边2,就是3*3宫格,3*2=6套 底边格子数量就是3*3+2=11,侧边格子数量就是3*2+1=7,
# if db==cb:
db_size = hs*db+db-1
cb_size= hs*cb+cb-1
print('{}宫格排列底{}侧{}共{}套,底边格子数{}'.format(hs,db,cb,db*cb,db_size ))
print('{}宫格排列底{}侧{}共{}套,侧边格子数{}'.format(hs,db,cb,db*cb,cb_size ))
# 确定每个宫格的左上角坐标 00 04 40 44
bgszm=[]
for a in range(0,cb_size,hs+1): # 0-11每隔4,写一个坐标 侧边y
for b in range(0,db_size,hs+1): # 0-11每隔4,写一个坐标 侧边x
bgszm.append('{}{}'.format('%02d'%a,'%02d'%b))
print(bgszm)
# 3宫格排列底3侧2共6套,底边格子数11
# 3宫格排列底3侧2共6套,侧边格子数7
# ['0000', '0004', '0008', '0400', '0404', '0408']
# 转为元祖
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_coord
subgrid_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:
# print(coordinates) # [(4, 8), (4, 9), (4, 10), (5, 8), (5, 9), (5, 10), (6, 8), (6, 9), (6, 10)]
for c in coordinates:
print(c) # 元组 (1, 2) 样式
s = ''.join(str(num).zfill(2) for num in c) # zfill将元组 (1, 2) 转换为字符串 '0102' 特别是(5,10)这种必须转成2个数字0510
print(str(s)) # '12'
bg.append(s) # '0102'
print(bg)
# 生成PDf
P=[]
for z in range(num):
P.clear()
# 制作4份数据
for j in range(db*cb): # 3宫格,4*3=12套
# ————————————————
# 版权声明:本文为CSDN博主「Vaeeeeeee」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
# 原文链接:https://blog.csdn.net/m0_46366547/article/details/131334720
def generate_sudoku_board():
# 创建一个9x9的二维列表,表示数独棋盘
board = [[0] * hs for _ in range(hs)]
# 递归函数,用于填充数独棋盘的每个单元格
def filling_board(row, col):
# 检查是否填充完成整个数独棋盘
if row == hs:
return True
# 计算下一个单元格的行和列索引
next_row = row if col < hs-1 else row + 1
next_col = (col + 1) % hs
import math
r = int(math.sqrt(hs))
print(r)
# 获取当前单元格在小九宫格中的索引
box_row = row // r
box_col = col // r
# 随机生成1到9的数字
numbers = random.sample(range(1, hs+1), hs)
for num in numbers:
# 检查行、列、小九宫格是否已经存在相同的数字
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] = num
# 递归填充下一个单元格
if filling_board(next_row, next_col):
return True
# 回溯,将当前单元格重置为0
board[row][col] = 0
return False
# 填充数独棋盘
filling_board(0, 0)
return board
# 这一块是按照等级随机产生空格,数量不稳定,
# def create_board(level): # level数字越大代表游戏难度越大,空白格子越多
# """
# 生成一个随机的数独棋盘,空白格少
# """
# board = generate_sudoku_board()
# board1 = copy.deepcopy(board)
# for i in range(hs*hs):
# row = i // hs
# col = i % hs
# if random.randint(0, hs) < level: # 随机数量
# board1[row][col] = 0 # 格子填充为0
# return (board,board1)
# if hs==9:
# v = create_board(5)[1]
# print(v)
# if hs==4:
# v = create_board(3)[1]
# print(v)
# 定量出现空白格子
def create_board(): # level数字越大代表游戏难度越大
"""
生成一个随机的数独棋盘,空白格少
"""
board = generate_sudoku_board()
board1 = copy.deepcopy(board)
blanks = random.sample(range(hs*hs), int(hs*hs*kk/10))
for i in blanks:
row = i // hs
col = i % hs
board[row][col] = 0
# if random.randint(0, hs) < level:
# board1[row][col] = 0
return board
v = create_board()
# 数字越小,空格少
# 数字大,空格多
# 这里无法控制空格的数量
# 提取每个元素
for a1 in v: # 第一次读取,[a,b][c,d][e,f]的内容-列表
for a2 in a1: # 第二次读取,[a,b,c,d,e,f]的内容-元素
if a2==0: # 如果某个元素==0,就替换成空
P.append('')
else: # 如果某个元素非0,就写入本身的数字
P.append(a2)
print(P)
print(len(P))
Q=P
doc = Document(path+r'\动物数独(四宫格横板).docx')
# 获取第一个表格,写难度用的
table = doc.tables[0]
for b1 in range(0,2):
# 在'00'单元格中插入文本
cell_00 = table.cell(0, b1)
cell_00_paragraph = cell_00.paragraphs[0]
cell_00_paragraph.text =f"第 {kk} 关"
cell_00_paragraph.style.font.bold = True
cell_00_paragraph.style.font.size = Pt(24)
cell_00_paragraph.style.font.name = "黑体"
cell_00_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
#
table = doc.tables[1] # 表0,表2 写标题用的
# 标题写入3、5单元格
for t in range(0,len(bg)): # 0-5是最下面一行,用来写卡片数字
pp=int(bg[t][0:2]) #
qq=int(bg[t][2:4])
k=str(Q[t]) # 提取list图案列表里面每个图形 t=索引数字
print(pp,qq,k)
# 图案符号的字体、大小参数
run=table.cell(pp,qq).paragraphs[0].add_run(k) # 在单元格0,0(第1行第1列)输入第0个图图案
run.font.name = '黑体'#输入时默认华文彩云字体
# run.font.size = Pt(46) #输入字体大小默认30号 换行(一页一份大卡片
run.font.size = Pt(size) #是否加粗
# run.font.color.rgb = RGBColor(150,150,150) #数字小,颜色深0-255
run.font.color.rgb = RGBColor(50,50,50) #数字小,颜色深0-255
run.bold=True
# paragraph.paragraph_format.line_spacing = Pt(180) #数字段间距
r = run._element
r.rPr.rFonts.set(qn('w:eastAsia'), '黑体')#将输入语句中的中文部分字体变为华文行楷
table.cell(pp,qq).paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER#居中
doc.save(imagePath+r'\{}.docx'.format('%02d'%(z+1)))#保存为XX学号的电话号码word
time.sleep(1)
from docx import Document
from docx.shared import Cm
# 读取四张卡通动物的文件名
animal_path = path+r'\02动物图片' # 替换为实际的文件夹路径
# 获取文件夹中所有文件的完整路径
file_paths = [os.path.join(animal_path, file_name) for file_name in os.listdir(animal_path)]
print(file_paths)
# 把数字1替换成01图片
# 打开Word文档
doc = Document(imagePath+r'\{}.docx'.format('%02d'%(z+1)))
# 获取所有表格
tables = doc.tables
# 遍历每个表格
for table in tables:
# 遍历表格的行
for i, row in enumerate(table.rows):
# 遍历行的单元格
for j, cell in enumerate(row.cells):
# 读取单元格的文本值
cell_text = cell.text
for x in range(0,4):
# 判断单元格的值是否为1
if cell_text == f'{x+1}':
# 删除原来的文本
cell.text = ''
# 插入图片
run = cell.paragraphs[0].add_run()
run.add_picture(file_paths[x], width=Cm(3), height=Cm(3))
# 设置图片对齐方式为居中
run.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
# 设置单元格的水平和垂直对齐方式为居中
cell.vertical_alignment = WD_ALIGN_PARAGRAPH.CENTER
cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
# 保存修改后的文档
doc.save(imagePath+r'\{}.docx'.format('%02d'%(z+1)))
time.sleep(2)
# # 关闭Word文档
# doc.close()
time.sleep(2)
from docx2pdf import convert
# docx 文件另存为PDF文件
inputFile = imagePath+"\{}.docx".format('%02d'%(z+1))# 要转换的文件:已存在
outputFile = imagePath+"\{}.pdf".format('%02d'%(z+1)) # 要生成的文件:不存在
# 先创建 不存在的 文件
f1 = open(outputFile, 'w')
f1.close()
# 再转换往PDF中写入内容
convert(inputFile, outputFile)
print('----------第4步:把都有PDF合并为一个打印用PDF------------')
# 多个PDF合并(CSDN博主「红色小小螃蟹」,https://blog.csdn.net/yangcunbiao/article/details/125248205)
import os
from PyPDF2 import PdfMerger
target_path = imagePath
pdf_lst = [f for f in os.listdir(target_path) if f.endswith('.pdf')]
pdf_lst = [os.path.join(target_path, 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(path+r"\(打印合集) 动物拼图{}宫格难度{} ({}乘{}等于{}套{}人{}份).pdf" .format(hs,kk,db,cb,db*cb,num,num))
file_merger.close()
# doc.Close()
# # print('----------第5步:删除临时文件夹------------')
import shutil
shutil.rmtree(imagePath) #递归删除文件夹,即:删除非空文件夹
time.sleep(3) # 防止转换时报错,预留生成时间
# 最后把PDF合并
import os
from PyPDF2 import PdfMerger, PdfFileReader
# 创建一个PdfMerger对象
merger = PdfMerger()
# 遍历文件夹中的所有PDF文件
folder_path = path
for filename in os.listdir(folder_path):
if filename.endswith('.pdf'):
# 打开PDF文件
pdf_path = os.path.join(folder_path, filename)
pdf_file = open(pdf_path, 'rb')
pdf_reader = PdfFileReader(pdf_file)
# 将PDF文件添加到合并器中
merger.append(pdf_reader)
# 关闭当前打开的PDF文件
pdf_file.close()
# 保存合并后的PDF文件
output_path = path+r"\动物数独4宫格(难度1-9).pdf"
merger.write(output_path)
merger.close()
print("PDF文件合并完成!")
漫长的生成后……
难度1到难度9的9个PDF+动物数独卡片1页PDF(黏贴图)=合并打印PDF
作品展示:
从难度1-难度9的生成的空格数量来看,它是取int的值,也就是只看小数点前面的那个数。
用代码测算一下实际空缺格数量
'''
4宫格难度1-难度9(抽取10%-90%的空格)实际是几个空?
作者:阿夏
时间:2024年4月12日
'''
n=4
g=n*n
for i in range(1,10):
print(f'{n}宫格,难度{i},抽取{i*10}%:实际有{int(g*i*10/100)}空,已有图案{g-int(g*i*10/100)}')
# 4宫格,难度1,抽取10%:实际有1空,已有图案15
# 4宫格,难度2,抽取20%:实际有3空,已有图案13
# 4宫格,难度3,抽取30%:实际有4空,已有图案12
# 4宫格,难度4,抽取40%:实际有6空,已有图案10
# 4宫格,难度5,抽取50%:实际有8空,已有图案8
# 4宫格,难度6,抽取60%:实际有9空,已有图案7
# 4宫格,难度7,抽取70%:实际有11空,已有图案5
# 4宫格,难度8,抽取80%:实际有12空,已有图案4
# 4宫格,难度9,抽取90%:实际有14空,已有图案2
4宫格,难度1,抽取10%:实际有1空,已有图案15
4宫格,难度2,抽取20%:实际有3空,已有图案13
4宫格,难度3,抽取30%:实际有4空,已有图案12
4宫格,难度4,抽取40%:实际有6空,已有图案10
4宫格,难度5,抽取50%:实际有8空,已有图案8
4宫格,难度6,抽取60%:实际有9空,已有图案7
4宫格,难度7,抽取70%:实际有11空,已有图案5
4宫格,难度8,抽取80%:实际有12空,已有图案4
4宫格,难度9,抽取90%:实际有14空,已有图案2
以4宫格 | 16格 | 为例 | ||
序号 | 难度 | 空格比例 | 空格数 | 图案数量 |
1 | 难度1 | 10% | 1 | 15 |
2 | 难度2 | 20% | 3 | 13 |
3 | 难度3 | 30% | 4 | 12 |
4 | 难度4 | 40% | 6 | 10 |
5 | 难度5 | 50% | 8 | 8 |
6 | 难度6 | 60% | 9 | 7 |
7 | 难度7 | 70% | 11 | 5 |
8 | 难度8 | 80% | 12 | 4 |
9 | 难度9 | 90% | 14 | 2 |