main.go (2179B)
1 package main 2 3 import ( 4 "context" 5 "flag" 6 7 "os" 8 "os/signal" 9 "path/filepath" 10 "syscall" 11 "time" 12 13 "code.dwrz.net/src/pkg/life" 14 "code.dwrz.net/src/pkg/log" 15 "code.dwrz.net/src/pkg/terminal" 16 ) 17 18 var ( 19 height = flag.Int("h", 0, "height") 20 width = flag.Int("w", 0, "width") 21 tick = flag.Int("t", 100, "ms between turns") 22 ) 23 24 func main() { 25 var l = log.New(os.Stderr) 26 27 // Parse flags. 28 flag.Parse() 29 if *height < 0 { 30 l.Error.Fatalf("invalid height: %d", *height) 31 } 32 if *width < 0 { 33 l.Error.Fatalf("invalid width: %d", *width) 34 } 35 if *tick <= 0 { 36 l.Error.Fatalf("invalid tick: %d", *tick) 37 } 38 39 // Setup the main context. 40 ctx, cancel := context.WithCancel(context.Background()) 41 42 // Setup workspace and log file. 43 cdir, err := os.UserCacheDir() 44 if err != nil { 45 l.Error.Fatalf( 46 "failed to determine user cache directory: %v", err, 47 ) 48 } 49 wdir := filepath.Join(cdir, "life") 50 51 if err := os.MkdirAll(wdir, os.ModeDir|0700); err != nil { 52 l.Error.Fatalf("failed to create tmp dir: %v", err) 53 } 54 55 f, err := os.Create(wdir + "/log") 56 if err != nil { 57 l.Error.Fatalf("failed to create log file: %v", err) 58 } 59 defer f.Close() 60 61 // Retrieve terminal info. 62 t, err := terminal.New(os.Stdin.Fd()) 63 if err != nil { 64 l.Error.Fatalf("failed to get terminal attributes: %v", err) 65 } 66 size, err := t.Size() 67 if err != nil { 68 l.Error.Fatalf("failed to get terminal size: %v", err) 69 } 70 if *height == 0 { 71 rows := int(size.Rows) 72 height = &rows 73 } 74 if *width == 0 { 75 cols := int(size.Columns) + 1 76 width = &cols 77 } 78 79 // TODO: refactor; handle sigwinch. 80 go func() { 81 var signals = make(chan os.Signal, 1) 82 signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT) 83 84 // Block until we receive a signal. 85 s := <-signals 86 l.Debug.Printf("received signal: %s", s) 87 88 cancel() 89 }() 90 91 // Setup the game. 92 var game = life.New(life.Parameters{ 93 Height: *height, 94 In: os.Stdin, 95 Log: log.New(f), 96 Out: os.Stdout, 97 Terminal: t, 98 Tick: time.Duration(*tick) * time.Millisecond, 99 Width: *width, 100 }) 101 if err != nil { 102 l.Error.Fatalf("failed to create game: %v", err) 103 } 104 105 // Run the game. 106 if err := game.Run(ctx); err != nil { 107 l.Error.Fatal(err) 108 } 109 }