# electron

使用electron创建窗口的时候,默认会使用window的边框以及工具栏,如果想要创建一个无边框的窗口,可以通过设置frame属性为false来实现。

1
2
3
4
5
6
7
8
// main.js
const { BrowserWindow } = require('electron')

let win = new BrowserWindow({
width: 800,
height: 600,
frame: false
})

这样就可以创建一个无边框的窗口了。但是随之又会带来两个问题:窗口无法拖拽以及无法最小化、最大化、关闭按钮消失(当然你也可以通过快捷键来使用这些功能)。

自定义窗口控制按钮

在 html内部,只能控制窗口的关闭,而最大化和最小化需要和主进程通信,然后再由主进程来控制窗口的最大化和最小化。

一般我们统一使用ipcMainipcRenderer将窗口的控制操作发送到主进程,然后由主进程来控制窗口的最大化、最小化和关闭(以便更好的控制窗口的行为)。

下面是一个简单的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html>
<head>
<title>无边框窗口</title>
<style>
#drag {
-webkit-app-region: drag;
}
</style>
</head>

<body>
<div id="drag">
<button id="min">-</button>
<button id="max">+</button>
<button id="close">x</button>
</div>
</body>

<script>
const { ipcRenderer } = require('electron')

document.getElementById('min').addEventListener('click', () => {
ipcRenderer.send('min')
})

document.getElementById('max').addEventListener('click', () => {
ipcRenderer.send('max')
})

document.getElementById('close').addEventListener('click', () => {
ipcRenderer.send('close')
})
</script>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// main.js
const { app, BrowserWindow, ipcMain } = require('electron')

let win

app.on('ready', () => {
win = new BrowserWindow({
width: 800,
height: 600,
frame: false
})

win.loadFile('index.html')

ipcMain.on('min', () => {
win.minimize()
})

ipcMain.on('max', () => {
if (win.isMaximized()) {
win.unmaximize()
} else {
win.maximize()
}
})

ipcMain.on('close', () => {
win.close()
})
})

窗口拖拽

想要使得窗口可以拖拽,只需要将元素的-webkit-app-region属性设置为drag即可。

1
2
3
#drag {
-webkit-app-region: drag;
}
1
<div id="drag"></div>

这样就可以使得div元素可以拖拽窗口了。

但是这样会使得div内部的元素无法点击,因为-webkit-app-region属性会使得元素变为一个拖拽区域。

想要解决这个问题办法也很简单,只需要将其内部不需要拖拽而是需要响应鼠标点击的元素的-webkit-app-region属性设置为no-drag即可。

完整实例

下面结合自定义窗口控制按钮和窗口拖拽来实现一个无边框窗口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<!DOCTYPE html>
<html>
<head>
<title>无边框窗口</title>
<style>
#drag {
-webkit-app-region: drag;
}

#control {
-webkit-app-region: no-drag;
}
</style>
</head>

<body>
<div id="drag">
<div id="control">
<button id="min">-</button>
<button id="max">+</button>
<button id="close">x</button>
</div>
</div>
</body>

<script>
const { ipcRenderer } = require('electron')

document.getElementById('min').addEventListener('click', () => {
ipcRenderer.send('min')
})

document.getElementById('max').addEventListener('click', () => {
ipcRenderer.send('max')
})

document.getElementById('close').addEventListener('click', () => {
ipcRenderer.send('close')
})

</script>

</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// main.js
const { app, BrowserWindow, ipcMain } = require('electron')

let win

app.on('ready', () => {
win = new BrowserWindow({
width: 800,
height: 600,
frame: false
})

win.loadFile('index.html')

ipcMain.on('min', () => {
win.minimize()
})

ipcMain.on('max', () => {
if (win.isMaximized()) {
win.unmaximize()
} else {
win.maximize()
}
})

ipcMain.on('close', () => {
win.close()
})
})

这样就可以实现一个无边框窗口了。

阅读全文 »

# JS

html 是一种标记语言,css 是一种样式语言。通过 编排 html 的层次结构,然后再使用css 来控制这些层次结构的样式,从而实现页面的设计。

通过将页面划分成大的块,然后再在这些块上面细分更小的块……这就是html的层次结构。然后再通过css来控制这些块的样式,从而实现页面的设计。

下面主要是积累一些常用的css设计技巧。

flex 布局

当你感到迷茫的时候,只要设置display: flex;然后再在开发者工具中直接用可视化工具来调整布局,就可以很快的解决问题。

如果不能解决问题,那么就套两个display: flex; hhhhh

阅读全文 »

# electron

问题概述

electron使用 npm 过程中卡住、显示timeout。

问题分析

实际上,这种情况大部分就是网络问题:使用下面的命令查看你当前使用的源:

1
npm config get registry

然后使用ping试一试能不能ping通这个源:(比如说你使用的是默认的源)

1
ping registry.npmjs.org

解决方案

首先清空缓存:

1
npm cache clean --force

然后切换源即可,下面是一些常用的源。

对了,这里还有一个很坑的问题,就是早在 2021 年,淘宝就发文称,npm 淘宝镜像已经从 registry.npm.taobao.org 切换到了 registry.npmmirror.com。旧域名也将于 2022 年 5 月 31 日停止服务(不过,直到今天 HTTPS 证书到期才真正不能用了)

国内可用源

1. 淘宝npm源

1
2
https://registry.npm.taobao.org
https://registry.npmmirror.com

2. 清华大学npm源

1
https://mirrors.tuna.tsinghua.edu.cn/npm/

3. 华为npm源

1
https://repo.huaweicloud.com/repository/npm/

4. 中科大npm源

1
https://mirrors.ustc.edu.cn/npm/
阅读全文 »

# INSIDE

inside 我不想介绍过多,这里只是记录一下我的游戏体验,以及拆分出游戏的一些元素。

游戏体验

inside 是一款具有独特画风的解密游戏,在游戏中,玩家扮演一个小男孩,穿越在一个充满了奇怪的机械设备和人类实验的世界中。

游戏中使用了极具特色的画风,配乐精美:

在剧情设计上,inside并不通过对话来展示故事,而是通过场景和角色的动作来让玩家感受到游戏的氛围,玩家通过和场景中的元素互动来推动游戏的剧情发展,并且了解背景故事。随着游戏的进行,谜题也逐渐变得复杂,设定也逐渐完善。

在谜题设计上,难度逐渐增加,但是整体来说并不难。

简单拆分一下游戏元素

这里主要是指游戏中的可玩操作,而非美术设计或者剧情。

游戏中的谜题主要可以分为两大类:

  1. 追击类:玩家需要在一定时间内逃脱追击,否则会被抓住。在此过程中,玩家需要找到关键的操作点,比如在某个地方短暂的停下来,或者在某个地方跳过去、避免被绊倒
  2. 谜题类:玩家需要通过操作场景中的元素,来解开谜题,推动剧情发展。这类谜题主要是通过操作场景中的机关来解开,比如拉动某个机关,或者按照某个顺序操作某些机关

而常规的平台跳跃的部分,则被弱化了,游戏中并没有太多需要玩家进行复杂跳跃或者操作的地方。

追击类

追击类更像是让故事背景主动的向你展开,使得玩家被动的带入游戏的氛围中。在游戏的开头,玩家就会被一群人追击,而玩家需要通过操作场景中的元素来逃脱,这一过程使得游戏在一开头就营造出了一种紧张的氛围。

被人追击可以说是最简单也是最直接的一种解密的方式,又因为游戏中的平台跳跃元素的弱化,实际上玩家做的只是跑,从而躲避追击者。

谜题类

谜题类则是游戏的主要玩法,也是玩家主动去探索世界背景,推动游戏剧情发展的方式。

游戏中,主要是设计了5大核心的谜题,分别是:

  1. 通过脑机接口控制 行尸走肉
  2. 控制潜艇
  3. 反重力水
  4. 蒸汽滑块
  5. 投掷物品

这五大核心谜题设计,都围绕着各自的核心机制展开,逐渐增加难度。同时也在不同的关卡中,通过不同的组合方式,来展示出不同的谜题设计。

在这里我懒得具体展开,总而言之这几类机关设计的都挺有意思的。
实际上,还能围绕这些机关设计出更多的谜题,游戏中有一些元素只是简单的做了几个关卡,而没有更深入的挖掘。而随着游戏的阶段的推进,有一些机关设计并不会再次出现

缺点

剧情的结局

整个游戏给我带来的遗憾就是,故事的结尾并不明晰,也没能给出一个明确的结局……扑朔迷离的结局,让我对整个游戏的评价打了一个折扣:在结尾,主人公小男孩进入了一个巨大的实验室,而在实验室的最深处,有一个巨大的肉球,而小男孩最终进入了这个肉球,并且操控肉球,最终肉球横冲直撞,被欺骗进入一个收容装置,但是小男孩又通过扒拉墙壁,逃出了收容装置,并且一路横冲直撞,最终逃出了实验室,但是实验室的外面,却是一片丛林与河岸……然后小男孩就不动了,游戏结束。

![](/2024/03/01/3.Source/INSIDE 2024_7_2 21_39_40.png)

末尾部分的谜题设计

在将近结尾的时候,游戏的节奏变得很快……同时也让人感到迷茫。

在游戏的前半段,玩家只需要一股脑的想办法到达右边,而在后半段,玩家变成肉球后,需要在实验室内横冲直撞。虽然说这段剧情也是情节的高潮之处,但是仍然让人感到有些迷茫(或许这种迷茫也是设计者的本意?)

小男孩变成肉球后,按理来说,实验室的人应该会感到恐慌,想办法阻止小男孩,但是实验室的人却没有任何反应,有很多人在围观,甚至为小男孩开路……虽然说后面揭示了这实际上是他们的计划,通过这种方式勾引小男孩进入收容装置……

在玩家需要逃离收容装置的时候,为了氛围的营造,整体的画面变得很暗,而且玩家需要通过扒拉收容装置的墙壁来逃离,这种操作方式让人感到有些迷茫,因为在这种情况下,玩家很难看清楚周围的环境,而且扒拉墙壁的操作也不是很直观,本身墙壁的设计就让人不会感觉是可以扒拉的再加上很多地方扒拉开之后也是不能走的,只有收容装置的右下角的那块墙壁扒拉之后,玩家可以通过那里露出来的排气口逃离……这一段感觉有点败笔。

总结

整体来说,inside是一款十分不错的解密游戏,画风独特,配乐精美,剧情设计独特,谜题设计也很有意思。但是游戏的结局和末尾部分的谜题设计,让人感到有些遗憾。

9/10

# d2l
# python

概述

环境的配置主要有三部分: - python的下载 及 环境配置 - 安装 torch ,d2l 及 其他 必要库 - jupyter notebook 的 安装和配置

python的下载 及 环境配置

python的下载

python的下载地址:python官网

下载python,我个人推荐是使用 anaconda 这个工具。 anaconda的下载地址:anaconda官网

它是一个非常好的python的环境管理工具,可以很方便的管理python的环境,而且它自带了很多的库,可以很方便的安装。这样的话在使用一些较为常用的库的时候就不需要再去下载了。

python的环境配置

安装完python之后,我们需要配置python的环境变量,使用非 windows 自带的 store 里面的 python 的话,在调用 python 指令的时候,会优先打开应用商店并推荐下载里面的python,但是实际上我们已经安装了python,所以我们需要配置环境变量。下面是配置环境变量的步骤:

1. 找到python的安装路径。

一般是在 C:\Users\用户名\AppData\Local\Programs\Python\Python版本号 下面,在cmd中使用 where python 可以查看python的安装路径。

我这里使用的是 anaconda ,我将其安装在了 E:\Anaconda 下面,版本为3.11。

另外,你可以发现,在 C:\Users\用户名\AppData\Local\Micosoft\WindowsApps 下面也有一个python的路径,但是这个路径是一个快捷方式,不是真正的python的安装路径。这个快捷方式指向的是 store 里面的 python。他会打开store里面的安装界面,推荐你下载store里面的python……而且系统默认环境变量的python也是这个路径,就很无语……

可以通过 python --version 查看python的版本,你看,如果查看那个快捷方式的python的版本,它不会显示版本号:

安装 torch,d2l 以及其他的 必要库

接下来我们需要安装 torch 和 d2l 以及其他的必要库。找到安装的anaconde 的 Anaconda Prompt,在里面输入以下指令:

1
2
pip install torch torchvision torchaudio
pip install d2l

这样就安装好了 torch 和 d2l 了。

你可以使用 pip list 查看已经安装的库。

另外,使用 pip 安装 和 使用 conda 安装有一点点区别,conda 安装的库会放在 E:\Anaconda\envs\你的环境\Lib\site-packages 下面,而 pip 安装的库会放在 E:\Anaconda\Lib\site-packages 下面。除非是你需要打包你的软件,否则的话两个实际上都是一样的。

在这里挖一个坑,后面再填:[[pip和conda的区别]]

juoyter notebook 的 安装和配置

jupyter notebook 包含了记笔记和运行代码的功能,你可以在查看教程的同时,运行里面镶嵌的代码,并且根据自己的理解修改代码,尝试不同的运行结果,这样可以更好的理解代码的含义。

首先,我们将 D2L Notebooks 的代码下载到本地:

1
2
3
4
mkdir d2l-zh && cd d2l-zh
curl https://zh-v2.d2l.ai/d2l-zh-2.0.0.zip -o d2l-zh.zip
unzip d2l-zh.zip && rm d2l-zh.zip
cd pytorch

然后,我们需要安装 jupyter notebook,使用以下指令:

1
pip install jupyter

这个库实际上 anaconda 里面已经自带了,但是它不在环境变量里面,我们需要将其添加到 环境变量,这样才能够直接执行 jupyter notebook 这个指令。

这里建议使用 everything 这个工具,可以很方便的查找文件,输入 jupyter 就可以找到 junpyter 这个程序的位置,然后将其添加到环境变量即可。

然后,我们就可以使用 在 D2L 的文件夹目录下 执行 jupyter notebook 来打开 jupyter notebook 了。

# python
# d2l

基础知识——符号说明

实际上,学习 深度学习,对于初学者来说,需要的基础知识面很广,比如说微积分,概率论,线性代数等,但是实际上涉及的并不深…

上面的东西刚好 大一 就会学,所以说,对于大一的同学来说,学习这个东西基本上没有障碍……简单回顾一下下面的这些数学符号基本上就差不多了:

本书中使用的符号概述如下。 ### 数字

  • \(x\):标量
  • \(\mathbf{x}\):向量
  • \(\mathbf{X}\):矩阵
  • \(\mathsf{X}\):张量
  • \(\mathbf{I}\):单位矩阵
  • \(x_i\), \([\mathbf{x}]_i\):向量\(\mathbf{x}\)\(i\)个元素
  • \(x_{ij}\), \([\mathbf{X}]_{ij}\):矩阵\(\mathbf{X}\)\(i\)行第\(j\)列的元素

集合论

  • \(\mathcal{X}\): 集合
  • \(\mathbb{Z}\): 整数集合
  • \(\mathbb{R}\): 实数集合
  • \(\mathbb{R}^n\): \(n\)维实数向量集合
  • \(\mathbb{R}^{a\times b}\): 包含\(a\)行和\(b\)列的实数矩阵集合
  • \(\mathcal{A}\cup\mathcal{B}\): 集合\(\mathcal{A}\)\(\mathcal{B}\)的并集
  • \(\mathcal{A}\cap\mathcal{B}\):集合\(\mathcal{A}\)\(\mathcal{B}\)的交集
  • \(\mathcal{A}\setminus\mathcal{B}\):集合\(\mathcal{A}\)与集合\(\mathcal{B}\)相减,\(\mathcal{B}\)关于\(\mathcal{A}\)的相对补集

函数和运算符

  • \(f(\cdot)\):函数
  • \(\log(\cdot)\):自然对数
  • \(\exp(\cdot)\): 指数函数
  • \(\mathbf{1}_\mathcal{X}\): 指示函数
  • \(\mathbf{(\cdot)}^\top\): 向量或矩阵的转置
  • \(\mathbf{X}^{-1}\): 矩阵的逆
  • \(\odot\): 按元素相乘
  • \([\cdot, \cdot]\):连结
  • \(\lvert \mathcal{X} \rvert\):集合的基数
  • \(\|\cdot\|_p\): :\(L_p\) 正则
  • \(\|\cdot\|\): \(L_2\) 正则
  • \(\langle \mathbf{x}, \mathbf{y} \rangle\):向量\(\mathbf{x}\)\(\mathbf{y}\)的点积
  • \(\sum\): 连加
  • \(\prod\): 连乘
  • \(\stackrel{\mathrm{def}}{=}\):定义

微积分

  • \(\frac{dy}{dx}\)\(y\)关于\(x\)的导数
  • \(\frac{\partial y}{\partial x}\)\(y\)关于\(x\)的偏导数
  • \(\nabla_{\mathbf{x}} y\)\(y\)关于\(\mathbf{x}\)的梯度
  • \(\int_a^b f(x) \;dx\): \(f\)\(a\)\(b\)区间上关于\(x\)的定积分
  • \(\int f(x) \;dx\): \(f\)关于\(x\)的不定积分

概率与信息论

  • \(P(\cdot)\):概率分布
  • \(z \sim P\): 随机变量\(z\)具有概率分布\(P\)
  • \(P(X \mid Y)\)\(X\mid Y\)的条件概率
  • \(p(x)\): 概率密度函数
  • \({E}_{x} [f(x)]\): 函数\(f\)\(x\)的数学期望
  • \(X \perp Y\): 随机变量\(X\)\(Y\)是独立的
  • \(X \perp Y \mid Z\): 随机变量\(X\)\(Y\)在给定随机变量\(Z\)的条件下是独立的
  • \(\mathrm{Var}(X)\): 随机变量\(X\)的方差
  • \(\sigma_X\): 随机变量\(X\)的标准差
  • \(\mathrm{Cov}(X, Y)\): 随机变量\(X\)\(Y\)的协方差
  • \(\rho(X, Y)\): 随机变量\(X\)\(Y\)的相关性
  • \(H(X)\): 随机变量\(X\)的熵
  • \(D_{\mathrm{KL}}(P\|Q)\): \(P\)\(Q\)的KL-散度

复杂度

  • \(\mathcal{O}\):大O标记

数据处理

数据处理主要涉及到两个核心的问题,一个是如何读取数据,另外一个则是如何处理为空的数据。

将数据处理之后我们还需要将其转换为

读取数据

在Python中,我们可以使用pandas库来读取数据,pandas库提供了read_csv函数,可以读取csv文件,返回一个DataFrame对象。

作为实例,我们创建一个人工数据集,然后将其保存为csv文件,然后使用pandas库读取数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import os

os.makedirs(os.path.join('..', 'data'), exist_ok=True)
data_file = os.path.join('..', 'data', 'house_tiny.csv')
with open(data_file, 'w') as f:
f.write('NumRooms,Alley,Price\n') # 列名
f.write('NA,Pave,127500\n') # 每行表示一个数据样本
f.write('2,NA,106000\n')
f.write('4,NA,178100\n')
f.write('NA,NA,140000\n')

import pandas as pd
data = pd.read_csv(data_file)
print(data)

处理空数据

在panda中,数据集中的空数据被标记为NA,在进行机器训练的时候,不能让机器直接处理空数据,所以说我们需要对空数据进行处理,一般有下述几种办法: 1. 删除法 2. 插值法

删除法将带有空数据的行视为无效数据,直接删除,插值法则是用已知数据的平均值或者中位数等来填充空数据。

在这里,我们用插值法来处理空数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 读取输入和输出数据
inputs = data.iloc[:, [0,1]]
outputs = data.iloc[:, 2]

# 用平均值填充空数据
tempRaw = data.iloc[:,0]
print(tempRaw,tempRaw.mean())
tempRaw = tempRaw.fillna(tempRaw.mean())
print(tempRaw,type(tempRaw))

print(inputs,type(inputs))
inputs.iloc[:, 0] = tempRaw
print(inputs)
print(outputs)

下面逐行解释一下上述代码:

[[data.iloc]] 用于选取数据集中的行和列,data.iloc[:, [0,1]]表示选取所有行和第0、1列的数据,data.iloc[:, 2]表示选取所有行和第2列的数据。

[[data.fillna]] 用于填充空数据,tempRaw.fillna(tempRaw.mean())表示用 该列的平均值 填充 空数据。

[[data.iloc]] 返回的是一个DataFrame对象,我们可以直接对其进行操作,inputs.iloc[:, 0] = tempRaw表示将tempRaw的数据赋值给inputs的第0列。

转换为张量

使用 pandas 读取数据之后,我们得到的数据类型是 pandasDataFrame 对象,我们需要将其转换为张量,才能用于训练。

1
2
3
4
5
import torch

X = torch.tensor(inputs.to_numpy(dtype=float))
y = torch.tensor(outputs.to_numpy(dtype=float))
X, y

torch.tensor() 使用 numpy 数组 初始化创建一个 张量,inputs.to_numpy()DataFrame 对象转换为 numpy 数组,dtype=float 表示将数据转换为浮点数类型。

数据从 DataFrame -> numpy 数组 -> 张量,完成了数据的转换。

0%