rpsa-sdk
A minimal, easy-to-use SDK for building Rock-Paper-Scissors strategies in Python. It provides:
- A base
Strategyinterface you can subclass to ensure correct method signatures. - Utility helper functions for common patterns (random play, countering, frequency analysis).
- Optional ML-model integration so you can plug in your own predictive model.
Table of Contents
- Installation
- Getting Started
- Core Interface:
Strategy - Utility Helpers
- Writing Your Own Strategy
- Example:
FrequencyStrategy - Running in a Contest
Installation
Install directly from PyPI:
pip install rpsa-sdk
Getting Started
Import the SDK components you need:
from rpsa_sdk.strategy import Strategy
from rpsa_sdk.helpers import random_move, counter_move, most_common
-
Strategy
An abstract base class. Subclass this and implement two methods:play(): Decide and return your next move ("rock","paper", or"scissors").handle_moves(): Update your internal state after each round, given your own move and the opponent’s move.
-
Helpers
Utility functions to speed up development:random_move()— returns a uniformly random choice of rock, paper, or scissors.counter_move(x)— returns the move that defeats the given movex.most_common(history, idx)— from a list of(own_move, opponent_move)tuples, finds the most frequent move at positionidx(use 0 or 1).
Core Interface: Strategy
All custom strategies must subclass Strategy:
class Strategy(ABC):
"""
Base class for RPS strategies.
Attributes:
name: ClassVar[str] # Unique strategy identifier
model: Any # Optional ML artifact
"""
name: ClassVar[str]
model: Any
def __init__(self, model: Any = None):
self.model = model
@abstractmethod
def play(self) -> Literal["rock", "paper", "scissors"]:
"""Return the next move."""
...
@abstractmethod
def handle_moves(self, own_move: OPTIONS, opponent_move: OPTIONS) -> None:
"""Update internal state after each round."""
...
Why?
- Enforces a consistent API for contest runners.
- Guarantees your strategy will be called in the expected way.
Utility Helpers
Located in rpsa_sdk/helpers.py, these functions speed up development:
| Function | Description |
|---|---|
random_move() |
Returns a uniformly random choice of "rock", "paper", or "scissors". |
counter_move(x) |
Returns the move that defeats the given move x. |
most_common(history, idx) |
From a list of (own_move, opponent_move) tuples, finds the most frequent move at position idx. |
from rpsa_sdk.helpers import random_move, counter_move, most_common
Use these helpers to quickly prototype or augment your own strategy logic.
Writing Your Own Strategy
- Subclass
Strategyand give your class a uniquenameto identify it.
class MyStrategy(Strategy):
name = "MyUniqueStrategy_v1"
...
- Implement the required methods:
play(): decide and return your next move.handle_moves(): update internal state after each round based on your and the opponent’s moves.
- Add optional parameters in your constructor (for example, history size or custom settings).
- Expose your strategy by assigning your class to a top-level
strategyvariable so the contest harness can import and instantiate it.
strategy = MyStrategy
Full Example: FrequencyStrategy
A ready-to-use strategy that counters the opponent’s most frequent recent move:
from rpsa_sdk.strategy import Strategy
from rpsa_sdk.helpers import counter_move, most_common
class FrequencyStrategy(Strategy):
name = "FrequencyStrategy_v1"
def __init__(self, model=None, max_history=50):
super().__init__(model)
self.history = []
self.max_history = max_history
def play(self):
if not self.history:
return "rock"
mc = most_common(self.history, idx=1)
return counter_move(mc)
def handle_moves(self, own_move, opponent_move):
self.history.append((own_move, opponent_move))
if len(self.history) > self.max_history:
self.history.pop(0)
# The contest runner will import this:
strategy = FrequencyStrategy
Running in a Contest
-
Place your strategy file into the code mirror.
-
Ensure it exposes a top-level
strategyvariable pointing to your class. -
Upload you ML model (if there are any), and use it in your
modelvariable -
The contest harness will:
-
Instantiate with
model=None(or load your uploaded model). -
Call
play()each round and thenhandle_moves(...).
-
Metadata
Release files for rpsa-sdk 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| rpsa_sdk-0.1.2.tar.gz | 4.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| rpsa_sdk-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 10.2 kB
Release files / rpsa_sdk-0.1.2.tar.gz
| Download URL | rpsa_sdk-0.1.2.tar.gz |
|---|---|
| Size | 4.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3768df18dae0f771d32da68aecbe43120dc16ea1322d32dacf558adc4d0df248
|
|
BLAKE2b-256 checksum How to use checksums |
9041e3aefb59d86e6d35116cff308ee5e6c03ff69d1a542d8e4905b5345957fe
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.3 CPython/3.11.1 Windows/10
|
Release files / rpsa_sdk-0.1.2-py3-none-any.whl
| Download URL | rpsa_sdk-0.1.2-py3-none-any.whl |
|---|---|
| Size | 5.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
139006cb534b653dc42275ecadf38bcd6843c98e6ae696857566bbbabcd06d1a
|
|
BLAKE2b-256 checksum How to use checksums |
a6f3a3492d685ecc87726472a907cc31163c8e82a04c2542d9f5d82ac7fe713c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.8.3 CPython/3.11.1 Windows/10
|