clawtan 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/clawtan/cli.py +111 -3
- package/package.json +1 -1
package/clawtan/cli.py
CHANGED
|
@@ -390,6 +390,19 @@ def _print_opponents(opponents: list):
|
|
|
390
390
|
print(line)
|
|
391
391
|
|
|
392
392
|
|
|
393
|
+
def _format_trade_tuple(val: list) -> str:
|
|
394
|
+
"""Decode trade resources (first 10 elements) into 'give X for Y' text.
|
|
395
|
+
|
|
396
|
+
Works for 10-element (OFFER_TRADE) and 11-element (current_trade,
|
|
397
|
+
ACCEPT/REJECT/CONFIRM) tuples — extra elements are ignored.
|
|
398
|
+
"""
|
|
399
|
+
giving = {RESOURCES[i]: val[i] for i in range(5) if val[i]}
|
|
400
|
+
wanting = {RESOURCES[i]: val[i + 5] for i in range(5) if val[i + 5]}
|
|
401
|
+
give_str = ", ".join(f"{n}x {r}" for r, n in giving.items()) or "nothing"
|
|
402
|
+
want_str = ", ".join(f"{n}x {r}" for r, n in wanting.items()) or "nothing"
|
|
403
|
+
return f"{give_str} for {want_str}"
|
|
404
|
+
|
|
405
|
+
|
|
393
406
|
_ACTION_HINTS = {
|
|
394
407
|
"RELEASE_CATCH": (
|
|
395
408
|
"Discard half your cards (server selects randomly).\n"
|
|
@@ -408,6 +421,33 @@ _ACTION_HINTS = {
|
|
|
408
421
|
"Year of Plenty: pick 2 free resources.\n"
|
|
409
422
|
" CLI: clawtan act PLAY_BOUNTIFUL_HARVEST '[\"DRIFTWOOD\",\"CORAL\"]'"
|
|
410
423
|
),
|
|
424
|
+
"OFFER_TRADE": (
|
|
425
|
+
"Offer a player-to-player trade. Value = 10-element list:\n"
|
|
426
|
+
" first 5 = resources you GIVE [DRIFTWOOD,CORAL,SHRIMP,KELP,PEARL],\n"
|
|
427
|
+
" last 5 = resources you WANT [DRIFTWOOD,CORAL,SHRIMP,KELP,PEARL].\n"
|
|
428
|
+
" CLI: clawtan act OFFER_TRADE '[0,0,0,1,0,0,1,0,0,0]' # give 1 KELP, want 1 CORAL"
|
|
429
|
+
),
|
|
430
|
+
"ACCEPT_TRADE": (
|
|
431
|
+
"Accept a trade offer. Value = 11-element current_trade tuple\n"
|
|
432
|
+
" (10 resource ints + offerer's turn index, echoed from the offer).\n"
|
|
433
|
+
" Just use the value shown in your available actions.\n"
|
|
434
|
+
" CLI: clawtan act ACCEPT_TRADE '[0,0,0,1,0,0,1,0,0,0,0]'"
|
|
435
|
+
),
|
|
436
|
+
"REJECT_TRADE": (
|
|
437
|
+
"Reject a trade offer. Value = 11-element current_trade tuple\n"
|
|
438
|
+
" (10 resource ints + offerer's turn index, echoed from the offer).\n"
|
|
439
|
+
" Just use the value shown in your available actions.\n"
|
|
440
|
+
" CLI: clawtan act REJECT_TRADE '[0,0,0,1,0,0,1,0,0,0,0]'"
|
|
441
|
+
),
|
|
442
|
+
"CONFIRM_TRADE": (
|
|
443
|
+
"Confirm trade with a specific acceptee. Value = 11-element list:\n"
|
|
444
|
+
" the 10 resource ints + the accepting player's color.\n"
|
|
445
|
+
" CLI: clawtan act CONFIRM_TRADE '[0,0,0,1,0,0,1,0,0,0,\"BLUE\"]'"
|
|
446
|
+
),
|
|
447
|
+
"CANCEL_TRADE": (
|
|
448
|
+
"Cancel your pending trade offer.\n"
|
|
449
|
+
" CLI: clawtan act CANCEL_TRADE"
|
|
450
|
+
),
|
|
411
451
|
}
|
|
412
452
|
|
|
413
453
|
|
|
@@ -567,6 +607,37 @@ def _print_actions(actions: list, my_color: str | None = None, state: dict | Non
|
|
|
567
607
|
print(f"\n (other players still need to act: {', '.join(sorted(other_colors))})")
|
|
568
608
|
|
|
569
609
|
|
|
610
|
+
def _print_trade_context(state: dict, my_color: str):
|
|
611
|
+
"""Show the active trade offer and who has accepted so far."""
|
|
612
|
+
trade = state.get("current_trade")
|
|
613
|
+
if not trade or not isinstance(trade, list) or len(trade) < 10:
|
|
614
|
+
return
|
|
615
|
+
|
|
616
|
+
prompt = state.get("current_prompt", "")
|
|
617
|
+
colors = state.get("colors", [])
|
|
618
|
+
offerer_idx = trade[10] if len(trade) > 10 else None
|
|
619
|
+
offerer = colors[offerer_idx] if offerer_idx is not None and offerer_idx < len(colors) else "?"
|
|
620
|
+
|
|
621
|
+
_section("Active Trade")
|
|
622
|
+
print(f" Offered by: {offerer}")
|
|
623
|
+
print(f" Trade: {_format_trade_tuple(trade)}")
|
|
624
|
+
|
|
625
|
+
if prompt == "DECIDE_TRADE":
|
|
626
|
+
if offerer == my_color:
|
|
627
|
+
print(" Waiting for other players to accept or reject.")
|
|
628
|
+
else:
|
|
629
|
+
print(" You must ACCEPT_TRADE or REJECT_TRADE.")
|
|
630
|
+
elif prompt == "DECIDE_ACCEPTEES":
|
|
631
|
+
acceptees = state.get("acceptees", [])
|
|
632
|
+
accepted = [colors[i] for i, a in enumerate(acceptees) if a and i < len(colors)]
|
|
633
|
+
if accepted:
|
|
634
|
+
print(f" Accepted by: {', '.join(accepted)}")
|
|
635
|
+
else:
|
|
636
|
+
print(" No one accepted.")
|
|
637
|
+
if offerer == my_color:
|
|
638
|
+
print(" You may CONFIRM_TRADE with an acceptee or CANCEL_TRADE.")
|
|
639
|
+
|
|
640
|
+
|
|
570
641
|
def _unpack_record(r):
|
|
571
642
|
"""Unpack an action record into (color, action_type, value).
|
|
572
643
|
|
|
@@ -671,6 +742,30 @@ def _format_live_action(color, action, val, state=None, pre_resources=None):
|
|
|
671
742
|
if action == "PLAY_CURRENT_BUILDING":
|
|
672
743
|
return f" [{ts}] {color} played Road Building"
|
|
673
744
|
|
|
745
|
+
if action == "OFFER_TRADE":
|
|
746
|
+
if isinstance(val, list) and len(val) == 10:
|
|
747
|
+
return f" [{ts}] {color} offered trade: {_format_trade_tuple(val)}"
|
|
748
|
+
return f" [{ts}] {color} offered a trade"
|
|
749
|
+
|
|
750
|
+
if action == "ACCEPT_TRADE":
|
|
751
|
+
if isinstance(val, list) and len(val) >= 10:
|
|
752
|
+
return f" [{ts}] {color} accepted trade: {_format_trade_tuple(val)}"
|
|
753
|
+
return f" [{ts}] {color} accepted a trade"
|
|
754
|
+
|
|
755
|
+
if action == "REJECT_TRADE":
|
|
756
|
+
if isinstance(val, list) and len(val) >= 10:
|
|
757
|
+
return f" [{ts}] {color} rejected trade: {_format_trade_tuple(val)}"
|
|
758
|
+
return f" [{ts}] {color} rejected a trade"
|
|
759
|
+
|
|
760
|
+
if action == "CONFIRM_TRADE":
|
|
761
|
+
if isinstance(val, list) and len(val) == 11:
|
|
762
|
+
partner = val[10]
|
|
763
|
+
return f" [{ts}] {color} confirmed trade with {partner}: {_format_trade_tuple(val[:10])}"
|
|
764
|
+
return f" [{ts}] {color} confirmed a trade"
|
|
765
|
+
|
|
766
|
+
if action == "CANCEL_TRADE":
|
|
767
|
+
return f" [{ts}] {color} cancelled their trade offer"
|
|
768
|
+
|
|
674
769
|
if action == "OCEAN_TRADE":
|
|
675
770
|
if isinstance(val, list) and len(val) >= 2:
|
|
676
771
|
giving = val[:-1]
|
|
@@ -901,6 +996,9 @@ def cmd_wait(args):
|
|
|
901
996
|
except (APIError, Exception):
|
|
902
997
|
pass
|
|
903
998
|
|
|
999
|
+
if state.get("is_resolving_trade"):
|
|
1000
|
+
_print_trade_context(state, color)
|
|
1001
|
+
|
|
904
1002
|
actions = state.get("current_playable_actions", [])
|
|
905
1003
|
if actions:
|
|
906
1004
|
_print_actions(actions, my_color=color, state=state)
|
|
@@ -1050,14 +1148,17 @@ def cmd_act(args):
|
|
|
1050
1148
|
_section("Resources")
|
|
1051
1149
|
_print_resources(my["resources"])
|
|
1052
1150
|
|
|
1151
|
+
if state.get("is_resolving_trade"):
|
|
1152
|
+
_print_trade_context(state, color)
|
|
1153
|
+
|
|
1053
1154
|
if my_actions:
|
|
1054
1155
|
_print_actions(actions, my_color=color, state=state)
|
|
1055
1156
|
else:
|
|
1056
1157
|
print("\n No actions available.")
|
|
1057
1158
|
elif my_actions:
|
|
1058
|
-
# We have actions even though current_color is someone else
|
|
1059
|
-
# (e.g. we also need to discard on a 7)
|
|
1060
1159
|
print(f" Prompt: {prompt}")
|
|
1160
|
+
if state.get("is_resolving_trade"):
|
|
1161
|
+
_print_trade_context(state, color)
|
|
1061
1162
|
_print_actions(actions, my_color=color, state=state)
|
|
1062
1163
|
else:
|
|
1063
1164
|
print(f"\n Action done. No more actions available. Run 'clawtan wait' for your next turn or action required.")
|
|
@@ -1354,7 +1455,14 @@ def main():
|
|
|
1354
1455
|
" PLAY_BOUNTIFUL_HARVEST <r> Year of Plenty, e.g. '[\"DRIFTWOOD\",\"CORAL\"]'\n"
|
|
1355
1456
|
" PLAY_TIDAL_MONOPOLY <res> Monopoly, e.g. SHRIMP\n"
|
|
1356
1457
|
" PLAY_CURRENT_BUILDING Road Building\n"
|
|
1357
|
-
"
|
|
1458
|
+
" OFFER_TRADE <val> Player trade: 10-element list [give5, want5]\n"
|
|
1459
|
+
" e.g. '[0,0,0,1,0,0,1,0,0,0]' = give 1 KELP, want 1 CORAL\n"
|
|
1460
|
+
" ACCEPT_TRADE <val> Accept trade (echo the 11-element value from actions)\n"
|
|
1461
|
+
" REJECT_TRADE <val> Reject trade (echo the 11-element value from actions)\n"
|
|
1462
|
+
" CONFIRM_TRADE <val> Confirm with acceptee: 10 ints + color, e.g.\n"
|
|
1463
|
+
" '[0,0,0,1,0,0,1,0,0,0,\"BLUE\"]'\n"
|
|
1464
|
+
" CANCEL_TRADE Cancel your pending trade offer\n"
|
|
1465
|
+
" OCEAN_TRADE <val> Maritime trade, e.g. '[\"KELP\",\"KELP\",\"KELP\",\"KELP\",\"SHRIMP\"]'\n"
|
|
1358
1466
|
" END_TIDE End your turn\n"
|
|
1359
1467
|
"\n"
|
|
1360
1468
|
"VALUE is parsed as JSON. Bare words (e.g. SHRIMP) are treated as strings.\n"
|