高考已经结束,先预祝各位考生成绩如意!

虽然在学校里工作了那么久,却没有留意过从哪一年开始高考由七月改到了六月。只是每到南风吹起、凤凰花开的时节,便会发现朋友圈里挂出了好多毕业照,于是就会想起1996年的7月9日,和随之而来的20年校园生活 ……

说到毕业照,我们上期公众号里解析的“Excel自动全家福”受到了很多朋友的关注。

在上次的文章里,杨老师分析了上财陈同学这个VBA程序的实现技巧,也就是怎样把图片随机排列到事先画好的合并单元格中,并且自动裁剪对齐。

文中的一句话引起了很多同学的兴趣,那就是“如果愿意投入更多的精力,我们可以把合并单元格的布局也交给程序去自动生成,而不是事先由人工划分好”。所以今天我们就接着分析一下这个有趣的小问题:给定一个矩形区域,怎样将其随机分割成若干个小矩形

比如下面这个Excel表格中,如果我们要把32张照片随机放置到B2:N8区域,也就是7行13列的矩形中,该怎样编写程序呢?考虑到这几周公众号讲的都是VBA,今天我们改用Python试一试。

ukd

一、 整体思路

相信很多同学看到这个问题时都会觉得无从下手,毕竟涉及图形、又要求像拼瓷砖一样对齐工整,恐怕手工设计也要费一些波折才行。不过实际上,这个问题并没有我们想的那么复杂,因为咱们小学时就已经做过类似的甚至更复杂的题目:

这是一道几乎所有人都见过的题目,标准答案是“3刀”,也就是前两刀切出十字形,然后在蛋糕中层横切,变成8块。杨老师当年回答了“4刀”,结果没有得分,对此本人至今仍不服气:大多数蛋糕都是上面奶油下面松饼,如果横切成8块,岂不是4块全奶油、4块全松饼,怎么分?你分?你细分!

不好意思跑题了。回到“划分矩形”这个问题上,道理其实是一样的:我们可以先把整个“全家福”区域看作一个大的矩形(蛋糕),然后在它的范围里随机生成一条横线或竖线,就可以把它分成两个小矩形。然后在这两个小矩形中随机挑出一个,再在它的范围里随机生成一条横线或竖线,就可以把这个小矩形划分为两个小小矩形”。这样经过两次操作,我们就把原区域随机划分成三个矩形。

以此类推,如果我们想划分为4个随机矩形,只要执行一步:从上面这三个矩形中随机选取一个、然后在它的范围里随机生成一个横线或竖线即可。

因此我们就得到了一个很好理解的算法:每次在区域内随机挑一个矩形(开始时一共只有一个矩形,就是这个区域本身),然后在它内部随机生成一个横线或竖线,如此反复。这样执行N次操作,就可以得到N+1个随机矩形。

ukd

二、 怎样表示和分割“矩形”

思路有了,但是要想变成程序代码,却还有一个坎要迈:怎样把“矩形”、“线段”这些几何形状写到代码里处理?

其实也很简单:一个矩形不过就是4个端点”的组合。比如上面划分为4个矩形的表格中,左上角第一个矩形C2:F4可以表示为 (2, 3, 4, 6) ,也就是左上角为第2行第3列(即C2)、右下角为第4行第6列(即F4)。同理,最右侧的矩形可以表示为(2, 8, 5, 9),也就是左上角H2、右下角I5

(2, 3, 4, 6) 对应到Python代码,显然就是我们在《全民一起玩Python 基础篇》中学过的概念:元组。更进一步,如果用1个元组表示1个矩形,那么4个矩形就要用4个元组。所以我们可以创建一个列表,把这些元组都装进去,于是这个列表就代表了当前已经划分出来的“所有矩形”。

当然,程序刚开始运行时,整个区域还从来没有划分过,所以只有一个矩形,因此列表中也只有一个元组。而接下来的任务,就是在这个矩形区域中随机找两个点(也就是一条线段),把它划成两个区域。怎样随机生成这两个点呢?

假设这个矩形(也就是一个元组)是用 r 来代表,比如 r = (2,3,4,6),也就是下面的图形。那么我们可以知道:它的宽度范围是从第3列到第6列,也就是 (r[1] , r[3] ) ,而它的高度范围则是从第2行到第4行,也就是 ( r[0] , r[2] ) 。

那么如果我们想在矩形 中生成一个随机竖线,从而将其划分为左右两个矩形,只需要调用Pythonrandom模块,生成一个 3到5之间的随机数即可,也就是 random.randint( r[1] , r[3]-1 ) 。假如这一次生成的随机数是 5 ,那么就相当于把第5列(E列)作为分割线(严格的说,是把E列作为第一个矩形的边界),也就是分成下面两个矩形:

用Python形式描述就是:

1. 取出原矩形 r = (2,3,4,6) 的宽度范围 (3,6) ,也就是 r[1] 和 r[3]

2. 生成该范围(左闭右开区间)内的随机数 randint( r[1], r[3]-1) ,得到一个随机数 x (假设为5)

3. 创建两个新的矩形元组:r1=(2,3,4,5) 和 r2=(2,6,4,6) ,也就是 (r[0],r[1],r[2], x ) 和 (r[0], x+1 , r[2], r[3] )

显然,这两个新的元组就是我们随机划分出的两个“小矩形”,把它们添加到列表中,我们的“全部矩形”就被更新为划分后的状态了。

不过还有一个步骤不要忘记:既然列表中原来的矩形元组 r 被分成了r1和 r2 两个新的矩形元组,那么原来的矩形 r 也就没有存在意义,应该从列表中删除掉。

所以把上面的过程写成代码,就是下面的样子:

上面的代码实现了“按照宽度进行一次横向拆分”。同样的思路,我们也可以实现“按照高度纵向拆分”,也就是取行号 r[0] 和 r[2] 之间的随机数 x ,然后用 (r[0], r[1], x, r[3] ) 和 (x+1 , r[1], r[2], r[3] ) 得到两个新矩形。

ukd

三、 最终方案

上面的代码实现了“拆分一次”,那么如果我们需要拆成20个矩形,只要把这段代码循环19次就够了。具体来说,还是从只包含一个矩形的列表开始,然后做一个19次的循环,每次循环都从列表中随机抽取出一个“倒霉的”矩形执行拆分即可(可以使用《全民一起玩Python 提高篇》介绍的random.sample函数)。

不过这里还有几个问题:

1. 按宽度拆分和按高度拆分是两个不同的代码,那么怎样在二者之间随机选择一种方式呢?这一点既可以用随机数方式解决(生成一个随机数,如果大于0.5就选宽度、否则选高度),也可以像下面杨老师的示例中那样:如果待拆分矩形的宽度大于高度,就按宽度横向拆分,否则按高度竖向拆分。

2. 假如要按照宽度进行横向拆分,但是待拆分矩形已经很窄,只有一列或两列宽,该怎么办呢?对于这种情况,我们可以在拆分前先进行一次判断:如果宽度 r[3]-r[1] 大于 2,我们才执行宽度拆分,否则重新循环重新抽取一个矩形。这个思路同样适用于对“扁矩形”按高度拆分的情况

3. 由于问题2的存在,有可能某次循环时没有执行任何拆分操作。这样会带来一个隐患:为了拆分出20个矩形,我们设计了一个19次的循环;但19次循环里只有17次执行了拆分,所以最终只得到18个矩形。为了避免这种情况,我们可以使用一个计数器模式的while循环,不过只有成功执行一次拆分时对循环变量(计数器)增加1。这样当发生问题2的情况时,由于循环变量(计数器)并没有增加,所以可以“多循环一次”。

搞清楚上面几个问题,最终算法就可以出炉了(篇幅所限、删除了注释):

不过最后还有一个问题:上面算法的结果都是数字,可是我们怎样把它们画到Excel中呢?这种问题,当然还是找老朋友 xlwings !

在xlwings中,我们可以使用下面的格式执行单元格合并操作:

worksheet.range((左上行号,左上列号) (右下行号,右下列号) ).api.merge

所以在执行完前面的算法,得到最终矩形列表 rects 之后,只要循环读取其中每个矩形的坐标元组,然后调用 xlwings 把指定行列的单元格合并,就可以看到最终的效果:

这就是“随机拆分矩形”的一个基本思路。其中还有很多细节可以进一步完善,比如怎样避免过于狭长的小矩形、怎样在中心位置留出一个最大的矩形作为C位等等。此外虽然我们使用的是Python,但所有细节也都可以用VBA对等实现。所以这些问题,就留给有兴趣的朋友们自己慢慢打磨吧。

最后,很多关心我们新课制作进度的同学没有看到前几期的公告,所以这里简单重述一下:目前我们正在制作《全民一起玩SQL 基础篇》和《全民一起玩Python 实战篇》,同时我们的新版在线教学平台也在紧张开发中。我们计划将新课程与新平台同步上线,以便为大家提供全方位沉浸式的学习资源。按我们的计划,预期发布时间为9月初,详情请随时关注我们的公众号。再次感谢各位的关注和耐心!

ukd

更多精彩阅读

接下来,我们会怎么走 —— 关于新的课程和教学方式

不变的,是初心 —— 写在又一门课程收尾之际

为什么又是游戏?—— 摘一段二十多年前的青涩文章

扫码听课

杨老师课程全集

全民一起玩Python

全民一起VBA

欢迎加入、一起进步

随机密码生成python_让“全家福”更加随机 —— 自动生成照片布局之Python实现...相关推荐

  1. java 试卷自动生成_基于JAVA的试题自动生成系统 - WEB源码|JSP源码/Java|源代码 - 源码中国...

    压缩包 : 试卷自动生成系统.rar 列表 试卷自动生成系统/.classpath 试卷自动生成系统/.project 试卷自动生成系统/bin/Db/Sql.class 试卷自动生成系统/bin/f ...

  2. freemarker mysql 生成bean_基于数据库的代码自动生成工具,生成JavaBean、生成数据库文档、生成前后端代码等(v6.6.6版)...

    TableGo_20191026 v6.6.6 正式发布,此次版本更新如下: 1.新增通过自定义模板生成Word文档的功能,可以使用FreeMarker模板生成自定义格式的数据库文档. 2.新增 Sw ...

  3. 绕线画算法python_一种绕线画自动生成及加工的方法和设备与流程

    本发明涉及技术领域,具体涉及一种绕线画自动生成及加工的方法和设备. 背景技术: 绕线画又称钉子画,简而言之,就是在木板上钉上钉子,然后在钉子间绕线,做出大概的轮廓,然后用线在钉子之间缠绕,组成几何图形 ...

  4. 软件测试自动生成测试数据,软件测试中测试数据的自动生成方法浅析

    一.引言 软件质量是制约计算机应用领域进一步发展的关键要素之一,保证软件质量.提高软件可靠性的重要手段是软件测试.软件测试中最关键的问题是测试数据的设计,它主要涉及两个方面,一是测试 数据生成,是测试 ...

  5. node.js require 自动执行脚本 并生成html,利用node.js实现自动生成前端项目组件的方法详解...

    本文主要给大家介绍了关于利用node.js实现自动生成前端项目组件的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍: 脚本编写背景 写这个小脚本的初衷是,项目本身添加一个组件太 ...

  6. mybatis 自动生成integer_Intellij IDEA 中使用 MyBatis-generator 自动生成 MyBatis代码

    1.IDEA创建maven工程(略) 2. 在maven项目的pom.xml 添加mybatis-generator-maven-plugin 插件和MySQL数据库驱动依赖 build>< ...

  7. html自动生成工具_关于STM32代码自动生成的工具的进度....

    前情提要:STM32代码自动生成工具_本想...但是...可是...所以 首先说一下那几天大家的反应,有的持观望态度,毕竟STM32CUBE很香:有的很激动,期待我快点出东西:还有的很淡定,知道我在挖 ...

  8. python 文案自动生成_Python应用 | 利用COM技术自动生成IBM i2舞弊关系分析图表

    点蓝字关注  ↑↑↑ 数据化审计:问题导向.应用至上.解决痛点 内容摘要 什么是COM技术 IBM I2 Analyst's Notebook软件介绍 如何使用Python调用I2的COM接口,批量自 ...

  9. php生成excel到服务器,yii phpexcel自动生成文件保存到服务器上

    yii phpexcel自动生成文件保存到服务器上 最近再整一个报表任务,每天必须把表导出来按excel格式发送邮件给管理员,利用phpexcel把表保存到服务器上,然后再通过phpmailer发送就 ...

最新文章

  1. python virtualenv用法
  2. node--非阻塞式I/O,单线程,异步,事件驱动
  3. MySQL — 外键关联操作
  4. 秒杀核心设计(减库存部分)-防超卖与高并发
  5. 配置树莓派linux的内核和编译并将镜像拷贝至树莓派
  6. 最流行的轻量级php框架,推荐20个最近很流行的优秀PHP框架
  7. nodejs总结之redis模块
  8. 贺利坚老师汇编课程32笔记:处理字符串——大小写转换通过与和或运算加减20H
  9. ug区域轮廓铣没有重叠距离_UG加工基本操作
  10. MySql 5.7.26(MySQL8)安装教程
  11. 找电影最强攻略,最全资源站
  12. Postman 接口压力测试
  13. 编程常用资料/网站收集
  14. 在选用矿物质防火电缆的时候应该注意什么?
  15. 利用vbs 运行程序 并使窗口隐藏
  16. uchome 标签讲解
  17. Document-Level Relation Extraction with Adaptive Thresholding and Localized Context Pooling 阅读笔记
  18. 如何学习大数据!!我要做大数据! 1
  19. lol好友列表显示聊天服务器断开,lol聊天服务器断开 英雄联盟聊天服务器连不上解决办法...
  20. 安利一款功能强大,简单好用的录屏软件!

热门文章

  1. php模拟post方法
  2. java 类加载的过程
  3. 云原生是什么?它从哪里来?又到哪里去?
  4. 敏捷20周年:一场失败的起义
  5. 一次解决Linux内核内存泄漏实战全过程
  6. 字节跳动回应抖音上市;苹果公司:全球多个国家的 App 价格将上涨;GDB 10.1 发布|极客头条
  7. 万字长文带你解析23 个问题 TCP 疑难杂症!
  8. 搞定 Linux 命令之进程与数据流,不服来辩!| 原力计划
  9. 登 GitHub 趋势榜首德国疫情追踪 App 号称可保疫情隐私数据无忧,你信吗?
  10. 万人马拉松,人脸识别系统如何又快又准完成校验?