gpt-4o继续迭代考场安排程序 一键生成考场清单

news2024/11/16 13:27:07

        接上两篇gpt-4o考场安排-CSDN博客,考场分层次安排,最终exe版-CSDN博客

当然你也可以只看这一篇。

今天又添加了以下功能,程序见后。

1、自动分页,每个考场打印一页

2、添加了打印试场单页眉

3、添加了页脚 第X页,其X页, 打印时间

表结构

程序运行界面

测试分配考场环境,共15个班分为两个层次由字段“层次”指定a, b。a层次9个考场,b层次15个,从b层开始编号,a层次考场号从16开编。

预览结果b层次

层次a预览结果

完整程序


import sys

import pandas as pd

import random

import openpyxl

from openpyxl.worksheet.pagebreak import Break

from openpyxl.styles import Font, Alignment, PatternFill, Border, Side

from openpyxl.worksheet.page import PageMargins

from datetime import datetime

from PyQt5.QtWidgets import (

    QApplication, QLabel, QLineEdit, QPushButton, QFileDialog,

    QVBoxLayout, QWidget, QMessageBox

)

from PyQt5.QtGui import QFont as QPyQtFont


def load_data(filename):
    return pd.read_excel(filename)


def save_data(df, filename, exam_name):
    df.to_excel(filename, index=False)

    format_excel(filename, df, exam_name)


def assign_seats(df, total_halls, start_hall=1):
    grouped = df.groupby('班级')

    groups = [group.sample(frac=1).reset_index(drop=True) for _, group in grouped]

    groups.sort(key=lambda x: len(x), reverse=True)

    iterators = [iter(group.iterrows()) for group in groups]

    arranged_data = []

    hall_number = start_hall

    seat_number = 1

    total_students = len(df)

    students_per_hall = total_students // total_halls

    extra_students = total_students % total_halls

    while iterators:

        random.shuffle(iterators)

        for it in iterators[:]:

            try:

                _, student = next(it)

                student_data = student.to_dict()

                student_data["考场"] = hall_number

                student_data["考号"] = f"{seat_number:02d}"

                arranged_data.append(student_data)

                seat_number += 1

                if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):
                    hall_number += 1

                    seat_number = 1

                if hall_number >= start_hall + total_halls:
                    hall_number = start_hall

            except StopIteration:

                iterators.remove(it)

    return arranged_data


def check_and_adjust_seating(arranged_data):
    def has_adjacent_same_class(data):

        for i in range(len(data) - 1):

            if data[i]['班级'] == data[i + 1]['班级']:
                return i

        return -1

    def find_valid_swap(index, data):

        current_class = data[index]['班级']

        for j in range(len(data)):

            if j != index and data[j]['班级'] != current_class:

                if (j == 0 or data[j - 1]['班级'] != current_class) and (

                        j == len(data) - 1 or data[j + 1]['班级'] != current_class):
                    return j

        return -1

    swap_operations = []

    while True:

        index = has_adjacent_same_class(arranged_data)

        if index == -1:
            break

        swap_index = find_valid_swap(index + 1, arranged_data)

        if swap_index == -1:
            raise ValueError("Cannot find a valid swap to adjust the seating arrangement.")

        swap_operations.append((index + 1, swap_index))

        arranged_data[index + 1], arranged_data[swap_index] = arranged_data[swap_index], arranged_data[index + 1]

    return arranged_data, swap_operations


def reassign_seats(arranged_data, total_halls, start_hall=1):
    hall_number = start_hall

    seat_number = 1

    total_students = len(arranged_data)

    students_per_hall = total_students // total_halls

    extra_students = total_students % total_halls

    for i, student in enumerate(arranged_data):

        student['考场'] = hall_number

        student['考号'] = f"{seat_number:02d}"

        seat_number += 1

        if seat_number > students_per_hall + (1 if hall_number - start_hall + 1 <= extra_students else 0):
            hall_number += 1

            seat_number = 1

        if hall_number >= start_hall + total_halls:
            hall_number = start_hall

    return arranged_data


def format_excel(filename, df, exam_name):

    if '层次' in df.columns:

        df = df.drop(columns=['层次'])



    wb = openpyxl.Workbook()

    ws = wb.active

    ws.title = "考场安排结果"



    # 将标题从第一行开始写入

    for col_num, column_title in enumerate(df.columns, 1):

        cell = ws.cell(row=1, column=col_num, value=column_title)

        cell.font = Font(bold=True, color="FFFFFF", size=16)

        cell.fill = PatternFill(start_color="4F81BD", end_color="4F81BD", fill_type="solid")

        cell.alignment = Alignment(horizontal="center", vertical="center")



    for row_num, row_data in enumerate(df.itertuples(index=False, name=None), 2):

        for col_num, cell_value in enumerate(row_data, 1):

            ws.cell(row=row_num, column=col_num, value=cell_value)



    for col in ws.columns:

        max_length = 0

        column = col[0].column_letter

        # Check if the column header is "考号"

        if ws.cell(row=1, column=col[0].col_idx).value == "考号":

            adjusted_width = 20  # 设置考号列的宽度为20

        else:

            for cell in col:

                if cell.value is not None:

                    max_length = max(max_length, len(str(cell.value)))

            adjusted_width = max_length + 10

        ws.column_dimensions[column].width = adjusted_width



    # 调整页面边距

    ws.page_margins = PageMargins(left=1.5, right=0.75, top=1.2, bottom=0.5)



    ws.print_title_rows = '1:1'  # 标题行在第一行开始

    ws.page_setup.orientation = 'portrait'

    ws.page_setup.paperSize = ws.PAPERSIZE_A4

    ws.page_setup.fitToPage = True

    ws.page_setup.fitToWidth = 1

    ws.page_setup.fitToHeight = False

    ws.page_setup.horizontalCentered = True

    ws.page_setup.verticalCentered = True



    page_height_in_inches = 11.69 - ws.page_margins.top - ws.page_margins.bottom

    page_height_in_points = page_height_in_inches * 72

    header_height_in_points = 50

    available_row_height_in_points = page_height_in_points - header_height_in_points



    hall_groups = df.groupby('考场')

    previous_max_row = 1  # 前一个最大行号调整为1以考虑空行

    thin_border = Border(left=Side(style='thin'), right=Side(style='thin'), top=Side(style='thin'), bottom=Side(style='thin'))

    for hall_number, (hall_id, hall_df) in enumerate(hall_groups):

        row_count = len(hall_df) + 1

        max_row = hall_df.index[-1] + 2  # 从第二行开始每个考场的数据

        row_height = available_row_height_in_points / row_count

        row_height = max(row_height, 15)

        for row in range(previous_max_row, max_row + 1):

            ws.row_dimensions[row].height = row_height

            for cell in ws[row]:

                cell.border = thin_border

                cell.font = Font(size=15)

                cell.alignment = Alignment(horizontal="center", vertical="center")

        if max_row < ws.max_row:

            ws.row_breaks.append(Break(max_row))

        previous_max_row = max_row + 1



    # 添加页眉和页脚,并使用制表符来向左移动页眉

    ws.oddHeader.center.text = f"&\"微软雅黑,Bold\"&20\t{exam_name}"  # 添加制表符以向左移动

    ws.oddFooter.center.text = "第 &P 页,共 &N 页"

    ws.oddFooter.right.text = f"&D &T"



    wb.save(filename)


def dataframe_to_rows(df, index=True, header=True):
    if header:

        rows = [list(df.columns)]

    else:

        rows = [[]]

    for row in df.itertuples(index=index, name=None):
        rows.append(list(row)[1:])

    return rows


def run_allocation(input_filename, a_total_halls, b_total_halls, start_level, exam_name):
    df = load_data(input_filename)

    if start_level == 'b':

        other_level = 'a'

        first_total_halls = b_total_halls

        second_total_halls = a_total_halls

    else:

        other_level = 'b'

        first_total_halls = a_total_halls

        second_total_halls = b_total_halls

    first_level_students = df[df['层次'] == start_level]

    arranged_first_students = assign_seats(first_level_students, first_total_halls, start_hall=1)

    adjusted_first_students, _ = check_and_adjust_seating(arranged_first_students)

    final_first_students = reassign_seats(adjusted_first_students, first_total_halls, start_hall=1)

    second_level_students = df[df['层次'] == other_level]

    arranged_second_students = assign_seats(second_level_students, second_total_halls, start_hall=first_total_halls + 1)

    adjusted_second_students, _ = check_and_adjust_seating(arranged_second_students)

    final_second_students = reassign_seats(adjusted_second_students, second_total_halls,
                                           start_hall=first_total_halls + 1)

    combined_students = final_first_students + final_second_students

    arranged_df = pd.DataFrame(combined_students)

    current_time = datetime.now().strftime("%Y%m%d_%H%M%S")

    output_filename = f"考场安排结果_{current_time}.xlsx"

    save_data(arranged_df, output_filename, exam_name)

    return output_filename


class ExamArrangementApp(QWidget):

    def __init__(self):

        super().__init__()

        self.initUI()

    def initUI(self):

        layout = QVBoxLayout()

        font = QPyQtFont("Arial", 14)

        self.file_label = QLabel('选择文件:')

        self.file_label.setFont(font)

        layout.addWidget(self.file_label)

        self.file_btn = QPushButton('选择文件')

        self.file_btn.setFont(font)

        self.file_btn.clicked.connect(self.select_file)

        layout.addWidget(self.file_btn)

        self.exam_name_label = QLabel('考试名称:')

        self.exam_name_label.setFont(font)

        layout.addWidget(self.exam_name_label)

        self.exam_name_input = QLineEdit()

        self.exam_name_input.setFont(font)

        layout.addWidget(self.exam_name_input)

        self.a_halls_label = QLabel('A层次考场数:')

        self.a_halls_label.setFont(font)

        layout.addWidget(self.a_halls_label)

        self.a_halls_input = QLineEdit()

        self.a_halls_input.setFont(font)

        layout.addWidget(self.a_halls_input)

        self.b_halls_label = QLabel('B层次考场数:')

        self.b_halls_label.setFont(font)

        layout.addWidget(self.b_halls_label)

        self.b_halls_input = QLineEdit()

        self.b_halls_input.setFont(font)

        layout.addWidget(self.b_halls_input)

        self.start_level_label = QLabel('首先开始编号的层次 (a/b):')

        self.start_level_label.setFont(font)

        layout.addWidget(self.start_level_label)

        self.start_level_input = QLineEdit()

        self.start_level_input.setFont(font)

        layout.addWidget(self.start_level_input)

        self.run_btn = QPushButton('运行')

        self.run_btn.setFont(font)

        self.run_btn.clicked.connect(self.run)

        layout.addWidget(self.run_btn)

        self.setLayout(layout)

        self.setWindowTitle('考场安排工具,By Bobo googaobo@gmail.com')

        self.resize(900, 630)

        self.center()

    def select_file(self):

        options = QFileDialog.Options()

        options |= QFileDialog.DontUseNativeDialog

        file_name, _ = QFileDialog.getOpenFileName(self, "选择Excel文件", "", "Excel Files (*.xlsx);;All Files (*)",
                                                   options=options)

        if file_name:
            self.file_label.setText(f'文件: {file_name}')

            self.input_filename = file_name

    def run(self):

        try:

            a_total_halls = int(self.a_halls_input.text())

            b_total_halls = int(self.b_halls_input.text())

            start_level = self.start_level_input.text()

            exam_name = self.exam_name_input.text()

            output_filename = run_allocation(self.input_filename, a_total_halls, b_total_halls, start_level, exam_name)

            QMessageBox.information(self, "成功", f"已成功生成文件:{output_filename}", QMessageBox.Ok)

        except Exception as e:

            QMessageBox.critical(self, "错误", str(e), QMessageBox.Ok)

    def center(self):

        qr = self.frameGeometry()

        cp = self.screen().availableGeometry().center()

        qr.moveCenter(cp)

        self.move(qr.topLeft())


if __name__ == '__main__':
    app = QApplication(sys.argv)

    ex = ExamArrangementApp()

    ex.show()

    sys.exit(app.exec_())

程序已打包exe,点赞留言QQ,发送程序。程序运行中有问题请评论区留言交流!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1688343.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

tomcat--安全配置多虚拟机

端口8005/tcp 安全配置管理 8005是Tomcat的管理端口&#xff0c;默认监听在127.0.0.1上。无需验证就可发送SHUTDOWN (大小写敏感)这个字符串&#xff0c;tomcat接收到后就会关闭此Server。此管理功能建议禁用&#xff0c;可将SHUTDOWN改为一串猜不出的字符串实现或者port修改成…

用手机打印需要下载什么软件

在快节奏的现代生活中&#xff0c;打印需求无处不在&#xff0c;无论是工作文件、学习资料还是生活小贴士&#xff0c;都可能需要一纸呈现。然而&#xff0c;传统的打印方式往往受限于时间和地点&#xff0c;让人倍感不便。今天&#xff0c;就为大家推荐一款便捷又省钱的手机打…

第三讲 栈、队列和数组 (1)

文章目录 第三讲 栈、队列和数组3.1 栈3.1.1 出栈元素的不同排列与卡特兰数3.1.2 栈的顺序表实现3.1.3共享栈3.1.4 栈的链表实现3.1.5 栈的两种实现的优缺点3.1.6 c中的栈( s t a c k stack stack)容器适配器3.1.7 栈的应用:star:3.1.7.1 **栈在括号匹配中的应用**3.1.7.2 **栈…

9.STL中list的常见操作(图文并茂)

目录 1.list的介绍及使用 1.1.list的构造 1.2 list iterator的使用 1.3. list capacity 1.4.list modifiers 1.5.list的迭代器失效 1.list的介绍及使用 list介绍 &#xff0c;可以通过以下图直观的感受到 vector 和 list 的区别 Vector 插入代价高&#xff0c;但便于排…

Java中String类常用方法

写笔记记录自己的学习记录以及巩固细节 目录 1.String类的常用方法 1.1 字符串构造 1.2 String对象的比较 1.2.1 比较两个字符串是否相等 1.2.2 比较两个字符串的大小 1.3 字符串查找 1.4 字符串的转化 1.4.1 字符串转整数 1.4.2 字符串转数字 1.4.3 大小写的转换 1…

[Redis]使用和原理

Redis介绍 Redis 是⼀种基于键值对的 NoSQL 数据库&#xff0c; Redis 可以满足很多的应用场景&#xff0c;而且因为 Redis 会将所有数据都存放再内存中&#xff0c;所以它的读写性能非常惊人。不仅如此&#xff0c;Redis 还可以将内存的数据利用快照和日志的形式保存到硬盘上…

数据库的事务四大特性(ACID)以及详解隔离性以及隔离级别

目录 一、事务相关概念 1、事务 2、事务的本质 3、回滚 4、事务使用 5、事务的四大特性 1、原子性&#xff08;Atomicity&#xff09; 2、一致性&#xff08;Consistency&#xff09; 3、隔离性&#xff08;Isolation&#xff09; 4、持久性&#xff08;Durability&a…

专业级润滑油,一站式批发服务

要为机械设备提供持久稳定的动力保障吗&#xff1f;选择我们的专业级润滑油&#xff0c;让您的设备运转更顺畅&#xff0c;效率更高。 我们专业从事润滑油批发多年&#xff0c;以优质的产品、合理的价格和完善的服务赢得了广大客户的信赖。无论是汽车、机械还是工业设备&#x…

Python中动态调用C#的dll动态链接库中方法

在Python中调用C#的dll库_哔哩哔哩_bilibili 环境准备&#xff1a; 安装 pythonnet pip install pythonnet在Python中调用C#动态链接库&#xff08;DLL&#xff09;&#xff0c;可以使用pythonnet库&#xff0c;它允许直接使用 .NET 的程序集。以下是一个示例&#xff0c;…

话题:如何让大模型变得更聪明?

随着人工智能&#xff08;AI&#xff09;技术的迅速发展&#xff0c;大模型&#xff08;如GPT-4、BERT、Transformer等&#xff09;在自然语言处理、图像识别和语音识别等领域取得了显著成果。然而&#xff0c;如何让大模型变得更聪明&#xff0c;进一步提升其性能和应用效果&a…

Softing工业推出新品edgeGate:一款用于工业边缘和云应用的硬件网关

2024年4月17日&#xff08;哈尔&#xff09;&#xff0c;Softing工业自动化在2024年汉诺威工业博览会上首次展示了新品edgeGate。该产品是一个无需维护的硬件物联网网关解决方案&#xff0c;可将生产数据从PLC和数控机床控制器传输至工业边缘及物联网云平台。 &#xff08;edge…

重学java 38.创建线程的方式⭐

It is during our darkest moments that we must focus to see the light —— 24.5.24 一、第一种方式_继承extends Thread方法 1.定义一个类,继承Thread 2.重写run方法,在run方法中设置线程任务(所谓的线程任务指的是此线程要干的具体的事儿,具体执行的代码) 3.创建自定义线程…

光伏企业都在用的户用光伏管理软件——鹧鸪云

随着全球对可再生能源和清洁能源的需求日益增长&#xff0c;光伏产业作为其中的佼佼者&#xff0c;正迎来前所未有的发展机遇。然而&#xff0c;随着光伏电站规模的扩大和分布范围的增加&#xff0c;如何高效、智能地管理这些电站&#xff0c;确保它们稳定、安全地运行&#xf…

做好商业分析,帮你用有限的资源选择高效益项目实现战略目标

对于组织来说&#xff0c;资源条件总是有限的&#xff0c;为了实现战略目标&#xff0c;则需要从众多项目中筛选出最合适的项目来实现收益。但项目的筛选往往会遇到很多难点&#xff0c;如信息收集不全影响筛选的准确性、评估标准不明确或难以量化、决策过程复杂等等。 那么如何…

【NumPy】关于numpy.reshape()函数,看这一篇文章就够了

&#x1f9d1; 博主简介&#xff1a;阿里巴巴嵌入式技术专家&#xff0c;深耕嵌入式人工智能领域&#xff0c;具备多年的嵌入式硬件产品研发管理经验。 &#x1f4d2; 博客介绍&#xff1a;分享嵌入式开发领域的相关知识、经验、思考和感悟&#xff0c;欢迎关注。提供嵌入式方向…

java如何获取IP和IP的归属地?

在Java中&#xff0c;获取IP地址通常指的是获取本地机器的IP地址或者通过某种方式&#xff08;如HTTP请求&#xff09;获取的远程IP地址。代码案例如下: 而要获取IP的归属地&#xff08;地理位置信息&#xff09;&#xff0c;则通常需要使用第三方IP地址查询服务&#xff0c;我…

【JAVA |再谈接口、Object、内部类】Object类中子类重写,Cloneable 接口、比较器、内部类

✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天开心哦&#xff01;✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; &#x1f388;丠丠64-CSDN博客&#x1f388; ✨✨ 帅哥美女们&#xff0c;我们共同加油&#xff01;一起…

element-plus:踩坑日记

el-table Q&#xff1a;有fixed属性时&#xff0c;无数据时&#xff0c;可能出现底部边框消失的bug 现象&#xff1a; 解决方法&#xff1a; .el-table__empty-block {border-bottom: 1px solid var(--el-table-border-color); } el-collapse 折叠面板 Q&#xff1a;标题上…

Java操作Word文档,根据模板生成文件

Java操作Word文档 poi-tl介绍 官方文档&#xff1a;https://deepoove.com/poi-tl/ poi-tl&#xff08;poi template language&#xff09;是Word模板引擎&#xff0c;使用模板和数据创建很棒的Word文档。 在文档的任何地方做任何事情&#xff08;Do Anything Anywhere&#…

在全志H616核桃派开发板上配置I2C引脚并读取温度数据

配置引脚 找到板子上的i2c引脚 为了方便查找&#xff0c;我们加入了一个显示功能引脚位置的功能&#xff0c;运行以下命令&#xff0c;查看板子的40pin引脚上有几个可用i2c gpio pin i2c启用i2c 我们使用set-device指令来使能/关闭指定设备的底层驱动&#xff0c;使能后&am…