Compare commits

..

109 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
187 changed files with 9158 additions and 2258 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

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
**/target/
/hello_world/main
/aoc*/**/input
/arduino/build-*/

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);
}

View File

@ -1,4 +0,0 @@
# argh command line parser
> NOTE: much of this is lifted from
> https://blog.gopheracademy.com/advent-2014/parsers-lexers/

View File

@ -1,34 +0,0 @@
package argh
import (
"fmt"
"log"
"os"
"path/filepath"
"runtime"
)
var (
tracingEnabled = os.Getenv("ARGH_TRACING") == "enabled"
traceLogger *log.Logger
)
func init() {
if !tracingEnabled {
return
}
traceLogger = log.New(os.Stderr, "ARGH TRACING: ", 0)
}
func tracef(format string, v ...any) {
if !tracingEnabled {
return
}
if _, file, line, ok := runtime.Caller(1); ok {
format = fmt.Sprintf("%v:%v ", filepath.Base(file), line) + format
}
traceLogger.Printf(format, v...)
}

View File

@ -1,46 +0,0 @@
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"git.meatballhat.com/x/box-o-sand/argh"
"github.com/davecgh/go-spew/spew"
)
func main() {
asJSON := os.Getenv("ARGH_OUTPUT_JSON") == "enabled"
log.SetFlags(0)
pt, err := argh.ParseArgs(os.Args, argh.NewParserConfig(
&argh.CommandConfig{
NValue: argh.OneOrMoreValue,
ValueNames: []string{"topping"},
Flags: &argh.Flags{
Automatic: true,
},
},
nil,
))
if err != nil {
log.Fatal(err)
}
ast := argh.NewQuerier(pt.Nodes).AST()
if asJSON {
b, err := json.MarshalIndent(ast, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
return
}
spew.Dump(ast)
}

View File

@ -1,12 +0,0 @@
module git.meatballhat.com/x/box-o-sand/argh
go 1.18
require github.com/pkg/errors v0.9.1
require (
github.com/davecgh/go-spew v1.1.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.7.1 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
)

View File

@ -1,12 +0,0 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,46 +0,0 @@
package argh
type Node interface{}
type TypedNode struct {
Type string
Node Node
}
type PassthroughArgs struct {
Nodes []Node
}
type CompoundShortFlag struct {
Nodes []Node
}
type Ident struct {
Literal string
}
type BadArg struct {
Literal string
From Pos
To Pos
}
type Command struct {
Name string
Values map[string]string
Nodes []Node
}
type Flag struct {
Name string
Values map[string]string
Nodes []Node
}
type StdinFlag struct{}
type StopFlag struct{}
type ArgDelimiter struct{}
type Assign struct{}

View File

@ -1,26 +0,0 @@
// Code generated by "stringer -type NValue"; DO NOT EDIT.
package argh
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[OneOrMoreValue - -2]
_ = x[ZeroOrMoreValue - -1]
_ = x[ZeroValue-0]
}
const _NValue_name = "OneOrMoreValueZeroOrMoreValueZeroValue"
var _NValue_index = [...]uint8{0, 14, 29, 38}
func (i NValue) String() string {
i -= -2
if i < 0 || i >= NValue(len(_NValue_index)-1) {
return "NValue(" + strconv.FormatInt(int64(i+-2), 10) + ")"
}
return _NValue_name[_NValue_index[i]:_NValue_index[i+1]]
}

View File

@ -1,346 +0,0 @@
package argh
import (
"fmt"
"io"
"strings"
)
type parser struct {
s *Scanner
cfg *ParserConfig
errors ParserErrorList
tok Token
lit string
pos Pos
buffered bool
}
type ParseTree struct {
Nodes []Node `json:"nodes"`
}
func ParseArgs(args []string, pCfg *ParserConfig) (*ParseTree, error) {
p := &parser{}
p.init(
strings.NewReader(strings.Join(args, string(nul))),
pCfg,
)
tracef("ParseArgs(...) parser=%+#v", p)
return p.parseArgs()
}
func (p *parser) addError(msg string) {
p.errors.Add(Position{Column: int(p.pos)}, msg)
}
func (p *parser) init(r io.Reader, pCfg *ParserConfig) {
p.errors = ParserErrorList{}
if pCfg == nil {
pCfg = POSIXyParserConfig
}
p.cfg = pCfg
p.s = NewScanner(r, pCfg.ScannerConfig)
p.next()
}
func (p *parser) parseArgs() (*ParseTree, error) {
if p.errors.Len() != 0 {
tracef("parseArgs() bailing due to initial error")
return nil, p.errors.Err()
}
tracef("parseArgs() parsing %q as program command; cfg=%+#v", p.lit, p.cfg.Prog)
prog := p.parseCommand(&p.cfg.Prog)
tracef("parseArgs() top level node is %T", prog)
nodes := []Node{prog}
if v := p.parsePassthrough(); v != nil {
tracef("parseArgs() appending passthrough argument %v", v)
nodes = append(nodes, v)
}
tracef("parseArgs() returning ParseTree")
return &ParseTree{Nodes: nodes}, p.errors.Err()
}
func (p *parser) next() {
tracef("next() before scan: %v %q %v", p.tok, p.lit, p.pos)
p.tok, p.lit, p.pos = p.s.Scan()
tracef("next() after scan: %v %q %v", p.tok, p.lit, p.pos)
}
func (p *parser) parseCommand(cCfg *CommandConfig) Node {
tracef("parseCommand(%+#v)", cCfg)
node := &Command{
Name: p.lit,
}
values := map[string]string{}
nodes := []Node{}
identIndex := 0
for i := 0; p.tok != EOL; i++ {
if !p.buffered {
tracef("parseCommand(...) buffered=false; scanning next")
p.next()
}
p.buffered = false
tracef("parseCommand(...) for=%d values=%+#v", i, values)
tracef("parseCommand(...) for=%d nodes=%+#v", i, nodes)
tracef("parseCommand(...) for=%d tok=%s lit=%q pos=%v", i, p.tok, p.lit, p.pos)
tracef("parseCommand(...) cCfg=%+#v", cCfg)
if subCfg, ok := cCfg.GetCommandConfig(p.lit); ok {
subCommand := p.lit
nodes = append(nodes, p.parseCommand(&subCfg))
tracef("parseCommand(...) breaking after sub-command=%v", subCommand)
break
}
switch p.tok {
case ARG_DELIMITER:
tracef("parseCommand(...) handling %s", p.tok)
nodes = append(nodes, &ArgDelimiter{})
continue
case IDENT, STDIN_FLAG:
tracef("parseCommand(...) handling %s", p.tok)
if cCfg.NValue.Contains(identIndex) {
name := fmt.Sprintf("%d", identIndex)
tracef("parseCommand(...) checking for name of identIndex=%d", identIndex)
if len(cCfg.ValueNames) > identIndex {
name = cCfg.ValueNames[identIndex]
tracef("parseCommand(...) setting name=%s from config value names", name)
} else if len(cCfg.ValueNames) == 1 && (cCfg.NValue == OneOrMoreValue || cCfg.NValue == ZeroOrMoreValue) {
name = fmt.Sprintf("%s.%d", cCfg.ValueNames[0], identIndex)
tracef("parseCommand(...) setting name=%s from repeating value name", name)
}
values[name] = p.lit
}
if p.tok == STDIN_FLAG {
nodes = append(nodes, &StdinFlag{})
} else {
nodes = append(nodes, &Ident{Literal: p.lit})
}
identIndex++
case LONG_FLAG, SHORT_FLAG, COMPOUND_SHORT_FLAG:
tok := p.tok
flagNode := p.parseFlag(cCfg.Flags)
tracef("parseCommand(...) appending %s node=%+#v", tok, flagNode)
nodes = append(nodes, flagNode)
case ASSIGN:
tracef("parseCommand(...) error on bare %s", p.tok)
p.addError("invalid bare assignment")
break
default:
tracef("parseCommand(...) breaking on %s", p.tok)
break
}
}
if len(nodes) > 0 {
node.Nodes = nodes
}
if len(values) > 0 {
node.Values = values
}
tracef("parseCommand(...) returning node=%+#v", node)
return node
}
func (p *parser) parseIdent() Node {
node := &Ident{Literal: p.lit}
return node
}
func (p *parser) parseFlag(flags *Flags) Node {
switch p.tok {
case SHORT_FLAG:
tracef("parseFlag(...) parsing short flag with config=%+#v", flags)
return p.parseShortFlag(flags)
case LONG_FLAG:
tracef("parseFlag(...) parsing long flag with config=%+#v", flags)
return p.parseLongFlag(flags)
case COMPOUND_SHORT_FLAG:
tracef("parseFlag(...) parsing compound short flag with config=%+#v", flags)
return p.parseCompoundShortFlag(flags)
}
panic(fmt.Sprintf("token %v cannot be parsed as flag", p.tok))
}
func (p *parser) parseShortFlag(flags *Flags) Node {
node := &Flag{Name: string(p.lit[1])}
flCfg, ok := flags.Get(node.Name)
if !ok {
p.addError(fmt.Sprintf("unknown flag %q", node.Name))
return node
}
return p.parseConfiguredFlag(node, flCfg)
}
func (p *parser) parseLongFlag(flags *Flags) Node {
node := &Flag{Name: string(p.lit[2:])}
flCfg, ok := flags.Get(node.Name)
if !ok {
p.addError(fmt.Sprintf("unknown flag %q", node.Name))
return node
}
return p.parseConfiguredFlag(node, flCfg)
}
func (p *parser) parseCompoundShortFlag(flags *Flags) Node {
flagNodes := []Node{}
withoutFlagPrefix := p.lit[1:]
for i, r := range withoutFlagPrefix {
node := &Flag{Name: string(r)}
if i == len(withoutFlagPrefix)-1 {
flCfg, ok := flags.Get(node.Name)
if !ok {
p.addError(fmt.Sprintf("unknown flag %q", node.Name))
continue
}
flagNodes = append(flagNodes, p.parseConfiguredFlag(node, flCfg))
continue
}
flagNodes = append(flagNodes, node)
}
return &CompoundShortFlag{Nodes: flagNodes}
}
func (p *parser) parseConfiguredFlag(node *Flag, flCfg FlagConfig) Node {
values := map[string]string{}
nodes := []Node{}
identIndex := 0
for i := 0; p.tok != EOL; i++ {
if !flCfg.NValue.Contains(identIndex) {
tracef("parseConfiguredFlag(...) identIndex=%d exceeds expected=%v; breaking", identIndex, flCfg.NValue)
break
}
p.next()
switch p.tok {
case ARG_DELIMITER:
nodes = append(nodes, &ArgDelimiter{})
continue
case ASSIGN:
nodes = append(nodes, &Assign{})
continue
case IDENT, STDIN_FLAG:
name := fmt.Sprintf("%d", identIndex)
tracef("parseConfiguredFlag(...) checking for name of identIndex=%d", identIndex)
if len(flCfg.ValueNames) > identIndex {
name = flCfg.ValueNames[identIndex]
tracef("parseConfiguredFlag(...) setting name=%s from config value names", name)
} else if len(flCfg.ValueNames) == 1 && (flCfg.NValue == OneOrMoreValue || flCfg.NValue == ZeroOrMoreValue) {
name = fmt.Sprintf("%s.%d", flCfg.ValueNames[0], identIndex)
tracef("parseConfiguredFlag(...) setting name=%s from repeating value name", name)
} else {
tracef("parseConfiguredFlag(...) setting name=%s", name)
}
values[name] = p.lit
if p.tok == STDIN_FLAG {
nodes = append(nodes, &StdinFlag{})
} else {
nodes = append(nodes, &Ident{Literal: p.lit})
}
identIndex++
default:
tracef("parseConfiguredFlag(...) breaking on %s %q %v; setting buffered=true", p.tok, p.lit, p.pos)
p.buffered = true
if len(nodes) > 0 {
node.Nodes = nodes
}
if len(values) > 0 {
node.Values = values
}
return node
}
}
if len(nodes) > 0 {
node.Nodes = nodes
}
if len(values) > 0 {
node.Values = values
}
return node
}
func (p *parser) parsePassthrough() Node {
nodes := []Node{}
for ; p.tok != EOL; p.next() {
nodes = append(nodes, &Ident{Literal: p.lit})
}
if len(nodes) == 0 {
return nil
}
return &PassthroughArgs{Nodes: nodes}
}

View File

@ -1,146 +0,0 @@
package argh
const (
OneOrMoreValue NValue = -2
ZeroOrMoreValue NValue = -1
ZeroValue NValue = 0
)
var (
POSIXyParserConfig = NewParserConfig(
nil,
POSIXyScannerConfig,
)
)
type NValue int
func (nv NValue) Contains(i int) bool {
tracef("NValue.Contains(%v)", i)
if i < int(ZeroValue) {
return false
}
if nv == OneOrMoreValue || nv == ZeroOrMoreValue {
return true
}
return int(nv) > i
}
type ParserConfig struct {
Prog CommandConfig
ScannerConfig *ScannerConfig
}
func NewParserConfig(prog *CommandConfig, sCfg *ScannerConfig) *ParserConfig {
if sCfg == nil {
sCfg = POSIXyScannerConfig
}
if prog == nil {
prog = &CommandConfig{}
}
prog.init()
pCfg := &ParserConfig{
Prog: *prog,
ScannerConfig: sCfg,
}
return pCfg
}
type CommandConfig struct {
NValue NValue
ValueNames []string
Flags *Flags
Commands *Commands
}
func (cCfg *CommandConfig) init() {
if cCfg.ValueNames == nil {
cCfg.ValueNames = []string{}
}
if cCfg.Flags == nil {
cCfg.Flags = &Flags{}
}
if cCfg.Commands == nil {
cCfg.Commands = &Commands{}
}
}
func (cCfg *CommandConfig) GetCommandConfig(name string) (CommandConfig, bool) {
tracef("CommandConfig.GetCommandConfig(%q)", name)
if cCfg.Commands == nil {
cCfg.Commands = &Commands{Map: map[string]CommandConfig{}}
}
return cCfg.Commands.Get(name)
}
func (cCfg *CommandConfig) GetFlagConfig(name string) (FlagConfig, bool) {
tracef("CommandConfig.GetFlagConfig(%q)", name)
if cCfg.Flags == nil {
cCfg.Flags = &Flags{Map: map[string]FlagConfig{}}
}
return cCfg.Flags.Get(name)
}
type FlagConfig struct {
NValue NValue
Persist bool
ValueNames []string
}
type Flags struct {
Parent *Flags
Map map[string]FlagConfig
Automatic bool
}
func (fl *Flags) Get(name string) (FlagConfig, bool) {
tracef("Flags.Get(%q)", name)
if fl.Map == nil {
fl.Map = map[string]FlagConfig{}
}
flCfg, ok := fl.Map[name]
if !ok {
if fl.Automatic {
return FlagConfig{}, true
}
if fl.Parent != nil {
flCfg, ok = fl.Parent.Get(name)
return flCfg, ok && flCfg.Persist
}
}
return flCfg, ok
}
type Commands struct {
Map map[string]CommandConfig
}
func (cmd *Commands) Get(name string) (CommandConfig, bool) {
tracef("Commands.Get(%q)", name)
if cmd.Map == nil {
cmd.Map = map[string]CommandConfig{}
}
cmdCfg, ok := cmd.Map[name]
return cmdCfg, ok
}

View File

@ -1,88 +0,0 @@
package argh
import (
"fmt"
"io"
"sort"
)
// ParserError is largely borrowed from go/scanner.Error
type ParserError struct {
Pos Position
Msg string
}
func (e ParserError) Error() string {
if e.Pos.IsValid() {
return e.Pos.String() + ":" + e.Msg
}
return e.Msg
}
// ParserErrorList is largely borrowed from go/scanner.ErrorList
type ParserErrorList []*ParserError
func (el *ParserErrorList) Add(pos Position, msg string) {
*el = append(*el, &ParserError{Pos: pos, Msg: msg})
}
func (el *ParserErrorList) Reset() { *el = (*el)[0:0] }
func (el ParserErrorList) Len() int { return len(el) }
func (el ParserErrorList) Swap(i, j int) { el[i], el[j] = el[j], el[i] }
func (el ParserErrorList) Less(i, j int) bool {
e := &el[i].Pos
f := &el[j].Pos
if e.Column != f.Column {
return e.Column < f.Column
}
return el[i].Msg < el[j].Msg
}
func (el ParserErrorList) Sort() {
sort.Sort(el)
}
func (el ParserErrorList) Error() string {
switch len(el) {
case 0:
return "no errors"
case 1:
return el[0].Error()
}
return fmt.Sprintf("%s (and %d more errors)", el[0], len(el)-1)
}
func (el ParserErrorList) Err() error {
if len(el) == 0 {
return nil
}
return el
}
func (el ParserErrorList) Is(other error) bool {
if _, ok := other.(ParserErrorList); ok {
return el.Error() == other.Error()
}
if v, ok := other.(*ParserErrorList); ok {
return el.Error() == (*v).Error()
}
return false
}
func PrintParserError(w io.Writer, err error) {
if list, ok := err.(ParserErrorList); ok {
for _, e := range list {
fmt.Fprintf(w, "%s\n", e)
}
} else if err != nil {
fmt.Fprintf(w, "%s\n", err)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,94 +0,0 @@
package argh
type Querier interface {
Program() (*Command, bool)
AST() []Node
}
func NewQuerier(nodes []Node) Querier {
return &defaultQuerier{nodes: nodes}
}
type defaultQuerier struct {
nodes []Node
}
func (dq *defaultQuerier) Program() (*Command, bool) {
if len(dq.nodes) == 0 {
tracef("Program nodes are empty")
return nil, false
}
tracef("Program node[0] is %T", dq.nodes[0])
v, ok := dq.nodes[0].(*Command)
if ok && v.Name == "" {
return v, false
}
return v, ok
}
func (dq *defaultQuerier) AST() []Node {
ret := []Node{}
for i, node := range dq.nodes {
tracef("AST i=%d node type=%T", i, node)
if _, ok := node.(*ArgDelimiter); ok {
continue
}
if _, ok := node.(*StopFlag); ok {
continue
}
if v, ok := node.(*CompoundShortFlag); ok {
if v.Nodes != nil {
ret = append(ret, NewQuerier(v.Nodes).AST()...)
}
continue
}
if v, ok := node.(*Command); ok {
astNodes := NewQuerier(v.Nodes).AST()
if len(astNodes) == 0 {
astNodes = nil
}
ret = append(
ret,
&Command{
Name: v.Name,
Values: v.Values,
Nodes: astNodes,
})
continue
}
if v, ok := node.(*Flag); ok {
astNodes := NewQuerier(v.Nodes).AST()
if len(astNodes) == 0 {
astNodes = nil
}
ret = append(
ret,
&Flag{
Name: v.Name,
Values: v.Values,
Nodes: astNodes,
})
continue
}
ret = append(ret, node)
}
return ret
}

View File

@ -1,60 +0,0 @@
package argh_test
import (
"testing"
"git.meatballhat.com/x/box-o-sand/argh"
"github.com/stretchr/testify/require"
)
func TestQuerier_Program(t *testing.T) {
for _, tc := range []struct {
name string
args []string
cfg *argh.ParserConfig
exp string
expOK bool
}{
{
name: "typical",
args: []string{"pizzas", "ahoy", "--treatsa", "fun"},
cfg: &argh.ParserConfig{
Prog: argh.CommandConfig{
Commands: &argh.Commands{
Map: map[string]argh.CommandConfig{
"ahoy": argh.CommandConfig{
Flags: &argh.Flags{
Map: map[string]argh.FlagConfig{
"treatsa": argh.FlagConfig{NValue: 1},
},
},
},
},
},
},
},
exp: "pizzas",
expOK: true,
},
{
name: "minimal",
args: []string{"pizzas"},
exp: "pizzas",
expOK: true,
},
{
name: "invalid",
args: []string{},
expOK: false,
},
} {
t.Run(tc.name, func(ct *testing.T) {
pt, err := argh.ParseArgs(tc.args, tc.cfg)
require.Nil(ct, err)
prog, ok := argh.NewQuerier(pt.Nodes).Program()
require.Equal(ct, tc.expOK, ok)
require.Equal(ct, tc.exp, prog.Name)
})
}
}

View File

@ -1,159 +0,0 @@
package argh
import (
"bufio"
"bytes"
"errors"
"io"
"log"
"unicode"
)
type Scanner struct {
r *bufio.Reader
i int
cfg *ScannerConfig
}
func NewScanner(r io.Reader, cfg *ScannerConfig) *Scanner {
if cfg == nil {
cfg = POSIXyScannerConfig
}
return &Scanner{
r: bufio.NewReader(r),
cfg: cfg,
}
}
func (s *Scanner) Scan() (Token, string, Pos) {
ch, pos := s.read()
if s.cfg.IsBlankspace(ch) {
_ = s.unread()
return s.scanBlankspace()
}
if s.cfg.IsAssignmentOperator(ch) {
return ASSIGN, string(ch), pos
}
if s.cfg.IsMultiValueDelim(ch) {
return MULTI_VALUE_DELIMITER, string(ch), pos
}
if ch == eol {
return EOL, "", pos
}
if ch == nul {
return ARG_DELIMITER, string(ch), pos
}
if unicode.IsGraphic(ch) {
_ = s.unread()
return s.scanArg()
}
return ILLEGAL, string(ch), pos
}
func (s *Scanner) read() (rune, Pos) {
ch, _, err := s.r.ReadRune()
s.i++
if errors.Is(err, io.EOF) {
return eol, Pos(s.i)
} else if err != nil {
log.Printf("unknown scanner error=%+v", err)
return eol, Pos(s.i)
}
return ch, Pos(s.i)
}
func (s *Scanner) unread() Pos {
_ = s.r.UnreadRune()
s.i--
return Pos(s.i)
}
func (s *Scanner) scanBlankspace() (Token, string, Pos) {
buf := &bytes.Buffer{}
ch, pos := s.read()
buf.WriteRune(ch)
for {
ch, pos = s.read()
if ch == eol {
break
} else if !s.cfg.IsBlankspace(ch) {
pos = s.unread()
break
} else {
_, _ = buf.WriteRune(ch)
}
}
return BS, buf.String(), pos
}
func (s *Scanner) scanArg() (Token, string, Pos) {
buf := &bytes.Buffer{}
ch, pos := s.read()
buf.WriteRune(ch)
for {
ch, pos = s.read()
if ch == eol || ch == nul || s.cfg.IsAssignmentOperator(ch) || s.cfg.IsMultiValueDelim(ch) {
pos = s.unread()
break
}
_, _ = buf.WriteRune(ch)
}
str := buf.String()
if len(str) == 0 {
return EMPTY, str, pos
}
ch0 := rune(str[0])
if len(str) == 1 {
if s.cfg.IsFlagPrefix(ch0) {
return STDIN_FLAG, str, pos
}
if s.cfg.IsAssignmentOperator(ch0) {
return ASSIGN, str, pos
}
return IDENT, str, pos
}
ch1 := rune(str[1])
if len(str) == 2 {
if s.cfg.IsFlagPrefix(ch0) && s.cfg.IsFlagPrefix(ch1) {
return STOP_FLAG, str, pos
}
if s.cfg.IsFlagPrefix(ch0) {
return SHORT_FLAG, str, pos
}
}
if s.cfg.IsFlagPrefix(ch0) {
if s.cfg.IsFlagPrefix(ch1) {
return LONG_FLAG, str, pos
}
return COMPOUND_SHORT_FLAG, str, pos
}
return IDENT, str, pos
}

View File

@ -1,39 +0,0 @@
package argh
var (
// POSIXyScannerConfig defines a scanner config that uses '-'
// as the flag prefix, which also means that "--" is the "long
// flag" prefix, a bare "--" is considered STOP_FLAG, and a
// bare "-" is considered STDIN_FLAG.
POSIXyScannerConfig = &ScannerConfig{
AssignmentOperator: '=',
FlagPrefix: '-',
MultiValueDelim: ',',
}
)
type ScannerConfig struct {
AssignmentOperator rune
FlagPrefix rune
MultiValueDelim rune
}
func (cfg *ScannerConfig) IsFlagPrefix(ch rune) bool {
return ch == cfg.FlagPrefix
}
func (cfg *ScannerConfig) IsMultiValueDelim(ch rune) bool {
return ch == cfg.MultiValueDelim
}
func (cfg *ScannerConfig) IsAssignmentOperator(ch rune) bool {
return ch == cfg.AssignmentOperator
}
func (cfg *ScannerConfig) IsBlankspace(ch rune) bool {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}
func (cfg *ScannerConfig) IsUnderscore(ch rune) bool {
return ch == '_'
}

View File

@ -1,53 +0,0 @@
//go:generate stringer -type Token
package argh
import "fmt"
const (
ILLEGAL Token = iota
EOL
EMPTY // ''
BS // ' ' '\t' '\n'
IDENT // char group without flag prefix: 'some' 'words'
ARG_DELIMITER // rune(0)
ASSIGN // '='
MULTI_VALUE_DELIMITER // ','
LONG_FLAG // char group with double flag prefix: '--flag'
SHORT_FLAG // single char with single flag prefix: '-f'
COMPOUND_SHORT_FLAG // char group with single flag prefix: '-flag'
STDIN_FLAG // '-'
STOP_FLAG // '--'
nul = rune(0)
eol = rune(-1)
)
type Token int
// Position is adapted from go/token.Position
type Position struct {
Column int
}
func (p *Position) IsValid() bool { return p.Column > 0 }
func (p Position) String() string {
s := ""
if p.IsValid() {
s = fmt.Sprintf("%d", p.Column)
}
if s == "" {
s = "-"
}
return s
}
// Pos is borrowed from go/token.Pos
type Pos int
const NoPos Pos = 0
func (p Pos) IsValid() bool {
return p != NoPos
}

View File

@ -1,35 +0,0 @@
// Code generated by "stringer -type Token"; DO NOT EDIT.
package argh
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[ILLEGAL-0]
_ = x[EOL-1]
_ = x[EMPTY-2]
_ = x[BS-3]
_ = x[IDENT-4]
_ = x[ARG_DELIMITER-5]
_ = x[ASSIGN-6]
_ = x[MULTI_VALUE_DELIMITER-7]
_ = x[LONG_FLAG-8]
_ = x[SHORT_FLAG-9]
_ = x[COMPOUND_SHORT_FLAG-10]
_ = x[STDIN_FLAG-11]
_ = x[STOP_FLAG-12]
}
const _Token_name = "ILLEGALEOLEMPTYBSIDENTARG_DELIMITERASSIGNMULTI_VALUE_DELIMITERLONG_FLAGSHORT_FLAGCOMPOUND_SHORT_FLAGSTDIN_FLAGSTOP_FLAG"
var _Token_index = [...]uint8{0, 7, 10, 15, 17, 22, 35, 41, 62, 71, 81, 100, 110, 119}
func (i Token) String() string {
if i < 0 || i >= Token(len(_Token_index)-1) {
return "Token(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _Token_name[_Token_index[i]:_Token_index[i+1]]
}

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

@ -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/

View File

@ -0,0 +1,11 @@
<?php
require_once 'vendor/autoload.php';
$hello_cmd = new Commando\Command();
$hello_cmd->option()->require()->describedAs('A person\'s name');
$name = $hello_cmd[0];
echo "Hello, $name", PHP_EOL;

View File

@ -0,0 +1,14 @@
{
"name": "meatballhat/personal-home-page",
"type": "library",
"require": {
"nategood/commando": "^0.4.0"
},
"license": "MIT",
"authors": [
{
"name": "Dan Buch",
"email": "dan@meatballhat.com"
}
]
}

124
personal-home-page/composer.lock generated Normal file
View File

@ -0,0 +1,124 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "4aa26239cdb17b13a548c56ac84b5749",
"packages": [
{
"name": "kevinlebrun/colors.php",
"version": "0.4.1",
"source": {
"type": "git",
"url": "https://github.com/kevinlebrun/colors.php.git",
"reference": "d132f36d06e48ea080855af19b4bcb1fb615224a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/kevinlebrun/colors.php/zipball/d132f36d06e48ea080855af19b4bcb1fb615224a",
"reference": "d132f36d06e48ea080855af19b4bcb1fb615224a",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "3.7.*",
"satooshi/php-coveralls": "dev-master",
"squizlabs/php_codesniffer": "1.*"
},
"type": "library",
"autoload": {
"psr-0": {
"Colors": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Kevin Le Brun",
"email": "lebrun.k@gmail.com",
"homepage": "http://kevinlebrun.fr",
"role": "developer"
}
],
"description": "Colors for PHP CLI scripts",
"homepage": "https://github.com/kevinlebrun/colors.php",
"keywords": [
"cli",
"color",
"colors",
"console",
"shell"
],
"support": {
"issues": "https://github.com/kevinlebrun/colors.php/issues",
"source": "https://github.com/kevinlebrun/colors.php/tree/0.4.1"
},
"time": "2014-12-23T01:23:37+00:00"
},
{
"name": "nategood/commando",
"version": "0.4.0",
"source": {
"type": "git",
"url": "https://github.com/nategood/commando.git",
"reference": "8fedd49fcb694faf60d87d5c2c4defdffa298fa0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nategood/commando/zipball/8fedd49fcb694faf60d87d5c2c4defdffa298fa0",
"reference": "8fedd49fcb694faf60d87d5c2c4defdffa298fa0",
"shasum": ""
},
"require": {
"kevinlebrun/colors.php": "~0.2",
"php": ">=5.6"
},
"type": "library",
"autoload": {
"psr-0": {
"Commando": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nate Good",
"email": "me@nategood.com"
}
],
"description": "PHP CLI Commando Style",
"homepage": "http://github.com/nategood/commando",
"keywords": [
"automation",
"cli",
"command",
"command line",
"command line interface",
"scripting"
],
"support": {
"issues": "https://github.com/nategood/commando/issues",
"source": "https://github.com/nategood/commando/tree/v0.4.0"
},
"time": "2019-07-10T02:37:11+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
</head>
<body>
<?php
echo "<h3>Hi, I'm a PHP script!</h3>";
?>
</body>
</html>

View File

@ -0,0 +1,35 @@
<?php
$name = 'Flavio';
var_dump($name);
$age = 20;
var_dump($age);
$base = 20;
$height = 10;
$area = $base * $height;
$test = 'an example';
$example = "This is $test";
print $example . "\n";
$firstName = 'Flavio';
$lastName = 'Copes';
$fullName = $firstName . ' ' . $lastName;
print '$fullName = ' . $fullName . "\n";
print strlen($fullName) . "\n";
$weirdName = str_replace('avio', 'ower', $fullName);
print '$weirdName = ' . $weirdName . "\n";
print 'exploded $weirdName = ' . var_dump(explode(' ', $weirdName)) . "\n";

View File

@ -0,0 +1 @@
<?php phpinfo(); ?>

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