× Overview The Robot Learning Hub Curriculum Safety For Schools Contact Sales
Learning Hub/Demo Code/Rock Paper Scissors

Demo: Rock Paper Scissors

Status Available
Level Intermediate
Time 15–20 minutes

The robot plays rock-paper-scissors with the user. It counts down, chooses rock, paper, or scissors, moves its hand into the selected pose, and compares the result.

Honest note

This demo runs in keyboard mode first, where the user enters their choice. A camera-assisted version using gesture detection may be added later. Do not describe the current version as hand-gesture recognition unless that is actually implemented.

What students learn

Students learn how robot behaviors can include randomness, user input, hand pose presets, branching logic, and a repeated game loop.

Hardware used

  • Hand and finger servos
  • Optional speaker for countdown
  • Optional RealSense camera for a future camera-assisted mode

Concepts covered

  • Random choice
  • Hand pose presets
  • Branching logic
  • User interaction
  • Game loop
  • Optional vision classification

Run command

Terminal
ros2 run swayform_demos rock_paper_scissors

Starter code

This version uses a game loop so students can run multiple rounds without restarting. Each round is a clean sequence: countdown, choose, move, judge.

Note: These examples are written as classroom starter code. Final hardware APIs can be adjusted to match the installed SwayForm software image.
python — rock_paper_scissors.py
"""
Demo: Rock Paper Scissors

Purpose:
Play a round of rock-paper-scissors with the user. The robot picks randomly.

Important:
This version uses keyboard input for the user's choice.
A camera-assisted version can be added later using gesture detection.
Do not describe this as hand-recognition unless that is implemented.
"""

import random
from time import sleep
from swayform.motion import MotionClient
from swayform.audio import AudioPrompt


VALID_CHOICES = ["rock", "paper", "scissors"]
COUNTDOWN_SECONDS = 1.0
POSE_HOLD_SECONDS = 1.5
ROUNDS_TO_PLAY = 3

WINS_AGAINST = {
    "rock": "scissors",
    "scissors": "paper",
    "paper": "rock",
}


def countdown(audio: AudioPrompt) -> None:
    """Say rock, paper, scissors aloud before the reveal."""
    for word in ["Rock", "Paper", "Scissors", "Shoot!"]:
        audio.say(word)
        sleep(COUNTDOWN_SECONDS)


def get_user_choice() -> str:
    """Prompt the user and validate their choice."""
    while True:
        raw = input("Your move (rock / paper / scissors): ").strip().lower()
        if raw in VALID_CHOICES:
            return raw
        print(f"Please enter one of: {', '.join(VALID_CHOICES)}")


def judge(robot: str, user: str) -> str:
    """Return 'robot', 'user', or 'tie'."""
    if robot == user:
        return "tie"
    if WINS_AGAINST[robot] == user:
        return "robot"
    return "user"


def play_round(motion: MotionClient, audio: AudioPrompt) -> str:
    """Run one complete round. Returns winner: 'robot', 'user', or 'tie'."""
    robot_choice = random.choice(VALID_CHOICES)
    user_choice = get_user_choice()

    countdown(audio)

    motion.set_hand_pose("right_hand", robot_choice)
    sleep(POSE_HOLD_SECONDS)

    result = judge(robot_choice, user_choice)
    print(f"Robot: {robot_choice}  |  You: {user_choice}  |  Result: {result}")

    motion.set_hand_pose("right_hand", "relaxed")
    return result


def main() -> None:
    motion = MotionClient()
    audio = AudioPrompt()

    scores = {"robot": 0, "user": 0, "tie": 0}

    motion.safe_pose("idle")

    for round_num in range(1, ROUNDS_TO_PLAY + 1):
        print(f"\n--- Round {round_num} ---")
        winner = play_round(motion, audio)
        scores[winner] += 1

    print(f"\nFinal score — Robot: {scores['robot']}  You: {scores['user']}  Ties: {scores['tie']}")
    motion.safe_pose("idle")


if __name__ == "__main__":
    main()

Code walkthrough

WINS_AGAINST dictionary
The win rule is stored as a lookup table instead of nested if-statements. This makes the logic easier to read and change.
Input validation loop
get_user_choice loops until the user enters a valid move. This prevents the demo from crashing on a typo.
countdown function
The countdown says each word aloud before the reveal. Students can replace this with a visual LED countdown or a different audio cue.
play_round returns the winner
Each round returns who won. The main loop collects these and prints a final score, making it easy to extend into best-of-five.
judge function
Separating the win logic into its own function makes it easy to test. Students can call judge("rock","scissors") in the Python shell and verify the result without running the full demo.

Try changing this

  • Make the game best of three rounds.
  • Add sound effects or a countdown.
  • Add head movement when the robot wins or loses.
  • Add a scoreboard variable.
Safety

Hand poses should use tested finger positions. Do not over-close the fingers around a person's hand.

Next step

After Rock Paper Scissors, try Lab 07: Hand Pose Timing.