├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE.md ├── README.md ├── crab.JPG └── src ├── krab.rs ├── main.rs └── tui.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "once_cell", 13 | "version_check", 14 | "zerocopy", 15 | ] 16 | 17 | [[package]] 18 | name = "allocator-api2" 19 | version = "0.2.18" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" 22 | 23 | [[package]] 24 | name = "anstream" 25 | version = "0.6.14" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" 28 | dependencies = [ 29 | "anstyle", 30 | "anstyle-parse", 31 | "anstyle-query", 32 | "anstyle-wincon", 33 | "colorchoice", 34 | "is_terminal_polyfill", 35 | "utf8parse", 36 | ] 37 | 38 | [[package]] 39 | name = "anstyle" 40 | version = "1.0.7" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" 43 | 44 | [[package]] 45 | name = "anstyle-parse" 46 | version = "0.2.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" 49 | dependencies = [ 50 | "utf8parse", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle-query" 55 | version = "1.1.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" 58 | dependencies = [ 59 | "windows-sys 0.52.0", 60 | ] 61 | 62 | [[package]] 63 | name = "anstyle-wincon" 64 | version = "3.0.3" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" 67 | dependencies = [ 68 | "anstyle", 69 | "windows-sys 0.52.0", 70 | ] 71 | 72 | [[package]] 73 | name = "arrayvec" 74 | version = "0.7.4" 75 | source = "registry+https://github.com/rust-lang/crates.io-index" 76 | checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" 77 | 78 | [[package]] 79 | name = "autocfg" 80 | version = "1.3.0" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 83 | 84 | [[package]] 85 | name = "bit-set" 86 | version = "0.5.3" 87 | source = "registry+https://github.com/rust-lang/crates.io-index" 88 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" 89 | dependencies = [ 90 | "bit-vec", 91 | ] 92 | 93 | [[package]] 94 | name = "bit-vec" 95 | version = "0.6.3" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" 98 | 99 | [[package]] 100 | name = "bitflags" 101 | version = "2.5.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" 104 | 105 | [[package]] 106 | name = "byteorder" 107 | version = "1.5.0" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 110 | 111 | [[package]] 112 | name = "cassowary" 113 | version = "0.3.0" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 116 | 117 | [[package]] 118 | name = "castaway" 119 | version = "0.2.2" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc" 122 | dependencies = [ 123 | "rustversion", 124 | ] 125 | 126 | [[package]] 127 | name = "cfg-if" 128 | version = "1.0.0" 129 | source = "registry+https://github.com/rust-lang/crates.io-index" 130 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 131 | 132 | [[package]] 133 | name = "clap" 134 | version = "4.5.7" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f" 137 | dependencies = [ 138 | "clap_builder", 139 | "clap_derive", 140 | ] 141 | 142 | [[package]] 143 | name = "clap_builder" 144 | version = "4.5.7" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f" 147 | dependencies = [ 148 | "anstream", 149 | "anstyle", 150 | "clap_lex", 151 | "strsim", 152 | ] 153 | 154 | [[package]] 155 | name = "clap_derive" 156 | version = "4.5.5" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6" 159 | dependencies = [ 160 | "heck", 161 | "proc-macro2", 162 | "quote", 163 | "syn 2.0.66", 164 | ] 165 | 166 | [[package]] 167 | name = "clap_lex" 168 | version = "0.7.1" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" 171 | 172 | [[package]] 173 | name = "colorchoice" 174 | version = "1.0.1" 175 | source = "registry+https://github.com/rust-lang/crates.io-index" 176 | checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" 177 | 178 | [[package]] 179 | name = "compact_str" 180 | version = "0.7.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" 183 | dependencies = [ 184 | "castaway", 185 | "cfg-if", 186 | "itoa", 187 | "ryu", 188 | "static_assertions", 189 | ] 190 | 191 | [[package]] 192 | name = "crossterm" 193 | version = "0.27.0" 194 | source = "registry+https://github.com/rust-lang/crates.io-index" 195 | checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" 196 | dependencies = [ 197 | "bitflags", 198 | "crossterm_winapi", 199 | "libc", 200 | "mio", 201 | "parking_lot", 202 | "signal-hook", 203 | "signal-hook-mio", 204 | "winapi", 205 | ] 206 | 207 | [[package]] 208 | name = "crossterm_winapi" 209 | version = "0.9.1" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 212 | dependencies = [ 213 | "winapi", 214 | ] 215 | 216 | [[package]] 217 | name = "either" 218 | version = "1.12.0" 219 | source = "registry+https://github.com/rust-lang/crates.io-index" 220 | checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" 221 | 222 | [[package]] 223 | name = "getrandom" 224 | version = "0.2.15" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 227 | dependencies = [ 228 | "cfg-if", 229 | "libc", 230 | "wasi", 231 | ] 232 | 233 | [[package]] 234 | name = "hashbrown" 235 | version = "0.12.3" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 238 | 239 | [[package]] 240 | name = "hashbrown" 241 | version = "0.14.5" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" 244 | dependencies = [ 245 | "ahash", 246 | "allocator-api2", 247 | ] 248 | 249 | [[package]] 250 | name = "heck" 251 | version = "0.5.0" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 254 | 255 | [[package]] 256 | name = "indexmap" 257 | version = "1.9.3" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 260 | dependencies = [ 261 | "autocfg", 262 | "hashbrown 0.12.3", 263 | ] 264 | 265 | [[package]] 266 | name = "is_terminal_polyfill" 267 | version = "1.70.0" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" 270 | 271 | [[package]] 272 | name = "itertools" 273 | version = "0.12.1" 274 | source = "registry+https://github.com/rust-lang/crates.io-index" 275 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 276 | dependencies = [ 277 | "either", 278 | ] 279 | 280 | [[package]] 281 | name = "itoa" 282 | version = "1.0.11" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" 285 | 286 | [[package]] 287 | name = "libc" 288 | version = "0.2.155" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" 291 | 292 | [[package]] 293 | name = "lock_api" 294 | version = "0.4.12" 295 | source = "registry+https://github.com/rust-lang/crates.io-index" 296 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 297 | dependencies = [ 298 | "autocfg", 299 | "scopeguard", 300 | ] 301 | 302 | [[package]] 303 | name = "log" 304 | version = "0.4.21" 305 | source = "registry+https://github.com/rust-lang/crates.io-index" 306 | checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" 307 | 308 | [[package]] 309 | name = "lru" 310 | version = "0.12.3" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" 313 | dependencies = [ 314 | "hashbrown 0.14.5", 315 | ] 316 | 317 | [[package]] 318 | name = "memoffset" 319 | version = "0.9.1" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" 322 | dependencies = [ 323 | "autocfg", 324 | ] 325 | 326 | [[package]] 327 | name = "mio" 328 | version = "0.8.11" 329 | source = "registry+https://github.com/rust-lang/crates.io-index" 330 | checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" 331 | dependencies = [ 332 | "libc", 333 | "log", 334 | "wasi", 335 | "windows-sys 0.48.0", 336 | ] 337 | 338 | [[package]] 339 | name = "mrKrabs" 340 | version = "1.1.0" 341 | dependencies = [ 342 | "clap", 343 | "crossterm", 344 | "rand", 345 | "ratatui", 346 | "savefile", 347 | "savefile-derive", 348 | ] 349 | 350 | [[package]] 351 | name = "once_cell" 352 | version = "1.19.0" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 355 | 356 | [[package]] 357 | name = "parking_lot" 358 | version = "0.12.3" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 361 | dependencies = [ 362 | "lock_api", 363 | "parking_lot_core", 364 | ] 365 | 366 | [[package]] 367 | name = "parking_lot_core" 368 | version = "0.9.10" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 371 | dependencies = [ 372 | "cfg-if", 373 | "libc", 374 | "redox_syscall", 375 | "smallvec", 376 | "windows-targets 0.52.5", 377 | ] 378 | 379 | [[package]] 380 | name = "paste" 381 | version = "1.0.15" 382 | source = "registry+https://github.com/rust-lang/crates.io-index" 383 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 384 | 385 | [[package]] 386 | name = "ppv-lite86" 387 | version = "0.2.17" 388 | source = "registry+https://github.com/rust-lang/crates.io-index" 389 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 390 | 391 | [[package]] 392 | name = "proc-macro-error" 393 | version = "1.0.4" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 396 | dependencies = [ 397 | "proc-macro-error-attr", 398 | "proc-macro2", 399 | "quote", 400 | "syn 1.0.109", 401 | "version_check", 402 | ] 403 | 404 | [[package]] 405 | name = "proc-macro-error-attr" 406 | version = "1.0.4" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 409 | dependencies = [ 410 | "proc-macro2", 411 | "quote", 412 | "version_check", 413 | ] 414 | 415 | [[package]] 416 | name = "proc-macro2" 417 | version = "1.0.85" 418 | source = "registry+https://github.com/rust-lang/crates.io-index" 419 | checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" 420 | dependencies = [ 421 | "unicode-ident", 422 | ] 423 | 424 | [[package]] 425 | name = "quote" 426 | version = "1.0.36" 427 | source = "registry+https://github.com/rust-lang/crates.io-index" 428 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 429 | dependencies = [ 430 | "proc-macro2", 431 | ] 432 | 433 | [[package]] 434 | name = "rand" 435 | version = "0.8.5" 436 | source = "registry+https://github.com/rust-lang/crates.io-index" 437 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 438 | dependencies = [ 439 | "libc", 440 | "rand_chacha", 441 | "rand_core", 442 | ] 443 | 444 | [[package]] 445 | name = "rand_chacha" 446 | version = "0.3.1" 447 | source = "registry+https://github.com/rust-lang/crates.io-index" 448 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 449 | dependencies = [ 450 | "ppv-lite86", 451 | "rand_core", 452 | ] 453 | 454 | [[package]] 455 | name = "rand_core" 456 | version = "0.6.4" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 459 | dependencies = [ 460 | "getrandom", 461 | ] 462 | 463 | [[package]] 464 | name = "ratatui" 465 | version = "0.26.3" 466 | source = "registry+https://github.com/rust-lang/crates.io-index" 467 | checksum = "f44c9e68fd46eda15c646fbb85e1040b657a58cdc8c98db1d97a55930d991eef" 468 | dependencies = [ 469 | "bitflags", 470 | "cassowary", 471 | "compact_str", 472 | "crossterm", 473 | "itertools", 474 | "lru", 475 | "paste", 476 | "stability", 477 | "strum", 478 | "unicode-segmentation", 479 | "unicode-truncate", 480 | "unicode-width", 481 | ] 482 | 483 | [[package]] 484 | name = "redox_syscall" 485 | version = "0.5.1" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" 488 | dependencies = [ 489 | "bitflags", 490 | ] 491 | 492 | [[package]] 493 | name = "rustc_version" 494 | version = "0.2.3" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 497 | dependencies = [ 498 | "semver", 499 | ] 500 | 501 | [[package]] 502 | name = "rustversion" 503 | version = "1.0.17" 504 | source = "registry+https://github.com/rust-lang/crates.io-index" 505 | checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" 506 | 507 | [[package]] 508 | name = "ryu" 509 | version = "1.0.18" 510 | source = "registry+https://github.com/rust-lang/crates.io-index" 511 | checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" 512 | 513 | [[package]] 514 | name = "savefile" 515 | version = "0.17.4" 516 | source = "registry+https://github.com/rust-lang/crates.io-index" 517 | checksum = "b0a3a623b09a2110f66fa932f1c2a81b0184eb832da45082638550a9abbed2d1" 518 | dependencies = [ 519 | "arrayvec", 520 | "bit-set", 521 | "bit-vec", 522 | "byteorder", 523 | "indexmap", 524 | "memoffset", 525 | "parking_lot", 526 | "rustc_version", 527 | "smallvec", 528 | ] 529 | 530 | [[package]] 531 | name = "savefile-derive" 532 | version = "0.17.4" 533 | source = "registry+https://github.com/rust-lang/crates.io-index" 534 | checksum = "cb342f6d7d45b6418fe64a1b8c98275d528f437950f637df49a9ff031816ffa1" 535 | dependencies = [ 536 | "proc-macro-error", 537 | "proc-macro2", 538 | "quote", 539 | "syn 1.0.109", 540 | ] 541 | 542 | [[package]] 543 | name = "scopeguard" 544 | version = "1.2.0" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 547 | 548 | [[package]] 549 | name = "semver" 550 | version = "0.9.0" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 553 | dependencies = [ 554 | "semver-parser", 555 | ] 556 | 557 | [[package]] 558 | name = "semver-parser" 559 | version = "0.7.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 562 | 563 | [[package]] 564 | name = "signal-hook" 565 | version = "0.3.17" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 568 | dependencies = [ 569 | "libc", 570 | "signal-hook-registry", 571 | ] 572 | 573 | [[package]] 574 | name = "signal-hook-mio" 575 | version = "0.2.3" 576 | source = "registry+https://github.com/rust-lang/crates.io-index" 577 | checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" 578 | dependencies = [ 579 | "libc", 580 | "mio", 581 | "signal-hook", 582 | ] 583 | 584 | [[package]] 585 | name = "signal-hook-registry" 586 | version = "1.4.2" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 589 | dependencies = [ 590 | "libc", 591 | ] 592 | 593 | [[package]] 594 | name = "smallvec" 595 | version = "1.13.2" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 598 | 599 | [[package]] 600 | name = "stability" 601 | version = "0.2.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a" 604 | dependencies = [ 605 | "quote", 606 | "syn 2.0.66", 607 | ] 608 | 609 | [[package]] 610 | name = "static_assertions" 611 | version = "1.1.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 614 | 615 | [[package]] 616 | name = "strsim" 617 | version = "0.11.1" 618 | source = "registry+https://github.com/rust-lang/crates.io-index" 619 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 620 | 621 | [[package]] 622 | name = "strum" 623 | version = "0.26.2" 624 | source = "registry+https://github.com/rust-lang/crates.io-index" 625 | checksum = "5d8cec3501a5194c432b2b7976db6b7d10ec95c253208b45f83f7136aa985e29" 626 | dependencies = [ 627 | "strum_macros", 628 | ] 629 | 630 | [[package]] 631 | name = "strum_macros" 632 | version = "0.26.4" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 635 | dependencies = [ 636 | "heck", 637 | "proc-macro2", 638 | "quote", 639 | "rustversion", 640 | "syn 2.0.66", 641 | ] 642 | 643 | [[package]] 644 | name = "syn" 645 | version = "1.0.109" 646 | source = "registry+https://github.com/rust-lang/crates.io-index" 647 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 648 | dependencies = [ 649 | "proc-macro2", 650 | "quote", 651 | "unicode-ident", 652 | ] 653 | 654 | [[package]] 655 | name = "syn" 656 | version = "2.0.66" 657 | source = "registry+https://github.com/rust-lang/crates.io-index" 658 | checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" 659 | dependencies = [ 660 | "proc-macro2", 661 | "quote", 662 | "unicode-ident", 663 | ] 664 | 665 | [[package]] 666 | name = "unicode-ident" 667 | version = "1.0.12" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 670 | 671 | [[package]] 672 | name = "unicode-segmentation" 673 | version = "1.11.0" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" 676 | 677 | [[package]] 678 | name = "unicode-truncate" 679 | version = "1.0.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "5a5fbabedabe362c618c714dbefda9927b5afc8e2a8102f47f081089a9019226" 682 | dependencies = [ 683 | "itertools", 684 | "unicode-width", 685 | ] 686 | 687 | [[package]] 688 | name = "unicode-width" 689 | version = "0.1.13" 690 | source = "registry+https://github.com/rust-lang/crates.io-index" 691 | checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" 692 | 693 | [[package]] 694 | name = "utf8parse" 695 | version = "0.2.2" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 698 | 699 | [[package]] 700 | name = "version_check" 701 | version = "0.9.4" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 704 | 705 | [[package]] 706 | name = "wasi" 707 | version = "0.11.0+wasi-snapshot-preview1" 708 | source = "registry+https://github.com/rust-lang/crates.io-index" 709 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 710 | 711 | [[package]] 712 | name = "winapi" 713 | version = "0.3.9" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 716 | dependencies = [ 717 | "winapi-i686-pc-windows-gnu", 718 | "winapi-x86_64-pc-windows-gnu", 719 | ] 720 | 721 | [[package]] 722 | name = "winapi-i686-pc-windows-gnu" 723 | version = "0.4.0" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 726 | 727 | [[package]] 728 | name = "winapi-x86_64-pc-windows-gnu" 729 | version = "0.4.0" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 732 | 733 | [[package]] 734 | name = "windows-sys" 735 | version = "0.48.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 738 | dependencies = [ 739 | "windows-targets 0.48.5", 740 | ] 741 | 742 | [[package]] 743 | name = "windows-sys" 744 | version = "0.52.0" 745 | source = "registry+https://github.com/rust-lang/crates.io-index" 746 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 747 | dependencies = [ 748 | "windows-targets 0.52.5", 749 | ] 750 | 751 | [[package]] 752 | name = "windows-targets" 753 | version = "0.48.5" 754 | source = "registry+https://github.com/rust-lang/crates.io-index" 755 | checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" 756 | dependencies = [ 757 | "windows_aarch64_gnullvm 0.48.5", 758 | "windows_aarch64_msvc 0.48.5", 759 | "windows_i686_gnu 0.48.5", 760 | "windows_i686_msvc 0.48.5", 761 | "windows_x86_64_gnu 0.48.5", 762 | "windows_x86_64_gnullvm 0.48.5", 763 | "windows_x86_64_msvc 0.48.5", 764 | ] 765 | 766 | [[package]] 767 | name = "windows-targets" 768 | version = "0.52.5" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" 771 | dependencies = [ 772 | "windows_aarch64_gnullvm 0.52.5", 773 | "windows_aarch64_msvc 0.52.5", 774 | "windows_i686_gnu 0.52.5", 775 | "windows_i686_gnullvm", 776 | "windows_i686_msvc 0.52.5", 777 | "windows_x86_64_gnu 0.52.5", 778 | "windows_x86_64_gnullvm 0.52.5", 779 | "windows_x86_64_msvc 0.52.5", 780 | ] 781 | 782 | [[package]] 783 | name = "windows_aarch64_gnullvm" 784 | version = "0.48.5" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" 787 | 788 | [[package]] 789 | name = "windows_aarch64_gnullvm" 790 | version = "0.52.5" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" 793 | 794 | [[package]] 795 | name = "windows_aarch64_msvc" 796 | version = "0.48.5" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" 799 | 800 | [[package]] 801 | name = "windows_aarch64_msvc" 802 | version = "0.52.5" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" 805 | 806 | [[package]] 807 | name = "windows_i686_gnu" 808 | version = "0.48.5" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" 811 | 812 | [[package]] 813 | name = "windows_i686_gnu" 814 | version = "0.52.5" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" 817 | 818 | [[package]] 819 | name = "windows_i686_gnullvm" 820 | version = "0.52.5" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" 823 | 824 | [[package]] 825 | name = "windows_i686_msvc" 826 | version = "0.48.5" 827 | source = "registry+https://github.com/rust-lang/crates.io-index" 828 | checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" 829 | 830 | [[package]] 831 | name = "windows_i686_msvc" 832 | version = "0.52.5" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" 835 | 836 | [[package]] 837 | name = "windows_x86_64_gnu" 838 | version = "0.48.5" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" 841 | 842 | [[package]] 843 | name = "windows_x86_64_gnu" 844 | version = "0.52.5" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" 847 | 848 | [[package]] 849 | name = "windows_x86_64_gnullvm" 850 | version = "0.48.5" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" 853 | 854 | [[package]] 855 | name = "windows_x86_64_gnullvm" 856 | version = "0.52.5" 857 | source = "registry+https://github.com/rust-lang/crates.io-index" 858 | checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" 859 | 860 | [[package]] 861 | name = "windows_x86_64_msvc" 862 | version = "0.48.5" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" 865 | 866 | [[package]] 867 | name = "windows_x86_64_msvc" 868 | version = "0.52.5" 869 | source = "registry+https://github.com/rust-lang/crates.io-index" 870 | checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" 871 | 872 | [[package]] 873 | name = "zerocopy" 874 | version = "0.7.34" 875 | source = "registry+https://github.com/rust-lang/crates.io-index" 876 | checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" 877 | dependencies = [ 878 | "zerocopy-derive", 879 | ] 880 | 881 | [[package]] 882 | name = "zerocopy-derive" 883 | version = "0.7.34" 884 | source = "registry+https://github.com/rust-lang/crates.io-index" 885 | checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" 886 | dependencies = [ 887 | "proc-macro2", 888 | "quote", 889 | "syn 2.0.66", 890 | ] 891 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "mrKrabs" 3 | version = "1.1.0" 4 | edition = "2021" 5 | authors = ["Tharun Tilakumara"] 6 | readme = "README.md" 7 | repository = "https://github.com/DrCheeseFace/Krabby-gotchi" 8 | license = "MIT" 9 | description = "A CLI based virtual pet game" 10 | 11 | [dependencies] 12 | clap = { version = "4.5.7", features = ["derive"] } 13 | crossterm = "0.27.0" 14 | rand = "0.8.5" 15 | ratatui = "0.26.3" 16 | savefile = "0.17" 17 | savefile-derive = "0.17" 18 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 Tharun Tilakumara 2 | 3 | Permission is hereby granted, free of charge, to any person (or crustacean) 4 | obtaining a copy of this software and associated documentation files 5 | (the "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | sublicense, and/or sell copies of the Software, and to permit persons to 8 | whom the Software is furnished to do so, subject to the following conditions: 9 | The above copyright notice and this permission notice shall be included 10 | in all copies or substantial portions of the Software. 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 12 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 13 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 14 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 15 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 16 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 17 | DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Krabby-gotchi (via the terminal) 2 | 3 | ![terminal app preview](https://github.com/DrCheeseFace/Krabby-gotchi/blob/master/crab.JPG?raw=true) 4 |

her real name is sally^

5 | 6 | 7 | ## What is this? 8 | Imagine a future where everyone had a crustacious companion. 9 |
10 | **A world devoid of conflict.** 11 |
12 | I present humbly to thee, 13 | 14 | ### A Krabby-gotchi 🦀 15 | (tamagotchi but crab) 16 | 17 | ## Ok but what really is this? 18 | The krabs made me do it. 19 | 20 | ## Ok but what *really really* is this? 21 | Learning rust. 22 |
23 | Hopefully will have a terminal tamagotchi by the end because tamagotchis 24 | are expensive and crabs are free if you are near an ocean. 25 | 26 | ## Install 27 | Its on crate.io! 28 |
29 | 30 | ``` 31 | cargo install mrKrabs@1.1.0 32 | ``` 33 | 34 | 35 | ## Dev 36 | Get Rust 37 | ``` 38 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 39 | ``` 40 | Clone this repo, cd into it and run 41 | ``` 42 | cargo run 43 | ``` 44 | ## TODO 45 | - [x] saving and config 46 | - [x] have krab stats 47 | - [x] feed the krab 48 | - [x] pet the krab 49 | - [x] tick down/ up status overtime 50 | - [x] forge the krab (animate) 51 | - [ ] animate the krab moving around perhaps 52 | - [ ] think about *maybe* implementing lobsters 53 | - [ ] make mood, status and stage enums later 54 | 55 | ## Contributing 56 | - If you spot a bug (which there probabably are many), put in an issue with how to reproduce it. 57 | - If you want to suggest a feature put in an issue with the feature request. 58 | - If you want to contribute code, make a pull request. anything short of a war crime will probably be accepted. 59 | 60 | 61 | ![funny krab gif](https://media2.giphy.com/media/v1.Y2lkPTc5MGI3NjExYnJjcDQ0ZDI2MnZyYjZja3RlNGlxemxueDhiZXl4eGFpcDI0bGE3MSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/gHPRSja3k9frLfWl0J/giphy.webp) 62 | -------------------------------------------------------------------------------- /crab.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DrCheeseFace/Krabby-gotchi/d4bf73f0f56233d8d9c0a88363ebc33f80b810b2/crab.JPG -------------------------------------------------------------------------------- /src/krab.rs: -------------------------------------------------------------------------------- 1 | use rand::{thread_rng, Rng}; 2 | 3 | #[derive(Debug, Savefile)] 4 | pub struct Krab { 5 | name: String, 6 | hunger: u16, 7 | happiness: u16, 8 | health: u16, 9 | age: u64, 10 | mood: String, 11 | status: String, 12 | stage: String, 13 | } 14 | 15 | impl Krab { 16 | pub fn new(name: String) -> Self { 17 | Self { 18 | name, 19 | hunger: 0, 20 | happiness: 500, 21 | health: 500, 22 | age: 0, 23 | mood: String::from("neutral"), 24 | status: String::from("alive"), 25 | stage: String::from("egg"), 26 | } 27 | } 28 | pub fn grow_older(&mut self) { 29 | //TODO vary += x based on current stats 30 | self.age += 1; 31 | match self.age { 32 | 0..=500 => { 33 | self.stage = String::from("egg"); 34 | } 35 | 501..=10000 => { 36 | self.stage = String::from("baby"); 37 | } 38 | 10001..=582800 => { 39 | self.stage = String::from("adult"); 40 | } 41 | _ => { 42 | self.stage = String::from("elder"); 43 | } 44 | } 45 | } 46 | pub fn on_tick(&mut self) { 47 | // I FUCKING LOVE IF ELSE 48 | if self.status != "dead" { 49 | self.grow_older(); 50 | 51 | if self.hunger == 0 { 52 | if self.health == 0 { 53 | self.status = String::from("dead"); 54 | } else { 55 | self.injure() 56 | } 57 | } 58 | 59 | if self.hunger > 800 { 60 | self.heal(); 61 | self.pet(); 62 | } 63 | if self.hunger < 500 { 64 | self.injure(); 65 | } 66 | 67 | if (self.hunger < 300) == (self.health < 300) { 68 | self.sadder(5); 69 | } else { 70 | self.sadder(2); 71 | } 72 | if self.happiness < 300 { 73 | self.starve() 74 | } 75 | 76 | let mut rng = thread_rng(); 77 | let m: f64 = (self.hunger as f64 + self.health as f64) / 2000 as f64; 78 | let is_happy: bool = rng.gen_bool(m); 79 | if is_happy { 80 | self.happier(2); 81 | } else { 82 | self.sadder(2); 83 | } 84 | } else { 85 | self.happiness = 0; 86 | self.hunger = 0; 87 | } 88 | self.starve(); 89 | } 90 | 91 | pub fn pet(&mut self) { 92 | if self.happiness < 995 { 93 | self.happiness += 5; 94 | } else { 95 | self.happiness = 1000; 96 | } 97 | } 98 | 99 | pub fn sadder(&mut self, n: u16) { 100 | if self.happiness > n { 101 | self.happiness -= n; 102 | } else { 103 | self.happiness = 0; 104 | } 105 | } 106 | pub fn happier(&mut self, n: u16) { 107 | if self.happiness < 1000 - n { 108 | self.happiness += n; 109 | } else { 110 | self.happiness = 1000; 111 | } 112 | } 113 | 114 | pub fn heal(&mut self) { 115 | if self.health < 995 { 116 | self.health += 5; 117 | } else { 118 | self.health = 1000; 119 | } 120 | } 121 | 122 | pub fn injure(&mut self) { 123 | if self.health > 1 { 124 | self.health -= 1; 125 | } else { 126 | self.health = 0; 127 | } 128 | } 129 | pub fn starve(&mut self) { 130 | if self.hunger > 1 { 131 | self.hunger -= 1; 132 | } else { 133 | self.hunger = 0; 134 | } 135 | } 136 | 137 | pub fn feed(&mut self) { 138 | if self.hunger < 995 { 139 | self.hunger += 5; 140 | } else { 141 | self.hunger = 1000; 142 | } 143 | } 144 | 145 | //getters 146 | #[warn(dead_code)] 147 | pub fn name(&self) -> &String { 148 | &self.name 149 | } 150 | pub fn hunger(&self) -> &u16 { 151 | &self.hunger 152 | } 153 | pub fn happiness(&self) -> &u16 { 154 | &self.happiness 155 | } 156 | pub fn health(&self) -> &u16 { 157 | &self.health 158 | } 159 | pub fn status(&self) -> &String { 160 | &self.status 161 | } 162 | pub fn stage(&self) -> &String { 163 | &self.stage 164 | } 165 | 166 | pub fn ascii(&self) -> Vec<&str> { 167 | let text = match self.stage.as_str() { 168 | "egg" => { 169 | vec![ 170 | " ████ ", 171 | " ██░░░░██ ", 172 | " ██░░░░░░░░██ ", 173 | " ██░░░░░░░░██ ", 174 | " ██░░░░░░░░░░░░██ ", 175 | " ██░░░░░░░░░░░░██ ", 176 | " ██░░░░░░░░░░░░██ ", 177 | " ██░░░░░░░░██ ", 178 | " ████████ ", 179 | ] 180 | } 181 | "baby" => { 182 | vec![ 183 | " ░░ ", 184 | " ░░░░ ░░░░░░ ", 185 | " ░░░░ ░░ ░░░░░░", 186 | " ░░░░ ░░ ░░ ░░▒▒", 187 | " ░░░░░░▒▒ ░░▒▒░░▒▒", 188 | " ░░▒▒ ░░▒▒", 189 | " ░░▒▒ ░░░░░░░░ ░░▒▒ ", 190 | " ░░░░░░░░░░░░░░░░ ", 191 | " ░░░░░░░░██░░██░░░░░░ ", 192 | " ▒▒░░░░░░░░░░░░░░░░▒▒ ", 193 | " ░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒░░░░", 194 | " ░░░░ ▒▒░░ ░░▒▒ ░░░░", 195 | " ░░ ▒▒ ▒▒ ░░", 196 | ] 197 | } 198 | "adult" => { 199 | vec![ 200 | " ▒▒▒▒░░ ", 201 | " ░░▒▒░░▒▒▒▒░░░░ ", 202 | " ▒▒▒▒▒▒░░▒▒▓▓▓▓▓▓▓▓▒▒ ▓▓▒▒▒▒ ", 203 | " ▒▒▒▒ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓░░░░▒▒░░ ", 204 | " ░░ ▒▒▒▒▒▒▓▓▓▓▓▓▓▓██▓▓▓▓▓▓░░░░░░ ▓▓ ", 205 | " ▒▒▓▓▒▒▓▓▓▓▓▓▓▓▓▓▓▓██▓▓████▓▓▒▒░░ ▒▒", 206 | " ░░▓▓▓▓░░░░░░░░░░▓▓▓▓▓▓▓▓▓▓▓▓░░▒▒▒▒ ░░▒▒", 207 | " ▓▓░░▓▓░░ ░░░░░░░░▒▒▒▒▒▒▓▓░░░░▓▓░░░░", 208 | "▒▒ ▒▒▒▒ ░░░░░░ ░░▒▒▓▓ ▓▓░░ ▒▒ ", 209 | "░░ ░░▒▒░░ ░░░░▒▒▒▒ ▓▓ ▓▓ ", 210 | " ░░░░ ░░ ▒▒░░▓▓ ▒▒ ", 211 | " ░░▒▒░░▒▒ ▒▒ ", 212 | " ░░▒▒▓▓▓▓▒▒ ▒▒ ▒▒ ", 213 | " ░░░░░░▒▒▒▒▒▒░░░░▒▒ ░░ ", 214 | " ░░░░░░░░░░░░ ░░▒▒ ", 215 | " ░░░░░░░░ ░░▒▒ ", 216 | ] 217 | } 218 | "elder" => { 219 | vec![ 220 | r"(\|) ._. (|/)" 221 | ] 222 | } 223 | _ => { 224 | vec![ 225 | "/l、", 226 | "(゚、 。 7", 227 | " l ~ヽ", 228 | " じしf_,)ノ", 229 | ] 230 | } 231 | }; 232 | return text; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | extern crate savefile; 2 | use savefile::prelude::*; 3 | #[macro_use] 4 | extern crate savefile_derive; 5 | 6 | use clap::Parser; 7 | use crossterm::event::{self, Event, KeyCode, KeyEvent, KeyEventKind}; 8 | use std::io; 9 | use std::time::{Duration, Instant}; 10 | mod krab; 11 | mod tui; 12 | 13 | #[derive(Parser, Debug)] 14 | #[command( 15 | version, 16 | about, 17 | long_about = "I bestow upon thee a (somewhat) friendly crustacean" 18 | )] 19 | struct Args { 20 | /// name the crab 21 | #[arg(short, long, default_value = "Eugene Krabs")] 22 | name: String, 23 | } 24 | 25 | #[derive(Debug)] 26 | pub struct App { 27 | exit: bool, 28 | tick_count: u64, 29 | krab: krab::Krab, 30 | show_help_menu: bool, 31 | show_save_timer: u16, 32 | } 33 | 34 | fn main() -> io::Result<()> { 35 | let mut terminal = tui::init()?; 36 | let mut app = App::new(Args::parse().name.clone()); 37 | let app_result = app.run(&mut terminal); 38 | tui::restore()?; 39 | app_result 40 | } 41 | 42 | impl App { 43 | fn new(name: String) -> Self { 44 | Self { 45 | exit: false, 46 | tick_count: 0, 47 | krab: krab::Krab::new(name), 48 | show_help_menu: false, 49 | show_save_timer: 0, 50 | } 51 | } 52 | 53 | pub fn run(&mut self, terminal: &mut tui::Tui) -> io::Result<()> { 54 | let mut last_tick = Instant::now(); 55 | let tick_rate = Duration::from_millis(100); 56 | self.load_save(); 57 | while !self.exit { 58 | terminal.draw(|frame| tui::render_frame(self, frame))?; 59 | let timeout = tick_rate.saturating_sub(last_tick.elapsed()); 60 | if event::poll(timeout).unwrap() { 61 | self.handle_events()?; 62 | } 63 | if last_tick.elapsed() >= tick_rate { 64 | last_tick = Instant::now(); 65 | self.on_tick()?; 66 | } 67 | } 68 | Ok(()) 69 | } 70 | 71 | fn on_tick(&mut self) -> io::Result<()> { 72 | self.tick_count += 1; 73 | if self.tick_count % 100 == 0 { 74 | self.krab.on_tick(); 75 | } 76 | if self.tick_count % 600 == 0 { 77 | self.save(true); 78 | } 79 | Ok(()) 80 | } 81 | 82 | fn handle_events(&mut self) -> io::Result<()> { 83 | match event::read()? { 84 | Event::Key(key_event) if key_event.kind == KeyEventKind::Press => { 85 | self.handle_key_event(key_event) 86 | } 87 | _ => {} 88 | }; 89 | Ok(()) 90 | } 91 | 92 | fn handle_key_event(&mut self, key_event: KeyEvent) { 93 | match key_event.code { 94 | KeyCode::Char('q') => self.exit(), 95 | KeyCode::Char('f') => self.krab.feed(), 96 | KeyCode::Char('p') => self.krab.pet(), 97 | KeyCode::Char('s') => self.save(true), 98 | KeyCode::Char('h') => self.toggle_help(), 99 | _ => {} 100 | } 101 | } 102 | 103 | fn toggle_help(&mut self) { 104 | self.show_help_menu = !self.show_help_menu; 105 | } 106 | 107 | fn exit(&mut self) { 108 | self.exit = true; 109 | self.save(false); 110 | } 111 | 112 | fn save(&mut self, show_save_alert: bool) { 113 | let save_krab = save_file("krabby-gotchi.save", 0, &self.krab); 114 | match save_krab { 115 | Ok(_) => {} 116 | Err(_) => { 117 | println!("Failed to save"); 118 | } 119 | } 120 | if show_save_alert { 121 | self.show_save_timer = 10; 122 | } 123 | } 124 | 125 | fn load_save(&mut self) { 126 | let loaded_krab = load_file::("krabby-gotchi.save", 0); 127 | match loaded_krab { 128 | Ok(_) => { 129 | self.krab = loaded_krab.unwrap(); 130 | } 131 | Err(_) => { 132 | let newkrab = krab::Krab::new(Args::parse().name.clone()); 133 | self.krab = newkrab; 134 | self.save(false); 135 | } 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/tui.rs: -------------------------------------------------------------------------------- 1 | use crossterm::{execute, terminal::*}; 2 | use ratatui::{ 3 | prelude::*, 4 | widgets::{block::*, *}, 5 | }; 6 | use std::io::{self, stdout, Stdout}; 7 | 8 | use crate::App; 9 | 10 | pub type Tui = Terminal>; 11 | 12 | pub fn init() -> io::Result { 13 | execute!(stdout(), EnterAlternateScreen)?; 14 | enable_raw_mode()?; 15 | Terminal::new(CrosstermBackend::new(stdout())) 16 | } 17 | pub fn restore() -> io::Result<()> { 18 | execute!(stdout(), LeaveAlternateScreen)?; 19 | disable_raw_mode()?; 20 | Ok(()) 21 | } 22 | pub fn render_frame(app: &mut App, frame: &mut Frame) { 23 | let vertical = Layout::vertical([Constraint::Percentage(50), Constraint::Percentage(50)]); 24 | let [krab, status] = vertical.areas(frame.size()); 25 | 26 | let status_chunks = Layout::default() 27 | .direction(Direction::Vertical) 28 | .constraints( 29 | [ 30 | Constraint::Percentage(10), 31 | Constraint::Percentage(23), 32 | Constraint::Percentage(23), 33 | Constraint::Percentage(23), 34 | Constraint::Percentage(10), 35 | Constraint::Percentage(10), 36 | ] 37 | .as_ref(), 38 | ) 39 | .split(status); 40 | 41 | frame.render_widget(krab_canvas(app, krab), krab); 42 | frame.render_widget(name_canvas(app), *status_chunks.get(0).unwrap()); 43 | frame.render_widget(hunger_canvas(app), *status_chunks.get(1).unwrap()); 44 | frame.render_widget(happiness_canvas(app), *status_chunks.get(2).unwrap()); 45 | frame.render_widget(health_canvas(app), *status_chunks.get(3).unwrap()); 46 | frame.render_widget(status_canvas(app), *status_chunks.get(4).unwrap()); 47 | frame.render_widget(stage_canvas(app), *status_chunks.get(5).unwrap()); 48 | 49 | let help_menu_center_rect: Rect = centered_rect(frame.size(), 30, 30); 50 | if app.show_help_menu { 51 | frame.render_widget( 52 | help_menu_canvas(help_menu_center_rect), 53 | help_menu_center_rect, 54 | ); 55 | } 56 | 57 | let save_alert_center_rect: Rect = centered_rect(frame.size(), 10, 10); 58 | if app.show_save_timer > 0 { 59 | frame.render_widget( 60 | save_alert_canvas(app, save_alert_center_rect), 61 | save_alert_center_rect, 62 | ); 63 | } 64 | } 65 | 66 | pub fn name_canvas(app: &mut App) -> impl Widget + '_ { 67 | let mut display_name: String = "Name: ".to_string(); 68 | display_name.push_str(app.krab.name()); 69 | Paragraph::new(display_name).block(Block::new()) 70 | } 71 | pub fn hunger_canvas(app: &mut App) -> impl Widget + '_ { 72 | Gauge::default() 73 | .block(Block::new().title("Hunger").borders(Borders::TOP)) 74 | .gauge_style(Style::default().fg(match_bar_color(app.krab.hunger()))) 75 | .percent((*app.krab.hunger() / 10) as u16) 76 | } 77 | pub fn happiness_canvas(app: &mut App) -> impl Widget + '_ { 78 | Gauge::default() 79 | .block(Block::new().title("Happiness")) 80 | .gauge_style(Style::default().fg(match_bar_color(app.krab.happiness()))) 81 | .percent((*app.krab.happiness() / 10) as u16) 82 | } 83 | pub fn health_canvas(app: &mut App) -> impl Widget + '_ { 84 | Gauge::default() 85 | .block(Block::new().title("Health").borders(Borders::BOTTOM)) 86 | .gauge_style(Style::default().fg(match_bar_color(app.krab.health()))) 87 | .percent((*app.krab.health() / 10) as u16) 88 | } 89 | pub fn status_canvas(app: &mut App) -> impl Widget + '_ { 90 | let mut display_mood: String = "Status: ".to_string(); 91 | display_mood.push_str(app.krab.status()); 92 | Paragraph::new(display_mood).block(Block::new()) 93 | } 94 | pub fn stage_canvas(app: &mut App) -> impl Widget + '_ { 95 | let mut display_mood: String = "Stage: ".to_string(); 96 | display_mood.push_str(app.krab.stage()); 97 | Paragraph::new(display_mood).block(Block::new()) 98 | } 99 | pub fn krab_canvas(app: &mut App, rect: Rect) -> impl Widget + '_ { 100 | Paragraph::new(app.krab.ascii().join("\n")) 101 | .block( 102 | Block::default() 103 | .borders(Borders::ALL) 104 | .padding(Padding::new(0, 0, rect.height / 4, 0)), 105 | ) 106 | .alignment(Alignment::Center) 107 | 108 | } 109 | 110 | pub fn help_menu_canvas(rect: Rect) -> impl Widget + 'static { 111 | let text = vec![ 112 | Line::from("Feed -> f"), 113 | Line::from("Pet -> p"), 114 | Line::from("Save -> s"), 115 | Line::from("Toggle Help -> h"), 116 | Line::from("Quit -> q"), 117 | ]; 118 | Paragraph::new(text) 119 | .block( 120 | Block::default() 121 | .borders(Borders::ALL) 122 | .title("Help Menu") 123 | .padding(Padding::new(0, 0, rect.height / 4, 0)), 124 | ) 125 | .alignment(Alignment::Center) 126 | } 127 | 128 | pub fn save_alert_canvas(app: &mut App, rect: Rect) -> impl Widget + 'static { 129 | if app.show_save_timer > 0 { 130 | app.show_save_timer -= 1; 131 | } 132 | Paragraph::new("saved!") 133 | .block(Block::default().borders(Borders::ALL).padding(Padding::new( 134 | 0, 135 | 0, 136 | rect.height / 3, 137 | 0, 138 | ))) 139 | .alignment(Alignment::Center) 140 | } 141 | 142 | fn match_bar_color(percent: &u16) -> Color { 143 | match percent { 144 | 0..=200 => Color::Red, 145 | 201..=500 => Color::Yellow, 146 | 501..=750 => Color::LightGreen, 147 | 751..=1000 => Color::Green, 148 | _ => Color::LightMagenta, 149 | } 150 | } 151 | 152 | 153 | fn centered_rect(r: Rect, percent_x: u16, percent_y: u16) -> Rect { 154 | let popup_layout = Layout::default() 155 | .direction(Direction::Vertical) 156 | .constraints([ 157 | Constraint::Percentage((100 - percent_y) / 2), 158 | Constraint::Percentage(percent_y), 159 | Constraint::Percentage((100 - percent_y) / 2), 160 | ]) 161 | .split(r); 162 | Layout::default() 163 | .direction(Direction::Horizontal) 164 | .constraints([ 165 | Constraint::Percentage((100 - percent_x) / 2), 166 | Constraint::Percentage(percent_x), 167 | Constraint::Percentage((100 - percent_x) / 2), 168 | ]) 169 | .split(popup_layout[1])[1] 170 | } 171 | --------------------------------------------------------------------------------