In [6]:
from IPython.display import Image
Image(url='https://raw.githubusercontent.com/bluemoondom/quantum/refs/heads/quantum/rock-paper-scissors.jpg')
Out[6]:
No description has been provided for this image
In [1]:
import numpy as np
import matplotlib.pyplot as plt
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister
from qiskit_aer import AerSimulator
import random
import ipywidgets as widgets
from IPython.display import display, clear_output, HTML
import io
from PIL import Image, ImageDraw, ImageFont

class QuantumRPSGame:
    def __init__(self):
        self.simulator = AerSimulator()
        self.player_wins = 0
        self.bob_wins = 0
        self.ties = 0
        self.rounds_played = 0
        self.chsh_values = []
        self.game_history = []
        self.player_choice = None
        self.output = widgets.Output()
        self.images = self.create_rps_images()
        self.setup_ui()
        
    def create_rps_images(self):
        """Create simple images for rock, paper, scissors"""
        images = {}
        size = (120, 120)
        
        # Rock image
        rock_img = Image.new('RGBA', size, (255, 255, 255, 0))
        draw = ImageDraw.Draw(rock_img)
        draw.ellipse([20, 20, 100, 100], fill=(100, 100, 100, 255), outline=(50, 50, 50, 255), width=4)
        for i in range(5):
            x, y = random.randint(30, 90), random.randint(30, 90)
            draw.ellipse([x-3, y-3, x+3, y+3], fill=(80, 80, 80, 255))
        images['Rock'] = rock_img
        
        # Scissors image
        scissors_img = Image.new('RGBA', size, (255, 255, 255, 0))
        draw = ImageDraw.Draw(scissors_img)
        draw.polygon([(30, 30), (40, 20), (50, 60), (40, 70)], fill=(180, 180, 180, 255), outline=(120, 120, 120, 255))
        draw.polygon([(70, 30), (80, 20), (90, 60), (80, 70)], fill=(180, 180, 180, 255), outline=(120, 120, 120, 255))
        draw.rectangle([45, 60, 75, 90], fill=(139, 69, 19, 255), outline=(101, 50, 14, 255), width=2)
        images['Scissors'] = scissors_img
        
        # Paper image
        paper_img = Image.new('RGBA', size, (255, 255, 255, 0))
        draw = ImageDraw.Draw(paper_img)
        draw.rectangle([25, 15, 95, 105], fill=(255, 255, 255, 255), outline=(100, 100, 100, 255), width=3)
        for i in range(25, 95, 12):
            draw.line([35, i, 85, i], fill=(200, 200, 200, 255), width=1)
        draw.polygon([(80, 15), (95, 15), (95, 30)], fill=(230, 230, 230, 255))
        images['Paper'] = paper_img
        
        return images
    
    def create_quantum_effect_image(self):
        """Create quantum effect visualization"""
        size = (200, 120)
        img = Image.new('RGBA', size, (0, 0, 0, 0))
        draw = ImageDraw.Draw(img)
        for i in range(15):
            x = random.randint(10, 190)
            y = random.randint(10, 110)
            r = random.randint(2, 8)
            colors = [(100, 200, 255), (255, 100, 200), (200, 255, 100), (255, 200, 100)]
            color = random.choice(colors)
            draw.ellipse([x-r, y-r, x+r, y+r], fill=color + (150,))
        return img
    
    def img_to_base64(self, img):
        """Convert PIL image to base64 string for HTML display"""
        buf = io.BytesIO()
        img.save(buf, format='PNG')
        buf.seek(0)
        import base64
        return base64.b64encode(buf.read()).decode()
    
    def setup_ui(self):
        """Set up user interface"""
        self.title = widgets.HTML(
            value="<h1 style='text-align: center; color: #4CAF50;'>🎮 Play Against Quantum Bob!</h1>"
        )
        
        self.rock_button = widgets.Button(
            description='🗿 Rock',
            button_style='',
            layout=widgets.Layout(width='120px', height='60px', margin='5px')
        )
        self.scissors_button = widgets.Button(
            description='✂️ Scissors',
            button_style='',
            layout=widgets.Layout(width='120px', height='60px', margin='5px')
        )
        self.paper_button = widgets.Button(
            description='📄 Paper',
            button_style='',
            layout=widgets.Layout(width='120px', height='60px', margin='5px')
        )
        
        def make_rock_choice(b):
            with self.output:
                print("Rock button pressed!")
            self.make_choice('Rock') 
        def make_scissors_choice(b):
            with self.output:
                print("Scissors button pressed!")
            self.make_choice('Scissors')
        def make_paper_choice(b):
            with self.output:
                print("Paper button pressed!")
            self.make_choice('Paper')
        
        self.rock_button.on_click(make_rock_choice)
        self.scissors_button.on_click(make_scissors_choice)
        self.paper_button.on_click(make_paper_choice)
        
        self.reset_button = widgets.Button(
            description='🔄 Reset',
            button_style='warning',
            layout=widgets.Layout(width='100px', height='40px')
        )
        self.reset_button.on_click(self.reset_game)
        
        self.score_widget = widgets.HTML(
            value=self.get_score_html()
        )
        
        self.choice_info = widgets.HTML(
            value="<div style='text-align: center; color: #666; margin: 10px;'><h3>👆 Choose your move!</h3></div>"
        )

        self.player_display = widgets.HTML(value="<div style='text-align: center;'><h3>👤 Your Move</h3><p>Waiting for selection...</p></div>")
        self.vs_widget = widgets.HTML(value="<h2 style='text-align: center; color: #FF5722;'>VS</h2>")
        self.bob_display = widgets.HTML(value="<div style='text-align: center;'><h3>🤖 Quantum Bob</h3><p>Ready...</p></div>")
        self.result_widget = widgets.HTML(value="")
        self.quantum_info = widgets.HTML(value="")

        self.game_area = widgets.VBox([
            self.title,
            self.score_widget,
            self.choice_info,
            widgets.HBox([self.rock_button, self.scissors_button, self.paper_button], 
                         layout=widgets.Layout(justify_content='center')),
            widgets.HBox([self.player_display, self.vs_widget, self.bob_display],
                         layout=widgets.Layout(justify_content='center')),
            self.result_widget,
            self.quantum_info,
            self.output
        ])
    
    def get_score_html(self):
        """Generate HTML for score display"""
        total = max(1, self.rounds_played)
        player_pct = (self.player_wins / total) * 100
        bob_pct = (self.bob_wins / total) * 100
        tie_pct = (self.ties / total) * 100
        return f"""<div style='text-align: center; margin: 20px; padding: 15px; 
                    background: linear-gradient(45deg, #e8f5e8, #f0f8ff); 
                    border-radius: 10px; border: 2px solid #4CAF50;'>
            <h3>🏆 Score after {self.rounds_played} rounds</h3>
            <p><strong>You:</strong> {self.player_wins} ({player_pct:.1f}%) | 
               <strong>Quantum Bob:</strong> {self.bob_wins} ({bob_pct:.1f}%) | 
               <strong>Ties:</strong> {self.ties} ({tie_pct:.1f}%)</p></div>"""
    
    def make_choice(self, choice):
        """Process player's choice and start the battle"""
        self.player_choice = choice
        print(f"🎯 Move selected: {choice}")
        choice_emojis = {"Rock": "🗿", "Scissors": "✂️", "Paper": "📄"}
        self.player_display.value = f"""<div style='text-align: center; background: #e3f2fd; padding: 15px; 
                    border-radius: 10px; margin: 5px; border: 2px solid #2196F3;'>
            <h3 style='color: #2196F3;'>👤 Your Move</h3>
            <div style='font-size: 48px; margin: 10px;'>{choice_emojis[choice]}</div>
            <p><strong>{choice}</strong></p></div>"""
        self.choice_info.value = "<div style='text-align: center; color: #FF5722;'><h3>⚛️ Bob is preparing his quantum move...</h3></div>"
        print("⚛️ Bob is preparing his quantum move...")
        self.show_quantum_processing()
        self.play_against_bob()
    
    def show_quantum_processing(self):
        """Show quantum state for Bob"""
        quantum_img = self.create_quantum_effect_image()
        quantum_b64 = self.img_to_base64(quantum_img)
        self.bob_display.value = f"""<div style='text-align: center; background: #fff3e0; padding: 15px; 
                    border-radius: 10px; margin: 5px; border: 2px solid #FF9800;'>
            <h3 style='color: #FF9800;'>🤖 Quantum Bob</h3>
            <img src="data:image/png;base64,{quantum_b64}" style="width: 100px; height: 60px;">
            <p>Quantum processing...</p></div>"""
    
    def create_chsh_circuit(self, alice_input, bob_input):
        """Create CHSH test circuit"""
        qr = QuantumRegister(2, 'q')
        cr = ClassicalRegister(2, 'c')
        qc = QuantumCircuit(qr, cr)

        # Create entangled Bell state
        qc.h(0)
        qc.cx(0, 1)

        # Apply rotations based on input strategies
        if alice_input == 1:
            qc.ry(-np.pi/4, 0)
        if bob_input == 1:
            qc.ry(np.pi/4, 1)
        
        # Measure both qubits
        qc.measure(0, 0)
        qc.measure(1, 1)
        return qc
    
    def play_quantum_round(self, alice_strategy, bob_strategy):
        """Run quantum circuit using AerSimulator"""
        qc = self.create_chsh_circuit(alice_strategy, bob_strategy)
        job = self.simulator.run(qc, shots=1)
        result = job.result()
        counts = result.get_counts()
        measurement = list(counts.keys())[0]
        alice_result = int(measurement[1])
        bob_result = int(measurement[0])
        return alice_result, bob_result
    
    def choice_to_strategy(self, choice):
        """Convert player choice to quantum strategy"""
        choice_map = {"Rock": 0, "Scissors": 1, "Paper": 2}
        return choice_map[choice] % 2
    
    def convert_to_rps(self, quantum_result, strategy, base_choice=None):
        """Convert quantum result to rock/paper/scissors"""
        if base_choice:
            return base_choice
        combined = (quantum_result + strategy) % 3
        moves = ['Rock', 'Scissors', 'Paper']
        return moves[combined]
    
    def determine_winner(self, player_move, bob_move):
        """Determine the winner of the round"""
        if player_move == bob_move:
            return "Tie"
        elif (player_move == "Rock" and bob_move == "Scissors") or \
             (player_move == "Scissors" and bob_move == "Paper") or \
             (player_move == "Paper" and bob_move == "Rock"):
            return "Player"
        else:
            return "Bob"
    
    def play_against_bob(self):
        """Main game logic"""
        if not self.player_choice:
            return

        # Convert choices to quantum strategies
        player_strategy = self.choice_to_strategy(self.player_choice)
        bob_strategy = random.randint(0, 1)
        
        # Play quantum round
        player_quantum, bob_quantum = self.play_quantum_round(player_strategy, bob_strategy)
        
        # Convert quantum results to RPS moves
        player_move = self.player_choice
        bob_move = self.convert_to_rps(bob_quantum, bob_strategy)
        
        # Determine winner
        winner = self.determine_winner(player_move, bob_move)
        
        # Update scores
        if winner == "Player":
            self.player_wins += 1
        elif winner == "Bob":
            self.bob_wins += 1
        else:
            self.ties += 1
        
        self.rounds_played += 1
        self.game_history.append((player_move, bob_move, winner))
        
        # Update display
        self.update_display(player_move, bob_move, winner, player_strategy, bob_strategy, 
                          player_quantum, bob_quantum)
        
        self.player_choice = None
    
    def update_display(self, player_move, bob_move, winner, player_strategy, bob_strategy,
                      player_quantum, bob_quantum):
        """Update the display with round results"""
        print(f"\n🎮 ROUND #{self.rounds_played} RESULT")
        print(f"👤 You: {player_move}")
        print(f"🤖 Bob: {bob_move}")
        
        if winner == "Player":
            print("🎉 YOU WIN!")
        elif winner == "Bob":
            print("🤖 Bob wins!")
        else:
            print("🤝 It's a tie!")
        print(f"📊 Score: You {self.player_wins} | Bob {self.bob_wins} | Ties {self.ties}")
        print(f"⚛️ Your strategy: {player_strategy}, Bob: {bob_strategy} → {bob_quantum}")
        print("-" * 50)

        # Update score display
        self.score_widget.value = self.get_score_html()
        
        # Update Bob's display with his move
        choice_emojis = {"Rock": "🗿", "Scissors": "✂️", "Paper": "📄"}
        self.bob_display.value = f"""
        <div style='text-align: center; background: #fff3e0; padding: 15px; border-radius: 10px; margin: 5px; border: 2px solid #FF9800;'>
            <h3 style='color: #FF9800;'>🤖 Quantum Bob</h3>
            <div style='font-size: 48px; margin: 10px;'>{choice_emojis[bob_move]}</div>
            <p><strong>{bob_move}</strong></p>
            <small>Strategy: {bob_strategy} | Quantum: {bob_quantum}</small></div>"""

        # Update result display
        if winner == "Player":
            winner_color = "#4CAF50"
            winner_text = "🎉 YOU WIN!"
        elif winner == "Bob":
            winner_color = "#FF5722"
            winner_text = "🤖 Bob wins!"
        else:
            winner_color = "#FF9800"
            winner_text = "🤝 It's a tie!"
        
        self.result_widget.value = f"""<div style='text-align: center; margin: 20px; padding: 15px; 
                    background: {winner_color}20; border-radius: 15px; 
                    border: 3px solid {winner_color};'>
            <h2 style='color: {winner_color};'>{winner_text}</h2>
            <p>Round #{self.rounds_played}</p></div>"""
            
        # Update quantum info display
        self.quantum_info.value = f"""<div style='text-align: center; margin: 15px; padding: 10px; 
                    background: linear-gradient(45deg, #e8f5e8, #f0f8ff); 
                    border-radius: 10px;'>
            <h4>⚛️ Quantum Details</h4>
            <p>Your move: {player_move} (strategy: {player_strategy})<br>
               Bob used quantum entanglement to generate his move<br>
               Quantum result: {bob_quantum} → {bob_move}</p></div>"""

        # Reset choice info
        self.choice_info.value = "<div style='text-align: center; color: #666; margin: 10px;'><h3>👆 Choose your next move!</h3></div>"

    def reset_game(self, button):
        """Reset the game"""
        with self.output:
            print("🔄 Resetting game...")
            
        self.player_wins = 0
        self.bob_wins = 0
        self.ties = 0
        self.rounds_played = 0
        self.game_history = []
        self.player_choice = None
        
        # Reset all displays
        self.score_widget.value = self.get_score_html()
        self.player_display.value = "<div style='text-align: center;'><h3>👤 Your Move</h3><p>Waiting for selection...</p></div>"
        self.bob_display.value = "<div style='text-align: center;'><h3>🤖 Quantum Bob</h3><p>Ready...</p></div>"
        self.result_widget.value = ""
        self.quantum_info.value = ""
        self.choice_info.value = "<div style='text-align: center; color: #666; margin: 10px;'><h3>👆 Choose your move!</h3></div>"
        
        with self.output:
            self.output.clear_output()
            print("🔄 Game reset! Ready for a new battle.")
            
    def display(self):
        """Display the game interface"""
        return self.game_area
        
    def show_stats(self):
        """Display detailed statistics"""
        if not self.game_history:
            print("No rounds played yet!")
            return
        
        fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(12, 10))
        
        # Win distribution pie chart
        labels = ['You', 'Quantum Bob', 'Ties']
        sizes = [self.player_wins, self.bob_wins, self.ties]
        colors = ['lightgreen', 'lightcoral', 'lightgray']
        ax1.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', startangle=90)
        ax1.set_title('Win Distribution')

        # Move frequency bar chart
        player_moves = [move[0] for move in self.game_history]
        bob_moves = [move[1] for move in self.game_history]
        
        move_counts_player = {move: player_moves.count(move) for move in ['Rock', 'Scissors', 'Paper']}
        move_counts_bob = {move: bob_moves.count(move) for move in ['Rock', 'Scissors', 'Paper']}
        
        x = np.arange(len(move_counts_player))
        width = 0.35
        
        ax2.bar(x - width/2, list(move_counts_player.values()), width, label='You', color='lightgreen')
        ax2.bar(x + width/2, list(move_counts_bob.values()), width, label='Quantum Bob', color='lightcoral')
        ax2.set_xlabel('Moves')
        ax2.set_ylabel('Count')
        ax2.set_title('Move Frequency')
        ax2.set_xticks(x)
        ax2.set_xticklabels(list(move_counts_player.keys()))
        ax2.legend()

        # CHSH values over time (if available)
        if self.chsh_values:
            ax3.plot(self.chsh_values, 'o-', color='purple', markersize=6)
            ax3.axhline(y=2, color='red', linestyle='--', label='Classical boundary')
            ax3.set_xlabel('Test number')
            ax3.set_ylabel('|CHSH value|')
            ax3.set_title('Quantum advantage over time')
            ax3.legend()
            ax3.grid(True, alpha=0.3)

        # Score evolution over time
        player_score_history = []
        bob_score_history = []
        player_wins_temp = 0
        bob_wins_temp = 0
        
        for _, _, winner in self.game_history:
            if winner == "Player":
                player_wins_temp += 1
            elif winner == "Bob":
                bob_wins_temp += 1
            player_score_history.append(player_wins_temp)
            bob_score_history.append(bob_wins_temp)
        
        ax4.plot(player_score_history, label='You', color='green', linewidth=2)
        ax4.plot(bob_score_history, label='Quantum Bob', color='red', linewidth=2)
        ax4.set_xlabel('Round')
        ax4.set_ylabel('Wins')
        ax4.set_title('Score Evolution')
        ax4.legend()
        ax4.grid(True, alpha=0.3)
        
        plt.tight_layout()
        plt.show()


# Example usage of the CHSH circuit
a_input = 1
b_input = 1
qr = QuantumRegister(2, 'q')
cr = ClassicalRegister(2, 'c')
qc = QuantumCircuit(qr, cr)
qc.h(0)
qc.cx(0, 1)
if a_input == 1:
    qc.ry(-np.pi/4, 0)
if b_input == 1:
    qc.ry(np.pi/4, 1)    
qc.measure(0, 0)
qc.measure(1, 1)
print(f"{a_input} VS {b_input}")
qc.draw('mpl')
1 VS 1
---------------------------------------------------------------------------
MissingOptionalLibraryError               Traceback (most recent call last)
Cell In[1], line 455
    453 qc.measure(1, 1)
    454 print(f"{a_input} VS {b_input}")
--> 455 qc.draw('mpl')

File D:\python\myqiskit2\Lib\site-packages\qiskit\circuit\quantumcircuit.py:3943, in QuantumCircuit.draw(self, output, scale, filename, style, interactive, plot_barriers, reverse_bits, justify, vertical_compression, idle_wires, with_layout, fold, ax, initial_state, cregbundle, wire_order, expr_len, measure_arrows)
   3940 # pylint: disable=cyclic-import
   3941 from qiskit.visualization import circuit_drawer
-> 3943 return circuit_drawer(
   3944     self,
   3945     scale=scale,
   3946     filename=filename,
   3947     style=style,
   3948     output=output,
   3949     interactive=interactive,
   3950     plot_barriers=plot_barriers,
   3951     reverse_bits=reverse_bits,
   3952     justify=justify,
   3953     vertical_compression=vertical_compression,
   3954     idle_wires=idle_wires,
   3955     with_layout=with_layout,
   3956     fold=fold,
   3957     ax=ax,
   3958     initial_state=initial_state,
   3959     cregbundle=cregbundle,
   3960     wire_order=wire_order,
   3961     expr_len=expr_len,
   3962     measure_arrows=measure_arrows,
   3963 )

File D:\python\myqiskit2\Lib\site-packages\qiskit\visualization\circuit\circuit_visualization.py:350, in circuit_drawer(circuit, scale, filename, style, output, interactive, plot_barriers, reverse_bits, justify, vertical_compression, idle_wires, with_layout, fold, ax, initial_state, cregbundle, wire_order, expr_len, measure_arrows)
    335     return _generate_latex_source(
    336         circuit,
    337         filename=filename,
   (...)    347         wire_order=complete_wire_order,
    348     )
    349 elif output == "mpl":
--> 350     image = _matplotlib_circuit_drawer(
    351         circuit,
    352         scale=scale,
    353         filename=filename,
    354         style=style,
    355         plot_barriers=plot_barriers,
    356         reverse_bits=reverse_bits,
    357         justify=justify,
    358         idle_wires=idle_wires,
    359         with_layout=with_layout,
    360         fold=fold,
    361         ax=ax,
    362         initial_state=initial_state,
    363         cregbundle=cregbundle,
    364         wire_order=complete_wire_order,
    365         expr_len=expr_len,
    366         measure_arrows=measure_arrows,
    367     )
    368 else:
    369     raise VisualizationError(
    370         f"Invalid output type {output} selected. The only valid choices "
    371         "are text, latex, latex_source, and mpl"
    372     )

File D:\python\myqiskit2\Lib\site-packages\qiskit\visualization\circuit\circuit_visualization.py:742, in _matplotlib_circuit_drawer(circuit, scale, filename, style, plot_barriers, reverse_bits, justify, idle_wires, with_layout, fold, ax, initial_state, cregbundle, wire_order, expr_len, measure_arrows)
    739 if fold is None:
    740     fold = 25
--> 742 qcd = _matplotlib.MatplotlibDrawer(
    743     qubits,
    744     clbits,
    745     nodes,
    746     circuit,
    747     scale=scale,
    748     style=style,
    749     reverse_bits=reverse_bits,
    750     plot_barriers=plot_barriers,
    751     fold=fold,
    752     ax=ax,
    753     initial_state=initial_state,
    754     cregbundle=cregbundle,
    755     with_layout=with_layout,
    756     expr_len=expr_len,
    757     measure_arrows=measure_arrows,
    758 )
    759 return qcd.draw(filename)

File D:\python\myqiskit2\Lib\site-packages\qiskit\utils\classtools.py:111, in _WrappedMethod.__get__.<locals>.out(*args, **kwargs)
    108 @functools.wraps(method)
    109 def out(*args, **kwargs):
    110     for callback in self._before:
--> 111         callback.__get__(obj, objtype)(*args, **kwargs)
    112     retval = method(*args, **kwargs)
    113     for callback in self._after:

File D:\python\myqiskit2\Lib\site-packages\qiskit\utils\lazy_tester.py:41, in _RequireNow.__call__(self, *_args, **_kwargs)
     40 def __call__(self, *_args, **_kwargs):
---> 41     self._tester.require_now(self._feature)

File D:\python\myqiskit2\Lib\site-packages\qiskit\utils\lazy_tester.py:221, in LazyDependencyManager.require_now(self, feature)
    219 if self:
    220     return
--> 221 raise MissingOptionalLibraryError(
    222     libname=self._name, name=feature, pip_install=self._install, msg=self._msg
    223 )

MissingOptionalLibraryError: "The 'pylatexenc' library is required to use 'MatplotlibDrawer'. You can install it with 'pip install pylatexenc'."
In [2]:
game = QuantumRPSGame()
display(game.display())
VBox(children=(HTML(value="<h1 style='text-align: center; color: #4CAF50;'>🎮 Play Against Quantum Bob!</h1>"),…
In [3]:
game.show_stats()
No description has been provided for this image
In [ ]: