Python编码实现自动生成三阶幻方和24点试卷

三阶幻方是一种特殊的方阵,由3行3列的格子组成,其中每个格子都填有一个不同的整数,使得每行、每列和每条对角线上的三个数之和都相等。三阶幻方有8种不同的解法。

24点是一种纸牌游戏,使用一副扑克牌,去掉大小王后,将剩下的52张牌随机排列。游戏的目标是通过组合四张牌的数字和运算符,得到24这个结果。每张牌的面值可以是从1到10的任意整数,而运算符可以是加、减、乘、除。游戏中可以任意改变数字之间的顺序,但是每个数字只能使用一次。如果能找到一种运算方式,让四张牌的数字运算结果等于24,就算胜利。

为了便于学生练习三阶幻方和24点,利用Python编码自动生成练习卷。具体实现如下:

import numpy as np  
from docx import Document  
from docx.shared import Inches  
import random  
bHasAnswer = True
# 顺时针旋转90度的函数  
def rotate_90_degrees(matrix):  
    return matrix.T[:, ::-1] 

# 生成随机数并加到幻方上的函数  
def add_random_numbers(magic_square):  
    random_number = random_number = np.random.randint(0, 80) 
    return magic_square + random_number  

def generate_magic_square():  
    magic_square = np.zeros((3, 3), dtype=int)  # 初始化一个3x3的零矩阵  
    magic_square[0, 1] = 1  # 从中间位置开始填充数字1  
    i, j = 0, 1  # 初始化位置为第一行第二列  
  
    for num in range(2, 10):  # 从2开始填充到9  
        # 计算下一个位置  
        next_i = (i - 1) % 3  
        next_j = (j + 1) % 3  
          
        # 如果下一个位置已经被填充,则尝试另一个位置  
        if magic_square[next_i, next_j] != 0:  
            next_i = (i + 1) % 3  
            next_j = j  
          
        # 放置当前数字  
        magic_square[next_i, next_j] = num  
          
        # 更新当前位置  
        i, j = next_i, next_j  
  
    # 计算幻方的常数和  
    constant_sum = np.sum(magic_square[0])  # 任何一行、列或对角线的和都应该等于这个值  
      
    # 验证生成的幻方是否有效  
    assert np.all(np.sum(magic_square, axis=0) == constant_sum), "Rows do not sum to the constant."  
    assert np.all(np.sum(magic_square, axis=1) == constant_sum), "Columns do not sum to the constant."  
    assert np.sum(np.diag(magic_square)) == constant_sum, "Main diagonal does not sum to the constant."  
    assert np.sum(np.diag(np.fliplr(magic_square))) == constant_sum, "Antidiagonal does not sum to the constant."  
    randomCount = np.random.randint(0, 3) 
    for i in range(randomCount):
        magic_square = rotate_90_degrees(magic_square)  
  
    # 加上随机数  
    random_magic_square = add_random_numbers(magic_square)  
    return random_magic_square  
  
# 调用函数并打印生成的幻方  
magic_square = generate_magic_square()  
print(magic_square)

import random  

def is_same_row(coords):  
    """判断三个坐标是否在同一行"""  
    return all(coord[0] == coords[0][0] for coord in coords)  
  
def is_same_col(coords):  
    """判断三个坐标是否在同一列"""  
    return all(coord[1] == coords[0][1] for coord in coords)  
  
def is_same_diagonal(coords):  
    """判断三个坐标是否在同一斜线上"""  
    # 检查主对角线(从左上到右下)  
    if all(coord[0] - coord[1] == coords[0][0] - coords[0][1] for coord in coords):  
        return True  
    # 检查副对角线(从右上到左下)  
    if all(coord[0] + coord[1] == coords[0][0] + coords[0][1] for coord in coords):  
        return True  
    return False  
  
def are_not_same_row_or_col(coords):  
    """判断三个坐标是否非同行同列"""  
    return not (is_same_row(coords) or is_same_col(coords))  
  
def is_in_special_relation(coords):  
    """判断三个坐标是否满足同行、同列、同一斜线中的任一条件"""  
    return is_same_row(coords) or is_same_col(coords) or is_same_diagonal(coords) 
 
# 定义一个函数来检查一个数是否是另一个数的对边数  
def is_opposite_side(coord1, coord2):  
    x1, y1 = coord1  
    x2, y2 = coord2  
    return (x1, (y2 + 1) % 3) == coord2 or ((x1 + 1) % 3, y1) == coord2 or (x2, (y1 + 1) % 3) == coord1 or ((x2 + 1) % 3, y2) == coord1  
  
# 随机选择三个坐标,避免两个都是对边坐标  
def select_non_paired_coordinates():  
    # 获取幻方中的所有坐标  
    coordinates = [(i, j) for i in range(3) for j in range(3)]  
      
    # 随机选择一个顶点坐标  
    first_coord = random.choice(coordinates)  
      
    excluded_coords = []  
    excluded_coords.append(first_coord)
      
    # 从剩下的坐标中随机选择第二个坐标  
    remaining_coords = [coord for coord in coordinates if coord not in excluded_coords]  
    second_coord = random.choice(remaining_coords)  
    excluded_coords.append(second_coord)

    
    remaining_coords = [coord for coord in coordinates if coord not in excluded_coords and not is_in_special_relation([first_coord, second_coord, coord])]
    third_coord = random.choice(remaining_coords) 
      
    return first_coord, second_coord, third_coord 
  
# 生成题目和答案的函数  
def generate_question_and_answer(magic_square):  
    
    # 题目表格  
    question_table = [  
        [' ', ' ', ' '],  
        [' ', ' ', ' '],  
        [' ', ' ', ' ']  
    ]  
    
    # 选择位置并打印结果  
    selected_pos = select_non_paired_coordinates()
    print(selected_pos)
    for i in range(3):  
        for j in range(3):  
            if (i, j) in selected_pos:  
                question_table[i][j] = magic_square[i][j].astype(str) 
    
    # 答案表格  
    answer_table = magic_square.astype(str).tolist()  
      
    # 将表格转换为文本  
    def table_to_text(table):  
        return '\n'.join(['\t'.join(row) for row in table])  
      
    question = f"\n{table_to_text(question_table)}"  
    answer = f"\n{table_to_text(answer_table)}"  
      
    return question_table, answer_table  

# 尝试生成一个答案(这只是一个示例,可能不是有效的答案)  
def generate_answer(numbers):  
    operations = ['+', '-', '*', '/']  
    for op1 in operations:  
        for op2 in operations:  
            for i in range(4):  
                for j in range(4):  
                    if i != j:  
                        try:  
                            expr = f"({numbers[i]}{op1}{numbers[j]})"  
                            if op1 == '/' and numbers[i] < numbers[j]:
                                continue
                            result1 = eval(expr)  
                            for k in range(4):  
                                if k not in (i, j):  
                                    for l in range(4):  
                                        if l not in (i, j, k):  
                                            expr2 = f"({result1}{op2}{numbers[k]})"  
                                            if op2 == '/' and numbers[i] < numbers[j]:
                                                continue
                                            result2 = eval(expr2)  
                                            if abs(eval(f"{result2}{op2}{numbers[l]}") - 24) < 0.0001:  
                                                return f"{numbers[i]}{op1}{numbers[j]}{op2}{numbers[k]}{op2}{numbers[l]} = 24"  
                        except ZeroDivisionError:  
                            continue  
    return "" 

# 生成一个随机的24点题目  
def generate_24_point_question():  
    numbers = [random.randint(1, 9) for _ in range(4)]  
    numbers.sort()  # 对数字进行排序,使得题目更有序  
    answer = generate_answer(numbers)
    while answer == "":
        numbers = [random.randint(1, 9) for _ in range(4)]  
        numbers.sort()  # 对数字进行排序,使得题目更有序  
        answer = generate_answer(numbers)
    question = f"用{numbers[0]}{numbers[1]}{numbers[2]}{numbers[3]}这四个数,通过加、减、乘、除(每个数只能用一次),使其结果等于24。请问如何计算?"  
    return question, answer

from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT  
from docx.shared import Cm 
from docx.shared import Pt
from docx.enum.text import WD_BREAK 

for index in range(20):
    # 创建Word文档  
    doc = Document()  
    headingStr = '2024年XX小学数学能力比赛三阶幻方和24点练习' + str(index+1)
    # 创建页眉  
    header = doc.sections[0].header  
    paragraph = header.paragraphs[0]  
    run = paragraph.add_run(headingStr)  
    run.font.size = Pt(8)  # 设置字体大小  
    paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 设置居中对齐  
  
    # 创建页脚  
    footer = doc.sections[0].footer  
    if not footer.paragraphs:  
        footer_paragraph = footer.add_paragraph()  
    else:  
        footer_paragraph = footer.paragraphs[0]  
  
    # 添加一些文本到页脚  
    footer_run = footer_paragraph.add_run(headingStr)  
    footer_run.font.size = Pt(8)  # 设置字体大小  
    footer_paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER  # 设置居中对齐  
  
    # 添加标题  
    doc.add_heading(headingStr, 1)  
    doc.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
    # 生成20题  
    doc.add_paragraph('一、请完成以下20题三阶幻方:')
    answers = []
    for id in range(20):  
        magic_square = generate_magic_square()  
        question, answer = generate_question_and_answer(magic_square)  
        answers.append(answer)
        # 添加题目  
        doc.add_paragraph('幻方题'+str(id+1)+':')  
        table = doc.add_table(rows=3, cols=3, style='Table Grid') 
        # 填充表格  
        for i in range(3):  
            table.columns[i].width = Cm(1) 
            for j in range(3):  
                cell = table.cell(i, j)  
                cell.text = question[i][j]  # 将整数转换为字符串并添加到单元格中
                cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER
        # 添加分隔线  
        if ((id+1) % 8) == 0:
            paragraph = doc.add_paragraph()  
            paragraph.add_run().add_break(WD_BREAK.PAGE)  
    doc.add_paragraph('二、请完成以下20题24点:')
    answers24 = []
    for id in range(20):
        question,answer = generate_24_point_question()  
        answers24.append(answer)
        doc.add_paragraph('24点题'+str(id+1)+':'+question+'\n')  
    if bHasAnswer:
        paragraph = doc.add_paragraph()  
        paragraph.add_run().add_break(WD_BREAK.PAGE) 
        doc.add_heading('幻方和24点答案:', 1)
        for id in range(20):  
            # 添加答案  
            doc.add_paragraph('幻方题'+str(id+1)+':')  
            table = doc.add_table(rows=3, cols=3, style='Table Grid') 
            answer = answers[id]
            # 填充表格  
            for i in range(3):  
                table.columns[i].width = Cm(1) 
                for j in range(3):  
                    cell = table.cell(i, j)  
                    cell.text = answer[i][j]  # 将整数转换为字符串并添加到单元格中
                    cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER 
            # 添加分隔线  
            if ((id+1) % 8) == 0:
                paragraph = doc.add_paragraph()  
                paragraph.add_run().add_break(WD_BREAK.PAGE)  
        doc.add_paragraph('\n-----------------------------------------------------------------------------------------------------------')
        for id in range(10):  
            # 添加答案 
            doc.add_paragraph('24点题'+str(id*2+1)+':'+answers24[id*2] + '\t24点题'+str(id*2+2)+':'+answers24[id*2+1])    
  
    # 保存Word文档  
    doc.save('D://doclibs//'+headingStr+'.docx')
  • 20
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

imgsq

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值