大嘴狗狗 - 程序设计
type: channel
link: https://www.sirit.com.cn/tag/%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1/
items: 工具箱里面找不到 Microsoft.Web.WebView2 控件的解决办法
items: 尹卂倉頡網頁輸入法【尝鲜】
items: 激光雕刻机打印错位解决方案
items: 给文章评论增加验证码
items: JavaScript 3D library — three.js
items: 用 Python 解开恶魔拼图 Puzzle of Evil
items: 多次执行 turtle 海龟图报错：turtle.Terminator
items: 如何让 PyCharm 的 turtle 窗口总在最前
items: 廖雪峰JavaScript教程学习摘录
items: 梦想小镇Township 我是如何一晚上赚 50 绿钞的
items: 非插件为Typecho评论添加算术验证
items: Python3 学习资源小记
items: beer.py Well-known programming example: Bottles of beer.
items: Python3 学习笔记
items: 学编程的好网站：Code.org
items: 更新树莓派 firmware（固件）

工具箱里面找不到 Microsoft.Web.WebView2 控件的解决办法
type: item
date: 2025-09-24T09:57:00+08:00
description: 最近在用 Visual Studio 2022 社区版 编一个桌面应用程序，需要用到 Microsoft.Web.WebView2 控件。新建项目，选C#，Windows平台，桌面应用程序，选择“Windows 窗体应用（.NET Framework）”，填写项目名称，选择存储位置之后，点击“创建”按钮，等几秒钟，一个简单的Form窗体应用程序就准备完毕。在【解决方案资源管理器】中，项目名称上点击右键，弹出菜单中选择“管理 NuGET 程序包”，在打开的界面中选择【浏览】标签页，在搜索框中输入“webview2”，排在最前面的就是 Microsoft.Web.WebView2，作者是 Microsoft，选择“Microsoft.Web.WebView2”后，右侧显示版本：最新稳定版 1.9.3485.44，点击【安装】按钮，弹出一个“预览更改”窗体，点击【应用】按钮即可，程序【输出】界面会显示如下信息：正在尝试收集与目标为“.NETFramework,Version=v4.8.1”的项目“BrowserRecorder”有关的包“Microsoft.Web.WebView2.1.0.3485.44”的依赖项信息收集依赖项信息花费时间 716 毫秒正在尝试解析程序包“Microsoft.Web.WebView2.1.0.3485.44”的依赖项，DependencyBehavior 为“Lowest”解析依赖项信息花费时间 0 毫秒正在解析操作以安装程序包“Microsoft.Web.WebView2.1.0.3485.44”已解析操作以安装程序包“Microsoft.Web.WebView2.1.0.3485.44”正在将程序包“Microsoft.Web.WebView2.1.0.3485.44”添加到文件夹“D:\C#Projects\BrowserRecorder\packages”已将程序包“Microsoft.Web.WebView2.1.0.3485.44”添加到文件夹“D:\C#Projects\BrowserRecorder\packages”已将程序包“Microsoft.Web.WebView2.1.0.3485.44”添加到“packages.config”已将“Microsoft.Web.WebView2 1.0.3485.44”成功安装到 BrowserRecorder执行 nuget 操作花费时间 2.25 秒已用时间: 00:00:03.0155245========== 已完成 ==========这时打开“工具箱”，里面应该出现“WebView2 Windows Form Control”，里面有两项，一个是“指针”，另一个是“WebView2”，而这个就是可以添加到窗体中的控件。但是不知道怎么回事，工具箱里面就是没有这些内容，重新安装了 Visual Studio 也没有用，正好这两天台风“五停”，闲着也是闲着，干脆把系统重新安装一下。现在的系统里装了很多乱七八糟的软件，导致 200GB 的 C 盘只有 30GB 的空间了。用 Ventoy 软件 格式化好久未用的 64GB 的 U盘，然后把 Win10_22H2_Chinese_Simplified_x64v1.iso 考到 U盘里面。重新启动电脑，开始全新安装 Windows，安装完成，设置好网络，系统会自动查找驱动，很快一个全新的系统就准备就绪。安装 Visual Studio 2022，新建项目，通过 NuGet 添加 Microsoft.Web.WebView2，一切都很顺利，但是打开工具箱一看，还是没有 “WebView2 Windows Form Control”选项，奇了怪了，心里忽然有个念头：难道是需要刷新一下才能显示出来吗？在“工具箱”界面的空白处点击右键，弹出菜单里面没有“刷新”选项，但是有一个“重置工具箱”选项，鬼使神差之下点了它，呵呵，试了好多遍都不显示的“WebView2 Windows Form Control”选项出现了！

尹卂倉頡網頁輸入法【尝鲜】
type: item
date: 2022-11-16T07:28:00+08:00
description: 网上大神真多，高手在民间。居然遇到一个制作输入法的网友，首先我觉得弄个输入法是个繁杂的事情，想想一大堆编码就会头疼，就像五笔一样，需要拆解汉字形成字根，它不像拼音输入法，会拼音就可以；其次，这个输入法有一个古怪的名字“尹卂倉頡網頁輸入法”，“尹卂”是作者的名字，而仓颉造字的故事大家基本都知道，所以看到名字就觉得这是个颇有神秘感的输入法，虽然它已经出现了很多年。当然，这确实也不是一般的输入法，我打赌除了网页键盘上的字以外，你想凭感觉输入其他的字是基本不可能的。还好，作者准备了搜索功能，不会拼的字可以先查一下它的编码，至于具体的编码及使用方法可以参看下面的文章：《尹卂倉頡規則正述》《尹卂倉頡簡易教程》尹卂倉頡輸入法網頁：https://ejsoon.win/wp-content/uploads/2022/11/ejcjonline.html整个输入法全部放在了一个 html 文件里面，网页大小只有 204k，简便易携带。“尹倉遍地開花”活动https://ejsoon.win/ejcjonline/ 操作说明用鼠标点击绿色汉字，在粉红色区域生成你想要的文字后，点击该字即可；点击“Enter”键会输入英文字母，而不是生成的汉字。代码说明我是使用了 iframe 内嵌的功能，这个功能在 Markdown 里面可以直接使用。代码如下，效果如上：

激光雕刻机打印错位解决方案
type: item
date: 2022-11-08T12:42:00+08:00
description: 之前激光雕刻出现了一些小问题：https://www.sirit.com.cn/archives/489/再三确认 LightBurn 里面绘制的图形没有问题，突发奇想，是不是生成的 GCode 文件出问题了呢？GCode 文件是文本格式，用记事本软件就可以打开。打开之前生成的 GCode 文件，太长，有点乱，干脆重新画个简单的图案来看一下 GCode 文件。软件问题在 LightBurn 里面画了 5 条线，按照 x，y 坐标定位，拼成了两个正方形，分别设置了每条线的颜色、顺序以及功率速度，然后保持成 GCode 文件。GCode 文件的内容如下：; GRBL device profile, absolute coords ; Bounds: X100 Y180 to X200 Y230 G00 G17 G40 G21 G54 G90 M4 ; Cut @ 6000 mm/min, 20% power M8 G0 X100Y230 ; Layer C01 G1 X200S200F6000 ; Cut @ 5000 mm/min, 30% power M8 G0 X200Y180 ; Layer C02 G1 X100S300F5000 ; Cut @ 4000 mm/min, 40% power M8 G0 X100Y180 ; Layer C03 G1 Y204.9S400F4000 G0 Y205.1 G1 Y230 ; Cut @ 3000 mm/min, 50% power M8 G0 X150Y230 ; Layer C04 G1 Y205.1S500F3000 G0 Y204.9 G1 Y180 ; Cut @ 175 mm/min, 100% power M8 G0 X200Y180 ; Layer C05 G1 Y204.9S1000F175 G0 Y205.1 G1 Y230 M9 G1 S0 M5 G90 ; return to user-defined finish pos G0 X0 Y0 M2硬件问题研究了半天，没发现什么问题，心里想着还是先确定硬件是否出问题吧。先把皮带松了一点，然后打印了厂家自带的老鹰图案，打的一踏糊涂，错位非常严重，很多线条都没有封闭。又用 LightBurn 作图：打印效果如下，橘黄色圆圈内都是错位。抽空问了 jd 上的厂家客服，回答是可能螺丝松了，或者皮带松紧度不合适，至于皮带的松紧度完全靠个人感觉来衡量，不能太紧，也不能太松。唉，这技术客服也太好干了吧。难道厂家就不能给出一个校正图案，打印一遍就知道哪里的问题吗？只能自己摸索了！鉴于我之前动了 Y 轴的皮带，我想最大的问题就在这里，可能皮带太松导致线条变换方向时产生错位，于是，我把 Y 轴的两根皮带用手拉到最紧，然后把固定压片上紧。再次打印老鹰图案，这一次，完美！总结其实第一次打印老鹰图案就有点错位，只是当时我以为打印的时候不小心碰到桌子，导致木板有移动而造成的错位。昨天打印时间拼图底板的时候，日期也有错位，我以为是字体丢失的原因，今天终于给解决了。我之前心里一直对软件出错存疑，其实软件出错的可能性最小。当发生类似事件时，还是先排查硬件是否出故障，最后再考虑软件的问题吧。

给文章评论增加验证码
type: item
date: 2022-09-13T13:10:00+08:00
description: 换了这个Moricolor主题之后，收到许多垃圾评论，都是全英文的，发的都是链接图片之类的东西，因为我开启了评论审核，所以一进后台就看到一大堆的垃圾评论。手动删除了几次，心想这也不是办法，总得解决一下，网上的解决办法，大致有几类：使用 Typecho 插件：有点麻烦，需要额外安装插件；增加汉字验证：提交时判断输入内容是否有汉字，一刀切，有点武断；是否中文浏览器：要是全英文的办公环境，还得来回切换浏览器的设置；增加验证码：在评论区增加验证码。选择了“增加验证码”，常见的就是增加一道口算题，如下图所示：代码参考文章：Typecho纯代码算术验证码加强版我根据他的代码，结合网站主题进行了部分修改（顺便说一句，Typecho后台可以直接改主题代码，真方便）：修改 functions.php 文件第一步：找到 function themeInit() 代码处：在该函数的最后增加一行代码：$comment = spam_protection_pre($comment, $post, $result); 第二步：来到 functions.php 文件末尾：增加下面两个函数的代码：function spam_protection_math() { $num1 = rand(1, 15); $num2 = rand(1, 15); echo " \n"; echo " "; echo " "; } function spam_protection_pre($comment, $post, $result) { if ($_REQUEST['text'] != null) { If($_POST['num1'] == null || $_POST['num2'] == null) { throw new Typecho_Widget_Exception(_t('验证码异常.', '评论失败')); } else { $sum = $_POST['sum']; switch ($sum) { case $_POST['num1'] + $_POST['num2'] : break; case null: throw new Typecho_Widget_Exception(_t('请输入计算结果...', '评论失败')); break; default: throw new Typecho_Widget_Exception(_t('计算错误，请重新输入计算结果.', '评论失败')); } } } return $comment; }上图中的绿色粗线是我修改过后的代码，一个是用 placeholder 把提示文字放到 input 框里面；另一个是修改 class，让它与我的网站主题保持一致。修改 comments.php 文件在 comments.php 文件中，找到 input 输入框的位置：在最后一个 input 后面，输入下面的代码，如下图所示：<?php spam_protection_math();?>最终效果：最新修改1004经过使用才发现，数字验证框没放对位置，登录之后导致看不到验证框，修改的代码如下： <?php spam_protection_math();?> <?php $this->remember('text', false); ?> 也就是把数字验证框的代码放到评论区的上方即可。

JavaScript 3D library — three.js
type: item
date: 2022-09-04T18:00:00+08:00
description: 网址：https://github.com/mrdoob/three.js中文文档：https://threejs.org/docs/#manual/zh/ { "imports": { "three": "../build/three.module.js", "three/addons/": "./jsm/" } } import * as THREE from 'three'; import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'; import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js'; let camera, scene, renderer; let clock; const mixers = []; init(); animate(); function init() { camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 1000 ); camera.position.set( 2, 3, - 6 ); camera.lookAt( 0, 1, 0 ); clock = new THREE.Clock(); scene = new THREE.Scene(); scene.background = new THREE.Color( 0xa0a0a0 ); scene.fog = new THREE.Fog( 0xa0a0a0, 10, 50 ); const hemiLight = new THREE.HemisphereLight( 0xffffff, 0x444444 ); hemiLight.position.set( 0, 20, 0 ); scene.add( hemiLight ); const dirLight = new THREE.DirectionalLight( 0xffffff ); dirLight.position.set( - 3, 10, - 10 ); dirLight.castShadow = true; dirLight.shadow.camera.top = 4; dirLight.shadow.camera.bottom = - 4; dirLight.shadow.camera.left = - 4; dirLight.shadow.camera.right = 4; dirLight.shadow.camera.near = 0.1; dirLight.shadow.camera.far = 40; scene.add( dirLight ); // scene.add( new THREE.CameraHelper( dirLight.shadow.camera ) ); // ground const mesh = new THREE.Mesh( new THREE.PlaneGeometry( 200, 200 ), new THREE.MeshPhongMaterial( { color: 0x999999, depthWrite: false } ) ); mesh.rotation.x = - Math.PI / 2; mesh.receiveShadow = true; scene.add( mesh ); const loader = new GLTFLoader(); loader.load( 'models/gltf/Soldier.glb', function ( gltf ) { gltf.scene.traverse( function ( object ) { if ( object.isMesh ) object.castShadow = true; } ); const model1 = SkeletonUtils.clone( gltf.scene ); const model2 = SkeletonUtils.clone( gltf.scene ); const model3 = SkeletonUtils.clone( gltf.scene ); const mixer1 = new THREE.AnimationMixer( model1 ); const mixer2 = new THREE.AnimationMixer( model2 ); const mixer3 = new THREE.AnimationMixer( model3 ); mixer1.c…

用 Python 解开恶魔拼图 Puzzle of Evil
type: item
date: 2022-04-15T17:32:00+08:00
description: 被 恶魔拼图（Puzzle of Evil） 困住了一天之后，我决定上网搜索一下，我怀疑是否存在答案，于是就看到了这篇文章： How wooden puzzles can destroy dev teams ，不同的是他们找到了 Easy 难度的答案，只是解不出 Hard 难度。好吧，看来 Easy 还是没问题的，是有答案的，那我也干脆用计算机暴力求解一下吧。问题分解拼图的外观如下：两种难度的底板参考 John Sullivan 的解法，用大三角形把两种难度框起来，从上到下，从左到右标上坐标。四个板块虽然也是上过博士课程的人，但我的数学知识基本都还给老师了，干脆用最简单的方法来解决板块的旋转和翻面时的坐标变换难题。每个板块有 2 面，按照形状有 6 个旋转的角度，因此有 12 个初始摆放位置（从大三角形的左下角开始），如下图：求解过程问题简化之后，剩下的就是循环求解，把每个板块先向右一格一格的移动，移到最右边，然后向上移动一格后，再依次从左向右移动，直到最上端。移动的过程中，任何时候板块的任何部分都不能移出大三角形之外；每移动一格都通过板块上每个小三角形的坐标来判断是否整个板块都位于底板内，计算的结果列表如下：板块ABCD015767024445036239048776054425067149117578125234135537146467156124163637合计66485078一共 4 种板块，每个板块 0 开头有 1~6 六个角度，分别是 01~06，翻面之后为 11~16。A 板块有 66 种可用摆放位置，B 板块有 48 种，为了减少循环的层数，先计算 A 和 B 板块同时摆放的可用位置，一共是 310 种。同理，C 和 D 板块有 539 种。最后再把 AB 与 CD 的结果做一次循环，铛~铛~铛~铛~~~，不到一秒钟，结果出来了，唯一的一个答案。按照板块上的坐标，先在大三角形里面标出了 A 板块的位置，答案如下：想挑战解谜的朋友不要点开看：A 板块的放置位置图片 boardEasyAns.png知道了 A 板块的位置之后，只剩下 3 个板块，难度下降很多，很快就解出来了，哦耶~~~Hard 难度Hard 难度和 Easy 难度的求解差别只在于底板形状的变化，因此只需要修改底板坐标参数即可。一番计算下来，结果果然为 0。posA= 72 posB= 52 posC= 60 posD= 88 pos(A+B) = 354 pos(C+D) = 899 pos(A+B+C+D) = 0这和本文开头的那篇文章（ How wooden puzzles can destroy dev teams ）中说的一样，见下面的引用：The hard side of the puzzle was unsolvable.Clearly there was a very evil puzzle master in our ranks.Jamie Wong readily admitted to bringing in the puzzle, but despite the staggering proof to the contrary, he was adamant that a solution existed. He said our solvers all shared a fatal flaw.原文说，上面的算法存在一个致命的缺点，这么一说我就明白了，是这样的：因为一开始我们就假设板块和底板都是有很多小三角形组成的，而且板块放置的时候是和底板中的小三角形重合的，Easy 难度也验证了这个假设；可是对于 Hard 难度，既然计算的结果为零，那就表明板块的放置不是和底板的小三角形重合。基于这个推测，我试着先在底板外把 4 块拼图拼成一个紧凑的图案，结果居然让我一次成功，拼好之后移到底板中，空间绰绰有余。最后的拼图结果就不放出来了，知道了上面的推测，答案就不远了。Python 求解代码我比较喜欢用 Jupyter Lab 编写一些简单的 Python 代码，编程全是自学的，欢迎大咖指教。# Puzzle of Evil Solution # 用大三角形板块包围底板形状 # 一个 4 个板块，每个板块有 6 个旋转角度和正反两面，以大三角形左下角为放置点，每个板块有 12 个初始位置，选择移动时位于底板内的那些位置保存成板块坐标 # import numpy # 三角形底板坐标初始化 RCord = numpy.zeros([10,19]) for i in range(9): RCord[9][i+7] = 1 for i in range(12): RCord[8][i+4] = 1 for i in range(13): RCo…

多次执行 turtle 海龟图报错：turtle.Terminator
type: item
date: 2022-03-28T22:44:00+08:00
description: 解决了 海龟画图窗口在最上 的问题之后，同学的儿子又发来新问题。他使用海龟模块绘制冰墩墩图案，准备多次绘制，结果每次第二次绘制都会报错，导致程序终止。调试环境：PyCharm 社区版 2021.3.3示例代码：flag = "Y" while(flag =="Y"): import turtle turtle.Screen().getcanvas().winfo_toplevel().attributes("-topmost", True) colors = ['red', 'purple', 'blue', 'green', 'yellow', 'orange'] t = turtle.Pen() t.shape("turtle") turtle.bgcolor('black') for x in range(72): t.pencolor(colors[x % 6]) t.width(x / 20 + 1) t.forward(x) t.left(30) turtle.done() flag = input("再来一次? （Y/N）").upper()第一遍执行完，关闭绘图窗口，当选择“再来一次”的时候就会出错：原因大概是 turtle.done() 只是暂停了程序的执行，使绘图窗口停留不关闭，当关闭绘图窗口后，turtle还在后台继续运行，因此下一次再执行 turtle 的代码就会出错。具体的解决办法见下面增加的两行代码：flag = "Y" while(flag =="Y"): import turtle turtle.Screen().getcanvas().winfo_toplevel().attributes("-topmost", True) colors = ['red', 'purple', 'blue', 'green', 'yellow', 'orange'] t = turtle.Pen() t.shape("turtle") turtle.bgcolor('black') for x in range(72): t.pencolor(colors[x % 6]) t.width(x / 20 + 1) t.forward(x) t.left(30) turtle.done() turtle.Turtle._screen = None # force recreation of singleton Screen object turtle.TurtleScreen._RUNNING = True # only set upon TurtleScreen() definition flag = input("再来一次? （Y/N）").upper()亲测有效，见下图的多次运行效果：

如何让 PyCharm 的 turtle 窗口总在最前
type: item
date: 2022-03-28T12:03:00+08:00
description: 一大早，本科同学来电话说他儿子有 Python 编程问题解决不了，说是画图窗口老是在后面被遮挡，然后把代码用微信发来让我看看。先把代码另存到本地，文件名为 d.py。打开 Jupyter LabJupyter Lab 是我最常用的 Python 编程环境，在浏览器里面就可以编程执行，非常方便。把代码拷贝进去，执行，turtle 画图窗口出现并保持在最前，没问题。Anaconda PowerShell Prompt打开 Anaconda PowerShell Prompt 命令行界面，输入 python d.py，回车，画图窗口顺利弹出在最前，没问题。stem86.comStem86 学习平台带有 Python 的编程环境，里面的 turtle 画图是直接显示的，更没问题了。Visual Studio Code用 VS Code 打开 d.py，启动调试，发现 turtle 窗口没有在最前，需要手动切换，有问题了。PyCharm使用 PyCharm 免费的社区版打开 d.py，画图窗口也没有在最前。解决方案之前一直用 Jupyter Lab，还没有注意到这个问题，貌似在 VS Code 和 PyCharm 软件调试时会把弹出窗口放到后面，要解决的话就得从窗口的控制入手。网上搜索了一番，找到如下代码：import turtle topwindow = turtle.Screen().getcanvas().winfo_toplevel() topwindow.call('wm', 'attributes', '.', '-topmost', '1') topwindow.call('wm', 'attributes', '.', '-topmost', '0') turtle.Screen().title("我是窗口标题") # Set the window titleOK，问题解决了。上面的代码可以简化如下：# 窗口置顶 turtle.Screen().getcanvas().winfo_toplevel().attributes("-topmost", True) # 窗口最大尺寸 turtle.Screen().getcanvas().winfo_toplevel().wm_maxsize(500,400) # 窗口标题 turtle.Screen().getcanvas().winfo_toplevel().title("Helllooooooooo") # 标题的最大化按钮不可用 turtle.Screen().getcanvas().winfo_toplevel().wm_resizable(False,False) # 窗口透明度 turtle.Screen().getcanvas().winfo_toplevel().attributes("-alpha", 0.5) # 工具栏标题模式 turtle.Screen().getcanvas().winfo_toplevel().attributes("-toolwindow", False) # 窗口全屏模式 turtle.Screen().getcanvas().winfo_toplevel().attributes("-fullscreen",True) 更多使用方式参见：http://tkdocs.com/tutorial/windows.html

廖雪峰JavaScript教程学习摘录
type: item
date: 2021-01-30T13:26:00+08:00
description: JavaScript是世界上最流行的脚本语言，因为你在电脑、手机、平板上浏览的所有的网页，以及无数基于HTML5的手机App，交互逻辑都是由JavaScript驱动的。简单地说，JavaScript是一种运行在浏览器中的解释型的编程语言。那么问题来了，为什么我们要学JavaScript？尤其是当你已经掌握了某些其他编程语言如Java、C++的情况下。简单粗暴的回答就是：因为你没有选择。在Web世界里，只有JavaScript能跨平台、跨浏览器驱动网页，与用户交互。Flash背后的ActionScript曾经流行过一阵子，不过随着移动应用的兴起，没有人用Flash开发手机App，所以它目前已经边缘化了。相反，随着HTML5在PC和移动端越来越流行，JavaScript变得更加重要了。并且，新兴的Node.js把JavaScript引入到了服务器端，JavaScript已经变成了全能型选手。JavaScript一度被认为是一种玩具编程语言，它有很多缺陷，所以不被大多数后端开发人员所重视。很多人认为，写JavaScript代码很简单，并且JavaScript只是为了在网页上添加一点交互和动画效果。但这是完全错误的理解。JavaScript确实很容易上手，但其精髓却不为大多数开发人员所熟知。编写高质量的JavaScript代码更是难上加难。一个合格的开发人员应该精通JavaScript和其他编程语言。如果你已经掌握了其他编程语言，或者你还什么都不会，请立刻开始学习JavaScript，不要被Web时代所淘汰。学习网址：https://www.liaoxuefeng.com/wiki/1022910821149312--------------------学习笔记--------------------JavaScript的语法和Java语言类似，每个语句以 ; 结束，语句块用{...}。JavaScript不区分整数和浮点数。十六进制用0x前缀和0-9，a-f表示。字符串是以单引号'或双引号"括起来的任意文本。由于JavaScript这个设计缺陷，不要使用 == 比较，始终坚持使用 === 比较。NaN === NaN; // falseisNaN(NaN); // true1 / 3 === (1 - 2 / 3); // falseMath.abs(1 / 3 - (1 - 2 / 3)) < 0.0000001; // trueJavaScript的设计者希望用null表示一个空的值，而undefined表示值未定义。JavaScript的对象是一组由键-值组成的无序集合。变量在JavaScript中就是用一个变量名表示，变量名是大小写英文、数字、$和_的组合，且不能用数字开头。要显示变量的内容，可以用console.log(x)，打开Chrome的控制台就可以看到结果。不用var申明的变量会被视为全局变量。启用strict模式的方法是在JavaScript代码的第一行写上：'use strict';由于多行字符串用 \n 写起来比较费事，所以最新的ES6标准新增了一种多行字符串的表示方法，用反引号 ` 表示。如果要往Array的头部添加若干元素，使用unshift()方法，shift()方法则把Array的第一个元素删掉。splice()方法是修改Array的“万能方法”，它可以从指定的索引开始删除若干元素，然后再从该位置添加若干元素。在编写JavaScript代码的时候，属性名尽量使用标准的变量名，这样就可以直接通过object.prop的形式访问一个属性了。要判断一个属性是否是xiaoming自身拥有的，而不是继承得到的，可以用 hasOwnProperty() 方法。我们建议永远都要写上 {}。JavaScript把 null、undefined、0、NaN 和空字符串''视为false，其他值一概视为true。for 循环的 3 个条件都是可以省略的，如果没有退出循环的判断条件，就必须使用 break 语句退出循环，否则就是死循环。for 循环的一个变体是 for ... in 循环，它可以把一个对象的所有属性依次循环出来。用 do { ... } while()循环要小心，循环体会至少执行1次，而 for 和 while 循环则可能一次都不执行。Map 是一组键值对的结构，具有极快的查找速度。初始化 Map 需要一个二维数组，或者直接初始化一个空 Map。要创建一个 Set，需要提供一个 Array 作为输入，或者直接创建一个空 Set。具有 iterable 类型的集合可以通过新的for ... of循环来遍历。更好的方式是直接使用 iterable 内置的 forEach 方法，它接收一个函数，每次迭代就自动回调…

梦想小镇Township 我是如何一晚上赚 50 绿钞的
type: item
date: 2020-05-07T12:59:00+08:00
description: 断断续续的在玩“梦想小镇”，大家都知道，绿钞在游戏里面绝对是硬通货，对于人民币玩家，完全可以通过购买绿钞实现快速升级。好吧，我是不会为游戏花钱的，除了我的最爱 Quake Live，花了RMB36元。steampowered 网站居然被举报为诈骗网站。嗯，确实骗了我不少钱，害得我天天玩游戏。最近游戏里面举行了一个农业大赛，也就是种庄稼就可以奖励积分，活动结束积分第一名可以奖励 50 张绿钞，哇，这可是千载难逢的好事，嗯，目前看来是。梦想小镇 (Township) 是一款比较传统的农场类模拟经营游戏，将城市建设和农场管理进行了结合。《梦想小镇》将城市建设和农场管理进行了独树一帜的结合！收获农作物、在工厂进行加工，再将货物出售以发展您的小镇。与远处的岛屿进行交易。开设餐厅、电影院和其他社区建筑，让您的小镇别具风味充满生机。探索矿井获取能源并找出古董。运营您自己的动物园并收集世界各地的动物。准备好筑造您的梦想了吗？我们开始吧！研究了一下积分情况，一个小麦1分，一个玉米2分，一个胡萝卜3分，基本上种植时间越长积分越高。不过仔细一算会发现时间和积分是不成比例的。比如，种一茬小麦需要2分钟，一茬玉米需要5分钟，也就是同样的时间，种小麦产生的积分更高，换算到其他作物也是一样，只有种小麦最划算，积分上升的也最快。玩了一个多小时，发现不对劲，这样升级是很快，但是 2 分钟一茬，也就意味着我要一直这么盯着才行。这怎么可以？我其他的事情都做不了了。还有什么事情可以让程序员为难呢？！（BGM...）是时候展现我真正的实力啦，哈哈哈说明：以下操作环境为 macOS Catalina，版本 10.15.4。网上搜索了 Mac 上的鼠标自动化操作，发现 PyAutoGUI 完全满足“鼠标点击和拖动”的要求，就它了。PyAutoGUI 官网：https://pyautogui.readthedocs.io/en/latest/Windows 下面有按键精灵可以用，很早很早以前用过。使用 PIP 安装好 PyAutoGUI ，就可以祭出我的 Python 大法，打开终端，输入：jupyter lab，开启python之旅！BUT 编程切记不要一上来就写代码，要先思考流程，模块设计，划分功能。不过，我一瞬间就明白了一切，开始直接动手写代码，嗯，就是这样的。好吧，循环流程大致有这么几步：收麦子 -> 种麦子-> 卖麦子收麦子：定位麦田位置，选中镰刀，在麦田上方挥舞镰刀收割种麦子：定位麦田位子，选中小麦种子，在麦田上方挥洒种子卖麦子：打开仓库，定位到小麦，修改销售数量，卖出小麦。【移动与点击代码】import pyautogui as pa from datetime import datetime import time #多次点击 def timesclick(x): for i in range(x): pa.click() time.sleep(0.1) #田地范围 def YiDong2(): for i in range(5): pa.moveTo(790-70*i, 255+45*i, duration=0.5) pa.moveTo(980+75*i, 255+45*i, duration=0.5) for i in range(5): pa.moveTo(380+40*i, 450+45*i, duration=0.5) pa.moveTo(1210-75*i, 450+45*i, duration=0.5) 【代码说明】不知道怎么回事，click()本身是支持多次点击的，修改clicks、interval就可以，但是 interval 不起作用，而如果点击快了，游戏里面是反应不过来的，因此只能自己写一个多次点击函数。游戏里面的坐标不是正方形，而是菱形，一开始是获取田地左上和右下坐标，然后横扫整个长方形，这样有点费时。重写代码，扫描范围改成菱形了。【收、种、卖代码】#收 麦子 def ShouMaizi(): pa.moveTo(820, 460, duration=0.25) pa.click() #鼠标在麦田中心点击一次 pa.moveTo(730, 820, duration=0.25) #镰刀位置 pa.mouseDown(730, 820)#选中镰刀 pa.moveTo(820, 460, duration=0.5) YiDong2() pa.mouseUp() #种 麦子 def Zhongmaizi(): pa.moveTo(820, 460, duration=0.25) #选块地 pa.click() pa.moveTo(400, 820, duration=0.25) #选小麦种子 pa.mouseDown(400, 820) p…

非插件为Typecho评论添加算术验证
type: item
date: 2019-04-08T10:48:00+08:00
description: 原文参见：https://black1ce.com/website/sum-verify.html引言最近被垃圾评论弄得很烦，开始每天才十多条，现在每天都有上百条，愈演愈烈，赶紧想办法。不喜欢插件，喜欢代码集成的方式。发现上面链接给的算术验证不错，原文写的不够详细，下面把使用方法写一下。说明针对主题： initial 2.4.3（ https://www.offodd.com/17.html ）注意：修改之前请务必备份网站！！！修改之前请务必备份网站！！！修改之前请务必备份网站！！！使用管理员身份登录之后，在后台编辑外观页面打开 functions.php 文件，在文件最后面添加下面的代码：//算术验证评论 function spam_protection_math(){ $num1=rand(1,49); $num2=rand(1,49); echo " $num1+$num2 = \n"; echo " \n"; echo " \n"; echo " "; } function spam_protection_pre($comment, $post, $result){ $sum=$_POST['sum']; switch($sum){ case $_POST['num1']+$_POST['num2']: break; case null: throw new Typecho_Widget_Exception(_t('对不起: 请输入验证码。返回上一页','评论失败')); break; default: throw new Typecho_Widget_Exception(_t('对不起: 验证码错误，请返回重试。','评论失败')); } return $comment; } 然后，在 functions.php 文件前部找到如下代码：function themeInit($archive) { $options = Helper::options(); $options->commentsAntiSpam = false; if ($options->PjaxOption || FindContents('page-whisper.php', 'commentsNum', 'd')) { $options->commentsOrder = 'DESC'; $options->commentsPageDisplay = 'first'; } if ($archive->is('single')) { $archive->content = hrefOpen($archive->content); if ($options->AttUrlReplace) { $archive->content = UrlReplace($archive->content); } if ($archive->fields->catalog) { $archive->content = createCatalog($archive->content); } } } 在里面添加一句代码 $comment = spam_protection_pre($comment);，改好的代码如下：function themeInit($archive) { $options = Helper::options(); $options->commentsAntiSpam = false; if ($options->PjaxOption || FindContents('page-whisper.php', 'commentsNum', 'd')) { $options->commentsOrder = 'DESC'; $options->commentsPageDisplay = 'first'; } if ($archive->is('single')) { $archive->content = hrefOpen($archive->content); if ($options->AttUrlReplace) { $archive->content = UrlReplace($archive->content); } if ($archive->fields->catalog) { $archive->content = createCatalog($archive->content); } } $comment = spam_protection_pre($comment); } 保存好 functions.php 文件之后，再打开 comments.php 文件，在如下图的位置处添加下面一行代码：<?php spam_protection_ma…

Python3 学习资源小记
type: item
date: 2019-03-31T10:47:00+08:00
description: 李笑来的《 自学是门手艺 》： https://github.com/selfteaching/the-craft-of-selfteaching/Python 加鸡汤，比一本正经枯燥无味的书籍更有利于阅读，也能学到一些编程之外的知识。当然，各花入各眼，有人挺反感。Python 代码仓库： https://github.com/python/Python Demo ：https://github.com/python/cpython/tree/master/Tools/demo廖雪峰的官方网站 Python 教程看完李笑来的书，可以再把这个过一遍。

beer.py Well-known programming example: Bottles of beer.
type: item
date: 2019-03-30T10:42:00+08:00
description: beer.py Well-known programming example: Bottles of beer.Github:https://github.com/python/cpython/blob/master/Tools/demo/beer.py#!/usr/bin/env python3 """ A Python version of the classic "bottles of beer on the wall" programming example. By Guido van Rossum, demystified after a version by Fredrik Lundh. """ import sys n = 100 if sys.argv[1:]: n = int(sys.argv[1]) def bottle(n): if n == 0: return "no more bottles of beer" if n == 1: return "one bottle of beer" return str(n) + " bottles of beer" for i in range(n, 0, -1): print(bottle(i), "on the wall,") print(bottle(i) + ".") print("Take one down, pass it around,") print(bottle(i-1), "on the wall.")在 jupyter lab 中运行报错：--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-18-d31cdec36abd> in <module> 11 n = 100 12 if sys.argv[1:]: ---> 13 n = int(sys.argv[1]) 14 15 def bottle(n): ValueError: invalid literal for int() with base 10: '-f'【解决办法】查找 sys.argv[] 的用法：https://docs.python.org/zh-cn/3/library/sys.html?highlight=argv#sys.argvsys.argv The list of command line arguments passed to a Python script.argv[0] is the script name (it is operating system dependent whetherthis is a full pathname or not). If the command was executed using the-c command line option to the interpreter, argv[0] is set to the string '-c'. If no script name was passed to the Python interpreter,argv[0] is the empty string.To loop over the standard input, or the list of files given on thecommand line, see the fileinput module. sys.argv[] 是传递给 Pythen 脚本文件的命令行参数列表。把 beer.py 下载到本地，chmod 777 beer.py$./beer.py100 bottles of beer on the wall, 100 bottles of beer. Take one down, pass it around, 99 bottles of beer on the wall. 99 bottles of beer on the wall, 99 bottles of beer. Take one down, pass it around, 98 bottles of beer on the wall. ......中间省略若干行...... 2 bottles of beer. Take one down, pass it around, one bottle of beer on the wall. one bottle of beer on the wall, one bott…

Python3 学习笔记
type: item
date: 2019-03-17T10:36:00+08:00
description: macOS Python 环境配置强烈建议使用 Anaconda（https://www.anaconda.com/），Windows、Linux、Mac都有相应版本，而且安装包管理起来比较方便；不过 Anaconda 更新起来比较慢，建议换成国内镜像源；安装完 Anaconda 后，如果终端窗口 conda 命令不能运行，可以先配置 .zshrc 文件；打开终端，输入： vi ~/.zshrc 之后回车，然后按字母 i 进入插入编辑模式，输入下列代码： export PATH=/opt/anaconda3/bin:$PATH ，其中红色字体要替换成你自己电脑上的conda所在目录，按 ESC 键，输入： :wq 三个字符，文件被保存后退出。终端再输入：source ~/.zshrc ，使其立即生效，这时就可以用： conda --version ，查看 conda 的版本信息。安装 OpenCV打开终端，输入： sudo pip3 install opencv-python ，按提示输入密码，之后就是漫长的安装过程。切换成国内镜像源会非常快：sudo pip3 install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple直接运行 py 文件.py 文件在Windows上是不能像exe文件直接执行的。但是，在Mac和Linux上是可以的，方法是在.py文件的第一行加上一个特殊的注释：#!/usr/bin/env python3 print('hello, world')然后，通过命令给 hello.py 以执行权限：$ chmod a+x hello.py，就可以直接运行 hello.py 了，执行：Air:~ sirit$ ./hello.pyprint() 输出字符串print()函数可接受多个字符串，用逗号“,”隔开，就可以连成一串输出，print()会依次打印每个字符串，遇到逗号“,”会输出一个空格。name = input('please enter your name: ')print('hello,', name)Python 基础Python的语法采用缩进方式，应该始终坚持使用4个空格的缩进。Python程序是大小写敏感的。以#开头的语句是注释。Python3 的六个标准数据类型中：不可变数据（3 个）：Number（数字）、String（字符串）、Tuple（元组）；可变数据（3 个）：List（列表）、Dictionary（字典）、Set（集合）。整数运算永远是精确的（除法难道也是精确的？是的！），而浮点数运算则可能会有四舍五入的误差。字符串是以单引号'或双引号"括起来的任意文本。转义字符\可以转义很多字符，比如\n表示换行，\t表示制表符，字符\本身也要转义，所以\\表示的字符就是\。Python用r''表示''内部的字符串默认不转义。在Python中，可以直接用True、False表示布尔值（请注意大小写）。空值是Python里一个特殊的值，用None表示。变量本身类型不固定的语言称之为动态语言，与之对应的是静态语言。静态语言在定义变量时必须指定变量类型，如果赋值的时候类型不匹配，就会报错。在Python中，通常用全部大写的变量名表示常量。Python的整数没有大小限制，而某些语言的整数根据其存储长度是有大小限制的，例如Java对32位整数的范围限制在-2147483648-2147483647。Python的浮点数也没有大小限制，但是超出一定范围就直接表示为inf（无限大）。list [ ] 是一种有序的集合，可以随时添加和删除其中的元素。另一种有序列表叫元组：tuple ( )。tuple ( ) 和 list [ ]非常类似，但是 tuple 一旦初始化就不能修改。条件判断条件判断从上向下匹配，当满足条件时执行对应的块内语句，后续的elif和else都不再执行。使用dict和set请务必注意，dict内部存放的顺序和key放入的顺序是没有关系的。和list比较，dict有以下几个特点：查找和插入的速度极快，不会随着key的增加而变慢；需要占用大量的内存，内存浪费多。而list相反：查找和插入的时间随着元素的增加而增加；占用空间小，浪费内存很少。所以，dict是用空间来换取时间的一种方法。dict可以用在需要高速查找的很多地方，在Python代码中几乎无处不在，正确使用dict非常重要，需要牢记的第一条就是dict的key必须是不可变对象。这是因为dict根据key来计算value的存储位置，如果每次计算相同的key得出的结果不同，那dict内部就完全混乱了。这个通过key计算位置的算法称为哈希算法（Hash）。要保证hash的正…

学编程的好网站：Code.org
type: item
date: 2019-03-08T10:25:00+08:00
description: 随着科技的进步，计算机应用越来越广。这几年人工智能、大数据的快速发展，再加上国家教育层面的鼓励，小朋友学编程的人数越来越多，各类的在线、线下培训机构如春笋般层出不穷。我们也试听了一些在线编程课，发现基本内容雷同，不外乎 Scratch 软件（或自行开发的类似 Scratch 的软件）和 Python 编程教学。下面给大家推荐的网站，适合很多年龄段的小朋友，可以先让小朋友跟着学，如果感兴趣，再报名兴趣班也不迟。不过，我看完网站的培训内容后发现，如果把网站的内容都学完了，基本也不用再报名兴趣班了，完全可以自学其他的编程知识了 ^_^ 。【网站地址】 https://code.org/【网站介绍】Code.org en® 是一个非营利组织。它致力于扩大在学校学习计算机科学的机会, 并增加妇女和代表性不足的少数群体的参与。 其愿景是：每个学校的每个学生都能像生物，化学，和代数一样学校计算机科学。 提供最广泛使用的中小学计算机科学课程，并每年组织编程一小时活动。这个活动已经吸引了全世界学生的10%参加。 Code.org 得到了亚马逊、脸书、谷歌、印孚瑟斯基金会，微软等更多慷慨捐助者的支持。【语言支持】可以通过网站页面页脚处的选择框切换成中文 “简体字”【课程介绍】课程 1 非常适合幼儿园的小朋友，里面的课程界面如下图：

更新树莓派 firmware（固件）
type: item
date: 2019-02-28T21:06:00+08:00
description: pi@sirit:~ $ sudo rpi-update *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom *** Performing self-update % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 13545 100 13545 0 0 13853 0 --:--:-- --:--:-- --:--:-- 13849 *** Relaunching after update *** Raspberry Pi firmware updater by Hexxeh, enhanced by AndrewS and Dom *** We're running for the first time *** Backing up files (this will take a few minutes) *** Backing up firmware *** Backing up modules 4.14.79-v7+ ############################################################# WARNING: This update bumps to rpi-4.19.y linux tree Be aware there could be compatibility issues with some drivers Discussion here: https://www.raspberrypi.org/forums/viewtopic.php?f=29&t=224931 ############################################################## Would you like to proceed? (y/N) *** Downloading specific firmware revision (this will take a few minutes) % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed 100 168 0 168 0 0 193 0 --:--:-- --:--:-- --:--:-- 193 100 58.2M 100 58.2M 0 0 890k 0 0:01:06 0:01:06 --:--:-- 456k *** Updating firmware *** Updating kernel modules *** depmod 4.19.25+ *** depmod 4.19.25-v7+ *** Updating VideoCore libraries *** Using HardFP libraries *** Updating SDK *** Running ldconfig *** Storing current firmware revision *** Deleting downloaded files *** Syncing changes to disk *** If no errors appeared, your firmware was successfully updated to 82f49d8dfd9c000a203fb1deae64a3eb87abf3c1 *** A reboot is needed to activate the new firmware pi@sirit:~ $