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
adminandGitHub 2e63bcb5c3 Write flatbuffer allocator diagnostics to stderr (#7484) 2026-06-21 08:23:55 -07:00
adminandGitHub e231f0c34e Use streams for Shardok controller diagnostics (#7483) 2026-06-21 08:23:35 -07:00
adminandGitHub 8155fe7b3f Remove Postgres shardok row early returns (#7482) 2026-06-21 08:23:17 -07:00
adminandGitHub 6fe1bcdff2 Use streams for map info diagnostics (#7481) 2026-06-21 08:23:00 -07:00
adminandGitHub b6b488bd46 Remove changed faction writer early returns (#7480) 2026-06-21 08:15:09 -07:00
adminandGitHub d97cc0cadc Use streams for Shardok server diagnostics (#7479) 2026-06-21 08:13:19 -07:00
adminandGitHub 2a3c742be9 Remove SQLite to Postgres migration admin flow (#7478) 2026-06-21 08:11:06 -07:00
adminandGitHub cdee86dbcb Remove S3 startup save sync (#7475) 2026-06-21 08:10:47 -07:00
adminandGitHub 60264e2bfc Make Shardok numeric casts explicit (#7477) 2026-06-21 08:09:58 -07:00
adminandGitHub 19fb315500 Make remaining unit byte casts explicit (#7476) 2026-06-21 08:09:34 -07:00
adminandGitHub 66710659c9 Tighten Shardok ownership cleanup (#7472) 2026-06-21 07:57:14 -07:00
adminandGitHub de5a34c485 Make game state dumper casts explicit (#7474) 2026-06-21 07:54:29 -07:00
adminandGitHub e0c7ba3874 Make Shardok casts explicit (#7473) 2026-06-21 07:54:04 -07:00
adminandGitHub 9e58fbee56 Remove S3 sync early returns (#7471) 2026-06-21 05:59:23 -07:00
adminandGitHub 5315941f88 Remove sqlite postgres migration return (#7470) 2026-06-21 05:59:01 -07:00
adminandGitHub 3ffeb0250b Remove battle progress early return (#7469) 2026-06-21 05:58:39 -07:00
adminandGitHub 451e6bb406 Avoid unnecessary endl flushes (#7465) 2026-06-21 05:58:06 -07:00
adminandGitHub 58d680bd59 Remove tutorial hero factions early return (#7464) 2026-06-20 21:47:23 -07:00
adminandGitHub 79eb708adb Normalize Shardok header guards (#7463) 2026-06-20 21:44:58 -07:00
adminandGitHub 1282e62781 Remove AsyncS3Persister early returns (#7466) 2026-06-20 21:44:29 -07:00
adminandGitHub 4af501feee Make gtest helper casts explicit (#7467) 2026-06-20 21:44:07 -07:00
adminandGitHub ef7c24f6de Make game over response casts explicit (#7468) 2026-06-20 21:43:29 -07:00
adminandGitHub 62edd02a22 Remove attack decision early returns (#7462) 2026-06-20 21:43:10 -07:00
adminandGitHub 6f22edc8f3 Remove GameMigrator early returns (#7461) 2026-06-20 18:43:08 -07:00
adminandGitHub 27bba1c2da Replace GNU alignment attributes with alignas (#7460) 2026-06-20 17:59:59 -07:00
adminandGitHub c95bc22f0e Remove simple Unit early returns (#7459) 2026-06-20 17:45:04 -07:00
adminandGitHub 844bab253d Rename test settings helper global (#7458) 2026-06-20 17:42:44 -07:00
adminandGitHub b8372487cf Remove backstory recovery early return (#7457) 2026-06-20 17:40:46 -07:00
adminandGitHub 8cc38466e6 Replace AI client flee debug macro (#7456) 2026-06-20 17:40:25 -07:00
adminandGitHub 14935b1a52 Remove march availability early returns (#7455) 2026-06-20 17:37:29 -07:00
adminandGitHub f7b14cd9ba Replace coords set index check macro (#7454) 2026-06-20 17:36:03 -07:00
adminandGitHub 9d1e61ef8d Remove defend availability early return (#7453) 2026-06-20 17:33:01 -07:00
adminandGitHub 8c912c1b3e Replace SuppressBeastsCommand type test (#7450) 2026-06-20 17:32:41 -07:00
adminandGitHub 1ff6ae0195 Replace test type predicates (#7452) 2026-06-20 17:32:12 -07:00
adminandGitHub 641bf456fa Replace iterative deepening debug macro (#7451) 2026-06-20 17:28:10 -07:00
adminandGitHub f21eaabb15 Modernize disabled C++ logging toggles (#7449) 2026-06-20 17:25:13 -07:00
adminandGitHub 7d38336e67 Remove EngineImpl applyActionResults return (#7448) 2026-06-20 17:23:56 -07:00
adminandGitHub f37ec78d10 Remove auth early returns (#7447) 2026-06-20 17:23:02 -07:00
adminandGitHub eb0f92dcd0 Remove simple utility early returns (#7446) 2026-06-20 17:21:20 -07:00
adminandGitHub ee06235cf4 Remove quest chooser early returns (#7445) 2026-06-20 17:20:53 -07:00
adminandGitHub 48dfe9054d Replace simple isInstanceOf predicates (#7443) 2026-06-20 17:20:33 -07:00
adminandGitHub c7e39e67aa Remove simple availability early returns (#7444) 2026-06-20 17:20:07 -07:00
adminandGitHub 86e51a11b7 Replace AI evaluator control macros with constexpr (#7442) 2026-06-20 16:35:44 -07:00
adminandGitHub 3c0e98280d Rename reserved test settings include guard (#7441) 2026-06-20 16:35:15 -07:00
adminandGitHub c54c9f7955 Remove Gemini parser early returns (#7440) 2026-06-20 16:34:50 -07:00
adminandGitHub 614c404bf4 Replace test roll macros with constexpr constants (#7439) 2026-06-20 16:15:09 -07:00
adminandGitHub c1ebcd49fc Replace combat macros with constexpr constants (#7437) 2026-06-20 16:11:00 -07:00
adminandGitHub 49551614fe Default simple C++ special members (#7436) 2026-06-20 16:10:21 -07:00
adminandGitHub b2b8603f23 Generalize FunctionalRandom sequence helpers (#7438) 2026-06-20 16:09:41 -07:00
adminandGitHub 4a6ecda8f8 Remove SettingsLoader asInstanceOf generation (#7432) 2026-06-20 15:58:17 -07:00
adminandGitHub b65d3c25e1 Remove observer asInstanceOf cast (#7427) 2026-06-20 15:56:58 -07:00
adminandGitHub 65f5ec1c38 Remove domain asInstanceOf casts (#7426) 2026-06-20 15:56:43 -07:00
adminandGitHub b8b225eb84 Rename reserved AI evaluator identifiers (#7433) 2026-06-20 14:47:37 -07:00
adminandGitHub c20239b9e8 Normalize static const declarations (#7434) 2026-06-20 14:47:12 -07:00
adminandGitHub a8df7228b3 Mark single-argument constructors explicit (#7431) 2026-06-20 14:46:47 -07:00
adminandGitHub b8ebc0efd8 Remove remaining inline body semicolons (#7428) 2026-06-20 14:46:21 -07:00
adminandGitHub 5ee86faf80 Remove redundant command constructor semicolons (#7425) 2026-06-20 14:44:41 -07:00
adminandGitHub 3d6524b2fa Remove key asInstanceOf casts (#7423) 2026-06-20 14:21:03 -07:00
adminandGitHub 82b671b234 Remove redundant factory constructor semicolons (#7422) 2026-06-20 14:20:16 -07:00
adminandGitHub 3ad6de784f Remove JSON asInstanceOf casts (#7421) 2026-06-20 14:19:46 -07:00
446 changed files with 6305 additions and 5534 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) {
@@ -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"],
@@ -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,21 +22,25 @@ 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(), (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 =
(net::eagle0::shardok::common::Terrain_Type)(existingTerrainType + 2);
static_cast<net::eagle0::shardok::common::Terrain_Type>(existingTerrainType + 2);
map.mutable_terrain(i)->set_type(newTerrain);
}
}
@@ -4,50 +4,51 @@
#include "MapInfoCalculator.hpp"
#include <cstddef>
#include <cstdlib>
#include <iostream>
#include "src/main/cpp/net/eagle0/shardok/ai/AIWaterCrossingCalculator.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/fb_helpers/HexMapHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/util/HexMapUtils.hpp"
#include "src/main/cpp/net/eagle0/shardok/util/MapLoader.hpp"
using namespace shardok;
using std::endl;
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) {
printf("Should have 10 starting positions!");
abort();
std::cerr << "Should have 10 starting positions!" << '\n';
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,
@@ -59,8 +60,8 @@ 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 OneMapInfo {
struct alignas(64) OneMapInfo {
uint32_t castleCount;
string name;
map<int, int> positionsRequiringCrossing;
} __attribute__((aligned(64)));
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
@@ -2,37 +2,40 @@
// Created by Dan Crosby on 4/18/22.
//
#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;
using std::endl;
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];
outputStreamPtr = new std::ofstream(outputPath);
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));
}
@@ -41,29 +44,29 @@ auto main(const int argc, char** argv) -> int {
bool firstMap = true;
for (const OneMapInfo& mapInfo : mapInfos) {
if (firstMap) {
outputStream << endl;
outputStream << '\n';
firstMap = false;
} else {
outputStream << "," << endl;
outputStream << "," << '\n';
}
outputStream << " {" << endl;
outputStream << R"( "name": ")" << mapInfo.name << "\"," << endl;
outputStream << " {" << '\n';
outputStream << R"( "name": ")" << mapInfo.name << "\"," << '\n';
outputStream << " \"castleCount\": " << mapInfo.castleCount << "," << endl;
outputStream << " \"castleCount\": " << mapInfo.castleCount << "," << '\n';
outputStream << " \"positions\": {";
bool firstPosition = true;
for (const auto& [position, count] : mapInfo.positionsRequiringCrossing) {
if (firstPosition) {
outputStream << endl;
outputStream << '\n';
firstPosition = false;
} else {
outputStream << "," << endl;
outputStream << "," << '\n';
}
outputStream << " \"" << position << "\": " << count;
}
outputStream << endl << " }" << endl << " }";
outputStream << '\n' << " }" << '\n' << " }";
}
outputStream << endl << "]" << endl;
outputStream << '\n' << "]" << '\n';
}
@@ -2,9 +2,13 @@
// Created by Dan Crosby on 3/29/21.
//
#include <algorithm>
#include <climits>
#include <iostream>
#include <memory>
#include <numeric>
#include <mutex>
#include <random>
#include <stdexcept>
#include <thread>
#include "src/main/cpp/net/eagle0/common/FilesystemUtils.hpp"
@@ -14,8 +18,6 @@
#include "src/main/protobuf/net/eagle0/common/random_units.pb.h"
using net::eagle0::common::RandomUnits;
using std::shared_ptr;
using std::vector;
constexpr int THREAD_COUNT = 16;
@@ -28,77 +30,110 @@ std::random_device rd;
std::mt19937 g(rd());
#endif
vector<string> fileNames{};
std::mutex randomMutex;
std::vector<std::string> fileNames{};
using namespace shardok;
ShardokGamesManager* manager;
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 vector<shared_ptr<const UnitProto>>& units) {
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);
auto p1UnitCount = randInt(1, 20);
vector<UnitProto> p1Units{};
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.set_player_id(0);
auto unit = units[i];
unit.mutate_player_id(0);
p1Units.push_back(unit);
}
auto p2UnitCount = randInt(1, 20);
vector<UnitProto> p2Units{};
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.set_player_id(1);
auto unit = units[i];
unit.mutate_player_id(1);
p2Units.push_back(unit);
}
printf("map name is %s, %d attacking %d\n", mapName.c_str(), p1UnitCount, p2UnitCount);
std::cout << "map name is " << mapName << ", " << p1UnitCount << " attacking " << p2UnitCount
<< '\n';
vector<VictoryConditionProto> attVictoryConditions{
std::vector<VictoryConditionProto> attVictoryConditions{
VictoryConditionProto::VICTORY_CONDITION_HOLDS_CRITICAL_TILES,
VictoryConditionProto::VICTORY_CONDITION_LAST_PLAYER_STANDING};
vector<VictoryConditionProto> defVictoryConditions{
std::vector<VictoryConditionProto> defVictoryConditions{
VictoryConditionProto::VICTORY_CONDITION_LAST_PLAYER_STANDING,
VictoryConditionProto::VICTORY_CONDITION_WIN_AFTER_MAX_ROUNDS};
auto p1 = PlayerInfoWithUnits(0, true, 5, false, 10000, attVictoryConditions, {}, p1Units);
auto p2 = PlayerInfoWithUnits(1, false, 7, false, 10000, defVictoryConditions, {}, p2Units);
auto p1 = shardok::PlayerInfoWithUnits(
0,
true,
5,
false,
10000,
attVictoryConditions,
{},
p1Units,
false);
auto p2 = shardok::PlayerInfoWithUnits(
1,
true,
7,
true,
10000,
defVictoryConditions,
{},
p2Units,
false);
string gameId = std::to_string(randInt(INT_MIN, INT_MAX));
std::string gameId = std::to_string(randInt(INT_MIN, INT_MAX));
manager->LockedCreateSpecifiedGame(gameId, {p1, p2}, mapName, "", month, "");
manager->UnlockedCreateSpecifiedGame(
gameId,
{p1, p2},
mapName,
"",
month,
TutorialBattleConfigProto{},
"");
}
auto LoadUnits() -> vector<shared_ptr<const UnitProto>> {
auto LoadUnits() -> std::vector<shardok::Unit> {
const auto bytes = byte_vector::FromPath("/tmp/random_heroes.bin");
RandomUnits commonUnits;
commonUnits.ParseFromArray(bytes.data(), (int)bytes.size());
printf("Loaded %d units\n", commonUnits.units_size());
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";
vector<shared_ptr<const UnitProto>> units{};
std::vector<shardok::Unit> units{};
units.reserve(commonUnits.units_size());
for (const auto& commonUnit : commonUnits.units()) {
// FIXME: assumes 2 players
units.push_back(std::make_shared<const UnitProto>(ConvertUnit(commonUnit, 0, {0, 1})));
units.push_back(shardok::ConvertUnit(commonUnit, 0, {0, 1}));
}
std::shuffle(units.begin(), units.end(), g);
return units;
}
[[noreturn]] void runBattlesThread(const vector<shared_ptr<const UnitProto>>& units) {
[[noreturn]] void runBattlesThread(const std::vector<shardok::Unit>& units) {
while (true) { runBattle(units); }
}
auto main(int argc, char** argv) -> int {
auto main(int /*argc*/, char** argv) -> int {
#if FIXED_SEED
std::srand(4564564);
g.seed(378473);
@@ -110,12 +145,12 @@ auto main(int argc, char** argv) -> int {
auto randomUnits = LoadUnits();
printf("Map file directory is %s\n", FilesystemUtils::MapFilesDirectory().c_str());
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 = new ShardokGamesManager(nullptr, std::vector<std::string>());
manager = std::make_unique<shardok::ShardokGamesManager>(std::vector<std::string>());
std::thread threads[THREAD_COUNT];
@@ -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
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 6/19/23.
//
#ifndef EAGLE0_AIATTACKGROUPS_HPP
#define EAGLE0_AIATTACKGROUPS_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP
#define EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP
#include <functional>
#include <vector>
@@ -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,17 +63,17 @@ 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
#endif // EAGLE0_AIATTACKGROUPS_HPP
#endif // EAGLE0_SHARDOK_AI_AI_ATTACK_GROUPS_HPP
@@ -17,10 +17,8 @@
namespace shardok {
using Unit = net::eagle0::shardok::storage::fb::Unit;
using std::shared_ptr;
using std::vector;
class AttackLocations {
class alignas(128) AttackLocations {
private:
const MapIndex rowCount;
const MapIndex columnCount;
@@ -147,9 +145,9 @@ public:
adjacentLocations += cs;
allLocations += cs;
}
} __attribute__((aligned(128)));
};
struct AttackLocationsCache {
struct alignas(128) AttackLocationsCache {
private:
const MapIndex rowCount;
const MapIndex columnCount;
@@ -165,8 +163,8 @@ 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;
} __attribute__((aligned(128)));
auto CachedLocations(const std::vector<const Unit*>& enemies, bool lateGame) -> AttackLocations;
};
using ALCache = std::unique_ptr<AttackLocationsCache>;
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 1/9/22.
//
#ifndef EAGLE0_AIATTACKERSTRATEGYSELECTOR_HPP
#define EAGLE0_AIATTACKERSTRATEGYSELECTOR_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_ATTACKER_STRATEGY_SELECTOR_HPP
#define EAGLE0_SHARDOK_AI_AI_ATTACKER_STRATEGY_SELECTOR_HPP
#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AICommonTypes.hpp"
@@ -32,4 +32,4 @@ public:
};
} // namespace shardok
#endif // EAGLE0_AIATTACKERSTRATEGYSELECTOR_HPP
#endif // EAGLE0_SHARDOK_AI_AI_ATTACKER_STRATEGY_SELECTOR_HPP
@@ -8,6 +8,8 @@
#include <chrono>
#include <cmath>
#include <future>
#include <iomanip>
#include <iostream>
#include <limits>
#include "AICommandFilter.hpp"
@@ -22,11 +24,11 @@ namespace shardok {
// No need to forward declare internal functions - use the public interface instead
// Helper constants and static variables
static const std::vector<double> _averageSequence = {0.5};
static const auto _averageGenerator = std::make_shared<SequenceRandomGenerator>(_averageSequence);
static const std::vector<double> kAverageSequence = {0.5};
static const auto kAverageGenerator = std::make_shared<SequenceRandomGenerator>(kAverageSequence);
#define MULTITHREAD true
#define LOGGING_ 0
constexpr bool kMultithread = true;
constexpr bool kLogging = false;
// Helper function to determine if a command type is deterministic
static auto IsDeterministic(const CommandType type) -> bool {
@@ -237,15 +239,16 @@ auto AICommandEvaluator::EvaluateWithRandomness(
return lookaheadFuture.get();
};
#if MULTITHREAD
auto launchPolicy = remainingLookahead == 1 ? std::launch::async : std::launch::deferred;
returnValue.lookaheadScore = std::async(launchPolicy, lookaheadLambda);
#else
std::promise<EvaluationResult> p;
returnValue.lookaheadScore = p.get_future();
auto lambdaResult = lookaheadLambda();
p.set_value(lambdaResult);
#endif
if constexpr (kMultithread) {
auto launchPolicy =
remainingLookahead == 1 ? std::launch::async : std::launch::deferred;
returnValue.lookaheadScore = std::async(launchPolicy, lookaheadLambda);
} else {
std::promise<EvaluationResult> p;
returnValue.lookaheadScore = p.get_future();
auto lambdaResult = lookaheadLambda();
p.set_value(lambdaResult);
}
}
return returnValue;
@@ -302,22 +305,23 @@ auto AICommandEvaluator::FindBestCommand(
minDistToEnemies = 0.0; // No enemies found
}
#if LOGGING_
// Log command count and distance metrics for performance analysis
const auto allCommandCount = guessedDescriptors->size();
const auto filteredCommandCount = filteredIndices.size();
const int currentRound = gameState->current_round();
if constexpr (kLogging) {
// Log command count and distance metrics for performance analysis
const auto allCommandCount = guessedDescriptors->size();
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);
#endif
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();
@@ -352,7 +356,7 @@ auto AICommandEvaluator::FindBestCommand(
originalIndex,
remainingLookahead,
maxRepeatCount,
_averageGenerator,
kAverageGenerator,
guessedEngine,
attackerStrategy,
allCastleCoords,
@@ -520,7 +524,7 @@ auto AICommandEvaluator::EvaluateCommand(
commandIndex,
remainingLookahead,
maxRepeatCount,
_averageGenerator,
kAverageGenerator,
guessedEngine,
attackerStrategy,
allCastleCoords,
@@ -3,8 +3,8 @@
// Separated from AIScoreCalculator to isolate pure state scoring from lookahead logic.
//
#ifndef EAGLE0_AICOMMANDEVALUATOR_HPP
#define EAGLE0_AICOMMANDEVALUATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_COMMAND_EVALUATOR_HPP
#define EAGLE0_SHARDOK_AI_AI_COMMAND_EVALUATOR_HPP
#include <chrono>
#include <future>
@@ -114,4 +114,4 @@ private:
} // namespace shardok
#endif // EAGLE0_AICOMMANDEVALUATOR_HPP
#endif // EAGLE0_SHARDOK_AI_AI_COMMAND_EVALUATOR_HPP
@@ -2,8 +2,8 @@
// Filter obviously bad commands to reduce search space for AI
//
#ifndef EAGLE0_AICOMMANDFILTER_HPP
#define EAGLE0_AICOMMANDFILTER_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_COMMAND_FILTER_HPP
#define EAGLE0_SHARDOK_AI_AI_COMMAND_FILTER_HPP
#include <memory>
#include <vector>
@@ -116,4 +116,4 @@ private:
} // namespace shardok
#endif // EAGLE0_AICOMMANDFILTER_HPP
#endif // EAGLE0_SHARDOK_AI_AI_COMMAND_FILTER_HPP
@@ -3,8 +3,8 @@
// Common type definitions used across AI utility functions
//
#ifndef EAGLE0_AICOMMONTYPES_HPP
#define EAGLE0_AICOMMONTYPES_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_COMMON_TYPES_HPP
#define EAGLE0_SHARDOK_AI_AI_COMMON_TYPES_HPP
#include <functional>
@@ -20,4 +20,4 @@ using BattalionTypeGetter = std::function<BattalionTypeSPtr(BattalionTypeId)>;
} // namespace shardok
#endif // EAGLE0_AICOMMONTYPES_HPP
#endif // EAGLE0_SHARDOK_AI_AI_COMMON_TYPES_HPP
@@ -2,8 +2,8 @@
// AI System Types and Configuration
//
#ifndef EAGLE0_AI_CONFIG_HPP
#define EAGLE0_AI_CONFIG_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_CONFIG_HPP
#define EAGLE0_SHARDOK_AI_AI_CONFIG_HPP
namespace shardok {
@@ -22,4 +22,4 @@ enum class ScoringCalculatorType {
} // namespace shardok
#endif // EAGLE0_AI_CONFIG_HPP
#endif // EAGLE0_SHARDOK_AI_AI_CONFIG_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 8/30/23.
//
#ifndef EAGLE0_AIDEFENDERSTRATEGYSELECTOR_HPP
#define EAGLE0_AIDEFENDERSTRATEGYSELECTOR_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_DEFENDER_STRATEGY_SELECTOR_HPP
#define EAGLE0_SHARDOK_AI_AI_DEFENDER_STRATEGY_SELECTOR_HPP
#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AICommonTypes.hpp"
@@ -26,4 +26,4 @@ public:
};
} // namespace shardok
#endif // EAGLE0_AIDEFENDERSTRATEGYSELECTOR_HPP
#endif // EAGLE0_SHARDOK_AI_AI_DEFENDER_STRATEGY_SELECTOR_HPP
@@ -55,12 +55,12 @@ auto DefenderDistanceBuf(
const bool includeUndead) -> double {
const auto &locationsToAttackMe = alCache->CachedLocations(defenderLocation, lateGame);
struct WithoutAndWith {
struct alignas(8) WithoutAndWith {
int without;
int with;
WithoutAndWith(const int a, const int b) : without(a), with(b) {}
} __attribute__((aligned(8)));
};
vector<WithoutAndWith> pointCosts{};
pointCosts.reserve(attackerUnits.size());
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 5/10/21.
//
#ifndef EAGLE0_AIDISTANCEDEBUF_HPP
#define EAGLE0_AIDISTANCEDEBUF_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_DISTANCE_DEBUF_HPP
#define EAGLE0_SHARDOK_AI_AI_DISTANCE_DEBUF_HPP
#include "AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/ai/AICommonTypes.hpp"
@@ -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,
@@ -29,4 +26,4 @@ auto DefenderDistanceBuf(
bool includeUndead) -> double;
} // namespace shardok
#endif // EAGLE0_AIDISTANCEDEBUF_HPP
#endif // EAGLE0_SHARDOK_AI_AI_DISTANCE_DEBUF_HPP
@@ -2,8 +2,8 @@
// Temporary AI experiment switches used by benchmark-only EXPERIMENTAL runs.
//
#ifndef EAGLE0_AI_EXPERIMENT_CONFIG_HPP
#define EAGLE0_AI_EXPERIMENT_CONFIG_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_EXPERIMENT_CONFIG_HPP
#define EAGLE0_SHARDOK_AI_AI_EXPERIMENT_CONFIG_HPP
#include <cstdlib>
#include <string>
@@ -20,4 +20,4 @@ inline auto IsAIExperiment(const int id) -> bool { return CurrentAIExperimentId(
} // namespace shardok
#endif // EAGLE0_AI_EXPERIMENT_CONFIG_HPP
#endif // EAGLE0_SHARDOK_AI_AI_EXPERIMENT_CONFIG_HPP
@@ -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,
@@ -3,8 +3,8 @@
// Provides O(1) weights based on command type and context
//
#ifndef EAGLE0_AI_HEURISTIC_WEIGHTING_HPP
#define EAGLE0_AI_HEURISTIC_WEIGHTING_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_HEURISTIC_WEIGHTING_HPP
#define EAGLE0_SHARDOK_AI_AI_HEURISTIC_WEIGHTING_HPP
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-redundant-constexpr-static-def"
@@ -37,4 +37,4 @@ public:
} // namespace shardok
#endif // EAGLE0_AI_HEURISTIC_WEIGHTING_HPP
#endif // EAGLE0_SHARDOK_AI_AI_HEURISTIC_WEIGHTING_HPP
@@ -2,11 +2,8 @@
// Created by Dan Crosby on 8/31/23.
//
#ifndef EAGLE0_AIMINIMUMDISTANCEANDTARGET_HPP
#define EAGLE0_AIMINIMUMDISTANCEANDTARGET_HPP
#include <utility>
#include <vector>
#ifndef EAGLE0_SHARDOK_AI_AI_MINIMUM_DISTANCE_AND_TARGET_HPP
#define EAGLE0_SHARDOK_AI_AI_MINIMUM_DISTANCE_AND_TARGET_HPP
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistances.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
@@ -15,7 +12,6 @@
namespace shardok {
using net::eagle0::shardok::storage::fb::Coords;
using std::shared_ptr;
struct CoordsAndDistance {
Coords coords;
@@ -34,4 +30,4 @@ auto MinimumDistance(
} // namespace shardok
#endif // EAGLE0_AIMINIMUMDISTANCEANDTARGET_HPP
#endif // EAGLE0_SHARDOK_AI_AI_MINIMUM_DISTANCE_AND_TARGET_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 4/7/21.
//
#ifndef EAGLE0_AISCOREUTILITIES_HPP
#define EAGLE0_AISCOREUTILITIES_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_SCORE_UTILITIES_HPP
#define EAGLE0_SHARDOK_AI_AI_SCORE_UTILITIES_HPP
#include <vector>
@@ -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;
@@ -31,4 +29,4 @@ auto PlayerInfoForPid(const GameStateW &, PlayerId pid) -> const PlayerInfo *;
} // namespace shardok
#endif // EAGLE0_AISCOREUTILITIES_HPP
#endif // EAGLE0_SHARDOK_AI_AI_SCORE_UTILITIES_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 1/10/22.
//
#ifndef EAGLE0_AISTRATEGY_HPP
#define EAGLE0_AISTRATEGY_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_STRATEGY_HPP
#define EAGLE0_SHARDOK_AI_AI_STRATEGY_HPP
#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackGroups.hpp"
@@ -34,4 +34,4 @@ auto CrossRiversStrategy(const CoordsSet& targetLocations) -> AIStrategy;
} // namespace shardok
#endif // EAGLE0_AISTRATEGY_HPP
#endif // EAGLE0_SHARDOK_AI_AI_STRATEGY_HPP
@@ -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
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 07/04/25.
//
#ifndef EAGLE0_AITIMEBUDGET_HPP
#define EAGLE0_AITIMEBUDGET_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_TIME_BUDGET_HPP
#define EAGLE0_SHARDOK_AI_AI_TIME_BUDGET_HPP
#include <atomic>
#include <chrono>
@@ -48,4 +48,4 @@ auto CalculateTimeBudget(
} // namespace shardok
#endif // EAGLE0_AITIMEBUDGET_HPP
#endif // EAGLE0_SHARDOK_AI_AI_TIME_BUDGET_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 4/7/21.
//
#ifndef EAGLE0_AIUNITSCORECALCULATOR_HPP
#define EAGLE0_AIUNITSCORECALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_UNIT_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_AI_UNIT_SCORE_CALCULATOR_HPP
#include "src/main/cpp/net/eagle0/shardok/library/action_point_distances/ActionPointDistances.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/CoordsSet.hpp"
@@ -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,
@@ -53,4 +50,4 @@ auto UnitValue(
} // namespace shardok
#endif // EAGLE0_AIUNITSCORECALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_AI_UNIT_SCORE_CALCULATOR_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 12/29/21.
//
#ifndef EAGLE0_AIWATERCROSSINGCALCULATOR_HPP
#define EAGLE0_AIWATERCROSSINGCALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_CALCULATOR_HPP
#include "src/main/cpp/net/eagle0/shardok/ai/AICommonTypes.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
@@ -23,7 +23,8 @@ static inline void AssertValid(const Coords& c, const HexMap* hexMap) {
if (!valid) {
std::stringstream str;
str << "Invalid coords " << (int)c.row() << ", " << (int)c.column();
str << "Invalid coords " << static_cast<int>(c.row()) << ", "
<< static_cast<int>(c.column());
throw ShardokInternalErrorException(str.str());
}
@@ -85,4 +86,4 @@ auto WaterCrossingScore(
} // namespace shardok
#endif // EAGLE0_AIWATERCROSSINGCALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_CALCULATOR_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 1/5/22.
//
#ifndef EAGLE0_AIWATERCROSSINGCOMMANDCHOOSER_HPP
#define EAGLE0_AIWATERCROSSINGCOMMANDCHOOSER_HPP
#ifndef EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_COMMAND_CHOOSER_HPP
#define EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_COMMAND_CHOOSER_HPP
#include <utility>
@@ -44,4 +44,4 @@ public:
} // namespace shardok
#endif // EAGLE0_AIWATERCROSSINGCOMMANDCHOOSER_HPP
#endif // EAGLE0_SHARDOK_AI_AI_WATER_CROSSING_COMMAND_CHOOSER_HPP
@@ -5,6 +5,8 @@
#include "IterativeDeepeningAI.hpp"
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <limits>
#include <numeric>
#include <utility>
@@ -19,7 +21,21 @@
namespace shardok {
#define DEBUG_ITERATIVE_DEEPENING_TIMINGS 1
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,
@@ -54,9 +70,9 @@ auto IterativeDeepeningAI::IterativeSearch(
// DEBUG: Clear TT to see if that's causing the suspicious depth reaching
// g_transpositionTable.clear(); // Uncomment to test without cross-search caching
if (commands->empty()) {
#if DEBUG_ITERATIVE_DEEPENING_TIMINGS
printf("ID AI: Commands are empty, returning early\n");
#endif
if (kDebugIterativeDeepeningTimings) {
std::cout << "ID AI: Commands are empty, returning early\n";
}
result.searchCompleted = true;
return result;
}
@@ -168,23 +184,23 @@ auto IterativeDeepeningAI::IterativeSearch(
// Log if best command changed from previous depth
if (currentDepth > 1 && currentBestCommand != previousBestCommand) {
#if DEBUG_ITERATIVE_DEEPENING_TIMINGS
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());
#endif
if (kDebugIterativeDeepeningTimings) {
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';
}
}
previousBestCommand = currentBestCommand;
@@ -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
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 07/04/25.
//
#ifndef EAGLE0_ITERATIVEDEEPENINGAI_HPP
#define EAGLE0_ITERATIVEDEEPENINGAI_HPP
#ifndef EAGLE0_SHARDOK_AI_ITERATIVE_DEEPENING_AI_HPP
#define EAGLE0_SHARDOK_AI_ITERATIVE_DEEPENING_AI_HPP
#include <chrono>
#include <future>
@@ -111,4 +111,4 @@ private:
} // namespace shardok
#endif // EAGLE0_ITERATIVEDEEPENINGAI_HPP
#endif // EAGLE0_SHARDOK_AI_ITERATIVE_DEEPENING_AI_HPP
@@ -8,8 +8,6 @@
#include "ShardokAIClient.hpp"
#define DEBUG_FLEE_DECISIONS
// Enable to dump game state and debug tree to /tmp for debugging
// #define ENABLE_MCTS_DEBUG_DUMP
@@ -17,9 +15,12 @@
#include <chrono>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#endif
#include <iomanip>
#include <iostream>
#include <set>
#include <unordered_map>
@@ -43,6 +44,7 @@ using net::eagle0::shardok::api::ActionResultView;
using net::eagle0::shardok::api::GameStateView;
static constexpr bool kPerformanceLogging = true;
static constexpr bool kDebugFleeDecisions = true;
void ApplyUpdate(GameStateView & /*currentView*/, const ActionResultView & /*update*/) {}
@@ -175,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;
@@ -207,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
@@ -239,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(
@@ -357,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
@@ -397,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;
@@ -468,12 +445,7 @@ auto ShardokAIClient::FinalRoundAttackerChooseCommandIndex(
maxRounds,
minimumFleeOddsThreshold,
desperateFleeThreshold,
#ifdef DEBUG_FLEE_DECISIONS
true // Enable debug logging
#else
false
#endif
);
kDebugFleeDecisions);
if (fleeDecision.shouldFlee) {
CommandChoiceResults results{};
@@ -516,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) {
@@ -527,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;
@@ -539,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
@@ -2,12 +2,13 @@
// TranspositionTable.hpp - Cache for game state evaluations to avoid redundant calculations
//
#ifndef EAGLE0_TRANSPOSITIONTABLE_HPP
#define EAGLE0_TRANSPOSITIONTABLE_HPP
#ifndef EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP
#define EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP
#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
@@ -88,4 +90,4 @@ extern TranspositionTable g_transpositionTable;
} // namespace shardok
#endif // EAGLE0_TRANSPOSITIONTABLE_HPP
#endif // EAGLE0_SHARDOK_AI_TRANSPOSITION_TABLE_HPP
@@ -2,8 +2,8 @@
// Shardok-specific MCTS AI that wraps the abstract implementation
//
#ifndef EAGLE0_SHARDOK_MCTSAI_HPP
#define EAGLE0_SHARDOK_MCTSAI_HPP
#ifndef EAGLE0_SHARDOK_AI_MCTS_SHARDOK_MCTSAI_HPP
#define EAGLE0_SHARDOK_AI_MCTS_SHARDOK_MCTSAI_HPP
#include <memory>
#include <vector>
@@ -68,4 +68,4 @@ private:
} // namespace shardok
#endif // EAGLE0_SHARDOK_MCTSAI_HPP
#endif // EAGLE0_SHARDOK_AI_MCTS_SHARDOK_MCTSAI_HPP
@@ -2,8 +2,8 @@
// Shardok-specific action adapter for MCTS
//
#ifndef EAGLE0_SHARDOK_ACTION_HPP
#define EAGLE0_SHARDOK_ACTION_HPP
#ifndef EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_ACTION_HPP
#define EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_ACTION_HPP
#include <memory>
#include <string>
@@ -58,4 +58,4 @@ private:
} // namespace shardok::mcts
#endif // EAGLE0_SHARDOK_ACTION_HPP
#endif // EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_ACTION_HPP
@@ -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);
}
}
@@ -2,13 +2,14 @@
// Shardok-specific game engine adapter for MCTS
//
#ifndef EAGLE0_SHARDOK_GAME_ENGINE_HPP
#define EAGLE0_SHARDOK_GAME_ENGINE_HPP
#ifndef EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_ENGINE_HPP
#define EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_ENGINE_HPP
#include <atomic>
#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();
@@ -141,4 +143,4 @@ public:
} // namespace mcts
} // namespace shardok
#endif // EAGLE0_SHARDOK_GAME_ENGINE_HPP
#endif // EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_ENGINE_HPP
@@ -2,8 +2,8 @@
// Shardok-specific game state adapter for MCTS
//
#ifndef EAGLE0_SHARDOK_GAME_STATE_HPP
#define EAGLE0_SHARDOK_GAME_STATE_HPP
#ifndef EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_STATE_HPP
#define EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_STATE_HPP
#include <memory>
@@ -80,4 +80,4 @@ private:
} // namespace mcts
} // namespace shardok
#endif // EAGLE0_SHARDOK_GAME_STATE_HPP
#endif // EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_GAME_STATE_HPP
@@ -2,8 +2,8 @@
// Factory for creating Shardok-specific MCTS components
//
#ifndef EAGLE0_SHARDOK_MCTS_FACTORY_HPP
#define EAGLE0_SHARDOK_MCTS_FACTORY_HPP
#ifndef EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_MCTS_FACTORY_HPP
#define EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_MCTS_FACTORY_HPP
#include <functional>
#include <memory>
@@ -67,4 +67,4 @@ public:
} // namespace mcts
} // namespace shardok
#endif // EAGLE0_SHARDOK_MCTS_FACTORY_HPP
#endif // EAGLE0_SHARDOK_AI_MCTS_ADAPTERS_SHARDOK_MCTS_FACTORY_HPP
@@ -2,10 +2,8 @@
// Created by dancrosby on 3/4/20.
//
#ifndef EAGLE0_AISCORECALCULATOR_HPP
#define EAGLE0_AISCORECALCULATOR_HPP
#include <future>
#ifndef EAGLE0_SHARDOK_AI_SCORE_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_AI_SCORE_CALCULATOR_HPP
#include "src/main/cpp/net/eagle0/shardok/ai/AIAttackLocations.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
@@ -16,8 +14,6 @@
namespace shardok {
using shardok::PlayerId;
using std::future;
using std::vector;
using ScoreValue = double;
@@ -53,4 +49,4 @@ public:
} // namespace shardok
#endif // EAGLE0_AISCORECALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_AI_SCORE_CALCULATOR_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 4/11/21.
//
#ifndef EAGLE0_AIVICTORYCONDITIONSCORECALCULATOR_HPP
#define EAGLE0_AIVICTORYCONDITIONSCORECALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_SCORE_AI_VICTORY_CONDITION_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_AI_VICTORY_CONDITION_SCORE_CALCULATOR_HPP
#include <vector>
@@ -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;
@@ -48,4 +47,4 @@ auto LastPlayerStandingVictoryScore(
} // namespace shardok
#endif // EAGLE0_AIVICTORYCONDITIONSCORECALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_AI_VICTORY_CONDITION_SCORE_CALCULATOR_HPP
@@ -3,8 +3,8 @@
// Uses bounded linear scoring tuned for MCTS exploration/exploitation balance
//
#ifndef EAGLE0_MCTSOPTIMIZEDAISCORECALCULATOR_HPP
#define EAGLE0_MCTSOPTIMIZEDAISCORECALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_SCORE_MCTS_OPTIMIZED_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_MCTS_OPTIMIZED_AI_SCORE_CALCULATOR_HPP
#include <memory>
@@ -29,4 +29,4 @@ using ALCache = std::unique_ptr<AttackLocationsCache>;
} // namespace shardok
#endif // EAGLE0_MCTSOPTIMIZEDAISCORECALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_MCTS_OPTIMIZED_AI_SCORE_CALCULATOR_HPP
@@ -8,6 +8,9 @@
#include <atomic>
#include <chrono>
#include <cmath>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <unordered_map>
#include "private/AIScoreCalculatorSharedUtilities.hpp"
@@ -41,9 +44,6 @@ class StandardAIScoreCalculator;
// Anonymous namespace for helper functions that don't need access to scorer
namespace {
#define LOGGING_ 0
#define PERFORMANCE_LOGGING_ 0
// Performance logging for AttackerScoreForState
struct AttackerScorePerformanceLogger {
static constexpr int LOG_INTERVAL = 100000;
@@ -60,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
}
}
@@ -2,8 +2,8 @@
// Standard implementation of AIScoreCalculator
//
#ifndef EAGLE0_STANDARDAISCORECALCULATOR_HPP
#define EAGLE0_STANDARDAISCORECALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_SCORE_STANDARD_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_STANDARD_AI_SCORE_CALCULATOR_HPP
#include <memory>
@@ -34,4 +34,4 @@ using ALCache = std::unique_ptr<AttackLocationsCache>;
} // namespace shardok
#endif // EAGLE0_STANDARDAISCORECALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_STANDARD_AI_SCORE_CALCULATOR_HPP
@@ -3,8 +3,8 @@
// This file is private to the ai/score package
//
#ifndef EAGLE0_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
#define EAGLE0_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
#ifndef EAGLE0_SHARDOK_AI_SCORE_PRIVATE_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
#define EAGLE0_SHARDOK_AI_SCORE_PRIVATE_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
#include <vector>
@@ -92,4 +92,4 @@ auto AttackerMultiplierForTargetDistance(
} // namespace score_calculator_internal
} // namespace shardok
#endif // EAGLE0_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_PRIVATE_AI_SCORE_CALCULATOR_SHARED_UTILITIES_HPP
@@ -3,8 +3,8 @@
// This file is private to the ai/score package
//
#ifndef EAGLE0_ABSTRACT_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_ABSTRACT_AI_SCORE_CALCULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_SCORE_PRIVATE_ABSTRACT_AI_SCORE_CALCULATOR_HPP
#define EAGLE0_SHARDOK_AI_SCORE_PRIVATE_ABSTRACT_AI_SCORE_CALCULATOR_HPP
#include <memory>
#include <unordered_map>
@@ -178,4 +178,4 @@ private:
} // namespace shardok
#endif // EAGLE0_ABSTRACT_AI_SCORE_CALCULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_SCORE_PRIVATE_ABSTRACT_AI_SCORE_CALCULATOR_HPP
@@ -21,7 +21,7 @@ std::unique_ptr<BattleConfigProto> AiBattleConfigLoader::LoadFromJsonFile(
const std::string& filepath) {
std::ifstream file(filepath);
if (!file.is_open()) {
std::cerr << "Failed to open config file: " << filepath << std::endl;
std::cerr << "Failed to open config file: " << filepath << '\n';
return nullptr;
}
@@ -41,7 +41,7 @@ std::unique_ptr<BattleConfigProto> AiBattleConfigLoader::LoadFromJsonString(
google::protobuf::util::JsonStringToMessage(jsonString, config.get(), options);
if (!status.ok()) {
std::cerr << "Failed to parse JSON config: " << status.message() << std::endl;
std::cerr << "Failed to parse JSON config: " << status.message() << '\n';
return nullptr;
}
@@ -103,7 +103,7 @@ std::string AiBattleConfigLoader::ToJsonString(const BattleConfigProto& config)
const auto status = google::protobuf::util::MessageToJsonString(config, &jsonString, options);
if (!status.ok()) {
std::cerr << "Failed to convert config to JSON: " << status.message() << std::endl;
std::cerr << "Failed to convert config to JSON: " << status.message() << '\n';
return "";
}
@@ -2,8 +2,8 @@
// AI Battle Simulator Configuration Loader
//
#ifndef EAGLE0_AI_BATTLE_CONFIG_HPP
#define EAGLE0_AI_BATTLE_CONFIG_HPP
#ifndef EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_CONFIG_HPP
#define EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_CONFIG_HPP
#include <memory>
#include <string>
@@ -44,4 +44,4 @@ public:
} // namespace ai_battle_simulator
} // namespace shardok
#endif // EAGLE0_AI_BATTLE_CONFIG_HPP
#endif // EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_CONFIG_HPP
@@ -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(
@@ -744,7 +747,8 @@ BattleResult AiBattleSimulator::RunBattlePhase(
auto availableCommands = engine.GetAvailableCommandProtos(currentPlayer, false);
if (availableCommands.empty()) {
std::cout << "No commands available for player " << (int)currentPlayer << "\n";
std::cout << "No commands available for player " << static_cast<int>(currentPlayer)
<< "\n";
break;
}
@@ -2,8 +2,8 @@
// AI Battle Simulator - Runs AI vs AI battles to completion
//
#ifndef EAGLE0_AI_BATTLE_SIMULATOR_HPP
#define EAGLE0_AI_BATTLE_SIMULATOR_HPP
#ifndef EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_SIMULATOR_HPP
#define EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_SIMULATOR_HPP
#include <memory>
#include <optional>
@@ -149,4 +149,4 @@ private:
} // namespace ai_battle_simulator
} // namespace shardok
#endif // EAGLE0_AI_BATTLE_SIMULATOR_HPP
#endif // EAGLE0_SHARDOK_AI_BATTLE_SIMULATOR_AI_BATTLE_SIMULATOR_HPP
@@ -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 {
@@ -78,7 +86,7 @@ auto ParseCommandLineArgs(int argc, char* argv[]) -> PerformanceTestConfig {
} // namespace
int main(int argc, char* argv[]) {
std::cout << "Starting AI Performance Runner..." << std::endl;
std::cout << "Starting AI Performance Runner..." << '\n';
// Set exec path so FilesystemUtils can find resource files
FilesystemUtils::SetExecPath(argv[0]);
@@ -300,4 +308,4 @@ int main(int argc, char* argv[]) {
}
return 0;
}
}
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 2025-01-15.
//
#ifndef EAGLE0_AIPERFORMANCERUNNER_HPP
#define EAGLE0_AIPERFORMANCERUNNER_HPP
#ifndef EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_AI_PERFORMANCE_RUNNER_HPP
#define EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_AI_PERFORMANCE_RUNNER_HPP
#include <chrono>
#include <map>
@@ -52,4 +52,4 @@ struct PerformanceTestConfig {
} // namespace shardok
#endif // EAGLE0_AIPERFORMANCERUNNER_HPP
#endif // EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_AI_PERFORMANCE_RUNNER_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 2025-01-15.
//
#ifndef EAGLE0_PERFORMANCETESTGAMESTATEBUILDER_HPP
#define EAGLE0_PERFORMANCETESTGAMESTATEBUILDER_HPP
#ifndef EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_PERFORMANCE_TEST_GAME_STATE_BUILDER_HPP
#define EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_PERFORMANCE_TEST_GAME_STATE_BUILDER_HPP
#include <flatbuffers/flatbuffers.h>
@@ -85,4 +85,4 @@ private:
} // namespace shardok
#endif // EAGLE0_PERFORMANCETESTGAMESTATEBUILDER_HPP
#endif // EAGLE0_SHARDOK_AI_PERFORMANCE_RUNNER_PERFORMANCE_TEST_GAME_STATE_BUILDER_HPP
@@ -3,8 +3,8 @@
// Used by both AI Performance Runner and AI Battle Simulator
//
#ifndef EAGLE0_AI_CLIENT_FACTORY_HPP
#define EAGLE0_AI_CLIENT_FACTORY_HPP
#ifndef EAGLE0_SHARDOK_AI_TESTING_COMMON_AI_CLIENT_FACTORY_HPP
#define EAGLE0_SHARDOK_AI_TESTING_COMMON_AI_CLIENT_FACTORY_HPP
#include <memory>
@@ -68,4 +68,4 @@ public:
} // namespace ai_testing_common
} // namespace shardok
#endif // EAGLE0_AI_CLIENT_FACTORY_HPP
#endif // EAGLE0_SHARDOK_AI_TESTING_COMMON_AI_CLIENT_FACTORY_HPP
@@ -3,8 +3,8 @@
// Used by both AI Performance Runner and AI Battle Simulator
//
#ifndef EAGLE0_GAME_PHASE_RUNNER_HPP
#define EAGLE0_GAME_PHASE_RUNNER_HPP
#ifndef EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_PHASE_RUNNER_HPP
#define EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_PHASE_RUNNER_HPP
#include <functional>
@@ -61,4 +61,4 @@ public:
} // namespace ai_testing_common
} // namespace shardok
#endif // EAGLE0_GAME_PHASE_RUNNER_HPP
#endif // EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_PHASE_RUNNER_HPP
@@ -3,8 +3,8 @@
// Used by both AI Performance Runner and AI Battle Simulator
//
#ifndef EAGLE0_GAME_SETTINGS_FACTORY_HPP
#define EAGLE0_GAME_SETTINGS_FACTORY_HPP
#ifndef EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_SETTINGS_FACTORY_HPP
#define EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_SETTINGS_FACTORY_HPP
#include <memory>
@@ -36,4 +36,4 @@ public:
} // namespace ai_testing_common
} // namespace shardok
#endif // EAGLE0_GAME_SETTINGS_FACTORY_HPP
#endif // EAGLE0_SHARDOK_AI_TESTING_COMMON_GAME_SETTINGS_FACTORY_HPP
@@ -2,8 +2,11 @@
// Created by Dan Crosby on 4/6/21.
//
#ifndef EAGLE0_GAMEUPDATERECEIVER_HPP
#define EAGLE0_GAMEUPDATERECEIVER_HPP
#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"
@@ -11,7 +14,6 @@
#pragma GCC diagnostic pop
namespace shardok {
using std::vector;
class GameUpdateReceiver {
private:
@@ -25,10 +27,10 @@ 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; }
};
} // namespace shardok
#endif // EAGLE0_GAMEUPDATERECEIVER_HPP
#endif // EAGLE0_SHARDOK_CONTROLLER_GAME_UPDATE_RECEIVER_HPP
@@ -11,6 +11,7 @@
#include <execinfo.h>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <ranges>
#include <string>
@@ -26,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;
@@ -39,7 +39,7 @@ private:
PlayerId shardokPlayerId;
int eagleFactionId;
string message;
std::string message;
public:
MismatchedPlayerIdException(const PlayerId shardokPid, const int eagleFid)
@@ -56,7 +56,7 @@ class MissingPlayerIdException : public std::exception {
private:
PlayerId shardokPlayerId;
string message;
std::string message;
public:
MissingPlayerIdException(const PlayerId shardokPid) : shardokPlayerId(shardokPid) {
@@ -115,8 +115,8 @@ auto ShardokGameController::LockedAIClientForPid(PlayerId pid) const
}
void ShardokGameController::DoAIThread() {
printf("Entering AI thread.\n");
if (aiClients.empty()) { printf("No AI players, exiting AI thread.\n"); }
std::cout << "Entering AI thread." << '\n';
if (aiClients.empty()) { std::cout << "No AI players, exiting AI thread." << '\n'; }
while (aiThreadKeepGoing) {
// Phase 1: Gather data for AI decision (brief lock)
@@ -154,7 +154,7 @@ void ShardokGameController::DoAIThread() {
// Lock released - polls can now get through
if (availableCommands->empty()) {
printf("no commands for player %d\n", playerId);
std::cout << "no commands for player " << playerId << '\n';
continue;
}
@@ -177,7 +177,7 @@ void ShardokGameController::DoAIThread() {
// Verify state hasn't changed while we were thinking
if (engine->GetUnfilteredHistoryCount() != expectedHistoryCount) {
// State changed (e.g., human posted command) - re-evaluate
printf("AI: State changed while thinking, re-evaluating\n");
std::cout << "AI: State changed while thinking, re-evaluating" << '\n';
continue;
}
@@ -208,12 +208,8 @@ void ShardokGameController::DoAIThread() {
aiThreadKeepGoing = !engine->GameIsOver();
}
} catch (const std::exception &e) {
fprintf(stderr,
"AI thread exception in game %s, player %d, round %d: %s\n",
cachedGameId.c_str(),
playerId,
gsv.current_round(),
e.what());
std::cerr << "AI thread exception in game " << cachedGameId << ", player " << playerId
<< ", round " << gsv.current_round() << ": " << e.what() << '\n';
void *backtraceArray[20];
const int backtraceSize = backtrace(backtraceArray, 20);
@@ -227,7 +223,7 @@ void ShardokGameController::DoAIThread() {
break;
}
}
printf("Exiting AI thread.\n");
std::cout << "Exiting AI thread." << '\n';
}
ShardokGameController::~ShardokGameController() {
@@ -274,7 +270,7 @@ void ShardokGameController::PostCommand(
const auto expectedToken = static_cast<int64_t>(engine->GetUnfilteredHistoryCount());
if (token < expectedToken) {
printf("Double token in postCommand\n");
std::cout << "Double token in postCommand" << '\n';
// The client is missing some updates; probably it's a double-submit
// Let's just ignore and see how it goes
} else if (token > expectedToken) {
@@ -322,7 +318,7 @@ void ShardokGameController::PostPlacementCommands(
const auto expectedToken = static_cast<int64_t>(engine->GetUnfilteredHistoryCount());
if (token < expectedToken) {
printf("Double token in postPlacementCommands\n");
std::cout << "Double token in postPlacementCommands" << '\n';
// The client is missing some updates; probably it's a double-submit
// Let's just ignore and see how it goes
} else if (token > expectedToken) {
@@ -2,8 +2,8 @@
// Created by dancrosby on 3/22/20.
//
#ifndef EAGLE0_ACTIONCOST_HPP
#define EAGLE0_ACTIONCOST_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_COST_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_COST_HPP
#include <cstdint>
@@ -52,4 +52,4 @@ inline constexpr ActionCost IMPOSSIBLE_ACTION_COST{ActionCost::impossible, 0};
} // namespace shardok
#endif // EAGLE0_ACTIONCOST_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_COST_HPP
@@ -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 {
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 2025-01-15.
//
#ifndef EAGLE0_GAMESTATEW_HPP
#define EAGLE0_GAMESTATEW_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_GAME_STATE_W_HPP
#define EAGLE0_SHARDOK_LIBRARY_GAME_STATE_W_HPP
#include <cstdint>
@@ -108,4 +108,4 @@ public:
} // namespace shardok
#endif // EAGLE0_GAMESTATEW_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_GAME_STATE_W_HPP
@@ -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,15 +25,13 @@
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 {
std::string description;
public:
explicit IllegalActionException(const std::string& d) : ShardokException(d){};
explicit IllegalActionException(const std::string& d) : ShardokException(d) {}
};
// Encapsulates any action that changes game state
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 4/4/20.
//
#ifndef EAGLE0_SHARDOKCOMMAND_HPP
#define EAGLE0_SHARDOKCOMMAND_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_SHARDOK_COMMAND_HPP
#define EAGLE0_SHARDOK_LIBRARY_SHARDOK_COMMAND_HPP
#include <memory>
#include <vector>
@@ -26,7 +26,7 @@ private:
const PlayerId playerId;
protected:
explicit ShardokCommand(const PlayerId pid) : playerId(pid){};
explicit ShardokCommand(const PlayerId pid) : playerId(pid) {}
public:
[[nodiscard]] virtual auto GetCommandType() const -> CommandType = 0;
@@ -57,10 +57,10 @@ 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
#endif // EAGLE0_SHARDOKCOMMAND_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_SHARDOK_COMMAND_HPP
@@ -712,7 +712,7 @@ auto SecuredByPlayerByUnitIdFromHistory(
continue;
}
if (!resolvedUnit.has_secured_by_player()) { continue; }
const auto *unit = (Unit *)resolvedUnit.unit_bytes().data();
const auto *unit = reinterpret_cast<const Unit *>(resolvedUnit.unit_bytes().data());
securedByPlayerByUnitId[unit->unit_id()] = resolvedUnit.secured_by_player().value();
}
}
@@ -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
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 1/11/21.
//
#ifndef EAGLE0_UNITPLACEMENTINFO_HPP
#define EAGLE0_UNITPLACEMENTINFO_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_UNIT_PLACEMENT_INFO_HPP
#define EAGLE0_SHARDOK_LIBRARY_UNIT_PLACEMENT_INFO_HPP
#include "src/main/cpp/net/eagle0/shardok/library/ShardokCTypes.h"
@@ -20,4 +20,4 @@ struct UnitPlacementInfo {
} // namespace shardok
#endif // EAGLE0_UNITPLACEMENTINFO_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_UNIT_PLACEMENT_INFO_HPP
@@ -27,11 +27,12 @@ auto FireSpreadActionFactory::MakeFireSpreadAction(
const int16_t weatherFactor =
settings.GetFirePropensityByWeatherConditions(weather->conditions());
int relativeWindDirection = (int)weather->wind().direction() - (int)direction;
int relativeWindDirection =
static_cast<int>(weather->wind().direction()) - static_cast<int>(direction);
if (relativeWindDirection < 0) relativeWindDirection += 6;
const int windIntensity =
(int)(weather->wind().speed_in_mph() *
settings.Backing().fire_propensity_wind_speed_multiplier());
const int windIntensity = static_cast<int>(
weather->wind().speed_in_mph() *
settings.Backing().fire_propensity_wind_speed_multiplier());
int16_t windFactor;
switch (relativeWindDirection) {
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 2/16/21.
//
#ifndef EAGLE0_ICEANDSNOWADJUSTMENTACTIONFACTORY_HPP
#define EAGLE0_ICEANDSNOWADJUSTMENTACTIONFACTORY_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_ICE_AND_SNOW_ADJUSTMENT_ACTION_FACTORY_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_ICE_AND_SNOW_ADJUSTMENT_ACTION_FACTORY_HPP
#include "src/main/cpp/net/eagle0/shardok/library/ShardokAction.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/Coordinates.hpp"
@@ -49,4 +49,4 @@ public:
};
} // namespace shardok
#endif // EAGLE0_ICEANDSNOWADJUSTMENTACTIONFACTORY_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_ICE_AND_SNOW_ADJUSTMENT_ACTION_FACTORY_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 11/29/20.
//
#ifndef EAGLE0_PLAYERSETUPCOMMANDFACTORY_HPP
#define EAGLE0_PLAYERSETUPCOMMANDFACTORY_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_PLAYER_SETUP_COMMAND_FACTORY_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_PLAYER_SETUP_COMMAND_FACTORY_HPP
#include <optional>
#include <vector>
@@ -22,7 +22,7 @@ private:
const SettingsGetter settings;
public:
explicit PlayerSetupCommandFactory(const SettingsGetter& getter) : settings(getter){};
explicit PlayerSetupCommandFactory(const SettingsGetter& getter) : settings(getter) {}
auto AddAvailablePlaceAndHideUnitCommandsForOneUnit(
CommandList& existingCommands,
@@ -40,4 +40,4 @@ public:
} // namespace shardok
#endif // EAGLE0_PLAYERSETUPCOMMANDFACTORY_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_PLAYER_SETUP_COMMAND_FACTORY_HPP
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 3/8/21.
//
#ifndef EAGLE0_UNDEADCHANGEACTIONFACTORY_HPP
#define EAGLE0_UNDEADCHANGEACTIONFACTORY_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_UNDEAD_CHANGE_ACTION_FACTORY_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_UNDEAD_CHANGE_ACTION_FACTORY_HPP
#include "src/main/cpp/net/eagle0/shardok/library/GameStateW.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/ShardokAction.hpp"
@@ -16,10 +16,10 @@ private:
const SettingsGetter settings;
public:
explicit UndeadChangeActionFactory(const SettingsGetter &getter) : settings(getter){};
explicit UndeadChangeActionFactory(const SettingsGetter &getter) : settings(getter) {}
[[nodiscard]] auto MakeUndeadChangeAction(const GameStateW &gameState) const -> ActionSPtr;
};
} // namespace shardok
#endif // EAGLE0_UNDEADCHANGEACTIONFACTORY_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_FACTORIES_UNDEAD_CHANGE_ACTION_FACTORY_HPP
@@ -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
@@ -2,11 +2,14 @@
// Created by Dan Crosby on 9/6/20.
//
#ifndef EAGLE0_ACTIONPOINTDISTANCES_HPP
#define EAGLE0_ACTIONPOINTDISTANCES_HPP
#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(
@@ -101,4 +102,4 @@ public:
} // namespace shardok
#endif // EAGLE0_ACTIONPOINTDISTANCES_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_HPP
@@ -6,21 +6,22 @@
#include <algorithm>
#include <chrono>
#include <iostream>
#include <ostream>
#include <unordered_map>
#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/map/HexMapHasher.hpp"
#define CACHE_STATS_LOGGING_ false
#define CACHE_STATS_FREQUENCY_SECONDS_ 1
namespace shardok {
constexpr bool kCacheStatsLogging = false;
constexpr int kCacheStatsFrequencySeconds = 1;
// Thread-local cache definition - stores raw pointers for zero overhead access
thread_local ActionPointDistancesCache::TLSCache ActionPointDistancesCache::tlsCache;
#if CACHE_STATS_LOGGING_
// Thread-local statistics for performance monitoring
thread_local struct {
int persistentHits = 0;
@@ -33,22 +34,20 @@ 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() >=
CACHE_STATS_FREQUENCY_SECONDS_) {
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);
kCacheStatsFrequencySeconds) {
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;
}
}
#endif
static void MaybePrintCacheStats() { MaybePrintCacheStats(std::cout); }
class BadHashException final : public std::exception {
public:
@@ -133,45 +132,37 @@ auto ActionPointDistancesCache::GetRaw(
// Check the persistent map first
if (auto it = persistentCache.find(cacheKey); it != persistentCache.end()) {
#if CACHE_STATS_LOGGING_
cacheStats.persistentHits++;
MaybePrintCacheStats();
#endif
if (kCacheStatsLogging) {
cacheStats.persistentHits++;
MaybePrintCacheStats();
}
// Return directly from persistent cache without TLS insertion
// This avoids the overhead of thread-local storage operations on hot path
return it->second.sharedPtr.get();
}
#if CACHE_STATS_LOGGING_
cacheStats.persistentMisses++;
#endif
if (kCacheStatsLogging) { cacheStats.persistentMisses++; }
// Check thread-local cache (no locks needed!)
if (auto it = tlsCache.find(cacheKey); it != tlsCache.end()) {
#if CACHE_STATS_LOGGING_
cacheStats.localHits++;
MaybePrintCacheStats();
#endif
if (kCacheStatsLogging) {
cacheStats.localHits++;
MaybePrintCacheStats();
}
return it->second.sharedPtr.get(); // Compute raw pointer on demand
}
#if CACHE_STATS_LOGGING_
cacheStats.localMisses++;
#endif
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;
})) {
#if CACHE_STATS_LOGGING_
cacheStats.sharedAccesses++;
#endif
if (kCacheStatsLogging) { cacheStats.sharedAccesses++; }
// Cache hit in shared cache - store in thread-local cache and return
tlsCache.emplace(cacheKey, CacheEntry(sharedResult));
#if CACHE_STATS_LOGGING_
MaybePrintCacheStats();
#endif
if (kCacheStatsLogging) { MaybePrintCacheStats(); }
return sharedResult.get();
}
@@ -2,9 +2,10 @@
// Created by Dan Crosby on 10/5/20.
//
#ifndef EAGLE0_ACTIONPOINTDISTANCESCACHE_HPP
#define EAGLE0_ACTIONPOINTDISTANCESCACHE_HPP
#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,8 +119,8 @@ public:
static size_t GetThreadLocalCacheSize();
};
using APDCache = shared_ptr<ActionPointDistancesCache>;
using APDCache = std::shared_ptr<ActionPointDistancesCache>;
} // namespace shardok
#endif // EAGLE0_ACTIONPOINTDISTANCESCACHE_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_ACTION_POINT_DISTANCES_CACHE_HPP
@@ -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;
}();
@@ -2,8 +2,8 @@
// Created by Dan Crosby on 10/13/22.
//
#ifndef EAGLE0_FIXEDACTIONPOINTDISTANCES_HPP
#define EAGLE0_FIXEDACTIONPOINTDISTANCES_HPP
#ifndef EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_FIXED_ACTION_POINT_DISTANCES_HPP
#define EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_FIXED_ACTION_POINT_DISTANCES_HPP
#include <utility>
#include <vector>
@@ -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);
@@ -44,4 +43,4 @@ public:
} // namespace shardok
#endif // EAGLE0_FIXEDACTIONPOINTDISTANCES_HPP
#endif // EAGLE0_SHARDOK_LIBRARY_ACTION_POINT_DISTANCES_FIXED_ACTION_POINT_DISTANCES_HPP
@@ -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" << std::endl;
}
@@ -8,6 +8,8 @@
#include "src/main/cpp/net/eagle0/shardok/library/action_result_applier/ActionResultApplier.hpp"
#include <string>
#include "src/main/cpp/net/eagle0/shardok/library/action_result_applier/GameStateCopier.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/action_result_applier/UnitHelpers.hpp"
#include "src/main/cpp/net/eagle0/shardok/library/map/HexMapHasher.hpp"
@@ -17,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;
@@ -29,6 +29,11 @@ using Unit = net::eagle0::shardok::storage::fb::Unit;
inline auto GetMutableUnit(GameState *state, UnitId unitId) -> Unit * {
return const_cast<Unit *>(state->mutable_units()->GetMutableObject(unitId));
}
inline auto UnitFromBytes(const std::string &unitBytes) -> const Unit & {
return *reinterpret_cast<const Unit *>(unitBytes.data());
}
using net::eagle0::shardok::storage::fb::VictoryCondition;
using net::eagle0::shardok::storage::fb::VictoryType;
@@ -86,7 +91,7 @@ void ApplyResolvedUnit(
const SettingsGetter &settingsGetter) {
ApplyResolvedUnit(
inoutState,
*((Unit *)resolvedUnit.unit_bytes().data()),
UnitFromBytes(resolvedUnit.unit_bytes()),
static_cast<net::eagle0::shardok::storage::fb::UnitStatus>(resolvedUnit.status()),
vipCapturedMoraleAdjustment,
settingsGetter);
@@ -96,7 +101,7 @@ void ApplyResolvedUnit(
GameStateT &inoutState,
const ResolvedUnitProto &resolvedUnit,
const double vipCapturedMoraleAdjustment) {
const Unit &unit = *((Unit *)resolvedUnit.unit_bytes().data());
const Unit &unit = UnitFromBytes(resolvedUnit.unit_bytes());
UnitId unitId = unit.unit_id();
if (unit.has_attached_hero() &&
@@ -139,7 +144,7 @@ void ApplyResolvedUnit(
std::erase_if(inoutState.units, [unitId](const auto &unit) {
return unit.unit_id() == unitId;
});
inoutState.units[unitId] = *((Unit *)resolvedUnit.unit_bytes().data());
inoutState.units[unitId] = UnitFromBytes(resolvedUnit.unit_bytes());
inoutState.units[unitId].mutate_status(
static_cast<net::eagle0::shardok::storage::fb::UnitStatus>(resolvedUnit.status()));
}
@@ -164,7 +169,7 @@ void MutatingAddUnits(GameStateW &mutatingState, const ActionResultProto &result
// First pass: check what kind of modifications we need
for (const auto &unitBytes : result.changed_units_fb()) {
const auto *unit = (Unit *)unitBytes.data();
const auto *unit = &UnitFromBytes(unitBytes);
maxChangedUnitId = std::max(maxChangedUnitId, unit->unit_id());
if (static_cast<unsigned int>(unit->unit_id()) >= mutatingState->units()->size()) {
@@ -194,7 +199,7 @@ void MutatingAddUnits(GameStateW &mutatingState, const ActionResultProto &result
// Convert reserved slots to real units in place
// We only need to process the units that are being changed
for (const auto &unitBytes : result.changed_units_fb()) {
const auto *unit = (Unit *)unitBytes.data();
const auto *unit = &UnitFromBytes(unitBytes);
auto *mutableUnit = GetMutableUnit(mutatingState.Get(), unit->unit_id());
if (mutableUnit->status() ==
net::eagle0::shardok::storage::fb::UnitStatus_RESERVED_SLOT) {
@@ -242,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);
}
@@ -293,13 +299,7 @@ void MutatingApplyResult(
const double vipCapturedMoraleAdjustment = settings.Backing().vip_captured_morale_adjustment();
for (const auto &changedUnitBytes : result.changed_units_fb()) {
const Unit *changedUnit = (Unit *)changedUnitBytes.data();
if (changedUnit->battalion().type() ==
net::eagle0::shardok::storage::fb::BattalionTypeId_UNDEAD &&
changedUnit->battalion().morale() != 50.0) {
printf("bad morale\n");
}
const Unit *changedUnit = &UnitFromBytes(changedUnitBytes);
internalAssert(
changedUnit->unit_id() < (int32_t)mutatingGameState->units()->size(),
@@ -383,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);
}

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