Compare commits

...

189 Commits

Author SHA1 Message Date
174c101fb1
Such temperature 2024-11-30 19:53:05 -05:00
4e7e47dd94
Doing a cc4e 2024-11-30 15:53:33 -05:00
a5ce30aeeb
Up through tutorial part 3, the first bit 2024-09-16 06:56:04 -04:00
11d4baf648
Adding polls app while working through django tutorial 2024-09-15 21:26:11 -04:00
b1197d5c6a
Ruffed up 2024-09-14 21:36:07 -04:00
2be95276a5
Oh djoy 2024-09-14 21:34:50 -04:00
3c8412d858
Playing with binary IO 2024-05-03 23:27:56 -04:00
ac113056a8
Playing with binary read/write 2024-05-03 22:37:15 -04:00
7241713b3f
Making a mess of ex17 extra credit (NOT WORKING) 2024-05-03 21:50:46 -04:00
0d19b4cb4f
Doing nully things with strncpy 2024-04-29 08:12:17 -04:00
1a0ba35f7a
Up through happy path of lcthw ex17 2024-04-28 22:56:59 -04:00
869f273723
Do the lcthw ex16 extra credit with stack structs 2024-04-28 22:10:16 -04:00
4c2c6ef429
Goofing around with that intro to algorithms book again 2024-04-28 22:02:16 -04:00
e5166ee912
Sorting negative cards 2024-04-27 22:22:56 -04:00
6ea704fe5b
Add an assertion to Person_print 2024-04-20 13:01:33 -04:00
01348b1436
Up through lcthw exercise 16 2024-04-20 12:41:53 -04:00
2dfa546e78
Something like ex15 extra credit 2024-04-20 08:38:27 -04:00
224300e1cf
Up through lcthw ex 15 2024-04-19 21:51:42 -04:00
0ce1da0737
Fold up a few lines 2024-04-19 21:26:19 -04:00
b979a794d6
lcthw ex14 extra credit 2024-04-19 21:22:10 -04:00
d2d54c12a8
Read argv files via readarray 2024-04-19 21:11:24 -04:00
8ac30a239d
Up through lcthw ex14 2024-04-19 20:53:48 -04:00
d4b5c737e5
Switch to NULL-terminated 2D array 2024-04-19 20:44:43 -04:00
5381d5f0ce
Through lcthw ex13 plus some make rework 2024-04-19 08:14:39 -04:00
ea9cb1f846
Revert "A bit more silly extra credit for ex12"
This reverts commit 58e734c60f.
2024-04-18 19:45:56 -04:00
58e734c60f
A bit more silly extra credit for ex12 2024-04-18 19:45:38 -04:00
df5d4f5a1f
Kinda extra credit ex12 2024-04-18 18:49:10 -04:00
32e70e96ce
Up through lcthw ex12 2024-04-18 18:28:12 -04:00
8af4f619f4
Revert "Trying and failing to break ex11.c"
This reverts commit 52a5ea57e1.
2024-04-17 08:29:40 -04:00
52a5ea57e1
Trying and failing to break ex11.c 2024-04-17 08:29:30 -04:00
1a894440f9
Up through lcthw 11 2024-04-17 08:22:20 -04:00
353b77271d
Modifications to ex10 2024-04-16 21:10:49 -04:00
8f9842ddfb
Up through lcthw 10 2024-04-16 21:10:41 -04:00
94cd12ac82
While backward 2024-04-16 20:47:34 -04:00
726566bb23
Up through lcthw ex9 2024-04-16 20:46:08 -04:00
7e07054a70
Having 2024-04-16 20:45:47 -04:00
af95125894
Up through ex8 2024-04-16 08:17:54 -04:00
7da7228911
Up through lcthw ex7 2024-04-16 08:03:12 -04:00
88133117ab
A more makey makefile 2024-04-15 19:59:15 -04:00
c8ac7ac727
Much cleanup to better match lesson text 2024-04-15 15:28:45 -04:00
a135c338ea
LCTHW ex3 2024-04-15 15:22:58 -04:00
0fd7b5873d
LCTHW ex 2ish 2024-04-15 15:16:14 -04:00
e28293e5bd
Back to having fun with LCTHW 2024-04-15 14:30:58 -04:00
58002830a8
Swinging the pendulum back to extremely basic 2024-04-15 09:55:20 -04:00
8532dd4657
Heron something what the heck 2024-04-14 22:17:51 -04:00
f6ac67a6a6
Too many more things about ModernC 2024-04-14 22:08:23 -04:00
8424a6836a
Doing my part for the flame war 2024-04-13 13:32:43 -04:00
8e2f5c1ff0
The "bad" getting started 2024-04-13 13:25:31 -04:00
9183869a50
Begin working through Modern C 2018-ish edition 2024-04-13 12:07:04 -04:00
1ed7fb7d33
This home page is _personal_ 2024-03-01 22:49:44 -05:00
a498ff949c
Oh right this thing 2024-03-01 19:48:32 -05:00
ad65630b3f
Wasn't I doing something with the UMN Kauffman course 2024-03-01 19:46:36 -05:00
9109e3a3dc
Booping around with kauffman assembly basics
https://www-users.cse.umn.edu/~kauffman/2021/06-assembly-basics.pdf
2023-11-08 12:42:46 -05:00
9d36627e87
Cloned undirected graph 2023-11-01 00:12:36 -04:00
db38eeada9
One more thought about max sub-array 2023-10-31 08:00:18 -04:00
cb68a35b1b
Sliding window max (peeked a bit) 2023-10-31 00:58:52 -04:00
01a189c5ee
Yet Another Off By One Error 2023-10-28 08:24:17 -04:00
3580198513
Max sub-array slidey window 2023-10-28 08:21:39 -04:00
efb8f453ae
Weird copying linked list-ish thing with random 2023-10-27 17:33:22 -04:00
5df7489f27
Factorial trailing zeroes thing 2023-10-27 16:12:17 -04:00
efc1c8f029
Fully un-busted yet slow Trie 2023-10-27 08:19:03 -04:00
43a2e51712
Less busted trie 2023-10-26 20:44:05 -04:00
88e4e319d3
Busted trie impl 2023-10-26 19:59:11 -04:00
c274f59f58
Do a better RandomizedSet 2023-10-26 03:58:50 -04:00
c8a4928ee8
a rushed RandomizedSet impl 2023-10-25 20:15:43 -04:00
6d523ad7c1
h-index cleanups 2023-10-25 19:19:00 -04:00
d9393152c5
Something like h-index? 2023-10-25 19:18:05 -04:00
2f3ce704b2
Jump game finally (?) but differently than solutions 2023-10-25 16:51:35 -04:00
54a7a2340c
Trying jump game again 2023-10-24 19:46:01 -04:00
8cc2e18965
Move roman bits 2023-10-24 15:48:15 -04:00
ffb16efcdc
Cheating with binary tree goop 2023-10-24 15:42:42 -04:00
10ec594031
Trying to understand binary tree from array 2023-10-24 08:12:35 -04:00
cee338520e
Sum binary tree path ints 2023-10-21 16:34:42 -04:00
e92d117a41
Return the correct right-connected binary tree root 2023-10-21 16:19:13 -04:00
dc9c3fd54d
Binary tree right join goop 2023-10-21 15:45:16 -04:00
a8d82b180a
Sorting linked list with mutation (oh no) 2023-10-21 08:41:41 -04:00
337a795ad0
Linked list sorting (?) 2023-10-21 08:23:14 -04:00
3f369e1e70
Correct min stack (?) 2023-10-21 07:25:38 -04:00
a3819c9b26
A poorly-made min stack 2023-10-21 07:18:56 -04:00
345464d0d4
Add a guard rail around Roman.i2r 2023-10-20 10:51:29 -04:00
5b55118373
More fun with roman numbers 2023-10-20 10:38:20 -04:00
accf0d0c2b
Linty bits 2023-10-20 08:22:16 -04:00
b672131cfc
Rearranging a bit 2023-10-20 08:11:07 -04:00
d03225edce
Bisecting and matrix goop 2023-10-20 07:57:25 -04:00
8434bf7025
Goop while suffering through leetcode things 2023-10-19 11:23:24 -04:00
087355502d
A few more RBE things 2023-10-19 11:08:38 -04:00
0e6448df23
Remove the example mix project 2023-10-08 12:50:13 -04:00
4da817996d
Doing an example mix project 2023-10-08 12:49:42 -04:00
7e0aa3b86b
fn closures in RBE 2023-10-01 06:01:54 -04:00
aa83db6f7a
fn closure in RBE 2023-09-30 20:17:22 -04:00
9d4f5b661b
Up through fn methods in RBE 2023-09-30 20:05:41 -04:00
b94fb3b31e
Remaining flow control in RBE 2023-09-30 19:51:09 -04:00
dacbddca6e
Some if-let in RBE 2023-09-30 19:39:55 -04:00
6e50ec65f8
Flow control match binding in RBE 2023-09-29 16:52:18 -04:00
ca812add16
Much more flow control destructuring in RBE 2023-09-27 23:16:10 -04:00
460741740b
Flow control for in RBE 2023-09-26 11:03:55 -04:00
7204f08177
Expressions and starting flow control in RBE 2023-09-26 06:43:22 -04:00
505e04613f
Up through conversion in RBE 2023-09-26 06:07:51 -04:00
7f4f627769
Much renaming and refreshing of RBE 2023-09-24 20:46:41 -04:00
dc8045a20e
Trivial goop while refreshing on RBE 2023-09-24 10:57:16 -04:00
41f53c34c0
Making some arduino-shaped messes 2023-01-07 18:44:31 -05:00
6c0083e094
Sudoku through the end of chapter 8 2022-11-26 16:09:32 -05:00
7f2f579241
Sudoku up through chapter 7 2022-11-26 09:42:41 -05:00
7d2ac20ce1
Beginning of sudoku chapter 7 with SDM loading 2022-11-25 15:37:57 -05:00
8f38a3b271
Sudoku up through chapter 5 2022-11-25 12:20:01 -05:00
96f5f85a27
Piston Sudoku up through 3rd chapter 2022-11-24 18:56:18 -05:00
6cf80e09b1
Piston tutorial getting started woop! 2022-11-24 18:25:07 -05:00
30ed115ed0
Moving argh to separate repo 2022-06-06 18:50:25 -04:00
8376608a1e Merge pull request 'arghing' (#1) from arghing into main
Reviewed-on: #1
2022-06-06 22:44:24 +00:00
3de96b813f
Making more messes with parser config 2022-06-04 17:38:24 -04:00
a73acedc6d
Minor tracing tweaks 2022-06-03 23:12:53 -04:00
92e3d6fe5b
Support persistent flags 2022-05-31 08:24:58 -04:00
395006cdb8
Renaming some error list bits & testing windows-like 2022-05-29 21:12:57 -04:00
622d47071a
Rename second parser attempt 2022-05-29 19:16:13 -04:00
1452d544bb
Dropping previous parser attempt 2022-05-29 19:10:16 -04:00
56c6a8cf09
Handle remaining skipped cases 2022-05-29 19:04:31 -04:00
cc29386cee
Use parser2 in querier tests 2022-05-27 08:22:07 -04:00
95453bf197
Retain literals that are values 2022-05-27 08:11:31 -04:00
a6526af6ff
Implement value capture for last compound short flag 2022-05-25 22:34:32 -04:00
3ea30a997a
Implementing value capture for short flags
and ensuring all unknown ident/stdin nodes are retained
2022-05-25 22:24:12 -04:00
03edacc8ec
Implementing long flag values in parser2 2022-05-25 21:55:16 -04:00
d1ffbe25a3
Do AST better maybe? 2022-05-22 21:43:02 -04:00
dc3a40b19d
Continuing the work with parser that's more like go/parser 2022-05-22 20:49:11 -04:00
f2e0de1b66
Making a mess with a parser that works more like go/parser 2022-05-22 08:47:45 -04:00
58842504c4
Minor bits while giving up (for now?) on command context 2022-05-18 22:19:53 -04:00
1080737931
Work on separate querier + cleanups 2022-05-18 20:15:31 -04:00
de6e907c60
Handle bare assignments as syntax error + NValue rework 2022-05-16 08:24:24 -04:00
9989801e62
Ensure program and commands can also receive positional arg values 2022-05-15 20:55:54 -04:00
8c280c303e
Handle variable count flag values 2022-05-15 14:22:56 -04:00
b2e61cd0d2
More fun with parser and parse tree tests 2022-05-14 20:58:09 -04:00
c15bafe55d
Yet more argh implementation fun 2022-05-13 20:58:55 -04:00
af7d5c6e14
Making a mess with command line parsing 2022-05-11 22:11:05 -04:00
512eddc1ab
Spleling pdf gen 2022-01-30 11:29:35 -05:00
2bc9788441
Spleling 2022-01-30 11:28:41 -05:00
c52d9b9563
More silly bits with hyrule modeling/sim 2022-01-27 21:25:44 -05:00
fbb04df86d
Define hyrule strategy swap rules 2022-01-27 21:03:19 -05:00
e30cbe2aca
Playing with cards modeling 2022-01-25 10:13:53 -05:00
116ad347db
More clarity around 3+ player rules, formatting fun 2022-01-23 11:38:37 -05:00
1493deac96
More hyrule refinements 2022-01-23 09:34:46 -05:00
a7e45b8add
Clarify scoring 2022-01-22 21:37:52 -05:00
f1cc614836
Write out initial rules for "Hyrule" card game 2022-01-22 21:35:53 -05:00
a2661f4369
Bye now 2021-12-28 13:55:03 -05:00
b020618d57
Do the pixijs intro 2021-12-28 13:54:43 -05:00
d2405f75d8
Cleanup whoops 2021-12-28 09:20:09 -05:00
1d827b517b
Done with the react thing 2021-11-07 10:06:01 -05:00
47d658f04f
Going through the react tic-tac-toe tutorial 2021-11-07 10:05:16 -05:00
6c45a1390b
RBE types aliasing 2021-10-25 09:38:08 -04:00
b25e99a632
RBE types inference 2021-10-25 09:35:14 -04:00
abd957d42f
RBE types literals 2021-10-25 09:32:37 -04:00
d326a055f7
RBE types cast 2021-10-25 08:54:04 -04:00
6d6e600720
RBE more variable bindings fun 2021-10-06 19:40:31 -04:00
d2563484f9
RBE variable bindings mutability 2021-09-29 11:38:53 -04:00
eac3c2d8a6
RBE variable bindings 2021-09-29 11:35:26 -04:00
052fb87667
bleh 2021-09-13 09:21:29 -04:00
9f431fcb11
Silly stuff 2021-09-13 09:14:00 -04:00
7e6a2ea52b
Update guessing game usage of rand 2021-09-12 15:12:16 -04:00
f45663f248
clean up mbox thing 2021-09-12 10:56:12 -04:00
951c3bcebe
lol 2021-09-12 10:55:48 -04:00
f57429613a
Clean up vim-just bits 2021-09-12 10:55:29 -04:00
7e976ccc6f
shuffle shuffle 2021-09-12 10:55:12 -04:00
278ec88944
RBE custom types constants 2021-09-12 10:35:45 -04:00
f40981544c
RBE custom types enum testcase linked list 2021-09-11 21:03:58 -04:00
cbcf9ce5fc
RBE custom types enum c-like 2021-09-11 20:59:39 -04:00
30ef5d8c91
RBE custom types enum use 2021-09-11 20:56:43 -04:00
5d0811636f
RBE custom types enum 2021-09-11 20:53:14 -04:00
90f6fdad97
RBE custom types structs activity 2 2021-09-11 20:00:34 -04:00
c57baae2cc
RBE custom types structs activity 1 2021-09-11 13:52:45 -04:00
013a8faa2f
RBE custom types structs 2021-09-11 13:42:09 -04:00
798575d9ef
RBE primitives array 2021-09-11 13:35:25 -04:00
20531d1154
RBE primitives tuples activity 2 2021-09-11 13:28:22 -04:00
cabb0a9eab
RBE primitives tuples activity 1 2021-09-11 13:26:27 -04:00
93860403c2
RBE primitives tuples 2021-09-10 14:24:08 -04:00
c6d3ef3505
Bleh start again 2021-09-10 14:17:33 -04:00
e34eb0d48f
RBE primitives literals 2021-09-10 14:15:32 -04:00
f574628afc
RBE primitives 2021-09-10 14:09:54 -04:00
60da2e20dc
RBE hello/print/fmt activity 2021-09-10 11:18:23 -04:00
8f891c1e73
RBE's hello/print/fmt 2021-09-10 11:15:07 -04:00
82ed5d328d
Activity for testcase_list 2021-09-10 11:01:45 -04:00
49889a15b8
RBE's hello/print/print_display/testcase_list 2021-09-10 11:00:40 -04:00
5568eb4409
Extra activity in hello/print/print_display 2021-09-10 10:56:36 -04:00
8d0699fb7a
Refeshing RBE time 2021-09-10 10:40:48 -04:00
7ae9903d95
Reading bytes time 2021-06-01 10:27:17 -04:00
8f3897e097
Fun with tcp 2021-06-01 08:49:27 -04:00
05043d778a
Minor changes to example file 2021-05-28 13:11:30 -04:00
ff7d915872
Replace dynamic subshell syntax bit with a setting 2021-05-28 13:07:35 -04:00
a9d1c31201
Switch just names to "Constant" syntax group
for better visibility/differentiation
2021-05-27 21:27:42 -04:00
56321d17b6
Refining just syntax a bit more 2021-05-27 15:59:40 -04:00
5bfc637a7e
Make the shell detection better? 2021-05-23 20:43:59 -04:00
6600e7b295
Initial vim syntax for just
including:
- operators
- quotes/strings
- raw quotes/strings
- backtick sub-shells
- curly substitutions
- "set shell" handling
2021-05-23 20:18:17 -04:00
232 changed files with 10261 additions and 1205 deletions

11
.editorconfig Normal file
View File

@ -0,0 +1,11 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
max_line_length = 90
[{*.c,*.go}]
indent_style = tab
indent_size = 4

2
.gitignore vendored
View File

@ -1,7 +1,9 @@
*.hex
*.log
*.out
*env
.dep
**/target/
/hello_world/main
/aoc*/**/input
/arduino/build-*/

View File

@ -1,4 +1,4 @@
Copyright (C) 2020 Dan Buch
Copyright (C) 2022 Dan Buch
MIT License

View File

@ -1,13 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
[dev-packages]
mypy = ""
pytest = ""
[requires]
python_version = "3.9"

156
aoc2020/py/Pipfile.lock generated
View File

@ -1,156 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "ed02d1728cc686824535903ae2f5f3956ba104434c4c6e532237df55bcd69a12"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3.9"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {},
"develop": {
"attrs": {
"hashes": [
"sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6",
"sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.3.0"
},
"iniconfig": {
"hashes": [
"sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3",
"sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"
],
"version": "==1.1.1"
},
"mypy": {
"hashes": [
"sha256:0a0d102247c16ce93c97066443d11e2d36e6cc2a32d8ccc1f705268970479324",
"sha256:0d34d6b122597d48a36d6c59e35341f410d4abfa771d96d04ae2c468dd201abc",
"sha256:2170492030f6faa537647d29945786d297e4862765f0b4ac5930ff62e300d802",
"sha256:2842d4fbd1b12ab422346376aad03ff5d0805b706102e475e962370f874a5122",
"sha256:2b21ba45ad9ef2e2eb88ce4aeadd0112d0f5026418324176fd494a6824b74975",
"sha256:72060bf64f290fb629bd4a67c707a66fd88ca26e413a91384b18db3876e57ed7",
"sha256:af4e9ff1834e565f1baa74ccf7ae2564ae38c8df2a85b057af1dbbc958eb6666",
"sha256:bd03b3cf666bff8d710d633d1c56ab7facbdc204d567715cb3b9f85c6e94f669",
"sha256:c614194e01c85bb2e551c421397e49afb2872c88b5830e3554f0519f9fb1c178",
"sha256:cf4e7bf7f1214826cf7333627cb2547c0db7e3078723227820d0a2490f117a01",
"sha256:da56dedcd7cd502ccd3c5dddc656cb36113dd793ad466e894574125945653cea",
"sha256:e86bdace26c5fe9cf8cb735e7cedfe7850ad92b327ac5d797c656717d2ca66de",
"sha256:e97e9c13d67fbe524be17e4d8025d51a7dca38f90de2e462243ab8ed8a9178d1",
"sha256:eea260feb1830a627fb526d22fbb426b750d9f5a47b624e8d5e7e004359b219c"
],
"index": "pypi",
"markers": "python_version >= '3.5'",
"version": "==0.790"
},
"mypy-extensions": {
"hashes": [
"sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d",
"sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"
],
"version": "==0.4.3"
},
"packaging": {
"hashes": [
"sha256:24e0da08660a87484d1602c30bb4902d74816b6985b93de36926f5bc95741858",
"sha256:78598185a7008a470d64526a8059de9aaa449238f280fc9eb6b13ba6c4109093"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==20.8"
},
"pluggy": {
"hashes": [
"sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0",
"sha256:966c145cd83c96502c3c3868f50408687b38434af77734af1e9ca461a4081d2d"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.13.1"
},
"py": {
"hashes": [
"sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3",
"sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"
],
"markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==1.10.0"
},
"pyparsing": {
"hashes": [
"sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1",
"sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==2.4.7"
},
"pytest": {
"hashes": [
"sha256:1969f797a1a0dbd8ccf0fecc80262312729afea9c17f1d70ebf85c5e76c6f7c8",
"sha256:66e419b1899bc27346cb2c993e12c5e5e8daba9073c1fbce33b9807abc95c306"
],
"index": "pypi",
"markers": "python_version >= '3.6'",
"version": "==6.2.1"
},
"toml": {
"hashes": [
"sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b",
"sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"
],
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
"version": "==0.10.2"
},
"typed-ast": {
"hashes": [
"sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1",
"sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d",
"sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6",
"sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd",
"sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37",
"sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151",
"sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07",
"sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440",
"sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70",
"sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496",
"sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea",
"sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400",
"sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc",
"sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606",
"sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc",
"sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581",
"sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412",
"sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a",
"sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2",
"sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787",
"sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f",
"sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937",
"sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64",
"sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487",
"sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b",
"sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41",
"sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a",
"sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3",
"sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166",
"sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"
],
"version": "==1.4.2"
},
"typing-extensions": {
"hashes": [
"sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918",
"sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c",
"sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"
],
"version": "==3.7.4.3"
}
}
}

View File

@ -1,49 +0,0 @@
import sys
import typing
def main() -> int:
inputs = [int(s) for s in sys.stdin.read().split()]
for i, j in _find_2020_pairs(inputs):
print(f"pair: {i} * {j} == {i * j}")
for i, j, k in _find_2020_triplets(inputs):
print(f"triplet: {i} * {j} * {k} == {i * j * k}")
return 0
def _find_2020_pairs(
inputs: typing.List[int],
) -> typing.Generator[typing.Tuple[int, ...], None, None]:
found = []
for i, in0 in enumerate(inputs):
for j, in1 in enumerate(inputs):
if i == j:
continue
if in0 + in1 == 2020:
to_yield = tuple(sorted([in0, in1]))
if to_yield not in found:
yield to_yield
found.append(to_yield)
def _find_2020_triplets(
inputs: typing.List[int],
) -> typing.Generator[typing.Tuple[int, ...], None, None]:
found = []
for i, in0 in enumerate(inputs):
for j, in1 in enumerate(inputs):
for k, in2 in enumerate(inputs):
if i == j or i == k:
continue
if in0 + in1 + in2 == 2020:
to_yield = tuple(sorted([in0, in1, in2]))
if to_yield not in found:
yield to_yield
found.append(to_yield)
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,53 +0,0 @@
import sys
def main() -> int:
n_valid = 0
total = 0
for pol_pas in [PolicyPassword.fromstring(s) for s in sys.stdin.readlines(False)]:
if pol_pas.is_valid():
n_valid += 1
total += 1
print(f"{n_valid}/{total} valid")
return 0
class Policy:
def __init__(self, char: str, pos1: int, pos2: int):
self.char = char
self.pos1 = pos1
self.pos2 = pos2
@classmethod
def fromstring(cls, input_string) -> "Policy":
parts = [s.strip() for s in input_string.split(" ")][:2]
pos = [int(s) for s in parts[0].split("-")][:2]
return cls(parts[1], pos[0], pos[1])
def is_valid(self, password: str) -> bool:
matches = 0
for pos in (self.pos1 - 1, self.pos2 - 1):
if password[pos] == self.char:
matches += 1
return matches == 1
class PolicyPassword:
def __init__(self, policy: "Policy", password: str):
self.policy = policy
self.password = password
@classmethod
def fromstring(cls, input_string: str) -> "PolicyPassword":
parts = [s.strip() for s in input_string.split(":")][:2]
return cls(Policy.fromstring(parts[0]), parts[1])
def is_valid(self) -> bool:
return self.policy.is_valid(self.password)
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,52 +0,0 @@
import functools
import sys
import typing
class Loc(typing.NamedTuple):
x: int
y: int
def main() -> int:
forest_frame = [list(line.strip()) for line in sys.stdin.readlines()]
frame_width = len(forest_frame[0])
frame_height = len(forest_frame)
all_trees_encountered = []
for slope in [
Loc(x=1, y=1),
Loc(x=3, y=1),
Loc(x=5, y=1),
Loc(x=7, y=1),
Loc(x=1, y=2),
]:
loc = Loc(x=0, y=0)
trees_encountered = 0
while loc.y <= (frame_height - 1):
at_loc = forest_frame[loc.y][loc.x]
if at_loc == "#":
trees_encountered += 1
next_x = (loc.x + slope.x) % frame_width
next_y = loc.y + slope.y
next_loc = Loc(x=next_x, y=next_y)
loc = next_loc
print(
f"(slope right={slope.x} down={slope.y}) trees encountered: {trees_encountered}"
)
all_trees_encountered.append(trees_encountered)
trees_encountered_product = functools.reduce(
lambda x, y: x * y, all_trees_encountered
)
print(f"trees encountered product: {trees_encountered_product}")
return 0
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,115 +0,0 @@
import sys
import typing
def main() -> int:
checked = []
for passport in _read_passports(sys.stdin):
if passport is None:
checked.append(False)
continue
checked.append(passport.is_valid())
print(f"total={len(checked)} valid={checked.count(True)}")
return 0
NoneString = typing.Optional[str]
VALID_EYE_COLORS = ("amb", "blu", "brn", "gry", "grn", "hzl", "oth")
class Passport:
byr: NoneString = None
cid: NoneString = None
ecl: NoneString = None
eyr: NoneString = None
hcl: NoneString = None
hgt: NoneString = None
iyr: NoneString = None
pid: NoneString = None
def is_valid(self) -> bool:
return (
self._is_year_in_range(self.byr, range(1920, 2003))
and self._is_year_in_range(self.iyr, range(2010, 2021))
and self._is_year_in_range(self.eyr, range(2020, 2031))
and self._has_valid_height()
and self._has_valid_hair_color()
and self.ecl in VALID_EYE_COLORS
and self._has_valid_passport_id()
)
def _has_valid_height(self) -> bool:
if self.hgt is None:
return False
height_value = 0
height_value_string = self.hgt.replace("cm", "").replace("in", "")
if not height_value_string.isdigit():
return False
height = int(height_value_string)
if self.hgt.endswith("cm") and height in range(150, 194):
return True
elif self.hgt.endswith("in") and height in range(59, 77):
return True
return False
def _has_valid_hair_color(self) -> bool:
if self.hcl is None:
return False
if not self.hcl.startswith("#"):
return False
hair_value = self.hcl.replace("#", "")
if len(hair_value) != 6:
return False
try:
_ = int(hair_value, 16)
return True
except ValueError:
return False
def _has_valid_passport_id(self) -> bool:
return (
self.pid is not None
and len(self.pid) == 9
and all([s.isdigit() for s in list(self.pid)])
)
def _is_year_in_range(self, value: NoneString, yr_range: range) -> bool:
if value is None:
return False
if len(value) != 4:
return False
if not value.isdigit():
return False
return int(value) in yr_range
def _read_passports(
instream: typing.TextIO,
) -> typing.Generator[typing.Optional[Passport], None, None]:
cur = Passport()
for i, line in enumerate(instream):
line = line.strip()
if line == "":
yield cur
cur = Passport()
for pair in line.split():
attr, value = pair.split(":", 1)
setattr(cur, attr, value)
yield cur
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,77 +0,0 @@
import sys
import typing
def main() -> int:
highest_seat = 0
taken_seats = set()
for line in sys.stdin:
line = line.strip()
if line == "":
continue
seat = _locate_seat(line)
if seat.number > highest_seat:
highest_seat = seat.number
taken_seats.add(seat.number)
print(f"bp={line} row={seat.row} column={seat.col} seat={seat.number}")
seat_number: typing.Optional[int] = None
n_found = 0
for candidate_seat in range(0, (127 * 8) + 1):
if candidate_seat in taken_seats:
continue
if (candidate_seat - 1) in taken_seats and (candidate_seat + 1) in taken_seats:
seat_number = candidate_seat
n_found += 1
print(f"highest_seat={highest_seat} seat_number={seat_number} n_found={n_found}")
return 0
class Seat:
row: int
column: int
def __init__(self, row: int = 0, col: int = 0):
self.row = row
self.col = col
@property
def number(self) -> int:
return (self.row * 8) + self.col
def _locate_seat(bp: str) -> Seat:
rows = list(range(0, 128))
cols = list(range(0, 8))
row_part = list(bp[:7])
col_part = list(bp[7:])
return Seat(
row=_bisect(rows, [{"F": 0, "B": 1}[s] for s in row_part]),
col=_bisect(cols, [{"L": 0, "R": 1}[s] for s in col_part]),
)
def _bisect(initial_selection: typing.List[int], bisections: typing.List[int]) -> int:
selection = initial_selection[:]
for bisection in bisections:
halfway = int(len(selection) / 2)
selection = [selection[:halfway], selection[halfway:]][bisection]
return selection[0]
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,3 +0,0 @@
BFFFBBFRRR
FFFBBBFRRR
BBFFBBFRLL

View File

@ -1,3 +0,0 @@
bp=BFFFBBFRRR row=70 column=7 seat=567
bp=FFFBBBFRRR row=14 column=7 seat=119
bp=BBFFBBFRLL row=102 column=4 seat=820

View File

@ -1,21 +0,0 @@
import sys
from pathlib import Path
import pytest
from solution import main
HERE = Path(__file__).absolute().parent
def test_solution(capsys):
with (HERE / "test-input").open() as infile:
sys.stdin = infile
main()
expected_output = (HERE / "test-output").read_text().splitlines()
assert expected_output == [
l for l in capsys.readouterr().out.splitlines() if l.startswith("counts_sum=")
]

View File

@ -1,42 +0,0 @@
import sys
import typing
def main() -> int:
counts_sum = sum([c for c in _iter_group_counts(sys.stdin)])
print(f"counts_sum={counts_sum}")
return 0
def _iter_group_counts(instream: typing.TextIO) -> typing.Generator[int, None, None]:
for i, group in enumerate(_iter_groups(instream)):
answers = set(list(group[0]))
print(f"i={i} initial={answers}")
for answers_text in group[1:]:
to_add = set(list(answers_text))
answers = answers.intersection(set(list(answers_text)))
print(f"i={i} added={to_add} result={answers}")
print(f"i={i} final={answers} n={len(answers)}")
yield len(answers)
def _iter_groups(instream):
cur_group = []
for line in instream:
line = line.strip()
if line == "":
yield cur_group
cur_group = []
continue
cur_group.append(line)
yield cur_group
if __name__ == "__main__":
sys.exit(main())

View File

@ -1,15 +0,0 @@
abc
a
b
c
ab
ac
a
a
a
a
b

View File

@ -1 +0,0 @@
counts_sum=6

View File

@ -1,21 +0,0 @@
import sys
from pathlib import Path
import pytest
from solution import main
HERE = Path(__file__).absolute().parent
def test_solution(capsys):
with (HERE / "test-input").open() as infile:
sys.stdin = infile
main()
expected_output = (HERE / "test-output").read_text().splitlines()
assert expected_output == [
l for l in capsys.readouterr().out.splitlines() if l.startswith("counts_sum")
]

2
arduino/.envrc Normal file
View File

@ -0,0 +1,2 @@
export ARDMK_DIR=/usr/share/arduino
export ARDMK_VENDOR=archlinux-arduino

3
arduino/Makefile Normal file
View File

@ -0,0 +1,3 @@
BOARD_TAG = uno
include $(ARDMK_DIR)/Arduino.mk

31
arduino/sos.ino Normal file
View File

@ -0,0 +1,31 @@
#define DIT_DURATION_MS 88
#define LETTER_PAUSE_MS 1000
void setup() {
pinMode(13, OUTPUT);
}
void dit() {
digitalWrite(13, HIGH);
delay(DIT_DURATION_MS);
digitalWrite(13, LOW);
delay(DIT_DURATION_MS);
}
void dah() {
digitalWrite(13, HIGH);
delay(DIT_DURATION_MS * 3);
digitalWrite(13, LOW);
delay(DIT_DURATION_MS);
}
void loop() {
dit(); dit(); dit();
delay(LETTER_PAUSE_MS);
dah();
delay(LETTER_PAUSE_MS);
dit(); dit(); dit();
delay(LETTER_PAUSE_MS);
}

19
cc4e/fc.c Normal file
View File

@ -0,0 +1,19 @@
#include <stdio.h>
/* print Fahrenheit-Celsius table
for f = 0, 20, ..., 300 */
int main() {
int lower, upper, step;
float fahr, celsius;
lower = 0; /* lower limit of temperature table */
upper = 300; /* upper limit */
step = 20; /* step size */
fahr = lower;
while (fahr <= upper) {
celsius = (5.0/9.0) * (fahr-32.0);
printf("%4.0f %6.1f\n", fahr, celsius);
fahr = fahr + step;
}
}

12
cc4e/fc_2.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
#define LOWER 0 /* lower limit of table */
#define UPPER 300 /* upper limit */
#define STEP 20 /* step size */
int main() { /* Fahrenheit-Celsius table */
int fahr;
for (fahr = LOWER; fahr <= UPPER; fahr = fahr + STEP)
printf("%4d %6.1f\n", fahr, (5.0/9.0)*(fahr-32));
}

5
cc4e/hello.c Normal file
View File

@ -0,0 +1,5 @@
#include <stdio.h>
int main() {
printf("hello, world\n");
return 0;
}

2
djoy/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.venv/
*.sqlite3

1
djoy/.python-version Normal file
View File

@ -0,0 +1 @@
3.12.6

0
djoy/djoy/__init__.py Normal file
View File

16
djoy/djoy/asgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
ASGI config for djoy project.
It exposes the ASGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/
"""
import os
from django.core.asgi import get_asgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djoy.settings")
application = get_asgi_application()

125
djoy/djoy/settings.py Normal file
View File

@ -0,0 +1,125 @@
"""
Django settings for djoy project.
Generated by 'django-admin startproject' using Django 5.1.1.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/5.1/ref/settings/
"""
import os
import pathlib
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = pathlib.Path(__file__).resolve().parent.parent
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get("DJOY_SECRET_KEY", "django-insecure-0xohno")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
"polls.apps.PollsConfig",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
ROOT_URLCONF = "djoy.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
WSGI_APPLICATION = "djoy.wsgi.application"
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
# Password validation
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
},
{
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
},
{
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
},
{
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
},
]
# Internationalization
# https://docs.djangoproject.com/en/5.1/topics/i18n/
LANGUAGE_CODE = "en-us"
TIME_ZONE = "UTC"
USE_I18N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.1/howto/static-files/
STATIC_URL = "static/"
# Default primary key field type
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"

24
djoy/djoy/urls.py Normal file
View File

@ -0,0 +1,24 @@
"""
URL configuration for djoy project.
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/5.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import include, path
urlpatterns = [
path("polls/", include("polls.urls")),
path("admin/", admin.site.urls),
]

16
djoy/djoy/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for djoy project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djoy.settings")
application = get_wsgi_application()

23
djoy/manage.py Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
"""Run administrative tasks."""
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "djoy.settings")
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
if __name__ == "__main__":
main()

0
djoy/polls/__init__.py Normal file
View File

5
djoy/polls/admin.py Normal file
View File

@ -0,0 +1,5 @@
from django.contrib import admin
from .models import Question
admin.site.register(Question)

6
djoy/polls/apps.py Normal file
View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class PollsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "polls"

View File

@ -0,0 +1,51 @@
# Generated by Django 5.1.1 on 2024-09-16 01:23
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.CreateModel(
name="Question",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("question_text", models.CharField(max_length=200)),
("pub_date", models.DateTimeField(verbose_name="date published")),
],
),
migrations.CreateModel(
name="Choice",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("choice_text", models.CharField(max_length=200)),
("votes", models.IntegerField(default=0)),
(
"question",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="polls.question"
),
),
],
),
]

View File

24
djoy/polls/models.py Normal file
View File

@ -0,0 +1,24 @@
import datetime
from django.db import models
from django.utils import timezone
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField("date published")
def __str__(self):
return self.question_text
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=models.CASCADE)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
def __str__(self):
return self.choice_text

3
djoy/polls/tests.py Normal file
View File

@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

11
djoy/polls/urls.py Normal file
View File

@ -0,0 +1,11 @@
from django.urls import path
from . import views
urlpatterns = [
path("", views.index, name="index"),
path("<int:question_id>/", views.detail, name="detail"),
path("<int:question_id>/results/", views.results, name="results"),
path("<int:question_id>/vote/", views.vote, name="vote"),
]

26
djoy/polls/views.py Normal file
View File

@ -0,0 +1,26 @@
from django.http import HttpResponse
from .models import Question
def index(request) -> HttpResponse:
latest_question_list = Question.objects.order_by("-pub_date")[:5]
output = ", ".join([q.question_text for q in latest_question_list])
return HttpResponse(output.encode())
def detail(request, question_id) -> HttpResponse:
_ = request
return HttpResponse(f"You're looking at question {question_id}.".encode())
def results(request, question_id) -> HttpResponse:
_ = request
return HttpResponse(
f"You're looking at the results of question {question_id}".encode()
)
def vote(request, question_id) -> HttpResponse:
_ = request
return HttpResponse(f"You're voting on question {question_id}".encode())

3
djoy/requirements.txt Normal file
View File

@ -0,0 +1,3 @@
Django
django-stubs
ruff

View File

@ -1,116 +0,0 @@
import argparse
import gzip
import hashlib
import logging
import os
import pathlib
import sys
import time
import typing
def main(sysargs=sys.argv[:]) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("mbox", type=argparse.FileType("rb"))
parser.add_argument("output_directory", type=pathlib.Path)
parser.add_argument(
"-s",
"--zzz",
default=0.005,
type=float,
help="sleep seconds in between messages",
)
parser.add_argument(
"-D",
"--debug",
action="store_true",
help="increase logging verbosity to debug level",
)
args = parser.parse_args(sysargs[1:])
log_level = logging.INFO
if os.environ.get("DEBUG") == "enabled":
log_level = logging.DEBUG
logging.basicConfig(level=log_level)
MBoxExploder().explode(
mbox=args.mbox, output_directory=args.output_directory, pause_seconds=args.zzz
)
return 0
class MBoxMessage:
def __init__(self):
self.lines = []
def as_gz_bytes(self) -> bytes:
return gzip.compress(self.as_bytes())
def as_bytes(self) -> bytes:
return b"".join([l for l in self.lines])
def signature(self) -> str:
return hashlib.sha512(self.as_bytes()).hexdigest()
def relpath(self) -> str:
sig = self.signature()
return os.path.sep.join([sig[0:2], sig[2:4], sig])
def gz_relpath(self) -> str:
return self.relpath() + ".gz"
class MBoxExploder:
def __init__(self):
self._log = logging.getLogger().getChild("mbox-exploder")
def explode(
self,
mbox: typing.BinaryIO,
output_directory: pathlib.Path,
pause_seconds: float,
):
for i, msg in enumerate(self._iter_mbox(mbox)):
if len(msg.lines) < 2:
self._log.warn("skipping invalid message (%r)", i)
continue
dest = output_directory / msg.gz_relpath()
dest.parent.mkdir(parents=True, exist_ok=True)
self._log.info("writing message to %s", str(dest))
dest.write_bytes(msg.as_gz_bytes())
time.sleep(pause_seconds)
def _iter_mbox(
self, mbox: typing.BinaryIO
) -> typing.Generator[MBoxMessage, None, None]:
msg = MBoxMessage()
cur_line = b""
while True:
byte = mbox.read(1)
if len(byte) == 0:
self._log.debug("reached EOF")
msg.lines.append(cur_line)
yield msg
return
cur_line += byte
if byte != b"\n":
continue
if cur_line.startswith(b"From ") and len(msg.lines) > 1:
self._log.debug("reached new msg")
yield msg
msg = MBoxMessage()
self._log.debug("appending line %r", cur_line)
msg.lines.append(cur_line)
cur_line = b""
if __name__ == "__main__":
sys.exit(main())

178
guessing_game/Cargo.lock generated
View File

@ -1,178 +0,0 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "autocfg"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
dependencies = [
"bitflags",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
[[package]]
name = "guessing_game"
version = "0.1.0"
dependencies = [
"rand",
]
[[package]]
name = "libc"
version = "0.2.80"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614"
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
dependencies = [
"autocfg",
"libc",
"rand_chacha",
"rand_core 0.4.2",
"rand_hc",
"rand_isaac",
"rand_jitter",
"rand_os",
"rand_pcg",
"rand_xorshift",
"winapi",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
dependencies = [
"autocfg",
"rand_core 0.3.1",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
dependencies = [
"rand_core 0.4.2",
]
[[package]]
name = "rand_core"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rand_jitter"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b"
dependencies = [
"libc",
"rand_core 0.4.2",
"winapi",
]
[[package]]
name = "rand_os"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
dependencies = [
"cloudabi",
"fuchsia-cprng",
"libc",
"rand_core 0.4.2",
"rdrand",
"winapi",
]
[[package]]
name = "rand_pcg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
dependencies = [
"autocfg",
"rand_core 0.4.2",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -1,3 +0,0 @@
fn main() {
println!("Hello, world!");
}

207
hyrule/README.md Normal file
View File

@ -0,0 +1,207 @@
# Hyrule
A card game for 2-7 players.
## requirements
Use a standard card playing deck, keeping Jokers. Shuffle however
you like.
## dealing
Each player is dealt 7 cards, kept secret from other players.
## turns
There are two variations for taking turns. "Chance rules" is
strictly a matter of chance, and is recommended for impatient
players because it tends to be faster-paced and has more of a
*surprise!* element. "Strategy rules" introduces an element of
strategy and is better suited for players with more _patience_.
### chance rules
Each player selects one card and places it face down in the middle
playing area between themselves and other players.
On the count of 3, all said together in rhythm, each player flips
over their own card. Precedence applies and the winning player
takes all cards.
### strategy rules
On the first turn or when an equal number of cards have been
captured by each player, the tallest player goes first. On each
subsequent turn, the player with the most captured cards plays
first. The play order then proceeds counter-clockwise.
When taking one's turn, the player may choose to either *play* or
*swap*.
#### strategy *play*
When choosing to *play*, the player selects a card and places it
face-up in the center play area. The remaining players take turns
counter-clockwise, each placing a card face-up in the center play
area. Precedence rules apply and the winning player takes all
cards.
#### strategy *swap*
When choosing to *swap*, the player discards one card face-up in
the discard pile (next to the stock pile) and then draws a card
from the stock, which should be laying face-down. The goal here may
be to take a chance at getting a better card than one is
discarding, or to force the next player in the rotation to play, or
both.
> **NOTE**: a player may only choose to *swap* if the player on the
> previous turn _did not swap_.
## precedence
The following rules apply across suits with the exception of
*jokers and fives* (explained below). Cards within a single suit
are compared with higher-value cards winning. Cards are counted
from ace (1) through king (13).
Ways to think about these rules could include:
- "rupee buys bomb" / money buys weapon
- "rupee buys sword" / money buys weapon
- "bomb blows up sword" / range weapon beats melee weapon
- "bomb blows up heart" / range weapon beats unarmed
- "sword cuts through heart" / melee weapon beats unarmed
- "heart is stronger than rupee" / love conquers money
**NOTE:** In the case of a turn that involves 3 or more cards, the
presence of both diamonds *and* hearts will result in the
highest-value heart winning the turn.
### diamonds ("rupees")
Beats:
- clubs ("bombs")
- spades ("swords")
### clubs ("bombs")
Beats:
- spades ("swords")
- hearts
### spades ("swords")
Beats:
- hearts
### hearts
Beats:
- diamonds ("rupees")
### jokers ("tingles")
Beats everything except *fives*
### fives
The 5 of a given suit will be granted special status *only* when
played against a joker ("tingle") and will win with the following
sub-precedence, which is roughly the inverse of the main
precedence:
- 5 of hearts
- 5 of spades / "master sword"
- 5 of clubs / "bomb cluster"
- 5 of diamonds / "blue rupee"
## scoring
At the conclusion of a round of 7 cards, the player with the most
cards is the winner. The face values of the cards are not
considered at scoring time. A draw may be handled in a "run-off
game" or ignored as you like.
## examples
In the following examples, the **winning card** is highlighted at
the top of each list, followed by an explanation for the outcome.
### 2-player
- **2 of clubs**
- 2 of spades
Clubs are higher-value than spades, or "bomb beats sword".
---
- **2 of clubs**
- ace of clubs
Cards within the same suit are compared at face value with aces
being *1*.
---
- **ace of hearts**
- king of diamonds
Hearts take precedence over diamonds, or "love is stronger than
money".
---
- **joker**
- king of hearts
The opposing card is not a *five*, or "tingle takes _(thing)_".
---
- **5 of spades**
- joker
The 5 of any suit will beat a joker given its special item status
in that scenario, or "tingle is distracted by the beauty of
_(thing)_".
### 3-player
- **2 of diamonds**
- 2 of clubs
- 2 of spades
Diamonds have higher precedence than clubs and spades, and there
are no hearts present.
---
- **6 of clubs**
- 6 of spades
- 6 of hearts
Clubs have higher precedence than spades and hearts, and there are
no diamonds present.
---
- **8 of hearts**
- 8 of diamonds
- 8 of spades
When both diamonds and hearts are present, hearts is highest
precedence.
---
- **king of diamonds**
- jack of diamonds
- queen of diamonds
Within the same suit, cards are compared by face value.

BIN
hyrule/README.pdf Normal file

Binary file not shown.

86
hyrule/cards.py Normal file
View File

@ -0,0 +1,86 @@
import dataclasses
import enum
import random
Suit = enum.Enum(
"Suit",
"""
CLUBS
DIAMONDS
HEARTS
SPADES
""",
)
FaceValue = enum.Enum(
"FaceValue",
"""
ACE
TWO
THREE
FOUR
FIVE
SIX
SEVEN
EIGHT
NINE
TEN
JACK
QUEEN
KING
""",
)
@dataclasses.dataclass
class Card:
suit: Suit
face_value: FaceValue
def __str__(self):
return f"{self.face_value} of {self.suit}"
class Joker:
def __str__(self):
return "JOKER"
class Deck:
def __init__(self, n_jokers=2):
self._cards = list(Deck.generate(n_jokers=n_jokers))
def __repr__(self):
return f"<Deck len={len(self)}>"
def __str__(self):
as_string = []
for card in self._cards:
as_string.append(str(card))
return "\n".join(as_string)
def __len__(self):
return len(self._cards)
def draw(self):
if len(self._cards) > 0:
return self._cards.pop()
return None
def shuffle(self):
random.shuffle(self._cards)
return self
def cut(self):
cut_point = random.randint(0, len(self))
self._cards = self._cards[cut_point:] + self._cards[:cut_point]
return self
@staticmethod
def generate(n_jokers=2):
for _ in range(n_jokers):
yield Joker()
for suit in Suit:
for face_value in FaceValue:
yield Card(suit=suit, face_value=face_value)

66
hyrule/hyrule.py Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env python3
import argparse
import dataclasses
import pprint
import sys
import typing
import cards
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter
)
parser.add_argument(
"--player-count", "-c", default=2, type=int, help="The number of players"
)
parser.add_argument(
"--turn-count",
"-n",
default=5,
type=int,
help="The number of turns to play",
)
args = parser.parse_args()
Hyrule(player_count=args.player_count, turn_count=args.turn_count).play()
return 0
@dataclasses.dataclass
class Player:
index: int
hand: typing.Set[cards.Card]
captured: typing.Set[cards.Card]
@property
def score(self):
return len(self.captured)
class Hyrule:
def __init__(self, player_count=2, turn_count=5):
self._players = [
Player(index=i, hand=set(), captured=set()) for i in range(player_count)
]
self._turn_count = turn_count
def play(self):
for turn in self._each_turn():
self._show_turn(turn)
def _each_turn(self):
for turn_number in range(self._turn_count):
yield self._simulate_turn(turn_number)
def _simulate_turn(self, turn_number):
...
def _show_turn(self, turn):
print(turn)
if __name__ == "__main__":
sys.exit(main())

2
hyrule/justfile Normal file
View File

@ -0,0 +1,2 @@
build:
pandoc -r markdown -w pdf -o README.pdf README.md

View File

@ -0,0 +1,62 @@
package main
import (
"fmt"
"os"
"strconv"
"strings"
)
func main() {
inBytes, err := os.ReadFile(os.Args[1])
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(1)
}
inLines := strings.Split(strings.TrimSpace(string(inBytes)), "\n")
inInts := make([]int64, len(inLines))
for i, line := range inLines {
v, err := strconv.ParseInt(line, 0, 64)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(1)
}
inInts[i] = v
}
if err := insertionSort(inInts); err != nil {
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
os.Exit(1)
}
for _, i := range inInts {
fmt.Printf("%v\n", i)
}
}
func insertionSort(inInts []int64) error {
if len(inInts) < 2 {
return nil
}
for j := 1; j < len(inInts); j += 1 {
key := inInts[j]
fmt.Fprintf(os.Stderr, "%+v (save %v from %v)\n", inInts, key, j)
i := j - 1
for ; i > -1 && inInts[i] > key; i -= 1 {
inInts[i+1] = inInts[i]
fmt.Fprintf(os.Stderr, "%+v (j=%v i=%v)\n", inInts, j, i)
}
inInts[i+1] = key
fmt.Fprintf(os.Stderr, "%+v (insert %v at %v)\n", inInts, key, i+1)
}
return nil
}

View File

@ -0,0 +1,38 @@
import os
import sys
def main() -> int:
in_ints: list[int] = []
with open(sys.argv[1]) as infile:
for line in infile:
in_ints.append(int(line.strip()))
insertion_sort(in_ints)
for i in in_ints:
print(i)
return 0
def insertion_sort(in_ints: list[int]) -> None:
for i in range(len(in_ints) - 1):
j = i + 1
key = in_ints[j]
print(f"{in_ints} (save {key} from {j})", file=sys.stderr)
while i > -1 and in_ints[i] > key:
in_ints[i + 1] = in_ints[i]
print(f"{in_ints} (j={j} i={i})", file=sys.stderr)
i -= 1
in_ints[i + 1] = key
print(f"{in_ints} (insert {key} at {i+1})", file=sys.stderr)
if __name__ == "__main__":
sys.exit(main())

View File

@ -0,0 +1,10 @@
11
2
17
-1
34
8
999
2
-56
3

1
lcthw/.envrc Normal file
View File

@ -0,0 +1 @@
export CFLAGS='-Werror -g'

3
lcthw/.ex10.argv Normal file
View File

@ -0,0 +1,3 @@
carrot
angelfood
yellow

5
lcthw/.ex13.argv Normal file
View File

@ -0,0 +1,5 @@
garble
geckle
gimple
gorble
gunkle

5
lcthw/.ex14.argv Normal file
View File

@ -0,0 +1,5 @@
eggs
legs
pegs
jeggings
banana pants

2
lcthw/.ex17.argv Normal file
View File

@ -0,0 +1,2 @@
ex17.db
l

2
lcthw/.ex17ec.argv Normal file
View File

@ -0,0 +1,2 @@
ex17ec.db
l

1
lcthw/.ex17play.argv Normal file
View File

@ -0,0 +1 @@
ex17play.bin

1
lcthw/.gdbinit Normal file
View File

@ -0,0 +1 @@
set debuginfod enabled off

2
lcthw/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
ex*
!ex*.c

35
lcthw/Makefile Normal file
View File

@ -0,0 +1,35 @@
SHELL := /bin/bash
CFLAGS ?= -Wall -g
GDBRUN = gdb --batch --ex run --ex bt --ex q --args
BUILD_TARGETS = $(foreach ex,$(wildcard ex*.c),$(subst .c,,$(ex)))
.PHONY: all
all: build test
.PHONY: echo
echo:
@echo BUILD_TARGETS=$(BUILD_TARGETS)
.PHONY: clean
clean:
rm -f $(BUILD_TARGETS)
.PHONY: build
build: $(BUILD_TARGETS)
.PHONY: gtest
gtest: $(BUILD_TARGETS)
@$(foreach bt, $(BUILD_TARGETS), make .gtest.$(bt) &&) printf '\ngYAY\n'
.gtest.%: %
@if test -f .$*.argv; then readarray -t test_argv <.$*.argv; fi && \
printf '\n==> %s\n' "$*" && $(GDBRUN) ./$* "$${test_argv[@]}"
.PHONY: test
test: $(BUILD_TARGETS)
@$(foreach bt, $(BUILD_TARGETS), make .test.$(bt) &&) printf '\nYAY\n'
.test.%: %
@if test -f .$*.argv; then readarray -t test_argv <.$*.argv; fi && \
printf '\n==> %s\n' "$*" && ./$* "$${test_argv[@]}"

12
lcthw/ex1.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
/* This is a comment. */
int main(int argc, char *argv[])
{
int distance = 100;
// this is also a comment
printf("You are %d miles away.\n", distance);
return 0;
}

62
lcthw/ex10.c Normal file
View File

@ -0,0 +1,62 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
if (argc < 2) {
printf("ERROR: You need at least one argument.\n");
// this is how you abort a program
return 1;
}
int i = 0;
int arg = 1;
for (arg = 1; arg < argc; arg++) {
for (i = 0; argv[arg][i] != '\0'; i++) {
printf("(%d) ", arg);
char letter = argv[arg][i];
// lowercase letters
if (letter >= 'A' && letter <= 'Z') {
letter += ('a' - 'A');
}
switch (letter) {
case 'a':
printf("%d: 'a'\n", i);
break;
case 'e':
printf("%d: 'e'\n", i);
break;
case 'i':
printf("%d: 'i'\n", i);
break;
case 'o':
printf("%d: 'o'\n", i);
break;
case 'u':
printf("%d: 'u'\n", i);
break;
case 'y':
// why i > 2? is this a bug?
if (i > 2) {
// it's only sometimes Y
printf("%d: 'y'\n", i);
} else {
printf("%d: %c is not a vowel\n", i, letter);
}
break;
default:
printf("%d: %c is not a vowel\n", i, letter);
}
}
}
return 0;
}

48
lcthw/ex11.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
int numbers[4] = { 0 };
char name[4] = { 'a' };
// first, print them out raw
printf("numbers: %d %d %d %d\n",
numbers[0], numbers[1], numbers[2], numbers[3]);
printf("name each: %c %c %c %c\n",
name[0], name[1], name[2], name[3]);
printf("name: %s\n", name);
// setup the numbers
numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 3;
numbers[3] = 4;
// setup the name
name[0] = 'Z';
name[1] = 'e';
name[2] = 'd';
name[3] = '\0';
// then print them out initialized
printf("numbers: %d %d %d %d\n",
numbers[0], numbers[1], numbers[2], numbers[3]);
printf("name each: %c %c %c %c\n",
name[0], name[1], name[2], name[3]);
// print the name like a string
printf("name: %s\n", name);
// another way to use name
char *another = "Zed";
printf("another: %s\n", another);
printf("another each: %c %c %c %c\n",
another[0], another[1], another[2], another[3]);
return 0;
}

32
lcthw/ex12.c Normal file
View File

@ -0,0 +1,32 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
int areas[] = { 10, 12, 13, 14, 20 };
char name[] = "Zed";
char full_name[] = {
'Z', 'e', 'd',
' ', 'A', '.', ' ',
'S', 'h', 'a', 'w', '\0',
};
// WARNING: On some systems you may have to change the
// %ld in this code to a %u since it will use unsigned ints
printf("The size of an int: %ld\n", sizeof(int));
printf("The size of areas (int[]): %ld\n", sizeof(areas));
printf("The number of ints in areas: %ld\n",
sizeof(areas) / sizeof(int));
printf("The first area is %d, the 2nd %d.\n", areas[0], areas[1]);
printf("The size of a char: %ld\n", sizeof(char));
printf("The size of name (char[]): %ld\n", sizeof(name));
printf("The number of chars: %ld\n", sizeof(name) / sizeof(char));
printf("The size of full_name (char[]): %ld\n", sizeof(full_name));
printf("The number of chars: %ld\n",
sizeof(full_name) / sizeof(char));
printf("name=\"%s\" and full_name=\"%s\"\n", name, full_name);
return 0;
}

26
lcthw/ex13.c Normal file
View File

@ -0,0 +1,26 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 0;
// go through each string in argv
// why am I skipping argv[0]?
for (i = 1; i < argc; i++) {
printf("arg %d: %s\n", i, argv[i]);
}
// let's make our own array of strings
char *states[] = {
"California",
"Oregon",
"Washington",
"Texas",
NULL,
};
for (i = 0; states[i] != NULL; i++) {
printf("state %d: %s\n", i, states[i]);
}
return 0;
}

36
lcthw/ex14.c Normal file
View File

@ -0,0 +1,36 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
// forward declarations
void print_letters(size_t len, char arg[]);
void print_arguments(int argc, char *argv[])
{
int i = 0;
for (i = 0; i < argc; i++) {
print_letters(strlen(argv[i]), argv[i]);
}
}
void print_letters(size_t len, char arg[])
{
int i = 0;
for (i = 0; i < len; i++) {
char ch = arg[i];
if (isprint((int)ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
int main(int argc, char *argv[])
{
print_arguments(argc, argv);
return 0;
}

56
lcthw/ex15.c Normal file
View File

@ -0,0 +1,56 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
// create two arrays we care about
int ages[] = { 23, 43, 12, 89, 2 };
char *names[] = {
"Alan", "Frank",
"Mary", "John", "Lisa"
};
// safely get the size of ages
int count = sizeof(ages) / sizeof(int);
int i = 0;
char **first_name = &names[0];
char **last_name = &names[count - 1];
printf("first_name=%p last_name=%p\n", first_name, last_name);
printf("*first_name=%s *last_name=%s\n", *first_name, *last_name);
printf("---\n");
// first way using indexing
for (i = count - 1; i > -1; i--) {
printf("%s has %d years alive.\n", names[i], ages[i]);
}
printf("---\n");
// setup the pointers to the start of the arrays
int *cur_age = ages;
char **cur_name = names;
// second way using pointers
for (i = count - 1; i > -1; i--) {
printf("%s is %d years old.\n", *(cur_name + i), *(cur_age + i));
}
printf("---\n");
// third way, pointers are just arrays
for (i = count - 1; i > -1; i--) {
printf("%s is %d years old again.\n", cur_name[i], cur_age[i]);
}
printf("---\n");
// fourth way with pointers in a stupid complex way
for (cur_name = names, cur_age = ages;
(cur_age - ages) < count; cur_name++, cur_age++) {
printf("%s lived %d years so far.\n", *cur_name, *cur_age);
}
return 0;
}

73
lcthw/ex16.c Normal file
View File

@ -0,0 +1,73 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who->name);
free(who);
}
void Person_print(struct Person *who)
{
assert(who != NULL);
printf("Name: %s\n", who->name);
printf("\tAge: %d\n", who->age);
printf("\tHeight: %d\n", who->height);
printf("\tWeight: %d\n", who->weight);
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person *joe = Person_create("Joe Alex", 32, 64, 100);
struct Person *frank = Person_create("Frank Blank", 20, 72, 180);
// print them out and where they are in memory
printf("Joe is at memory location %p:\n", joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", frank);
Person_print(frank);
// make everyone age 20 years and print them again
joe->age += 20;
joe->height -= 2;
joe->weight += 40;
Person_print(joe);
frank->age += 20;
frank->weight += 20;
Person_print(frank);
// destroy them both so we clean up
Person_destroy(joe);
Person_destroy(frank);
return 0;
}

57
lcthw/ex16ec.c Normal file
View File

@ -0,0 +1,57 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Person {
char *name;
int age;
int height;
int weight;
};
struct Person Person_create(char *name, int age, int height, int weight)
{
struct Person who;
who.name = strdup(name);
who.age = age;
who.height = height;
who.weight = weight;
return who;
}
void Person_print(struct Person who)
{
printf("Name: %s\n", who.name);
printf("\tAge: %d\n", who.age);
printf("\tHeight: %d\n", who.height);
printf("\tWeight: %d\n", who.weight);
}
int main(int argc, char *argv[])
{
// make two people structures
struct Person joe = Person_create("Joe Alex", 32, 64, 100);
struct Person frank = Person_create("Frank Blank", 20, 72, 180);
// print them out and where they are in memory
printf("Joe is at memory location %p:\n", &joe);
Person_print(joe);
printf("Frank is at memory location %p:\n", &frank);
Person_print(frank);
// make everyone age 20 years and print them again
joe.age += 20;
joe.height -= 2;
joe.weight += 40;
Person_print(joe);
frank.age += 20;
frank.weight += 20;
Person_print(frank);
return 0;
}

237
lcthw/ex17.c Normal file
View File

@ -0,0 +1,237 @@
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#define MAX_DATA 512
#define MAX_ROWS 100
struct Address {
int id;
int set;
char name[MAX_DATA];
char email[MAX_DATA];
};
struct Database {
struct Address rows[MAX_ROWS];
};
struct Connection {
FILE *file;
struct Database *db;
};
void die(const char *message)
{
if (errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
void Address_print(struct Address *addr)
{
printf("%d %s %s\n", addr->id, addr->name, addr->email);
}
void Database_load(struct Connection *conn)
{
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
if (rc != 1) {
die("Failed to load database.");
}
}
struct Connection *Database_open(const char *filename, char mode)
{
struct Connection *conn = malloc(sizeof(struct Connection));
if (!conn) {
die("Memory error");
}
conn->db = malloc(sizeof(struct Database));
if (!conn->db) {
die("Memory error");
}
if (mode == 'c') {
conn->file = fopen(filename, "w");
} else {
conn->file = fopen(filename, "r+");
if (conn->file) {
Database_load(conn);
}
}
if (!conn->file) {
die("Failed to open file");
}
return conn;
}
void Database_close(struct Connection *conn)
{
if (conn) {
if (conn->file) {
fclose(conn->file);
}
if (conn->db) {
free(conn->db);
}
free(conn);
}
}
void Database_write(struct Connection *conn)
{
rewind(conn->file);
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
if (rc != 1) {
die("Failed to write database.");
}
rc = fflush(conn->file);
if (rc == -1) {
die("Cannot flush database");
}
}
void Database_create(struct Connection *conn)
{
int i = 0;
for (i = 0; i < MAX_ROWS; i++) {
struct Address addr = {.id = i, .set = 0};
conn->db->rows[i] = addr;
}
}
void Database_set(struct Connection *conn, int id, const char *name, const char *email)
{
struct Address *addr = &conn->db->rows[id];
if (addr->set) {
die("Already set, delete it first");
}
addr->set = 1;
char *res = strncpy(addr->name, name, MAX_DATA);
if (!res) {
die("Name copy failed");
}
addr->name[MAX_DATA - 1] = '\0';
res = strncpy(addr->email, email, MAX_DATA);
if (!res) {
die("Email copy failed");
}
addr->email[MAX_DATA - 1] = '\0';
}
void Database_get(struct Connection *conn, int id)
{
struct Address *addr = &conn->db->rows[id];
if (addr->set) {
Address_print(addr);
} else {
die("ID is not set");
}
}
void Database_delete(struct Connection *conn, int id)
{
struct Address addr = {.id = id, .set = 0};
conn->db->rows[id] = addr;
}
void Database_list(struct Connection *conn)
{
int i = 0;
struct Database *db = conn->db;
for (i = 0; i < MAX_ROWS; i++) {
struct Address *cur = &db->rows[i];
if (cur->set) {
Address_print(cur);
}
}
}
int main(int argc, char *argv[])
{
if (argc < 3) {
die("USAGE: ex17 <dbfile> <action> [action params]");
}
char *filename = argv[1];
char action = argv[2][0];
struct Connection *conn = Database_open(filename, action);
int id = 0;
if (argc > 3) {
id = atoi(argv[3]);
}
if (id >= MAX_ROWS) {
die("There's not that many records.");
}
switch (action) {
case 'c':
Database_create(conn);
Database_write(conn);
break;
case 'g':
if (argc != 4) {
die("Need an id to get");
}
Database_get(conn, id);
break;
case 's':
if (argc != 6) {
die("Need an id, name, email to set");
}
Database_set(conn, id, argv[4], argv[5]);
Database_write(conn);
break;
case 'd':
if (argc != 4) {
die("Need an id to delete");
}
Database_delete(conn, id);
Database_write(conn);
break;
case 'l':
Database_list(conn);
break;
default:
die("Invalid action: c=create, g=get, s=set, d=del, l=list");
}
Database_close(conn);
return 0;
}

305
lcthw/ex17ec.c Normal file
View File

@ -0,0 +1,305 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#define DEFAULT_MAX_DATA 512
#define DEFAULT_MAX_ROWS 100
struct Address {
char *name;
char *email;
};
struct TableOfContents {
size_t n_rows;
size_t string_field_size;
};
struct Database {
struct Address *rows;
};
struct Connection {
FILE *file;
struct TableOfContents *toc;
struct Database *db;
};
void Database_close(struct Connection *conn);
struct Address *Database_get(struct Connection *conn, const char *email);
void die(struct Connection *conn, const char *message)
{
Database_close(conn);
if (errno) {
perror(message);
} else {
printf("ERROR: %s\n", message);
}
exit(1);
}
void Address_print(struct Address *addr)
{
if (!addr) {
return;
}
printf("%s %s\n", addr->name, addr->email);
}
size_t Database_addr_size(struct Connection *conn)
{
return sizeof(struct Address) +
/* name */ conn->toc->string_field_size +
/* email */ conn->toc->string_field_size;
}
size_t Database_size(struct Connection *conn)
{
return sizeof(struct Database) +
(conn->toc->n_rows * Database_addr_size(conn));
}
size_t Database_n_rows(struct Connection *conn)
{
return sizeof(conn->db->rows) / Database_addr_size(conn);
}
void Database_load(struct Connection *conn)
{
int rc = 0;
rc = fread(conn->toc, sizeof(struct TableOfContents), 1, conn->file);
if (rc != 1) {
die(conn, "Failed to load TableOfContents.");
}
rc = fread(conn->db, Database_size(conn), 1, conn->file);
if (rc != 1) {
die(conn, "Failed to load Database.");
}
}
struct Connection *Database_open(const char *filename, char mode, size_t string_field_size)
{
struct Connection *conn = malloc(sizeof(struct Connection));
if (!conn) {
die(conn, "Memory error allocating Connection");
}
conn->toc = malloc(sizeof(struct TableOfContents));
if (!conn->toc) {
die(conn, "Memory error allocating TableOfContents");
}
conn->toc->string_field_size = string_field_size;
conn->db = malloc(sizeof(struct Database));
if (!conn->db) {
die(conn, "Memory error allocating Database");
}
if (mode == 'c') {
conn->file = fopen(filename, "w");
conn->toc->n_rows = 1;
conn->db->rows = malloc(Database_addr_size(conn));
if (!conn->db->rows) {
die(conn, "Memory error allocating Database rows");
}
} else {
conn->file = fopen(filename, "r+");
if (conn->file) {
Database_load(conn);
}
}
if (!conn->file) {
die(conn, "Failed to open file");
}
return conn;
}
void Database_close(struct Connection *conn)
{
if (conn) {
if (conn->file) {
fclose(conn->file);
}
if (conn->toc) {
free(conn->toc);
}
if (conn->db) {
free(conn->db);
}
free(conn);
}
}
void Database_write(struct Connection *conn)
{
rewind(conn->file);
int rc = 0;
rc = fwrite(conn->toc, sizeof(struct TableOfContents), 1, conn->file);
if (rc != 1) {
die(conn, "Failed to write TableOfContents.");
}
rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
if (rc != 1) {
die(conn, "Failed to write Database.");
}
rc = fflush(conn->file);
if (rc == -1) {
die(conn, "Cannot flush");
}
}
void Database_set(struct Connection *conn, const char *name, const char *email)
{
struct Address *addr = Database_get(conn, email);
if (!addr) {
addr = malloc(Database_addr_size(conn));
conn->db->rows[Database_n_rows(conn)+1] = *addr;
}
char *res = strncpy(addr->name, name, conn->toc->string_field_size);
if (!res) {
die(conn, "Name copy failed");
}
addr->name[conn->toc->string_field_size - 1] = '\0';
res = strncpy(addr->email, email, conn->toc->string_field_size);
if (!res) {
die(conn, "Email copy failed");
}
addr->email[conn->toc->string_field_size - 1] = '\0';
}
struct Address *Database_get(struct Connection *conn, const char *email)
{
int i = 0;
struct Address *addr;
for (i = 0; i < Database_n_rows(conn); i++) {
addr = &conn->db->rows[i];
if (strcmp(addr->email, email) == 0) {
return addr;
}
}
return NULL;
}
void Database_delete(struct Connection *conn, const char *email)
{
struct Address *addr = Database_get(conn, email);
if (!addr) {
// already deleted
return;
}
addr->email = NULL;
addr->name = NULL;
}
void Database_list(struct Connection *conn)
{
int i = 0;
struct Database *db = conn->db;
for (i = 0; i < Database_n_rows(conn); i++) {
struct Address *cur = &db->rows[i];
Address_print(cur);
}
}
size_t get_string_field_size()
{
size_t string_field_size = DEFAULT_MAX_DATA;
const char *string_field_size_string = getenv("EX17_MAX_DATA");
if (string_field_size_string) {
int string_field_size_int = atoi(string_field_size_string);
string_field_size = string_field_size_int;
}
return string_field_size;
}
int main(int argc, char *argv[])
{
if (argc < 3) {
die(NULL, "USAGE: ex17 <dbfile> <action> [action params]");
}
char *filename = argv[1];
char action = argv[2][0];
size_t string_field_size = get_string_field_size();
struct Connection *conn = Database_open(filename, action, string_field_size);
switch (action) {
case 'c':
Database_write(conn);
break;
case 'g':
if (argc != 4) {
die(conn, "Need an `email` to get");
}
Address_print(Database_get(conn, argv[3]));
break;
case 's':
if (argc != 5) {
die(conn, "Need a `name` and `email` to set");
}
Database_set(conn, argv[3], argv[4]);
Database_write(conn);
break;
case 'd':
if (argc != 4) {
die(conn, "Need an `email` to delete");
}
Database_delete(conn, argv[3]);
Database_write(conn);
break;
case 'l':
Database_list(conn);
break;
default:
die(conn, "Invalid action: c=create, g=get, s=set, d=del, l=list");
}
Database_close(conn);
return 0;
}

109
lcthw/ex17play.c Normal file
View File

@ -0,0 +1,109 @@
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define NAME_SIZE 64
struct State {
int counter;
time_t updated_at;
char name[NAME_SIZE];
size_t history_entries;
};
static char *names[] = {
"boingo",
"barko",
"flip",
"dingles",
"zebra",
"horus",
"blendy",
"kitems",
"horple",
NULL,
};
char *random_name()
{
int i = 0;
int mod = 0;
for (i = 0; names[i] != NULL; i++) {
mod = i;
}
return names[random() % mod];
}
void tick(FILE *fp, int init)
{
struct State *state = malloc(sizeof(struct State));
if (!state) {
err(EXIT_FAILURE, "Memory error making State");
}
if (init == 0) {
size_t read = fread(state, sizeof(struct State), 1, fp);
fprintf(
stderr,
"Read %d \"%s\" (%lu byte(s)) from %lu\n",
state->counter, state->name, sizeof(struct State) * read, state->updated_at
);
}
time_t history[state->history_entries];
size_t histories_read = fread(&history, sizeof(time_t), state->history_entries, fp);
state->counter++;
state->updated_at = time(0);
strncpy(state->name, random_name(), NAME_SIZE);
state->history_entries++;
rewind(fp);
size_t wrote = fwrite(state, sizeof(struct State), 1, fp);
fwrite(history, sizeof(time_t), sizeof(history) / sizeof(time_t), fp);
fwrite(&state->updated_at, sizeof(time_t), 1, fp);
fprintf(
stderr,
"Wrote %d \"%s\" (%lu byte(s)) at %lu (history length=%lu)\n",
state->counter, state->name, sizeof(struct State) * wrote, state->updated_at,
state->history_entries
);
}
int main(int argc, char *argv[])
{
if (argc < 2) {
errx(EXIT_FAILURE, "Missing filename argument");
}
int random_seed = time(0);
const char *random_seed_str = getenv("RANDOM_SEED");
if (random_seed_str) {
random_seed = atoi(random_seed_str);
}
srandom(random_seed);
int init = 0;
FILE *fp = fopen(argv[1], "r+");
if (!fp) {
fp = fopen(argv[1], "w+");
init = 1;
}
if (!fp) {
err(EXIT_FAILURE, "Failed to open file");
}
tick(fp, init);
fclose(fp);
return 0;
}

12
lcthw/ex3.c Normal file
View File

@ -0,0 +1,12 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
int age = 10;
int height = 72;
printf("I am %d years old.\n", age);
printf("I am %d inches tall.\n", height);
return 0;
}

43
lcthw/ex7.c Normal file
View File

@ -0,0 +1,43 @@
#include <stdio.h>
int main(int argc, char* argv[])
{
int distance = 100;
float power = 2.345f;
double super_power = 56789.4532;
char initial = 'A';
char first_name[] = "Zed";
char last_name[] = "Shaw";
printf("You are %d miles away.\n", distance);
printf("You have %f levels of power.\n", power);
printf("You have %f awesome super powers.\n", super_power);
printf("I have an initial %c.\n", initial);
printf("I have a first name %s.\n", first_name);
printf("I have a last name %s.\n", last_name);
printf("My whole name is %s %c. %s.\n",
first_name, initial, last_name);
int bugs = 100;
double bug_rate = 1.2;
printf("You have %d bugs at the imaginary rate of %f.\n",
bugs, bug_rate);
long universe_of_defects = 1L * 1024L * 1024L * 1024L;
printf("The entire universe has %ld bugs.\n", universe_of_defects);
double expected_bugs = bugs * bug_rate;
printf("You are expected to have %f bugs.\n", expected_bugs);
double part_of_universe = expected_bugs / universe_of_defects;
printf("That is only a %e portion of the universe.\n",
part_of_universe);
// this makes no sense, just a demo of something weird
char nul_byte = '\0';
int care_percentage = bugs * nul_byte;
printf("Which means you should care %d%%.\n", care_percentage);
return 0;
}

21
lcthw/ex8.c Normal file
View File

@ -0,0 +1,21 @@
#include <stdio.h>
int main(int argc, char* argv[])
{
int i = 0;
if (argc == 1) {
printf("You have no argument.\n");
} else if (argc > 1 && argc < 4) {
printf("Here's your arguments:\n");
for (i = 0; i < argc; i++) {
printf("%s ", argv[i]);
}
printf("\n");
} else {
printf("You have too many arguments.\n");
}
return 0;
}

15
lcthw/ex9.c Normal file
View File

@ -0,0 +1,15 @@
#include <stdio.h>
int main(int argc, char *argv[])
{
int i = 25;
while (i > 0) {
printf("%d", i);
i--;
}
// need this to add a final newline
printf("\n");
return 0;
}

1
leetcode/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.envrc

1
leetcode/.python-version Normal file
View File

@ -0,0 +1 @@
3.12.0

File diff suppressed because one or more lines are too long

147
leetcode/pyproject.toml Normal file
View File

@ -0,0 +1,147 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "leetcode"
description = 'What A Mess'
readme = "README.md"
version = "0.1.0"
requires-python = ">=3.7"
license = "MIT"
keywords = []
authors = [
{ name = "Dan Buch", email = "dan@meatballhat.com" },
]
classifiers = []
dependencies = [
"ipython",
"ipdb",
"matplotlib",
"numpy"
]
[tool.hatch.envs.default]
dependencies = [
"coverage[toml]>=6.5",
"pytest",
]
[tool.hatch.envs.default.scripts]
test = "pytest {args:tests}"
test-cov = "coverage run -m pytest {args:tests}"
cov-report = [
"- coverage combine",
"coverage report",
]
cov = [
"test-cov",
"cov-report",
]
[[tool.hatch.envs.all.matrix]]
python = ["3.7", "3.8", "3.9", "3.10", "3.11"]
[tool.hatch.envs.lint]
detached = true
dependencies = [
"black>=23.1.0",
"mypy>=1.0.0",
"ruff>=0.0.243",
]
[tool.hatch.envs.lint.scripts]
typing = "mypy --install-types --non-interactive {args:.}"
style = [
"ruff {args:.}",
"black --check --diff {args:.}",
]
fmt = [
"black {args:.}",
"ruff --fix {args:.}",
"style",
]
all = [
"style",
"typing",
]
[tool.black]
target-version = ["py37"]
line-length = 90
[tool.ruff]
target-version = "py37"
line-length = 90
select = [
"A",
"ARG",
"B",
"C",
"DTZ",
"E",
"EM",
"F",
"FBT",
"I",
"ICN",
"ISC",
"N",
"PLC",
"PLE",
"PLR",
"PLW",
"Q",
"RUF",
"S",
"T",
"TID",
"UP",
"W",
"YTT",
]
ignore = [
# Allow non-abstract empty methods in abstract base classes
"B027",
# Allow boolean positional values in function calls, like `dict.get(... True)`
"FBT003",
# Ignore checks for possible passwords
"S105", "S106", "S107",
# Ignore complexity
"C901", "PLR0911", "PLR0912", "PLR0913", "PLR0915",
# Allow print func
"T201",
# Allow assert statements
"S101",
]
unfixable = [
# Don't touch unused imports
"F401",
]
[tool.ruff.isort]
known-first-party = ["leetcode"]
[tool.ruff.flake8-tidy-imports]
ban-relative-imports = "all"
[tool.ruff.per-file-ignores]
# Tests can use magic values, assertions, and relative imports
"tests/**/*" = ["PLR2004", "S101", "TID252"]
[tool.coverage.run]
source_pkgs = ["leetcode", "tests"]
branch = true
parallel = true
omit = [
"src/leetcode/__about__.py",
]
[tool.coverage.paths]
leetcode = ["src/leetcode", "*/leetcode/src/leetcode"]
tests = ["tests", "*/leetcode/tests"]
[tool.coverage.report]
exclude_lines = [
"no cov",
"if __name__ == .__main__.:",
"if TYPE_CHECKING:",
]

57
leetcode/roman.py Normal file
View File

@ -0,0 +1,57 @@
SIMPLE = {
"I": 1,
"V": 5,
"X": 10,
"L": 50,
"C": 100,
"D": 500,
"M": 1000,
}
SIMPLE_REVERSE = {v: k for k, v in SIMPLE.items()}
COMPOUND = {
"IV": 4,
"IX": 9,
"XL": 40,
"XC": 90,
"CD": 400,
"CM": 900,
}
PREFIXES = {k[0] for k in COMPOUND.keys()}
COMPOUND_REVERSE = {v: k for k, v in COMPOUND.items()}
ALL = SIMPLE | COMPOUND
ALL_REVERSE = {v: k for k, v in ALL.items()}
def i2r(i: int) -> str:
if i > 100_000:
raise ValueError(f"{i} is too silly")
r: list[str] = []
for int_val, roman_val in sorted(ALL_REVERSE.items(), reverse=True):
remainder = i % int_val
r += [roman_val] * int((i - remainder) / int_val)
i = remainder
return "".join(r)
def r2i(r: str) -> int:
total = 0
offset = 0
for i in range(len(r)):
if i + offset > len(r) - 1:
break
c = r[i + offset]
if c in PREFIXES and (i + offset + 1) < len(r) and c + r[i + offset + 1] in ALL:
total += ALL[c + r[i + offset + 1]]
offset += 1
continue
total += ALL[c]
return total

57
leetcode/spiral_matrix.py Normal file
View File

@ -0,0 +1,57 @@
import itertools
import typing
def matrix_spiral(matrix: list[list[typing.Any]]) -> list[typing.Any]:
return [matrix[y][x] for x, y in matrix_spiral_path(matrix)]
def matrix_spiral_path(matrix: list[list[int]]) -> list[tuple[int, int]]:
snek = SpinSnek(matrix)
while snek.step():
...
return snek.path
COMPASS = (
(1, 0), # east
(0, 1), # south
(-1, 0), # west
(0, -1), # north
)
class SpinSnek:
def __init__(self, board: list[list[int]], loc: tuple[int, int] = (0, 0)):
self.max_loc: tuple[int, int] = (len(board[0]) - 1, len(board) - 1)
self.spinner: itertools.cycle[tuple[int, int]] = itertools.cycle(COMPASS)
self.direction = next(self.spinner)
self.path: list[tuple[int, int]] = [loc]
self.missteps: int = 0
def step(self) -> bool:
loc = self.path[-1]
next_loc: tuple[int, int] = (
loc[0] + self.direction[0],
loc[1] + self.direction[1],
)
if (
next_loc[0] > self.max_loc[0]
or next_loc[1] > self.max_loc[1]
or next_loc[0] < 0
or next_loc[1] < 0
or next_loc in self.path
):
self.direction = next(self.spinner)
if self.missteps > len(COMPASS) - 1:
return False
self.missteps += 1
return self.step()
self.missteps: int = 0
self.path.append(next_loc)
return True

169
leetcode/stdlib.py Normal file
View File

@ -0,0 +1,169 @@
import dataclasses
import typing
class LinkedListNode(typing.Protocol):
val: int
next: typing.Optional["LinkedListNode"]
class ListNode:
"""ListNode is the leetcode "standard library" type used in linked lists"""
def __init__(self, val: int = 0, next: typing.Optional["ListNode"] = None): # no qa
self.val = val
self.next = next
class ListNodeRandom:
"""ListNodeRandom is another weirdo linked list thing from
leetcode that is obviously very different than a binary tree
node :upside_down_face:
"""
def __init__(
self,
x: int,
next: typing.Optional["ListNodeRandom"] = None,
random: typing.Optional["ListNodeRandom"] = None,
):
self.val = x
self.next = next
self.random = random
@dataclasses.dataclass
class ListNodeRandomNicely:
val: int
next: typing.Optional["ListNodeRandomNicely"] = None
random: typing.Optional["ListNodeRandomNicely"] = None
class BinaryTreeNode(typing.Protocol):
val: int
left: typing.Optional["BinaryTreeNode"]
right: typing.Optional["BinaryTreeNode"]
class TreeNode:
"""TreeNode is the leetcode "standard library" type used in binary trees"""
def __init__(
self,
val: int = 0,
left: typing.Optional["TreeNode"] = None,
right: typing.Optional["TreeNode"] = None,
):
self.val = val
self.left = left
self.right = right
@classmethod
def from_int(cls, val: int | None) -> typing.Optional["TreeNode"]:
if val is None:
return None
return TreeNode(val)
# __repr__ was added by me
def __repr__(self) -> str:
filtered_parts = []
for key, value in [
("val", self.val),
("left", self.left),
("right", self.right),
]:
if value is not None:
filtered_parts.append((key, value))
middle = ", ".join([f"{k}={v!r}" for k, v in filtered_parts])
return f"TreeNode({middle})"
# __eq__ was added by me
def __eq__(self, other: typing.Optional["TreeNode"]) -> bool:
return (
other is not None
and self.val == other.val
and self.left == other.left
and self.right == other.right
)
class ConnectableBinaryTreeNode(typing.Protocol):
val: int
left: typing.Optional["BinaryTreeNode"]
right: typing.Optional["BinaryTreeNode"]
next: typing.Optional["BinaryTreeNode"]
class Node:
"""Node is the *other* leetcode "standard library" type used in binary trees"""
def __init__(
self,
val: int = 0,
left: typing.Optional["Node"] = None,
right: typing.Optional["Node"] = None,
next: typing.Optional["Node"] = None, # no qa
):
self.val = val
self.left = left
self.right = right
self.next = next
# __repr__ was added by me
def __repr__(self) -> str:
filtered_parts = []
for key, value in [
("val", self.val),
("right", self.right),
("left", self.left),
("next", self.next),
]:
if value is not None:
filtered_parts.append((key, value))
middle = ", ".join([f"{k}={v!r}" for k, v in filtered_parts])
return f"Node({middle})"
# __eq__ was added by me
def __eq__(self, other: "Node") -> bool:
return (
other is not None
and self.val == other.val
and self.left == other.left
and self.right == other.right
and self.next == other.next
)
# __list__ was added by me
def __list__(self) -> list[int | None]:
ret = [self.val]
ret += self.right.__list__() if self.right is not None else [None]
ret += self.left.__list__() if self.left is not None else [None]
ret += self.next.__list__() if self.next is not None else [None]
return ret
class NeighborlyNode:
"""NeighborlyNode is a "Node" type used in leetcode graph puzzles"""
def __init__(self, val=0, neighbors=None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
class NeighborlyNodeNicely(typing.NamedTuple):
val: int
neighbors: list["NeighborlyNodeNicely"]
def __eq__(self, other: typing.Optional["NeighborlyNodeNicely"]) -> bool:
return (
other is not None
and self.val == other.val
and [n.val for n in self.neighbors] == [n.val for n in other.neighbors]
)

640
leetcode/stuff.py Normal file
View File

@ -0,0 +1,640 @@
import collections.abc
import copy
import random
import typing
import stdlib
def yep(s: str) -> bool:
return s.strip().lower().startswith("y")
def guess_bisect_repl(lower: int, upper: int) -> int:
mid = lower + ((upper - lower) // 2)
if yep(input(f"is it {mid}? ")):
return mid
if yep(input(f"higher than {mid}? ")):
return guess_bisect_repl(mid, upper)
return guess_bisect_repl(lower, mid)
def find_sqrt_ish(n: int) -> int:
return int(find_bisect(0, n, gen_sqrt_check(n)))
def gen_sqrt_check(n: int) -> typing.Callable[[float], int]:
def check(mid: float) -> int:
mid_sq: float = mid * mid
if mid_sq == n:
return 0
if mid_sq < n:
return 1
return -1
return check
def find_bisect(
lower: float, upper: float, check: typing.Callable[[float], int]
) -> float:
mid: float = lower + ((upper - lower) / 2)
print(f"lower={lower} mid={mid} upper={upper}")
if mid == lower or mid == upper or check(mid) == 0:
return mid
if check(mid) == 1:
return find_bisect(mid, upper, check)
return find_bisect(lower, mid, check)
def cartesian_path(p0: tuple[int, int], p1: tuple[int, int]) -> list[tuple[int, int]]:
path: list[tuple[int, int]] = []
if p0 < p1:
for i in range(p0[1], p1[1]):
path.append((i, p0[0]))
for i in range(p0[0], p1[0]):
path.append((p1[1], i))
else:
for i in range(p0[1], p1[1] - 1, -1):
path.append((i, p0[0]))
for i in range(p0[0] - 1, p1[0], -1):
path.append((p1[1], i))
return path
def gen_matrix(width: int, height: int) -> list[list[int]]:
return [list(range(width)) for _ in range(height)]
class MinStack:
def __init__(self):
self._v: list[int] = []
self._min: list[int] = []
def push(self, val: int) -> None:
self._v.append(val)
self._min.append(min(val, self._min[-1] if self._min else val))
def pop(self) -> None:
self._v.pop(-1)
self._min.pop(-1)
def top(self) -> int:
return self._v[-1]
def getMin(self) -> int: # no qa
return self._min[-1]
def linked_list_to_list(head: stdlib.LinkedListNode | None) -> list[int]:
seen: set[int] = set()
ret: list[int] = []
while head is not None:
if hash(head) in seen:
return ret
seen.add(hash(head))
ret.append(head.val)
head = head.next
return ret
def sort_linked_list(head: stdlib.LinkedListNode | None) -> stdlib.LinkedListNode | None:
by_val: list[tuple[int, stdlib.LinkedListNode]] = []
ret: stdlib.LinkedListNode | None = None
while head is not None:
by_val.append((head.val, head))
head = head.next
cur = ret
for _, node in sorted(by_val, key=lambda v: v[0]):
if cur is None:
cur = ret = node
continue
cur.next = node
cur = cur.next
if cur is not None:
cur.next = None
return ret
def connect_binary_tree_right(
root: stdlib.ConnectableBinaryTreeNode | None,
) -> tuple[stdlib.ConnectableBinaryTreeNode | None, list[int | None]]:
if root is None:
return None, []
by_level = binary_tree_by_level(copy.deepcopy(root))
by_level = typing.cast(dict[int, list[stdlib.ConnectableBinaryTreeNode]], by_level)
serialized: list[int | None] = []
print("")
if 0 not in by_level or len(by_level[0]) == 0:
return None, []
connected_root = by_level[0][0]
for level, nodes in sorted(by_level.items(), key=lambda p: p[0]):
for i in range(len(nodes)):
serialized.append(nodes[i].val)
if len(nodes) > i + 1:
print(f"{'-' * level}> connecting {nodes[i].val} -> {nodes[i + 1].val}")
nodes[i].next = nodes[i + 1]
serialized.append(None)
return connected_root, serialized
def binary_tree_by_level(
root: stdlib.BinaryTreeNode,
) -> dict[int, list[stdlib.BinaryTreeNode]]:
combined: dict[int, list[stdlib.BinaryTreeNode]] = {}
for path in collect_binary_tree_levels(0, root):
level, node = path
combined.setdefault(level, [])
combined[level].insert(0, node)
return combined
def collect_binary_tree_levels(
level: int, node: stdlib.BinaryTreeNode | None
) -> typing.Iterator[tuple[int, stdlib.BinaryTreeNode]]:
if node is None:
return
yield (level, node)
yield from collect_binary_tree_levels(level + 1, node.right)
yield from collect_binary_tree_levels(level + 1, node.left)
def sum_binary_tree_path_ints(root: stdlib.BinaryTreeNode | None) -> int:
path_ints: list[int] = []
for path in collect_binary_tree_paths(root):
path_ints.append(int("".join([str(node.val) for node in path])))
return sum(path_ints)
def binary_tree_paths_as_lists(
paths: list[list[stdlib.BinaryTreeNode]],
) -> list[list[int]]:
paths_vals: list[list[int]] = []
for path in paths:
paths_vals.append([node.val for node in path])
return paths_vals
def collect_binary_tree_paths(
node: stdlib.BinaryTreeNode | None,
) -> typing.Iterator[list[stdlib.BinaryTreeNode]]:
if node is None:
return
if node.right is None and node.left is None:
yield [node]
return
if node.right is not None:
for path in collect_binary_tree_paths(node.right):
yield [node] + path
if node.left is not None:
for path in collect_binary_tree_paths(node.left):
yield [node] + path
def binary_tree_from_list(inlist: list[int | None]) -> stdlib.BinaryTreeNode | None:
if len(inlist) == 0:
return None
nodes: list[stdlib.BinaryTreeNode | None] = [
typing.cast(stdlib.BinaryTreeNode | None, stdlib.TreeNode.from_int(i))
for i in inlist
]
nodes_copy = nodes[::-1]
root = nodes_copy.pop()
for node in nodes:
if node is None:
continue
if len(nodes_copy) == 0:
break
node.left = nodes_copy.pop()
if len(nodes_copy) > 0:
node.right = nodes_copy.pop()
return root
def binary_tree_from_preorder_inorder(
preorder: list[int], inorder: list[int]
) -> stdlib.BinaryTreeNode | None:
preorder_reversed = preorder[::-1]
def subtree(left: list[int], right: list[int]) -> stdlib.BinaryTreeNode:
root: stdlib.BinaryTreeNode = typing.cast(
stdlib.BinaryTreeNode, stdlib.TreeNode(preorder_reversed.pop())
)
if len(left) > 1:
split_pos = left.index(preorder_reversed[-1])
root.left = subtree(left[:split_pos], left[split_pos + 1 :])
elif len(left) == 1:
preorder_reversed.remove(left[0])
root.left = typing.cast(stdlib.BinaryTreeNode, stdlib.TreeNode(left[0]))
if len(right) > 1:
split_pos = right.index(preorder_reversed[-1])
root.right = subtree(right[:split_pos], right[split_pos + 1 :])
elif len(right) == 1:
preorder_reversed.remove(right[0])
root.right = typing.cast(stdlib.BinaryTreeNode, stdlib.TreeNode(right[0]))
return root
split_pos = inorder.index(preorder[0])
return subtree(inorder[:split_pos], inorder[split_pos + 1 :])
class JumpSpace(typing.NamedTuple):
pos: int
val: int
moves: list["JumpSpace"]
@classmethod
def from_board(
cls, pos: int = 0, board: typing.Iterable[int] = ()
) -> typing.Optional["JumpSpace"]:
board = list(board)
if len(board) == 0:
return None
space = cls(pos, board[pos], [])
space.collect(board)
return space
def collect(self, board: list[int]) -> None:
del self.moves[:]
if self.pos > len(board) or len(board) == 0:
return
for n in range(self.pos + 1, self.pos + self.val + 1):
if n >= len(board):
break
self.moves.append(typing.cast(JumpSpace, JumpSpace.from_board(n, board)))
def jump_paths(self) -> list[list[int]]:
ret: list[list[int]] = [[self.pos]]
for next_space in self.moves:
for path in next_space.jump_paths():
ret.append([self.pos] + path)
return ret
def collect_complete_jump_paths_from_board(board: list[int]) -> list[list[int]]:
return [
p
for p in collect_jump_paths_from_board(board)
if len(p) > 0 and p[-1] >= len(board) - 1
]
def collect_jump_paths_from_board(board: list[int]) -> list[list[int]]:
space = JumpSpace.from_board(0, board)
if space is None:
return []
return space.jump_paths()
# NOTE: the expensive way goes like this
# complete_paths = collect_complete_jump_paths_from_board(board)
# if len(complete_paths) == 0:
# return -1
# return min([len(p) - 1 for p in complete_paths])
def count_min_jumps_from_board(board: list[int]) -> int:
return len(collect_min_jumps_from_board(board))
def collect_min_jumps_from_board(board: list[int]) -> list[int]:
if len(board) < 3:
return list(range(1, len(board)))
jumps: list[int] = []
range_begin: int = 0
val = board[range_begin]
range_end: int = range_begin + val + 1
while range_end < len(board):
potential_jumps = board[range_begin:range_end]
scored_jumps = [
(val + range_begin + i, val, range_begin + i)
for i, val in enumerate(potential_jumps)
]
_, val, space = max(scored_jumps)
jumps.append(space)
range_begin = space
range_end = range_begin + val + 1
return jumps + [len(board) - 1]
def h_index(citations: list[int]) -> int:
last_qualified = None
for i, citation_count in enumerate(list(sorted(citations, reverse=True))):
if citation_count >= i + 1:
last_qualified = i + 1
else:
break
return last_qualified or 0
class SlowRandomizedSet:
def __init__(self):
self._i: set[int] = set()
def insert(self, val: int) -> bool:
ok = val not in self._i
self._i.add(val)
return ok
def remove(self, val: int) -> bool:
if val in self._i:
self._i.remove(val)
return True
return False
def getRandom(self) -> int:
return random.choice(list(self._i))
class RandomizedSet:
def __init__(self):
self._l: list[int] = []
self._m: dict[int, int] = {}
def insert(self, val: int) -> bool:
if val in self._m:
return False
self._m[val] = len(self._l)
self._l.append(val)
return True
def remove(self, val: int) -> bool:
if val not in self._m:
return False
val_loc = self._m[val]
last_val = self._l[-1]
self._l[val_loc] = last_val
self._m[last_val] = val_loc
self._l.pop()
self._m.pop(val)
return True
def getRandom(self) -> int:
return random.choice(self._l)
class TrieNode(typing.NamedTuple):
value: str
kids: dict[str, "TrieNode"]
@property
def is_leaf(self) -> bool:
return "__self__" in self.kids
@classmethod
def leaf(cls) -> "TrieNode":
return cls("__self__", {})
class Trie:
def __init__(self):
self._root_node = TrieNode("", {})
def insert(self, word: str) -> None:
if len(word) == 0:
return
current_node = self._root_node
for prefix in [word[: i + 1] for i in range(len(word))]:
current_node.kids.setdefault(prefix, TrieNode(prefix, {}))
current_node = current_node.kids[prefix]
leaf = TrieNode.leaf()
current_node.kids[leaf.value] = leaf
def search(self, word: str) -> bool:
return self._has(word, prefix_ok=False)
def startsWith(self, prefix: str) -> bool:
return self._has(prefix, prefix_ok=True)
def _has(self, word: str, prefix_ok: bool) -> bool:
if len(word) == 0:
return True
reverse_path = [word[: i + 1] for i in range(len(word))][::-1]
current_node = self._root_node
while reverse_path and current_node is not None:
current_node = current_node.kids.get(reverse_path.pop())
return (
current_node is not None
and (current_node.is_leaf or prefix_ok)
and current_node.value == word
)
def count_factorial_trailing_zeroes(number: int) -> int:
divisor: int = 5
zeroes_count: int = 0
while divisor <= number:
zeroes_count += number // divisor
divisor *= 5
return zeroes_count
def copy_random_list(
head: stdlib.ListNodeRandom | None,
) -> stdlib.ListNodeRandom | None:
if head is None:
return None
ordered = []
cur = head
while cur is not None:
ordered.append(cur)
cur = cur.next
ordered_copy = [stdlib.ListNodeRandom(entry.val) for entry in ordered]
hash_idx = {hash(n): i for i, n in enumerate(ordered)}
for i, entry in enumerate(ordered):
if i + 1 < len(ordered_copy):
ordered_copy[i].next = ordered_copy[i + 1]
if entry.random is not None:
ordered_copy[i].random = ordered_copy[hash_idx[hash(entry.random)]]
return ordered_copy[0]
def sum_max_sub_array(nums: list[int]) -> int:
mmax = last = prev = nums[0]
for i in range(1, len(nums)):
prev = nums[i] + last
last = max(nums[i], prev)
mmax = max(mmax, last)
return mmax
def sum_max_sub_array_i(nums: list[int]) -> tuple[int, int]:
mmax_i: int = 0
mmax = last = prev = nums[0]
for i in range(1, len(nums)):
prev = nums[i] + last
last = max(nums[i], prev)
mmax_i = i if last > mmax else mmax_i
mmax = max(mmax, last)
return mmax_i, mmax
def sum_max_sub_array_accum(nums: list[int]) -> int:
accum: list[int] = [nums[0]]
for i in range(1, len(nums)):
prev: int = nums[i] + accum[-1]
accum.append(max(nums[i], prev))
return max(accum)
def accum_sub_array_maxes(nums: list[int]) -> list[int]:
accum: list[int] = [nums[0]]
for i in range(1, len(nums)):
prev: int = nums[i] + accum[-1]
accum.append(max(nums[i], prev))
return accum
def neighborly_node_from_list(inlist: list[list[int]]):
# Alias "Node" type for leetcode compat
Node = stdlib.NeighborlyNodeNicely
if len(inlist) == 0:
return None
outlist = [Node(i + 1, []) for i in range(len(inlist))]
for i in range(len(inlist)):
outlist[i].neighbors[:] = []
for neighbor_val in inlist[i]:
outlist[i].neighbors.append(outlist[neighbor_val - 1])
return outlist[0]
def neighborly_node_to_list(node) -> list[list[int]]:
serialized: dict[int, list[int]] = {}
for cur in traverse_neighborly_node(node, serialized):
if cur is None:
break
serialized[cur.val] = [n.val for n in cur.neighbors]
return [v for _, v in sorted(serialized.items())]
def traverse_neighborly_node(
node: stdlib.NeighborlyNodeNicely, memo: collections.abc.Container[int]
) -> typing.Iterator[stdlib.NeighborlyNodeNicely | None]:
yield node
if node is None:
return
for neighbor in node.neighbors:
if neighbor.val in memo:
continue
yield from traverse_neighborly_node(neighbor, memo)
def find_min_in_rotated_array(nums: list[int]) -> int:
if nums[0] <= nums[-1]:
return nums[0]
if len(nums) <= 3:
return min(nums)
if nums[len(nums) // 2] > nums[-1]:
return find_min_in_rotated_array(nums[len(nums) // 2 :])
return find_min_in_rotated_array(nums[: (len(nums) // 2) + 1])

15
leetcode/test_roman.py Normal file
View File

@ -0,0 +1,15 @@
import pytest
import roman
@pytest.mark.parametrize(
("n", "expected"),
[
(3, "III"),
(58, "LVIII"),
(1994, "MCMXCIV"),
],
)
def test_int_to_roman(n: int, expected: str):
assert roman.i2r(n) == expected

View File

@ -0,0 +1,46 @@
import pytest
import spiral_matrix
@pytest.mark.parametrize(
("matrix", "expected"),
[
(
[
["a", "b", "c"],
["d", "e", "f"],
["g", "h", "i"],
],
["a", "b", "c", "f", "i", "h", "g", "d", "e"],
),
(
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
],
[1, 2, 3, 4, 8, 12, 11, 10, 9, 5, 6, 7],
),
(
[
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
[1, 2, 3, 4, 5, 6, 7, 8, 9],
],
[] # noqa
+ [1, 2, 3, 4, 5, 6, 7, 8, 9] # right
+ [9, 9, 9] # down
+ [9, 8, 7, 6, 5, 4, 3, 2, 1] # left
+ [1, 1] # up
+ [1, 2, 3, 4, 5, 6, 7, 8] # right
+ [8] # down
+ [8, 7, 6, 5, 4, 3, 2] # left
+ [2, 3, 4, 5, 6, 7], # right
),
],
)
def test_matrix_spiral(matrix, expected):
assert spiral_matrix.matrix_spiral(matrix) == expected

505
leetcode/test_stuff.py Normal file
View File

@ -0,0 +1,505 @@
import json
import pytest
import stuff
import stdlib
@pytest.mark.parametrize(
("n", "expected"),
[
(0, 0),
(1, 1),
(5, 2),
(4, 2),
(8, 2),
(9, 3),
],
)
def test_find_sqrt_ish(n: int, expected: int):
assert stuff.find_sqrt_ish(n) == expected
@pytest.mark.parametrize(
("ops", "expected"),
[
(
(
[
("new",),
("push", -2),
("push", 0),
("push", -3),
("getMin",),
("pop",),
("top",),
("getMin",),
]
),
[
None,
None,
None,
None,
-3,
None,
0,
-2,
],
)
],
)
def test_min_stack(ops: list[tuple[str] | tuple[str, int]], expected: list[int | None]):
returned: list[int | None] = []
inst: stuff.MinStack | None = None
for op in ops:
if len(op) == 1:
if op[0] == "new":
inst = stuff.MinStack()
returned.append(None)
continue
returned.append(getattr(inst, op[0])())
continue
method, arg = op
returned.append(getattr(inst, method)(arg))
assert returned == expected
@pytest.mark.parametrize(
("head", "expected"),
[
(None, None),
(
stdlib.ListNode(
4, stdlib.ListNode(2, stdlib.ListNode(1, stdlib.ListNode(3)))
),
stdlib.ListNode(
1, stdlib.ListNode(2, stdlib.ListNode(3, stdlib.ListNode(4)))
),
),
(
stdlib.ListNode(
4,
stdlib.ListNode(
19,
stdlib.ListNode(
14,
stdlib.ListNode(
5,
stdlib.ListNode(
-3,
stdlib.ListNode(
1,
stdlib.ListNode(
8,
stdlib.ListNode(
5, stdlib.ListNode(11, stdlib.ListNode(15))
),
),
),
),
),
),
),
),
stdlib.ListNode(
-3,
stdlib.ListNode(
1,
stdlib.ListNode(
4,
stdlib.ListNode(
5,
stdlib.ListNode(
5,
stdlib.ListNode(
8,
stdlib.ListNode(
11,
stdlib.ListNode(
14, stdlib.ListNode(15, stdlib.ListNode(19))
),
),
),
),
),
),
),
),
),
],
)
def test_sort_linked_list(
head: stdlib.LinkedListNode | None, expected: stdlib.LinkedListNode | None
):
if head is None:
assert stuff.sort_linked_list(head) == expected
return
assert stuff.linked_list_to_list(
stuff.sort_linked_list(head)
) == stuff.linked_list_to_list(expected)
@pytest.mark.parametrize(
("root", "expected"),
[
(
stdlib.Node(
1,
left=stdlib.Node(2, left=stdlib.Node(4), right=stdlib.Node(5)),
right=stdlib.Node(3, right=stdlib.Node(7)),
),
[1, None, 2, 3, None, 4, 5, 7, None],
),
],
)
def test_connect_binary_tree_right(
root: stdlib.ConnectableBinaryTreeNode | None, expected: list[int | None] | None
):
if expected is None:
assert root is None
return
connected, serialized = stuff.connect_binary_tree_right(root)
assert connected is not None
assert serialized == expected
@pytest.mark.parametrize(
("root", "expected"),
[
(
stdlib.Node(
4,
right=stdlib.Node(0),
left=stdlib.Node(9, right=stdlib.Node(1), left=stdlib.Node(5)),
),
1026,
),
],
)
def test_connect_binary_tree_sum_numbers(
root: stdlib.BinaryTreeNode | None, expected: int
):
assert stuff.sum_binary_tree_path_ints(root) == expected
@pytest.mark.parametrize(
("inlist", "expected"),
[
(
[3, 5, 1, 6, 2, 0, 8, None, None, 7, 4],
stdlib.TreeNode(
3,
left=stdlib.TreeNode(
5,
left=stdlib.TreeNode(6),
right=stdlib.TreeNode(
2,
left=stdlib.TreeNode(7),
right=stdlib.TreeNode(4),
),
),
right=stdlib.TreeNode(
1,
left=stdlib.TreeNode(0),
right=stdlib.TreeNode(8),
),
),
),
],
)
def test_binary_tree_from_list(
inlist: list[int | None], expected: stdlib.BinaryTreeNode | None
):
assert stuff.binary_tree_from_list(inlist) == expected
@pytest.mark.parametrize(
("preorder", "inorder", "expected"),
[
(
[3, 9, 20, 15, 7],
[9, 3, 15, 20, 7],
stdlib.TreeNode(
3,
left=stdlib.TreeNode(9),
right=stdlib.TreeNode(
20, left=stdlib.TreeNode(15), right=stdlib.TreeNode(7)
),
),
),
(
[-1],
[-1],
stdlib.TreeNode(-1),
),
(
[1, 2],
[1, 2],
stdlib.TreeNode(1, right=stdlib.TreeNode(2)),
),
],
)
def test_binary_tree_from_preorder_inorder(
preorder: list[int], inorder: list[int], expected: stdlib.BinaryTreeNode
):
assert stuff.binary_tree_from_preorder_inorder(preorder, inorder) == expected
@pytest.mark.parametrize(
("board", "expected"),
[
(
[2, 3, 1, 1, 4],
[
[0, 1, 2, 3, 4],
[0, 1, 3, 4],
[0, 1, 4],
[0, 2, 3, 4],
],
),
],
)
def test_collect_complete_jump_paths_from_board(
board: list[int], expected: list[list[int]]
):
assert list(sorted(stuff.collect_complete_jump_paths_from_board(board))) == expected
@pytest.mark.parametrize(
("board", "expected"),
[
(
[2, 3, 1, 1, 4],
2,
),
(
[2, 3, 0, 1, 4],
2,
),
(
[1],
0,
),
(
[1, 2],
1,
),
(
[6, 2, 6, 1, 7, 9, 3, 5, 3, 7, 2, 8, 9, 4, 7, 7, 2, 2, 8, 4, 6, 6, 1, 3],
4,
),
(
[3, 4, 3, 2, 5, 4, 3],
3,
),
(
[3, 2, 1],
1,
),
(
[1, 2, 3],
2,
),
],
)
def test_count_min_jumps_from_board(board: list[int], expected: int):
assert stuff.count_min_jumps_from_board(board) == expected
@pytest.mark.parametrize(
("citations", "expected"),
[
(
[3, 0, 6, 1, 5],
3,
),
(
[1, 3, 1],
1,
),
(
[100],
1,
),
],
)
def test_h_index(citations: list[int], expected: int):
assert stuff.h_index(citations) == expected
@pytest.mark.parametrize(
("cls",),
[
(stuff.SlowRandomizedSet,),
(stuff.RandomizedSet,),
],
)
def test_randomized_set(cls: type[stuff.RandomizedSet] | type[stuff.SlowRandomizedSet]):
inst = cls()
assert inst.insert(1) is True
assert inst.remove(2) is False
assert inst.insert(2) is True
assert inst.getRandom() in (1, 2)
assert inst.remove(1) is True
assert inst.insert(2) is False
assert inst.getRandom() == 2
inst = cls()
assert inst.insert(1) is True
assert inst.insert(10) is True
assert inst.insert(20) is True
assert inst.insert(30) is True
seen: set[int] = set()
for _ in range(10_000):
seen.add(inst.getRandom())
assert seen == {1, 10, 20, 30}
# ["remove","remove","insert","getRandom","remove","insert"]
# [[0],[0],[0],[],[0],[0]]
inst = cls()
assert inst.remove(0) is False
assert inst.remove(0) is False
assert inst.insert(0) is True
assert inst.getRandom() == 0
assert inst.remove(0) is True
assert inst.insert(0) is True
# ["RandomizedSet","insert","insert","remove","insert","remove","getRandom"]
# [[],[0],[1],[0],[2],[1],[]]
inst = cls()
assert inst.insert(0) is True
assert inst.insert(1) is True
assert inst.remove(0) is True
assert inst.insert(2) is True
assert inst.remove(1) is True
assert inst.getRandom() == 2
def test_trie_single_letter():
trie = stuff.Trie()
assert trie.insert("a") is None
assert trie.search("a") is True
assert trie.startsWith("a") is True
def test_trie_prefix_leaf():
trie = stuff.Trie()
assert trie.insert("apple") is None
assert trie.search("apple") is True
assert trie.search("app") is False
assert trie.startsWith("app") is True
assert trie.insert("app") is None
assert trie.search("app") is True
def test_trie_two_letter():
trie = stuff.Trie()
assert trie.insert("ab") is None
assert trie.search("a") is False
assert trie.startsWith("a") is True
def test_trie_busy():
trie = stuff.Trie()
assert trie.insert("app") is None
assert trie.insert("apple") is None
assert trie.insert("beer") is None
assert trie.insert("add") is None
assert trie.insert("jam") is None
assert trie.insert("rental") is None
assert trie.search("apps") is False
assert trie.search("app") is True
assert trie.search("ad") is False
assert trie.search("applepie") is False
assert trie.search("rest") is False
assert trie.search("jan") is False
assert trie.search("rent") is False
assert trie.search("beer") is True
assert trie.search("jam") is True
assert trie.startsWith("apps") is False
assert trie.startsWith("app") is True
assert trie.startsWith("ad") is True
assert trie.startsWith("applepie") is False
assert trie.startsWith("rest") is False
assert trie.startsWith("jan") is False
assert trie.startsWith("rent") is True
assert trie.startsWith("beer") is True
assert trie.startsWith("jam") is True
@pytest.mark.parametrize(
("nums", "expected"),
[
(
[-2, 1, -3, 4, -1, 2, 1, -5, 4],
6,
),
(
[1],
1,
),
(
[5, 4, -1, 7, 8],
23,
),
(
[-2, 1],
1,
),
(
json.load(open(".testdata/max_sub_array0.json")),
11081,
),
],
)
def test_max_sub_array(nums: list[int], expected: int):
assert stuff.sum_max_sub_array(nums) == expected
@pytest.mark.parametrize(
("inlist",),
[
([[2, 3, 4], [1, 7], [1], [1, 5, 6, 8], [4], [4], [2], [4]],),
([[2, 4], [1, 3], [2, 4], [1, 3]],),
],
)
def test_copy_neighborly_node(inlist):
orig = stuff.neighborly_node_from_list(inlist)
copied = stuff.neighborly_node_from_list(stuff.neighborly_node_to_list(orig))
assert id(orig) != id(copied)
assert orig == copied
assert stuff.neighborly_node_to_list(orig) == stuff.neighborly_node_to_list(copied)
@pytest.mark.parametrize(
("nums", "expected"),
[
([3, 4, 5, 1, 2], 1),
([4, 5, 6, 7, 0, 1, 2], 0),
([11, 13, 15, 17], 11),
],
)
def test_find_min_in_rotated_array(nums: list[int], expected: int):
assert stuff.find_min_in_rotated_array(nums) == expected

1
modernc/01/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
getting-started

23
modernc/01/bad.c Normal file
View File

@ -0,0 +1,23 @@
/* This may look like nonsense, but really is -*- mode: C -*- */
/* The main thing that this program does. */
void main() {
// Decralations
int i;
double A[5] = {
9.0,
2.9,
3.E+25,
.00007,
};
// Doing some work
for (i = 0; i < 5; ++i) {
printf("element %d is %g, \tits square is %g\n",
i,
A[i],
A[i]*A[i]);
}
return 0;
}

View File

@ -0,0 +1,24 @@
/* This may look like nonsense, but really is -*- mode: C -*- */
#include <stdlib.h>
#include <stdio.h>
/* The main thing that this program does. */
int main(void) {
// Decralations
double A[5] = {
[0] = 9.0,
[1] = 2.9,
[4] = 3.E+25,
[3] = .00007,
};
// Doing some work
for (size_t i = 0; i < 5; ++i) {
printf("element %zu is %g, \tits square is %g\n",
i,
A[i],
A[i]*A[i]);
}
return EXIT_SUCCESS;
}

2
modernc/03/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
challenge-1
heron

90
modernc/03/array.c Normal file
View File

@ -0,0 +1,90 @@
#include <stdlib.h>
#include "array.h"
void IntArray_new(IntArray* a, size_t size) {
a->arr = malloc(size * sizeof(int));
a->used = 0;
a->size = size;
}
int IntArray_append(IntArray* a, int el) {
if (a->used == a->size) {
a->size *= 2;
a->arr = realloc(a->arr, a->size * sizeof(int));
}
a->used++;
a->arr[a->used] = el;
return a->used;
}
int IntArray_get(IntArray* a, int idx, int dflt) {
if (idx > a->used) {
return dflt;
}
return a->arr[idx];
}
int IntArray_length(IntArray* a) {
return a->used;
}
void IntArray_mergesort(IntArray* a) {
IntArray left_side;
IntArray right_side;
size_t split = a->used / 2;
IntArray_new(&left_side, split);
IntArray_new(&right_side, split);
for (int i = 0; i < split; ++i) {
IntArray_append(&left_side, IntArray_get(a, i, 0));
}
for (int i = split; i < a->used; ++i) {
IntArray_append(&right_side, IntArray_get(a, i, 0));
}
IntArray_mergesort(&left_side);
IntArray_mergesort(&right_side);
IntArray_mergesort_merge(a, &left_side, &right_side);
}
void IntArray_mergesort_merge(IntArray* a, IntArray* left_side, IntArray* right_side) {
IntArray_free(a);
size_t i = 0;
size_t j = 0;
while (i < left_side->used && j < right_side->used) {
if (left_side->arr[i] <= right_side->arr[j]) {
IntArray_append(a, left_side->arr[i]);
i++;
} else {
IntArray_append(a, right_side->arr[j]);
j++;
}
}
for (size_t li = 0; li < left_side->used; ++li) {
IntArray_append(a, left_side->arr[li]);
}
for (size_t ri = 0; ri < right_side->used; ++ri) {
IntArray_append(a, right_side->arr[ri]);
}
}
void IntArray_quicksort(IntArray* a) {
return;
}
void IntArray_free(IntArray* a) {
free(a->arr);
a->arr = NULL;
a->used = a->size = 0;
}

22
modernc/03/array.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef INCLUDED_ARRAY_H
#include <stdlib.h>
typedef struct {
int *arr;
size_t used;
size_t size;
} IntArray;
void IntArray_new(IntArray*, size_t);
int IntArray_append(IntArray*, int);
int IntArray_get(IntArray*, int, int);
int IntArray_length(IntArray*);
void IntArray_mergesort(IntArray*);
void IntArray_mergesort_merge(IntArray*, IntArray*, IntArray*);
void IntArray_quicksort(IntArray*);
void IntArray_free(IntArray*);
#define INCLUDED_ARRAY_H 1
#endif

114
modernc/03/challenge-1.c Normal file
View File

@ -0,0 +1,114 @@
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include "array.h"
#define IODASH "-"
void usage(char* prog) {
fprintf(stderr, "Usage: %s [-f|--input-file <input-file>] [-o|--output-file <output-file>]\n", prog);
}
int main(int argc, char **argv) {
char* input_file = IODASH;
char* output_file = IODASH;
int c = 0;
while (1) {
static struct option long_options[] = {
{"input-file", required_argument, 0, 'f'},
{"output-file", required_argument, 0, 'o'},
};
int option_index = 0;
c = getopt_long(argc, argv, "f:o:", long_options, &option_index);
if (c == -1) {
break;
}
switch (c) {
case 'f':
input_file = optarg;
break;
case 'o':
output_file = optarg;
break;
default:
usage(argv[0]);
return 1;
}
}
if (strcmp(input_file, IODASH) == 0) {
fprintf(stderr, "(reading from stdin)\n");
}
if (strcmp(output_file, IODASH) == 0) {
fprintf(stderr, "(writing to stdout)\n");
}
printf("input_file='%s' output_file='%s'\n", input_file, output_file);
FILE* instream;
instream = stdin;
if (strcmp(input_file, IODASH) != 0) {
instream = fopen(input_file, "r");
}
if (instream == NULL) {
perror("opening input file");
return EXIT_FAILURE;
}
FILE* outstream;
outstream = stdout;
if (strcmp(output_file, IODASH) != 0) {
outstream = fopen(output_file, "r");
}
if (outstream == NULL) {
perror("opening output file");
return EXIT_FAILURE;
}
int line_int;
ssize_t nread;
char* endptr = NULL;
char* line = NULL;
size_t len = 0;
IntArray accum;
IntArray_new(&accum, 100);
while ((nread = getline(&line, &len, instream)) != -1) {
IntArray_append(&accum, atoi(line));
}
printf("Accumulated %i ints\n", IntArray_length(&accum));
IntArray_mergesort(&accum);
printf("Merge sorted:\n");
for (int i = 0; i < accum.used; ++i) {
printf("%i: %i\n", i, IntArray_get(&accum, i, 0));
}
if (strcmp(input_file, IODASH) != 0) {
fclose(instream);
}
if (strcmp(output_file, IODASH) != 0) {
fclose(outstream);
}
return EXIT_SUCCESS;
}

40
modernc/03/heron.c Normal file
View File

@ -0,0 +1,40 @@
#include <stdlib.h>
#include <stdio.h>
/* lower and upper iteration limits centered around 1.0 */
static double const eps1m01 = 1.0 - 0x1P-01;
static double const eps1p01 = 1.0 + 0x1P-01;
static double const eps1m24 = 1.0 - 0x1P-24;
static double const eps1p24 = 1.0 + 0x1P-24;
int main(int argc, char* argv[argc+1]) {
for (int i = 1; i < argc; ++i) {
double const a = strtod(argv[i], 0);
double x = 1.0;
for (;;) {
double prod = a*x;
if (prod < eps1m01) {
x *= 2.0;
} else if (eps1p01 < prod) {
x *= 0.5;
} else {
break;
}
}
for (;;) {
double prod = a*x;
if ((prod < eps1m24) || (eps1p24 < prod)) {
x *= (2.0 - prod);
} else {
break;
}
}
printf("heron: a=%.5e,\tx=%.5e,\ta*x=%.12f\n",
a, x, a*x);
}
return EXIT_SUCCESS;
}

1
modernc/05/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
basic

9
modernc/05/basic.c Normal file
View File

@ -0,0 +1,9 @@
#include <stdio.h>
int main() {
double x = 5.0;
double y = 3.0;
x = (x * 1.5) - y;
printf("x is \%g\n", x);
}

1
personal-home-page/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/vendor/

Some files were not shown because too many files have changed in this diff Show More