Compare commits

..
Author SHA1 Message Date
admin c541085956 Preserve Unity 6000.4 generated iOS outputs 2026-06-22 09:10:40 -07:00
admin c97c141155 Revert "Upgrade Unity client to 6000.5.0f1 (#7325)"
This reverts commit 6a98cd8d6d.
2026-06-22 08:34:01 -07:00
adminandGitHub 72ea2de25c Version Addressables by Unity editor (#7731) 2026-06-22 08:33:15 -07:00
adminandGitHub 4b559c2278 Report validated command lookup failures explicitly (#7720) 2026-06-22 07:38:14 -07:00
adminandGitHub 327ecf1aed Qualify std algorithms in hex map utils (#7721) 2026-06-22 07:37:26 -07:00
adminandGitHub 8fc893ce08 Qualify iterators in game state guesser (#7719) 2026-06-22 07:36:38 -07:00
adminandGitHub 0ec0e10c0f Remove stale iterator aliases from APD (#7718) 2026-06-22 07:34:02 -07:00
adminandGitHub 38c7a01743 Qualify std types in fixed APD test (#7717) 2026-06-22 07:33:50 -07:00
adminandGitHub a481b5ce60 Report recruit heroes ruling hero explicitly (#7716) 2026-06-22 07:32:35 -07:00
adminandGitHub 7786db1040 Qualify std types in Shardok games manager (#7715) 2026-06-22 07:30:48 -07:00
adminandGitHub 200aa0d319 Report exile vassal lookup failures explicitly (#7714) 2026-06-22 07:30:27 -07:00
adminandGitHub c8bb543907 Remove stale std aliases from AI headers (#7713) 2026-06-22 07:30:08 -07:00
adminandGitHub de7ecf45d1 Avoid repeated eligible gift get (#7712) 2026-06-22 07:27:18 -07:00
adminandGitHub f25298ed9e Report command factory lookup failures explicitly (#7711) 2026-06-22 07:27:01 -07:00
adminandGitHub d4ea2fbd93 Report arm troops lookup failures explicitly (#7710) 2026-06-22 07:24:24 -07:00
adminandGitHub 79c51fb21a Qualify STL containers in game state helpers (#7709) 2026-06-22 07:23:48 -07:00
adminandGitHub c57c9b5f18 Qualify std helpers in Shardok production code (#7708) 2026-06-22 07:20:09 -07:00
adminandGitHub 823cd73d33 Report missing hero descriptions explicitly (#7707) 2026-06-22 07:19:50 -07:00
adminandGitHub 54db4b6e34 Report missing suppress beasts effect text (#7706) 2026-06-22 07:18:56 -07:00
adminandGitHub 112399d67c Qualify smart pointer helpers in Shardok tests (#7705) 2026-06-22 07:18:42 -07:00
adminandGitHub 01b80d8798 Report missing province ruling faction explicitly (#7704) 2026-06-22 07:18:14 -07:00
adminandGitHub f6a3f36a13 Remove unused vector aliases in Shardok tests (#7703) 2026-06-22 07:18:01 -07:00
adminandGitHub d674e23987 Report missing common unit faction explicitly (#7702) 2026-06-22 07:17:46 -07:00
adminandGitHub 51aebf5e40 Qualify std vector in Shardok tests (#7701) 2026-06-22 07:15:59 -07:00
adminandGitHub 2ec6d2f1d7 Report missing seek-more-leaders faction explicitly (#7700) 2026-06-22 07:15:23 -07:00
adminandGitHub 9f94917a2d Report required lookup failures explicitly (#7687) 2026-06-22 07:08:10 -07:00
adminandGitHub 06f2104750 Report new game lookup failures explicitly (#7688) 2026-06-22 07:07:53 -07:00
adminandGitHub b1e1e36236 Report empty in-memory history explicitly (#7690) 2026-06-22 07:06:02 -07:00
adminandGitHub 9eb2056ac6 Report map load failures with context (#7691) 2026-06-22 07:05:40 -07:00
adminandGitHub 0c3cb22e83 Report unknown hex terrain types explicitly (#7692) 2026-06-22 07:05:24 -07:00
adminandGitHub 92f27ba273 Report missing faction utility lookups explicitly (#7693) 2026-06-22 07:05:04 -07:00
adminandGitHub 47d682e7c1 Report unaffiliated phase lookup failures explicitly (#7694) 2026-06-22 07:04:23 -07:00
adminandGitHub 75d84b67ff Report missing action ruling factions explicitly (#7695) 2026-06-22 07:03:52 -07:00
adminandGitHub be8f5ca5da Report missing beast fallback explicitly (#7696) 2026-06-22 07:03:24 -07:00
adminandGitHub c7910a6183 Report missing withdrawing flee province explicitly (#7697) 2026-06-22 07:03:08 -07:00
renovate[bot]andGitHub 98afc28762 Update alpine_linux:3.24 Docker digest to 28bd5fe (#7698) 2026-06-22 06:17:57 -07:00
adminandGitHub 4cd1349a5a Fix AI victory score test std types (#7699) 2026-06-22 05:44:05 -07:00
adminandGitHub cebac64264 Avoid unsafe diplomacy hero fallback head (#7668) 2026-06-21 21:48:23 -07:00
adminandGitHub 172125e03b Avoid unsafe AI game arg head (#7667) 2026-06-21 21:48:09 -07:00
adminandGitHub 15006091b4 Report missing AI commands explicitly (#7670) 2026-06-21 21:46:19 -07:00
adminandGitHub 2175f1d957 Report missing diplomacy offers explicitly (#7671) 2026-06-21 21:45:56 -07:00
adminandGitHub d445cbfe25 Avoid unsafe ruling hero head (#7673) 2026-06-21 21:44:07 -07:00
adminandGitHub 5fc56c342d Avoid unsafe shuffle tail heads (#7674) 2026-06-21 21:43:53 -07:00
adminandGitHub e5350d03a8 Report missing recon targets explicitly (#7676) 2026-06-21 21:43:40 -07:00
adminandGitHub 097daf3dc1 Report missing province ruling heroes explicitly (#7678) 2026-06-21 21:43:25 -07:00
adminandGitHub 3c3dc85187 Avoid standard aliases in command factory headers (#7675)
* Avoid standard aliases in command factory headers

* Fix available commands std type qualification
2026-06-21 21:42:47 -07:00
adminandGitHub a775a667f6 Remove unused vector alias from unit filter (#7677) 2026-06-21 21:41:27 -07:00
adminandGitHub a1a7a69aeb Remove unused vector alias from game settings (#7679) 2026-06-21 21:41:08 -07:00
adminandGitHub ff549ab337 Qualify shared pointers in cache and settings headers (#7686)
* Qualify shared pointers in cache and settings headers

* Fix map info test shared pointer spelling
2026-06-21 21:40:51 -07:00
adminandGitHub 464651503e Avoid vector aliases in utility headers (#7672) 2026-06-21 21:36:38 -07:00
adminandGitHub 2f93250c8e Avoid vector aliases in AI headers (#7669) 2026-06-21 21:36:14 -07:00
adminandGitHub 22ce7ba750 Report missing tutorial ruling heroes explicitly (#7680) 2026-06-21 21:35:54 -07:00
adminandGitHub acbb09f6a1 Qualify vector usage in action point distances (#7681) 2026-06-21 21:35:40 -07:00
adminandGitHub 900dd23ae7 Use explicit backstory text id accessors (#7683) 2026-06-21 21:35:14 -07:00
adminandGitHub 0f391776aa Qualify vector usage in duel utilities (#7682) 2026-06-21 21:34:42 -07:00
adminandGitHub 817fb613ab Clean up library implementation std aliases (#7684) 2026-06-21 21:34:16 -07:00
adminandGitHub 2f57ea0160 Qualify std types in available commands header (#7685) 2026-06-21 21:33:59 -07:00
adminandGitHub f5d5aedf9d Avoid std aliases in map loader header (#7647) 2026-06-21 19:56:47 -07:00
adminandGitHub c5114e9bf1 Avoid unsafe OpenAI choice head (#7648) 2026-06-21 19:56:35 -07:00
adminandGitHub 7514aed437 Remove unused vector alias from unit filter header (#7649) 2026-06-21 19:56:19 -07:00
adminandGitHub f4d381c9d4 Report missing headshot output path (#7650) 2026-06-21 19:56:09 -07:00
adminandGitHub 8698036f7c Avoid unsafe migration version lookup (#7651) 2026-06-21 19:55:51 -07:00
adminandGitHub 21f04cfd46 Avoid string alias in shardok exception header (#7652) 2026-06-21 19:55:30 -07:00
adminandGitHub 074cf62cc9 Avoid unsafe recruit province head (#7653) 2026-06-21 19:52:34 -07:00
adminandGitHub a66f833c90 Avoid unsafe aftermath auto-resolve head (#7654) 2026-06-21 19:51:53 -07:00
adminandGitHub d704d23d39 Avoid unsafe aftermath hostile error head (#7655) 2026-06-21 19:48:34 -07:00
adminandGitHub e2570aec4a Use explicit vectors in implementation files (#7656) 2026-06-21 19:48:06 -07:00
adminandGitHub 6b97fde9ab Report missing tutorial battle explicitly (#7657) 2026-06-21 19:47:50 -07:00
adminandGitHub 30adf1bcbf Avoid vector aliases in APD headers (#7658) 2026-06-21 19:46:25 -07:00
adminandGitHub f205b49a54 Avoid string alias in action result helper header (#7659) 2026-06-21 19:46:06 -07:00
adminandGitHub 5c7e18696e Avoid unsafe quest chooser hero heads (#7660) 2026-06-21 19:45:50 -07:00
adminandGitHub c78b00b0fc Avoid vector alias in coords set header (#7661) 2026-06-21 19:45:19 -07:00
adminandGitHub b05d6e1e1b Avoid unsafe recon candidate head (#7662) 2026-06-21 19:45:05 -07:00
adminandGitHub da0bce655c Avoid standard aliases in shardok action headers (#7663) 2026-06-21 19:44:41 -07:00
adminandGitHub d4dcbcc9d5 Report missing uncontested conqueror explicitly (#7664) 2026-06-21 19:44:26 -07:00
adminandGitHub f132e5b87b Remove unused string alias from hero header (#7665) 2026-06-21 19:42:05 -07:00
adminandGitHub 872475e82b Avoid map alias in unit header (#7666) 2026-06-21 19:41:48 -07:00
adminandGitHub 66d062bfda Avoid unsafe pregenerated hero head (#7631) 2026-06-21 15:55:51 -07:00
adminandGitHub a514ceb62f Cache repeated loop bounds (#7632) 2026-06-21 15:55:38 -07:00
adminandGitHub b0d8a5bc41 Avoid unsafe province distance frontier lookup (#7633) 2026-06-21 15:55:19 -07:00
adminandGitHub 8f4bb5130e Avoid namespace import in map info implementation (#7634) 2026-06-21 15:55:03 -07:00
adminandGitHub 9386589558 Avoid unsafe attack decision unit head (#7638) 2026-06-21 15:54:47 -07:00
adminandGitHub 5945289a81 Use explicit std types in map loader (#7639) 2026-06-21 15:54:31 -07:00
adminandGitHub 53346cc85b Use explicit std types in game over response populator (#7640) 2026-06-21 15:26:45 -07:00
adminandGitHub a6fad3ac4e Use explicit string type in shardok controller (#7641) 2026-06-21 15:26:32 -07:00
adminandGitHub cb7e2b5d5c Use explicit std types in shardok server main (#7642) 2026-06-21 15:26:15 -07:00
adminandGitHub 0f764416a3 Avoid namespace import in AI performance runner (#7643) 2026-06-21 15:25:56 -07:00
adminandGitHub c9e0012bf7 Avoid namespace import in random battle runner (#7644) 2026-06-21 15:25:37 -07:00
adminandGitHub 457f2a677a Avoid vector alias in game update receiver header (#7645) 2026-06-21 15:25:10 -07:00
adminandGitHub ced56ee41f Avoid string alias in server configuration header (#7646) 2026-06-21 15:24:56 -07:00
adminandGitHub 4e910f1f22 Report missing migration save files explicitly (#7637) 2026-06-21 15:16:53 -07:00
adminandGitHub 34bceebace Remove unused registrar header string import (#7636) 2026-06-21 15:16:34 -07:00
adminandGitHub b4f802ba77 Avoid unsafe LLM update group bounds (#7635) 2026-06-21 15:16:15 -07:00
adminandGitHub 3d9d464870 Avoid unsafe battle aftermath claimant head (#7630) 2026-06-21 15:04:00 -07:00
adminandGitHub a7e21427f9 Avoid namespace imports in map info header (#7627) 2026-06-21 15:03:43 -07:00
adminandGitHub bdbf10294b Avoid namespace import in map info runner (#7629) 2026-06-21 15:02:57 -07:00
adminandGitHub 8588430cf0 Avoid unsafe TSV header lookup (#7628) 2026-06-21 15:01:15 -07:00
adminandGitHub d920bb5c17 Report utility TSV load failures explicitly (#7626) 2026-06-21 14:59:01 -07:00
adminandGitHub 64fe9bf59d Cache map starting position count in tests (#7625) 2026-06-21 14:58:23 -07:00
adminandGitHub 101b0bf41f Cache hex map terrain count (#7624) 2026-06-21 14:54:31 -07:00
adminandGitHub 019865b5ee Reserve converted victory conditions (#7623) 2026-06-21 14:54:16 -07:00
adminandGitHub 799d34a1f1 Avoid unsafe Gemini response heads (#7622) 2026-06-21 14:54:03 -07:00
adminandGitHub 951d533ed3 Avoid unsafe rate limit header heads (#7619) 2026-06-21 14:53:49 -07:00
adminandGitHub 459eb0ef7b Cache Eagle interface player counts (#7621) 2026-06-21 14:53:15 -07:00
adminandGitHub f710105bd9 Cache action result repeated field counts (#7620) 2026-06-21 14:53:01 -07:00
adminandGitHub 4998e3ce40 Cache changed unit counts in gtest helpers (#7618) 2026-06-21 14:48:32 -07:00
adminandGitHub d739b374a4 Cache AI battle protobuf unit counts (#7617) 2026-06-21 14:48:15 -07:00
adminandGitHub bd61ebcbb6 Use flatbuffer-sized production knowledge indices (#7616) 2026-06-21 14:47:53 -07:00
adminandGitHub 3963275092 Report hero backstory load failures explicitly (#7569) 2026-06-21 14:40:52 -07:00
adminandGitHub a796e0fe67 Avoid unsafe battle request error message lookup (#7583) 2026-06-21 14:40:35 -07:00
adminandGitHub 52ac61fa1d Qualify flatbuffer wrapper abort calls (#7606) 2026-06-21 14:40:13 -07:00
adminandGitHub 29ca7665b1 Use size_t for AI integration unit loops (#7607) 2026-06-21 14:39:25 -07:00
adminandGitHub d9bdb814f4 Use size_t for MCTS reserve unit loops (#7608) 2026-06-21 14:39:09 -07:00
adminandGitHub 3dfb094a08 Use size_t for optimized score test unit loops (#7609) 2026-06-21 14:38:51 -07:00
adminandGitHub 7ce1818a7f Use flatbuffer-sized unit knowledge indices (#7610) 2026-06-21 14:37:45 -07:00
adminandGitHub 6e6eff7991 Use flatbuffer-sized retreat factory knowledge index (#7615) 2026-06-21 14:37:04 -07:00
adminandGitHub aa9c98f081 Use flatbuffer-sized game start knowledge indices (#7611) 2026-06-21 14:36:00 -07:00
adminandGitHub cdf0ad45f0 Use flatbuffer-sized move test knowledge index (#7612) 2026-06-21 14:35:14 -07:00
adminandGitHub 1b97b6673f Use flatbuffer-sized melee test knowledge index (#7613) 2026-06-21 14:34:10 -07:00
adminandGitHub 721d432bc6 Use flatbuffer-sized flee factory knowledge index (#7614) 2026-06-21 14:33:01 -07:00
adminandGitHub e513a784eb Report missing start game heroes explicitly (#7571) 2026-06-21 14:30:42 -07:00
adminandGitHub ff8da78992 Report missing tutorial battle players explicitly (#7577) 2026-06-21 14:30:11 -07:00
adminandGitHub 84a69ce982 Match prisoner leader faction options (#7572) 2026-06-21 14:28:27 -07:00
adminandGitHub 7d743f8678 Report missing proto converter fields explicitly (#7575) 2026-06-21 14:28:13 -07:00
adminandGitHub 3f24e15392 Bind custom battle human updates explicitly (#7578) 2026-06-21 14:27:49 -07:00
adminandGitHub 0f86bb6874 Match engine command lookup explicitly (#7580) 2026-06-21 14:27:29 -07:00
adminandGitHub 05ee7a2ab2 Report unruled defend flee provinces explicitly (#7582) 2026-06-21 14:25:46 -07:00
adminandGitHub b9321433d0 Report fixed hero load failures explicitly (#7567) 2026-06-21 14:24:29 -07:00
adminandGitHub 62791401e9 Use streams for raise dead setup output (#7581) 2026-06-21 14:18:59 -07:00
adminandGitHub 4d28bba9cc Use streams for MCTS decision investigation output (#7579) 2026-06-21 14:18:42 -07:00
adminandGitHub 1f3660e1f3 Use streams for reserve combat phase output (#7576) 2026-06-21 14:18:24 -07:00
adminandGitHub 95ff44e205 Use streams for reserve setup diagnostics (#7574) 2026-06-21 14:18:08 -07:00
adminandGitHub 987a164092 Report missing hostile army neighbor explicitly (#7584) 2026-06-21 14:17:51 -07:00
adminandGitHub 1b5b11fd5b Match pending aftermath info explicitly (#7586) 2026-06-21 14:17:35 -07:00
adminandGitHub ddcde52e27 Bind validated command options explicitly (#7587) 2026-06-21 14:12:54 -07:00
adminandGitHub ea2da84535 Report missing declined quest hero explicitly (#7589) 2026-06-21 14:12:04 -07:00
adminandGitHub abed8ee574 Bind control weather option explicitly (#7590) 2026-06-21 14:09:50 -07:00
adminandGitHub 556c59a9c7 Report S3 credential load failures explicitly (#7566) 2026-06-21 14:09:39 -07:00
adminandGitHub ad2d085b24 Stabilize sqlite history upload snapshot test (#7605) 2026-06-21 14:08:50 -07:00
adminandGitHub d7209102b8 Report missing battalion types explicitly (#7592) 2026-06-21 13:25:39 -07:00
adminandGitHub 14e1ba6795 Avoid unwrapping province distances (#7594) 2026-06-21 13:25:25 -07:00
adminandGitHub 65b56081ce Report beast info load failures explicitly (#7595) 2026-06-21 13:25:00 -07:00
adminandGitHub eafb51cbfa Report name generator load failures explicitly (#7564) 2026-06-21 13:24:37 -07:00
adminandGitHub 3444ae296e Report missing ransom offer prisoner explicitly (#7597) 2026-06-21 13:24:23 -07:00
adminandGitHub 4f2fff5da6 Use streams for MCTS start fire test output (#7565) 2026-06-21 13:23:50 -07:00
adminandGitHub 144483a45d Use streams for start fire cost explanation (#7573) 2026-06-21 13:21:53 -07:00
adminandGitHub 53345b2bb0 Use streams for MCTS rain fire output (#7568) 2026-06-21 13:17:20 -07:00
adminandGitHub 5d6bc429b0 Use streams for start fire cost summary (#7570) 2026-06-21 13:17:00 -07:00
adminandGitHub a4faf61613 Report missing divine acting province explicitly (#7599) 2026-06-21 13:16:41 -07:00
adminandGitHub fdd516598d Report missing apprehended outlaw explicitly (#7601) 2026-06-21 13:16:29 -07:00
adminandGitHub 70da6990c4 Match optional date protos explicitly (#7602) 2026-06-21 13:13:12 -07:00
adminandGitHub e8b18d0805 Use streams for raise dead filter output (#7585) 2026-06-21 13:12:03 -07:00
adminandGitHub 1ca9e8678c Use streams for MCTS investigation intro output (#7588) 2026-06-21 13:11:29 -07:00
adminandGitHub 94670149fe Use streams for MCTS end-turn score output (#7591) 2026-06-21 13:11:14 -07:00
adminandGitHub 8e253c2972 Use streams for MCTS start-fire failure output (#7596) 2026-06-21 13:11:00 -07:00
adminandGitHub 6e15c6d9cb Use streams for MCTS start-fire success output (#7593) 2026-06-21 13:10:21 -07:00
adminandGitHub ca00e90ad6 Use streams for AI command mismatch diagnostics (#7600) 2026-06-21 13:10:07 -07:00
adminandGitHub b1d76ea661 Use streams for MCTS path comparison output (#7598) 2026-06-21 13:09:52 -07:00
adminandGitHub 059d428cfa Make Shardok player id conversions explicit (#7603) 2026-06-21 13:08:19 -07:00
adminandGitHub a4b50eb357 Tighten map info index handling (#7604) 2026-06-21 13:07:43 -07:00
adminandGitHub 0dfd5aa11d Use streams for critical fire score output (#7563) 2026-06-21 10:32:50 -07:00
adminandGitHub 2b63ccd145 Report name format parse failures explicitly (#7562) 2026-06-21 10:32:38 -07:00
adminandGitHub 97cec5ec38 Add Shardok Linux ARM64 PR build (#7561) 2026-06-21 10:29:17 -07:00
adminandGitHub 31fb5a3616 Avoid partial battalion access in riot command errors (#7560) 2026-06-21 10:27:28 -07:00
adminandGitHub 7b7130d67d Use resource handling for Shardok map info (#7552) 2026-06-21 10:25:49 -07:00
adminandGitHub 6707ad55ff Report missing beasts event explicitly (#7559) 2026-06-21 10:25:37 -07:00
adminandGitHub 89aa73b63a Use resource handling for image paths (#7554) 2026-06-21 10:25:21 -07:00
adminandGitHub bb7453a002 Avoid partial Option access in HeroNameCache (#7555) 2026-06-21 10:25:09 -07:00
adminandGitHub 8cea29dcb0 Avoid partial command access in early AI (#7556) 2026-06-21 10:24:55 -07:00
adminandGitHub d5d74ec8d6 Avoid partial command access in mid-game AI (#7557) 2026-06-21 10:24:32 -07:00
adminandGitHub 9b000b94ac Report missing Shardok map info explicitly (#7558) 2026-06-21 10:24:13 -07:00
adminandGitHub 82ed9fcc83 Include array in CombatDamage (#7553) 2026-06-21 10:23:51 -07:00
adminandGitHub cd53283935 Use resource handling for LLM usage loads (#7551) 2026-06-21 10:17:08 -07:00
adminandGitHub 3faddf76f8 Use resource handling in JsonUtils (#7550) 2026-06-21 10:15:43 -07:00
adminandGitHub 6e24ae2f4f Use streams for MCTS archery debug output (#7538) 2026-06-21 10:10:27 -07:00
adminandGitHub 66912580c8 Use streams in C++ debug headers (#7540) 2026-06-21 10:10:13 -07:00
adminandGitHub 219dd830e1 Use streams for MCTS score sequence output (#7541) 2026-06-21 10:09:51 -07:00
adminandGitHub 3d5cdcc78e Use streams for combat damage strings (#7542) 2026-06-21 10:09:32 -07:00
adminandGitHub ab1d43fae3 Use streams for MCTS minimax debug output (#7543) 2026-06-21 10:09:19 -07:00
adminandGitHub 2d51f3c23d Use resource handling for name format reads (#7548) 2026-06-21 10:09:03 -07:00
adminandGitHub f9447cf7aa Use resource handling for map info migration (#7549) 2026-06-21 10:08:42 -07:00
adminandGitHub c6ed0bfc7d Use streams for AI choice diagnostics (#7534) 2026-06-21 10:06:57 -07:00
adminandGitHub 2d4621b1a6 Use pattern matching for parser literals (#7547) 2026-06-21 10:05:48 -07:00
adminandGitHub 3bf929b4a5 Use streams for MCTS fire score analysis (#7544) 2026-06-21 10:02:45 -07:00
adminandGitHub ebed01ba86 Use streams for abstract MCTS diagnostics (#7545) 2026-06-21 10:02:29 -07:00
adminandGitHub 880d005347 Use streams for Alah fire score analysis (#7546) 2026-06-21 10:02:12 -07:00
adminandGitHub e8ef216de8 Use streams for common C++ diagnostics (#7539) 2026-06-21 10:01:47 -07:00
adminandGitHub baa453594a Delete old dropped games automatically (#7535) 2026-06-21 09:46:01 -07:00
adminandGitHub 9c767d5c49 Use streams for MCTS score placement diagnostics (#7537) 2026-06-21 09:45:15 -07:00
adminandGitHub e0892bd2fa Use streams for MCTS setup diagnostics (#7536) 2026-06-21 09:44:55 -07:00
adminandGitHub 315be7c465 Use streams for ID AI performance logs (#7533) 2026-06-21 09:42:33 -07:00
adminandGitHub 9d34dc0954 Use streams for AI debug dump messages (#7532) 2026-06-21 09:42:14 -07:00
adminandGitHub bdedd43e3c Use streams for score timing diagnostic (#7531) 2026-06-21 09:42:02 -07:00
adminandGitHub 97e779675e Use streams in gtest contains diagnostics (#7528) 2026-06-21 09:41:43 -07:00
adminandGitHub 2ef4216886 Use cerr for flatbuffer allocator failures (#7530) 2026-06-21 09:41:28 -07:00
adminandGitHub 8c9764a57e Use cerr for APD thread diagnostic (#7529) 2026-06-21 09:41:09 -07:00
adminandGitHub eb94eb1a6d Use streams in available commands test diagnostics (#7527) 2026-06-21 09:40:53 -07:00
adminandGitHub 12e3fb99eb Keep dropped games in existing storage (#7525) 2026-06-21 09:32:34 -07:00
adminandGitHub 2bd90a26a8 Remove client text getTexts returns (#7526) 2026-06-21 09:32:04 -07:00
adminandGitHub 24db3a4cb1 Use streams for AI command count logging (#7524) 2026-06-21 09:31:02 -07:00
adminandGitHub 0d05ea1730 Use streams for iterative deepening diagnostics (#7523) 2026-06-21 09:30:45 -07:00
adminandGitHub 9c13b3c1bf Use streams for AI flee debug output (#7522) 2026-06-21 09:27:34 -07:00
adminandGitHub 492d9d16eb Remove StringConstructionParser returns (#7507) 2026-06-21 09:20:30 -07:00
adminandGitHub c4cd0eb683 Remove broken action point distance timer (#7509) 2026-06-21 09:15:53 -07:00
adminandGitHub 287f7b9818 Fix random battle runner build (#7521) 2026-06-21 09:15:35 -07:00
adminandGitHub 15b5a3e0c1 Remove SQLite client text guard returns (#7505) 2026-06-21 09:15:15 -07:00
adminandGitHub cf93c43ef2 Remove AI time budget debug print (#7506) 2026-06-21 09:14:55 -07:00
adminandGitHub 380c24537b Remove stale undead morale diagnostic (#7508) 2026-06-21 09:12:31 -07:00
adminandGitHub 6200bc7e02 Remove SqliteHistory flush return (#7510) 2026-06-21 09:12:05 -07:00
adminandGitHub e92465c894 Use explicit chrono imports in distance test (#7511) 2026-06-21 09:11:52 -07:00
adminandGitHub 6f432d221a Remove GameController debug return (#7512) 2026-06-21 09:11:28 -07:00
adminandGitHub b8ddca4e76 Route action point cache stats through streams (#7513) 2026-06-21 09:11:12 -07:00
adminandGitHub f343ee9f7f Send battalion type parse errors to stderr (#7514) 2026-06-21 09:10:53 -07:00
adminandGitHub 9a8c4c6fdd Remove GameController post battle return (#7515) 2026-06-21 09:10:38 -07:00
adminandGitHub 96f2dc0454 Send hex map migrator errors to stderr (#7516) 2026-06-21 09:10:21 -07:00
adminandGitHub e0988ef186 Remove GamesManager cache invalidation returns (#7517) 2026-06-21 09:07:20 -07:00
adminandGitHub a154174fa1 Remove broken Shardok inspector target (#7496) 2026-06-21 09:05:50 -07:00
adminandGitHub 042861f065 Remove GamesManager S3 archive return (#7520) 2026-06-21 09:04:54 -07:00
adminandGitHub 0f776af050 Remove GamesManager flush marker returns (#7518) 2026-06-21 09:04:18 -07:00
adminandGitHub 166e50924f Remove GamesManager LLM response return (#7519) 2026-06-21 09:04:00 -07:00
adminandGitHub efb34ede56 Remove Postgres client text guard returns (#7504) 2026-06-21 09:02:56 -07:00
adminandGitHub 22b55eb223 Allow routing transposition table stats output (#7503) 2026-06-21 08:41:33 -07:00
adminandGitHub f5d9027206 Allow routing MCTS cache stats output (#7502) 2026-06-21 08:39:52 -07:00
adminandGitHub 9dcbeff21a Avoid endl flushes in AI integration tests (#7501) 2026-06-21 08:39:29 -07:00
adminandGitHub 0cc7c4d0a2 Remove SQLite download recovery return (#7500) 2026-06-21 08:36:29 -07:00
adminandGitHub b0ca65b720 Use unique_ptr in attacker strategy selector test (#7499) 2026-06-21 08:36:09 -07:00
adminandGitHub e3eb3eb7bf Own nonstandard hex map adjacency cache entries (#7498) 2026-06-21 08:34:22 -07:00
adminandGitHub b8b2c92227 Remove SQLite legacy guard returns (#7497) 2026-06-21 08:33:33 -07:00
adminandGitHub 424dde5da6 Remove SQLite migration pending return (#7495) 2026-06-21 08:33:00 -07:00
adminandGitHub ce7e636987 Remove SQLite replay empty range return (#7494) 2026-06-21 08:31:12 -07:00
adminandGitHub c51f61ba56 Remove expand command selector return (#7492) 2026-06-21 08:28:42 -07:00
adminandGitHub 91623bcf7a Remove broken corrupt game checker (#7491) 2026-06-21 08:28:14 -07:00
adminandGitHub 34e14a3521 Check hex map migrator parse results (#7490) 2026-06-21 08:27:52 -07:00
adminandGitHub 6c1a79b342 Remove GameController AI guard returns (#7489) 2026-06-21 08:27:25 -07:00
adminandGitHub 6af5014866 Remove OAuth handler early returns (#7488) 2026-06-21 08:26:59 -07:00
adminandGitHub 16f53dc1b1 Use make_shared for battalion types (#7487) 2026-06-21 08:26:40 -07:00
adminandGitHub df09fe0684 Remove authorization interceptor early returns (#7486) 2026-06-21 08:26:09 -07:00
adminandGitHub e765764cea Remove SQLite shardok row early returns (#7485) 2026-06-21 08:25:13 -07:00
266 changed files with 4604 additions and 3276 deletions
+3 -1
View File
@@ -177,10 +177,12 @@ jobs:
env:
DO_CDN_PAT: ${{ secrets.DO_CDN_PAT }}
run: |
UNITY_VERSION=$(grep "m_EditorVersion:" src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt | head -1 | sed 's/m_EditorVersion: //')
UNITY_MAJOR_MINOR=$(echo "$UNITY_VERSION" | sed -E 's/^([0-9]+)\.([0-9]+).*/\1.\2/')
curl -s -X DELETE "https://api.digitalocean.com/v2/cdn/endpoints/8c98df29-6f0c-4704-8e82-ca40a2b81aa8/cache" \
-H "Authorization: Bearer $DO_CDN_PAT" \
-H "Content-Type: application/json" \
-d '{"files": ["addressables/iOS/*"]}' \
-d "{\"files\": [\"addressables/iOS/$UNITY_MAJOR_MINOR/*\"]}" \
--fail || echo "Warning: CDN purge failed (non-fatal)"
- name: Archive Build Log
+7 -25
View File
@@ -50,11 +50,9 @@ on:
- "scripts/notarize_wait.sh"
- "ci/github_actions/build_mac.sh"
- "ci/github_actions/build_unity_mac.sh"
- "ci/github_actions/ensure_unity_installed.sh"
- "ci/github_actions/ensure_bazel_installed.sh"
- ".github/actions/setup-bazel/**"
- "ci/github_actions/detect_addressables_changes.sh"
- "src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt"
- "src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectSettings.asset"
- ".bazelrc"
- "ci/mac/**"
@@ -125,25 +123,11 @@ jobs:
- name: Clean stale files
run: |
git clean -ffd
LIBRARY_DIR="src/main/csharp/net/eagle0/clients/unity/eagle0/Library"
VERSION_CACHE="$LIBRARY_DIR/.last_unity_version"
PROJECT_VERSION_FILE="src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt"
CURRENT_VERSION=$(grep "m_EditorVersion:" "$PROJECT_VERSION_FILE" | head -1 | sed 's/m_EditorVersion: //')
# Nuke Library/ when Unity version changes to avoid import loops
if [ -f "$VERSION_CACHE" ]; then
CACHED_VERSION=$(cat "$VERSION_CACHE")
if [ "$CACHED_VERSION" != "$CURRENT_VERSION" ]; then
echo "Unity version changed ($CACHED_VERSION -> $CURRENT_VERSION) -- clearing Library/"
rm -rf "$LIBRARY_DIR"
fi
fi
# Only clear Bee/ when C# files were added/deleted/renamed (structural
# changes that stale the DAG). Content-only modifications are handled by
# Bee's incremental compilation. See persist_library.sh for background.
BEE_DIR="$LIBRARY_DIR/Bee"
SHA_FILE="$LIBRARY_DIR/.last_built_sha"
BEE_DIR="src/main/csharp/net/eagle0/clients/unity/eagle0/Library/Bee"
SHA_FILE="src/main/csharp/net/eagle0/clients/unity/eagle0/Library/.last_built_sha"
if [ -f "$SHA_FILE" ] && [ -d "$BEE_DIR" ]; then
LAST_SHA=$(cat "$SHA_FILE")
if git diff --diff-filter=ADR --name-only "$LAST_SHA" HEAD -- '*.cs' '*.csproj' '*.asmdef' 2>/dev/null | grep -q .; then
@@ -200,12 +184,6 @@ jobs:
mkdir -p src/main/csharp/net/eagle0/clients/unity/eagle0/Library
git rev-parse HEAD > src/main/csharp/net/eagle0/clients/unity/eagle0/Library/.last_built_sha
- name: Save Unity version for Library/ cache invalidation
if: success()
run: |
mkdir -p src/main/csharp/net/eagle0/clients/unity/eagle0/Library
grep "m_EditorVersion:" src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt | head -1 | sed 's/m_EditorVersion: //' > src/main/csharp/net/eagle0/clients/unity/eagle0/Library/.last_unity_version
- name: Check if should deploy
id: check-deploy
run: |
@@ -267,6 +245,7 @@ jobs:
runs-on: [self-hosted, macOS, notarize]
outputs:
deployed_version: ${{ steps.deploy-mac.outputs.deployed_version }}
deployed_unity_major_minor: ${{ steps.deploy-mac.outputs.deployed_unity_major_minor }}
concurrency:
group: mac-deploy-${{ github.ref }}
cancel-in-progress: false
@@ -495,6 +474,9 @@ jobs:
rm "$SPARKLE_PRIVATE_KEY_PATH"
echo "deployed_version=$VERSION" >> $GITHUB_OUTPUT
UNITY_VERSION=$(grep "m_EditorVersion:" src/main/csharp/net/eagle0/clients/unity/eagle0/ProjectSettings/ProjectVersion.txt | head -1 | sed 's/m_EditorVersion: //')
UNITY_MAJOR_MINOR=$(echo "$UNITY_VERSION" | sed -E 's/^([0-9]+)\.([0-9]+).*/\1.\2/')
echo "deployed_unity_major_minor=$UNITY_MAJOR_MINOR" >> $GITHUB_OUTPUT
# Artifact cleanup is handled by the cleanup job on ubuntu-latest
- name: Cleanup build directory
@@ -515,7 +497,7 @@ jobs:
curl -s -X DELETE "https://api.digitalocean.com/v2/cdn/endpoints/8c98df29-6f0c-4704-8e82-ca40a2b81aa8/cache" \
-H "Authorization: Bearer $DO_CDN_PAT" \
-H "Content-Type: application/json" \
-d '{"files": ["mac/*", "addressables/StandaloneOSX/*"]}' \
-d '{"files": ["mac/*", "addressables/StandaloneOSX/${{ needs.deploy-mac.outputs.deployed_unity_major_minor }}/*"]}' \
--fail || echo "Warning: CDN purge failed (non-fatal)"
curl -X POST "https://admin.eagle0.net/notify-update?platform=mac&version=${{ needs.deploy-mac.outputs.deployed_version }}&required=false" \
+6
View File
@@ -20,6 +20,7 @@ on:
- 'ci/github_actions/ensure_bazel_installed.sh'
- 'scripts/build_eagle_ci.sh'
- 'scripts/build_shardok_ci.sh'
- 'scripts/build_shardok_linux_arm64_ci.sh'
- '.github/actions/setup-bazel/**'
- '.github/workflows/server_build.yml'
@@ -83,6 +84,7 @@ jobs:
'src/main/cpp/',
'src/main/protobuf/net/eagle0/shardok/',
'scripts/build_shardok_ci.sh',
'scripts/build_shardok_linux_arm64_ci.sh',
];
const shared = matches(sharedPatterns);
@@ -106,6 +108,10 @@ jobs:
name: 'Shardok server',
command: './scripts/build_shardok_ci.sh',
});
include.push({
name: 'Shardok Linux ARM64 server',
command: './scripts/build_shardok_linux_arm64_ci.sh',
});
}
core.setOutput('build_matrix', JSON.stringify({include}));
+1 -1
View File
@@ -294,7 +294,7 @@ to be used for different players or game situations within the same server proce
**C# (Unity Client):**
- Located in `/src/main/csharp/net/eagle0/clients/unity/eagle0/`
- Uses Unity 6.5 (6000.5.0f1) with comprehensive protobuf integration (100+ .proto files)
- Uses Unity 6 (6000.4.10f1) with comprehensive protobuf integration (100+ .proto files)
- Key components: `EagleConnection.cs` (gRPC client), `EagleGameController.cs` (main game logic)
- Real-time bidirectional streaming with server via `PersistentClientConnection.cs`
- Strategic map UI in `Assets/Eagle/`, tactical battle UI in `Assets/Shardok/`
+1 -1
View File
@@ -282,7 +282,7 @@ oci.pull(
# Base image for Admin Server (Alpine for lightweight Go binary)
oci.pull(
name = "alpine_linux",
digest = "sha256:a2d49ea686c2adfe3c992e47dc3b5e7fa6e6b5055609400dc2acaeb241c829f4",
digest = "sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b",
image = "docker.io/library/alpine",
platforms = ["linux/amd64"],
tag = "3.24",
+8 -8
View File
@@ -904,7 +904,7 @@
"@@rules_oci+//oci:extensions.bzl%oci": {
"general": {
"bzlTransitiveDigest": "H23W9dvwCQM6h+Wt8PjIahx08EkAU5eSbUxAyx9Mopc=",
"usagesDigest": "tbQ7wHHObzzrBzSRv652104GY3xxiaQDK5OUp2YeEbg=",
"usagesDigest": "k6DBHAkb5br/tpwCPUMJgqwb+7U4DXyCmBZQBgLnHJ8=",
"recordedInputs": [
"REPO_MAPPING:aspect_bazel_lib+,bazel_tools bazel_tools",
"REPO_MAPPING:bazel_features+,bazel_tools bazel_tools",
@@ -922,7 +922,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/eclipse-temurin",
"identifier": "sha256:db3011b348ad87ced055afe5145238d87a3d8f0e8f23eb4d0cd8cecb4659b085",
"identifier": "sha256:0beb258e10ad28d2bae0f74349a170bdfa67da0ef87c028cbf3d95c3e1170120",
"platform": "linux/amd64",
"target_name": "eclipse_temurin_25_jre_linux_amd64",
"bazel_tags": []
@@ -936,7 +936,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/eclipse-temurin",
"identifier": "sha256:db3011b348ad87ced055afe5145238d87a3d8f0e8f23eb4d0cd8cecb4659b085",
"identifier": "sha256:0beb258e10ad28d2bae0f74349a170bdfa67da0ef87c028cbf3d95c3e1170120",
"platforms": {
"@@platforms//cpu:x86_64": "@eclipse_temurin_25_jre_linux_amd64"
},
@@ -980,7 +980,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/ubuntu",
"identifier": "24.04",
"identifier": "26.04",
"platform": "linux/amd64",
"target_name": "ubuntu_24_04_linux_amd64",
"bazel_tags": []
@@ -993,7 +993,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/ubuntu",
"identifier": "24.04",
"identifier": "26.04",
"platform": "linux/arm64/v8",
"target_name": "ubuntu_24_04_linux_arm64_v8",
"bazel_tags": []
@@ -1007,7 +1007,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/ubuntu",
"identifier": "24.04",
"identifier": "26.04",
"platforms": {
"@@platforms//cpu:x86_64": "@ubuntu_24_04_linux_amd64",
"@@platforms//cpu:arm64": "@ubuntu_24_04_linux_arm64_v8"
@@ -1023,7 +1023,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/alpine",
"identifier": "sha256:a2d49ea686c2adfe3c992e47dc3b5e7fa6e6b5055609400dc2acaeb241c829f4",
"identifier": "sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b",
"platform": "linux/amd64",
"target_name": "alpine_linux_linux_amd64",
"bazel_tags": []
@@ -1037,7 +1037,7 @@
"scheme": "https",
"registry": "index.docker.io",
"repository": "library/alpine",
"identifier": "sha256:a2d49ea686c2adfe3c992e47dc3b5e7fa6e6b5055609400dc2acaeb241c829f4",
"identifier": "sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b",
"platforms": {
"@@platforms//cpu:x86_64": "@alpine_linux_linux_amd64"
},
+1 -3
View File
@@ -5,8 +5,7 @@ set -x
COMMAND_LOG="$(bazel info command_log)"
bazel build \
//src/main/cpp/net/eagle0/shardok:shardok-server \
//src/main/cpp/net/eagle0/shardok:shardok-inspector
//src/main/cpp/net/eagle0/shardok:shardok-server
STATUS="$?"
if [ $STATUS -eq 0 ]
@@ -26,7 +25,6 @@ echo "Setting up Shardok files..."
/bin/cp -R ./bazel-bin/src/main/cpp/net/eagle0/shardok/shardok-server ./shardok/
/bin/mkdir -p ./shardok/shardok-server.runfiles/net_eagle0/src/main/
/bin/cp -R ./bazel-bin/src/main/cpp/net/eagle0/shardok/shardok-server.runfiles/net_eagle0/src/main/resources ./shardok/shardok-server.runfiles/net_eagle0/src/main/
/bin/cp -R ./bazel-bin/src/main/cpp/net/eagle0/shardok/shardok-inspector ./shardok/
echo "tar & zip shardok files..."
/bin/tar cfh - shardok | /usr/bin/pigz > ./deploy/shardok.tar.gz
+2 -10
View File
@@ -49,7 +49,7 @@ check_modules_installed() {
fi
;;
mac)
if ! has_mac_il2cpp_support "$unity_path" "$unity_app_contents_path"; then
if ! has_il2cpp_variation "${unity_app_contents_path}/PlaybackEngines/MacStandaloneSupport/Variations"; then
echo "✗ Mac IL2CPP module not installed for Unity ${UNITY_VERSION}"
return 1
fi
@@ -67,7 +67,7 @@ check_modules_installed() {
echo "✗ iOS module missing"
missing=1
fi
if ! has_mac_il2cpp_support "$unity_path" "$unity_app_contents_path"; then
if ! has_il2cpp_variation "${unity_app_contents_path}/PlaybackEngines/MacStandaloneSupport/Variations"; then
echo "✗ Mac IL2CPP module missing"
missing=1
fi
@@ -84,14 +84,6 @@ check_modules_installed() {
return 0
}
has_mac_il2cpp_support() {
local unity_path="$1"
local unity_app_contents_path="$2"
has_il2cpp_variation "${unity_app_contents_path}/PlaybackEngines/MacStandaloneSupport/Variations" ||
has_il2cpp_variation "${unity_path}/PlaybackEngines/MacStandaloneSupport/Variations"
}
has_il2cpp_variation() {
local variations_path="$1"
local variation
+9 -6
View File
@@ -13,7 +13,10 @@ set -euxo pipefail
BUILD_TARGET=$1
WORKSPACE=$(pwd)
UNITY_PROJECT="$WORKSPACE/src/main/csharp/net/eagle0/clients/unity/eagle0"
SERVER_DATA="$UNITY_PROJECT/ServerData/$BUILD_TARGET"
UNITY_VERSION=$(grep "m_EditorVersion:" "$UNITY_PROJECT/ProjectSettings/ProjectVersion.txt" | head -1 | sed 's/m_EditorVersion: //')
UNITY_MAJOR_MINOR=$(echo "$UNITY_VERSION" | sed -E 's/^([0-9]+)\.([0-9]+).*/\1.\2/')
ADDRESSABLES_PREFIX="addressables/$BUILD_TARGET/$UNITY_MAJOR_MINOR"
SERVER_DATA="$UNITY_PROJECT/ServerData/$BUILD_TARGET/$UNITY_MAJOR_MINOR"
# DigitalOcean Spaces configuration (same region as other eagle0 buckets)
DO_ENDPOINT="https://sfo3.digitaloceanspaces.com"
@@ -75,7 +78,7 @@ summarize_pending_uploads() {
sorted_uploads_file=$(mktemp)
trap 'rm -f "$sync_args_file" "$uploads_file" "$sorted_uploads_file"' RETURN
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/addressables/$BUILD_TARGET/" \
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/$ADDRESSABLES_PREFIX/" \
--endpoint-url "$DO_ENDPOINT" \
--acl public-read \
--size-only \
@@ -178,7 +181,7 @@ if [ ! -d "$SERVER_DATA" ]; then
fi
echo "Uploading Addressables bundles from $SERVER_DATA"
echo "Target: s3://$DO_BUCKET/addressables/$BUILD_TARGET/"
echo "Target: s3://$DO_BUCKET/$ADDRESSABLES_PREFIX/"
# Configure AWS CLI for DigitalOcean Spaces
export AWS_ACCESS_KEY_ID="$ACCESS_KEY_ID"
@@ -193,13 +196,13 @@ summarize_pending_uploads
#
# --delete removes files in destination that don't exist in source.
# --acl public-read makes files publicly accessible.
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/addressables/$BUILD_TARGET/" \
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/$ADDRESSABLES_PREFIX/" \
--endpoint-url "$DO_ENDPOINT" \
--acl public-read \
--size-only \
--delete
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/addressables/$BUILD_TARGET/" \
aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/$ADDRESSABLES_PREFIX/" \
--endpoint-url "$DO_ENDPOINT" \
--acl public-read \
--exclude "*" \
@@ -208,4 +211,4 @@ aws s3 sync "$SERVER_DATA" "s3://$DO_BUCKET/addressables/$BUILD_TARGET/" \
--include "*.json"
echo "Addressables upload complete"
echo "Files available at: https://assets.eagle0.net/addressables/$BUILD_TARGET/"
echo "Files available at: https://assets.eagle0.net/$ADDRESSABLES_PREFIX/"
+17
View File
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail
bazel_cmd=(bazel)
if [ -n "${BAZEL_OUTPUT_USER_ROOT:-}" ]; then
bazel_cmd+=("--output_user_root=${BAZEL_OUTPUT_USER_ROOT}")
fi
if [ -n "${BAZEL_OUTPUT_BASE:-}" ]; then
bazel_cmd+=("--output_base=${BAZEL_OUTPUT_BASE}")
fi
"${bazel_cmd[@]}" build \
--platforms=//:linux_arm64 \
--extra_toolchains=@llvm_toolchain_linux_arm64//:cc-toolchain-aarch64-linux \
"$@" \
//src/main/cpp/net/eagle0/shardok:shardok-server
@@ -14,6 +14,7 @@
#include <cstdio>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <mutex>
#include "tools/cpp/runfiles/runfiles.h"
@@ -37,7 +38,7 @@ auto rloc(const string& execPath) -> string {
const std::unique_ptr<Runfiles> runfiles(Runfiles::Create(execPath, &error));
if (runfiles == nullptr) {
fprintf(stderr, "Error! %s\n", error.c_str());
std::cerr << "Error! " << error << '\n';
abort();
// error handling
}
@@ -78,9 +79,9 @@ auto FilesystemUtils::MapFilesDirectory() -> string {
void FilesystemUtils::MakeDirectoryIfNecessary(const string& directoryPath) {
if (fs::create_directories(directoryPath))
fprintf(stderr, "Directory %s created\n", directoryPath.c_str());
std::cerr << "Directory " << directoryPath << " created\n";
else
fprintf(stderr, "No new directory created for %s\n", directoryPath.c_str());
std::cerr << "No new directory created for " << directoryPath << '\n';
}
auto FilesystemUtils::SaveFilesDirectory() -> string {
@@ -140,11 +141,11 @@ auto FilesystemUtils::AtomicallySaveToPath(const string& path, const byte_vector
if (ostr.good()) {
const int err = rename(tempPath.c_str(), path.c_str());
if (err == -1) {
fprintf(stderr, "Failed to move file to %s! Errno %d\n", path.c_str(), errno);
std::cerr << "Failed to move file to " << path << "! Errno " << errno << '\n';
return false;
}
} else {
fprintf(stderr, "Failed writing to %s!\n", tempPath.c_str());
std::cerr << "Failed writing to " << tempPath << "!\n";
return false;
}
@@ -80,7 +80,7 @@ void EmitShardokLatencyTrace(
out << "}";
std::scoped_lock lock(LogMutex());
std::cerr << out.str() << std::endl;
std::cerr << out.str() << '\n';
}
ScopedShardokLatencyTrace::ScopedShardokLatencyTrace(
@@ -10,6 +10,7 @@
#include <condition_variable>
#include <functional>
#include <future>
#include <iostream>
#include <memory>
#include <mutex>
#include <queue>
@@ -171,7 +172,7 @@ public:
// Get detailed queue information for debugging
void debug_queue_state() const {
std::unique_lock<std::mutex> lock(const_cast<std::mutex&>(queue_mutex));
printf("ThreadPool: Queue size: %zu\n", tasks.size());
std::cout << "ThreadPool: Queue size: " << tasks.size() << '\n';
if (!tasks.empty()) {
// Create a copy to inspect priorities without modifying queue
auto queue_copy = tasks;
@@ -180,9 +181,9 @@ public:
priorities.push_back(queue_copy.top().priority);
queue_copy.pop();
}
printf("ThreadPool: Priorities in queue: ");
for (int p : priorities) { printf("%d ", p); }
printf("\n");
std::cout << "ThreadPool: Priorities in queue: ";
for (int p : priorities) { std::cout << p << ' '; }
std::cout << '\n';
}
}
@@ -197,4 +198,4 @@ public:
} // namespace eagle0::common
#endif // EAGLE0_THREADPOOL_HPP
#endif // EAGLE0_THREADPOOL_HPP
@@ -9,9 +9,11 @@
#include <fstream>
#include <future>
#include <iomanip>
#include <iostream>
#include <limits>
#include <mutex>
#include <random>
#include <sstream>
#include <stdexcept>
#include <thread>
@@ -862,12 +864,12 @@ auto AbstractMCTSAI::LogSearchResults(
// Log selected command
const std::string selectedDesc =
bestChild->action ? bestChild->action->getDescription() : "Unknown";
printf("MCTS: Selected %s (visit:%d, reward:%.2f, lookahead:%.2f) from %zu options\n",
selectedDesc.c_str(),
bestChild->visitCount,
bestChild->averageReward,
bestChild->lookaheadScore,
rootNode->children.size());
std::ostringstream selectedLine;
selectedLine << std::fixed << std::setprecision(2) << "MCTS: Selected " << selectedDesc
<< " (visit:" << bestChild->visitCount << ", reward:" << bestChild->averageReward
<< ", lookahead:" << bestChild->lookaheadScore << ") from "
<< rootNode->children.size() << " options";
std::cout << selectedLine.str() << '\n';
// Log top 3 actions by visits
std::vector<const MCTSNode*> sortedChildren;
@@ -879,20 +881,17 @@ auto AbstractMCTSAI::LogSearchResults(
// Show all actions if there are <= 10, otherwise top 5
const size_t numToShow = sortedChildren.size() <= 10 ? sortedChildren.size() : 5;
printf("MCTS: Top %zu actions by visits (out of %zu total):\n",
numToShow,
sortedChildren.size());
std::cout << "MCTS: Top " << numToShow << " actions by visits (out of " << sortedChildren.size()
<< " total):\n";
for (size_t i = 0; i < numToShow; ++i) {
const auto* child = sortedChildren[i];
printf(" [%zu] visits:%d avgReward:%.2f immediate:%.2f lookahead:%.2f",
i,
child->visitCount,
child->averageReward,
child->immediateScore,
child->lookaheadScore);
std::ostringstream line;
line << std::fixed << std::setprecision(2) << " [" << i << "] visits:" << child->visitCount
<< " avgReward:" << child->averageReward << " immediate:" << child->immediateScore
<< " lookahead:" << child->lookaheadScore;
// Show the action's own description
if (child->action) { printf(" %s", child->action->getDescription().c_str()); }
if (child->action) { line << ' ' << child->action->getDescription(); }
// Show sequence preview
if (!child->children.empty()) {
@@ -905,16 +904,15 @@ auto AbstractMCTSAI::LogSearchResults(
}
}
if (bestNext && bestNext->action) {
printf(" -> %s", bestNext->action->getDescription().c_str());
line << " -> " << bestNext->action->getDescription();
}
}
printf("\n");
std::cout << line.str() << '\n';
}
printf("MCTS: Tree stats - max depth:%d, total nodes:%d, root visits:%d\n",
result.searchDepth,
result.nodesEvaluated,
rootNode->visitCount);
std::cout << "MCTS: Tree stats - max depth:" << result.searchDepth
<< ", total nodes:" << result.nodesEvaluated
<< ", root visits:" << rootNode->visitCount << '\n';
// Log best sequence from chosen action (following most-visited path)
std::vector<const MCTSNode*> bestSequence;
@@ -940,7 +938,10 @@ auto AbstractMCTSAI::LogSearchResults(
}
if (!bestSequence.empty()) {
printf("MCTS: Best sequence from chosen action (final: %.2f):\n", sequenceScore);
std::ostringstream sequenceLine;
sequenceLine << std::fixed << std::setprecision(2)
<< "MCTS: Best sequence from chosen action (final: " << sequenceScore << "):";
std::cout << sequenceLine.str() << '\n';
int displayedStep = 0;
for (size_t i = 0; i < bestSequence.size(); ++i) {
const auto* node = bestSequence[i];
@@ -949,29 +950,31 @@ auto AbstractMCTSAI::LogSearchResults(
if (i > 0 && node->parent && node->parent->IsChanceNode()) { continue; }
displayedStep++;
printf(" %d.", displayedStep);
if (node->action) { printf(" %s", node->action->getDescription().c_str()); }
std::ostringstream line;
line << " " << displayedStep << ".";
if (node->action) { line << ' ' << node->action->getDescription(); }
// If this is a chance node, display outcome probabilities and scores
if (node->IsChanceNode() && !node->outcomeProbabilities.empty()) {
printf(" [");
line << " [";
for (size_t j = 0; j < node->outcomeProbabilities.size(); ++j) {
if (j > 0) printf(", ");
if (j > 0) { line << ", "; }
const double prob = node->outcomeProbabilities[j] * 100;
// Show lookahead score for each outcome if child exists
if (j < node->children.size() && node->children[j]->visitCount > 0) {
printf("%.0f%%->%.1f", prob, node->children[j]->lookaheadScore);
line << std::fixed << std::setprecision(0) << prob << "%->"
<< std::setprecision(1) << node->children[j]->lookaheadScore;
} else {
printf("%.0f%%->?", prob);
line << std::fixed << std::setprecision(0) << prob << "%->?";
}
}
printf("]");
line << "]";
}
printf(" (visits:%d, immediate:%.2f, lookahead:%.2f)\n",
node->visitCount,
node->immediateScore,
node->lookaheadScore);
line << std::fixed << std::setprecision(2) << " (visits:" << node->visitCount
<< ", immediate:" << node->immediateScore << ", lookahead:" << node->lookaheadScore
<< ")";
std::cout << line.str() << '\n';
// For non-root nodes in the sequence, show what the top alternatives were
// Skip showing alternatives for chance nodes (they have outcome children, not action
@@ -991,17 +994,17 @@ auto AbstractMCTSAI::LogSearchResults(
});
// Show top 3 alternatives at this decision point
printf(" Alternatives at this node (%zu total):\n", siblings.size());
std::cout << " Alternatives at this node (" << siblings.size() << " total):\n";
const size_t topN = std::min(siblings.size(), size_t(3));
for (size_t j = 0; j < topN; ++j) {
const auto* alt = siblings[j];
printf(" [%zu] visits:%d immediate:%.2f lookahead:%.2f",
j,
alt->visitCount,
alt->immediateScore,
alt->lookaheadScore);
if (alt->action) { printf(" %s", alt->action->getDescription().c_str()); }
printf("\n");
std::ostringstream altLine;
altLine << std::fixed << std::setprecision(2) << " [" << j
<< "] visits:" << alt->visitCount
<< " immediate:" << alt->immediateScore
<< " lookahead:" << alt->lookaheadScore;
if (alt->action) { altLine << ' ' << alt->action->getDescription(); }
std::cout << altLine.str() << '\n';
}
}
}
@@ -1013,7 +1016,7 @@ auto AbstractMCTSAI::DumpTreeToFile(const MCTSNode* root, const std::string& fil
std::ofstream out(filepath);
if (!out) {
fprintf(stderr, "Failed to open dump file: %s\n", filepath.c_str());
std::cerr << "Failed to open dump file: " << filepath << '\n';
return;
}
@@ -1042,7 +1045,7 @@ auto AbstractMCTSAI::DumpTreeToFile(const MCTSNode* root, const std::string& fil
out << "\n=== End of Tree Dump ===\n";
out.close();
printf("MCTS: Tree dumped to %s\n", filepath.c_str());
std::cout << "MCTS: Tree dumped to " << filepath << '\n';
}
auto AbstractMCTSAI::DumpNodeRecursive(
@@ -6,8 +6,11 @@
#define EAGLE0_ABSTRACT_MCTSNODE_HPP
#include <cmath>
#include <iomanip>
#include <iostream>
#include <limits>
#include <memory>
#include <sstream>
#include <vector>
#include "MCTSAction.hpp"
@@ -205,13 +208,13 @@ struct MCTSNode {
isMaximizingPlayer ? child->lookaheadScore : -child->lookaheadScore;
const double explorationValue =
explorationConstant * std::sqrt(std::log(visitCount) / child->visitCount);
printf(" UCB: %s lookahead=%.2f expl=%.2f (+%.2f) = %.2f [%s]\n",
isMaximizingPlayer ? "MAX" : "MIN",
child->lookaheadScore,
exploitationValue,
explorationValue,
value,
child->action ? child->action->getDescription().c_str() : "root");
std::ostringstream line;
line << std::fixed << std::setprecision(2)
<< " UCB: " << (isMaximizingPlayer ? "MAX" : "MIN")
<< " lookahead=" << child->lookaheadScore << " expl=" << exploitationValue
<< " (+" << explorationValue << ") = " << value << " ["
<< (child->action ? child->action->getDescription() : "root") << "]";
std::cout << line.str() << '\n';
}
if (value > bestValue) {
+19 -30
View File
@@ -28,36 +28,6 @@ cc_binary(
deps = [":shardok-server-lib"],
)
cc_binary(
name = "shardok-inspector",
srcs = ["shardok_inspector.cpp"],
copts = COPTS,
data = [
"//src/main/resources/net/eagle0/shardok:battalion_types",
"//src/main/resources/net/eagle0/shardok:settings",
"//src/main/resources/net/eagle0/shardok/maps",
],
visibility = ["//visibility:public"],
deps = [
"//src/main/cpp/net/eagle0/common:byte_vector",
"//src/main/cpp/net/eagle0/common:filesystem_utils",
"//src/main/cpp/net/eagle0/common:tsv_parser",
"//src/main/cpp/net/eagle0/shardok/library:engine",
],
)
cc_binary(
name = "corrupt-game-checker",
srcs = ["CorruptGameChecker.cpp"],
copts = COPTS,
deps = [
"//src/main/cpp/net/eagle0/common:byte_vector",
"//src/main/cpp/net/eagle0/common:filesystem_utils",
"//src/main/cpp/net/eagle0/shardok/library:game_state_w",
"//src/main/protobuf/net/eagle0/common:shardok_internal_interface_cc_grpc",
],
)
cc_binary(
name = "hex-map-migrator",
srcs = ["HexMapMigrator.cpp"],
@@ -69,6 +39,25 @@ cc_binary(
],
)
cc_binary(
name = "random_battle_runner",
srcs = ["RandomBattleRunner.cpp"],
copts = COPTS,
data = [
"//src/main/resources/net/eagle0/shardok:battalion_types",
"//src/main/resources/net/eagle0/shardok:settings",
"//src/main/resources/net/eagle0/shardok/maps",
],
deps = [
"//src/main/cpp/net/eagle0/common:byte_vector",
"//src/main/cpp/net/eagle0/common:filesystem_utils",
"//src/main/cpp/net/eagle0/common:unit_conversions",
"//src/main/cpp/net/eagle0/shardok/library:shardok_c_types",
"//src/main/cpp/net/eagle0/shardok/server:games_manager",
"//src/main/protobuf/net/eagle0/common:random_units_cc_proto",
],
)
cc_library(
name = "map_info_calculator",
srcs = ["MapInfoCalculator.cpp"],
@@ -1,46 +0,0 @@
//
// Created by Dan Crosby on 1/9/22.
//
#include "src/main/cpp/net/eagle0/common/byte_vector.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
#include "src/main/protobuf/net/eagle0/common/shardok_internal_interface.pb.h"
#include "src/main/protobuf/net/eagle0/shardok/storage/game.pb.h"
auto main(int argc, char** argv) -> int {
char* path = argv[1];
printf("Checking file %s\n", path);
auto bytes = byte_vector::FromPath(path);
net::eagle0::shardok::storage::Game game;
game.ParseFromArray(bytes.data(), bytes.size());
printf("The game ID is %s\n", game.game_id().c_str());
printf("The size is %lu\n", bytes.size());
const int arCount = game.action_result_size();
printf("There are %d results\n", arCount);
for (int arIndex = 0; arIndex < arCount; arIndex++) {
shardok::GameStateW gameState =
shardok::GameStateW::FromByteString(game.action_result(arIndex).state_after_fb());
const auto* hexMap = gameState->hex_map();
for (int terrainIndex = 0; terrainIndex < hexMap->terrain()->size(); terrainIndex++) {
const auto* terrain = hexMap->terrain()->Get(terrainIndex);
if (terrain->type() == net::eagle0::shardok::storage::fb::Terrain_::Type_STILL_WATER)
continue;
if (terrain->type() == net::eagle0::shardok::storage::fb::Terrain_::Type_RIVER)
continue;
if (terrain->modifier().bridge().present()) {
printf("Caught one! arIndex %d, terrainIndex %d\n", arIndex, terrainIndex);
printf("Action result was %s\n",
game.action_result(arIndex).action_result().DebugString().c_str());
exit(0);
}
}
}
}
@@ -2,7 +2,7 @@
// Created by Dan Crosby on 3/19/20.
//
#include <cstdio>
#include <iostream>
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
#include "src/main/cpp/net/eagle0/common/byte_vector.hpp"
@@ -14,7 +14,7 @@ void ModifyMap(HexMapProto& map);
int main(const int argc, char** argv) {
if (argc < 3) {
printf("Usage: %s input_path output_path\n", argv[0]);
std::cerr << "Usage: " << argv[0] << " input_path output_path\n";
return -1;
}
@@ -22,18 +22,22 @@ int main(const int argc, char** argv) {
const std::string outputPath = argv[2];
const byte_vector mapProtoBytes = byte_vector::FromPath(inputPath);
net::eagle0::shardok::common::HexMap mapProto;
mapProto.ParseFromArray(mapProtoBytes.data(), static_cast<int>(mapProtoBytes.size()));
if (!mapProto.ParseFromArray(mapProtoBytes.data(), static_cast<int>(mapProtoBytes.size()))) {
std::cerr << "Failed to parse hex map from " << inputPath << '\n';
return -1;
}
ModifyMap(mapProto);
const std::string outputString = mapProto.SerializeAsString();
if (FilesystemUtils::AtomicallySaveToPath(outputPath, byte_vector(outputString))) return 0;
printf("Failed to save.\n");
std::cerr << "Failed to save.\n";
return -1;
}
void ModifyMap(HexMapProto& map) {
for (int i = 0; i < map.terrain_size(); i++) {
const int terrainCount = map.terrain_size();
for (int i = 0; i < terrainCount; i++) {
const auto existingTerrainType = map.terrain(i).type();
const auto newTerrain =
static_cast<net::eagle0::shardok::common::Terrain_Type>(existingTerrainType + 2);
@@ -4,6 +4,7 @@
#include "MapInfoCalculator.hpp"
#include <cstddef>
#include <cstdlib>
#include <iostream>
@@ -12,44 +13,42 @@
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/MapLoader.hpp"
using namespace shardok;
auto LoadMapFb(const string& mapName) -> Wrapper<HexMap> {
auto LoadMapFb(const std::string& mapName) -> shardok::Wrapper<shardok::HexMap> {
const HexMapProto mapProto = LoadMap(mapName);
flatbuffers::FlatBufferBuilder fbb{};
const auto hexMapOffset = fb::ConvertHexMapProto(fbb, mapProto);
const auto hexMapOffset = shardok::fb::ConvertHexMapProto(fbb, mapProto);
fbb.Finish(hexMapOffset);
return Wrapper<HexMap>(fbb);
return shardok::Wrapper<shardok::HexMap>(fbb);
}
auto CalculateMap(
const string& mapName,
const std::shared_ptr<ActionPointDistancesCache>& apdCache,
const BattalionTypeSPtr& battalionType) -> OneMapInfo {
const std::string& mapName,
const std::shared_ptr<shardok::ActionPointDistancesCache>& apdCache,
const shardok::BattalionTypeSPtr& battalionType) -> OneMapInfo {
auto hexMap = LoadMapFb(mapName);
const auto mapId = ActionPointDistancesCache::GetMapId(hexMap);
const auto mapId = shardok::ActionPointDistancesCache::GetMapId(hexMap);
const CoordsSet criticalTileLocations = GetCriticalTileLocations(hexMap);
const shardok::CoordsSet criticalTileLocations = shardok::GetCriticalTileLocations(hexMap);
OneMapInfo info{
.castleCount = criticalTileLocations.size(),
.name = mapName,
.positionsRequiringCrossing = {}};
for (unsigned int i = 0; i < hexMap->attacker_starting_positions()->size(); i++) {
for (std::size_t i = 0; i < hexMap->attacker_starting_positions()->size(); i++) {
const auto* positionList = hexMap->attacker_starting_positions()->Get(i);
if (positionList->positions()->size() < 1) continue;
if (positionList->positions()->empty()) continue;
if (positionList->positions()->size() != 10) {
std::cerr << "Should have 10 starting positions!" << '\n';
abort();
std::abort();
}
int positionsRequiringCrossing = 0;
for (const auto* startingPosition : *positionList->positions()) {
for (const Coords& castlePosition : criticalTileLocations) {
if (!CanReach(
for (const shardok::Coords& castlePosition : criticalTileLocations) {
if (!shardok::CanReach(
*startingPosition,
castlePosition,
hexMap,
@@ -61,7 +60,7 @@ auto CalculateMap(
};
}
}
info.positionsRequiringCrossing[i] = positionsRequiringCrossing;
info.positionsRequiringCrossing[static_cast<int>(i)] = positionsRequiringCrossing;
}
return info;
@@ -12,19 +12,15 @@
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistancesCache.hpp"
using namespace shardok;
using std::map;
using std::string;
struct alignas(64) OneMapInfo {
uint32_t castleCount;
string name;
map<int, int> positionsRequiringCrossing;
std::string name;
std::map<int, int> positionsRequiringCrossing;
};
auto CalculateMap(
const string& mapName,
const std::shared_ptr<ActionPointDistancesCache>& apdCache,
const BattalionTypeSPtr& battalionType) -> OneMapInfo;
const std::string& mapName,
const std::shared_ptr<shardok::ActionPointDistancesCache>& apdCache,
const shardok::BattalionTypeSPtr& battalionType) -> OneMapInfo;
#endif // EAGLE0_MAPINFOCALCULATOR_HPP
@@ -5,36 +5,37 @@
#include <fstream>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include "MapInfoCalculator.hpp"
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/BattalionTypeRegistrar.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/MapLoader.hpp"
using namespace shardok;
auto main(const int argc, char** argv) -> int {
FilesystemUtils::SetExecPath(argv[0]);
std::ostream* outputStreamPtr = &std::cout;
std::ofstream outputFile{};
if (argc > 1) {
const string outputPath = argv[1];
const std::string outputPath = argv[1];
outputFile.open(outputPath);
outputStreamPtr = &outputFile;
}
std::ostream& outputStream = *outputStreamPtr;
const auto gameSettings = std::make_shared<GameSettings>();
const auto gameSettings = std::make_shared<shardok::GameSettings>();
auto setter = gameSettings->GetSetter();
BattalionTypeRegistrar::RegisterBattalionTypes(setter);
const BattalionTypeSPtr& battalionType = gameSettings->GetGetter().GetBattalionType(
shardok::BattalionTypeRegistrar::RegisterBattalionTypes(setter);
const shardok::BattalionTypeSPtr& battalionType = gameSettings->GetGetter().GetBattalionType(
net::eagle0::shardok::storage::fb::BattalionTypeId_LIGHT_INFANTRY);
vector<OneMapInfo> mapInfos{};
for (const string& mapName : GetMapNames()) {
std::shared_ptr<ActionPointDistancesCache> apdCache =
std::make_shared<ActionPointDistancesCache>();
std::vector<OneMapInfo> mapInfos{};
for (const std::string& mapName : GetMapNames()) {
std::shared_ptr<shardok::ActionPointDistancesCache> apdCache =
std::make_shared<shardok::ActionPointDistancesCache>();
mapInfos.push_back(CalculateMap(mapName, apdCache, battalionType));
}
@@ -0,0 +1,162 @@
//
// Created by Dan Crosby on 3/29/21.
//
#include <algorithm>
#include <climits>
#include <iostream>
#include <memory>
#include <mutex>
#include <random>
#include <stdexcept>
#include <thread>
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
#include "src/main/cpp/net/eagle0/common/UnitConversions.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
#include "src/main/cpp/net/eagle0/shardok/server/ShardokGamesManager.hpp"
#include "src/main/protobuf/net/eagle0/common/random_units.pb.h"
using net::eagle0::common::RandomUnits;
constexpr int THREAD_COUNT = 16;
#define FIXED_SEED true
#if FIXED_SEED
std::mt19937 g;
#else
std::random_device rd;
std::mt19937 g(rd());
#endif
std::mutex randomMutex;
std::vector<std::string> fileNames{};
std::unique_ptr<shardok::ShardokGamesManager> manager;
auto randInt(const int lowInc, const int hiInc) {
std::lock_guard<std::mutex> lock(randomMutex);
return std::uniform_int_distribution(lowInc, hiInc)(g);
}
void runBattle(const std::vector<shardok::Unit>& units) {
if (fileNames.empty()) { throw std::runtime_error("No map files found"); }
if (units.size() < 2) { throw std::runtime_error("Need at least two units to run a battle"); }
auto mapName = fileNames[randInt(0, (int)fileNames.size() - 1)];
auto month = randInt(1, 12);
const auto maxP1UnitCount = std::min<size_t>(20, units.size() - 1);
auto p1UnitCount = randInt(1, static_cast<int>(maxP1UnitCount));
std::vector<shardok::Unit> p1Units{};
for (int i = 0; i < p1UnitCount; i++) {
auto unit = units[i];
unit.mutate_player_id(0);
p1Units.push_back(unit);
}
const auto maxP2UnitCount = std::min<size_t>(20, units.size() - p1UnitCount);
auto p2UnitCount = randInt(1, static_cast<int>(maxP2UnitCount));
std::vector<shardok::Unit> p2Units{};
for (int i = p1UnitCount; i < p1UnitCount + p2UnitCount; i++) {
auto unit = units[i];
unit.mutate_player_id(1);
p2Units.push_back(unit);
}
std::cout << "map name is " << mapName << ", " << p1UnitCount << " attacking " << p2UnitCount
<< '\n';
std::vector<VictoryConditionProto> attVictoryConditions{
VictoryConditionProto::VICTORY_CONDITION_HOLDS_CRITICAL_TILES,
VictoryConditionProto::VICTORY_CONDITION_LAST_PLAYER_STANDING};
std::vector<VictoryConditionProto> defVictoryConditions{
VictoryConditionProto::VICTORY_CONDITION_LAST_PLAYER_STANDING,
VictoryConditionProto::VICTORY_CONDITION_WIN_AFTER_MAX_ROUNDS};
auto p1 = shardok::PlayerInfoWithUnits(
0,
true,
5,
false,
10000,
attVictoryConditions,
{},
p1Units,
false);
auto p2 = shardok::PlayerInfoWithUnits(
1,
true,
7,
true,
10000,
defVictoryConditions,
{},
p2Units,
false);
std::string gameId = std::to_string(randInt(INT_MIN, INT_MAX));
manager->UnlockedCreateSpecifiedGame(
gameId,
{p1, p2},
mapName,
"",
month,
TutorialBattleConfigProto{},
"");
}
auto LoadUnits() -> std::vector<shardok::Unit> {
const auto bytes = byte_vector::FromPath("/tmp/random_heroes.bin");
RandomUnits commonUnits;
if (!commonUnits.ParseFromArray(bytes.data(), static_cast<int>(bytes.size()))) {
throw std::runtime_error("Failed to parse /tmp/random_heroes.bin");
}
std::cout << "Loaded " << commonUnits.units_size() << " units\n";
std::vector<shardok::Unit> units{};
units.reserve(commonUnits.units_size());
for (const auto& commonUnit : commonUnits.units()) {
// FIXME: assumes 2 players
units.push_back(shardok::ConvertUnit(commonUnit, 0, {0, 1}));
}
std::shuffle(units.begin(), units.end(), g);
return units;
}
[[noreturn]] void runBattlesThread(const std::vector<shardok::Unit>& units) {
while (true) { runBattle(units); }
}
auto main(int /*argc*/, char** argv) -> int {
#if FIXED_SEED
std::srand(4564564);
g.seed(378473);
#else
std::srand(std::time(nullptr));
#endif
FilesystemUtils::SetExecPath(argv[0]);
auto randomUnits = LoadUnits();
std::cout << "Map file directory is " << FilesystemUtils::MapFilesDirectory() << '\n';
fileNames = FilesystemUtils::FilesInDirectory(FilesystemUtils::MapFilesDirectory(), ".e0m");
for (auto& fileName : fileNames) { fileName.resize(fileName.size() - 4); }
manager = std::make_unique<shardok::ShardokGamesManager>(std::vector<std::string>());
std::thread threads[THREAD_COUNT];
for (int i = 0; i < THREAD_COUNT; i++) {
threads[i] = std::thread(runBattlesThread, randomUnits);
}
for (auto& thread : threads) { thread.join(); }
}
@@ -16,9 +16,6 @@ namespace shardok {
constexpr double kOverpowerRatio = 2.0;
constexpr double kBraveWaterCostMultiplier = 1.2;
using std::pair;
using std::shared_ptr;
DIST_T NormalizedCostWhenBraving(const DIST_T cost) {
if (cost >= static_cast<double>(ActionPointDistances::IMPOSSIBLE) / kBraveWaterCostMultiplier)
return ActionPointDistances::IMPOSSIBLE;
@@ -235,4 +232,4 @@ auto GenerateTargetPriorities(
return allTargetsUnitsAndDistances;
}
} // namespace shardok
} // namespace shardok
@@ -20,7 +20,6 @@ namespace shardok {
using GameState = net::eagle0::shardok::storage::fb::GameState;
using Unit = net::eagle0::shardok::storage::fb::Unit;
using net::eagle0::shardok::storage::fb::PlayerInfo;
using std::vector;
using BattalionTypeGetter = std::function<BattalionTypeSPtr(BattalionTypeId)>;
@@ -33,9 +32,9 @@ struct TargetAndAttackLocations {
struct TargetPriorityList {
UnitId attackingUnitId;
vector<TargetAndAttackLocations> priorityOrder;
std::vector<TargetAndAttackLocations> priorityOrder;
TargetPriorityList(const UnitId uid, const vector<TargetAndAttackLocations>& po)
TargetPriorityList(const UnitId uid, const std::vector<TargetAndAttackLocations>& po)
: attackingUnitId(uid),
priorityOrder(po) {}
};
@@ -64,16 +63,16 @@ auto EffectiveDistance(
// Chooses a list of targets in priority order for each unit.
auto GenerateTargetPriorities(
const vector<const Unit*>& occupants,
const std::vector<const Unit*>& occupants,
const HexMap* map,
const CoordsSet& targets,
PlayerId attackerId,
const vector<const Unit*>& remainingUnits,
const std::vector<const Unit*>& remainingUnits,
const APDCache& apdCache,
const ALCache& alCache,
const BattalionTypeGetter& battalionTypeGetter,
ActionPoints braveWaterCost,
bool isLateGame = false) -> vector<TargetPriorityList>;
bool isLateGame = false) -> std::vector<TargetPriorityList>;
} // namespace shardok
@@ -17,8 +17,6 @@
namespace shardok {
using Unit = net::eagle0::shardok::storage::fb::Unit;
using std::shared_ptr;
using std::vector;
class alignas(128) AttackLocations {
private:
@@ -165,7 +163,7 @@ public:
auto CachedLocations(const Coords& singleTarget, bool lateGame) -> const AttackLocations&;
auto CachedLocations(const CoordsSet& targets, bool lateGame) -> AttackLocations;
auto CachedLocations(const vector<const Unit*>& enemies, bool lateGame) -> AttackLocations;
auto CachedLocations(const std::vector<const Unit*>& enemies, bool lateGame) -> AttackLocations;
};
using ALCache = std::unique_ptr<AttackLocationsCache>;
@@ -8,6 +8,8 @@
#include <chrono>
#include <cmath>
#include <future>
#include <iomanip>
#include <iostream>
#include <limits>
#include "AICommandFilter.hpp"
@@ -309,16 +311,16 @@ auto AICommandEvaluator::FindBestCommand(
const auto filteredCommandCount = filteredIndices.size();
const int currentRound = gameState->current_round();
printf("AI_COMMAND_COUNT: Round %d, Player %d, Defender %d, MinDist %.1f, Commands %zu -> "
"%zu "
"(%.1f%% filtered)\n",
currentRound,
static_cast<int>(pid),
isDefender ? 1 : 0,
minDistToEnemies,
allCommandCount,
filteredCommandCount,
100.0 * (allCommandCount - filteredCommandCount) / allCommandCount);
const auto flags = std::cout.flags();
const auto precision = std::cout.precision();
std::cout << "AI_COMMAND_COUNT: Round " << currentRound << ", Player "
<< static_cast<int>(pid) << ", Defender " << (isDefender ? 1 : 0) << ", MinDist "
<< std::fixed << std::setprecision(1) << minDistToEnemies << ", Commands "
<< allCommandCount << " -> " << filteredCommandCount << " ("
<< 100.0 * (allCommandCount - filteredCommandCount) / allCommandCount
<< "% filtered)\n";
std::cout.flags(flags);
std::cout.precision(precision);
}
const auto commandCount = filteredIndices.size();
@@ -13,14 +13,11 @@
namespace shardok {
using std::shared_ptr;
using std::vector;
auto DefenderDistanceBuf(
const Coords &defenderLocation,
const HexMap *hexMap,
const MapId &mapId,
const vector<const Unit *> &attackerUnits,
const std::vector<const Unit *> &attackerUnits,
const APDCache &apdCache,
const ALCache &alCache,
const BattalionTypeGetter &battalionTypeGetter,
@@ -8,12 +8,29 @@
#include "AIFleeDecisionCalculator.hpp"
#include <iomanip>
#include <iostream>
#include "src/main/cpp/net/eagle0/shardok/ai/AIScoreUtilities.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AIUnitScoreCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"
namespace shardok {
namespace {
void WritePercent(std::ostream& output, const double value) {
const auto flags = output.flags();
const auto precision = output.precision();
output << std::fixed << std::setprecision(1) << value;
output.flags(flags);
output.precision(precision);
}
} // namespace
auto AIFleeDecisionCalculator::GetFleeCommandIndex(
const CommandList::const_iterator& fleeCommand,
const CommandListSPtr& availableCommands) -> size_t {
@@ -144,15 +161,14 @@ auto AIFleeDecisionCalculator::EvaluateFleeVsFight(
const int fleeSuccessChance = (*fleeCommand)->GetOddsPercentile();
if (enableDebugLogging) {
printf("AI FinalRound: Evaluating flee (odds=%d%%)...\n", fleeSuccessChance);
std::cout << "AI FinalRound: Evaluating flee (odds=" << fleeSuccessChance << "%)...\n";
}
// Check if flee odds are good enough to attempt
if (fleeSuccessChance >= minimumFleeOddsThreshold) {
if (enableDebugLogging) {
printf("AI FinalRound: Good flee odds (%d%% >= %d%%), choosing flee\n",
fleeSuccessChance,
minimumFleeOddsThreshold);
std::cout << "AI FinalRound: Good flee odds (" << fleeSuccessChance
<< "% >= " << minimumFleeOddsThreshold << "%), choosing flee\n";
}
return FleeDecision{
true,
@@ -166,9 +182,9 @@ auto AIFleeDecisionCalculator::EvaluateFleeVsFight(
// If combat situation is hopeless, even bad flee odds are better than certain death
if (combatWinChance <= 0.05 && fleeSuccessChance >= desperateFleeThreshold) {
if (enableDebugLogging) {
printf("AI FinalRound: Combat hopeless (%.1f%%), desperate flee attempt (%d%%)\n",
combatWinChance * 100,
fleeSuccessChance);
std::cout << "AI FinalRound: Combat hopeless (";
WritePercent(std::cout, combatWinChance * 100);
std::cout << "%), desperate flee attempt (" << fleeSuccessChance << "%)\n";
}
return FleeDecision{
true,
@@ -188,20 +204,21 @@ auto AIFleeDecisionCalculator::EvaluateFleeVsFight(
const double adjustedCombatThreshold = combatWinChance * FLEE_VS_COMBAT_MARGIN;
if (enableDebugLogging) {
printf("AI FinalRound: Flee=%d%%, Combat=%.1f%%, Threshold=%.1f%% -> ",
fleeSuccessChance,
combatWinChance * 100,
adjustedCombatThreshold * 100);
std::cout << "AI FinalRound: Flee=" << fleeSuccessChance << "%, Combat=";
WritePercent(std::cout, combatWinChance * 100);
std::cout << "%, Threshold=";
WritePercent(std::cout, adjustedCombatThreshold * 100);
std::cout << "% -> ";
}
if (fleeChance > adjustedCombatThreshold) {
if (enableDebugLogging) { printf("FLEE (better odds)\n"); }
if (enableDebugLogging) { std::cout << "FLEE (better odds)\n"; }
return FleeDecision{
true,
GetFleeCommandIndex(fleeCommand, availableCommands),
"Flee has better expected outcome"};
} else {
if (enableDebugLogging) { printf("FIGHT (better expected outcome)\n"); }
if (enableDebugLogging) { std::cout << "FIGHT (better expected outcome)\n"; }
// Return 0 to indicate we should use standard command selection
return FleeDecision{
false,
@@ -5,9 +5,6 @@
#ifndef EAGLE0_SHARDOK_AI_AI_MINIMUM_DISTANCE_AND_TARGET_HPP
#define EAGLE0_SHARDOK_AI_AI_MINIMUM_DISTANCE_AND_TARGET_HPP
#include <utility>
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistances.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
#include "src/main/protobuf/net/eagle0/shardok/common/coords.pb.h"
@@ -15,7 +12,6 @@
namespace shardok {
using net::eagle0::shardok::storage::fb::Coords;
using std::shared_ptr;
struct CoordsAndDistance {
Coords coords;
@@ -16,8 +16,6 @@ namespace shardok {
using ScoreValue = double;
using std::vector;
using GameState = net::eagle0::shardok::storage::fb::GameState;
using PlayerInfo = net::eagle0::shardok::storage::fb::PlayerInfo;
using Unit = net::eagle0::shardok::storage::fb::Unit;
@@ -116,15 +116,6 @@ auto CalculateTimeBudget(
const auto clampedBudgetMs = std::clamp(budgetMs, 200.0, maxBudgetMs);
const auto remainingBudget = std::chrono::milliseconds(static_cast<int64_t>(clampedBudgetMs));
// TEMPORARY DEBUG OUTPUT
printf("[DEBUG CalculateTimeBudget] numCommands=%zu, msPerCommand=%.2f, budgetMs=%.2f, "
"clampedBudgetMs=%.2f, isClose=%d\n",
numCommands,
msPerCommand,
budgetMs,
clampedBudgetMs,
isClose);
// Get minimum depth requirement
const size_t minDepth = settingsGetter.Backing().min_lookahead_turns();
@@ -134,4 +125,4 @@ auto CalculateTimeBudget(
.isCloseToEnemy = isClose};
}
} // namespace shardok
} // namespace shardok
@@ -14,9 +14,6 @@
namespace shardok {
using net::eagle0::shardok::storage::fb::Unit;
using std::shared_ptr;
using std::vector;
using ScoreValue = double;
class AttackLocations;
@@ -29,8 +26,8 @@ auto GetRangedAttackBonus(
const Terrain *terrain,
const AttackLocations &attackLocations,
int roundsRemaining,
const vector<const Unit *> &attackerUnits,
const vector<const Unit *> &defenderUnits,
const std::vector<const Unit *> &attackerUnits,
const std::vector<const Unit *> &defenderUnits,
int meteorRange,
double minVigorToCast,
ActionPoints archeryActionPointCost = 0) -> double;
@@ -38,10 +35,10 @@ auto GetRangedAttackBonus(
auto UnitValue(
const Unit *unit,
bool isAttacker,
const vector<const Unit *> &attackerUnits,
const std::vector<const Unit *> &attackerUnits,
bool attackerWantsCastles,
bool includeCastleBonus,
const vector<const Unit *> &defenderUnits,
const std::vector<const Unit *> &defenderUnits,
const HexMap *map,
int roundsRemaining,
const AttackLocations &locationsThisSideCanAttackFrom,
@@ -5,6 +5,8 @@
#include "IterativeDeepeningAI.hpp"
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <utility>
@@ -21,6 +23,20 @@ namespace shardok {
constexpr bool kDebugIterativeDeepeningTimings = true;
namespace {
void WriteFixed(std::ostream& output, const double value, const int precision) {
const auto flags = output.flags();
const auto originalPrecision = output.precision();
output << std::fixed << std::setprecision(precision) << value;
output.flags(flags);
output.precision(originalPrecision);
}
} // namespace
IterativeDeepeningAI::IterativeDeepeningAI(
const PlayerId playerId,
const bool isDefender,
@@ -55,7 +71,7 @@ auto IterativeDeepeningAI::IterativeSearch(
// g_transpositionTable.clear(); // Uncomment to test without cross-search caching
if (commands->empty()) {
if (kDebugIterativeDeepeningTimings) {
printf("ID AI: Commands are empty, returning early\n");
std::cout << "ID AI: Commands are empty, returning early\n";
}
result.searchCompleted = true;
return result;
@@ -169,21 +185,21 @@ auto IterativeDeepeningAI::IterativeSearch(
// Log if best command changed from previous depth
if (currentDepth > 1 && currentBestCommand != previousBestCommand) {
if (kDebugIterativeDeepeningTimings) {
printf("ID AI: Best command changed at depth %lu:\n", currentDepth);
printf(" Depth %lu best: command %zu (score %.2f) - type: %s\n",
currentDepth - 1,
previousBestCommand,
scoresByDepth[previousBestCommand][currentDepth - 1],
net::eagle0::shardok::common::CommandType_Name(
(*commands)[previousBestCommand]->GetCommandType())
.c_str());
printf(" Depth %lu best: command %zu (score %.2f) - type: %s\n",
currentDepth,
currentBestCommand,
currentBestScore,
net::eagle0::shardok::common::CommandType_Name(
(*commands)[currentBestCommand]->GetCommandType())
.c_str());
std::cout << "ID AI: Best command changed at depth " << currentDepth << ":\n"
<< " Depth " << currentDepth - 1 << " best: command "
<< previousBestCommand << " (score ";
WriteFixed(std::cout, scoresByDepth[previousBestCommand][currentDepth - 1], 2);
std::cout << ") - type: "
<< net::eagle0::shardok::common::CommandType_Name(
(*commands)[previousBestCommand]->GetCommandType())
<< '\n'
<< " Depth " << currentDepth << " best: command "
<< currentBestCommand << " (score ";
WriteFixed(std::cout, currentBestScore, 2);
std::cout << ") - type: "
<< net::eagle0::shardok::common::CommandType_Name(
(*commands)[currentBestCommand]->GetCommandType())
<< '\n';
}
}
@@ -239,9 +255,9 @@ auto IterativeDeepeningAI::IterativeSearch(
static_cast<double>(initialBudgetMs.count());
if (budgetUsedPercent > 0.5) {
printf("ID AI: Stopping after depth %lu - used %.1f%% of time budget\n",
currentDepth,
budgetUsedPercent * 100);
std::cout << "ID AI: Stopping after depth " << currentDepth << " - used ";
WriteFixed(std::cout, budgetUsedPercent * 100, 1);
std::cout << "% of time budget\n";
completionReason = EvaluationCompletionReason::NOT_ENOUGH_TIME_TO_CONTINUE;
break;
}
@@ -271,9 +287,9 @@ auto IterativeDeepeningAI::IterativeSearch(
// Validation: if completion reason is RAN_OUT_OF_COMMANDS, evaluation should be 100%
if (completionReason == EvaluationCompletionReason::RAN_OUT_OF_COMMANDS &&
result.commandCountEvaluated < result.availableCommandCount) {
printf("ERROR: Completion reason RAN_OUT_OF_COMMANDS but evaluation %lu/%zu < 100%%\n",
result.commandCountEvaluated,
result.availableCommandCount);
std::cerr << "ERROR: Completion reason RAN_OUT_OF_COMMANDS but evaluation "
<< result.commandCountEvaluated << '/' << result.availableCommandCount
<< " < 100%\n";
}
// Print TranspositionTable statistics
@@ -15,9 +15,12 @@
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#endif
#include <iomanip>
#include <iostream>
#include <set>
#include <unordered_map>
@@ -174,25 +177,20 @@ auto ShardokAIClient::StandardChooseCommandIndex(
// Verify that the AI's guessed state produces the same available commands as reality
if (commandCount != realAvailableCommands->size()) {
fprintf(stderr,
"AI command count mismatch: guessed=%zu real=%zu player=%d round=%d\n",
commandCount,
realAvailableCommands->size(),
playerId,
guessedState->current_round());
std::cerr << "AI command count mismatch: guessed=" << commandCount
<< " real=" << realAvailableCommands->size() << " player=" << playerId
<< " round=" << guessedState->current_round() << "\n";
const auto maxDump = std::max(commandCount, realAvailableCommands->size());
for (size_t i = 0; i < maxDump; i++) {
const auto *realName = i < realAvailableCommands->size()
? net::eagle0::shardok::common::CommandType_Name(
(*realAvailableCommands)[i]->GetCommandType())
.c_str()
: "(none)";
const auto *guessedName = i < commandCount
? net::eagle0::shardok::common::CommandType_Name(
(*guessedCommands)[i]->GetCommandType())
.c_str()
: "(none)";
const auto realName = i < realAvailableCommands->size()
? net::eagle0::shardok::common::CommandType_Name(
(*realAvailableCommands)[i]->GetCommandType())
: "(none)";
const auto guessedName = i < commandCount
? net::eagle0::shardok::common::CommandType_Name(
(*guessedCommands)[i]->GetCommandType())
: "(none)";
const int realActor = i < realAvailableCommands->size()
? (*realAvailableCommands)[i]->GetActorUnitId()
: -1;
@@ -206,17 +204,10 @@ auto ShardokAIClient::StandardChooseCommandIndex(
: -1;
const int guessedRow = i < commandCount ? (*guessedCommands)[i]->GetTargetRow() : -1;
const int guessedCol = i < commandCount ? (*guessedCommands)[i]->GetTargetColumn() : -1;
fprintf(stderr,
" [%zu] real: %s unit=%d (%d,%d) guessed: %s unit=%d (%d,%d)\n",
i,
realName,
realActor,
realRow,
realCol,
guessedName,
guessedActor,
guessedRow,
guessedCol);
std::cerr << " [" << i << "] real: " << realName << " unit=" << realActor << " ("
<< realRow << "," << realCol << ") guessed: " << guessedName
<< " unit=" << guessedActor << " (" << guessedRow << "," << guessedCol
<< ")\n";
}
// Find positions in real commands that are missing from guessed commands
@@ -238,45 +229,34 @@ auto ShardokAIClient::StandardChooseCommandIndex(
for (const auto &[unitId, positions] : realPositions) {
for (const auto &[row, col] : positions) {
if (!guessedPositions[unitId].contains({row, col})) {
fprintf(stderr,
" Missing from guessed: unit=%d pos=(%d,%d)",
unitId,
row,
col);
std::cerr << " Missing from guessed: unit=" << unitId << " pos=(" << row << ","
<< col << ")";
const Coords missingCoords(row, col);
const auto *occupant = guessedState.GetOccupant(missingCoords);
if (occupant) {
fprintf(stderr,
" -> guessed occupant: unit_id=%d player=%d status=%d "
"loc=(%d,%d) hidden=%d battalion_size=%d\n",
occupant->unit_id(),
occupant->player_id(),
static_cast<int>(occupant->status()),
occupant->location().row(),
occupant->location().column(),
occupant->hidden(),
occupant->battalion().size());
std::cerr << " -> guessed occupant: unit_id=" << occupant->unit_id()
<< " player=" << occupant->player_id()
<< " status=" << static_cast<int>(occupant->status()) << " loc=("
<< occupant->location().row() << ","
<< occupant->location().column()
<< ") hidden=" << occupant->hidden()
<< " battalion_size=" << occupant->battalion().size() << "\n";
} else {
fprintf(stderr, " -> no occupant in guessed state\n");
std::cerr << " -> no occupant in guessed state\n";
}
}
}
}
// Dump all guessed state units for full picture
fprintf(stderr, " Guessed state units (%u total):\n", guessedState->units()->size());
std::cerr << " Guessed state units (" << guessedState->units()->size() << " total):\n";
for (size_t i = 0; i < guessedState->units()->size(); i++) {
const auto *u = guessedState->units()->Get(static_cast<unsigned int>(i));
fprintf(stderr,
" unit_id=%d player=%d status=%d loc=(%d,%d) hidden=%d "
"starting_pos_idx=%d\n",
u->unit_id(),
u->player_id(),
static_cast<int>(u->status()),
u->location().row(),
u->location().column(),
u->hidden(),
u->starting_position_index());
std::cerr << " unit_id=" << u->unit_id() << " player=" << u->player_id()
<< " status=" << static_cast<int>(u->status()) << " loc=("
<< u->location().row() << "," << u->location().column()
<< ") hidden=" << u->hidden()
<< " starting_pos_idx=" << u->starting_position_index() << "\n";
}
throw ShardokInternalErrorException(
@@ -356,9 +336,9 @@ auto ShardokAIClient::StandardChooseCommandIndex(
// Write the flatbuffer game state to file using SaveTo method
if (guessedState.SaveTo(statePath)) {
printf("Game state dumped to: %s\n", statePath.c_str());
std::cout << "Game state dumped to: " << statePath << '\n';
} else {
printf("Failed to dump game state to: %s\n", statePath.c_str());
std::cout << "Failed to dump game state to: " << statePath << '\n';
}
#endif // ENABLE_MCTS_DEBUG_DUMP
@@ -396,19 +376,17 @@ auto ShardokAIClient::StandardChooseCommandIndex(
if constexpr (kPerformanceLogging) {
if (result.commandCountEvaluated < result.availableCommandCount) {
printf("ID AI: Depth %d - evaluated %lu/%zu commands\n",
result.depthAchieved,
result.commandCountEvaluated,
result.availableCommandCount);
std::cout << "ID AI: Depth " << result.depthAchieved << " - evaluated "
<< result.commandCountEvaluated << '/' << result.availableCommandCount
<< " commands\n";
}
const auto chosenCommandType =
(*realAvailableCommands)[result.chosenIndex]->GetCommandType();
printf("ID AI: Search complete - achieved depth %d for best command %zu (%s)\n",
result.depthAchieved,
result.chosenIndex,
net::eagle0::shardok::common::CommandType_Name(chosenCommandType).c_str());
std::cout << "ID AI: Search complete - achieved depth " << result.depthAchieved
<< " for best command " << result.chosenIndex << " ("
<< net::eagle0::shardok::common::CommandType_Name(chosenCommandType) << ")\n";
fflush(stdout);
std::cout << std::flush;
}
return result;
@@ -510,7 +488,7 @@ auto ShardokAIClient::ChooseCommandIndex(
totalChoices++;
if (totalChoices % 1000 == 0) {
printf("TYPES CHOSEN:\n");
std::cout << "TYPES CHOSEN:\n";
vector<std::pair<int, CommandType>> choices{};
for (int i = 0; i <= net::eagle0::shardok::common::CommandType_MAX; i++) {
if (typeChosenCount[i] != 0) {
@@ -521,9 +499,9 @@ auto ShardokAIClient::ChooseCommandIndex(
std::ranges::sort(choices);
std::ranges::reverse(choices);
for (const auto &[index, choice] : choices) {
printf("%5d %s\n", index, CommandType_Name(choice).c_str());
std::cout << std::setw(5) << index << ' ' << CommandType_Name(choice) << '\n';
}
printf("\n\n");
std::cout << "\n\n";
}
return results;
@@ -533,7 +511,7 @@ auto ShardokAIClient::ChooseCommandIndex(const ShardokEngine &engine) const
-> CommandChoiceResults {
if (const auto &availableCommands = engine.GetAvailableCommandsForAIPlayer(playerId);
availableCommands->empty()) {
printf("no commands for player %d\n", playerId);
std::cout << "no commands for player " << playerId << '\n';
throw ShardokInternalErrorException(
"Asked to choose a command, but there are none available");
} else {
@@ -4,9 +4,9 @@
#include "TranspositionTable.hpp"
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <iostream>
namespace shardok {
@@ -100,15 +100,23 @@ void TranspositionTable::clear() {
current_age = 0;
}
void TranspositionTable::printStats() const {
printf("TranspositionTable Stats:\n");
printf(" Probes: %" PRIu64 "\n", stats.probes.load());
printf(" Hits: %" PRIu64 " (%.1f%%)\n", stats.hits.load(), stats.hitRate());
printf(" Stores: %" PRIu64 "\n", stats.stores.load());
printf(" Collisions: %" PRIu64 "\n", stats.collisions.load());
printf(" Table size: %zu entries (%.1f MB)\n",
TABLE_SIZE,
(TABLE_SIZE * sizeof(TTEntry)) / (1024.0 * 1024.0));
void TranspositionTable::printStats() const { printStats(std::cout); }
void TranspositionTable::printStats(std::ostream& output) const {
const auto flags = output.flags();
const auto precision = output.precision();
output << "TranspositionTable Stats:\n"
<< " Probes: " << stats.probes.load() << '\n'
<< " Hits: " << stats.hits.load() << " (" << std::fixed << std::setprecision(1)
<< stats.hitRate() << "%)\n"
<< " Stores: " << stats.stores.load() << '\n'
<< " Collisions: " << stats.collisions.load() << '\n'
<< " Table size: " << TABLE_SIZE << " entries ("
<< (TABLE_SIZE * sizeof(TTEntry)) / (1024.0 * 1024.0) << " MB)\n";
output.flags(flags);
output.precision(precision);
}
} // namespace shardok
} // namespace shardok
@@ -8,6 +8,7 @@
#include <atomic>
#include <cstdint>
#include <optional>
#include <ostream>
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
@@ -81,6 +82,7 @@ public:
// Print statistics to stdout
void printStats() const;
void printStats(std::ostream& output) const;
};
// Global instance for the AI to use
@@ -6,6 +6,8 @@
#include <algorithm>
#include <chrono>
#include <iomanip>
#include <iostream>
#include <numeric>
#include "ShardokAction.hpp"
@@ -509,7 +511,9 @@ size_t ShardokGameEngine::mapFilteredIndexToOriginal(
return shardokAction->getIndex();
}
void ShardokGameEngine::reportCacheStatistics() const {
void ShardokGameEngine::reportCacheStatistics() const { reportCacheStatistics(std::cout); }
void ShardokGameEngine::reportCacheStatistics(std::ostream& output) const {
const uint64_t hits = cacheHits_.load(std::memory_order_relaxed);
const uint64_t misses = cacheMisses_.load(std::memory_order_relaxed);
const uint64_t hashTime = timeInHashComputation_.load(std::memory_order_relaxed);
@@ -523,27 +527,29 @@ void ShardokGameEngine::reportCacheStatistics() const {
const double avgActionsTimeUs =
misses > 0 ? static_cast<double>(actionsTime) / static_cast<double>(misses) : 0.0;
printf("Legal Actions Cache Stats:\n");
printf(" Lookups: %llu hits, %llu misses, %.1f%% hit rate, %zu entries\n",
static_cast<unsigned long long>(hits),
static_cast<unsigned long long>(misses),
hitRate * 100.0,
legalActionsCache_.size());
printf(" Timing: %.2f us avg hash, %.2f us avg actions (on miss)\n",
avgHashTimeUs,
avgActionsTimeUs);
printf(" Total time: %.2f ms in hash, %.2f ms in actions\n",
hashTime / 1000.0,
actionsTime / 1000.0);
// Calculate if transposition table is worth it
const double timeWithCache = hashTime + actionsTime;
const double timeWithoutCache =
avgActionsTimeUs * static_cast<double>(totalLookups); // All lookups recompute
const double savings = (timeWithoutCache - timeWithCache) / timeWithoutCache * 100.0;
printf(" Cache savings: %.1f%% vs. no cache (%.2f ms saved)\n",
savings,
(timeWithoutCache - timeWithCache) / 1000.0);
const auto flags = output.flags();
const auto precision = output.precision();
output << "Legal Actions Cache Stats:\n"
<< " Lookups: " << hits << " hits, " << misses << " misses, " << std::fixed
<< std::setprecision(1) << hitRate * 100.0 << "% hit rate, "
<< legalActionsCache_.size() << " entries\n"
<< " Timing: " << std::setprecision(2) << avgHashTimeUs << " us avg hash, "
<< avgActionsTimeUs << " us avg actions (on miss)\n"
<< " Total time: " << hashTime / 1000.0 << " ms in hash, " << actionsTime / 1000.0
<< " ms in actions\n"
<< " Cache savings: " << std::setprecision(1) << savings << "% vs. no cache ("
<< std::setprecision(2) << (timeWithoutCache - timeWithCache) / 1000.0
<< " ms saved)\n";
output.flags(flags);
output.precision(precision);
}
}
@@ -9,6 +9,7 @@
#include <functional>
#include <gtl/phmap.hpp>
#include <memory>
#include <ostream>
#include <vector>
#include "src/main/cpp/net/eagle0/common/mcts/abstract/MCTSGameEngine.hpp"
@@ -92,6 +93,7 @@ public:
// Report transposition table statistics
void reportCacheStatistics() const;
void reportCacheStatistics(std::ostream& output) const;
// Reset cache statistics
void resetCacheStatistics();
@@ -5,8 +5,6 @@
#ifndef EAGLE0_SHARDOK_AI_SCORE_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_AI_SCORE_CALCULATOR_HPP
#include <future>
#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
@@ -16,8 +14,6 @@
namespace shardok {
using shardok::PlayerId;
using std::future;
using std::vector;
using ScoreValue = double;
@@ -20,7 +20,6 @@ namespace shardok {
using GameState = net::eagle0::shardok::storage::fb::GameState;
using net::eagle0::shardok::storage::fb::PlayerInfo;
using std::vector;
using ScoreValue = double;
@@ -8,6 +8,9 @@
#include <atomic>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include "private/AIScoreCalculatorSharedUtilities.hpp"
@@ -57,11 +60,12 @@ struct AttackerScorePerformanceLogger {
if (callCount.load() % LOG_INTERVAL == 0) {
double intervalAvg = intervalTime.load() / LOG_INTERVAL;
double overallAvg = totalTime.load() / callCount.load();
printf("AttackerScoreForState: %d calls, last %d avg: %.1f µs, overall avg: %.1f µs\n",
callCount.load(),
LOG_INTERVAL,
intervalAvg * 1000000.0,
overallAvg * 1000000.0);
std::ostringstream message;
message << std::fixed << std::setprecision(1)
<< "AttackerScoreForState: " << callCount.load() << " calls, last "
<< LOG_INTERVAL << " avg: " << intervalAvg * 1000000.0
<< " µs, overall avg: " << overallAvg * 1000000.0 << " µs\n";
std::cout << message.str();
intervalTime.store(0.0); // Reset for next interval
}
}
@@ -359,7 +359,8 @@ GameStateW AiBattleSimulator::CreateInitialGameState() const {
std::vector<net::eagle0::shardok::storage::fb::Unit> units;
// Attacker units
for (int i = 0; i < config_.attacker().units_size(); ++i) {
const int attackerUnitCount = config_.attacker().units_size();
for (int i = 0; i < attackerUnitCount; ++i) {
const auto& unitConfig = config_.attacker().units(i);
net::eagle0::shardok::storage::fb::Unit unit{};
@@ -453,8 +454,9 @@ GameStateW AiBattleSimulator::CreateInitialGameState() const {
}
// Defender units
int defenderUnitIdStart = config_.attacker().units_size();
for (int i = 0; i < config_.defender().units_size(); ++i) {
const int defenderUnitIdStart = attackerUnitCount;
const int defenderUnitCount = config_.defender().units_size();
for (int i = 0; i < defenderUnitCount; ++i) {
const auto& unitConfig = config_.defender().units(i);
net::eagle0::shardok::storage::fb::Unit unit{};
@@ -678,8 +680,9 @@ BattleResult AiBattleSimulator::RunConfiguredSetupPhase(ShardokEngine& engine) {
playerConfig,
int unitIdOffset) {
std::vector<UnitPlacementInfo> placements;
placements.reserve(playerConfig.units_size());
for (int i = 0; i < playerConfig.units_size(); ++i) {
const int unitCount = playerConfig.units_size();
placements.reserve(unitCount);
for (int i = 0; i < unitCount; ++i) {
const auto& unitConfig = playerConfig.units(i);
if (!unitConfig.has_fixed_position()) {
throw std::invalid_argument(
@@ -18,7 +18,15 @@
#include "src/main/cpp/net/eagle0/shardok/library/ShardokEngine.hpp"
#include "src/main/protobuf/net/eagle0/shardok/common/command_type.pb.h"
using namespace shardok;
using shardok::AIAlgorithmType;
using shardok::AIPerformanceMetrics;
using shardok::EvaluationCompletionReason;
using shardok::PerformanceTestConfig;
using shardok::PerformanceTestGameStateBuilder;
using shardok::PlayerId;
using shardok::ShardokAIClient;
using shardok::ShardokEngine;
namespace ai_testing_common = shardok::ai_testing_common;
namespace {
@@ -300,4 +308,4 @@ int main(int argc, char* argv[]) {
}
return 0;
}
}
@@ -5,13 +5,15 @@
#ifndef EAGLE0_SHARDOK_CONTROLLER_GAME_UPDATE_RECEIVER_HPP
#define EAGLE0_SHARDOK_CONTROLLER_GAME_UPDATE_RECEIVER_HPP
#include <atomic>
#include <vector>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-redundant-constexpr-static-def"
#include "src/main/protobuf/net/eagle0/shardok/api/action_result_view.pb.h"
#pragma GCC diagnostic pop
namespace shardok {
using std::vector;
class GameUpdateReceiver {
private:
@@ -25,7 +27,7 @@ public:
virtual ~GameUpdateReceiver() = default;
virtual void ReceiveActionResult(const net::eagle0::shardok::api::ActionResultView& result) = 0;
virtual void ReceiveActionResults(
const vector<net::eagle0::shardok::api::ActionResultView>& results) = 0;
const std::vector<net::eagle0::shardok::api::ActionResultView>& results) = 0;
[[nodiscard]] auto GetIdentifier() const -> long { return identifier; }
};
@@ -27,7 +27,6 @@ using net::eagle0::common::ScopedShardokLatencyTrace;
using std::condition_variable;
using std::mutex;
using std::scoped_lock;
using std::string;
using std::unique_lock;
using std::weak_ptr;
@@ -40,7 +39,7 @@ private:
PlayerId shardokPlayerId;
int eagleFactionId;
string message;
std::string message;
public:
MismatchedPlayerIdException(const PlayerId shardokPid, const int eagleFid)
@@ -57,7 +56,7 @@ class MissingPlayerIdException : public std::exception {
private:
PlayerId shardokPlayerId;
string message;
std::string message;
public:
MissingPlayerIdException(const PlayerId shardokPid) : shardokPlayerId(shardokPid) {
@@ -9,6 +9,7 @@
#include "AvailableCommandsFactory.hpp"
#include <algorithm>
#include <memory>
#include <ranges>
#include "src/main/cpp/net/eagle0/shardok/library/FireUtils.hpp"
@@ -21,8 +22,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/view_filters/GameStateFilter.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/view_filters/GameStateGuesser.hpp"
using std::make_shared;
namespace shardok {
class AvailableCommandsFactoryImpl : public AvailableCommandsFactory {
@@ -51,7 +50,7 @@ private:
return (player == end(*gameState->player_infos()) || !player->is_defender());
}
const vector<shared_ptr<const CommandFactory>> commandFactories;
const std::vector<std::shared_ptr<const CommandFactory>> commandFactories;
const PlayerSetupCommandFactory playerSetupCommandFactory;
// AvailableCommands helpers for a single unit
@@ -97,7 +96,7 @@ auto AvailableCommandsFactoryImpl::GetPlayerSetupCommands(
gameState,
reinforcementPositions);
return make_shared<CommandList>(previewCommands);
return std::make_shared<CommandList>(previewCommands);
}
void AvailableCommandsFactoryImpl::AddAvailableCommandsForOneUnit(
@@ -116,7 +115,7 @@ void AvailableCommandsFactoryImpl::AddAvailableCommandsForOneUnit(
const Coords &currentCoords = unit->location();
const bool isEligibleCharger = unit->unit_id() == gameState->eligible_charger_id();
vector<UnitId> possibleChargees{};
std::vector<UnitId> possibleChargees{};
for (const UnitId cid : *gameState->possible_chargee_ids()) {
if (cid != -1) { possibleChargees.push_back(cid); }
}
@@ -195,11 +194,11 @@ auto AvailableCommandsFactoryImpl::GetAvailableCommands(
const std::optional<std::vector<Coords>> &reinforcementPositions) const -> CommandListSPtr {
CommandList commands{};
vector<AdjacentTile> adjacentTiles;
std::vector<AdjacentTile> adjacentTiles;
playerSetupCommandFactory
.AddAvailablePlayerSetupCommands(commands, playerId, gameState, reinforcementPositions);
if (!commands.empty()) return make_shared<CommandList>(commands);
if (!commands.empty()) return std::make_shared<CommandList>(commands);
for (const Unit *unit : *gameState->units()) {
if (unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT) continue;
@@ -251,7 +250,7 @@ auto AvailableCommandsFactoryImpl::GetAvailableCommands(
}
if (commands.empty()) return nullptr;
return make_shared<CommandList>(commands);
return std::make_shared<CommandList>(commands);
}
} // namespace shardok
@@ -9,6 +9,7 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_AVAILABLE_COMMANDS_FACTORY_HPP
#define EAGLE0_SHARDOK_LIBRARY_AVAILABLE_COMMANDS_FACTORY_HPP
#include <memory>
#include <optional>
#include <vector>
@@ -20,14 +21,12 @@
namespace shardok {
using std::optional;
using std::unique_ptr;
using UnitIdOptional = optional<UnitId>;
using UnitIdOptional = std::optional<UnitId>;
class AvailableCommandsFactory {
public:
static auto MakeAvailableCommandsFactory(const SettingsGetter &settingsGetter)
-> unique_ptr<AvailableCommandsFactory>;
-> std::unique_ptr<AvailableCommandsFactory>;
virtual ~AvailableCommandsFactory() = default;
@@ -8,17 +8,18 @@
#include "BattalionType.hpp"
#include <iostream>
#include <mutex>
#include <unordered_map>
#include "src/main/cpp/net/eagle0/common/MapUtils.hpp"
namespace shardok {
using std::unordered_map;
using BattalionTypeId = net::eagle0::shardok::storage::fb::BattalionTypeId;
ActionCost actionCostForKey(const unordered_map<string, string> &map, const string &key) {
ActionCost actionCostForKey(
const std::unordered_map<std::string, std::string> &map,
const std::string &key) {
const int pointCost = IntForKey(map, key);
return pointCost == -1 ? IMPOSSIBLE_ACTION_COST : ActionCost::StandardActionCost(pointCost);
@@ -27,7 +28,7 @@ ActionCost actionCostForKey(const unordered_map<string, string> &map, const stri
std::shared_ptr<const BattalionType> BattalionType::NewBattalionTypeFromMap(
const std::unordered_map<std::string, std::string> &map) {
try {
auto *newType = new BattalionType{
return std::make_shared<const BattalionType>(BattalionType{
map.at("TypeName"),
BattalionTypeId(std::stoi(map.at("TypeId"))),
IntForKey(map, "Capacity"),
@@ -171,11 +172,9 @@ std::shared_ptr<const BattalionType> BattalionType::NewBattalionTypeFromMap(
DoubleForKey(map, "AmbushOddsWithoutHero"),
DoubleForKey(map, "BaseStunChanceOnCharge"),
DoubleForKey(map, "TrainingDifferenceMultiplierForStunChanceOnCharge"),
DoubleForKey(map, "MonthlyFoodCost")};
return std::shared_ptr<const BattalionType>(newType);
DoubleForKey(map, "MonthlyFoodCost")});
} catch (const std::out_of_range &e) {
printf("Failed to parse file map; caught exception %s\n", e.what());
std::cerr << "Failed to parse file map; caught exception " << e.what() << '\n';
return nullptr;
}
}
@@ -13,7 +13,8 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <iomanip>
#include <sstream>
#include <string>
#include <vector>
@@ -244,33 +245,27 @@ public:
}
[[nodiscard]] auto ToString() const -> std::string {
std::array<char, 1024> buffer{};
snprintf(
buffer.data(),
buffer.size(),
"slashing=%f / %f, puncturing=%f / %f, stabbing=%f / %f, crushing=%f / %f, "
"fire=%f / "
"%f, cold=%f / %f, lightning=%f / %f, aessence=%f / %f, impact=%f / %f",
GetNormalDamageOfType(DamageType_slashing),
GetPenetratingDamageOfType(DamageType_slashing),
GetNormalDamageOfType(DamageType_puncturing),
GetPenetratingDamageOfType(DamageType_puncturing),
GetNormalDamageOfType(DamageType_stabbing),
GetPenetratingDamageOfType(DamageType_stabbing),
GetNormalDamageOfType(DamageType_crushing),
GetPenetratingDamageOfType(DamageType_crushing),
GetNormalDamageOfType(DamageType_fire),
GetPenetratingDamageOfType(DamageType_fire),
GetNormalDamageOfType(DamageType_cold),
GetPenetratingDamageOfType(DamageType_cold),
GetNormalDamageOfType(DamageType_lightning),
GetPenetratingDamageOfType(DamageType_lightning),
GetNormalDamageOfType(DamageType_aessence),
GetPenetratingDamageOfType(DamageType_aessence),
GetNormalDamageOfType(DamageType_impact),
GetPenetratingDamageOfType(DamageType_impact));
return {buffer.data()};
std::ostringstream out;
out << std::fixed << std::setprecision(6)
<< "slashing=" << GetNormalDamageOfType(DamageType_slashing) << " / "
<< GetPenetratingDamageOfType(DamageType_slashing)
<< ", puncturing=" << GetNormalDamageOfType(DamageType_puncturing) << " / "
<< GetPenetratingDamageOfType(DamageType_puncturing)
<< ", stabbing=" << GetNormalDamageOfType(DamageType_stabbing) << " / "
<< GetPenetratingDamageOfType(DamageType_stabbing)
<< ", crushing=" << GetNormalDamageOfType(DamageType_crushing) << " / "
<< GetPenetratingDamageOfType(DamageType_crushing)
<< ", fire=" << GetNormalDamageOfType(DamageType_fire) << " / "
<< GetPenetratingDamageOfType(DamageType_fire)
<< ", cold=" << GetNormalDamageOfType(DamageType_cold) << " / "
<< GetPenetratingDamageOfType(DamageType_cold)
<< ", lightning=" << GetNormalDamageOfType(DamageType_lightning) << " / "
<< GetPenetratingDamageOfType(DamageType_lightning)
<< ", aessence=" << GetNormalDamageOfType(DamageType_aessence) << " / "
<< GetPenetratingDamageOfType(DamageType_aessence)
<< ", impact=" << GetNormalDamageOfType(DamageType_impact) << " / "
<< GetPenetratingDamageOfType(DamageType_impact);
return out.str();
}
class Builder {
@@ -10,12 +10,10 @@
namespace shardok {
using std::vector;
auto ShardokAction::Execute(
const GameStateW& currentState,
const std::shared_ptr<RandomGenerator>& generator) const -> vector<ActionResult> {
vector<ActionResult> results = InternalExecute(currentState, generator);
const std::shared_ptr<RandomGenerator>& generator) const -> std::vector<ActionResult> {
std::vector<ActionResult> results = InternalExecute(currentState, generator);
return results;
}
@@ -23,10 +21,10 @@ auto ShardokAction::Execute(
auto ShardokAction::ExecuteWithRoll(
const GameStateW& currentState,
const std::shared_ptr<RandomGenerator>& generator,
const std::optional<int32_t> roll) const -> vector<ActionResult> {
vector<ActionResult> results = InternalExecuteWithRoll(currentState, generator, roll);
const std::optional<int32_t> roll) const -> std::vector<ActionResult> {
std::vector<ActionResult> results = InternalExecuteWithRoll(currentState, generator, roll);
return results;
}
} // namespace shardok
} // namespace shardok
@@ -9,6 +9,9 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_SHARDOK_ACTION_HPP
#define EAGLE0_SHARDOK_LIBRARY_SHARDOK_ACTION_HPP
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "ShardokException.hpp"
@@ -22,8 +25,6 @@
namespace shardok {
using net::eagle0::shardok::storage::ActionResult;
using std::shared_ptr;
using std::vector;
using PercentileRollOdds = net::eagle0::shardok::storage::Odds;
class IllegalActionException : public ShardokException {
@@ -57,9 +57,9 @@ public:
}
};
using CommandSPtr = shared_ptr<ShardokCommand>;
using CommandList = vector<CommandSPtr>;
using CommandListSPtr = shared_ptr<const CommandList>;
using CommandSPtr = std::shared_ptr<ShardokCommand>;
using CommandList = std::vector<CommandSPtr>;
using CommandListSPtr = std::shared_ptr<const CommandList>;
} // namespace shardok
@@ -14,12 +14,11 @@
#include <utility>
namespace shardok {
using std::string;
class ShardokException : public std::exception {
protected:
string description;
explicit ShardokException(string desc) : description(std::move(desc)) {}
std::string description;
explicit ShardokException(std::string desc) : description(std::move(desc)) {}
public:
[[nodiscard]] auto what() const noexcept -> const char* override {
@@ -30,13 +29,13 @@ public:
// Thrown when the client has provided us with bad info. The game state should still be OK.
class ShardokClientErrorException : public ShardokException {
public:
explicit ShardokClientErrorException(const string& desc) : ShardokException(desc) {}
explicit ShardokClientErrorException(const std::string& desc) : ShardokException(desc) {}
};
// Thrown when we have some bad internal state. Probably not recoverable.
class ShardokInternalErrorException : public ShardokException {
public:
explicit ShardokInternalErrorException(const string& desc) : ShardokException(desc) {}
explicit ShardokInternalErrorException(const std::string& desc) : ShardokException(desc) {}
};
static inline void internalAssert(const bool condition) {
@@ -49,13 +48,13 @@ static inline void internalAssert(const bool condition, const std::string& messa
class ShardokNotImplementedException : public ShardokException {
public:
explicit ShardokNotImplementedException(const string& operation)
explicit ShardokNotImplementedException(const std::string& operation)
: ShardokException("Operation " + operation + " is not yet implemented.") {}
};
class ShardokEagleInterfaceException : public ShardokException {
public:
explicit ShardokEagleInterfaceException(const string& desc) : ShardokException(desc) {}
explicit ShardokEagleInterfaceException(const std::string& desc) : ShardokException(desc) {}
};
} // namespace shardok
@@ -11,9 +11,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"
namespace shardok {
using std::begin;
using std::end;
using std::vector;
struct ActionPointDistances::BraveableTileInfo {
struct BraveableFromInfo {
@@ -22,7 +19,7 @@ struct ActionPointDistances::BraveableTileInfo {
};
CoordsSet cs;
vector<BraveableFromInfo> details;
std::vector<BraveableFromInfo> details;
explicit BraveableTileInfo(const HexMap* hexMap) : cs(hexMap) {}
};
@@ -68,10 +65,10 @@ auto ActionPointDistances::BraveWaterPossibleCoords(const HexMap* hexMap) const
return info;
}
auto ActionPointDistances::CreateIndexToCoords(const HexMap* hexMap) -> vector<Coords> {
auto ActionPointDistances::CreateIndexToCoords(const HexMap* hexMap) -> std::vector<Coords> {
const int8_t columnCount = hexMap->column_count();
const int indexCount = hexMap->row_count() * columnCount;
vector<Coords> indexToCoords;
std::vector<Coords> indexToCoords;
indexToCoords.reserve(indexCount);
for (int i = 0; i < indexCount; i++) {
indexToCoords.emplace_back(
@@ -82,10 +79,10 @@ auto ActionPointDistances::CreateIndexToCoords(const HexMap* hexMap) -> vector<C
}
auto ActionPointDistances::CreateAdjacencyTable(const HexMap* hexMap)
-> vector<std::array<int, 6>> {
-> std::vector<std::array<int, 6>> {
const int8_t columnCount = hexMap->column_count();
const int indexCount = hexMap->row_count() * columnCount;
vector<std::array<int, 6>> adjacencyTable;
std::vector<std::array<int, 6>> adjacencyTable;
adjacencyTable.reserve(indexCount);
for (int i = 0; i < indexCount; i++) {
const Coords coords(
@@ -105,22 +102,23 @@ auto ActionPointDistances::CreateAdjacencyTable(const HexMap* hexMap)
}
void ActionPointDistances::PopulateOne(
vector<DIST_T>& ds,
std::vector<DIST_T>& ds,
const HexMap* hexMap,
const bool includeBravingWater,
const int braveWaterCost,
const BattalionTypeSPtr& battalionType,
const std::shared_ptr<BraveableTileInfo>& braveWaterPossibleCoords,
const vector<Coords>& indexToCoords,
const vector<std::array<int, 6>>& adjacencyTable) {
vector<uint8_t> visited(ds.size());
const std::vector<Coords>& indexToCoords,
const std::vector<std::array<int, 6>>& adjacencyTable) {
std::vector<uint8_t> visited(ds.size());
// Priority queue for efficient minimum selection: {distance, index}
std::priority_queue<std::pair<DIST_T, int>, std::vector<std::pair<DIST_T, int>>, std::greater<>>
pq;
// Find starting index (the one with distance 0)
for (int i = 0; i < static_cast<int>(ds.size()); i++) {
const int distanceCount = static_cast<int>(ds.size());
for (int i = 0; i < distanceCount; i++) {
if (ds[i] == 0) {
pq.emplace(0, i);
break;
@@ -206,9 +204,9 @@ auto ActionPointDistances::GenerateDistances(
const bool includeBravingWater,
const int braveWaterCost,
const BattalionTypeSPtr& battalionType,
const std::shared_ptr<BraveableTileInfo>& braveWaterPossibleCoords) -> vector<DIST_T> {
const std::shared_ptr<BraveableTileInfo>& braveWaterPossibleCoords) -> std::vector<DIST_T> {
const int indexCount = hexMap->row_count() * hexMap->column_count();
auto ds = vector(indexCount, IMPOSSIBLE);
auto ds = std::vector(indexCount, IMPOSSIBLE);
ds[fromIndex] = 0;
@@ -259,4 +257,4 @@ OnDemandActionPointDistances::OnDemandActionPointDistances(
}
}
} // namespace shardok
} // namespace shardok
@@ -5,8 +5,11 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_HPP
#include <array>
#include <future>
#include <optional>
#include <limits>
#include <memory>
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/BattalionType.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/FlatbufferWrapper.hpp"
@@ -21,9 +24,6 @@ namespace shardok {
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
using HexMapW = Wrapper<HexMap>;
using Coords = net::eagle0::shardok::storage::fb::Coords;
using std::optional;
using std::shared_future;
using std::vector;
using DIST_T = int16_t;
@@ -35,28 +35,29 @@ protected:
struct BraveableTileInfo;
static void PopulateOne(
vector<DIST_T> &ds,
std::vector<DIST_T> &ds,
const net::eagle0::shardok::storage::fb::HexMap *hexMap,
bool includeBravingWater,
int braveWaterCost,
const BattalionTypeSPtr &battalionType,
const std::shared_ptr<BraveableTileInfo> &braveWaterPossibleCoords,
const vector<Coords> &indexToCoords,
const vector<std::array<int, 6>> &adjacencyTable);
const std::vector<Coords> &indexToCoords,
const std::vector<std::array<int, 6>> &adjacencyTable);
static auto GenerateDistances(
int fromIndex,
const HexMap *hexMap,
bool includeBravingWater,
int braveWaterCost,
const BattalionTypeSPtr &battalionType,
const std::shared_ptr<BraveableTileInfo> &braveWaterPossibleCoords) -> vector<DIST_T>;
const std::shared_ptr<BraveableTileInfo> &braveWaterPossibleCoords)
-> std::vector<DIST_T>;
auto BraveWaterPossibleCoords(const HexMap *hexMap) const -> std::shared_ptr<BraveableTileInfo>;
// Create coordinate lookup table for efficient index->coords conversion
static auto CreateIndexToCoords(const HexMap *hexMap) -> vector<Coords>;
static auto CreateIndexToCoords(const HexMap *hexMap) -> std::vector<Coords>;
// Create adjacency lookup table for efficient neighbor access
static auto CreateAdjacencyTable(const HexMap *hexMap) -> vector<std::array<int, 6>>;
static auto CreateAdjacencyTable(const HexMap *hexMap) -> std::vector<std::array<int, 6>>;
[[nodiscard]] auto ToIndex(const Coords &coords) const -> int {
return coords.row() * column_count + coords.column();
@@ -79,7 +80,7 @@ private:
const HexMapW hexMap;
const BattalionTypeSPtr battalionType;
vector<shared_future<vector<int16_t>>> distances;
std::vector<std::shared_future<std::vector<int16_t>>> distances;
public:
explicit OnDemandActionPointDistances(
@@ -6,6 +6,8 @@
#include <algorithm>
#include <chrono>
#include <iostream>
#include <ostream>
#include <unordered_map>
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/FixedActionPointDistances.hpp"
@@ -32,22 +34,21 @@ thread_local struct {
} cacheStats;
// Helper function to print stats periodically
static void MaybePrintCacheStats() {
static void MaybePrintCacheStats(std::ostream& output) {
auto now = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::seconds>(now - cacheStats.lastReportTime).count() >=
kCacheStatsFrequencySeconds) {
printf("Thread cache stats: %d persistent hits, %d persistent misses, %d local hits, "
"%d local misses, %d shared accesses, %d eviction events\n",
cacheStats.persistentHits,
cacheStats.persistentMisses,
cacheStats.localHits,
cacheStats.localMisses,
cacheStats.sharedAccesses,
cacheStats.evictionEvents);
output << "Thread cache stats: " << cacheStats.persistentHits << " persistent hits, "
<< cacheStats.persistentMisses << " persistent misses, " << cacheStats.localHits
<< " local hits, " << cacheStats.localMisses << " local misses, "
<< cacheStats.sharedAccesses << " shared accesses, " << cacheStats.evictionEvents
<< " eviction events\n";
cacheStats.lastReportTime = now;
}
}
static void MaybePrintCacheStats() { MaybePrintCacheStats(std::cout); }
class BadHashException final : public std::exception {
public:
BadHashException() = default;
@@ -154,7 +155,7 @@ auto ActionPointDistancesCache::GetRaw(
if (kCacheStatsLogging) { cacheStats.localMisses++; }
// Check shared cache before expensive ice-clearing operation
shared_ptr<ActionPointDistances> sharedResult;
std::shared_ptr<ActionPointDistances> sharedResult;
if (sharedDistances.if_contains(cacheKey, [&sharedResult](const auto& kv) {
sharedResult = kv.second;
})) {
@@ -5,6 +5,7 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_CACHE_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_CACHE_HPP
#include <memory>
#include <shared_mutex>
#include <unordered_map>
@@ -17,8 +18,6 @@
namespace shardok {
using std::shared_ptr;
struct MapId {
uint64_t terrainTypesId;
uint64_t modifierId;
@@ -58,9 +57,10 @@ struct FullCacheKeyHash {
class ActionPointDistancesCache {
private:
struct CacheEntry {
shared_ptr<ActionPointDistances> sharedPtr;
std::shared_ptr<ActionPointDistances> sharedPtr;
explicit CacheEntry(shared_ptr<ActionPointDistances> ptr) : sharedPtr(std::move(ptr)) {}
explicit CacheEntry(std::shared_ptr<ActionPointDistances> ptr)
: sharedPtr(std::move(ptr)) {}
};
// Tier 1: persistent map. This is NOT safe to write to while reads may be happening.
@@ -70,10 +70,10 @@ private:
using APDMap = gtl::parallel_flat_hash_map<
FullCacheKey,
shared_ptr<ActionPointDistances>,
std::shared_ptr<ActionPointDistances>,
FullCacheKeyHash,
std::equal_to<FullCacheKey>,
std::allocator<std::pair<const FullCacheKey, shared_ptr<ActionPointDistances>>>,
std::allocator<std::pair<const FullCacheKey, std::shared_ptr<ActionPointDistances>>>,
6,
std::mutex>;
@@ -119,7 +119,7 @@ public:
static size_t GetThreadLocalCacheSize();
};
using APDCache = shared_ptr<ActionPointDistancesCache>;
using APDCache = std::shared_ptr<ActionPointDistancesCache>;
} // namespace shardok
@@ -54,31 +54,3 @@ cc_library(
"//src/main/cpp/net/eagle0/shardok/library/fb_helpers:hex_map_helpers",
],
)
cc_library(
name = "fixed_action_point_distances_timer",
srcs = ["FixedActionPointDistancesTimer.cpp"],
copts = COPTS,
data = [
"//src/main/resources/net/eagle0/shardok/maps",
],
deps = [
"//src/main/cpp/net/eagle0/common:sequence_random_generator",
"//src/main/cpp/net/eagle0/shardok/library/action_point_distances:fixed_action_point_distances",
"//src/main/cpp/net/eagle0/shardok/library/settings_loader",
"//src/main/cpp/net/eagle0/shardok/util:map_loader",
"@googletest//:gtest",
"@googletest//:gtest_main",
],
)
cc_binary(
name = "fixed_action_point_distances_timer_app",
copts = COPTS,
data = [
"//src/main/resources/net/eagle0/shardok/maps",
],
deps = [
":fixed_action_point_distances_timer",
],
)
@@ -4,6 +4,7 @@
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/FixedActionPointDistances.hpp"
#include <iostream>
#include <thread>
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
@@ -13,10 +14,8 @@ static const int ASYNC_COUNT = []() {
const int cores = static_cast<int>(std::thread::hardware_concurrency());
// Use cores-2 to leave room for OS and other processes, minimum 4 threads
const int threadCount = std::max(4, cores - 4);
fprintf(stderr,
"ActionPointDistances using %d threads (detected %d cores)\n",
threadCount,
cores);
std::cerr << "ActionPointDistances using " << threadCount << " threads (detected " << cores
<< " cores)\n";
return threadCount;
}();
@@ -13,12 +13,11 @@
namespace shardok {
using std::vector;
using BattalionTypeSPtr = std::shared_ptr<const BattalionType>;
class FixedActionPointDistances final : public ActionPointDistances {
private:
vector<vector<DIST_T>> distances;
std::vector<std::vector<DIST_T>> distances;
// Private constructor - use Create factory method instead
explicit FixedActionPointDistances(const HexMap *map, int columnCount);
@@ -1,48 +0,0 @@
//
// Created by Dan Crosby on 11/26/22.
//
#include <include/gtest/gtest.h>
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistances.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/FixedActionPointDistances.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/HexMapHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings_loader/SettingsLoader.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/MapLoader.hpp"
using namespace std::chrono;
using namespace shardok;
auto main(int argc, char** argv) -> int {
FilesystemUtils::SetExecPath(
"/Users/dancrosby/CodingProjects/github/eagle0/bazel-bin/src/main/cpp/net/eagle0/"
"shardok/library/action_point_distances/fixed_action_point_distances_timer_app");
const auto gameSettings = SettingsLoader::LoadSettings();
const vector<string> mapNames = GetMapNames();
vector<HexMapW> hexMaps;
for (const string& name : mapNames) {
auto hexMapProto = LoadMap(name);
flatbuffers::FlatBufferBuilder fbb;
const auto offset = shardok::fb::ConvertHexMapProto(fbb, hexMapProto);
fbb.Finish(offset);
hexMaps.emplace_back(fbb);
}
const auto& battalionType = gameSettings->GetGetter().GetBattalionType(
net::eagle0::shardok::storage::fb::BattalionTypeId_LIGHT_INFANTRY);
const auto start = system_clock::now();
for (int i = 0; i < 100; i++) {
for (const HexMapW& hexMap : hexMaps) {
shardok::FixedActionPointDistances
distances(hexMap, 0x1234, 0xABCD, battalionType, true, 5);
}
}
const auto end = system_clock::now();
std::cerr << duration_cast<microseconds>(end - start).count() << " µs" << '\n';
}
@@ -19,8 +19,6 @@
namespace shardok {
using std::unique_ptr;
using ResolvedUnitProto = net::eagle0::shardok::storage::ResolvedUnit;
using GameState = net::eagle0::shardok::storage::fb::GameState;
using GameStateT = net::eagle0::shardok::storage::fb::GameStateT;
@@ -249,12 +247,13 @@ void MutatingApplyResult(
internalAssert(mutatingGameState->mutable_status()->mutate_state(
static_cast<net::eagle0::shardok::storage::fb::GameStatus_::State>(
result.game_status().state())));
for (int i = 0; i < result.game_status().winning_shardok_ids_size(); i++) {
const int winningShardokIdCount = result.game_status().winning_shardok_ids_size();
for (int i = 0; i < winningShardokIdCount; i++) {
mutatingGameState->mutable_status()->mutable_winning_shardok_ids()->Mutate(
i,
result.game_status().winning_shardok_ids(i));
}
for (int i = result.game_status().winning_shardok_ids_size(); i < 10; i++) {
for (int i = winningShardokIdCount; i < 10; i++) {
mutatingGameState->mutable_status()->mutable_winning_shardok_ids()->Mutate(i, -1);
}
@@ -302,12 +301,6 @@ void MutatingApplyResult(
for (const auto &changedUnitBytes : result.changed_units_fb()) {
const Unit *changedUnit = &UnitFromBytes(changedUnitBytes);
if (changedUnit->battalion().type() ==
net::eagle0::shardok::storage::fb::BattalionTypeId_UNDEAD &&
changedUnit->battalion().morale() != 50.0) {
printf("bad morale\n");
}
internalAssert(
changedUnit->unit_id() < (int32_t)mutatingGameState->units()->size(),
"Got a changed unit outside acceptable range");
@@ -390,10 +383,11 @@ void MutatingApplyResult(
} else {
internalAssert(mutatingGameState->mutate_eligible_charger_id(-1));
}
for (int i = 0; i < result.possible_chargees_size(); i++) {
const int possibleChargeeCount = result.possible_chargees_size();
for (int i = 0; i < possibleChargeeCount; i++) {
mutatingGameState->mutable_possible_chargee_ids()->Mutate(i, result.possible_chargees(i));
}
for (int i = result.possible_chargees_size(); i < 6; i++) {
for (int i = possibleChargeeCount; i < 6; i++) {
mutatingGameState->mutable_possible_chargee_ids()->Mutate(i, -1);
}
@@ -19,8 +19,6 @@ using net::eagle0::shardok::storage::fb::VictoryCondition;
using PlayerInfoFb = net::eagle0::shardok::storage::fb::PlayerInfo;
using GameStatusFb = net::eagle0::shardok::storage::fb::GameStatus;
using GameStatusProto = net::eagle0::shardok::common::GameStatus;
using std::optional;
using std::unordered_set;
static inline auto GameIsOver(const GameStatusFb* status) -> bool {
return (status->state() == net::eagle0::shardok::storage::fb::GameStatus_::State_VICTORY);
@@ -41,12 +39,12 @@ static inline auto HasVictoryCondition(const PlayerInfoFb* pi, const VictoryCond
return false;
}
auto UpdateGameStatusAction::SurvivingPlayers() const -> unordered_set<PlayerId> {
auto UpdateGameStatusAction::SurvivingPlayers() const -> std::unordered_set<PlayerId> {
if (gameState->status()->state() ==
net::eagle0::shardok::storage::fb::GameStatus_::State_SET_UP)
return unordered_set<PlayerId>{};
return std::unordered_set<PlayerId>{};
unordered_set<PlayerId> survivingPids{};
std::unordered_set<PlayerId> survivingPids{};
for (const Unit* unit : *gameState->units()) {
if (unit->status() != net::eagle0::shardok::storage::fb::UnitStatus_NORMAL_UNIT) continue;
@@ -288,7 +286,7 @@ auto UpdateGameStatusAction::InternalExecute(
}
// Second check: allied players collectively holding all critical tiles
unordered_set<PlayerId> occupantPlayerIds{};
std::unordered_set<PlayerId> occupantPlayerIds{};
bool allTilesOccupiedWithHeroes = true;
for (const auto& criticalTile : criticalTileLocations) {
const auto* possibleOccupant = currentState.GetOccupant(criticalTile);
@@ -356,4 +354,4 @@ auto UpdateGameStatusAction::InternalExecute(
// If we got all the way through, keep the status as it is
return results;
}
} // namespace shardok
} // namespace shardok
@@ -16,7 +16,6 @@
#include "src/main/protobuf/net/eagle0/shardok/api/unit_view.pb.h"
namespace shardok {
using std::vector;
class ChallengeDuelCommandFactory : public CommandFactory {
private:
@@ -32,7 +31,7 @@ public:
ActionPoints remainingActionPoints,
const HexMap *map,
const Units *units,
const vector<PlayerId> &allyPids) const;
const std::vector<PlayerId> &allyPids) const;
void AddAvailableCommands(CommandList &commands, const CommandParams &params) const override;
};
@@ -4,6 +4,8 @@
#include "CommandFactoriesList.hpp"
#include <memory>
#include "src/main/cpp/net/eagle0/shardok/library/command_factories/BlowBridgeCommandFactory.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/command_factories/BraveWaterCommandFactory.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/command_factories/BuildBridgeCommandFactory.hpp"
@@ -34,42 +36,42 @@
namespace shardok {
using std::make_shared;
auto MakeFactories(const SettingsGetter& settings) -> vector<shared_ptr<const CommandFactory>> {
auto MakeFactories(const SettingsGetter& settings)
-> std::vector<std::shared_ptr<const CommandFactory>> {
// Command factories that produce "must-do" commands like Meteor Target should be first.
// Ultimately I should probably move that metadata into the CommandFactory and sort it here.
return {make_shared<MeteorTargetCommandFactory>(settings),
make_shared<ControlCommandFactory>(settings),
make_shared<ArcheryCommandFactory>(settings),
make_shared<BlowBridgeCommandFactory>(settings),
make_shared<BraveWaterCommandFactory>(settings),
make_shared<BuildBridgeCommandFactory>(settings),
make_shared<ChallengeDuelCommandFactory>(settings),
make_shared<ChargeCommandFactory>(settings),
make_shared<EvacuatePrisonersCommandFactory>(settings),
make_shared<ExtinguishFireCommandFactory>(settings),
make_shared<FearCommandFactory>(settings),
make_shared<FleeCommandFactory>(settings),
make_shared<FortifyCommandFactory>(settings),
make_shared<FreezeWaterCommandFactory>(settings),
make_shared<HideCommandFactory>(settings),
make_shared<HolyWaveCommandFactory>(settings),
make_shared<LightningBoltCommandFactory>(settings),
make_shared<MeleeCommandFactory>(settings),
make_shared<MeteorStartCommandFactory>(settings),
make_shared<RaiseDeadCommandFactory>(settings),
make_shared<ReduceCommandFactory>(settings),
make_shared<ReinforceCommandFactory>(settings),
make_shared<RepairCommandFactory>(settings),
make_shared<RetreatCommandFactory>(settings),
make_shared<ScoutCommandFactory>(settings),
make_shared<StartFireCommandFactory>(settings),
make_shared<MoveCommandFactory>(settings)};
return {std::make_shared<MeteorTargetCommandFactory>(settings),
std::make_shared<ControlCommandFactory>(settings),
std::make_shared<ArcheryCommandFactory>(settings),
std::make_shared<BlowBridgeCommandFactory>(settings),
std::make_shared<BraveWaterCommandFactory>(settings),
std::make_shared<BuildBridgeCommandFactory>(settings),
std::make_shared<ChallengeDuelCommandFactory>(settings),
std::make_shared<ChargeCommandFactory>(settings),
std::make_shared<EvacuatePrisonersCommandFactory>(settings),
std::make_shared<ExtinguishFireCommandFactory>(settings),
std::make_shared<FearCommandFactory>(settings),
std::make_shared<FleeCommandFactory>(settings),
std::make_shared<FortifyCommandFactory>(settings),
std::make_shared<FreezeWaterCommandFactory>(settings),
std::make_shared<HideCommandFactory>(settings),
std::make_shared<HolyWaveCommandFactory>(settings),
std::make_shared<LightningBoltCommandFactory>(settings),
std::make_shared<MeleeCommandFactory>(settings),
std::make_shared<MeteorStartCommandFactory>(settings),
std::make_shared<RaiseDeadCommandFactory>(settings),
std::make_shared<ReduceCommandFactory>(settings),
std::make_shared<ReinforceCommandFactory>(settings),
std::make_shared<RepairCommandFactory>(settings),
std::make_shared<RetreatCommandFactory>(settings),
std::make_shared<ScoutCommandFactory>(settings),
std::make_shared<StartFireCommandFactory>(settings),
std::make_shared<MoveCommandFactory>(settings)};
}
auto CommandFactoriesList::GetFactories() const -> vector<shared_ptr<const CommandFactory>> {
auto CommandFactoriesList::GetFactories() const
-> std::vector<std::shared_ptr<const CommandFactory>> {
return factories;
}
@@ -12,17 +12,14 @@
namespace shardok {
using std::shared_ptr;
using std::vector;
class CommandFactoriesList {
private:
vector<shared_ptr<const CommandFactory>> factories;
std::vector<std::shared_ptr<const CommandFactory>> factories;
public:
explicit CommandFactoriesList(const SettingsGetter& settings);
auto GetFactories() const -> vector<shared_ptr<const CommandFactory>>;
auto GetFactories() const -> std::vector<std::shared_ptr<const CommandFactory>>;
};
} // namespace shardok
@@ -15,7 +15,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
namespace shardok {
using std::vector;
class FearCommandFactory : public CommandFactory {
private:
@@ -31,7 +30,7 @@ public:
const Coords &position,
const HexMap *hexMap,
const Units *units,
const vector<PlayerId> &allyPids) const;
const std::vector<PlayerId> &allyPids) const;
void AddAvailableCommands(CommandList &commands, const CommandParams &params) const override;
};
@@ -12,7 +12,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
namespace shardok {
using std::vector;
class ScoutCommandFactory : public CommandFactory {
private:
@@ -11,7 +11,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/util/CombatUtils.hpp"
namespace shardok {
using std::vector;
ArcheryCommand::ArcheryCommand(
const SettingsGetter& settingsGetter,
@@ -32,7 +31,7 @@ ArcheryCommand::ArcheryCommand(
auto ArcheryCommand::InternalExecuteWithRoll(
const GameStateW& currentState,
const std::shared_ptr<RandomGenerator>& generator,
const std::optional<int32_t> roll) const -> vector<ActionResult> {
const std::optional<int32_t> roll) const -> std::vector<ActionResult> {
const auto ambushRoll = generator->Percentile();
const auto attackerRoll = roll.value_or(generator->OpenEndedPercentile());
return ExecuteWithRolls(currentState, ambushRoll, attackerRoll);
@@ -41,7 +40,7 @@ auto ArcheryCommand::InternalExecuteWithRoll(
[[nodiscard]] auto ArcheryCommand::ExecuteWithRolls(
const GameStateW& currentState,
double ambushRoll,
double attackerRoll) const -> vector<ActionResult> {
double attackerRoll) const -> std::vector<ActionResult> {
Unit attackerAfter = *currentState->units()->Get(attackerId);
MutatingSpendActionPoints(
&attackerAfter,
@@ -114,4 +113,4 @@ auto ArcheryCommand::GetCommandProto() const -> CommandProto {
return proto;
}
} // namespace shardok
} // namespace shardok
@@ -4,6 +4,8 @@
#include "RaiseDeadCommand.hpp"
#include <cstdint>
#include "src/main/cpp/net/eagle0/shardok/library/actions/ActionRequiresHeroException.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/ActionResultFlatbufferHelpers.hpp"
@@ -107,7 +109,7 @@ auto GetNewUnit(
unit.mutate_player_id(playerId);
unit.mutate_commanding_unit_id(commandingUnitId);
for (int i = 0; i < unit.opponent_knowledge()->size(); i++) {
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); i++) {
unit.mutable_opponent_knowledge()->Mutate(i, 0);
}
@@ -13,8 +13,6 @@
#include "src/main/cpp/net/eagle0/shardok/library/view_filters/UnitFilter.hpp"
namespace shardok {
using std::vector;
constexpr int NUM_RUNS = 10;
constexpr int COMBAT_ROUNDS = 50;
constexpr double BATTALION_STRENGTH_WEIGHT = 0.5;
@@ -28,8 +26,8 @@ auto GetAcceptOdds(
const Terrain &defenderTerrain) -> PercentileRollOdds {
net::eagle0::shardok::api::UnitView filteredView =
UnitFilteredForPlayer(settings, challenger, defender->player_id(), {});
vector<double> stats = {static_cast<double>(defender->attached_hero().bravery())};
vector<OtherFactor> otherFactors{};
std::vector<double> stats = {static_cast<double>(defender->attached_hero().bravery())};
std::vector<OtherFactor> otherFactors{};
Unit believedChallenger = *challenger;
MutatingSpendActionPoints(
@@ -8,9 +8,9 @@
#include <unistd.h>
#include <cerrno>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <mutex>
namespace shardok {
@@ -23,15 +23,15 @@ public:
mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
if (b == MAP_FAILED) {
std::fputs("mmap failed\n", stderr);
abort();
std::cerr << "mmap failed\n";
std::abort();
}
return b;
}
auto deallocate(uint8_t* buf, const size_t size) -> void override {
if (const auto result = munmap(buf, size); result != 0) {
std::fprintf(stderr, "munmap failed, errno %s\n", strerror(errno));
abort();
std::cerr << "munmap failed, errno " << strerror(errno) << '\n';
std::abort();
}
}
@@ -45,8 +45,8 @@ public:
auto* b = static_cast<uint8_t*>(malloc(size));
if (b == nullptr) {
std::fputs("malloc failed\n", stderr);
abort();
std::cerr << "malloc failed\n";
std::abort();
}
return b;
}
@@ -6,6 +6,9 @@
#include <flatbuffers/flatbuffers.h>
#include <unordered_map>
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/HexMapHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/InvalidProtoException.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
@@ -13,8 +16,6 @@
namespace shardok::fb {
using std::unique_ptr;
using std::unordered_map;
using namespace net::eagle0::shardok::storage::fb;
using GameStatusProto = net::eagle0::shardok::common::GameStatus;
@@ -44,12 +45,14 @@ auto ConvertVictoryCondition(const net::eagle0::shardok::common::VictoryConditio
auto FromPlayerInfoProto(flatbuffers::FlatBufferBuilder& fbb, const PlayerInfoProto& piProto)
-> flatbuffers::Offset<net::eagle0::shardok::storage::fb::PlayerInfo> {
auto alliesVec = vector<AlliedPlayer>();
auto alliesVec = std::vector<AlliedPlayer>();
for (const auto& apProto : piProto.allies()) { alliesVec.emplace_back(apProto.player_id()); }
const auto alliesOffset = fbb.CreateVectorOfStructs(alliesVec);
auto vcVec = vector<int8_t>();
for (int i = 0; i < piProto.victory_conditions_size(); i++) {
auto vcVec = std::vector<int8_t>();
const int victoryConditionCount = piProto.victory_conditions_size();
vcVec.reserve(victoryConditionCount);
for (int i = 0; i < victoryConditionCount; i++) {
vcVec.push_back(ConvertVictoryCondition(piProto.victory_conditions(i)));
}
const auto vcOffset = fbb.CreateVector(vcVec);
@@ -73,10 +76,10 @@ auto RequiredMonthlyFood(const Unit& unit, const SettingsGetter& settingsGetter)
}
auto FoodPercentageByPid(
const vector<PlayerInfoProto>& playerInfoProtos,
const vector<Unit>& units,
const SettingsGetter& settings) -> unordered_map<int, double> {
unordered_map<int, double> foodRequirementsByPid;
const std::vector<PlayerInfoProto>& playerInfoProtos,
const std::vector<Unit>& units,
const SettingsGetter& settings) -> std::unordered_map<int, double> {
std::unordered_map<int, double> foodRequirementsByPid;
for (const auto& unit : units) {
const auto cost = RequiredMonthlyFood(unit, settings);
if (foodRequirementsByPid.count(unit.player_id()) > 0) {
@@ -109,8 +112,8 @@ auto BaseMorale(const Unit& unit) -> double {
auto SetupInitialGameState(
const GameId& gameId,
const HexMapProto& hexMapProto,
const vector<PlayerInfoProto>& playerInfoProtos,
vector<Unit>& units,
const std::vector<PlayerInfoProto>& playerInfoProtos,
std::vector<Unit>& units,
int month,
bool isWinter,
const SettingsGetter& settings) -> GameStateW {
@@ -138,7 +141,7 @@ auto SetupInitialGameState(
&endGameCondition);
auto gameIdOffset = fbb.CreateString(gameId);
auto playerInfoVec = vector<Offset<PlayerInfo>>();
auto playerInfoVec = std::vector<Offset<PlayerInfo>>();
for (const auto& piProto : playerInfoProtos) {
playerInfoVec.push_back(FromPlayerInfoProto(fbb, piProto));
}
@@ -157,7 +160,7 @@ auto SetupInitialGameState(
// Add slack units: 3 per necromancer, minimum 5 for general use
int slackUnits = std::max(5, necromancerCount * 3);
auto unitsVec = vector<Unit>();
auto unitsVec = std::vector<Unit>();
unitsVec.reserve(units.size() + slackUnits);
for (const auto& unit : units) {
Unit modifiedUnit = unit;
@@ -200,7 +203,7 @@ auto SetupInitialGameState(
auto unitsOffset = fbb.CreateVectorOfSortedStructs(&unitsVec);
vector<UnitId> possibleChargeeIdsVec = {-1, -1, -1, -1, -1, -1};
std::vector<UnitId> possibleChargeeIdsVec = {-1, -1, -1, -1, -1, -1};
auto possibleChargeeIdsOffset = fbb.CreateVector(possibleChargeeIdsVec);
GameStateBuilder builder(fbb);
@@ -19,7 +19,6 @@
namespace shardok::fb {
using std::vector;
using HexMapProto = net::eagle0::shardok::common::HexMap;
using PlayerInfoProto = net::eagle0::shardok::common::PlayerInfo;
using net::eagle0::shardok::storage::fb::GameState;
@@ -32,8 +31,8 @@ using GameStatusProto = net::eagle0::shardok::common::GameStatus;
auto SetupInitialGameState(
const GameId& gameId,
const HexMapProto& hexMapProto,
const vector<PlayerInfoProto>& playerInfoProtos,
vector<Unit>& units,
const std::vector<PlayerInfoProto>& playerInfoProtos,
std::vector<Unit>& units,
int month,
bool isWinter,
const SettingsGetter& settings) -> GameStateW;
@@ -15,7 +15,6 @@ namespace shardok::fb {
using TerrainProto = net::eagle0::shardok::common::Terrain;
using namespace net::eagle0::shardok::storage::fb;
using std::vector;
auto ConvertType(const net::eagle0::shardok::common::Terrain_Type protoType) -> Terrain_::Type {
using namespace Terrain_;
@@ -50,7 +49,7 @@ auto CreateStartingPositionsList(
FlatBufferBuilder& fbb,
const net::eagle0::shardok::common::StartingPositionList& splProto)
-> Offset<StartingPositionList> {
vector<Coords> coordsVec;
std::vector<Coords> coordsVec;
coordsVec.reserve(splProto.positions_size());
for (const auto& position : splProto.positions()) {
coordsVec.emplace_back(position.row(), position.column());
@@ -120,14 +119,14 @@ auto ConvertHexMapProto(
const float initialWinterIceIntegrity) -> Offset<HexMap> {
const auto dspOffset = CreateStartingPositionsList(fbb, mapProto.defender_starting_positions());
vector<Offset<StartingPositionList>> asplOffsets;
std::vector<Offset<StartingPositionList>> asplOffsets;
asplOffsets.reserve(mapProto.attacker_starting_positions_size());
for (const auto& aspl : mapProto.attacker_starting_positions()) {
asplOffsets.push_back(CreateStartingPositionsList(fbb, aspl));
}
const auto aspOffset = fbb.CreateVector(asplOffsets);
vector<MonthlyWeather> monthlyWeatherVec;
std::vector<MonthlyWeather> monthlyWeatherVec;
monthlyWeatherVec.reserve(mapProto.monthly_weather_size());
for (const auto& mwp : mapProto.monthly_weather()) {
monthlyWeatherVec.emplace_back(
@@ -144,7 +143,7 @@ auto ConvertHexMapProto(
const auto monthlyWeatherOffset = fbb.CreateVectorOfStructs(monthlyWeatherVec);
const auto emptyModifier = SingleModifier(false, 0.0);
vector<Terrain> terrainVec;
std::vector<Terrain> terrainVec;
terrainVec.reserve(mapProto.terrain_size());
const bool calculateHash = mapProto.base_hash() == 0;
@@ -202,7 +201,7 @@ auto ConvertHexMapProto(
}
auto CopyStartingPositionsList(FlatBufferBuilder& fbb, const StartingPositionList* spl) {
vector<Coords> coordsVec = {};
std::vector<Coords> coordsVec = {};
if (spl && spl->positions()) {
coordsVec.reserve(spl->positions()->size());
@@ -216,17 +215,17 @@ auto CopyHexMap(const HexMap* hexMap) -> HexMapW {
FlatBufferBuilder fbb;
fbb.ForceDefaults(true);
vector<Terrain> terrainVec;
std::vector<Terrain> terrainVec;
terrainVec.reserve(hexMap->terrain()->size());
for (const auto* t : *hexMap->terrain()) terrainVec.push_back(*t);
const auto terrainOffset = fbb.CreateVectorOfStructs(terrainVec);
vector<MonthlyWeather> weatherVec;
std::vector<MonthlyWeather> weatherVec;
weatherVec.reserve(hexMap->monthly_weather()->size());
for (const auto* w : *hexMap->monthly_weather()) weatherVec.push_back(*w);
const auto weatherOffset = fbb.CreateVectorOfStructs(weatherVec);
vector<Offset<StartingPositionList>> asplVec = {};
std::vector<Offset<StartingPositionList>> asplVec = {};
asplVec.reserve(hexMap->attacker_starting_positions()->size());
for (const auto* spl : *hexMap->attacker_starting_positions()) {
asplVec.push_back(CopyStartingPositionsList(fbb, spl));
@@ -23,7 +23,6 @@ constexpr size_t STANDARD_SIZE = 12 * 14;
using HexMap = net::eagle0::shardok::storage::fb::HexMap;
using BackingBitset = common::IterableBitset<168>;
using std::vector;
class CoordsSet {
private:
@@ -101,8 +100,8 @@ public:
[[nodiscard]] auto empty() const -> bool { return store.empty(); }
// Should only be used for debugging.
[[nodiscard]] auto as_vector() const -> vector<Coords> {
return vector<Coords>{this->begin(), this->end()};
[[nodiscard]] auto as_vector() const -> std::vector<Coords> {
return std::vector<Coords>{this->begin(), this->end()};
}
auto operator+=(const CoordsSet& rhs) -> CoordsSet& {
@@ -14,7 +14,6 @@
namespace shardok {
using BattalionTypeId = net::eagle0::shardok::storage::fb::BattalionTypeId;
using std::vector;
const SettingsKeys kSettingsKeys = SettingsKeys();
@@ -12,7 +12,7 @@
namespace shardok {
auto SettingsLoader::LoadSettings() -> shared_ptr<GameSettings> {
auto SettingsLoader::LoadSettings() -> std::shared_ptr<GameSettings> {
auto gameSettings = std::make_shared<GameSettings>();
auto setter = gameSettings->GetSetter();
@@ -11,11 +11,9 @@
namespace shardok {
using std::shared_ptr;
class SettingsLoader {
public:
static auto LoadSettings() -> shared_ptr<GameSettings>;
static auto LoadSettings() -> std::shared_ptr<GameSettings>;
};
} // namespace shardok
@@ -11,7 +11,6 @@
#include <limits>
#include <optional>
#include <string>
#include "src/main/cpp/net/eagle0/shardok/library/ActionCost.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/CombatDamage.hpp"
@@ -23,7 +22,6 @@
#pragma GCC diagnostic pop
namespace shardok {
using std::string;
using Hero = net::eagle0::shardok::storage::fb::Hero;
@@ -9,6 +9,7 @@
#include "src/main/cpp/net/eagle0/shardok/library/unit/Unit.hpp"
#include <algorithm>
#include <cstdint>
#include <utility>
namespace shardok {
@@ -44,7 +45,7 @@ auto OpponentKnowledge(const Unit &unit, const PlayerId toPlayer) -> int {
if (toPlayer == -1) {
// handle observer, with pid -1
int8_t max = 0;
for (int i = 0; i < unit.opponent_knowledge()->size(); i++) {
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); i++) {
max = std::max(max, unit.opponent_knowledge()->Get(i));
}
return max;
@@ -58,7 +59,7 @@ auto OpponentKnowledge(const Unit *unit, const PlayerId toPlayer) -> int {
if (toPlayer == -1) {
// handle observer, with pid -1
int8_t max = 0;
for (int i = 0; i < unit->opponent_knowledge()->size(); i++) {
for (uint32_t i = 0; i < unit->opponent_knowledge()->size(); i++) {
max = std::max(max, unit->opponent_knowledge()->Get(i));
}
return max;
@@ -189,7 +190,7 @@ void MutatingBumpOpponentKnowledge(Unit *unit, const PlayerId pid, const int bum
void MutatingBumpAllKnowledgeToMinimum(Unit *unit, const int minimum) {
const auto current = unit->opponent_knowledge();
for (int i = 0; i < current->size(); i++) {
for (uint32_t i = 0; i < current->size(); i++) {
if (current->Get(i) < minimum) { unit->mutable_opponent_knowledge()->Mutate(i, minimum); }
}
}
@@ -9,6 +9,8 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_UNIT_UNIT_HPP
#define EAGLE0_SHARDOK_LIBRARY_UNIT_UNIT_HPP
#include <map>
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
#include "src/main/cpp/net/eagle0/shardok/library/settings/GameSettings.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/unit/Battalion.hpp"
@@ -20,7 +22,6 @@ namespace shardok {
using std::begin;
using std::end;
using std::find_if;
using std::map;
using std::optional;
using std::remove_if;
@@ -76,8 +77,8 @@ void MutatingBumpCharismaXp(Unit *unit, int newXp);
void MutatingBumpOpponentKnowledge(Unit *unit, PlayerId pid, int bump);
void MutatingBumpAllKnowledgeToMinimum(Unit *unit, int bump);
auto ReserveUnitsForPlayer(const Units *units, PlayerId pid) -> map<UnitId, const Unit *>;
auto PlacedUnitsForPlayer(const Units *units, PlayerId pid) -> map<UnitId, const Unit *>;
auto ReserveUnitsForPlayer(const Units *units, PlayerId pid) -> std::map<UnitId, const Unit *>;
auto PlacedUnitsForPlayer(const Units *units, PlayerId pid) -> std::map<UnitId, const Unit *>;
} // namespace shardok
@@ -12,7 +12,6 @@
namespace shardok {
using std::string;
using ActionResult = net::eagle0::shardok::storage::ActionResult;
using ResolvedUnit = net::eagle0::shardok::storage::ResolvedUnit;
using Unit = net::eagle0::shardok::storage::fb::Unit;
@@ -22,7 +21,7 @@ static inline void AddChangedUnit(ActionResult& result, const Unit& unit) {
}
static inline void AddUnitToResolved(ResolvedUnit& resolvedUnit, const Unit& unit) {
*resolvedUnit.mutable_unit_bytes() = string((char*)&unit, sizeof(Unit));
*resolvedUnit.mutable_unit_bytes() = std::string((char*)&unit, sizeof(Unit));
}
} // namespace shardok
@@ -18,7 +18,6 @@ namespace shardok {
using net::eagle0::shardok::common::ActionType;
using net::eagle0::shardok::storage::ActionResult;
using std::vector;
using BattalionFb = net::eagle0::shardok::storage::fb::Battalion;
using HeroFb = net::eagle0::shardok::storage::fb::Hero;
@@ -26,8 +26,8 @@ auto CubeToOffset(const Cube &cube) -> Coords {
return Coords(row, column);
}
auto CubesWithinDistance(const Cube &c1, const int distance) -> vector<Cube> {
vector<Cube> cubes{};
auto CubesWithinDistance(const Cube &c1, const int distance) -> std::vector<Cube> {
std::vector<Cube> cubes{};
for (int x = -distance; x <= distance; x++) {
for (int y = std::max(-distance, -x - distance); y <= std::min(distance, -x + distance);
@@ -40,8 +40,8 @@ auto CubesWithinDistance(const Cube &c1, const int distance) -> vector<Cube> {
return cubes;
}
auto CubesWithExactDistance(const Cube &c1, const int distance) -> vector<Cube> {
vector<Cube> cubes{};
auto CubesWithExactDistance(const Cube &c1, const int distance) -> std::vector<Cube> {
std::vector<Cube> cubes{};
for (int x = -distance; x <= distance; x++) {
for (int y = std::max(-distance, -x - distance); y <= std::min(distance, -x + distance);
@@ -76,7 +76,7 @@ auto FixupCube(
// Always rounds half up, instead of away from zero.
auto RoundHalfUp(const double d) -> double { return std::floor(d + 0.5); }
auto CubeLerp(const Cube &c1, const Cube &c2, const double t) -> vector<Cube> {
auto CubeLerp(const Cube &c1, const Cube &c2, const double t) -> std::vector<Cube> {
const auto floatX = std::lerp(c1.x, c2.x, t);
const auto newX = RoundHalfUp(floatX);
const auto xDiff = abs(newX - floatX);
@@ -89,7 +89,7 @@ auto CubeLerp(const Cube &c1, const Cube &c2, const double t) -> vector<Cube> {
const auto newZ = RoundHalfUp(floatZ);
const auto zDiff = abs(newZ - floatZ);
vector<Cube> cubes{};
std::vector<Cube> cubes{};
cubes.push_back(FixupCube(newX, xDiff, newY, yDiff, newZ, zDiff));
// The 0.5 case represents a situation where the line passes exactly between two hexes. In that
@@ -107,8 +107,8 @@ auto CubeLerp(const Cube &c1, const Cube &c2, const double t) -> vector<Cube> {
// Slight variation of the method described in
// https://www.redblobgames.com/grids/hexagons/#line-drawing
// When rounding, we include *both* hexes for the in-between case.
auto CubeLineInclusive(const Cube &c1, const Cube &c2) -> vector<Cube> {
vector<Cube> cubes;
auto CubeLineInclusive(const Cube &c1, const Cube &c2) -> std::vector<Cube> {
std::vector<Cube> cubes;
const auto dist = CubeDistance(c1, c2);
const double reciprocal = 1.0 / dist;
@@ -120,4 +120,4 @@ auto CubeLineInclusive(const Cube &c1, const Cube &c2) -> vector<Cube> {
return cubes;
}
} // namespace shardok
} // namespace shardok
@@ -5,12 +5,12 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_UTIL_HEX_CUBE_UTILS_HPP
#define EAGLE0_SHARDOK_LIBRARY_UTIL_HEX_CUBE_UTILS_HPP
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/map/Coordinates.hpp"
namespace shardok {
using std::vector;
struct Cube {
int16_t x;
int16_t y;
@@ -28,12 +28,12 @@ static inline auto CubeDistance(const Cube &c1, const Cube &c2) -> int {
return (abs(c1.x - c2.x) + abs(c1.y - c2.y) + abs(c1.z - c2.z)) / 2;
}
auto CubesWithinDistance(const Cube &c1, int distance) -> vector<Cube>;
auto CubesWithExactDistance(const Cube &c1, int distance) -> vector<Cube>;
auto CubesWithinDistance(const Cube &c1, int distance) -> std::vector<Cube>;
auto CubesWithExactDistance(const Cube &c1, int distance) -> std::vector<Cube>;
// Returns all the hexes that are on the line between c1 and c2, including the endpoints.
// In a case where the line passes exactly between two hexes, includes BOTH hexes.
auto CubeLineInclusive(const Cube &c1, const Cube &c2) -> vector<Cube>;
auto CubeLineInclusive(const Cube &c1, const Cube &c2) -> std::vector<Cube>;
} // namespace shardok
@@ -9,6 +9,7 @@
#include "HexMapUtils.hpp"
#include <algorithm>
#include <memory>
#include <ranges>
#include "HexCubeUtils.hpp"
@@ -17,9 +18,6 @@
namespace shardok {
using std::any_of;
using std::begin;
using std::end;
using Terrain = net::eagle0::shardok::storage::fb::Terrain;
const vector<Coords> ADJACENT_TILE_MODS_EVEN_ROW =
@@ -88,13 +86,16 @@ auto HasForestAccess(
const CoordsSet adjacentCoords = HexMapUtils::GetAdjacentCoords(hexMap, coords);
return any_of(begin(adjacentCoords), end(adjacentCoords), [&](const Coords &adjCoords) {
if (KnownEnemyOccupant(player, units, allyPids, adjCoords)) return false;
if (GetTerrain(hexMap, adjCoords)->type() ==
net::eagle0::shardok::storage::fb::Terrain_::Type_FOREST)
return true;
return false;
});
return std::any_of(
std::begin(adjacentCoords),
std::end(adjacentCoords),
[&](const Coords &adjCoords) {
if (KnownEnemyOccupant(player, units, allyPids, adjCoords)) return false;
if (GetTerrain(hexMap, adjCoords)->type() ==
net::eagle0::shardok::storage::fb::Terrain_::Type_FOREST)
return true;
return false;
});
}
const std::vector<CoordsSet> HexMapUtils::standardCoords =
@@ -160,16 +161,18 @@ auto HexMapUtils::GetAdjacentCoords(const HexMap *map, const Coords &origin) ->
// the standard map size, and tests usually use something else. So let's use some statics here
// for tests, knowing that we generally make a new one between runs.
static std::vector<CoordsSet *> *cachedCoords = nullptr;
if (cachedCoords == nullptr) {
cachedCoords = new vector<CoordsSet *>(map->column_count() * map->row_count());
static std::vector<std::unique_ptr<CoordsSet>> cachedCoords;
const auto mapSize = map->column_count() * map->row_count();
if (cachedCoords.size() != static_cast<size_t>(mapSize)) {
cachedCoords.clear();
cachedCoords.resize(mapSize);
}
const auto index = origin.row() * map->column_count() + origin.column();
if ((*cachedCoords)[index] == nullptr) {
(*cachedCoords)[index] =
new CoordsSet(ComputeAdjacentCoords(map->row_count(), map->column_count(), origin));
if (cachedCoords[index] == nullptr) {
cachedCoords[index] = std::make_unique<CoordsSet>(
ComputeAdjacentCoords(map->row_count(), map->column_count(), origin));
}
return *(*cachedCoords)[index];
return *cachedCoords[index];
}
auto HexMapUtils::GetAdjacentTiles(const HexMap *map, const Coords &origin)
@@ -324,7 +327,7 @@ void MaybeAdd(const Cube &cube, CoordsSet &set, const HexMap *map) {
const auto c2 = OffsetToCube(coords2);
auto line = CubeLineInclusive(c1, c2);
return std::any_of(begin(line), end(line), [&map](const Cube &c) {
return std::any_of(std::begin(line), std::end(line), [&map](const Cube &c) {
const auto betweenCoords = CubeToOffset(c);
if (CoordsAreValid(map, betweenCoords) &&
GetTerrain(map, betweenCoords)->type() ==
@@ -30,7 +30,7 @@ auto NextPlayerId(const GameState *gameState, const PlayerId pid, const bool all
return nextPid;
}
auto AlliedPids(const GameState *gameState, int playerId) -> vector<PlayerId> {
auto AlliedPids(const GameState *gameState, int playerId) -> std::vector<PlayerId> {
if (gameState->player_infos() == nullptr) return {};
const auto &pi = std::find_if(
std::begin(*gameState->player_infos()),
@@ -38,7 +38,7 @@ auto AlliedPids(const GameState *gameState, int playerId) -> vector<PlayerId> {
[playerId](const PlayerInfoFb *pi) { return pi->player_id() == playerId; });
if (pi == std::end(*gameState->player_infos())) { return std::vector<PlayerId>{}; }
vector<PlayerId> allyPids{};
std::vector<PlayerId> allyPids{};
if (pi->allies()) {
for (const auto &ally : *pi->allies()) { allyPids.push_back(ally->player_id()); }
@@ -5,6 +5,8 @@
#ifndef EAGLE0_SHARDOK_LIBRARY_UTIL_PLAYER_UTILS_HPP
#define EAGLE0_SHARDOK_LIBRARY_UTIL_PLAYER_UTILS_HPP
#include <vector>
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/game_state.hpp"
@@ -12,12 +14,11 @@ namespace shardok {
using PlayerInfoFb = net::eagle0::shardok::storage::fb::PlayerInfo;
using GameState = net::eagle0::shardok::storage::fb::GameState;
using std::vector;
auto PlayerIsDefender(const GameState *gameState, int playerId) -> bool;
auto NextPlayerId(const GameState *gameState, PlayerId pid, bool allowUncontrolled = true)
-> PlayerId;
auto AlliedPids(const GameState *gameState, int playerId) -> vector<PlayerId>;
auto AlliedPids(const GameState *gameState, int playerId) -> std::vector<PlayerId>;
} // namespace shardok
@@ -4,6 +4,7 @@
#include "src/main/cpp/net/eagle0/shardok/library/view_filters/GameStateGuesser.hpp"
#include <cstdint>
#include <optional>
#include <vector>
@@ -15,10 +16,6 @@
namespace shardok {
using std::begin;
using std::end;
using std::vector;
using flatbuffers::FlatBufferBuilder;
using flatbuffers::Offset;
@@ -156,7 +153,7 @@ auto GameStateGuesser::GuessedState(
auto gameIdOffset = fbb.CreateString(gameStateView.game_id());
vector<Offset<net::eagle0::shardok::storage::fb::PlayerInfo>> piVec{};
std::vector<Offset<net::eagle0::shardok::storage::fb::PlayerInfo>> piVec{};
for (const PlayerInfoProto &pi : gameStateView.player_infos()) {
piVec.push_back(fb::FromPlayerInfoProto(fbb, pi));
}
@@ -164,9 +161,9 @@ auto GameStateGuesser::GuessedState(
auto statusDescription = fbb.CreateString(gameStateView.status().description());
vector<PlayerId> winningShardokIdsVec = {
begin(gameStateView.status().winning_shardok_ids()),
end(gameStateView.status().winning_shardok_ids())};
std::vector<PlayerId> winningShardokIdsVec = {
std::begin(gameStateView.status().winning_shardok_ids()),
std::end(gameStateView.status().winning_shardok_ids())};
for (int i = gameStateView.status().winning_shardok_ids_size(); i < 10; i++) {
winningShardokIdsVec.push_back(-1);
}
@@ -211,8 +208,8 @@ auto GameStateGuesser::GuessedState(
bool foundDefender = false;
UnitId maxId = 0;
vector<UnitId> foundUnits{};
vector<Unit> unitsVec{};
std::vector<UnitId> foundUnits{};
std::vector<Unit> unitsVec{};
for (const auto &uv : gameStateView.units()) {
unitsVec.push_back(GuessedUnit(
settings,
@@ -348,8 +345,8 @@ auto GameStateGuesser::GuessedState(
auto unitsOffset = fbb.CreateVectorOfSortedStructs(&unitsVec);
auto chargeeIdsVec = std::vector<UnitId>(
begin(gameStateView.possible_chargee_ids()),
end(gameStateView.possible_chargee_ids()));
std::begin(gameStateView.possible_chargee_ids()),
std::end(gameStateView.possible_chargee_ids()));
for (int i = gameStateView.possible_chargee_ids_size(); i < 6; i++) {
chargeeIdsVec.push_back(-1);
}
@@ -481,7 +478,7 @@ auto GuessedUnit(
unit.mutate_has_moved_in_zoc(uv.has_moved_in_zoc());
for (int i = 0; i < unit.opponent_knowledge()->size(); i++) {
for (uint32_t i = 0; i < unit.opponent_knowledge()->size(); i++) {
unit.mutable_opponent_knowledge()->Mutate(i, 0);
}
unit.mutable_opponent_knowledge()->Mutate(toPid, uv.my_knowledge());
@@ -693,4 +690,4 @@ auto KnownUnitStats(const GameStateView &gameStateView)
return result;
}
} // namespace shardok
} // namespace shardok
@@ -146,9 +146,11 @@ auto MakeGameStateViewDiff(const GameStateView &before, const GameStateView &aft
changed = true;
}
for (int i = 0; i < after.player_totals_size(); i++) {
const int afterPlayerTotalCount = after.player_totals_size();
const int beforePlayerTotalCount = before.player_totals_size();
for (int i = 0; i < afterPlayerTotalCount; i++) {
const auto &afterTotal = after.player_totals(i);
if (before.player_totals_size() <= i) {
if (beforePlayerTotalCount <= i) {
*diff.add_changed_player_totals() = afterTotal;
} else {
const auto &beforeTotal = before.player_totals(i);
@@ -164,4 +166,4 @@ auto MakeGameStateViewDiff(const GameStateView &before, const GameStateView &aft
return changed ? diff : std::optional<GameStateViewDiff>();
}
} // namespace shardok
} // namespace shardok
@@ -17,7 +17,6 @@ namespace shardok {
using net::eagle0::shardok::api::UnitView;
using net::eagle0::shardok::common::CommandType;
using std::vector;
auto UnknownUnit(
UnitId uid,
@@ -14,7 +14,6 @@ namespace shardok {
using net::eagle0::shardok::api::UnitView;
using Unit = net::eagle0::shardok::storage::fb::Unit;
using std::vector;
[[nodiscard]] auto UnitFilteredForPlayer(
const SettingsGetter &settings,
@@ -110,7 +110,9 @@ auto ConvertPlayerInfo(
const int32_t eagleFactionId = pi.eagle_faction_id();
vector<PlayerId> allPids{};
for (int i = 0; i < allPis.size(); i++) { allPids.push_back(i); }
const int playerInfoCount = allPis.size();
allPids.reserve(playerInfoCount);
for (int i = 0; i < playerInfoCount; i++) { allPids.push_back(static_cast<PlayerId>(i)); }
vector<Unit> shardokUnits;
shardokUnits.reserve(pi.units().size());
@@ -132,9 +134,9 @@ auto ConvertPlayerInfo(
alliedPids.reserve(pi.allies_size());
for (const auto &ally : pi.allies()) {
const int32_t alliedFid = ally.eagle_faction_id();
for (int i = 0; i < allPis.size(); i++) {
for (int i = 0; i < playerInfoCount; i++) {
if (allPis[i].eagle_faction_id() == alliedFid) {
alliedPids.push_back(i);
alliedPids.push_back(static_cast<PlayerId>(i));
break;
}
}
@@ -182,8 +184,9 @@ void EagleInterfaceImpl::StartGame(const NewGameRequest &request) {
// Convert each interface player struct into the Shardok storage equivalents
vector<PlayerInfoWithUnits> playersInfo{};
playersInfo.reserve(request.user_infos_size());
for (int i = 0; i < request.user_infos_size(); i++) {
const int userInfoCount = request.user_infos_size();
playersInfo.reserve(userInfoCount);
for (int i = 0; i < userInfoCount; i++) {
playersInfo.push_back(ConvertPlayerInfo(request.user_infos(), static_cast<PlayerId>(i)));
}
@@ -218,7 +221,7 @@ void EagleInterfaceImpl::StartGame(const NewGameRequest &request) {
watcherAllies.reserve(request.watcher_eagle_faction_ids_size());
for (const int32_t watcherFid : request.watcher_eagle_faction_ids()) {
std::vector<PlayerId> allyPids;
for (int i = 0; i < request.user_infos_size(); i++) {
for (int i = 0; i < userInfoCount; i++) {
for (const auto &ally : request.user_infos(i).allies()) {
if (ally.eagle_faction_id() == watcherFid) {
allyPids.push_back(static_cast<PlayerId>(i));
@@ -14,12 +14,10 @@
namespace shardok {
using net::eagle0::common::VictoryCondition;
using std::string;
using std::vector;
namespace {
auto EagleFactionIdForPlayer(
const vector<net::eagle0::shardok::common::PlayerInfo> &resolvedPlayerInfos,
const std::vector<net::eagle0::shardok::common::PlayerInfo> &resolvedPlayerInfos,
const PlayerId playerId) -> std::optional<int32_t> {
const auto it = std::ranges::find_if(
resolvedPlayerInfos,
@@ -32,10 +30,10 @@ auto EagleFactionIdForPlayer(
} // namespace
auto PopulateGameOverResponse(
const string &gameId,
const std::string &gameId,
const net::eagle0::shardok::common::GameStatus &gameStatus,
const vector<net::eagle0::shardok::common::PlayerInfo> &resolvedPlayerInfos,
const vector<net::eagle0::shardok::storage::ResolvedUnit> &resolvedUnits,
const std::vector<net::eagle0::shardok::common::PlayerInfo> &resolvedPlayerInfos,
const std::vector<net::eagle0::shardok::storage::ResolvedUnit> &resolvedUnits,
net::eagle0::common::GameOverResponse *gameOverResponse) -> bool {
const auto &endCondition = gameStatus.end_game_condition();
@@ -19,32 +19,30 @@
#ifdef __clang__
#pragma GCC diagnostic ignored "-Wexit-time-destructors"
#endif
const string ServerConfiguration::kShardokGrpcAddress = "shardokGrpcAddress";
const string ServerConfiguration::kEagleInterfaceGrpcAddress = "eagleInterfaceGrpcAddress";
const string ServerConfiguration::kEagleGrpcAddress = "eagleGrpcAddress";
const string ServerConfiguration::kSslCertPath = "sslCertPath";
const string ServerConfiguration::kSslPrivateKeyPath = "sslPrivateKeyPath";
const string ServerConfiguration::kAuthTokenPath = "authTokenPath";
const std::string ServerConfiguration::kShardokGrpcAddress = "shardokGrpcAddress";
const std::string ServerConfiguration::kEagleInterfaceGrpcAddress = "eagleInterfaceGrpcAddress";
const std::string ServerConfiguration::kEagleGrpcAddress = "eagleGrpcAddress";
const std::string ServerConfiguration::kSslCertPath = "sslCertPath";
const std::string ServerConfiguration::kSslPrivateKeyPath = "sslPrivateKeyPath";
const std::string ServerConfiguration::kAuthTokenPath = "authTokenPath";
#pragma GCC diagnostic pop
using std::unordered_map;
std::unordered_map<std::string, std::string> DefaultValues();
unordered_map<string, string> DefaultValues();
unordered_map<string, string> DefaultValues() {
std::unordered_map<std::string, std::string> DefaultValues() {
// Check environment variables for Docker deployment
// Docker containers should set SHARDOK_EAGLE_INTERFACE_ADDRESS=0.0.0.0:40042
// to listen on all interfaces for container networking
const char* eagleInterfaceAddr = getenv("SHARDOK_EAGLE_INTERFACE_ADDRESS");
const char* shardokAddr = getenv("SHARDOK_GRPC_ADDRESS");
return unordered_map<string, string>{
return std::unordered_map<std::string, std::string>{
{ServerConfiguration::kShardokGrpcAddress, shardokAddr ? shardokAddr : "localhost"},
{ServerConfiguration::kEagleInterfaceGrpcAddress,
eagleInterfaceAddr ? eagleInterfaceAddr : "localhost:40042"}};
}
ServerConfiguration::ServerConfiguration(const string& filePath) {
ServerConfiguration::ServerConfiguration(const std::string& filePath) {
if (!FilesystemUtils::FileExistsAtPath(filePath)) {
std::cerr << "Config file not found at " << filePath << '\n';
configValues = DefaultValues();
@@ -56,20 +54,22 @@ ServerConfiguration::ServerConfiguration(const string& filePath) {
while (!istr.eof()) {
istr.getline(line, 256);
if (strnlen(line, 256) < 3) continue;
string key = strtok(line, " =");
string value = strtok(nullptr, " =");
std::string key = strtok(line, " =");
std::string value = strtok(nullptr, " =");
configValues[key] = value;
}
}
int ServerConfiguration::intForKey(const string& key, const int defaultValue) {
int ServerConfiguration::intForKey(const std::string& key, const int defaultValue) {
const auto foundVal = configValues.find(key);
if (foundVal == configValues.end()) { return defaultValue; }
return std::stoi(foundVal->second);
}
string ServerConfiguration::stringForKey(const string& key, const string& defaultValue) {
std::string ServerConfiguration::stringForKey(
const std::string& key,
const std::string& defaultValue) {
const auto foundVal = configValues.find(key);
if (foundVal == configValues.end()) { return defaultValue; }
return foundVal->second;
@@ -12,24 +12,22 @@
#include <string>
#include <unordered_map>
using std::string;
class ServerConfiguration {
private:
std::unordered_map<string, string> configValues;
std::unordered_map<std::string, std::string> configValues;
public:
explicit ServerConfiguration(const string& filePath);
explicit ServerConfiguration(const std::string& filePath);
int intForKey(const string& key, int defaultValue = 0);
string stringForKey(const string& key, const string& defaultValue = "");
int intForKey(const std::string& key, int defaultValue = 0);
std::string stringForKey(const std::string& key, const std::string& defaultValue = "");
const static string kShardokGrpcAddress;
const static string kEagleInterfaceGrpcAddress;
const static string kEagleGrpcAddress;
const static string kSslCertPath;
const static string kSslPrivateKeyPath;
const static string kAuthTokenPath;
const static std::string kShardokGrpcAddress;
const static std::string kEagleInterfaceGrpcAddress;
const static std::string kEagleGrpcAddress;
const static std::string kSslCertPath;
const static std::string kSslPrivateKeyPath;
const static std::string kAuthTokenPath;
};
#endif // EAGLE0_SHARDOK_SERVER_SERVER_CONFIGURATION_HPP
@@ -23,27 +23,27 @@
#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit.hpp"
namespace shardok {
using std::shared_ptr;
auto SetUpController(
const GameSettingsSPtr &gameSettings,
const GameId &gameId,
const string &mapName,
const string &customMapBytes,
const std::string &mapName,
const std::string &customMapBytes,
int month,
const vector<Unit> &units,
const vector<PlayerInfoProto> &playerSetupInfos,
const std::vector<Unit> &units,
const std::vector<PlayerInfoProto> &playerSetupInfos,
const TutorialBattleConfigProto &tutorialConfig,
const string &serializedRequest,
const std::string &serializedRequest,
const std::vector<std::pair<int32_t, std::vector<PlayerId>>> &watcherAllies = {})
-> shared_ptr<ShardokGameController>;
-> std::shared_ptr<ShardokGameController>;
ShardokGamesManager::ShardokGamesManager(const std::vector<std::string> &extraSettings) {
gameSettings = SettingsLoader::LoadSettings();
for (const string &str : extraSettings) {
for (const std::string &str : extraSettings) {
std::stringstream stream(str);
string key, value;
std::string key;
std::string value;
std::getline(stream, key, '=');
std::getline(stream, value);
std::cerr << key << " << " << value << '\n';
@@ -69,7 +69,7 @@ void ShardokGamesManager::RemoveController(const GameId &gameId) {
auto ShardokGamesManager::UnlockedCreateFromGameStateBytes(
const byte_vector &gameStateBytes,
int32_t startingHistoryCount,
const string &mapName) -> GameId {
const std::string &mapName) -> GameId {
std::unique_lock<std::shared_mutex> lk(runningControllersLock);
auto gs = GameStateW::FromByteVector(gameStateBytes);
@@ -83,13 +83,13 @@ auto ShardokGamesManager::UnlockedCreateFromGameStateBytes(
}
auto ShardokGamesManager::UnlockedCreateSpecifiedGame(
const string &gameId,
const vector<PlayerInfoWithUnits> &playerSetupInfos,
const string &mapName,
const string &customMapBytes,
const std::string &gameId,
const std::vector<PlayerInfoWithUnits> &playerSetupInfos,
const std::string &mapName,
const std::string &customMapBytes,
const int month,
const TutorialBattleConfigProto &tutorialConfig,
const string &serializedRequest,
const std::string &serializedRequest,
const std::vector<std::pair<int32_t, std::vector<PlayerId>>> &watcherAllies) -> GameId {
// Check for existing game with this ID and early-exit
std::unique_lock<std::shared_mutex> lk(runningControllersLock);
@@ -104,19 +104,19 @@ auto ShardokGamesManager::UnlockedCreateSpecifiedGame(
return gameId;
}
vector<PlayerInfoProto> playerInfos{};
std::vector<PlayerInfoProto> playerInfos{};
std::transform(
std::begin(playerSetupInfos),
std::end(playerSetupInfos),
std::back_inserter(playerInfos),
[](const PlayerInfoWithUnits &psi) { return psi.playerInfo; });
vector<Unit> units{};
std::vector<Unit> units{};
for (const auto &info : playerSetupInfos) {
units.insert(std::end(units), std::begin(info.units), std::end(info.units));
}
const shared_ptr<ShardokGameController> controller = SetUpController(
const std::shared_ptr<ShardokGameController> controller = SetUpController(
gameSettings,
gameId,
mapName,
@@ -132,9 +132,9 @@ auto ShardokGamesManager::UnlockedCreateSpecifiedGame(
}
auto ShardokGamesManager::LockedCreateGame(
const shared_ptr<ShardokGameController> &controller,
const vector<PlayerInfoWithUnits> & /*playerInfos*/,
const string & /*serializedRequest*/) -> GameId {
const std::shared_ptr<ShardokGameController> &controller,
const std::vector<PlayerInfoWithUnits> & /*playerInfos*/,
const std::string & /*serializedRequest*/) -> GameId {
std::vector<std::shared_ptr<ShardokAIClient>> aiClients{};
GameId newGameId = controller->GetGameId();
@@ -147,15 +147,15 @@ auto ShardokGamesManager::LockedCreateGame(
auto SetUpController(
const GameSettingsSPtr &gameSettings,
const GameId &gameId,
const string &mapName,
const string &customMapBytes,
const std::string &mapName,
const std::string &customMapBytes,
const int month,
const vector<Unit> &units,
const vector<PlayerInfoProto> &playerInfos,
const std::vector<Unit> &units,
const std::vector<PlayerInfoProto> &playerInfos,
const TutorialBattleConfigProto &tutorialConfig,
const string &serializedRequest,
const std::string &serializedRequest,
const std::vector<std::pair<int32_t, std::vector<PlayerId>>> &watcherAllies)
-> shared_ptr<ShardokGameController> {
-> std::shared_ptr<ShardokGameController> {
auto unplacedUnits = std::vector<Unit>();
UnitId nextUnitId = 0;
@@ -187,7 +187,7 @@ auto SetUpController(
// These units exist in the game state from the start but are invisible and inactive
// until the TutorialBattleController activates them at the triggered round.
if (tutorialConfig.enabled()) {
vector<PlayerId> allPlayerIds;
std::vector<PlayerId> allPlayerIds;
for (size_t i = 0; i < playerInfos.size(); i++) {
allPlayerIds.push_back(static_cast<PlayerId>(i));
}
@@ -27,8 +27,6 @@ class GameStatePersister;
using net::eagle0::shardok::common::GameStatus;
using PlayerInfoProto = net::eagle0::shardok::common::PlayerInfo;
using TutorialBattleConfigProto = net::eagle0::common::TutorialBattleConfig;
using std::string;
using std::vector;
using VictoryConditionProto = net::eagle0::shardok::common::VictoryCondition;
namespace shardok {
@@ -38,14 +36,14 @@ class ShardokGameController;
struct PlayerInfoWithUnits {
public:
const PlayerInfoProto playerInfo;
const vector<Unit> units;
const std::vector<Unit> units;
static auto MakePlayerInfo(
const PlayerId pid,
const bool def,
const int food,
const vector<VictoryConditionProto> &victoryConditions,
const vector<PlayerId> &alliedPids,
const std::vector<VictoryConditionProto> &victoryConditions,
const std::vector<PlayerId> &alliedPids,
const int32_t eagleFactionId,
const bool isAi,
const bool cannotBecomeOutlaw) -> PlayerInfoProto {
@@ -68,9 +66,9 @@ public:
const int32_t eagleFactionId,
const bool def,
const int food,
const vector<VictoryConditionProto> &victoryConditions,
const vector<PlayerId> &alliedPids,
vector<Unit> us,
const std::vector<VictoryConditionProto> &victoryConditions,
const std::vector<PlayerId> &alliedPids,
std::vector<Unit> us,
const bool cannotBecomeOutlaw)
: playerInfo(MakePlayerInfo(
pid,
@@ -93,8 +91,8 @@ private:
auto LockedCreateGame(
const std::shared_ptr<ShardokGameController> &controller,
const vector<PlayerInfoWithUnits> &playerInfos,
const string &serializedRequest) -> GameId;
const std::vector<PlayerInfoWithUnits> &playerInfos,
const std::string &serializedRequest) -> GameId;
public:
explicit ShardokGamesManager(const std::vector<std::string> &extraSettings);
@@ -105,19 +103,19 @@ public:
auto UnlockedCreateSpecifiedGame(
const GameId &gameId,
const vector<PlayerInfoWithUnits> &playerSetupInfos,
const string &mapName,
const string &customMapBytes,
const std::vector<PlayerInfoWithUnits> &playerSetupInfos,
const std::string &mapName,
const std::string &customMapBytes,
int month,
const TutorialBattleConfigProto &tutorialConfig,
const string &serializedRequest,
const std::string &serializedRequest,
const std::vector<std::pair<int32_t, std::vector<PlayerId>>> &watcherAllies = {})
-> GameId;
auto UnlockedCreateFromGameStateBytes(
const byte_vector &gameStateBytes,
int32_t startingHistoryCount,
const string &mapName) -> GameId;
const std::string &mapName) -> GameId;
};
} // namespace shardok
@@ -1,140 +0,0 @@
//
// Created by Dan Crosby on 6/24/20.
//
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
#include "src/main/cpp/net/eagle0/common/TsvParser.hpp"
#include "src/main/cpp/net/eagle0/common/byte_vector.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokEngine.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/GameStateHelpers.hpp"
#include "src/main/flatbuffer/net/eagle0/shardok/storage/unit.hpp"
#include "src/main/protobuf/net/eagle0/shardok/storage/game.pb.h"
using net::eagle0::shardok::storage::Game;
using Unit = net::eagle0::shardok::storage::fb::Unit;
void PrintChangedUnits(const net::eagle0::shardok::storage::ActionResult& result);
auto MakeEngine(const net::eagle0::shardok::storage::Game& game, int includeResultCount)
-> std::shared_ptr<shardok::ShardokEngine>;
auto main(int argc, char** argv) -> int {
if (argc < 2) {
printf("Please supply a path.");
return 1;
}
const auto* path = argv[1];
FilesystemUtils::SetExecPath(argv[0]);
printf("Using path %s\n", path);
const auto protoBytes = byte_vector::FromPath(path);
Game game{};
game.ParseFromArray(protoBytes.data(), protoBytes.size());
auto engine = MakeEngine(game, 200);
auto result = game.action_result(201).action_result();
auto availableCommands = engine->GetAvailableCommandProtos(0, true);
for (size_t i = 0; i < availableCommands.size(); i++) {
auto cmd = availableCommands[i];
if (result.has_actor() == cmd.has_actor() &&
result.actor().value() == cmd.actor().value() && result.has_target_coords() &&
result.target_coords() == cmd.target()) {
printf("Command: %s\n", cmd.DebugString().c_str());
engine->PostCommand(0, i);
break;
}
}
availableCommands = engine->GetAvailableCommandProtos(0, true);
for (size_t i = 0; i < availableCommands.size(); i++) {
auto cmd = availableCommands[i];
if (cmd.type() == net::eagle0::shardok::common::END_TURN_COMMAND) {
printf("Command: %s\n", cmd.DebugString().c_str());
engine->PostCommand(0, i);
break;
}
}
availableCommands = engine->GetAvailableCommandProtos(1, true);
for (size_t i = 0; i < availableCommands.size(); i++) {
auto cmd = availableCommands[i];
if (cmd.type() == net::eagle0::shardok::common::END_TURN_COMMAND) {
printf("Command: %s\n", cmd.DebugString().c_str());
engine->PostCommand(1, i);
break;
}
}
result = game.action_result(218).action_result();
availableCommands = engine->GetAvailableCommandProtos(0, true);
for (size_t i = 0; i < availableCommands.size(); i++) {
auto cmd = availableCommands[i];
if (result.has_actor() == cmd.has_actor() &&
result.actor().value() == cmd.actor().value() && result.has_target_coords() &&
result.target_coords() == cmd.target()) {
printf("Command: %s\n", cmd.DebugString().c_str());
engine->PostCommand(0, i);
break;
}
}
// for (int i=180; i<219; i++) {
// const auto& result = game.action_result(i).action_result();
// // if (result.type() == net::eagle0::shardok::common::REDUCE || result.type() ==
// net::eagle0::shardok::common::METEOR_UNIT_DAMAGE) {
// printf("%d ", i);
// PrintChangedUnits(result);
// printf("id 0 after size: %d\n\n",
// game.action_result(i).state_after().units().at(0).battalion().size());
// // }
// }
// for (const auto& kv : firstState.units()) {
// printf("id: %d name: %s\n", kv.second.attached_hero().eagle_hero_id(),
// kv.second.attached_hero().name().c_str());
// }
printf("Finished");
return 0;
}
void PrintChangedUnits(const net::eagle0::shardok::storage::ActionResult& result) {
printf("%s\n", net::eagle0::shardok::common::ActionType_Name(result.type()).c_str());
for (const string& changedUnitData : result.changed_units_fb()) {
const auto& changedUnit = *reinterpret_cast<const Unit*>(changedUnitData.data());
printf("id: %d name: %s sizeAfter: %d\n",
changedUnit.unit_id(),
changedUnit.has_attached_hero() ? changedUnit.attached_hero().name().c_str() : "N/A",
changedUnit.battalion().size());
}
printf("\n");
}
auto MakeEngine(const net::eagle0::shardok::storage::Game& game, int includeResultCount)
-> std::shared_ptr<shardok::ShardokEngine> {
auto settings = std::make_shared<shardok::GameSettings>();
TsvParser parser;
const string settingsPath = "src/main/resources/net/eagle0/shardok/settings.tsv";
printf("Settings path is %s\n", settingsPath.c_str());
string settingsTsv = string(byte_vector::FromPath(settingsPath));
auto setter = shardok::GameSettings::Setter(*settings);
auto valuesAndTypes = parser.ParseColumnEntryTsv(settingsTsv);
setter.SetFromTypesAndValues(valuesAndTypes[1], valuesAndTypes[0]);
const string battalionTypesPath = "src/main/resources/net/eagle0/shardok/battalionTypes.tsv";
string tsv = string(byte_vector::FromPath(battalionTypesPath));
auto battalionMaps = parser.ParseColumnEntryTsv(tsv);
for (const std::unordered_map<string, string>& map : battalionMaps) {
setter.RegisterBattalionType(shardok::BattalionType::NewBattalionTypeFromMap(map));
}
return std::make_shared<shardok::ShardokEngine>(
settings,
shardok::fb::GameStateW::FromByteString(
game.action_result(includeResultCount).state_after_fb()));
}

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