From 5657b241e59902a53b625f89136f61fbe663cb32 Mon Sep 17 00:00:00 2001 From: Luca Di Vita Date: Tue, 10 Oct 2023 12:34:00 +0200 Subject: [PATCH 1/6] code simplification --- Live Coding Completo.ipynb | 3535 +++++++++++++++++++++--------------- 1 file changed, 2049 insertions(+), 1486 deletions(-) diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index 14f4d5a..aefa5d5 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -1,1511 +1,2074 @@ { - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "id": "b35fe87b", - "metadata": {}, - "source": [ - "# Rock - Paper - Scissors - Lizard - Spock\n", - "\n", - "Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano." - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "78e5f376", - "metadata": {}, - "source": [ - "## Task 1\n", - "\n", - "Nella prossima cella studieremo:\n", - "\n", - "* cos'è una variabile in Python\n", - "* quali sono i tipi di variabile che è possibile avere in Python\n", - "* come è possible prendere un input da parte dell'utente\n", - "* come è possibile creare una lista con le possibili scelte di gioco\n", - "* come è possibile generare la mossa del computer in maniera casuale" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6cfa68db", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.287013Z", - "start_time": "2023-05-19T12:20:20.860873Z" - } - }, - "outputs": [], - "source": [ - "intero=10\n", - "booleano=True\n", - "numero_float=0.13\n", - "stringa='pycon'\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.303529Z", - "start_time": "2023-05-19T12:20:20.876923Z" + "cells": [ + { + "cell_type": "markdown", + "id": "b35fe87b", + "metadata": { + "id": "b35fe87b" + }, + "source": [ + "# Rock - Paper - Scissors - Lizard - Spock\n", + "\n", + "Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano." + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print('Ciao Mondo :)')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.333073Z", - "start_time": "2023-05-19T12:20:20.891457Z" + { + "cell_type": "markdown", + "id": "78e5f376", + "metadata": { + "id": "78e5f376" + }, + "source": [ + "## Task 1\n", + "\n", + "Nella prossima cella studieremo:\n", + "\n", + "* cos'è una variabile in Python\n", + "* quali sono i tipi di variabile che è possibile avere in Python\n", + "* come è possible prendere un input da parte dell'utente\n", + "* come è possibile creare una lista con le possibili scelte di gioco\n", + "* come è possibile generare la mossa del computer in maniera casuale" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print(intero)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.334653Z", - "start_time": "2023-05-19T12:20:20.905149Z" + { + "cell_type": "code", + "execution_count": 1, + "id": "6cfa68db", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:23.287013Z", + "start_time": "2023-05-19T12:20:20.860873Z" + }, + "id": "6cfa68db" + }, + "outputs": [], + "source": [ + "intero=10\n", + "booleano=True\n", + "numero_float=0.13\n", + "stringa='pycon'\n" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print(stringa,intero)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:26.414596Z", - "start_time": "2023-05-19T12:20:20.924676Z" + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:23.303529Z", + "start_time": "2023-05-19T12:20:20.876923Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "DLo0HbU8jwtm", + "outputId": "9226f8b9-f85b-4771-de99-c977f968902c" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Ciao Mondo :)\n" + ] + } + ], + "source": [ + "print('Ciao Mondo :)')" + ], + "id": "DLo0HbU8jwtm" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "risultato = input('digita un numero?')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:26.415102Z", - "start_time": "2023-05-19T12:20:26.202688Z" + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:23.333073Z", + "start_time": "2023-05-19T12:20:20.891457Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "0OX9TkPDjwtm", + "outputId": "8d2b6b1b-6616-4391-ec37-2b4eea872887" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "10\n" + ] + } + ], + "source": [ + "print(intero)" + ], + "id": "0OX9TkPDjwtm" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print(risultato)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.451911Z", - "start_time": "2023-05-19T12:20:26.220803Z" + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:23.334653Z", + "start_time": "2023-05-19T12:20:20.905149Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "W70GvccNjwtn", + "outputId": "74b1298a-18b6-4de1-932d-0c5d8d8530a3" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "pycon 10\n" + ] + } + ], + "source": [ + "print(stringa,intero)" + ], + "id": "W70GvccNjwtn" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "user_action = input(\"Enter a choice (rock, paper, scissors): \")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.466948Z", - "start_time": "2023-05-19T12:20:30.278604Z" + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:26.414596Z", + "start_time": "2023-05-19T12:20:20.924676Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "sCQu4LkLjwtn", + "outputId": "18546cab-9bb5-4ba5-eff3-e8d1f6f3cdfb" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "digita un numero?6\n" + ] + } + ], + "source": [ + "risultato = input('digita un numero?')" + ], + "id": "sCQu4LkLjwtn" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "import random\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.467949Z", - "start_time": "2023-05-19T12:20:30.295991Z" + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:26.415102Z", + "start_time": "2023-05-19T12:20:26.202688Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Pslrt8Nwjwto", + "outputId": "b4483087-23fc-48d3-84d8-f25ef139452c" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "6\n" + ] + } + ], + "source": [ + "print(risultato)\n" + ], + "id": "Pslrt8Nwjwto" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "\n", - "possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", - "computer_action = random.choice(possible_actions)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.469948Z", - "start_time": "2023-05-19T12:20:30.312305Z" + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:30.451911Z", + "start_time": "2023-05-19T12:20:26.220803Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "hy51y-owjwto", + "outputId": "5715043a-8497-45e5-9ffb-d49334861b12" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter a choice (rock, paper, scissors): rock\n" + ] + } + ], + "source": [ + "user_action = input(\"Enter a choice (rock, paper, scissors): \")" + ], + "id": "hy51y-owjwto" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "f9faebb5", - "metadata": {}, - "source": [ - "## Task 2\n", - "\n", - "In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "90af3eea", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.469948Z", - "start_time": "2023-05-19T12:20:30.326982Z" - } - }, - "outputs": [], - "source": [ - "if user_action == computer_action:\n", - " print(f\"Both players selected {user_action}. It's a tie!\")\n", - "elif user_action == \"rock\":\n", - " if computer_action == \"scissors\":\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - "elif user_action == \"paper\":\n", - " if computer_action == \"rock\":\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - "elif user_action == \"scissors\":\n", - " if computer_action == \"paper\":\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "f9182a9f", - "metadata": {}, - "source": [ - "### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n", - "\n", - "In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche: \n", - "- prendere in input dall'utente una scelta\n", - "- generare la mossa del computer\n", - "- confrontare le mosse\n", - "- mostrare un output\n", - "\n", - "A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "47580fd9", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.753623Z", - "start_time": "2023-05-19T12:20:30.346046Z" - } - }, - "outputs": [], - "source": [ - "while True:\n", - " user_action = input(\"Enter a choice (rock, paper, scissors): \")\n", - " possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", - " computer_action = random.choice(possible_actions)\n", - " print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n", - "\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action}. It's a tie!\")\n", - " elif user_action == \"rock\":\n", - " if computer_action == \"scissors\":\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - " elif user_action == \"paper\":\n", - " if computer_action == \"rock\":\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - " elif user_action == \"scissors\":\n", - " if computer_action == \"paper\":\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")\n", - "\n", - " play_again = input(\"Play again? (y/n): \")\n", - " if play_again.lower() != \"y\":\n", - " break" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "dd16cb05", - "metadata": {}, - "source": [ - "## Task 3: Ottimizzazioni nel codice\n", - "\n", - "Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**. \n", - "\n", - "Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile. " - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "2dfe73b6", - "metadata": {}, - "source": [ - "### Task 3a: Creiamo un enum\n", - "\n", - "In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0ec721b6", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.753623Z", - "start_time": "2023-05-19T12:20:44.647673Z" - } - }, - "outputs": [], - "source": [ - "from enum import IntEnum\n", - "\n", - "class Action(IntEnum):\n", - " Rock = 0\n", - " Paper = 1\n", - " Scissors = 2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.756156Z", - "start_time": "2023-05-19T12:20:44.665466Z" + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:30.466948Z", + "start_time": "2023-05-19T12:20:30.278604Z" + }, + "id": "sO8y1DHqjwto" + }, + "outputs": [], + "source": [ + "import random\n" + ], + "id": "sO8y1DHqjwto" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "print('Action.Rock == Action.Rock',Action.Rock == Action.Rock)\n", - "print('Action.Rock == Action(0)',Action.Rock == Action(0))\n", - "print('Action(0)',Action(0))" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "92eea47a", - "metadata": {}, - "source": [ - "### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n", - "\n", - "Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n", - "\n", - "- Fai giocare l'utente -> `get_user_selection()`\n", - "- Fai giocare il computer -> `get_computer_selection()`\n", - "- Decidi chi ha vinto -> `determine_winner(user_selection, computer_selection)`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08c5263b", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.756156Z", - "start_time": "2023-05-19T12:20:44.679996Z" - } - }, - "outputs": [], - "source": [ - "def get_user_selection():\n", - " user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n", - " selection = int(user_input)\n", - " action = Action(selection)\n", - " return action\n", - "\n", - "\n", - "def get_user_selection():\n", - " choices = [f\"{action.name}[{action.value}]\" for action in Action]\n", - " choices_str = \", \".join(choices)\n", - " selection = int(input(f\"Enter a choice ({choices_str}): \"))\n", - " action = Action(selection)\n", - " return action" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.793367Z", - "start_time": "2023-05-19T12:20:44.696045Z" + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:30.467949Z", + "start_time": "2023-05-19T12:20:30.295991Z" + }, + "id": "NxgXYbZ-jwtp" + }, + "outputs": [], + "source": [ + "\n", + "possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", + "computer_action = random.choice(possible_actions)\n" + ], + "id": "NxgXYbZ-jwtp" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "def get_computer_selection():\n", - " selection = random.randint(0, len(Action) - 1)\n", - " action = Action(selection)\n", - " return action" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.794876Z", - "start_time": "2023-05-19T12:20:44.715076Z" + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:30.469948Z", + "start_time": "2023-05-19T12:20:30.312305Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "EKBwgQm1jwtp", + "outputId": "29d0c513-554e-4ddf-d586-543dc412f021" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + "You chose rock, computer chose scissors.\n", + "\n" + ] + } + ], + "source": [ + "print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n" + ], + "id": "EKBwgQm1jwtp" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", - " elif user_action == Action.Rock:\n", - " if computer_action == Action.Scissors:\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - " elif user_action == Action.Paper:\n", - " if computer_action == Action.Rock:\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - " elif user_action == Action.Scissors:\n", - " if computer_action == Action.Paper:\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "4ca7428d", - "metadata": {}, - "source": [ - "Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita: \n", - "\n", - "- `start_game()`\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8ebfa484", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.794876Z", - "start_time": "2023-05-19T12:20:44.724834Z" - } - }, - "outputs": [], - "source": [ - "def start_game():\n", - " while True:\n", - " try:\n", - " user_action = get_user_selection()\n", - " except ValueError as e:\n", - " range_str = f\"[0, {len(Action) - 1}]\"\n", - " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", - " continue\n", - "\n", - " computer_action = get_computer_selection()\n", - " determine_winner(user_action, computer_action)\n", - "\n", - " play_again = input(\"Play again? (y/n): \")\n", - " if play_again.lower() != \"y\":\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.862916Z", - "start_time": "2023-05-19T12:20:44.741502Z" + { + "cell_type": "markdown", + "id": "f9faebb5", + "metadata": { + "id": "f9faebb5" + }, + "source": [ + "## Task 2\n", + "\n", + "In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "start_game()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "6955e8bc", - "metadata": {}, - "source": [ - "### Task 3c: Creiamo un dizionario con le mosse vincenti\n", - "\n", - "Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n", - "- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n", - "- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96893f8d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.864487Z", - "start_time": "2023-05-19T12:20:50.756391Z" - } - }, - "outputs": [], - "source": [ - "victories = {\n", - " Action.Rock: [Action.Scissors], # Rock beats scissors\n", - " Action.Paper: [Action.Rock], # Paper beats rock\n", - " Action.Scissors: [Action.Paper] # Scissors beats paper\n", - "}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "c3205d3c", - "metadata": {}, - "source": [ - "### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dce77a8a", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.864487Z", - "start_time": "2023-05-19T12:20:50.774458Z" - } - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n", - " defeats = victories[user_action]\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", - " elif computer_action in defeats:\n", - " print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n", - " else:\n", - " print(f\"{computer_action.name} beats {user_action.name}! You lose.\")" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.122073Z", - "start_time": "2023-05-19T12:20:50.794541Z" + { + "cell_type": "code", + "execution_count": 11, + "id": "90af3eea", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:30.469948Z", + "start_time": "2023-05-19T12:20:30.326982Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "90af3eea", + "outputId": "77ce39e0-e58a-436d-d35b-eac6a0f1e829" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Rock smashes scissors! You win!\n" + ] + } + ], + "source": [ + "if user_action == computer_action:\n", + " print(f\"Both players selected {user_action}. It's a tie!\")\n", + "elif user_action == \"rock\":\n", + " if computer_action == \"scissors\":\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + "elif user_action == \"paper\":\n", + " if computer_action == \"rock\":\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + "elif user_action == \"scissors\":\n", + " if computer_action == \"paper\":\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "start_game()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "ee1b1835", - "metadata": {}, - "source": [ - "### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n", - "\n", - "È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "60f6e2d5", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.122073Z", - "start_time": "2023-05-19T12:20:56.018470Z" - } - }, - "outputs": [], - "source": [ - "class Action(IntEnum):\n", - " Rock = 0\n", - " Paper = 1\n", - " Scissors = 2\n", - " Lizard = 3\n", - " Spock = 4\n", - "\n", - "victories = {\n", - " Action.Scissors: [Action.Lizard, Action.Paper],\n", - " Action.Paper: [Action.Spock, Action.Rock],\n", - " Action.Rock: [Action.Lizard, Action.Scissors],\n", - " Action.Lizard: [Action.Spock, Action.Paper],\n", - " Action.Spock: [Action.Scissors, Action.Rock]\n", - "}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "67881ce8", - "metadata": {}, - "source": [ - "### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art \n", - "\n", - "Creeremo due nuovi dizionari: \n", - "- in `ascii_action` metteremo le ascii art delle mosse\n", - "- in `ascii_results` metteremo le ascii art dei possibili risultati" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4422813d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.182207Z", - "start_time": "2023-05-19T12:20:56.037218Z" - } - }, - "outputs": [], - "source": [ - "ascii_action = {\n", - " Action.Scissors: r\"\"\"\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \"\"\",\n", - " Action.Paper: r\"\"\"\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \"\"\",\n", - " Action.Rock: r\"\"\"\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \"\"\",\n", - " Action.Lizard: r\"\"\"\n", - " _ _ _\n", - " | | (_) | |\n", - " | | _ __________ _ _ __ __| |\n", - " | | | |_ /_ / _` | '__/ _` |\n", - " | |___| |/ / / / (_| | | | (_| |\n", - " \\_____/_/___/___\\__,_|_| \\__,_|\n", - " \"\"\",\n", - " Action.Spock: r\"\"\"\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \"\"\"\n", - "}\n", - "\n", - "COMPUTER_WIN=-1\n", - "HUMAN_WIN=1\n", - "DROW=0\n", - "ascii_result = {\n", - " COMPUTER_WIN: r\"\"\"\n", - " _____ ________ _________ _ _ _____ ___________\n", - "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", - "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", - "| | | | | | |\\/| || __/| | | | | | | __|| /\n", - "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", - " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - " \"\"\",\n", - " HUMAN_WIN: r\"\"\"\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \"\"\",\n", - " DROW: r\"\"\"\n", - " _ _ _\n", - " | | (_) | |\n", - " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", - " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", - "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", - " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", - " __/ |\n", - " |___/\n", - " ___ _ _ __\n", - " / / | | | (_) \\ \\\\\n", - "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", - "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", - "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", - "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", - " \\_\\ __/ /_/\n", - " |___/ \"\"\"\n", - "}" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "75f2c6d5", - "metadata": {}, - "source": [ - "Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art: \n", - "- `display_action`\n", - "- `display_results`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c96921e2", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.182207Z", - "start_time": "2023-05-19T12:20:56.052294Z" - } - }, - "outputs": [], - "source": [ - "def display_action(action):\n", - " print(ascii_action[action])\n", - "\n", - "def display_result(result):\n", - " print(ascii_result[result])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.183207Z", - "start_time": "2023-05-19T12:20:56.064342Z" + { + "cell_type": "markdown", + "id": "f9182a9f", + "metadata": { + "id": "f9182a9f" + }, + "source": [ + "### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n", + "\n", + "In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche:\n", + "- prendere in input dall'utente una scelta\n", + "- generare la mossa del computer\n", + "- confrontare le mosse\n", + "- mostrare un output\n", + "\n", + "A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**." + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "display_action(Action.Spock)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "c1b643e3", - "metadata": {}, - "source": [ - "Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "252c6e45", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.184209Z", - "start_time": "2023-05-19T12:20:56.081582Z" - } - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " print(f\"You chose\")\n", - " display_action(user_action)\n", - " print(f\"The computer chose\")\n", - " display_action(computer_action)\n", - " defeats = victories[user_action]\n", - " if user_action == computer_action:\n", - " display_result(DROW)\n", - " return DROW\n", - " elif computer_action in defeats:\n", - " display_result(HUMAN_WIN)\n", - " return HUMAN_WIN\n", - " else:\n", - " display_result(COMPUTER_WIN)\n", - " return COMPUTER_WIN" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:01.057176Z", - "start_time": "2023-05-19T12:20:56.101255Z" + { + "cell_type": "code", + "execution_count": 12, + "id": "47580fd9", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.753623Z", + "start_time": "2023-05-19T12:20:30.346046Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "47580fd9", + "outputId": "0a9d7003-7bea-4590-8af6-675e3b1f0944" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter a choice (rock, paper, scissors): rock\n", + "\n", + "You chose rock, computer chose scissors.\n", + "\n", + "Rock smashes scissors! You win!\n", + "Play again? (y/n): n\n" + ] + } + ], + "source": [ + "while True:\n", + " user_action = input(\"Enter a choice (rock, paper, scissors): \")\n", + " possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", + " computer_action = random.choice(possible_actions)\n", + " print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n", + "\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action}. It's a tie!\")\n", + " elif user_action == \"rock\":\n", + " if computer_action == \"scissors\":\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + " elif user_action == \"paper\":\n", + " if computer_action == \"rock\":\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + " elif user_action == \"scissors\":\n", + " if computer_action == \"paper\":\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")\n", + "\n", + " play_again = input(\"Play again? (y/n): \")\n", + " if play_again.lower() != \"y\":\n", + " break" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "start_game()" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "5e478a36", - "metadata": {}, - "source": [ - "### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n", - "\n", - "Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla! " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ec5766f6", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:01.096343Z", - "start_time": "2023-05-19T12:21:01.055176Z" - } - }, - "outputs": [], - "source": [ - "def print_game_results(game_results):\n", - " num_tied = game_results.count(DROW)/len(game_results)*100\n", - " num_player_wins = game_results.count(HUMAN_WIN)/len(game_results)*100\n", - " num_computer_wins =game_results.count(COMPUTER_WIN)/len(game_results)*100\n", - "\n", - " print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n", - "\n", - "def start_game(num_games=1):\n", - " game_results=[]\n", - " counter=0\n", - " while True:\n", - " try:\n", - " user_action = get_user_selection()\n", - " except ValueError as e:\n", - " range_str = f\"[0, {len(Action) - 1}]\"\n", - " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", - " continue\n", - "\n", - " computer_action = get_computer_selection()\n", - " game_results.append(determine_winner(user_action, computer_action))\n", - " counter+=1\n", - "\n", - " if counter>=num_games:\n", - " break\n", - " print_game_results(game_results)\n", - " return game_results\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:09.040634Z", - "start_time": "2023-05-19T12:21:01.070699Z" + { + "cell_type": "markdown", + "id": "dd16cb05", + "metadata": { + "id": "dd16cb05" + }, + "source": [ + "## Task 3: Ottimizzazioni nel codice\n", + "\n", + "Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**.\n", + "\n", + "Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile." + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "game_results=start_game(5)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "aae3e00d", - "metadata": {}, - "source": [ - "### Utilizziamo un'interfaccia grafica!\n", - "\n", - "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", - "\n", - "Concetti connessi: \n", - "- list comprehension\n", - "- `widgets.Dropdown`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6b41097", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:09.162321Z", - "start_time": "2023-05-19T12:21:08.955141Z" - } - }, - "outputs": [], - "source": [ - "import ipywidgets as widgets\n", - "options=[(action.name,action.value) for action in Action]\n", - "menu = widgets.Dropdown(\n", - " options=options ,\n", - " description='Chose:')\n", - "output = widgets.Output(layout={'border': '1px solid black'})\n", - "\n", - "def on_button_clicked(b):\n", - " output.clear_output()\n", - " with output:\n", - " computer_action = get_computer_selection()\n", - " determine_winner(Action(menu.value), computer_action)\n", - "\n", - "button = widgets.Button(description=\"Play!\", button_style='success', icon='check')\n", - "button.on_click(on_button_clicked)\n", - "box = widgets.VBox([menu, button, output])\n", - "\n", - "display(box)" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "d95e966e", - "metadata": {}, - "source": [ - "## Time to use ML!\n", - "\n", - "Nelle celle successive andremo ad utilizzare il Machine Learning per addestrare un modello predittivo in grado di dedurre la mossa dell'utente a partire dall'inquadratura della mano ottenuta con la webcam.\n", - "\n", - "Installiamo le librerie necessarie e importiamole:" - ] - }, - { - "attachments": {}, - "cell_type": "markdown", - "id": "2065bc78", - "metadata": {}, - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "735944ea", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:26:06.922965Z", - "start_time": "2023-05-19T12:25:54.947034Z" - } - }, - "outputs": [], - "source": [ - "!pip install numpy\n", - "!pip install opencv-python\n", - "!pip install mediapipe\n", - "!pip install requests" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:26:10.333815Z", - "start_time": "2023-05-19T12:26:10.296111Z" + { + "cell_type": "markdown", + "id": "2dfe73b6", + "metadata": { + "id": "2dfe73b6" + }, + "source": [ + "### Task 3a: Creiamo un enum\n", + "\n", + "In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "import numpy as np\n", - "import mediapipe as mp\n", - "import cv2" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:26:11.205558Z", - "start_time": "2023-05-19T12:26:10.759149Z" + { + "cell_type": "code", + "execution_count": 13, + "id": "0ec721b6", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.753623Z", + "start_time": "2023-05-19T12:20:44.647673Z" + }, + "id": "0ec721b6" + }, + "outputs": [], + "source": [ + "from enum import IntEnum\n", + "\n", + "class Action(IntEnum):\n", + " Rock = 0\n", + " Paper = 1\n", + " Scissors = 2" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "import requests\n", - "url = \"https://raw.githubusercontent.com/ntu-rris/google-mediapipe/main/data/gesture_train.csv\"\n", - "\n", - "# If repo is private - we need to add a token in header:\n", - "\n", - "\n", - "resp = requests.get(url)\n", - "\n", - "with open('./gesture_train.csv', 'wb') as f:\n", - " f.write(resp.content)\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:07.433893Z", - "start_time": "2023-05-19T12:27:07.331888Z" + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.756156Z", + "start_time": "2023-05-19T12:20:44.665466Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "4BTg9ygOjwtq", + "outputId": "e0967596-b4a6-4c75-e447-3b9e7dc452b7" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Action.Rock == Action.Rock True\n", + "Action.Rock == Action(0) True\n", + "Action(0) Action.Rock\n" + ] + } + ], + "source": [ + "print('Action.Rock == Action.Rock',Action.Rock == Action.Rock)\n", + "print('Action.Rock == Action(0)',Action.Rock == Action(0))\n", + "print('Action(0)',Action(0))" + ], + "id": "4BTg9ygOjwtq" }, - "collapsed": false - }, - "outputs": [], - "source": [ - "# Define default camera intrinsic\n", - "img_width = 640\n", - "img_height = 480\n", - "intrin_default = {\n", - " 'fx': img_width*0.9, # Approx 0.7w < f < w https://www.learnopencv.com/approximate-focal-length-for-webcams-and-cell-phone-cameras/\n", - " 'fy': img_width*0.9,\n", - " 'cx': img_width*0.5, # Approx center of image\n", - " 'cy': img_height*0.5,\n", - " 'width': img_width,\n", - "}\n", - "class GestureRecognition:\n", - " def __init__(self):\n", - "\n", - " # 11 types of gesture 'name':class label\n", - " self.gesture = {\n", - " 'fist':0,'one':1,'two':2,'three':3,'four':4,'five':5,'six':6,\n", - " 'rock':7,'spiderman':8,'yeah':9,'ok':10,\n", - " }\n", - "\n", - " # Load training data\n", - " file = np.genfromtxt('./gesture_train.csv', delimiter=',')\n", - " # Extract input joint angles\n", - " angle = file[:,:-1].astype(np.float32)\n", - " # Extract output class label\n", - " label = file[:, -1].astype(np.float32)\n", - " # Use OpenCV KNN\n", - " self.knn = cv2.ml.KNearest_create()\n", - " self.knn.train(angle, cv2.ml.ROW_SAMPLE, label)\n", - "\n", - "\n", - "\n", - " def eval(self, angle):\n", - " # Use KNN for gesture recognition\n", - " data = np.asarray([angle], dtype=np.float32)\n", - " ret, results, neighbours ,dist = self.knn.findNearest(data, 3)\n", - " idx = int(results[0][0]) # Index of class label\n", - "\n", - " return list(self.gesture)[idx] # Return name of class label\n", - "\n", - "\n", - "class MediaPipeHand:\n", - " def __init__(self, static_image_mode=True, max_num_hands=1,\n", - " model_complexity=1, intrin=None):\n", - " self.max_num_hands = max_num_hands\n", - " if intrin is None:\n", - " self.intrin = intrin_default\n", - " else:\n", - " self.intrin = intrin\n", - "\n", - " # Access MediaPipe Solutions Python API\n", - " mp_hands = mp.solutions.hands\n", - " # help(mp_hands.Hands)\n", - "\n", - " # Initialize MediaPipe Hands\n", - " # static_image_mode:\n", - " # For video processing set to False:\n", - " # Will use previous frame to localize hand to reduce latency\n", - " # For unrelated images set to True:\n", - " # To allow hand detection to run on every input images\n", - "\n", - " # max_num_hands:\n", - " # Maximum number of hands to detect\n", - "\n", - " # model_complexity:\n", - " # Complexity of the hand landmark model: 0 or 1.\n", - " # Landmark accuracy as well as inference latency generally\n", - " # go up with the model complexity. Default to 1.\n", - "\n", - " # min_detection_confidence:\n", - " # Confidence value [0,1] from hand detection model\n", - " # for detection to be considered successful\n", - "\n", - " # min_tracking_confidence:\n", - " # Minimum confidence value [0,1] from landmark-tracking model\n", - " # for hand landmarks to be considered tracked successfully,\n", - " # or otherwise hand detection will be invoked automatically on the next input image.\n", - " # Setting it to a higher value can increase robustness of the solution,\n", - " # at the expense of a higher latency.\n", - " # Ignored if static_image_mode is true, where hand detection simply runs on every image.\n", - "\n", - " self.pipe = mp_hands.Hands(\n", - " static_image_mode=static_image_mode,\n", - " max_num_hands=max_num_hands,\n", - " model_complexity=model_complexity,\n", - " min_detection_confidence=0.5,\n", - " min_tracking_confidence=0.5)\n", - "\n", - " # Define hand parameter\n", - " self.param = []\n", - " for i in range(max_num_hands):\n", - " p = {\n", - " 'keypt' : np.zeros((21,2)), # 2D keypt in image coordinate (pixel)\n", - " 'joint' : np.zeros((21,3)), # 3D joint in camera coordinate (m)\n", - " 'class' : None, # Left / right / none hand\n", - " 'score' : 0, # Probability of predicted handedness (always>0.5, and opposite handedness=1-score)\n", - " 'angle' : np.zeros(15), # Flexion joint angles in degree\n", - " 'gesture' : None, # Type of hand gesture\n", - " 'rvec' : np.zeros(3), # Global rotation vector Note: this term is only used for solvepnp initialization\n", - " 'tvec' : np.asarray([0,0,0.6]), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve\n", - " 'fps' : -1, # Frame per sec\n", - " # https://github.com/google/mediapipe/issues/1351\n", - " # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image\n", - " # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image\n", - " }\n", - " self.param.append(p)\n", - "\n", - "\n", - " def result_to_param(self, result, img):\n", - " # Convert mediapipe result to my own param\n", - " img_height, img_width, _ = img.shape\n", - "\n", - " # Reset param\n", - " for p in self.param:\n", - " p['class'] = None\n", - "\n", - " if result.multi_hand_landmarks is not None:\n", - " # Loop through different hands\n", - " for i, res in enumerate(result.multi_handedness):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " self.param[i]['class'] = res.classification[0].label\n", - " self.param[i]['score'] = res.classification[0].score\n", - "\n", - " # Loop through different hands\n", - " for i, res in enumerate(result.multi_hand_landmarks):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " # Loop through 21 landmark for each hand\n", - " for j, lm in enumerate(res.landmark):\n", - " self.param[i]['keypt'][j,0] = lm.x * img_width # Convert normalized coor to pixel [0,1] -> [0,width]\n", - " self.param[i]['keypt'][j,1] = lm.y * img_height # Convert normalized coor to pixel [0,1] -> [0,height]\n", - "\n", - " # Ignore it https://github.com/google/mediapipe/issues/1320\n", - " # self.param[i]['visible'][j] = lm.visibility\n", - " # self.param[i]['presence'][j] = lm.presence\n", - "\n", - " if result.multi_hand_world_landmarks is not None:\n", - " for i, res in enumerate(result.multi_hand_world_landmarks):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " # Loop through 21 landmark for each hand\n", - " for j, lm in enumerate(res.landmark):\n", - " self.param[i]['joint'][j,0] = lm.x\n", - " self.param[i]['joint'][j,1] = lm.y\n", - " self.param[i]['joint'][j,2] = lm.z\n", - "\n", - " # Convert relative 3D joint to angle\n", - " self.param[i]['angle'] = self.convert_joint_to_angle(self.param[i]['joint'])\n", - " # Convert relative 3D joint to camera coordinate\n", - " self.convert_joint_to_camera_coor(self.param[i], self.intrin)\n", - "\n", - " return self.param\n", - "\n", - "\n", - " def convert_joint_to_angle(self, joint):\n", - " # Get direction vector of bone from parent to child\n", - " v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint\n", - " v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint\n", - " v = v2 - v1 # [20,3]\n", - " # Normalize v\n", - " v = v/np.linalg.norm(v, axis=1)[:, np.newaxis]\n", - "\n", - " # Get angle using arcos of dot product\n", - " angle = np.arccos(np.einsum('nt,nt->n',\n", - " v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:],\n", - " v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,]\n", - "\n", - " return np.degrees(angle) # Convert radian to degree\n", - "\n", - "\n", - " def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True):\n", - " # MediaPipe version 0.8.9.1 onwards:\n", - " # Given real-world 3D joint centered at middle MCP joint -> J_origin\n", - " # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec,\n", - " # We need to find the unknown translation vector -> tvec = [tx,ty,tz]\n", - " # Such that when J_camera is projected to the 2D image plane\n", - " # It matches the 2D keypoint locations\n", - "\n", - " # Considering all 21 keypoints,\n", - " # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns\n", - " # Since the equations are linear wrt [tx,ty,tz]\n", - " # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz]\n", - "\n", - " # Consider a single keypoint (pixel x) and joint (X,Y,Z)\n", - " # Using the perspective projection eq:\n", - " # (x - cx)/fx = (X + tx) / (Z + tz)\n", - " # Similarly for pixel y:\n", - " # (y - cy)/fy = (Y + ty) / (Z + tz)\n", - " # Rearranging the above linear equations by keeping constants to the right hand side:\n", - " # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z\n", - " # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z\n", - " # Therefore, we can factor out the unknowns and form a matrix eq:\n", - " # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z]\n", - " # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z]\n", - " # [tz]\n", - "\n", - " idx = [i for i in range(21)] # Use all landmarks\n", - "\n", - " if use_solvepnp:\n", - " # Method 1: OpenCV solvePnP\n", - " fx, fy = intrin['fx'], intrin['fy']\n", - " cx, cy = intrin['cx'], intrin['cy']\n", - " intrin_mat = np.asarray([[fx,0,cx],[0,fy,cy],[0,0,1]])\n", - " dist_coeff = np.zeros(4)\n", - "\n", - " ret, param['rvec'], param['tvec'] = cv2.solvePnP(\n", - " param['joint'][idx], param['keypt'][idx],\n", - " intrin_mat, dist_coeff, param['rvec'], param['tvec'],\n", - " useExtrinsicGuess=True)\n", - " # Add tvec to all joints\n", - " param['joint'] += param['tvec']\n", - "\n", - " else:\n", - " # Method 2:\n", - " A = np.zeros((len(idx),2,3))\n", - " b = np.zeros((len(idx),2))\n", - "\n", - " A[:,0,0] = intrin['fx']\n", - " A[:,1,1] = intrin['fy']\n", - " A[:,0,2] = -(param['keypt'][idx,0] - intrin['cx'])\n", - " A[:,1,2] = -(param['keypt'][idx,1] - intrin['cy'])\n", - "\n", - " b[:,0] = -intrin['fx'] * param['joint'][idx,0] \\\n", - " + (param['keypt'][idx,0] - intrin['cx']) * param['joint'][idx,2]\n", - " b[:,1] = -intrin['fy'] * param['joint'][idx,1] \\\n", - " + (param['keypt'][idx,1] - intrin['cy']) * param['joint'][idx,2]\n", - "\n", - " A = A.reshape(-1,3) # [8,3]\n", - " b = b.flatten() # [8]\n", - "\n", - " # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides\n", - " x = np.linalg.solve(A.T @ A, A.T @ b)\n", - " # Add tvec to all joints\n", - " param['joint'] += x\n", - "\n", - "\n", - "\n", - " def forward(self, img):\n", - "\n", - " # Extract result\n", - " result = self.pipe.process(img)\n", - "\n", - " # Convert result to my own param\n", - " param = self.result_to_param(result, img)\n", - "\n", - " return param\n", - "\n", - "\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:09.195732Z", - "start_time": "2023-05-19T12:27:09.078715Z" + { + "cell_type": "markdown", + "id": "92eea47a", + "metadata": { + "id": "92eea47a" + }, + "source": [ + "### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n", + "\n", + "Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n", + "\n", + "- Fai giocare l'utente -> `get_user_selection()`\n", + "- Fai giocare il computer -> `get_computer_selection()`\n", + "- Decidi chi ha vinto -> `determine_winner(user_selection, computer_selection)`" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "import io\n", - "\n", - "try:\n", - " from google.colab.output import eval_js\n", - " colab = True\n", - "except:\n", - " colab = False\n", - "\n", - "# colab=False\n", - "\n", - "if colab:\n", - " from IPython.display import display, Javascript\n", - " from google.colab.output import eval_js\n", - " from base64 import b64decode\n", - " from PIL import Image as PIL_Image\n", - "\n", - "\n", - " def take_photo(quality=0.8):\n", - " js = Javascript('''\n", - " async function takePhoto(quality) {\n", - " const div = document.createElement('div');\n", - " const capture = document.createElement('button');\n", - " capture.textContent = 'Capture';\n", - " div.appendChild(capture);\n", - "\n", - " const video = document.createElement('video');\n", - " video.style.display = 'block';\n", - " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", - "\n", - " document.body.appendChild(div);\n", - " div.appendChild(video);\n", - " video.srcObject = stream;\n", - " await video.play();\n", - "\n", - " // Resize the output to fit the video element.\n", - " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", - "\n", - " // Wait for Capture to be clicked.\n", - " await new Promise((resolve) => capture.onclick = resolve);\n", - "\n", - " const canvas = document.createElement('canvas');\n", - " canvas.width = video.videoWidth;\n", - " canvas.height = video.videoHeight;\n", - " canvas.getContext('2d').drawImage(video, 0, 0);\n", - " stream.getVideoTracks()[0].stop();\n", - " div.remove();\n", - " return canvas.toDataURL('image/jpeg', quality);\n", - " }\n", - " ''')\n", - " display(js)\n", - " data = eval_js('takePhoto({})'.format(quality))\n", - " binary = b64decode(data.split(',')[1])\n", - "\n", - "\n", - " image = PIL_Image.open(io.BytesIO(binary))\n", - " image_np = np.array(image)\n", - "\n", - " # with open(filename, 'wb') as f:\n", - " # f.write(binary)\n", - " return image_np\n", - "else:\n", - " import cv2\n", - " def take_photo(filename='photo.jpg', quality=0.8):\n", - " cam = cv2.VideoCapture(0)\n", - "\n", - " cv2.namedWindow(\"test\")\n", - "\n", - " img_counter = 0\n", - "\n", - " while True:\n", - " ret, frame = cam.read()\n", - " # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)\n", - " if not ret:\n", - " print(\"failed to grab frame\")\n", - " break\n", - " cv2.imshow(\"test\", frame)\n", - "\n", - " k = cv2.waitKey(1)\n", - " if k%256 == 27 or k%256 == 32 :\n", - " # ESC pressed\n", - " break\n", - "\n", - " cam.release()\n", - "\n", - " cv2.destroyAllWindows()\n", - "\n", - " # Preprocess image\n", - " img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n", - " # Flip image for 3rd person view\n", - " img = cv2.flip(img, 1)\n", - "\n", - " # To improve performance, optionally mark image as not writeable to pass by reference\n", - " img.flags.writeable = False\n", - "\n", - " return img" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:10.726845Z", - "start_time": "2023-05-19T12:27:10.611796Z" + { + "cell_type": "code", + "execution_count": 15, + "id": "08c5263b", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.756156Z", + "start_time": "2023-05-19T12:20:44.679996Z" + }, + "id": "08c5263b" + }, + "outputs": [], + "source": [ + "def get_user_selection():\n", + " user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n", + " selection = int(user_input)\n", + " action = Action(selection)\n", + " return action\n", + "\n", + "\n", + "def get_user_selection():\n", + " choices = [f\"{action.name}[{action.value}]\" for action in Action]\n", + " choices_str = \", \".join(choices)\n", + " selection = int(input(f\"Enter a choice ({choices_str}): \"))\n", + " action = Action(selection)\n", + " return action" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "def start_game(num_games=1):\n", - " game_results=[]\n", - " counter=0\n", - " # Load mediapipe hand class\n", - " pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n", - " # Load gesture recognition class\n", - " gest = GestureRecognition()\n", - " while True:\n", - " try:\n", - " img = take_photo()\n", - "\n", - " # # Show the image which was just taken.\n", - " # plt.imshow(img)\n", - " # Feedforward to extract keypoint\n", - " param = pipe.forward(img)\n", - " # Evaluate gesture for all hands\n", - "\n", - " for p in param:\n", - " if p['class'] is not None:\n", - " p['gesture'] = gest.eval(p['angle'])\n", - " # print(p['class'])\n", - " # print(p['gesture'])\n", - "\n", - " if p['gesture']=='fist':\n", - " action = Action.Rock\n", - " elif p['gesture']=='five':\n", - " action = Action.Paper\n", - " elif (p['gesture']=='three') or (p['gesture']=='yeah'):\n", - " action = Action.Scissors\n", - " elif (p['gesture']=='rock') :\n", - " action = Action.Lizard\n", - " elif (p['gesture']=='four'):\n", - " action = Action.Spock\n", - " if action is not None:\n", - " computer_action = get_computer_selection()\n", - " game_results.append(determine_winner(action, computer_action))\n", - " counter+=1\n", - " print_game_results(game_results)\n", - " old_action=action\n", - "\n", - " if counter>=num_games:\n", - " break\n", - " except Exception as err:\n", - " # Errors will be thrown if the user does not have a webcam or if they do not\n", - " # grant the page permission to access it.\n", - " print(str(err))\n", - " raise err\n", - "\n", - " pipe.pipe.close()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:39.871557Z", - "start_time": "2023-05-19T12:27:12.133115Z" + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.793367Z", + "start_time": "2023-05-19T12:20:44.696045Z" + }, + "id": "hldiDTxqjwtr" + }, + "outputs": [], + "source": [ + "def get_computer_selection():\n", + " selection = random.randint(0, len(Action) - 1)\n", + " action = Action(selection)\n", + " return action" + ], + "id": "hldiDTxqjwtr" + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.794876Z", + "start_time": "2023-05-19T12:20:44.715076Z" + }, + "id": "eMYFUSiojwtr" + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", + " elif user_action == Action.Rock:\n", + " if computer_action == Action.Scissors:\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + " elif user_action == Action.Paper:\n", + " if computer_action == Action.Rock:\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + " elif user_action == Action.Scissors:\n", + " if computer_action == Action.Paper:\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")" + ], + "id": "eMYFUSiojwtr" + }, + { + "cell_type": "markdown", + "id": "4ca7428d", + "metadata": { + "id": "4ca7428d" + }, + "source": [ + "Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita:\n", + "\n", + "- `start_game()`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "8ebfa484", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:44.794876Z", + "start_time": "2023-05-19T12:20:44.724834Z" + }, + "id": "8ebfa484" + }, + "outputs": [], + "source": [ + "def start_game():\n", + " while True:\n", + " try:\n", + " user_action = get_user_selection()\n", + " except ValueError as e:\n", + " range_str = f\"[0, {len(Action) - 1}]\"\n", + " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", + " continue\n", + "\n", + " computer_action = get_computer_selection()\n", + " determine_winner(user_action, computer_action)\n", + "\n", + " play_again = input(\"Play again? (y/n): \")\n", + " if play_again.lower() != \"y\":\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:50.862916Z", + "start_time": "2023-05-19T12:20:44.741502Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "I3BM0Z4Kjwtr", + "outputId": "9dc86a75-5e41-4d2a-ad46-828f04eb01d8" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n", + "Paper covers rock! You lose.\n", + "Play again? (y/n): n\n" + ] + } + ], + "source": [ + "start_game()" + ], + "id": "I3BM0Z4Kjwtr" + }, + { + "cell_type": "markdown", + "id": "6955e8bc", + "metadata": { + "id": "6955e8bc" + }, + "source": [ + "### Task 3c: Creiamo un dizionario con le mosse vincenti\n", + "\n", + "Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n", + "- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n", + "- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "96893f8d", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:50.864487Z", + "start_time": "2023-05-19T12:20:50.756391Z" + }, + "id": "96893f8d" + }, + "outputs": [], + "source": [ + "victories = {\n", + " Action.Rock: [Action.Scissors], # Rock beats scissors\n", + " Action.Paper: [Action.Rock], # Paper beats rock\n", + " Action.Scissors: [Action.Paper] # Scissors beats paper\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "c3205d3c", + "metadata": { + "id": "c3205d3c" + }, + "source": [ + "### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "dce77a8a", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:50.864487Z", + "start_time": "2023-05-19T12:20:50.774458Z" + }, + "id": "dce77a8a" + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n", + " defeats = victories[user_action]\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", + " elif computer_action in defeats:\n", + " print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n", + " else:\n", + " print(f\"{computer_action.name} beats {user_action.name}! You lose.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.122073Z", + "start_time": "2023-05-19T12:20:50.794541Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "cv6L7ahtjwtr", + "outputId": "bf4268a8-17f1-49d1-8c54-4b9d69356cf9" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n", + "You chose Rock. The computer chose Scissors.\n", + "Rock beats Scissors! You win!\n", + "Play again? (y/n): n\n" + ] + } + ], + "source": [ + "start_game()" + ], + "id": "cv6L7ahtjwtr" + }, + { + "cell_type": "markdown", + "id": "ee1b1835", + "metadata": { + "id": "ee1b1835" + }, + "source": [ + "### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n", + "\n", + "È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "60f6e2d5", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.122073Z", + "start_time": "2023-05-19T12:20:56.018470Z" + }, + "id": "60f6e2d5" + }, + "outputs": [], + "source": [ + "class Action(IntEnum):\n", + " Rock = 0\n", + " Paper = 1\n", + " Scissors = 2\n", + " Lizard = 3\n", + " Spock = 4\n", + "\n", + "victories = {\n", + " Action.Scissors: [Action.Lizard, Action.Paper],\n", + " Action.Paper: [Action.Spock, Action.Rock],\n", + " Action.Rock: [Action.Lizard, Action.Scissors],\n", + " Action.Lizard: [Action.Spock, Action.Paper],\n", + " Action.Spock: [Action.Scissors, Action.Rock]\n", + "}" + ] }, - "collapsed": false - }, - "outputs": [], - "source": [ - "start_game(num_games=5)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" + { + "cell_type": "markdown", + "id": "67881ce8", + "metadata": { + "id": "67881ce8" + }, + "source": [ + "### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art\n", + "\n", + "Creeremo due nuovi dizionari:\n", + "- in `ascii_action` metteremo le ascii art delle mosse\n", + "- in `ascii_results` metteremo le ascii art dei possibili risultati" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "4422813d", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.182207Z", + "start_time": "2023-05-19T12:20:56.037218Z" + }, + "id": "4422813d" + }, + "outputs": [], + "source": [ + "ascii_action = {\n", + " Action.Scissors: r\"\"\"\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \"\"\",\n", + " Action.Paper: r\"\"\"\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \"\"\",\n", + " Action.Rock: r\"\"\"\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \"\"\",\n", + " Action.Lizard: r\"\"\"\n", + " _ _ _\n", + " | | (_) | |\n", + " | | _ __________ _ _ __ __| |\n", + " | | | |_ /_ / _` | '__/ _` |\n", + " | |___| |/ / / / (_| | | | (_| |\n", + " \\_____/_/___/___\\__,_|_| \\__,_|\n", + " \"\"\",\n", + " Action.Spock: r\"\"\"\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \"\"\"\n", + "}\n", + "\n", + "COMPUTER_WIN=-1\n", + "HUMAN_WIN=1\n", + "DROW=0\n", + "ascii_result = {\n", + " COMPUTER_WIN: r\"\"\"\n", + " _____ ________ _________ _ _ _____ ___________\n", + "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", + "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", + "| | | | | | |\\/| || __/| | | | | | | __|| /\n", + "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", + " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + " \"\"\",\n", + " HUMAN_WIN: r\"\"\"\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \"\"\",\n", + " DROW: r\"\"\"\n", + " _ _ _\n", + " | | (_) | |\n", + " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", + " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", + "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", + " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", + " __/ |\n", + " |___/\n", + " ___ _ _ __\n", + " / / | | | (_) \\ \\\\\n", + "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", + "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", + "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", + "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", + " \\_\\ __/ /_/\n", + " |___/ \"\"\"\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "75f2c6d5", + "metadata": { + "id": "75f2c6d5" + }, + "source": [ + "Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art:\n", + "- `display_action`\n", + "- `display_results`" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "c96921e2", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.182207Z", + "start_time": "2023-05-19T12:20:56.052294Z" + }, + "id": "c96921e2" + }, + "outputs": [], + "source": [ + "def display_action(action):\n", + " print(ascii_action[action])\n", + "\n", + "def display_result(result):\n", + " print(ascii_result[result])" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.183207Z", + "start_time": "2023-05-19T12:20:56.064342Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "18tMjb3sjwts", + "outputId": "138c7568-2c5e-4297-a358-7f389b5f3dda" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \n" + ] + } + ], + "source": [ + "display_action(Action.Spock)" + ], + "id": "18tMjb3sjwts" + }, + { + "cell_type": "markdown", + "id": "c1b643e3", + "metadata": { + "id": "c1b643e3" + }, + "source": [ + "Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "id": "252c6e45", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:20:56.184209Z", + "start_time": "2023-05-19T12:20:56.081582Z" + }, + "id": "252c6e45" + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " print(f\"You chose\")\n", + " display_action(user_action)\n", + " print(f\"The computer chose\")\n", + " display_action(computer_action)\n", + " defeats = victories[user_action]\n", + " if user_action == computer_action:\n", + " display_result(DROW)\n", + " return DROW\n", + " elif computer_action in defeats:\n", + " display_result(HUMAN_WIN)\n", + " return HUMAN_WIN\n", + " else:\n", + " display_result(COMPUTER_WIN)\n", + " return COMPUTER_WIN" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:21:01.057176Z", + "start_time": "2023-05-19T12:20:56.101255Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "q_y93jZFjwtv", + "outputId": "60a49797-24a8-4ff2-ba4b-a10f6f6ff1ca" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 4\n", + "You chose\n", + "\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n", + "Play again? (y/n): n\n" + ] + } + ], + "source": [ + "start_game()" + ], + "id": "q_y93jZFjwtv" + }, + { + "cell_type": "markdown", + "id": "5e478a36", + "metadata": { + "id": "5e478a36" + }, + "source": [ + "### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n", + "\n", + "Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla!" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "id": "ec5766f6", + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:21:01.096343Z", + "start_time": "2023-05-19T12:21:01.055176Z" + }, + "id": "ec5766f6" + }, + "outputs": [], + "source": [ + "def print_game_results(game_results):\n", + " num_tied = game_results.count(DROW)/len(game_results)*100\n", + " num_player_wins = game_results.count(HUMAN_WIN)/len(game_results)*100\n", + " num_computer_wins =game_results.count(COMPUTER_WIN)/len(game_results)*100\n", + "\n", + " print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n", + "\n", + "def start_game(num_games=1):\n", + " game_results=[]\n", + " counter=0\n", + " while True:\n", + " try:\n", + " user_action = get_user_selection()\n", + " except ValueError as e:\n", + " range_str = f\"[0, {len(Action) - 1}]\"\n", + " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", + " continue\n", + "\n", + " computer_action = get_computer_selection()\n", + " game_results.append(determine_winner(user_action, computer_action))\n", + " counter+=1\n", + "\n", + " if counter>=num_games:\n", + " break\n", + " print_game_results(game_results)\n", + " return game_results\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:21:09.040634Z", + "start_time": "2023-05-19T12:21:01.070699Z" + }, + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "lcLQZxy3jwtw", + "outputId": "26e10e4e-f36b-443f-d972-099151877e4b" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 4\n", + "You chose\n", + "\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n", + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", + "You chose\n", + "\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n", + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", + "You chose\n", + "\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n", + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", + "You chose\n", + "\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \n", + "\n", + " _____ ________ _________ _ _ _____ ___________\n", + "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", + "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", + "| | | | | | |\\/| || __/| | | | | | | __|| /\n", + "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", + " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + " \n", + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", + "You chose\n", + "\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \n", + "The computer chose\n", + "\n", + " _ _ _\n", + " | | (_) | |\n", + " | | _ __________ _ _ __ __| |\n", + " | | | |_ /_ / _` | '__/ _` |\n", + " | |___| |/ / / / (_| | | | (_| |\n", + " \\_____/_/___/___\\__,_|_| \\__,_|\n", + " \n", + "\n", + " _____ ________ _________ _ _ _____ ___________\n", + "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", + "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", + "| | | | | | |\\/| || __/| | | | | | | __|| /\n", + "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", + " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + " \n", + "There were 0.0 % tied games \n", + "the player won 60.0 % of games\n", + "the computer won 40.0 % of games\n", + "in a total of 5 games\n" + ] + } + ], + "source": [ + "game_results=start_game(5)" + ], + "id": "lcLQZxy3jwtw" + }, + { + "cell_type": "markdown", + "id": "aae3e00d", + "metadata": { + "id": "aae3e00d" + }, + "source": [ + "### Utilizziamo un'interfaccia grafica!\n", + "\n", + "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", + "\n", + "Concetti connessi:\n", + "- list comprehension\n", + "- `widgets.Dropdown`" + ] + }, + { + "cell_type": "code", + "source": [ + "!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "uddtBN5Hj0mh", + "outputId": "d96882c6-0a5b-4e7d-d5e8-c14e39f3bd6c" + }, + "id": "uddtBN5Hj0mh", + "execution_count": 31, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Downloading...\n", + "From: https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\n", + "To: /content/support.py\n", + "\r 0% 0.00/370 [00:000.5, and opposite handedness=1-score)\n", + " 'angle' : np.zeros(15), # Flexion joint angles in degree\n", + " 'gesture' : None, # Type of hand gesture\n", + " 'rvec' : np.zeros(3), # Global rotation vector Note: this term is only used for solvepnp initialization\n", + " 'tvec' : np.asarray([0,0,0.6]), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve\n", + " 'fps' : -1, # Frame per sec\n", + " # https://github.com/google/mediapipe/issues/1351\n", + " # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image\n", + " # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image\n", + " }\n", + " self.param.append(p)\n", + "\n", + "\n", + " def result_to_param(self, result, img):\n", + " # Convert mediapipe result to my own param\n", + " img_height, img_width, _ = img.shape\n", + "\n", + " # Reset param\n", + " for p in self.param:\n", + " p['class'] = None\n", + "\n", + " if result.multi_hand_landmarks is not None:\n", + " # Loop through different hands\n", + " for i, res in enumerate(result.multi_handedness):\n", + " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", + " self.param[i]['class'] = res.classification[0].label\n", + " self.param[i]['score'] = res.classification[0].score\n", + "\n", + " # Loop through different hands\n", + " for i, res in enumerate(result.multi_hand_landmarks):\n", + " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", + " # Loop through 21 landmark for each hand\n", + " for j, lm in enumerate(res.landmark):\n", + " self.param[i]['keypt'][j,0] = lm.x * img_width # Convert normalized coor to pixel [0,1] -> [0,width]\n", + " self.param[i]['keypt'][j,1] = lm.y * img_height # Convert normalized coor to pixel [0,1] -> [0,height]\n", + "\n", + " # Ignore it https://github.com/google/mediapipe/issues/1320\n", + " # self.param[i]['visible'][j] = lm.visibility\n", + " # self.param[i]['presence'][j] = lm.presence\n", + "\n", + " if result.multi_hand_world_landmarks is not None:\n", + " for i, res in enumerate(result.multi_hand_world_landmarks):\n", + " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", + " # Loop through 21 landmark for each hand\n", + " for j, lm in enumerate(res.landmark):\n", + " self.param[i]['joint'][j,0] = lm.x\n", + " self.param[i]['joint'][j,1] = lm.y\n", + " self.param[i]['joint'][j,2] = lm.z\n", + "\n", + " # Convert relative 3D joint to angle\n", + " self.param[i]['angle'] = self.convert_joint_to_angle(self.param[i]['joint'])\n", + " # Convert relative 3D joint to camera coordinate\n", + " self.convert_joint_to_camera_coor(self.param[i], self.intrin)\n", + "\n", + " return self.param\n", + "\n", + "\n", + " def convert_joint_to_angle(self, joint):\n", + " # Get direction vector of bone from parent to child\n", + " v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint\n", + " v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint\n", + " v = v2 - v1 # [20,3]\n", + " # Normalize v\n", + " v = v/np.linalg.norm(v, axis=1)[:, np.newaxis]\n", + "\n", + " # Get angle using arcos of dot product\n", + " angle = np.arccos(np.einsum('nt,nt->n',\n", + " v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:],\n", + " v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,]\n", + "\n", + " return np.degrees(angle) # Convert radian to degree\n", + "\n", + "\n", + " def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True):\n", + " # MediaPipe version 0.8.9.1 onwards:\n", + " # Given real-world 3D joint centered at middle MCP joint -> J_origin\n", + " # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec,\n", + " # We need to find the unknown translation vector -> tvec = [tx,ty,tz]\n", + " # Such that when J_camera is projected to the 2D image plane\n", + " # It matches the 2D keypoint locations\n", + "\n", + " # Considering all 21 keypoints,\n", + " # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns\n", + " # Since the equations are linear wrt [tx,ty,tz]\n", + " # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz]\n", + "\n", + " # Consider a single keypoint (pixel x) and joint (X,Y,Z)\n", + " # Using the perspective projection eq:\n", + " # (x - cx)/fx = (X + tx) / (Z + tz)\n", + " # Similarly for pixel y:\n", + " # (y - cy)/fy = (Y + ty) / (Z + tz)\n", + " # Rearranging the above linear equations by keeping constants to the right hand side:\n", + " # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z\n", + " # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z\n", + " # Therefore, we can factor out the unknowns and form a matrix eq:\n", + " # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z]\n", + " # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z]\n", + " # [tz]\n", + "\n", + " idx = [i for i in range(21)] # Use all landmarks\n", + "\n", + " if use_solvepnp:\n", + " # Method 1: OpenCV solvePnP\n", + " fx, fy = intrin['fx'], intrin['fy']\n", + " cx, cy = intrin['cx'], intrin['cy']\n", + " intrin_mat = np.asarray([[fx,0,cx],[0,fy,cy],[0,0,1]])\n", + " dist_coeff = np.zeros(4)\n", + "\n", + " ret, param['rvec'], param['tvec'] = cv2.solvePnP(\n", + " param['joint'][idx], param['keypt'][idx],\n", + " intrin_mat, dist_coeff, param['rvec'], param['tvec'],\n", + " useExtrinsicGuess=True)\n", + " # Add tvec to all joints\n", + " param['joint'] += param['tvec']\n", + "\n", + " else:\n", + " # Method 2:\n", + " A = np.zeros((len(idx),2,3))\n", + " b = np.zeros((len(idx),2))\n", + "\n", + " A[:,0,0] = intrin['fx']\n", + " A[:,1,1] = intrin['fy']\n", + " A[:,0,2] = -(param['keypt'][idx,0] - intrin['cx'])\n", + " A[:,1,2] = -(param['keypt'][idx,1] - intrin['cy'])\n", + "\n", + " b[:,0] = -intrin['fx'] * param['joint'][idx,0] \\\n", + " + (param['keypt'][idx,0] - intrin['cx']) * param['joint'][idx,2]\n", + " b[:,1] = -intrin['fy'] * param['joint'][idx,1] \\\n", + " + (param['keypt'][idx,1] - intrin['cy']) * param['joint'][idx,2]\n", + "\n", + " A = A.reshape(-1,3) # [8,3]\n", + " b = b.flatten() # [8]\n", + "\n", + " # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides\n", + " x = np.linalg.solve(A.T @ A, A.T @ b)\n", + " # Add tvec to all joints\n", + " param['joint'] += x\n", + "\n", + "\n", + "\n", + " def forward(self, img):\n", + "\n", + " # Extract result\n", + " result = self.pipe.process(img)\n", + "\n", + " # Convert result to my own param\n", + " param = self.result_to_param(result, img)\n", + "\n", + " return param\n", + "\n", + "\n", + "\n" + ], + "id": "pTVnoYlxjwtw" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:27:09.195732Z", + "start_time": "2023-05-19T12:27:09.078715Z" + }, + "id": "5UfPPceOjwtx" + }, + "outputs": [], + "source": [ + "import io\n", + "\n", + "try:\n", + " from google.colab.output import eval_js\n", + " colab = True\n", + "except:\n", + " colab = False\n", + "\n", + "# colab=False\n", + "\n", + "if colab:\n", + " from IPython.display import display, Javascript\n", + " from google.colab.output import eval_js\n", + " from base64 import b64decode\n", + " from PIL import Image as PIL_Image\n", + "\n", + "\n", + " def take_photo(quality=0.8):\n", + " js = Javascript('''\n", + " async function takePhoto(quality) {\n", + " const div = document.createElement('div');\n", + " const capture = document.createElement('button');\n", + " capture.textContent = 'Capture';\n", + " div.appendChild(capture);\n", + "\n", + " const video = document.createElement('video');\n", + " video.style.display = 'block';\n", + " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", + "\n", + " document.body.appendChild(div);\n", + " div.appendChild(video);\n", + " video.srcObject = stream;\n", + " await video.play();\n", + "\n", + " // Resize the output to fit the video element.\n", + " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", + "\n", + " // Wait for Capture to be clicked.\n", + " await new Promise((resolve) => capture.onclick = resolve);\n", + "\n", + " const canvas = document.createElement('canvas');\n", + " canvas.width = video.videoWidth;\n", + " canvas.height = video.videoHeight;\n", + " canvas.getContext('2d').drawImage(video, 0, 0);\n", + " stream.getVideoTracks()[0].stop();\n", + " div.remove();\n", + " return canvas.toDataURL('image/jpeg', quality);\n", + " }\n", + " ''')\n", + " display(js)\n", + " data = eval_js('takePhoto({})'.format(quality))\n", + " binary = b64decode(data.split(',')[1])\n", + "\n", + "\n", + " image = PIL_Image.open(io.BytesIO(binary))\n", + " image_np = np.array(image)\n", + "\n", + " # with open(filename, 'wb') as f:\n", + " # f.write(binary)\n", + " return image_np\n", + "else:\n", + " import cv2\n", + " def take_photo(filename='photo.jpg', quality=0.8):\n", + " cam = cv2.VideoCapture(0)\n", + "\n", + " cv2.namedWindow(\"test\")\n", + "\n", + " img_counter = 0\n", + "\n", + " while True:\n", + " ret, frame = cam.read()\n", + " # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)\n", + " if not ret:\n", + " print(\"failed to grab frame\")\n", + " break\n", + " cv2.imshow(\"test\", frame)\n", + "\n", + " k = cv2.waitKey(1)\n", + " if k%256 == 27 or k%256 == 32 :\n", + " # ESC pressed\n", + " break\n", + "\n", + " cam.release()\n", + "\n", + " cv2.destroyAllWindows()\n", + "\n", + " # Preprocess image\n", + " img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n", + " # Flip image for 3rd person view\n", + " img = cv2.flip(img, 1)\n", + "\n", + " # To improve performance, optionally mark image as not writeable to pass by reference\n", + " img.flags.writeable = False\n", + "\n", + " return img" + ], + "id": "5UfPPceOjwtx" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:27:10.726845Z", + "start_time": "2023-05-19T12:27:10.611796Z" + }, + "id": "3CCoidG5jwtx" + }, + "outputs": [], + "source": [ + "def start_game(num_games=1):\n", + " game_results=[]\n", + " counter=0\n", + " # Load mediapipe hand class\n", + " pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n", + " # Load gesture recognition class\n", + " gest = GestureRecognition()\n", + " while True:\n", + " try:\n", + " img = take_photo()\n", + "\n", + " # # Show the image which was just taken.\n", + " # plt.imshow(img)\n", + " # Feedforward to extract keypoint\n", + " param = pipe.forward(img)\n", + " # Evaluate gesture for all hands\n", + "\n", + " for p in param:\n", + " if p['class'] is not None:\n", + " p['gesture'] = gest.eval(p['angle'])\n", + " # print(p['class'])\n", + " # print(p['gesture'])\n", + "\n", + " if p['gesture']=='fist':\n", + " action = Action.Rock\n", + " elif p['gesture']=='five':\n", + " action = Action.Paper\n", + " elif (p['gesture']=='three') or (p['gesture']=='yeah'):\n", + " action = Action.Scissors\n", + " elif (p['gesture']=='rock') :\n", + " action = Action.Lizard\n", + " elif (p['gesture']=='four'):\n", + " action = Action.Spock\n", + " if action is not None:\n", + " computer_action = get_computer_selection()\n", + " game_results.append(determine_winner(action, computer_action))\n", + " counter+=1\n", + " print_game_results(game_results)\n", + " old_action=action\n", + "\n", + " if counter>=num_games:\n", + " break\n", + " except Exception as err:\n", + " # Errors will be thrown if the user does not have a webcam or if they do not\n", + " # grant the page permission to access it.\n", + " print(str(err))\n", + " raise err\n", + "\n", + " pipe.pipe.close()" + ], + "id": "3CCoidG5jwtx" + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2023-05-19T12:27:39.871557Z", + "start_time": "2023-05-19T12:27:12.133115Z" + }, + "id": "biwLyBjhjwtx" + }, + "outputs": [], + "source": [ + "start_game(num_games=5)" + ], + "id": "biwLyBjhjwtx" + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + }, + "colab": { + "provenance": [] + } }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} + "nbformat": 4, + "nbformat_minor": 5 +} \ No newline at end of file From 819fb19014f1726e64801f5b48eceead8440b381 Mon Sep 17 00:00:00 2001 From: Luca Di Vita Date: Wed, 11 Oct 2023 14:43:10 +0200 Subject: [PATCH 2/6] code simplification --- Live Coding Completo.ipynb | 1252 +++++++++++++++++++----------------- support.py | 273 ++++++++ 2 files changed, 942 insertions(+), 583 deletions(-) create mode 100644 support.py diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index aefa5d5..68adf3f 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -61,7 +61,7 @@ "base_uri": "https://localhost:8080/" }, "id": "DLo0HbU8jwtm", - "outputId": "9226f8b9-f85b-4771-de99-c977f968902c" + "outputId": "562230cf-75bd-4f3c-e77b-8bd19359f923" }, "outputs": [ { @@ -89,7 +89,7 @@ "base_uri": "https://localhost:8080/" }, "id": "0OX9TkPDjwtm", - "outputId": "8d2b6b1b-6616-4391-ec37-2b4eea872887" + "outputId": "a574317b-31b0-477c-b046-d312ad601525" }, "outputs": [ { @@ -117,7 +117,7 @@ "base_uri": "https://localhost:8080/" }, "id": "W70GvccNjwtn", - "outputId": "74b1298a-18b6-4de1-932d-0c5d8d8530a3" + "outputId": "a3b2ca60-3d28-4e18-a67b-89dbdd9e3d14" }, "outputs": [ { @@ -145,14 +145,14 @@ "base_uri": "https://localhost:8080/" }, "id": "sCQu4LkLjwtn", - "outputId": "18546cab-9bb5-4ba5-eff3-e8d1f6f3cdfb" + "outputId": "df9929df-8e20-4727-9c28-6599ce085f35" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "digita un numero?6\n" + "digita un numero?0\n" ] } ], @@ -173,14 +173,14 @@ "base_uri": "https://localhost:8080/" }, "id": "Pslrt8Nwjwto", - "outputId": "b4483087-23fc-48d3-84d8-f25ef139452c" + "outputId": "b82ee90e-627d-4ee1-eef3-c75961f4f1b5" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "6\n" + "0\n" ] } ], @@ -201,7 +201,7 @@ "base_uri": "https://localhost:8080/" }, "id": "hy51y-owjwto", - "outputId": "5715043a-8497-45e5-9ffb-d49334861b12" + "outputId": "5625255b-ced0-48c1-970e-0bba1648aa3c" }, "outputs": [ { @@ -263,7 +263,7 @@ "base_uri": "https://localhost:8080/" }, "id": "EKBwgQm1jwtp", - "outputId": "29d0c513-554e-4ddf-d586-543dc412f021" + "outputId": "c1d76205-ac9a-4ef0-8316-76f958a44d43" }, "outputs": [ { @@ -271,7 +271,7 @@ "name": "stdout", "text": [ "\n", - "You chose rock, computer chose scissors.\n", + "You chose rock, computer chose paper.\n", "\n" ] } @@ -306,14 +306,14 @@ "base_uri": "https://localhost:8080/" }, "id": "90af3eea", - "outputId": "77ce39e0-e58a-436d-d35b-eac6a0f1e829" + "outputId": "f28c8553-1e44-4b87-ccba-38b278614e21" }, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ - "Rock smashes scissors! You win!\n" + "Paper covers rock! You lose.\n" ] } ], @@ -368,7 +368,7 @@ "base_uri": "https://localhost:8080/" }, "id": "47580fd9", - "outputId": "0a9d7003-7bea-4590-8af6-675e3b1f0944" + "outputId": "68bc0cbc-9fc5-4601-eeaa-aa41d29c6e5f" }, "outputs": [ { @@ -377,9 +377,9 @@ "text": [ "Enter a choice (rock, paper, scissors): rock\n", "\n", - "You chose rock, computer chose scissors.\n", + "You chose rock, computer chose paper.\n", "\n", - "Rock smashes scissors! You win!\n", + "Paper covers rock! You lose.\n", "Play again? (y/n): n\n" ] } @@ -473,7 +473,7 @@ "base_uri": "https://localhost:8080/" }, "id": "4BTg9ygOjwtq", - "outputId": "e0967596-b4a6-4c75-e447-3b9e7dc452b7" + "outputId": "c5c5e344-566f-4a7e-8ac6-8b6fa335af03" }, "outputs": [ { @@ -643,7 +643,7 @@ "base_uri": "https://localhost:8080/" }, "id": "I3BM0Z4Kjwtr", - "outputId": "9dc86a75-5e41-4d2a-ad46-828f04eb01d8" + "outputId": "c3e60e94-9187-4a74-e2dc-ba47e0c694dd" }, "outputs": [ { @@ -651,7 +651,7 @@ "output_type": "stream", "text": [ "Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n", - "Paper covers rock! You lose.\n", + "Both players selected Rock. It's a tie!\n", "Play again? (y/n): n\n" ] } @@ -741,7 +741,7 @@ "base_uri": "https://localhost:8080/" }, "id": "cv6L7ahtjwtr", - "outputId": "bf4268a8-17f1-49d1-8c54-4b9d69356cf9" + "outputId": "cb9e5e5d-95bf-4bfd-e69f-913c2423ed57" }, "outputs": [ { @@ -986,7 +986,7 @@ "base_uri": "https://localhost:8080/" }, "id": "18tMjb3sjwts", - "outputId": "138c7568-2c5e-4297-a358-7f389b5f3dda" + "outputId": "a6cd64b7-609c-43d9-d86d-8d89ffaedf78" }, "outputs": [ { @@ -1063,59 +1063,51 @@ "base_uri": "https://localhost:8080/" }, "id": "q_y93jZFjwtv", - "outputId": "60a49797-24a8-4ff2-ba4b-a10f6f6ff1ca" + "outputId": "a46694b8-b9de-4543-a5aa-803a44bf53c9" }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 4\n", + "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 0\n", "You chose\n", "\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + " \n", + "The computer chose\n", "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + " \n", "\n", - " \n", + " _ _ _\n", + " | | (_) | |\n", + " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", + " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", + "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", + " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", + " __/ |\n", + " |___/\n", + " ___ _ _ __\n", + " / / | | | (_) \\ \\\\\n", + "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", + "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", + "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", + "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", + " \\_\\ __/ /_/\n", + " |___/ \n", "Play again? (y/n): n\n" ] } @@ -1191,7 +1183,7 @@ "base_uri": "https://localhost:8080/" }, "id": "lcLQZxy3jwtw", - "outputId": "26e10e4e-f36b-443f-d972-099151877e4b" + "outputId": "a01480e3-f1ac-4857-b211-8b2e54d9a8ab" }, "outputs": [ { @@ -1212,108 +1204,12 @@ " \n", "The computer chose\n", "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \n", - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", - "You chose\n", - "\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \n", - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", - "You chose\n", - "\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", " \n", "\n", " _ _ _ ____ ___ ___ _ _\n", @@ -1340,91 +1236,15 @@ "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", "\n", " \n", - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", - "You chose\n", - "\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \n", - "\n", - " _____ ________ _________ _ _ _____ ___________\n", - "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", - "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", - "| | | | | | |\\/| || __/| | | | | | | __|| /\n", - "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", - " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - " \n", - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n", - "You chose\n", - "\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " _ _ _\n", - " | | (_) | |\n", - " | | _ __________ _ _ __ __| |\n", - " | | | |_ /_ / _` | '__/ _` |\n", - " | |___| |/ / / / (_| | | | (_| |\n", - " \\_____/_/___/___\\__,_|_| \\__,_|\n", - " \n", - "\n", - " _____ ________ _________ _ _ _____ ___________\n", - "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", - "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", - "| | | | | | |\\/| || __/| | | | | | | __|| /\n", - "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", - " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - " \n", "There were 0.0 % tied games \n", - "the player won 60.0 % of games\n", - "the computer won 40.0 % of games\n", - "in a total of 5 games\n" + "the player won 100.0 % of games\n", + "the computer won 0.0 % of games\n", + "in a total of 1 games\n" ] } ], "source": [ - "game_results=start_game(5)" + "game_results=start_game(1)" ], "id": "lcLQZxy3jwtw" }, @@ -1444,6 +1264,65 @@ "- `widgets.Dropdown`" ] }, + { + "cell_type": "code", + "source": [ + "!pip install numpy\n", + "!pip install opencv-python\n", + "!pip install mediapipe\n", + "!pip install requests" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yE1oRjMn5G0f", + "outputId": "3a93152c-7404-4fff-afd8-88eb52d21135" + }, + "id": "yE1oRjMn5G0f", + "execution_count": 31, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.23.5)\n", + "Requirement already satisfied: opencv-python in /usr/local/lib/python3.10/dist-packages (4.8.0.76)\n", + "Requirement already satisfied: numpy>=1.21.2 in /usr/local/lib/python3.10/dist-packages (from opencv-python) (1.23.5)\n", + "Collecting mediapipe\n", + " Downloading mediapipe-0.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (33.6 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m33.6/33.6 MB\u001b[0m \u001b[31m44.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.4.0)\n", + "Requirement already satisfied: attrs>=19.1.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.1.0)\n", + "Requirement already satisfied: flatbuffers>=2.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.5.26)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.7.1)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.23.5)\n", + "Requirement already satisfied: opencv-contrib-python in /usr/local/lib/python3.10/dist-packages (from mediapipe) (4.8.0.76)\n", + "Requirement already satisfied: protobuf<4,>=3.11 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.20.3)\n", + "Collecting sounddevice>=0.4.4 (from mediapipe)\n", + " Downloading sounddevice-0.4.6-py3-none-any.whl (31 kB)\n", + "Requirement already satisfied: CFFI>=1.0 in /usr/local/lib/python3.10/dist-packages (from sounddevice>=0.4.4->mediapipe) (1.16.0)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (1.1.1)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (0.12.0)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (4.43.1)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (1.4.5)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (23.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (9.4.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (3.1.1)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (2.8.2)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from CFFI>=1.0->sounddevice>=0.4.4->mediapipe) (2.21)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib->mediapipe) (1.16.0)\n", + "Installing collected packages: sounddevice, mediapipe\n", + "Successfully installed mediapipe-0.10.7 sounddevice-0.4.6\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (2.31.0)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests) (3.3.0)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests) (3.4)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests) (2.0.6)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests) (2023.7.22)\n" + ] + } + ] + }, { "cell_type": "code", "source": [ @@ -1454,10 +1333,10 @@ "base_uri": "https://localhost:8080/" }, "id": "uddtBN5Hj0mh", - "outputId": "d96882c6-0a5b-4e7d-d5e8-c14e39f3bd6c" + "outputId": "7a03f77d-d449-48c1-9627-3ecc8ad41274" }, "id": "uddtBN5Hj0mh", - "execution_count": 31, + "execution_count": 32, "outputs": [ { "output_type": "stream", @@ -1466,7 +1345,7 @@ "Downloading...\n", "From: https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\n", "To: /content/support.py\n", - "\r 0% 0.00/370 [00:000.5, and opposite handedness=1-score)\n", - " 'angle' : np.zeros(15), # Flexion joint angles in degree\n", - " 'gesture' : None, # Type of hand gesture\n", - " 'rvec' : np.zeros(3), # Global rotation vector Note: this term is only used for solvepnp initialization\n", - " 'tvec' : np.asarray([0,0,0.6]), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve\n", - " 'fps' : -1, # Frame per sec\n", - " # https://github.com/google/mediapipe/issues/1351\n", - " # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image\n", - " # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image\n", - " }\n", - " self.param.append(p)\n", - "\n", - "\n", - " def result_to_param(self, result, img):\n", - " # Convert mediapipe result to my own param\n", - " img_height, img_width, _ = img.shape\n", - "\n", - " # Reset param\n", - " for p in self.param:\n", - " p['class'] = None\n", - "\n", - " if result.multi_hand_landmarks is not None:\n", - " # Loop through different hands\n", - " for i, res in enumerate(result.multi_handedness):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " self.param[i]['class'] = res.classification[0].label\n", - " self.param[i]['score'] = res.classification[0].score\n", - "\n", - " # Loop through different hands\n", - " for i, res in enumerate(result.multi_hand_landmarks):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " # Loop through 21 landmark for each hand\n", - " for j, lm in enumerate(res.landmark):\n", - " self.param[i]['keypt'][j,0] = lm.x * img_width # Convert normalized coor to pixel [0,1] -> [0,width]\n", - " self.param[i]['keypt'][j,1] = lm.y * img_height # Convert normalized coor to pixel [0,1] -> [0,height]\n", - "\n", - " # Ignore it https://github.com/google/mediapipe/issues/1320\n", - " # self.param[i]['visible'][j] = lm.visibility\n", - " # self.param[i]['presence'][j] = lm.presence\n", - "\n", - " if result.multi_hand_world_landmarks is not None:\n", - " for i, res in enumerate(result.multi_hand_world_landmarks):\n", - " if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand\n", - " # Loop through 21 landmark for each hand\n", - " for j, lm in enumerate(res.landmark):\n", - " self.param[i]['joint'][j,0] = lm.x\n", - " self.param[i]['joint'][j,1] = lm.y\n", - " self.param[i]['joint'][j,2] = lm.z\n", - "\n", - " # Convert relative 3D joint to angle\n", - " self.param[i]['angle'] = self.convert_joint_to_angle(self.param[i]['joint'])\n", - " # Convert relative 3D joint to camera coordinate\n", - " self.convert_joint_to_camera_coor(self.param[i], self.intrin)\n", - "\n", - " return self.param\n", - "\n", - "\n", - " def convert_joint_to_angle(self, joint):\n", - " # Get direction vector of bone from parent to child\n", - " v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint\n", - " v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint\n", - " v = v2 - v1 # [20,3]\n", - " # Normalize v\n", - " v = v/np.linalg.norm(v, axis=1)[:, np.newaxis]\n", - "\n", - " # Get angle using arcos of dot product\n", - " angle = np.arccos(np.einsum('nt,nt->n',\n", - " v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:],\n", - " v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,]\n", - "\n", - " return np.degrees(angle) # Convert radian to degree\n", - "\n", - "\n", - " def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True):\n", - " # MediaPipe version 0.8.9.1 onwards:\n", - " # Given real-world 3D joint centered at middle MCP joint -> J_origin\n", - " # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec,\n", - " # We need to find the unknown translation vector -> tvec = [tx,ty,tz]\n", - " # Such that when J_camera is projected to the 2D image plane\n", - " # It matches the 2D keypoint locations\n", - "\n", - " # Considering all 21 keypoints,\n", - " # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns\n", - " # Since the equations are linear wrt [tx,ty,tz]\n", - " # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz]\n", - "\n", - " # Consider a single keypoint (pixel x) and joint (X,Y,Z)\n", - " # Using the perspective projection eq:\n", - " # (x - cx)/fx = (X + tx) / (Z + tz)\n", - " # Similarly for pixel y:\n", - " # (y - cy)/fy = (Y + ty) / (Z + tz)\n", - " # Rearranging the above linear equations by keeping constants to the right hand side:\n", - " # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z\n", - " # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z\n", - " # Therefore, we can factor out the unknowns and form a matrix eq:\n", - " # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z]\n", - " # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z]\n", - " # [tz]\n", - "\n", - " idx = [i for i in range(21)] # Use all landmarks\n", - "\n", - " if use_solvepnp:\n", - " # Method 1: OpenCV solvePnP\n", - " fx, fy = intrin['fx'], intrin['fy']\n", - " cx, cy = intrin['cx'], intrin['cy']\n", - " intrin_mat = np.asarray([[fx,0,cx],[0,fy,cy],[0,0,1]])\n", - " dist_coeff = np.zeros(4)\n", - "\n", - " ret, param['rvec'], param['tvec'] = cv2.solvePnP(\n", - " param['joint'][idx], param['keypt'][idx],\n", - " intrin_mat, dist_coeff, param['rvec'], param['tvec'],\n", - " useExtrinsicGuess=True)\n", - " # Add tvec to all joints\n", - " param['joint'] += param['tvec']\n", - "\n", - " else:\n", - " # Method 2:\n", - " A = np.zeros((len(idx),2,3))\n", - " b = np.zeros((len(idx),2))\n", - "\n", - " A[:,0,0] = intrin['fx']\n", - " A[:,1,1] = intrin['fy']\n", - " A[:,0,2] = -(param['keypt'][idx,0] - intrin['cx'])\n", - " A[:,1,2] = -(param['keypt'][idx,1] - intrin['cy'])\n", - "\n", - " b[:,0] = -intrin['fx'] * param['joint'][idx,0] \\\n", - " + (param['keypt'][idx,0] - intrin['cx']) * param['joint'][idx,2]\n", - " b[:,1] = -intrin['fy'] * param['joint'][idx,1] \\\n", - " + (param['keypt'][idx,1] - intrin['cy']) * param['joint'][idx,2]\n", - "\n", - " A = A.reshape(-1,3) # [8,3]\n", - " b = b.flatten() # [8]\n", - "\n", - " # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides\n", - " x = np.linalg.solve(A.T @ A, A.T @ b)\n", - " # Add tvec to all joints\n", - " param['joint'] += x\n", - "\n", - "\n", - "\n", - " def forward(self, img):\n", - "\n", - " # Extract result\n", - " result = self.pipe.process(img)\n", - "\n", - " # Convert result to my own param\n", - " param = self.result_to_param(result, img)\n", - "\n", - " return param\n", - "\n", - "\n", - "\n" - ], - "id": "pTVnoYlxjwtw" + "id": "-PEs3CLQ0RES", + "execution_count": 35, + "outputs": [] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": { "ExecuteTime": { "end_time": "2023-05-19T12:27:09.195732Z", @@ -1869,6 +1460,7 @@ "outputs": [], "source": [ "import io\n", + "import numpy as np\n", "\n", "try:\n", " from google.colab.output import eval_js\n", @@ -1968,7 +1560,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": { "ExecuteTime": { "end_time": "2023-05-19T12:27:10.726845Z", @@ -2032,15 +1624,125 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": { "ExecuteTime": { "end_time": "2023-05-19T12:27:39.871557Z", "start_time": "2023-05-19T12:27:12.133115Z" }, - "id": "biwLyBjhjwtx" + "id": "biwLyBjhjwtx", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 481 + }, + "outputId": "8e042567-872e-4c9f-cb48-b34f2ec9797b" }, - "outputs": [], + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "application/javascript": [ + "\n", + " async function takePhoto(quality) {\n", + " const div = document.createElement('div');\n", + " const capture = document.createElement('button');\n", + " capture.textContent = 'Capture';\n", + " div.appendChild(capture);\n", + "\n", + " const video = document.createElement('video');\n", + " video.style.display = 'block';\n", + " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", + "\n", + " document.body.appendChild(div);\n", + " div.appendChild(video);\n", + " video.srcObject = stream;\n", + " await video.play();\n", + "\n", + " // Resize the output to fit the video element.\n", + " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", + "\n", + " // Wait for Capture to be clicked.\n", + " await new Promise((resolve) => capture.onclick = resolve);\n", + "\n", + " const canvas = document.createElement('canvas');\n", + " canvas.width = video.videoWidth;\n", + " canvas.height = video.videoHeight;\n", + " canvas.getContext('2d').drawImage(video, 0, 0);\n", + " stream.getVideoTracks()[0].stop();\n", + " div.remove();\n", + " return canvas.toDataURL('image/jpeg', quality);\n", + " }\n", + " " + ] + }, + "metadata": {} + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "application/javascript": [ + "\n", + " async function takePhoto(quality) {\n", + " const div = document.createElement('div');\n", + " const capture = document.createElement('button');\n", + " capture.textContent = 'Capture';\n", + " div.appendChild(capture);\n", + "\n", + " const video = document.createElement('video');\n", + " video.style.display = 'block';\n", + " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", + "\n", + " document.body.appendChild(div);\n", + " div.appendChild(video);\n", + " video.srcObject = stream;\n", + " await video.play();\n", + "\n", + " // Resize the output to fit the video element.\n", + " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", + "\n", + " // Wait for Capture to be clicked.\n", + " await new Promise((resolve) => capture.onclick = resolve);\n", + "\n", + " const canvas = document.createElement('canvas');\n", + " canvas.width = video.videoWidth;\n", + " canvas.height = video.videoHeight;\n", + " canvas.getContext('2d').drawImage(video, 0, 0);\n", + " stream.getVideoTracks()[0].stop();\n", + " div.remove();\n", + " return canvas.toDataURL('image/jpeg', quality);\n", + " }\n", + " " + ] + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "'GestureRecognition' object has no attribute 'eval'\n" + ] + }, + { + "output_type": "error", + "ename": "AttributeError", + "evalue": "ignored", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mstart_game\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum_games\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m\u001b[0m in \u001b[0;36mstart_game\u001b[0;34m(num_games)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;31m# grant the page permission to access it.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mpipe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpipe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m\u001b[0m in \u001b[0;36mstart_game\u001b[0;34m(num_games)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mparam\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'class'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'gesture'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0meval\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'angle'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0;31m# print(p['class'])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;31m# print(p['gesture'])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mAttributeError\u001b[0m: 'GestureRecognition' object has no attribute 'eval'" + ] + } + ], "source": [ "start_game(num_games=5)" ], @@ -2067,6 +1769,390 @@ }, "colab": { "provenance": [] + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "6dbe33b9f1a445abb3293bf657b12fae": { + "model_module": "@jupyter-widgets/controls", + "model_name": "VBoxModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_0374851a408243198c4dcad1044959d4", + "IPY_MODEL_e87660665d2a4f1a92503f87ea974fc3", + "IPY_MODEL_5371e0071fae495bb1c9592897f1ccf4" + ], + "layout": "IPY_MODEL_c6cc915e6f994733bc78130cbe028657" + } + }, + "0374851a408243198c4dcad1044959d4": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DropdownModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Rock", + "Paper", + "Scissors", + "Lizard", + "Spock" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "Chose:", + "description_tooltip": null, + "disabled": false, + "index": 0, + "layout": "IPY_MODEL_4c3819168db1404c9341c4166712a9a0", + "style": "IPY_MODEL_796fc107ef4241469841d521200315f2" + } + }, + "e87660665d2a4f1a92503f87ea974fc3": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ButtonModel", + "model_module_version": "1.5.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ButtonView", + "button_style": "success", + "description": "Play!", + "disabled": false, + "icon": "check", + "layout": "IPY_MODEL_349f091e76cb498dab8e6180b6eb53fd", + "style": "IPY_MODEL_e6d4c5294b0745c4839e940a23375fbf", + "tooltip": "" + } + }, + "5371e0071fae495bb1c9592897f1ccf4": { + "model_module": "@jupyter-widgets/output", + "model_name": "OutputModel", + "model_module_version": "1.0.0", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_26326f1f8f0e4d07b7388894b2a2c4c2", + "msg_id": "", + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "You chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "The computer chose\n", + "\n", + " _ _ _\n", + " | | (_) | |\n", + " | | _ __________ _ _ __ __| |\n", + " | | | |_ /_ / _` | '__/ _` |\n", + " | |___| |/ / / / (_| | | | (_| |\n", + " \\_____/_/___/___\\__,_|_| \\__,_|\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n" + ] + } + ] + } + }, + "c6cc915e6f994733bc78130cbe028657": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "4c3819168db1404c9341c4166712a9a0": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "796fc107ef4241469841d521200315f2": { + "model_module": "@jupyter-widgets/controls", + "model_name": "DescriptionStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "349f091e76cb498dab8e6180b6eb53fd": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "e6d4c5294b0745c4839e940a23375fbf": { + "model_module": "@jupyter-widgets/controls", + "model_name": "ButtonStyleModel", + "model_module_version": "1.5.0", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "button_color": null, + "font_weight": "" + } + }, + "26326f1f8f0e4d07b7388894b2a2c4c2": { + "model_module": "@jupyter-widgets/base", + "model_name": "LayoutModel", + "model_module_version": "1.2.0", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": "1px solid black", + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + } } }, "nbformat": 4, diff --git a/support.py b/support.py new file mode 100644 index 0000000..5cc75fe --- /dev/null +++ b/support.py @@ -0,0 +1,273 @@ +import numpy as np +import mediapipe as mp +import cv2 +import requests +import ipywidgets as widgets + +###################################### + +def create_dropdown(actions): + menu = widgets.Dropdown( + options=actions , + description='Chose:') + output = widgets.Output(layout={'border': '1px solid black'}) + + button = widgets.Button(description="Play!", button_style='success', icon='check') + box = widgets.VBox([menu, button, output]) + return output, button, box, menu + +######################################## + +def download_dataset(): + url = "https://raw.githubusercontent.com/ntu-rris/google-mediapipe/main/data/gesture_train.csv" + resp = requests.get(url) + with open('./gesture_train.csv', 'wb') as f: + f.write(resp.content) + +######################################## + +# Define default camera intrinsic +img_width = 640 +img_height = 480 +intrin_default = { + 'fx': img_width*0.9, # Approx 0.7w < f < w https://www.learnopencv.com/approximate-focal-length-for-webcams-and-cell-phone-cameras/ + 'fy': img_width*0.9, + 'cx': img_width*0.5, # Approx center of image + 'cy': img_height*0.5, + 'width': img_width, +} + +class GestureRecognition: + import numpy as np + import mediapipe as mp + import cv2 + def __init__(self): + # 11 types of gesture 'name':class label + self.gesture = { + 'fist':0,'one':1,'two':2,'three':3,'four':4,'five':5,'six':6, + 'rock':7,'spiderman':8,'yeah':9,'ok':10, + } + + # Load training data + file = np.genfromtxt('./gesture_train.csv', delimiter=',') + # Extract input joint angles + angle = file[:,:-1].astype(np.float32) + # Extract output class label + label = file[:, -1].astype(np.float32) + # Use OpenCV KNN + self.knn = cv2.ml.KNearest_create() + self.knn.train(angle, cv2.ml.ROW_SAMPLE, label) + + def eval(self, angle): + # Use KNN for gesture recognition + data = np.asarray([angle], dtype=np.float32) + ret, results, neighbours ,dist = self.knn.findNearest(data, 3) + idx = int(results[0][0]) # Index of class label + + return list(self.gesture)[idx] # Return name of class label + + +class MediaPipeHand: + def __init__(self, static_image_mode=True, max_num_hands=1, + model_complexity=1, intrin=None): + self.max_num_hands = max_num_hands + if intrin is None: + self.intrin = intrin_default + else: + self.intrin = intrin + + # Access MediaPipe Solutions Python API + mp_hands = mp.solutions.hands + # help(mp_hands.Hands) + + # Initialize MediaPipe Hands + # static_image_mode: + # For video processing set to False: + # Will use previous frame to localize hand to reduce latency + # For unrelated images set to True: + # To allow hand detection to run on every input images + + # max_num_hands: + # Maximum number of hands to detect + + # model_complexity: + # Complexity of the hand landmark model: 0 or 1. + # Landmark accuracy as well as inference latency generally + # go up with the model complexity. Default to 1. + + # min_detection_confidence: + # Confidence value [0,1] from hand detection model + # for detection to be considered successful + + # min_tracking_confidence: + # Minimum confidence value [0,1] from landmark-tracking model + # for hand landmarks to be considered tracked successfully, + # or otherwise hand detection will be invoked automatically on the next input image. + # Setting it to a higher value can increase robustness of the solution, + # at the expense of a higher latency. + # Ignored if static_image_mode is true, where hand detection simply runs on every image. + + self.pipe = mp_hands.Hands( + static_image_mode=static_image_mode, + max_num_hands=max_num_hands, + model_complexity=model_complexity, + min_detection_confidence=0.5, + min_tracking_confidence=0.5) + + # Define hand parameter + self.param = [] + for i in range(max_num_hands): + p = { + 'keypt' : np.zeros((21,2)), # 2D keypt in image coordinate (pixel) + 'joint' : np.zeros((21,3)), # 3D joint in camera coordinate (m) + 'class' : None, # Left / right / none hand + 'score' : 0, # Probability of predicted handedness (always>0.5, and opposite handedness=1-score) + 'angle' : np.zeros(15), # Flexion joint angles in degree + 'gesture' : None, # Type of hand gesture + 'rvec' : np.zeros(3), # Global rotation vector Note: this term is only used for solvepnp initialization + 'tvec' : np.asarray([0,0,0.6]), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve + 'fps' : -1, # Frame per sec + # https://github.com/google/mediapipe/issues/1351 + # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image + # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image + } + self.param.append(p) + + + def result_to_param(self, result, img): + # Convert mediapipe result to my own param + img_height, img_width, _ = img.shape + + # Reset param + for p in self.param: + p['class'] = None + + if result.multi_hand_landmarks is not None: + # Loop through different hands + for i, res in enumerate(result.multi_handedness): + if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand + self.param[i]['class'] = res.classification[0].label + self.param[i]['score'] = res.classification[0].score + + # Loop through different hands + for i, res in enumerate(result.multi_hand_landmarks): + if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand + # Loop through 21 landmark for each hand + for j, lm in enumerate(res.landmark): + self.param[i]['keypt'][j,0] = lm.x * img_width # Convert normalized coor to pixel [0,1] -> [0,width] + self.param[i]['keypt'][j,1] = lm.y * img_height # Convert normalized coor to pixel [0,1] -> [0,height] + + # Ignore it https://github.com/google/mediapipe/issues/1320 + # self.param[i]['visible'][j] = lm.visibility + # self.param[i]['presence'][j] = lm.presence + + if result.multi_hand_world_landmarks is not None: + for i, res in enumerate(result.multi_hand_world_landmarks): + if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand + # Loop through 21 landmark for each hand + for j, lm in enumerate(res.landmark): + self.param[i]['joint'][j,0] = lm.x + self.param[i]['joint'][j,1] = lm.y + self.param[i]['joint'][j,2] = lm.z + + # Convert relative 3D joint to angle + self.param[i]['angle'] = self.convert_joint_to_angle(self.param[i]['joint']) + # Convert relative 3D joint to camera coordinate + self.convert_joint_to_camera_coor(self.param[i], self.intrin) + + return self.param + + + def convert_joint_to_angle(self, joint): + # Get direction vector of bone from parent to child + v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint + v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint + v = v2 - v1 # [20,3] + # Normalize v + v = v/np.linalg.norm(v, axis=1)[:, np.newaxis] + + # Get angle using arcos of dot product + angle = np.arccos(np.einsum('nt,nt->n', + v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:], + v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,] + + return np.degrees(angle) # Convert radian to degree + + + def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True): + # MediaPipe version 0.8.9.1 onwards: + # Given real-world 3D joint centered at middle MCP joint -> J_origin + # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec, + # We need to find the unknown translation vector -> tvec = [tx,ty,tz] + # Such that when J_camera is projected to the 2D image plane + # It matches the 2D keypoint locations + + # Considering all 21 keypoints, + # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns + # Since the equations are linear wrt [tx,ty,tz] + # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz] + + # Consider a single keypoint (pixel x) and joint (X,Y,Z) + # Using the perspective projection eq: + # (x - cx)/fx = (X + tx) / (Z + tz) + # Similarly for pixel y: + # (y - cy)/fy = (Y + ty) / (Z + tz) + # Rearranging the above linear equations by keeping constants to the right hand side: + # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z + # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z + # Therefore, we can factor out the unknowns and form a matrix eq: + # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z] + # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z] + # [tz] + + idx = [i for i in range(21)] # Use all landmarks + + if use_solvepnp: + # Method 1: OpenCV solvePnP + fx, fy = intrin['fx'], intrin['fy'] + cx, cy = intrin['cx'], intrin['cy'] + intrin_mat = np.asarray([[fx,0,cx],[0,fy,cy],[0,0,1]]) + dist_coeff = np.zeros(4) + + ret, param['rvec'], param['tvec'] = cv2.solvePnP( + param['joint'][idx], param['keypt'][idx], + intrin_mat, dist_coeff, param['rvec'], param['tvec'], + useExtrinsicGuess=True) + # Add tvec to all joints + param['joint'] += param['tvec'] + + else: + # Method 2: + A = np.zeros((len(idx),2,3)) + b = np.zeros((len(idx),2)) + + A[:,0,0] = intrin['fx'] + A[:,1,1] = intrin['fy'] + A[:,0,2] = -(param['keypt'][idx,0] - intrin['cx']) + A[:,1,2] = -(param['keypt'][idx,1] - intrin['cy']) + + b[:,0] = -intrin['fx'] * param['joint'][idx,0] \ + + (param['keypt'][idx,0] - intrin['cx']) * param['joint'][idx,2] + b[:,1] = -intrin['fy'] * param['joint'][idx,1] \ + + (param['keypt'][idx,1] - intrin['cy']) * param['joint'][idx,2] + + A = A.reshape(-1,3) # [8,3] + b = b.flatten() # [8] + + # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides + x = np.linalg.solve(A.T @ A, A.T @ b) + # Add tvec to all joints + param['joint'] += x + + + + def forward(self, img): + # Extract result + result = self.pipe.process(img) + + # Convert result to my own param + param = self.result_to_param(result, img) + + return param + + From 4f8be6a4a09a06159b48c5622ca428335771645d Mon Sep 17 00:00:00 2001 From: Moreno Mazzocchetti Date: Mon, 13 Nov 2023 14:32:16 +0100 Subject: [PATCH 3/6] Update Live Coding Completo --- .gitignore | 4 +- Live Coding Completo.ipynb | 2161 +----------------------------------- support.py | 94 +- 3 files changed, 97 insertions(+), 2162 deletions(-) diff --git a/.gitignore b/.gitignore index 1a6e47c..e717817 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store ~* -.ipynb_checkpoints \ No newline at end of file +.ipynb_checkpoints +/.idea +/.venv diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index 68adf3f..673428d 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -1,2160 +1 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "b35fe87b", - "metadata": { - "id": "b35fe87b" - }, - "source": [ - "# Rock - Paper - Scissors - Lizard - Spock\n", - "\n", - "Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano." - ] - }, - { - "cell_type": "markdown", - "id": "78e5f376", - "metadata": { - "id": "78e5f376" - }, - "source": [ - "## Task 1\n", - "\n", - "Nella prossima cella studieremo:\n", - "\n", - "* cos'è una variabile in Python\n", - "* quali sono i tipi di variabile che è possibile avere in Python\n", - "* come è possible prendere un input da parte dell'utente\n", - "* come è possibile creare una lista con le possibili scelte di gioco\n", - "* come è possibile generare la mossa del computer in maniera casuale" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "6cfa68db", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.287013Z", - "start_time": "2023-05-19T12:20:20.860873Z" - }, - "id": "6cfa68db" - }, - "outputs": [], - "source": [ - "intero=10\n", - "booleano=True\n", - "numero_float=0.13\n", - "stringa='pycon'\n" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.303529Z", - "start_time": "2023-05-19T12:20:20.876923Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "DLo0HbU8jwtm", - "outputId": "562230cf-75bd-4f3c-e77b-8bd19359f923" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Ciao Mondo :)\n" - ] - } - ], - "source": [ - "print('Ciao Mondo :)')" - ], - "id": "DLo0HbU8jwtm" - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.333073Z", - "start_time": "2023-05-19T12:20:20.891457Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "0OX9TkPDjwtm", - "outputId": "a574317b-31b0-477c-b046-d312ad601525" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "10\n" - ] - } - ], - "source": [ - "print(intero)" - ], - "id": "0OX9TkPDjwtm" - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:23.334653Z", - "start_time": "2023-05-19T12:20:20.905149Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "W70GvccNjwtn", - "outputId": "a3b2ca60-3d28-4e18-a67b-89dbdd9e3d14" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "pycon 10\n" - ] - } - ], - "source": [ - "print(stringa,intero)" - ], - "id": "W70GvccNjwtn" - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:26.414596Z", - "start_time": "2023-05-19T12:20:20.924676Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "sCQu4LkLjwtn", - "outputId": "df9929df-8e20-4727-9c28-6599ce085f35" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "digita un numero?0\n" - ] - } - ], - "source": [ - "risultato = input('digita un numero?')" - ], - "id": "sCQu4LkLjwtn" - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:26.415102Z", - "start_time": "2023-05-19T12:20:26.202688Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "Pslrt8Nwjwto", - "outputId": "b82ee90e-627d-4ee1-eef3-c75961f4f1b5" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "0\n" - ] - } - ], - "source": [ - "print(risultato)\n" - ], - "id": "Pslrt8Nwjwto" - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.451911Z", - "start_time": "2023-05-19T12:20:26.220803Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "hy51y-owjwto", - "outputId": "5625255b-ced0-48c1-970e-0bba1648aa3c" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Enter a choice (rock, paper, scissors): rock\n" - ] - } - ], - "source": [ - "user_action = input(\"Enter a choice (rock, paper, scissors): \")" - ], - "id": "hy51y-owjwto" - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.466948Z", - "start_time": "2023-05-19T12:20:30.278604Z" - }, - "id": "sO8y1DHqjwto" - }, - "outputs": [], - "source": [ - "import random\n" - ], - "id": "sO8y1DHqjwto" - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.467949Z", - "start_time": "2023-05-19T12:20:30.295991Z" - }, - "id": "NxgXYbZ-jwtp" - }, - "outputs": [], - "source": [ - "\n", - "possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", - "computer_action = random.choice(possible_actions)\n" - ], - "id": "NxgXYbZ-jwtp" - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.469948Z", - "start_time": "2023-05-19T12:20:30.312305Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "EKBwgQm1jwtp", - "outputId": "c1d76205-ac9a-4ef0-8316-76f958a44d43" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\n", - "You chose rock, computer chose paper.\n", - "\n" - ] - } - ], - "source": [ - "print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n" - ], - "id": "EKBwgQm1jwtp" - }, - { - "cell_type": "markdown", - "id": "f9faebb5", - "metadata": { - "id": "f9faebb5" - }, - "source": [ - "## Task 2\n", - "\n", - "In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "90af3eea", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:30.469948Z", - "start_time": "2023-05-19T12:20:30.326982Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "90af3eea", - "outputId": "f28c8553-1e44-4b87-ccba-38b278614e21" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Paper covers rock! You lose.\n" - ] - } - ], - "source": [ - "if user_action == computer_action:\n", - " print(f\"Both players selected {user_action}. It's a tie!\")\n", - "elif user_action == \"rock\":\n", - " if computer_action == \"scissors\":\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - "elif user_action == \"paper\":\n", - " if computer_action == \"rock\":\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - "elif user_action == \"scissors\":\n", - " if computer_action == \"paper\":\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")" - ] - }, - { - "cell_type": "markdown", - "id": "f9182a9f", - "metadata": { - "id": "f9182a9f" - }, - "source": [ - "### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n", - "\n", - "In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche:\n", - "- prendere in input dall'utente una scelta\n", - "- generare la mossa del computer\n", - "- confrontare le mosse\n", - "- mostrare un output\n", - "\n", - "A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "47580fd9", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.753623Z", - "start_time": "2023-05-19T12:20:30.346046Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "47580fd9", - "outputId": "68bc0cbc-9fc5-4601-eeaa-aa41d29c6e5f" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Enter a choice (rock, paper, scissors): rock\n", - "\n", - "You chose rock, computer chose paper.\n", - "\n", - "Paper covers rock! You lose.\n", - "Play again? (y/n): n\n" - ] - } - ], - "source": [ - "while True:\n", - " user_action = input(\"Enter a choice (rock, paper, scissors): \")\n", - " possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", - " computer_action = random.choice(possible_actions)\n", - " print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n", - "\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action}. It's a tie!\")\n", - " elif user_action == \"rock\":\n", - " if computer_action == \"scissors\":\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - " elif user_action == \"paper\":\n", - " if computer_action == \"rock\":\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - " elif user_action == \"scissors\":\n", - " if computer_action == \"paper\":\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")\n", - "\n", - " play_again = input(\"Play again? (y/n): \")\n", - " if play_again.lower() != \"y\":\n", - " break" - ] - }, - { - "cell_type": "markdown", - "id": "dd16cb05", - "metadata": { - "id": "dd16cb05" - }, - "source": [ - "## Task 3: Ottimizzazioni nel codice\n", - "\n", - "Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**.\n", - "\n", - "Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile." - ] - }, - { - "cell_type": "markdown", - "id": "2dfe73b6", - "metadata": { - "id": "2dfe73b6" - }, - "source": [ - "### Task 3a: Creiamo un enum\n", - "\n", - "In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "0ec721b6", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.753623Z", - "start_time": "2023-05-19T12:20:44.647673Z" - }, - "id": "0ec721b6" - }, - "outputs": [], - "source": [ - "from enum import IntEnum\n", - "\n", - "class Action(IntEnum):\n", - " Rock = 0\n", - " Paper = 1\n", - " Scissors = 2" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.756156Z", - "start_time": "2023-05-19T12:20:44.665466Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "4BTg9ygOjwtq", - "outputId": "c5c5e344-566f-4a7e-8ac6-8b6fa335af03" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Action.Rock == Action.Rock True\n", - "Action.Rock == Action(0) True\n", - "Action(0) Action.Rock\n" - ] - } - ], - "source": [ - "print('Action.Rock == Action.Rock',Action.Rock == Action.Rock)\n", - "print('Action.Rock == Action(0)',Action.Rock == Action(0))\n", - "print('Action(0)',Action(0))" - ], - "id": "4BTg9ygOjwtq" - }, - { - "cell_type": "markdown", - "id": "92eea47a", - "metadata": { - "id": "92eea47a" - }, - "source": [ - "### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n", - "\n", - "Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n", - "\n", - "- Fai giocare l'utente -> `get_user_selection()`\n", - "- Fai giocare il computer -> `get_computer_selection()`\n", - "- Decidi chi ha vinto -> `determine_winner(user_selection, computer_selection)`" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "08c5263b", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.756156Z", - "start_time": "2023-05-19T12:20:44.679996Z" - }, - "id": "08c5263b" - }, - "outputs": [], - "source": [ - "def get_user_selection():\n", - " user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n", - " selection = int(user_input)\n", - " action = Action(selection)\n", - " return action\n", - "\n", - "\n", - "def get_user_selection():\n", - " choices = [f\"{action.name}[{action.value}]\" for action in Action]\n", - " choices_str = \", \".join(choices)\n", - " selection = int(input(f\"Enter a choice ({choices_str}): \"))\n", - " action = Action(selection)\n", - " return action" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.793367Z", - "start_time": "2023-05-19T12:20:44.696045Z" - }, - "id": "hldiDTxqjwtr" - }, - "outputs": [], - "source": [ - "def get_computer_selection():\n", - " selection = random.randint(0, len(Action) - 1)\n", - " action = Action(selection)\n", - " return action" - ], - "id": "hldiDTxqjwtr" - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.794876Z", - "start_time": "2023-05-19T12:20:44.715076Z" - }, - "id": "eMYFUSiojwtr" - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", - " elif user_action == Action.Rock:\n", - " if computer_action == Action.Scissors:\n", - " print(\"Rock smashes scissors! You win!\")\n", - " else:\n", - " print(\"Paper covers rock! You lose.\")\n", - " elif user_action == Action.Paper:\n", - " if computer_action == Action.Rock:\n", - " print(\"Paper covers rock! You win!\")\n", - " else:\n", - " print(\"Scissors cuts paper! You lose.\")\n", - " elif user_action == Action.Scissors:\n", - " if computer_action == Action.Paper:\n", - " print(\"Scissors cuts paper! You win!\")\n", - " else:\n", - " print(\"Rock smashes scissors! You lose.\")" - ], - "id": "eMYFUSiojwtr" - }, - { - "cell_type": "markdown", - "id": "4ca7428d", - "metadata": { - "id": "4ca7428d" - }, - "source": [ - "Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita:\n", - "\n", - "- `start_game()`\n" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "id": "8ebfa484", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:44.794876Z", - "start_time": "2023-05-19T12:20:44.724834Z" - }, - "id": "8ebfa484" - }, - "outputs": [], - "source": [ - "def start_game():\n", - " while True:\n", - " try:\n", - " user_action = get_user_selection()\n", - " except ValueError as e:\n", - " range_str = f\"[0, {len(Action) - 1}]\"\n", - " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", - " continue\n", - "\n", - " computer_action = get_computer_selection()\n", - " determine_winner(user_action, computer_action)\n", - "\n", - " play_again = input(\"Play again? (y/n): \")\n", - " if play_again.lower() != \"y\":\n", - " break" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.862916Z", - "start_time": "2023-05-19T12:20:44.741502Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "I3BM0Z4Kjwtr", - "outputId": "c3e60e94-9187-4a74-e2dc-ba47e0c694dd" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n", - "Both players selected Rock. It's a tie!\n", - "Play again? (y/n): n\n" - ] - } - ], - "source": [ - "start_game()" - ], - "id": "I3BM0Z4Kjwtr" - }, - { - "cell_type": "markdown", - "id": "6955e8bc", - "metadata": { - "id": "6955e8bc" - }, - "source": [ - "### Task 3c: Creiamo un dizionario con le mosse vincenti\n", - "\n", - "Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n", - "- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n", - "- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "id": "96893f8d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.864487Z", - "start_time": "2023-05-19T12:20:50.756391Z" - }, - "id": "96893f8d" - }, - "outputs": [], - "source": [ - "victories = {\n", - " Action.Rock: [Action.Scissors], # Rock beats scissors\n", - " Action.Paper: [Action.Rock], # Paper beats rock\n", - " Action.Scissors: [Action.Paper] # Scissors beats paper\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "c3205d3c", - "metadata": { - "id": "c3205d3c" - }, - "source": [ - "### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "id": "dce77a8a", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:50.864487Z", - "start_time": "2023-05-19T12:20:50.774458Z" - }, - "id": "dce77a8a" - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n", - " defeats = victories[user_action]\n", - " if user_action == computer_action:\n", - " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", - " elif computer_action in defeats:\n", - " print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n", - " else:\n", - " print(f\"{computer_action.name} beats {user_action.name}! You lose.\")" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.122073Z", - "start_time": "2023-05-19T12:20:50.794541Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "cv6L7ahtjwtr", - "outputId": "cb9e5e5d-95bf-4bfd-e69f-913c2423ed57" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n", - "You chose Rock. The computer chose Scissors.\n", - "Rock beats Scissors! You win!\n", - "Play again? (y/n): n\n" - ] - } - ], - "source": [ - "start_game()" - ], - "id": "cv6L7ahtjwtr" - }, - { - "cell_type": "markdown", - "id": "ee1b1835", - "metadata": { - "id": "ee1b1835" - }, - "source": [ - "### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n", - "\n", - "È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "id": "60f6e2d5", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.122073Z", - "start_time": "2023-05-19T12:20:56.018470Z" - }, - "id": "60f6e2d5" - }, - "outputs": [], - "source": [ - "class Action(IntEnum):\n", - " Rock = 0\n", - " Paper = 1\n", - " Scissors = 2\n", - " Lizard = 3\n", - " Spock = 4\n", - "\n", - "victories = {\n", - " Action.Scissors: [Action.Lizard, Action.Paper],\n", - " Action.Paper: [Action.Spock, Action.Rock],\n", - " Action.Rock: [Action.Lizard, Action.Scissors],\n", - " Action.Lizard: [Action.Spock, Action.Paper],\n", - " Action.Spock: [Action.Scissors, Action.Rock]\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "67881ce8", - "metadata": { - "id": "67881ce8" - }, - "source": [ - "### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art\n", - "\n", - "Creeremo due nuovi dizionari:\n", - "- in `ascii_action` metteremo le ascii art delle mosse\n", - "- in `ascii_results` metteremo le ascii art dei possibili risultati" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "id": "4422813d", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.182207Z", - "start_time": "2023-05-19T12:20:56.037218Z" - }, - "id": "4422813d" - }, - "outputs": [], - "source": [ - "ascii_action = {\n", - " Action.Scissors: r\"\"\"\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \"\"\",\n", - " Action.Paper: r\"\"\"\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \"\"\",\n", - " Action.Rock: r\"\"\"\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \"\"\",\n", - " Action.Lizard: r\"\"\"\n", - " _ _ _\n", - " | | (_) | |\n", - " | | _ __________ _ _ __ __| |\n", - " | | | |_ /_ / _` | '__/ _` |\n", - " | |___| |/ / / / (_| | | | (_| |\n", - " \\_____/_/___/___\\__,_|_| \\__,_|\n", - " \"\"\",\n", - " Action.Spock: r\"\"\"\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \"\"\"\n", - "}\n", - "\n", - "COMPUTER_WIN=-1\n", - "HUMAN_WIN=1\n", - "DROW=0\n", - "ascii_result = {\n", - " COMPUTER_WIN: r\"\"\"\n", - " _____ ________ _________ _ _ _____ ___________\n", - "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", - "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", - "| | | | | | |\\/| || __/| | | | | | | __|| /\n", - "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", - " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - " \"\"\",\n", - " HUMAN_WIN: r\"\"\"\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \"\"\",\n", - " DROW: r\"\"\"\n", - " _ _ _\n", - " | | (_) | |\n", - " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", - " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", - "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", - " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", - " __/ |\n", - " |___/\n", - " ___ _ _ __\n", - " / / | | | (_) \\ \\\\\n", - "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", - "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", - "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", - "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", - " \\_\\ __/ /_/\n", - " |___/ \"\"\"\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "75f2c6d5", - "metadata": { - "id": "75f2c6d5" - }, - "source": [ - "Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art:\n", - "- `display_action`\n", - "- `display_results`" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "id": "c96921e2", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.182207Z", - "start_time": "2023-05-19T12:20:56.052294Z" - }, - "id": "c96921e2" - }, - "outputs": [], - "source": [ - "def display_action(action):\n", - " print(ascii_action[action])\n", - "\n", - "def display_result(result):\n", - " print(ascii_result[result])" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.183207Z", - "start_time": "2023-05-19T12:20:56.064342Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "18tMjb3sjwts", - "outputId": "a6cd64b7-609c-43d9-d86d-8d89ffaedf78" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \n" - ] - } - ], - "source": [ - "display_action(Action.Spock)" - ], - "id": "18tMjb3sjwts" - }, - { - "cell_type": "markdown", - "id": "c1b643e3", - "metadata": { - "id": "c1b643e3" - }, - "source": [ - "Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "id": "252c6e45", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:20:56.184209Z", - "start_time": "2023-05-19T12:20:56.081582Z" - }, - "id": "252c6e45" - }, - "outputs": [], - "source": [ - "def determine_winner(user_action, computer_action):\n", - " print(f\"You chose\")\n", - " display_action(user_action)\n", - " print(f\"The computer chose\")\n", - " display_action(computer_action)\n", - " defeats = victories[user_action]\n", - " if user_action == computer_action:\n", - " display_result(DROW)\n", - " return DROW\n", - " elif computer_action in defeats:\n", - " display_result(HUMAN_WIN)\n", - " return HUMAN_WIN\n", - " else:\n", - " display_result(COMPUTER_WIN)\n", - " return COMPUTER_WIN" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:01.057176Z", - "start_time": "2023-05-19T12:20:56.101255Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "q_y93jZFjwtv", - "outputId": "a46694b8-b9de-4543-a5aa-803a44bf53c9" - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 0\n", - "You chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "The computer chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "\n", - " _ _ _\n", - " | | (_) | |\n", - " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", - " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", - "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", - " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", - " __/ |\n", - " |___/\n", - " ___ _ _ __\n", - " / / | | | (_) \\ \\\\\n", - "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", - "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", - "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", - "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", - " \\_\\ __/ /_/\n", - " |___/ \n", - "Play again? (y/n): n\n" - ] - } - ], - "source": [ - "start_game()" - ], - "id": "q_y93jZFjwtv" - }, - { - "cell_type": "markdown", - "id": "5e478a36", - "metadata": { - "id": "5e478a36" - }, - "source": [ - "### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n", - "\n", - "Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla!" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "id": "ec5766f6", - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:01.096343Z", - "start_time": "2023-05-19T12:21:01.055176Z" - }, - "id": "ec5766f6" - }, - "outputs": [], - "source": [ - "def print_game_results(game_results):\n", - " num_tied = game_results.count(DROW)/len(game_results)*100\n", - " num_player_wins = game_results.count(HUMAN_WIN)/len(game_results)*100\n", - " num_computer_wins =game_results.count(COMPUTER_WIN)/len(game_results)*100\n", - "\n", - " print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n", - "\n", - "def start_game(num_games=1):\n", - " game_results=[]\n", - " counter=0\n", - " while True:\n", - " try:\n", - " user_action = get_user_selection()\n", - " except ValueError as e:\n", - " range_str = f\"[0, {len(Action) - 1}]\"\n", - " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", - " continue\n", - "\n", - " computer_action = get_computer_selection()\n", - " game_results.append(determine_winner(user_action, computer_action))\n", - " counter+=1\n", - "\n", - " if counter>=num_games:\n", - " break\n", - " print_game_results(game_results)\n", - " return game_results\n", - "\n" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:21:09.040634Z", - "start_time": "2023-05-19T12:21:01.070699Z" - }, - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "lcLQZxy3jwtw", - "outputId": "a01480e3-f1ac-4857-b211-8b2e54d9a8ab" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 4\n", - "You chose\n", - "\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \n", - "The computer chose\n", - "\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \n", - "There were 0.0 % tied games \n", - "the player won 100.0 % of games\n", - "the computer won 0.0 % of games\n", - "in a total of 1 games\n" - ] - } - ], - "source": [ - "game_results=start_game(1)" - ], - "id": "lcLQZxy3jwtw" - }, - { - "cell_type": "markdown", - "id": "aae3e00d", - "metadata": { - "id": "aae3e00d" - }, - "source": [ - "### Utilizziamo un'interfaccia grafica!\n", - "\n", - "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", - "\n", - "Concetti connessi:\n", - "- list comprehension\n", - "- `widgets.Dropdown`" - ] - }, - { - "cell_type": "code", - "source": [ - "!pip install numpy\n", - "!pip install opencv-python\n", - "!pip install mediapipe\n", - "!pip install requests" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "yE1oRjMn5G0f", - "outputId": "3a93152c-7404-4fff-afd8-88eb52d21135" - }, - "id": "yE1oRjMn5G0f", - "execution_count": 31, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.23.5)\n", - "Requirement already satisfied: opencv-python in /usr/local/lib/python3.10/dist-packages (4.8.0.76)\n", - "Requirement already satisfied: numpy>=1.21.2 in /usr/local/lib/python3.10/dist-packages (from opencv-python) (1.23.5)\n", - "Collecting mediapipe\n", - " Downloading mediapipe-0.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (33.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m33.6/33.6 MB\u001b[0m \u001b[31m44.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hRequirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.4.0)\n", - "Requirement already satisfied: attrs>=19.1.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.1.0)\n", - "Requirement already satisfied: flatbuffers>=2.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.5.26)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.7.1)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.23.5)\n", - "Requirement already satisfied: opencv-contrib-python in /usr/local/lib/python3.10/dist-packages (from mediapipe) (4.8.0.76)\n", - "Requirement already satisfied: protobuf<4,>=3.11 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.20.3)\n", - "Collecting sounddevice>=0.4.4 (from mediapipe)\n", - " Downloading sounddevice-0.4.6-py3-none-any.whl (31 kB)\n", - "Requirement already satisfied: CFFI>=1.0 in /usr/local/lib/python3.10/dist-packages (from sounddevice>=0.4.4->mediapipe) (1.16.0)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (1.1.1)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (0.12.0)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (4.43.1)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (1.4.5)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (23.2)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (9.4.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (3.1.1)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib->mediapipe) (2.8.2)\n", - "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from CFFI>=1.0->sounddevice>=0.4.4->mediapipe) (2.21)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib->mediapipe) (1.16.0)\n", - "Installing collected packages: sounddevice, mediapipe\n", - "Successfully installed mediapipe-0.10.7 sounddevice-0.4.6\n", - "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (2.31.0)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests) (3.3.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests) (3.4)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests) (2.0.6)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests) (2023.7.22)\n" - ] - } - ] - }, - { - "cell_type": "code", - "source": [ - "!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "uddtBN5Hj0mh", - "outputId": "7a03f77d-d449-48c1-9627-3ecc8ad41274" - }, - "id": "uddtBN5Hj0mh", - "execution_count": 32, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Downloading...\n", - "From: https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\n", - "To: /content/support.py\n", - "\r 0% 0.00/10.6k [00:00 capture.onclick = resolve);\n", - "\n", - " const canvas = document.createElement('canvas');\n", - " canvas.width = video.videoWidth;\n", - " canvas.height = video.videoHeight;\n", - " canvas.getContext('2d').drawImage(video, 0, 0);\n", - " stream.getVideoTracks()[0].stop();\n", - " div.remove();\n", - " return canvas.toDataURL('image/jpeg', quality);\n", - " }\n", - " ''')\n", - " display(js)\n", - " data = eval_js('takePhoto({})'.format(quality))\n", - " binary = b64decode(data.split(',')[1])\n", - "\n", - "\n", - " image = PIL_Image.open(io.BytesIO(binary))\n", - " image_np = np.array(image)\n", - "\n", - " # with open(filename, 'wb') as f:\n", - " # f.write(binary)\n", - " return image_np\n", - "else:\n", - " import cv2\n", - " def take_photo(filename='photo.jpg', quality=0.8):\n", - " cam = cv2.VideoCapture(0)\n", - "\n", - " cv2.namedWindow(\"test\")\n", - "\n", - " img_counter = 0\n", - "\n", - " while True:\n", - " ret, frame = cam.read()\n", - " # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)\n", - " if not ret:\n", - " print(\"failed to grab frame\")\n", - " break\n", - " cv2.imshow(\"test\", frame)\n", - "\n", - " k = cv2.waitKey(1)\n", - " if k%256 == 27 or k%256 == 32 :\n", - " # ESC pressed\n", - " break\n", - "\n", - " cam.release()\n", - "\n", - " cv2.destroyAllWindows()\n", - "\n", - " # Preprocess image\n", - " img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n", - " # Flip image for 3rd person view\n", - " img = cv2.flip(img, 1)\n", - "\n", - " # To improve performance, optionally mark image as not writeable to pass by reference\n", - " img.flags.writeable = False\n", - "\n", - " return img" - ], - "id": "5UfPPceOjwtx" - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:10.726845Z", - "start_time": "2023-05-19T12:27:10.611796Z" - }, - "id": "3CCoidG5jwtx" - }, - "outputs": [], - "source": [ - "def start_game(num_games=1):\n", - " game_results=[]\n", - " counter=0\n", - " # Load mediapipe hand class\n", - " pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n", - " # Load gesture recognition class\n", - " gest = GestureRecognition()\n", - " while True:\n", - " try:\n", - " img = take_photo()\n", - "\n", - " # # Show the image which was just taken.\n", - " # plt.imshow(img)\n", - " # Feedforward to extract keypoint\n", - " param = pipe.forward(img)\n", - " # Evaluate gesture for all hands\n", - "\n", - " for p in param:\n", - " if p['class'] is not None:\n", - " p['gesture'] = gest.eval(p['angle'])\n", - " # print(p['class'])\n", - " # print(p['gesture'])\n", - "\n", - " if p['gesture']=='fist':\n", - " action = Action.Rock\n", - " elif p['gesture']=='five':\n", - " action = Action.Paper\n", - " elif (p['gesture']=='three') or (p['gesture']=='yeah'):\n", - " action = Action.Scissors\n", - " elif (p['gesture']=='rock') :\n", - " action = Action.Lizard\n", - " elif (p['gesture']=='four'):\n", - " action = Action.Spock\n", - " if action is not None:\n", - " computer_action = get_computer_selection()\n", - " game_results.append(determine_winner(action, computer_action))\n", - " counter+=1\n", - " print_game_results(game_results)\n", - " old_action=action\n", - "\n", - " if counter>=num_games:\n", - " break\n", - " except Exception as err:\n", - " # Errors will be thrown if the user does not have a webcam or if they do not\n", - " # grant the page permission to access it.\n", - " print(str(err))\n", - " raise err\n", - "\n", - " pipe.pipe.close()" - ], - "id": "3CCoidG5jwtx" - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "ExecuteTime": { - "end_time": "2023-05-19T12:27:39.871557Z", - "start_time": "2023-05-19T12:27:12.133115Z" - }, - "id": "biwLyBjhjwtx", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 481 - }, - "outputId": "8e042567-872e-4c9f-cb48-b34f2ec9797b" - }, - "outputs": [ - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "application/javascript": [ - "\n", - " async function takePhoto(quality) {\n", - " const div = document.createElement('div');\n", - " const capture = document.createElement('button');\n", - " capture.textContent = 'Capture';\n", - " div.appendChild(capture);\n", - "\n", - " const video = document.createElement('video');\n", - " video.style.display = 'block';\n", - " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", - "\n", - " document.body.appendChild(div);\n", - " div.appendChild(video);\n", - " video.srcObject = stream;\n", - " await video.play();\n", - "\n", - " // Resize the output to fit the video element.\n", - " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", - "\n", - " // Wait for Capture to be clicked.\n", - " await new Promise((resolve) => capture.onclick = resolve);\n", - "\n", - " const canvas = document.createElement('canvas');\n", - " canvas.width = video.videoWidth;\n", - " canvas.height = video.videoHeight;\n", - " canvas.getContext('2d').drawImage(video, 0, 0);\n", - " stream.getVideoTracks()[0].stop();\n", - " div.remove();\n", - " return canvas.toDataURL('image/jpeg', quality);\n", - " }\n", - " " - ] - }, - "metadata": {} - }, - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "application/javascript": [ - "\n", - " async function takePhoto(quality) {\n", - " const div = document.createElement('div');\n", - " const capture = document.createElement('button');\n", - " capture.textContent = 'Capture';\n", - " div.appendChild(capture);\n", - "\n", - " const video = document.createElement('video');\n", - " video.style.display = 'block';\n", - " const stream = await navigator.mediaDevices.getUserMedia({video: true});\n", - "\n", - " document.body.appendChild(div);\n", - " div.appendChild(video);\n", - " video.srcObject = stream;\n", - " await video.play();\n", - "\n", - " // Resize the output to fit the video element.\n", - " google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n", - "\n", - " // Wait for Capture to be clicked.\n", - " await new Promise((resolve) => capture.onclick = resolve);\n", - "\n", - " const canvas = document.createElement('canvas');\n", - " canvas.width = video.videoWidth;\n", - " canvas.height = video.videoHeight;\n", - " canvas.getContext('2d').drawImage(video, 0, 0);\n", - " stream.getVideoTracks()[0].stop();\n", - " div.remove();\n", - " return canvas.toDataURL('image/jpeg', quality);\n", - " }\n", - " " - ] - }, - "metadata": {} - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "'GestureRecognition' object has no attribute 'eval'\n" - ] - }, - { - "output_type": "error", - "ename": "AttributeError", - "evalue": "ignored", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mstart_game\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnum_games\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;32m\u001b[0m in \u001b[0;36mstart_game\u001b[0;34m(num_games)\u001b[0m\n\u001b[1;32m 45\u001b[0m \u001b[0;31m# grant the page permission to access it.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mstr\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0merr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 47\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0merr\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 48\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 49\u001b[0m \u001b[0mpipe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpipe\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mclose\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;32m\u001b[0m in \u001b[0;36mstart_game\u001b[0;34m(num_games)\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mp\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mparam\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'class'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mnot\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'gesture'\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mgest\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0meval\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mp\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'angle'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 21\u001b[0m \u001b[0;31m# print(p['class'])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 22\u001b[0m \u001b[0;31m# print(p['gesture'])\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mAttributeError\u001b[0m: 'GestureRecognition' object has no attribute 'eval'" - ] - } - ], - "source": [ - "start_game(num_games=5)" - ], - "id": "biwLyBjhjwtx" - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3 (ipykernel)", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.1" - }, - "colab": { - "provenance": [] - }, - "widgets": { - "application/vnd.jupyter.widget-state+json": { - "6dbe33b9f1a445abb3293bf657b12fae": { - "model_module": "@jupyter-widgets/controls", - "model_name": "VBoxModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "VBoxModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "VBoxView", - "box_style": "", - "children": [ - "IPY_MODEL_0374851a408243198c4dcad1044959d4", - "IPY_MODEL_e87660665d2a4f1a92503f87ea974fc3", - "IPY_MODEL_5371e0071fae495bb1c9592897f1ccf4" - ], - "layout": "IPY_MODEL_c6cc915e6f994733bc78130cbe028657" - } - }, - "0374851a408243198c4dcad1044959d4": { - "model_module": "@jupyter-widgets/controls", - "model_name": "DropdownModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DropdownModel", - "_options_labels": [ - "Rock", - "Paper", - "Scissors", - "Lizard", - "Spock" - ], - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "DropdownView", - "description": "Chose:", - "description_tooltip": null, - "disabled": false, - "index": 0, - "layout": "IPY_MODEL_4c3819168db1404c9341c4166712a9a0", - "style": "IPY_MODEL_796fc107ef4241469841d521200315f2" - } - }, - "e87660665d2a4f1a92503f87ea974fc3": { - "model_module": "@jupyter-widgets/controls", - "model_name": "ButtonModel", - "model_module_version": "1.5.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ButtonModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/controls", - "_view_module_version": "1.5.0", - "_view_name": "ButtonView", - "button_style": "success", - "description": "Play!", - "disabled": false, - "icon": "check", - "layout": "IPY_MODEL_349f091e76cb498dab8e6180b6eb53fd", - "style": "IPY_MODEL_e6d4c5294b0745c4839e940a23375fbf", - "tooltip": "" - } - }, - "5371e0071fae495bb1c9592897f1ccf4": { - "model_module": "@jupyter-widgets/output", - "model_name": "OutputModel", - "model_module_version": "1.0.0", - "state": { - "_dom_classes": [], - "_model_module": "@jupyter-widgets/output", - "_model_module_version": "1.0.0", - "_model_name": "OutputModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/output", - "_view_module_version": "1.0.0", - "_view_name": "OutputView", - "layout": "IPY_MODEL_26326f1f8f0e4d07b7388894b2a2c4c2", - "msg_id": "", - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "You chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "The computer chose\n", - "\n", - " _ _ _\n", - " | | (_) | |\n", - " | | _ __________ _ _ __ __| |\n", - " | | | |_ /_ / _` | '__/ _` |\n", - " | |___| |/ / / / (_| | | | (_| |\n", - " \\_____/_/___/___\\__,_|_| \\__,_|\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \n" - ] - } - ] - } - }, - "c6cc915e6f994733bc78130cbe028657": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "4c3819168db1404c9341c4166712a9a0": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "796fc107ef4241469841d521200315f2": { - "model_module": "@jupyter-widgets/controls", - "model_name": "DescriptionStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "DescriptionStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "description_width": "" - } - }, - "349f091e76cb498dab8e6180b6eb53fd": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": null, - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - }, - "e6d4c5294b0745c4839e940a23375fbf": { - "model_module": "@jupyter-widgets/controls", - "model_name": "ButtonStyleModel", - "model_module_version": "1.5.0", - "state": { - "_model_module": "@jupyter-widgets/controls", - "_model_module_version": "1.5.0", - "_model_name": "ButtonStyleModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "StyleView", - "button_color": null, - "font_weight": "" - } - }, - "26326f1f8f0e4d07b7388894b2a2c4c2": { - "model_module": "@jupyter-widgets/base", - "model_name": "LayoutModel", - "model_module_version": "1.2.0", - "state": { - "_model_module": "@jupyter-widgets/base", - "_model_module_version": "1.2.0", - "_model_name": "LayoutModel", - "_view_count": null, - "_view_module": "@jupyter-widgets/base", - "_view_module_version": "1.2.0", - "_view_name": "LayoutView", - "align_content": null, - "align_items": null, - "align_self": null, - "border": "1px solid black", - "bottom": null, - "display": null, - "flex": null, - "flex_flow": null, - "grid_area": null, - "grid_auto_columns": null, - "grid_auto_flow": null, - "grid_auto_rows": null, - "grid_column": null, - "grid_gap": null, - "grid_row": null, - "grid_template_areas": null, - "grid_template_columns": null, - "grid_template_rows": null, - "height": null, - "justify_content": null, - "justify_items": null, - "left": null, - "margin": null, - "max_height": null, - "max_width": null, - "min_height": null, - "min_width": null, - "object_fit": null, - "object_position": null, - "order": null, - "overflow": null, - "overflow_x": null, - "overflow_y": null, - "padding": null, - "right": null, - "top": null, - "visibility": null, - "width": null - } - } - } - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} \ No newline at end of file +{"cells":[{"cell_type":"markdown","metadata":{"id":"b35fe87b"},"source":["# Rock - Paper - Scissors - Lizard - Spock\n","\n","Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano."]},{"cell_type":"markdown","metadata":{"id":"78e5f376"},"source":["## Task 1\n","\n","Nella prossima cella studieremo:\n","\n","* cos'è una variabile in Python\n","* quali sono i tipi di variabile che è possibile avere in Python\n","* come è possible prendere un input da parte dell'utente\n","* come è possibile creare una lista con le possibili scelte di gioco\n","* come è possibile generare la mossa del computer in maniera casuale"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"6cfa68db"},"outputs":[],"source":["intero = 10\n","booleano = True\n","numero_float = 0.13\n","stringa = 'pycon'\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":7,"status":"ok","timestamp":1699709841312,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"DLo0HbU8jwtm","outputId":"8fb84091-34ba-4dbd-94ea-3e2ccad4f316"},"outputs":[{"name":"stdout","output_type":"stream","text":["Ciao Mondo :)\n"]}],"source":["print('Ciao Mondo :)')"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":279,"status":"ok","timestamp":1699709841586,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"0OX9TkPDjwtm","outputId":"236a58da-c29b-46cb-8eab-b2e50a15556d"},"outputs":[{"name":"stdout","output_type":"stream","text":["10\n"]}],"source":["print(intero)"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5,"status":"ok","timestamp":1699709841586,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"W70GvccNjwtn","outputId":"a87c9464-85b8-4086-a9d4-d5cbceea3b2c"},"outputs":[{"name":"stdout","output_type":"stream","text":["pycon 10\n"]}],"source":["print(stringa,intero)"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2795,"status":"ok","timestamp":1699709844379,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"sCQu4LkLjwtn","outputId":"c5b694ec-2b17-4f51-f402-a6eff4790264"},"outputs":[{"name":"stdout","output_type":"stream","text":["digita un numero?5\n"]}],"source":["risultato = input('digita un numero?')"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":8,"status":"ok","timestamp":1699709844379,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"Pslrt8Nwjwto","outputId":"57c4624b-b1e5-463a-c625-6e40ba2d13ce"},"outputs":[{"name":"stdout","output_type":"stream","text":["5\n"]}],"source":["print(risultato)\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2801,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"hy51y-owjwto","outputId":"a2168225-1f45-49b1-cc33-f2c021a60afa"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (rock, paper, scissors): rock\n"]}],"source":["user_action = input(\"Enter a choice (rock, paper, scissors): \")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"sO8y1DHqjwto"},"outputs":[],"source":["import random\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"NxgXYbZ-jwtp"},"outputs":[],"source":["\n","possible_actions = [\"rock\", \"paper\", \"scissors\"]\n","computer_action = random.choice(possible_actions)\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":9,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"EKBwgQm1jwtp","outputId":"14137bef-862d-4d35-9cc8-5e7b0fd9b847"},"outputs":[{"name":"stdout","output_type":"stream","text":["\n","You chose rock, computer chose scissors.\n","\n"]}],"source":["print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n"]},{"cell_type":"markdown","metadata":{"id":"f9faebb5"},"source":["## Task 2\n","\n","In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"90af3eea","outputId":"dd03b6a2-38f4-43e5-9807-ce912ff62e13"},"outputs":[{"name":"stdout","output_type":"stream","text":["Rock smashes scissors! You win!\n"]}],"source":["if user_action == computer_action:\n"," print(f\"Both players selected {user_action}. It's a tie!\")\n","elif user_action == \"rock\":\n"," if computer_action == \"scissors\":\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n","elif user_action == \"paper\":\n"," if computer_action == \"rock\":\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n","elif user_action == \"scissors\":\n"," if computer_action == \"paper\":\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")"]},{"cell_type":"markdown","metadata":{"id":"f9182a9f"},"source":["### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n","\n","In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche:\n","- prendere in input dall'utente una scelta\n","- generare la mossa del computer\n","- confrontare le mosse\n","- mostrare un output\n","\n","A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**."]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4668,"status":"ok","timestamp":1699709851839,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"47580fd9","outputId":"921ac4d0-4b70-40ad-b75a-dd8041c5a911"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (rock, paper, scissors): rock\n","\n","You chose rock, computer chose rock.\n","\n","Both players selected rock. It's a tie!\n","Play again? (y/n): n\n"]}],"source":["while True:\n"," user_action = input(\"Enter a choice (rock, paper, scissors): \")\n"," possible_actions = [\"rock\", \"paper\", \"scissors\"]\n"," computer_action = random.choice(possible_actions)\n"," print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n","\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action}. It's a tie!\")\n"," elif user_action == \"rock\":\n"," if computer_action == \"scissors\":\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n"," elif user_action == \"paper\":\n"," if computer_action == \"rock\":\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n"," elif user_action == \"scissors\":\n"," if computer_action == \"paper\":\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")\n","\n"," play_again = input(\"Play again? (y/n): \")\n"," if play_again.lower() != \"y\":\n"," break"]},{"cell_type":"markdown","metadata":{"id":"dd16cb05"},"source":["## Task 3: Ottimizzazioni nel codice\n","\n","Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**.\n","\n","Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile."]},{"cell_type":"markdown","metadata":{"id":"2dfe73b6"},"source":["### Task 3a: Creiamo un enum\n","\n","In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"0ec721b6"},"outputs":[],"source":["from enum import IntEnum\n","\n","class Action(IntEnum):\n"," Rock = 0\n"," Paper = 1\n"," Scissors = 2"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":10,"status":"ok","timestamp":1699709851839,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"4BTg9ygOjwtq","outputId":"fbfc8ae2-0cfe-42cd-ce09-0426001729cc"},"outputs":[{"name":"stdout","output_type":"stream","text":["Action.Rock == Action.Rock True\n","Action.Rock == Action(0) True\n","Action(0) Action.Rock\n"]}],"source":["print('Action.Rock == Action.Rock',Action.Rock == Action.Rock)\n","print('Action.Rock == Action(0)',Action.Rock == Action(0))\n","print('Action(0)',Action(0))"]},{"cell_type":"markdown","metadata":{"id":"92eea47a"},"source":["### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n","\n","Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n","\n","- Fai giocare l'utente -\u003e `get_user_selection()`\n","- Fai giocare il computer -\u003e `get_computer_selection()`\n","- Decidi chi ha vinto -\u003e `determine_winner(user_selection, computer_selection)`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"08c5263b"},"outputs":[],"source":["def get_user_selection():\n"," user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n"," selection = int(user_input)\n"," action = Action(selection)\n"," return action\n","\n","\n","def get_user_selection():\n"," choices = [f\"{action.name}[{action.value}]\" for action in Action]\n"," choices_str = \", \".join(choices)\n"," selection = int(input(f\"Enter a choice ({choices_str}): \"))\n"," action = Action(selection)\n"," return action"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"hldiDTxqjwtr"},"outputs":[],"source":["def get_computer_selection():\n"," selection = random.randint(0, len(Action) - 1)\n"," action = Action(selection)\n"," return action"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"eMYFUSiojwtr"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action.name}. It's a tie!\")\n"," elif user_action == Action.Rock:\n"," if computer_action == Action.Scissors:\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n"," elif user_action == Action.Paper:\n"," if computer_action == Action.Rock:\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n"," elif user_action == Action.Scissors:\n"," if computer_action == Action.Paper:\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")"]},{"cell_type":"markdown","metadata":{"id":"4ca7428d"},"source":["Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita:\n","\n","- `start_game()`\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"8ebfa484"},"outputs":[],"source":["def start_game():\n"," while True:\n"," try:\n"," user_action = get_user_selection()\n"," except ValueError as e:\n"," range_str = f\"[0, {len(Action) - 1}]\"\n"," print(f\"Invalid selection. Enter a value in range {range_str}\")\n"," continue\n","\n"," computer_action = get_computer_selection()\n"," determine_winner(user_action, computer_action)\n","\n"," play_again = input(\"Play again? (y/n): \")\n"," if play_again.lower() != \"y\":\n"," break"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":11137,"status":"ok","timestamp":1699709862968,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"I3BM0Z4Kjwtr","outputId":"a102b536-8581-40b3-9aed-3e9eea5c921d"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2]): 1\n","Paper covers rock! You win!\n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"6955e8bc"},"source":["### Task 3c: Creiamo un dizionario con le mosse vincenti\n","\n","Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n","- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n","- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"96893f8d"},"outputs":[],"source":["victories = {\n"," Action.Rock: [Action.Scissors], # Rock beats scissors\n"," Action.Paper: [Action.Rock], # Paper beats rock\n"," Action.Scissors: [Action.Paper] # Scissors beats paper\n","}"]},{"cell_type":"markdown","metadata":{"id":"c3205d3c"},"source":["### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dce77a8a"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n"," defeats = victories[user_action]\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action.name}. It's a tie!\")\n"," elif computer_action in defeats:\n"," print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n"," else:\n"," print(f\"{computer_action.name} beats {user_action.name}! You lose.\")"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":11858,"status":"ok","timestamp":1699709874816,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"cv6L7ahtjwtr","outputId":"609f516f-00c3-42ae-ba9e-1496fc56cae8"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2]): 2\n","You chose Scissors. The computer chose Rock.\n","Rock beats Scissors! You lose.\n","Play again? (y/n): y\n","Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n","You chose Rock. The computer chose Paper.\n","Paper beats Rock! You lose.\n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"ee1b1835"},"source":["### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n","\n","È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"60f6e2d5"},"outputs":[],"source":["class Action(IntEnum):\n"," Rock = 0\n"," Paper = 1\n"," Scissors = 2\n"," Lizard = 3\n"," Spock = 4\n","\n","victories = {\n"," Action.Scissors: [Action.Lizard, Action.Paper],\n"," Action.Paper: [Action.Spock, Action.Rock],\n"," Action.Rock: [Action.Lizard, Action.Scissors],\n"," Action.Lizard: [Action.Spock, Action.Paper],\n"," Action.Spock: [Action.Scissors, Action.Rock]\n","}"]},{"cell_type":"markdown","metadata":{"id":"67881ce8"},"source":["### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art\n","\n","Creeremo due nuovi dizionari:\n","- in `ascii_action` metteremo le ascii art delle mosse\n","- in `ascii_results` metteremo le ascii art dei possibili risultati"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"4422813d"},"outputs":[],"source":["ascii_action = {\n"," Action.Scissors: r\"\"\"\n"," _____ _\n"," / ___| (_)\n"," \\ `--. ___ _ ___ ___ ___ _ __ ___\n"," `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n"," /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n"," \\____/ \\___|_|___/___/\\___/|_| |___/\n"," \"\"\",\n"," Action.Paper: r\"\"\"\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \"\"\",\n"," Action.Rock: r\"\"\"\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \"\"\",\n"," Action.Lizard: r\"\"\"\n"," _ _ _\n"," | | (_) | |\n"," | | _ __________ _ _ __ __| |\n"," | | | |_ /_ / _` | '__/ _` |\n"," | |___| |/ / / / (_| | | | (_| |\n"," \\_____/_/___/___\\__,_|_| \\__,_|\n"," \"\"\",\n"," Action.Spock: r\"\"\"\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \"\"\"\n","}\n","\n","COMPUTER_WIN=-1\n","HUMAN_WIN=1\n","DROW=0\n","ascii_result = {\n"," COMPUTER_WIN: r\"\"\"\n"," _____ ________ _________ _ _ _____ ___________\n","/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n","| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n","| | | | | | |\\/| || __/| | | | | | | __|| /\n","| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n"," \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n"," \"\"\",\n"," HUMAN_WIN: r\"\"\"\n"," _ _ _ ____ ___ ___ _ _\n","| | | | | | | \\/ | / _ \\ | \\ | |\n","| |_| | | | | . . |/ /_\\ \\| \\| |\n","| _ | | | | |\\/| || _ || . ` |\n","| | | | |_| | | | || | | || |\\ |\n","\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n","\n"," __\n"," / _|\n"," | |_ ___ _ __ _ __ _____ __\n"," | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n"," _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n","(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n","\n"," \"\"\",\n"," DROW: r\"\"\"\n"," _ _ _\n"," | | (_) | |\n"," __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n"," / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n","| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n"," \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n"," __/ |\n"," |___/\n"," ___ _ _ __\n"," / / | | | (_) \\ \\\\\n","| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n","| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n","| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n","| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n"," \\_\\ __/ /_/\n"," |___/ \"\"\"\n","}"]},{"cell_type":"markdown","metadata":{"id":"75f2c6d5"},"source":["Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art:\n","- `display_action`\n","- `display_results`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"c96921e2"},"outputs":[],"source":["def display_action(action):\n"," print(ascii_action[action])\n","\n","def display_result(result):\n"," print(ascii_result[result])"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":15,"status":"ok","timestamp":1699709874816,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"18tMjb3sjwts","outputId":"24de5258-e6d3-4a97-8e09-17f6659485f3"},"outputs":[{"name":"stdout","output_type":"stream","text":["\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \n"]}],"source":["display_action(Action.Spock)"]},{"cell_type":"markdown","metadata":{"id":"c1b643e3"},"source":["Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"252c6e45"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," print(f\"You chose\")\n"," display_action(user_action)\n"," print(f\"The computer chose\")\n"," display_action(computer_action)\n"," defeats = victories[user_action]\n"," if user_action == computer_action:\n"," display_result(DROW)\n"," return DROW\n"," elif computer_action in defeats:\n"," display_result(HUMAN_WIN)\n"," return HUMAN_WIN\n"," else:\n"," display_result(COMPUTER_WIN)\n"," return COMPUTER_WIN"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4400,"status":"ok","timestamp":1699709879202,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"q_y93jZFjwtv","outputId":"9a6ba887-29e9-4baa-840d-d98ea434c6d0"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 0\n","You chose\n","\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \n","The computer chose\n","\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \n","\n"," _____ ________ _________ _ _ _____ ___________\n","/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n","| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n","| | | | | | |\\/| || __/| | | | | | | __|| /\n","| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n"," \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n"," \n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"5e478a36"},"source":["### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n","\n","Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla!"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"ec5766f6"},"outputs":[],"source":["def print_game_results(game_results):\n"," num_tied = game_results.count(DROW)/len(game_results)*100\n"," num_player_wins = game_results.count(HUMAN_WIN)/len(game_results)*100\n"," num_computer_wins =game_results.count(COMPUTER_WIN)/len(game_results)*100\n","\n"," print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n","\n","def start_game(num_games=1):\n"," game_results=[]\n"," counter=0\n"," while True:\n"," try:\n"," user_action = get_user_selection()\n"," except ValueError as e:\n"," range_str = f\"[0, {len(Action) - 1}]\"\n"," print(f\"Invalid selection. Enter a value in range {range_str}\")\n"," continue\n","\n"," computer_action = get_computer_selection()\n"," game_results.append(determine_winner(user_action, computer_action))\n"," counter+=1\n","\n"," if counter\u003e=num_games:\n"," break\n"," print_game_results(game_results)\n"," return game_results\n","\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4689,"status":"ok","timestamp":1699709883885,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"lcLQZxy3jwtw","outputId":"15a53e1a-4624-4a0a-e604-2b687f656fef"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n","You chose\n","\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \n","The computer chose\n","\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \n","\n"," _ _ _\n"," | | (_) | |\n"," __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n"," / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n","| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n"," \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n"," __/ |\n"," |___/\n"," ___ _ _ __\n"," / / | | | (_) \\ \\\\\n","| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n","| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n","| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n","| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n"," \\_\\ __/ /_/\n"," |___/ \n","There were 100.0 % tied games \n","the player won 0.0 % of games\n","the computer won 0.0 % of games\n","in a total of 1 games\n"]}],"source":["game_results=start_game(1)"]},{"cell_type":"markdown","metadata":{"id":"aae3e00d"},"source":["### Utilizziamo un'interfaccia grafica!\n","\n","Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n","\n","Concetti connessi:\n","- list comprehension\n","- `widgets.Dropdown`"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":15258,"status":"ok","timestamp":1699709899132,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"yE1oRjMn5G0f","outputId":"fe2da3a7-4310-44a5-c77d-560c2e9739e5"},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.23.5)\n","Requirement already satisfied: opencv-python in /usr/local/lib/python3.10/dist-packages (4.8.0.76)\n","Requirement already satisfied: numpy\u003e=1.21.2 in /usr/local/lib/python3.10/dist-packages (from opencv-python) (1.23.5)\n","Requirement already satisfied: mediapipe in /usr/local/lib/python3.10/dist-packages (0.10.8)\n","Requirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.4.0)\n","Requirement already satisfied: attrs\u003e=19.1.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.1.0)\n","Requirement already satisfied: flatbuffers\u003e=2.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.5.26)\n","Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.7.1)\n","Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.23.5)\n","Requirement already satisfied: opencv-contrib-python in /usr/local/lib/python3.10/dist-packages (from mediapipe) (4.8.0.76)\n","Requirement already satisfied: protobuf\u003c4,\u003e=3.11 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.20.3)\n","Requirement already satisfied: sounddevice\u003e=0.4.4 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (0.4.6)\n","Requirement already satisfied: CFFI\u003e=1.0 in /usr/local/lib/python3.10/dist-packages (from sounddevice\u003e=0.4.4-\u003emediapipe) (1.16.0)\n","Requirement already satisfied: contourpy\u003e=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (1.2.0)\n","Requirement already satisfied: cycler\u003e=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (0.12.1)\n","Requirement already satisfied: fonttools\u003e=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (4.44.0)\n","Requirement already satisfied: kiwisolver\u003e=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (1.4.5)\n","Requirement already satisfied: packaging\u003e=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (23.2)\n","Requirement already satisfied: pillow\u003e=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (9.4.0)\n","Requirement already satisfied: pyparsing\u003e=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (3.1.1)\n","Requirement already satisfied: python-dateutil\u003e=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (2.8.2)\n","Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from CFFI\u003e=1.0-\u003esounddevice\u003e=0.4.4-\u003emediapipe) (2.21)\n","Requirement already satisfied: six\u003e=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil\u003e=2.7-\u003ematplotlib-\u003emediapipe) (1.16.0)\n","Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (2.31.0)\n","Requirement already satisfied: charset-normalizer\u003c4,\u003e=2 in /usr/local/lib/python3.10/dist-packages (from requests) (3.3.2)\n","Requirement already satisfied: idna\u003c4,\u003e=2.5 in /usr/local/lib/python3.10/dist-packages (from requests) (3.4)\n","Requirement already satisfied: urllib3\u003c3,\u003e=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests) (2.0.7)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests) (2023.7.22)\n"]}],"source":["!pip install numpy\n","!pip install opencv-python\n","!pip install mediapipe\n","!pip install requests"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":951,"status":"ok","timestamp":1699709900079,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"uddtBN5Hj0mh","outputId":"5aaf0849-e0d3-48be-fa9e-35bf7473506f"},"outputs":[{"name":"stdout","output_type":"stream","text":["Downloading...\n","From: https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\n","To: /content/support.py\n","\r 0% 0.00/13.2k [00:00\u003c?, ?B/s]\r100% 13.2k/13.2k [00:00\u003c00:00, 51.9MB/s]\n"]}],"source":["!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"Pg1r0Rq14b9f"},"outputs":[],"source":["from support import *"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":847},"executionInfo":{"elapsed":7,"status":"ok","timestamp":1699709900079,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"a6b41097","outputId":"aadb9b9b-abec-4391-fe5b-93f908d710c6"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"bce58963af05485d9e28cc4836e298c7","version_major":2,"version_minor":0},"text/plain":["VBox(children=(Dropdown(description='Chose:', options=(('Rock', 0), ('Paper', 1), ('Scissors', 2), ('Lizard', …"]},"metadata":{},"output_type":"display_data"}],"source":["options=[(action.name,action.value) for action in Action]\n","output, button, box, menu = create_dropdown(options)\n","\n","def on_button_clicked(b):\n"," output.clear_output()\n"," with output:\n"," computer_action = get_computer_selection()\n"," determine_winner(Action(menu.value), computer_action)\n","\n","button.on_click(on_button_clicked)\n","\n","display(box)"]},{"cell_type":"markdown","metadata":{"id":"d95e966e"},"source":["## Time to use ML!\n","\n","Nelle celle successive andremo ad utilizzare il Machine Learning per addestrare un modello predittivo in grado di dedurre la mossa dell'utente a partire dall'inquadratura della mano ottenuta con la webcam.\n","\n","Installiamo le librerie necessarie e importiamole:"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"3CCoidG5jwtx"},"outputs":[],"source":["def start_game(num_games=1):\n"," game_results=[]\n"," counter=0\n"," # Load mediapipe hand class\n"," pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n"," # Load gesture recognition class\n"," gest = GestureRecognition()\n"," while True:\n"," try:\n"," img = take_photo()\n"," param = pipe.forward(img)\n"," # Evaluate gesture for all hands\n","\n"," for p in param:\n"," if p['class'] is not None:\n"," p['gesture'] = gest.eval(p['angle'])\n"," action = None\n"," if p['gesture']=='fist':\n"," action = Action.Rock\n"," elif p['gesture']=='five':\n"," action = Action.Paper\n"," elif (p['gesture']=='three') or (p['gesture']=='yeah'):\n"," action = Action.Scissors\n"," elif (p['gesture']=='rock') :\n"," action = Action.Lizard\n"," elif (p['gesture']=='four'):\n"," action = Action.Spock\n"," if action is not None:\n"," computer_action = get_computer_selection()\n"," game_results.append(determine_winner(action, computer_action))\n"," counter+=1\n"," print_game_results(game_results)\n"," old_action=action\n","\n"," if counter\u003e=num_games:\n"," break\n"," except Exception as err:\n"," # Errors will be thrown if the user does not have a webcam or if they do not\n"," # grant the page permission to access it.\n"," print(str(err))\n"," raise err\n","\n"," pipe.pipe.close()"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"background_save":true,"base_uri":"https://localhost:8080/","height":17},"id":"biwLyBjhjwtx"},"outputs":[{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"}],"source":["start_game(num_games=5)"]}],"metadata":{"colab":{"name":"","version":""},"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.1"},"widgets":{"application/vnd.jupyter.widget-state+json":{"044c8c12d53c4f80b02a195ee1b10ded":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Rock","Paper","Scissors","Lizard","Spock"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"Chose:","description_tooltip":null,"disabled":false,"index":0,"layout":"IPY_MODEL_249fd3223b024434870c8581f5221f70","style":"IPY_MODEL_38d57a4f87494825b29f284516a9c312"}},"249fd3223b024434870c8581f5221f70":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"38d57a4f87494825b29f284516a9c312":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"67200cd7f8924627aa18cc81af0a478d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":"1px solid black","bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9181989fa1c943b895c8d8920b57c0d4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bce58963af05485d9e28cc4836e298c7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_044c8c12d53c4f80b02a195ee1b10ded","IPY_MODEL_f698ce0c10b946beb5563253752f3f6b","IPY_MODEL_debad6f6bc9c4066bbb98c12cf703d26"],"layout":"IPY_MODEL_9181989fa1c943b895c8d8920b57c0d4"}},"debad6f6bc9c4066bbb98c12cf703d26":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_67200cd7f8924627aa18cc81af0a478d","msg_id":"","outputs":[{"name":"stdout","output_type":"stream","text":["You chose\n","\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \n","The computer chose\n","\n"," _____ _\n"," / ___| (_)\n"," \\ `--. ___ _ ___ ___ ___ _ __ ___\n"," `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n"," /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n"," \\____/ \\___|_|___/___/\\___/|_| |___/\n"," \n","\n"," _ _ _ ____ ___ ___ _ _\n","| | | | | | | \\/ | / _ \\ | \\ | |\n","| |_| | | | | . . |/ /_\\ \\| \\| |\n","| _ | | | | |\\/| || _ || . ` |\n","| | | | |_| | | | || | | || |\\ |\n","\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n","\n"," __\n"," / _|\n"," | |_ ___ _ __ _ __ _____ __\n"," | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n"," _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n","(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n","\n"," \n"]}]}},"f12b87967424418d8f6fed872834a091":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":""}},"f698ce0c10b946beb5563253752f3f6b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"success","description":"Play!","disabled":false,"icon":"check","layout":"IPY_MODEL_fcf2583dce504a9c960c73d0492264d5","style":"IPY_MODEL_f12b87967424418d8f6fed872834a091","tooltip":""}},"fcf2583dce504a9c960c73d0492264d5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}}}},"nbformat":4,"nbformat_minor":5} \ No newline at end of file diff --git a/support.py b/support.py index 5cc75fe..547c599 100644 --- a/support.py +++ b/support.py @@ -3,6 +3,7 @@ import cv2 import requests import ipywidgets as widgets +import io ###################################### @@ -24,6 +25,7 @@ def download_dataset(): with open('./gesture_train.csv', 'wb') as f: f.write(resp.content) +download_dataset() ######################################## # Define default camera intrinsic @@ -36,6 +38,7 @@ def download_dataset(): 'cy': img_height*0.5, 'width': img_width, } +######################################### class GestureRecognition: import numpy as np @@ -65,7 +68,7 @@ def eval(self, angle): idx = int(results[0][0]) # Index of class label return list(self.gesture)[idx] # Return name of class label - +##################################### class MediaPipeHand: def __init__(self, static_image_mode=True, max_num_hands=1, @@ -270,4 +273,93 @@ def forward(self, img): return param +########################################## + +try: + from google.colab.output import eval_js + colab = True +except: + colab = False + +if colab: + from IPython.display import display, Javascript + from google.colab.output import eval_js + from base64 import b64decode + from PIL import Image as PIL_Image + + def take_photo(quality=0.8): + js = Javascript(''' + async function takePhoto(quality) { + const div = document.createElement('div'); + const capture = document.createElement('button'); + capture.textContent = 'Capture'; + div.appendChild(capture); + + const video = document.createElement('video'); + video.style.display = 'block'; + const stream = await navigator.mediaDevices.getUserMedia({video: true}); + + document.body.appendChild(div); + div.appendChild(video); + video.srcObject = stream; + await video.play(); + + // Resize the output to fit the video element. + google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true); + + // Wait for Capture to be clicked. + await new Promise((resolve) => capture.onclick = resolve); + + const canvas = document.createElement('canvas'); + canvas.width = video.videoWidth; + canvas.height = video.videoHeight; + canvas.getContext('2d').drawImage(video, 0, 0); + stream.getVideoTracks()[0].stop(); + div.remove(); + return canvas.toDataURL('image/jpeg', quality); + } + ''') + display(js) + data = eval_js('takePhoto({})'.format(quality)) + binary = b64decode(data.split(',')[1]) + + + image = PIL_Image.open(io.BytesIO(binary)) + image_np = np.array(image) + return image_np +else: + def take_photo(filename='photo.jpg', quality=0.8): + cam = cv2.VideoCapture(0) + + cv2.namedWindow("test") + + img_counter = 0 + + while True: + ret, frame = cam.read() + # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) + if not ret: + print("failed to grab frame") + break + cv2.imshow("test", frame) + + k = cv2.waitKey(1) + if k%256 == 27 or k%256 == 32 : + # ESC pressed + break + + cam.release() + + cv2.destroyAllWindows() + + # Preprocess image + img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + # Flip image for 3rd person view + img = cv2.flip(img, 1) + + # To improve performance, optionally mark image as not writeable to pass by reference + img.flags.writeable = False + + return img + From 9f4dd1115a9e02923b0447a9313afb1e12a6b935 Mon Sep 17 00:00:00 2001 From: Moreno Mazzocchetti Date: Mon, 13 Nov 2023 19:11:37 +0100 Subject: [PATCH 4/6] Code refinements --- .gitignore | 1 + Live Coding Completo.ipynb | 2041 +++++++++++++++++++++++++++++++++++- 2 files changed, 2041 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index e717817..0e9cc8f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ .ipynb_checkpoints /.idea /.venv +__pycache__ \ No newline at end of file diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index 673428d..817f6ba 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -1 +1,2040 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"b35fe87b"},"source":["# Rock - Paper - Scissors - Lizard - Spock\n","\n","Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano."]},{"cell_type":"markdown","metadata":{"id":"78e5f376"},"source":["## Task 1\n","\n","Nella prossima cella studieremo:\n","\n","* cos'è una variabile in Python\n","* quali sono i tipi di variabile che è possibile avere in Python\n","* come è possible prendere un input da parte dell'utente\n","* come è possibile creare una lista con le possibili scelte di gioco\n","* come è possibile generare la mossa del computer in maniera casuale"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"6cfa68db"},"outputs":[],"source":["intero = 10\n","booleano = True\n","numero_float = 0.13\n","stringa = 'pycon'\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":7,"status":"ok","timestamp":1699709841312,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"DLo0HbU8jwtm","outputId":"8fb84091-34ba-4dbd-94ea-3e2ccad4f316"},"outputs":[{"name":"stdout","output_type":"stream","text":["Ciao Mondo :)\n"]}],"source":["print('Ciao Mondo :)')"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":279,"status":"ok","timestamp":1699709841586,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"0OX9TkPDjwtm","outputId":"236a58da-c29b-46cb-8eab-b2e50a15556d"},"outputs":[{"name":"stdout","output_type":"stream","text":["10\n"]}],"source":["print(intero)"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5,"status":"ok","timestamp":1699709841586,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"W70GvccNjwtn","outputId":"a87c9464-85b8-4086-a9d4-d5cbceea3b2c"},"outputs":[{"name":"stdout","output_type":"stream","text":["pycon 10\n"]}],"source":["print(stringa,intero)"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2795,"status":"ok","timestamp":1699709844379,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"sCQu4LkLjwtn","outputId":"c5b694ec-2b17-4f51-f402-a6eff4790264"},"outputs":[{"name":"stdout","output_type":"stream","text":["digita un numero?5\n"]}],"source":["risultato = input('digita un numero?')"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":8,"status":"ok","timestamp":1699709844379,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"Pslrt8Nwjwto","outputId":"57c4624b-b1e5-463a-c625-6e40ba2d13ce"},"outputs":[{"name":"stdout","output_type":"stream","text":["5\n"]}],"source":["print(risultato)\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":2801,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"hy51y-owjwto","outputId":"a2168225-1f45-49b1-cc33-f2c021a60afa"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (rock, paper, scissors): rock\n"]}],"source":["user_action = input(\"Enter a choice (rock, paper, scissors): \")"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"sO8y1DHqjwto"},"outputs":[],"source":["import random\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"NxgXYbZ-jwtp"},"outputs":[],"source":["\n","possible_actions = [\"rock\", \"paper\", \"scissors\"]\n","computer_action = random.choice(possible_actions)\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":9,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"EKBwgQm1jwtp","outputId":"14137bef-862d-4d35-9cc8-5e7b0fd9b847"},"outputs":[{"name":"stdout","output_type":"stream","text":["\n","You chose rock, computer chose scissors.\n","\n"]}],"source":["print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n"]},{"cell_type":"markdown","metadata":{"id":"f9faebb5"},"source":["## Task 2\n","\n","In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":5,"status":"ok","timestamp":1699709847174,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"90af3eea","outputId":"dd03b6a2-38f4-43e5-9807-ce912ff62e13"},"outputs":[{"name":"stdout","output_type":"stream","text":["Rock smashes scissors! You win!\n"]}],"source":["if user_action == computer_action:\n"," print(f\"Both players selected {user_action}. It's a tie!\")\n","elif user_action == \"rock\":\n"," if computer_action == \"scissors\":\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n","elif user_action == \"paper\":\n"," if computer_action == \"rock\":\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n","elif user_action == \"scissors\":\n"," if computer_action == \"paper\":\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")"]},{"cell_type":"markdown","metadata":{"id":"f9182a9f"},"source":["### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n","\n","In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche:\n","- prendere in input dall'utente una scelta\n","- generare la mossa del computer\n","- confrontare le mosse\n","- mostrare un output\n","\n","A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**."]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4668,"status":"ok","timestamp":1699709851839,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"47580fd9","outputId":"921ac4d0-4b70-40ad-b75a-dd8041c5a911"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (rock, paper, scissors): rock\n","\n","You chose rock, computer chose rock.\n","\n","Both players selected rock. It's a tie!\n","Play again? (y/n): n\n"]}],"source":["while True:\n"," user_action = input(\"Enter a choice (rock, paper, scissors): \")\n"," possible_actions = [\"rock\", \"paper\", \"scissors\"]\n"," computer_action = random.choice(possible_actions)\n"," print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n","\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action}. It's a tie!\")\n"," elif user_action == \"rock\":\n"," if computer_action == \"scissors\":\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n"," elif user_action == \"paper\":\n"," if computer_action == \"rock\":\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n"," elif user_action == \"scissors\":\n"," if computer_action == \"paper\":\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")\n","\n"," play_again = input(\"Play again? (y/n): \")\n"," if play_again.lower() != \"y\":\n"," break"]},{"cell_type":"markdown","metadata":{"id":"dd16cb05"},"source":["## Task 3: Ottimizzazioni nel codice\n","\n","Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**.\n","\n","Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile."]},{"cell_type":"markdown","metadata":{"id":"2dfe73b6"},"source":["### Task 3a: Creiamo un enum\n","\n","In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"0ec721b6"},"outputs":[],"source":["from enum import IntEnum\n","\n","class Action(IntEnum):\n"," Rock = 0\n"," Paper = 1\n"," Scissors = 2"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":10,"status":"ok","timestamp":1699709851839,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"4BTg9ygOjwtq","outputId":"fbfc8ae2-0cfe-42cd-ce09-0426001729cc"},"outputs":[{"name":"stdout","output_type":"stream","text":["Action.Rock == Action.Rock True\n","Action.Rock == Action(0) True\n","Action(0) Action.Rock\n"]}],"source":["print('Action.Rock == Action.Rock',Action.Rock == Action.Rock)\n","print('Action.Rock == Action(0)',Action.Rock == Action(0))\n","print('Action(0)',Action(0))"]},{"cell_type":"markdown","metadata":{"id":"92eea47a"},"source":["### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n","\n","Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n","\n","- Fai giocare l'utente -\u003e `get_user_selection()`\n","- Fai giocare il computer -\u003e `get_computer_selection()`\n","- Decidi chi ha vinto -\u003e `determine_winner(user_selection, computer_selection)`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"08c5263b"},"outputs":[],"source":["def get_user_selection():\n"," user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n"," selection = int(user_input)\n"," action = Action(selection)\n"," return action\n","\n","\n","def get_user_selection():\n"," choices = [f\"{action.name}[{action.value}]\" for action in Action]\n"," choices_str = \", \".join(choices)\n"," selection = int(input(f\"Enter a choice ({choices_str}): \"))\n"," action = Action(selection)\n"," return action"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"hldiDTxqjwtr"},"outputs":[],"source":["def get_computer_selection():\n"," selection = random.randint(0, len(Action) - 1)\n"," action = Action(selection)\n"," return action"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"eMYFUSiojwtr"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action.name}. It's a tie!\")\n"," elif user_action == Action.Rock:\n"," if computer_action == Action.Scissors:\n"," print(\"Rock smashes scissors! You win!\")\n"," else:\n"," print(\"Paper covers rock! You lose.\")\n"," elif user_action == Action.Paper:\n"," if computer_action == Action.Rock:\n"," print(\"Paper covers rock! You win!\")\n"," else:\n"," print(\"Scissors cuts paper! You lose.\")\n"," elif user_action == Action.Scissors:\n"," if computer_action == Action.Paper:\n"," print(\"Scissors cuts paper! You win!\")\n"," else:\n"," print(\"Rock smashes scissors! You lose.\")"]},{"cell_type":"markdown","metadata":{"id":"4ca7428d"},"source":["Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita:\n","\n","- `start_game()`\n"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"8ebfa484"},"outputs":[],"source":["def start_game():\n"," while True:\n"," try:\n"," user_action = get_user_selection()\n"," except ValueError as e:\n"," range_str = f\"[0, {len(Action) - 1}]\"\n"," print(f\"Invalid selection. Enter a value in range {range_str}\")\n"," continue\n","\n"," computer_action = get_computer_selection()\n"," determine_winner(user_action, computer_action)\n","\n"," play_again = input(\"Play again? (y/n): \")\n"," if play_again.lower() != \"y\":\n"," break"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":11137,"status":"ok","timestamp":1699709862968,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"I3BM0Z4Kjwtr","outputId":"a102b536-8581-40b3-9aed-3e9eea5c921d"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2]): 1\n","Paper covers rock! You win!\n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"6955e8bc"},"source":["### Task 3c: Creiamo un dizionario con le mosse vincenti\n","\n","Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n","- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n","- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"96893f8d"},"outputs":[],"source":["victories = {\n"," Action.Rock: [Action.Scissors], # Rock beats scissors\n"," Action.Paper: [Action.Rock], # Paper beats rock\n"," Action.Scissors: [Action.Paper] # Scissors beats paper\n","}"]},{"cell_type":"markdown","metadata":{"id":"c3205d3c"},"source":["### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"dce77a8a"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n"," defeats = victories[user_action]\n"," if user_action == computer_action:\n"," print(f\"Both players selected {user_action.name}. It's a tie!\")\n"," elif computer_action in defeats:\n"," print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n"," else:\n"," print(f\"{computer_action.name} beats {user_action.name}! You lose.\")"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":11858,"status":"ok","timestamp":1699709874816,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"cv6L7ahtjwtr","outputId":"609f516f-00c3-42ae-ba9e-1496fc56cae8"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2]): 2\n","You chose Scissors. The computer chose Rock.\n","Rock beats Scissors! You lose.\n","Play again? (y/n): y\n","Enter a choice (Rock[0], Paper[1], Scissors[2]): 0\n","You chose Rock. The computer chose Paper.\n","Paper beats Rock! You lose.\n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"ee1b1835"},"source":["### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n","\n","È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"60f6e2d5"},"outputs":[],"source":["class Action(IntEnum):\n"," Rock = 0\n"," Paper = 1\n"," Scissors = 2\n"," Lizard = 3\n"," Spock = 4\n","\n","victories = {\n"," Action.Scissors: [Action.Lizard, Action.Paper],\n"," Action.Paper: [Action.Spock, Action.Rock],\n"," Action.Rock: [Action.Lizard, Action.Scissors],\n"," Action.Lizard: [Action.Spock, Action.Paper],\n"," Action.Spock: [Action.Scissors, Action.Rock]\n","}"]},{"cell_type":"markdown","metadata":{"id":"67881ce8"},"source":["### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art\n","\n","Creeremo due nuovi dizionari:\n","- in `ascii_action` metteremo le ascii art delle mosse\n","- in `ascii_results` metteremo le ascii art dei possibili risultati"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"4422813d"},"outputs":[],"source":["ascii_action = {\n"," Action.Scissors: r\"\"\"\n"," _____ _\n"," / ___| (_)\n"," \\ `--. ___ _ ___ ___ ___ _ __ ___\n"," `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n"," /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n"," \\____/ \\___|_|___/___/\\___/|_| |___/\n"," \"\"\",\n"," Action.Paper: r\"\"\"\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \"\"\",\n"," Action.Rock: r\"\"\"\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \"\"\",\n"," Action.Lizard: r\"\"\"\n"," _ _ _\n"," | | (_) | |\n"," | | _ __________ _ _ __ __| |\n"," | | | |_ /_ / _` | '__/ _` |\n"," | |___| |/ / / / (_| | | | (_| |\n"," \\_____/_/___/___\\__,_|_| \\__,_|\n"," \"\"\",\n"," Action.Spock: r\"\"\"\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \"\"\"\n","}\n","\n","COMPUTER_WIN=-1\n","HUMAN_WIN=1\n","DROW=0\n","ascii_result = {\n"," COMPUTER_WIN: r\"\"\"\n"," _____ ________ _________ _ _ _____ ___________\n","/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n","| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n","| | | | | | |\\/| || __/| | | | | | | __|| /\n","| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n"," \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n"," \"\"\",\n"," HUMAN_WIN: r\"\"\"\n"," _ _ _ ____ ___ ___ _ _\n","| | | | | | | \\/ | / _ \\ | \\ | |\n","| |_| | | | | . . |/ /_\\ \\| \\| |\n","| _ | | | | |\\/| || _ || . ` |\n","| | | | |_| | | | || | | || |\\ |\n","\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n","\n"," __\n"," / _|\n"," | |_ ___ _ __ _ __ _____ __\n"," | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n"," _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n","(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n","\n"," \"\"\",\n"," DROW: r\"\"\"\n"," _ _ _\n"," | | (_) | |\n"," __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n"," / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n","| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n"," \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n"," __/ |\n"," |___/\n"," ___ _ _ __\n"," / / | | | (_) \\ \\\\\n","| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n","| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n","| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n","| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n"," \\_\\ __/ /_/\n"," |___/ \"\"\"\n","}"]},{"cell_type":"markdown","metadata":{"id":"75f2c6d5"},"source":["Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art:\n","- `display_action`\n","- `display_results`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"c96921e2"},"outputs":[],"source":["def display_action(action):\n"," print(ascii_action[action])\n","\n","def display_result(result):\n"," print(ascii_result[result])"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":15,"status":"ok","timestamp":1699709874816,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"18tMjb3sjwts","outputId":"24de5258-e6d3-4a97-8e09-17f6659485f3"},"outputs":[{"name":"stdout","output_type":"stream","text":["\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \n"]}],"source":["display_action(Action.Spock)"]},{"cell_type":"markdown","metadata":{"id":"c1b643e3"},"source":["Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"252c6e45"},"outputs":[],"source":["def determine_winner(user_action, computer_action):\n"," print(f\"You chose\")\n"," display_action(user_action)\n"," print(f\"The computer chose\")\n"," display_action(computer_action)\n"," defeats = victories[user_action]\n"," if user_action == computer_action:\n"," display_result(DROW)\n"," return DROW\n"," elif computer_action in defeats:\n"," display_result(HUMAN_WIN)\n"," return HUMAN_WIN\n"," else:\n"," display_result(COMPUTER_WIN)\n"," return COMPUTER_WIN"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4400,"status":"ok","timestamp":1699709879202,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"q_y93jZFjwtv","outputId":"9a6ba887-29e9-4baa-840d-d98ea434c6d0"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 0\n","You chose\n","\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \n","The computer chose\n","\n"," _____ _\n"," / ___| | |\n"," \\ `--. _ __ ___ ___| | __\n"," `--. \\ '_ \\ / _ \\ / __| |/ /\n"," /\\__/ / |_) | (_) | (__| \u003c\n"," \\____/| .__/ \\___/ \\___|_|\\_\\\\\n"," | |\n"," |_|\n"," \n","\n"," _____ ________ _________ _ _ _____ ___________\n","/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n","| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n","| | | | | | |\\/| || __/| | | | | | | __|| /\n","| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n"," \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n"," \n","Play again? (y/n): n\n"]}],"source":["start_game()"]},{"cell_type":"markdown","metadata":{"id":"5e478a36"},"source":["### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n","\n","Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla!"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"ec5766f6"},"outputs":[],"source":["def print_game_results(game_results):\n"," num_tied = game_results.count(DROW)/len(game_results)*100\n"," num_player_wins = game_results.count(HUMAN_WIN)/len(game_results)*100\n"," num_computer_wins =game_results.count(COMPUTER_WIN)/len(game_results)*100\n","\n"," print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n","\n","def start_game(num_games=1):\n"," game_results=[]\n"," counter=0\n"," while True:\n"," try:\n"," user_action = get_user_selection()\n"," except ValueError as e:\n"," range_str = f\"[0, {len(Action) - 1}]\"\n"," print(f\"Invalid selection. Enter a value in range {range_str}\")\n"," continue\n","\n"," computer_action = get_computer_selection()\n"," game_results.append(determine_winner(user_action, computer_action))\n"," counter+=1\n","\n"," if counter\u003e=num_games:\n"," break\n"," print_game_results(game_results)\n"," return game_results\n","\n"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":4689,"status":"ok","timestamp":1699709883885,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"lcLQZxy3jwtw","outputId":"15a53e1a-4624-4a0a-e604-2b687f656fef"},"outputs":[{"name":"stdout","output_type":"stream","text":["Enter a choice (Rock[0], Paper[1], Scissors[2], Lizard[3], Spock[4]): 1\n","You chose\n","\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \n","The computer chose\n","\n"," ______\n"," | ___ \\\n"," | |_/ /_ _ _ __ ___ _ __\n"," | __/ _` | '_ \\ / _ \\ '__|\n"," | | | (_| | |_) | __/ |\n"," \\_| \\__,_| .__/ \\___|_|\n"," | |\n"," |_|\n"," \n","\n"," _ _ _\n"," | | (_) | |\n"," __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n"," / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n","| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n"," \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n"," __/ |\n"," |___/\n"," ___ _ _ __\n"," / / | | | (_) \\ \\\\\n","| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n","| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n","| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n","| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n"," \\_\\ __/ /_/\n"," |___/ \n","There were 100.0 % tied games \n","the player won 0.0 % of games\n","the computer won 0.0 % of games\n","in a total of 1 games\n"]}],"source":["game_results=start_game(1)"]},{"cell_type":"markdown","metadata":{"id":"aae3e00d"},"source":["### Utilizziamo un'interfaccia grafica!\n","\n","Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n","\n","Concetti connessi:\n","- list comprehension\n","- `widgets.Dropdown`"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":15258,"status":"ok","timestamp":1699709899132,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"yE1oRjMn5G0f","outputId":"fe2da3a7-4310-44a5-c77d-560c2e9739e5"},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (1.23.5)\n","Requirement already satisfied: opencv-python in /usr/local/lib/python3.10/dist-packages (4.8.0.76)\n","Requirement already satisfied: numpy\u003e=1.21.2 in /usr/local/lib/python3.10/dist-packages (from opencv-python) (1.23.5)\n","Requirement already satisfied: mediapipe in /usr/local/lib/python3.10/dist-packages (0.10.8)\n","Requirement already satisfied: absl-py in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.4.0)\n","Requirement already satisfied: attrs\u003e=19.1.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.1.0)\n","Requirement already satisfied: flatbuffers\u003e=2.0 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (23.5.26)\n","Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.7.1)\n","Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from mediapipe) (1.23.5)\n","Requirement already satisfied: opencv-contrib-python in /usr/local/lib/python3.10/dist-packages (from mediapipe) (4.8.0.76)\n","Requirement already satisfied: protobuf\u003c4,\u003e=3.11 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (3.20.3)\n","Requirement already satisfied: sounddevice\u003e=0.4.4 in /usr/local/lib/python3.10/dist-packages (from mediapipe) (0.4.6)\n","Requirement already satisfied: CFFI\u003e=1.0 in /usr/local/lib/python3.10/dist-packages (from sounddevice\u003e=0.4.4-\u003emediapipe) (1.16.0)\n","Requirement already satisfied: contourpy\u003e=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (1.2.0)\n","Requirement already satisfied: cycler\u003e=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (0.12.1)\n","Requirement already satisfied: fonttools\u003e=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (4.44.0)\n","Requirement already satisfied: kiwisolver\u003e=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (1.4.5)\n","Requirement already satisfied: packaging\u003e=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (23.2)\n","Requirement already satisfied: pillow\u003e=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (9.4.0)\n","Requirement already satisfied: pyparsing\u003e=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (3.1.1)\n","Requirement already satisfied: python-dateutil\u003e=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib-\u003emediapipe) (2.8.2)\n","Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from CFFI\u003e=1.0-\u003esounddevice\u003e=0.4.4-\u003emediapipe) (2.21)\n","Requirement already satisfied: six\u003e=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil\u003e=2.7-\u003ematplotlib-\u003emediapipe) (1.16.0)\n","Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (2.31.0)\n","Requirement already satisfied: charset-normalizer\u003c4,\u003e=2 in /usr/local/lib/python3.10/dist-packages (from requests) (3.3.2)\n","Requirement already satisfied: idna\u003c4,\u003e=2.5 in /usr/local/lib/python3.10/dist-packages (from requests) (3.4)\n","Requirement already satisfied: urllib3\u003c3,\u003e=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests) (2.0.7)\n","Requirement already satisfied: certifi\u003e=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests) (2023.7.22)\n"]}],"source":["!pip install numpy\n","!pip install opencv-python\n","!pip install mediapipe\n","!pip install requests"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":951,"status":"ok","timestamp":1699709900079,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"uddtBN5Hj0mh","outputId":"5aaf0849-e0d3-48be-fa9e-35bf7473506f"},"outputs":[{"name":"stdout","output_type":"stream","text":["Downloading...\n","From: https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\n","To: /content/support.py\n","\r 0% 0.00/13.2k [00:00\u003c?, ?B/s]\r100% 13.2k/13.2k [00:00\u003c00:00, 51.9MB/s]\n"]}],"source":["!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"Pg1r0Rq14b9f"},"outputs":[],"source":["from support import *"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"base_uri":"https://localhost:8080/","height":847},"executionInfo":{"elapsed":7,"status":"ok","timestamp":1699709900079,"user":{"displayName":"Moreno Mazzocchetti","userId":"18050587376363424786"},"user_tz":-60},"id":"a6b41097","outputId":"aadb9b9b-abec-4391-fe5b-93f908d710c6"},"outputs":[{"data":{"application/vnd.jupyter.widget-view+json":{"model_id":"bce58963af05485d9e28cc4836e298c7","version_major":2,"version_minor":0},"text/plain":["VBox(children=(Dropdown(description='Chose:', options=(('Rock', 0), ('Paper', 1), ('Scissors', 2), ('Lizard', …"]},"metadata":{},"output_type":"display_data"}],"source":["options=[(action.name,action.value) for action in Action]\n","output, button, box, menu = create_dropdown(options)\n","\n","def on_button_clicked(b):\n"," output.clear_output()\n"," with output:\n"," computer_action = get_computer_selection()\n"," determine_winner(Action(menu.value), computer_action)\n","\n","button.on_click(on_button_clicked)\n","\n","display(box)"]},{"cell_type":"markdown","metadata":{"id":"d95e966e"},"source":["## Time to use ML!\n","\n","Nelle celle successive andremo ad utilizzare il Machine Learning per addestrare un modello predittivo in grado di dedurre la mossa dell'utente a partire dall'inquadratura della mano ottenuta con la webcam.\n","\n","Installiamo le librerie necessarie e importiamole:"]},{"cell_type":"code","execution_count":null,"metadata":{"id":"3CCoidG5jwtx"},"outputs":[],"source":["def start_game(num_games=1):\n"," game_results=[]\n"," counter=0\n"," # Load mediapipe hand class\n"," pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n"," # Load gesture recognition class\n"," gest = GestureRecognition()\n"," while True:\n"," try:\n"," img = take_photo()\n"," param = pipe.forward(img)\n"," # Evaluate gesture for all hands\n","\n"," for p in param:\n"," if p['class'] is not None:\n"," p['gesture'] = gest.eval(p['angle'])\n"," action = None\n"," if p['gesture']=='fist':\n"," action = Action.Rock\n"," elif p['gesture']=='five':\n"," action = Action.Paper\n"," elif (p['gesture']=='three') or (p['gesture']=='yeah'):\n"," action = Action.Scissors\n"," elif (p['gesture']=='rock') :\n"," action = Action.Lizard\n"," elif (p['gesture']=='four'):\n"," action = Action.Spock\n"," if action is not None:\n"," computer_action = get_computer_selection()\n"," game_results.append(determine_winner(action, computer_action))\n"," counter+=1\n"," print_game_results(game_results)\n"," old_action=action\n","\n"," if counter\u003e=num_games:\n"," break\n"," except Exception as err:\n"," # Errors will be thrown if the user does not have a webcam or if they do not\n"," # grant the page permission to access it.\n"," print(str(err))\n"," raise err\n","\n"," pipe.pipe.close()"]},{"cell_type":"code","execution_count":null,"metadata":{"colab":{"background_save":true,"base_uri":"https://localhost:8080/","height":17},"id":"biwLyBjhjwtx"},"outputs":[{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"},{"data":{"application/javascript":["\n"," async function takePhoto(quality) {\n"," const div = document.createElement('div');\n"," const capture = document.createElement('button');\n"," capture.textContent = 'Capture';\n"," div.appendChild(capture);\n","\n"," const video = document.createElement('video');\n"," video.style.display = 'block';\n"," const stream = await navigator.mediaDevices.getUserMedia({video: true});\n","\n"," document.body.appendChild(div);\n"," div.appendChild(video);\n"," video.srcObject = stream;\n"," await video.play();\n","\n"," // Resize the output to fit the video element.\n"," google.colab.output.setIframeHeight(document.documentElement.scrollHeight, true);\n","\n"," // Wait for Capture to be clicked.\n"," await new Promise((resolve) =\u003e capture.onclick = resolve);\n","\n"," const canvas = document.createElement('canvas');\n"," canvas.width = video.videoWidth;\n"," canvas.height = video.videoHeight;\n"," canvas.getContext('2d').drawImage(video, 0, 0);\n"," stream.getVideoTracks()[0].stop();\n"," div.remove();\n"," return canvas.toDataURL('image/jpeg', quality);\n"," }\n"," "],"text/plain":["\u003cIPython.core.display.Javascript object\u003e"]},"metadata":{},"output_type":"display_data"}],"source":["start_game(num_games=5)"]}],"metadata":{"colab":{"name":"","version":""},"kernelspec":{"display_name":"Python 3 (ipykernel)","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.9.1"},"widgets":{"application/vnd.jupyter.widget-state+json":{"044c8c12d53c4f80b02a195ee1b10ded":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DropdownModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DropdownModel","_options_labels":["Rock","Paper","Scissors","Lizard","Spock"],"_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"DropdownView","description":"Chose:","description_tooltip":null,"disabled":false,"index":0,"layout":"IPY_MODEL_249fd3223b024434870c8581f5221f70","style":"IPY_MODEL_38d57a4f87494825b29f284516a9c312"}},"249fd3223b024434870c8581f5221f70":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"38d57a4f87494825b29f284516a9c312":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"67200cd7f8924627aa18cc81af0a478d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":"1px solid black","bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9181989fa1c943b895c8d8920b57c0d4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"bce58963af05485d9e28cc4836e298c7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"VBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"VBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"VBoxView","box_style":"","children":["IPY_MODEL_044c8c12d53c4f80b02a195ee1b10ded","IPY_MODEL_f698ce0c10b946beb5563253752f3f6b","IPY_MODEL_debad6f6bc9c4066bbb98c12cf703d26"],"layout":"IPY_MODEL_9181989fa1c943b895c8d8920b57c0d4"}},"debad6f6bc9c4066bbb98c12cf703d26":{"model_module":"@jupyter-widgets/output","model_module_version":"1.0.0","model_name":"OutputModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/output","_model_module_version":"1.0.0","_model_name":"OutputModel","_view_count":null,"_view_module":"@jupyter-widgets/output","_view_module_version":"1.0.0","_view_name":"OutputView","layout":"IPY_MODEL_67200cd7f8924627aa18cc81af0a478d","msg_id":"","outputs":[{"name":"stdout","output_type":"stream","text":["You chose\n","\n"," ______ _\n"," | ___ \\ | |\n"," | |_/ /___ ___| | __\n"," | // _ \\ / __| |/ /\n"," | |\\ \\ (_) | (__| \u003c\n"," \\_| \\_\\___/ \\___|_|\\_\\\n","\n"," \n","The computer chose\n","\n"," _____ _\n"," / ___| (_)\n"," \\ `--. ___ _ ___ ___ ___ _ __ ___\n"," `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n"," /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n"," \\____/ \\___|_|___/___/\\___/|_| |___/\n"," \n","\n"," _ _ _ ____ ___ ___ _ _\n","| | | | | | | \\/ | / _ \\ | \\ | |\n","| |_| | | | | . . |/ /_\\ \\| \\| |\n","| _ | | | | |\\/| || _ || . ` |\n","| | | | |_| | | | || | | || |\\ |\n","\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n","\n","\n"," _ _ _____ _ _ _____ _ _ _\n","| | | |_ _| \\ | |/ ___| | | | |\n","| | | | | | | \\| |\\ `--. | | | |\n","| |/\\| | | | | . ` | `--. \\ | | | |\n","\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n"," \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n","\n","\n"," __\n"," / _|\n"," | |_ ___ _ __ _ __ _____ __\n"," | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n"," _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n","(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n","\n"," \n"]}]}},"f12b87967424418d8f6fed872834a091":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","button_color":null,"font_weight":""}},"f698ce0c10b946beb5563253752f3f6b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ButtonModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ButtonModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ButtonView","button_style":"success","description":"Play!","disabled":false,"icon":"check","layout":"IPY_MODEL_fcf2583dce504a9c960c73d0492264d5","style":"IPY_MODEL_f12b87967424418d8f6fed872834a091","tooltip":""}},"fcf2583dce504a9c960c73d0492264d5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}}}}},"nbformat":4,"nbformat_minor":5} \ No newline at end of file +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "b35fe87b" + }, + "source": [ + "# Rock - Paper - Scissors - Lizard - Spock\n", + "\n", + "Benvenuto al Beginners'Day del [Pycon 23](https://pycon.it/)! In questo workshop imparerai le basi della programmazione con il linguaggio Python sviluppando da zero svariate versioni del classico gioco Sasso-Carta-Forbice. Dalla versione classica alla version **top** in cui tramite Machine Learning il nostro programma riconoscerà da webcam la nostra mossa, tutto è a portata di mano." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "78e5f376" + }, + "source": [ + "## Task 1\n", + "\n", + "Nella prossima cella studieremo:\n", + "\n", + "* cos'è una variabile in Python\n", + "* quali sono i tipi di variabile che è possibile avere in Python\n", + "* come è possible prendere un input da parte dell'utente\n", + "* come è possibile creare una lista con le possibili scelte di gioco\n", + "* come è possibile generare la mossa del computer in maniera casuale" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "id": "6cfa68db", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:38.993136852Z", + "start_time": "2023-11-13T18:04:38.836371914Z" + } + }, + "outputs": [], + "source": [ + "integer_number = 10\n", + "float_number = 0.13\n", + "boolean = True\n", + "string = 'pycon'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 7, + "status": "ok", + "timestamp": 1699709841312, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "DLo0HbU8jwtm", + "outputId": "8fb84091-34ba-4dbd-94ea-3e2ccad4f316", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:39.124866047Z", + "start_time": "2023-11-13T18:04:38.851382834Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ciao Mondo :)\n" + ] + } + ], + "source": [ + "print('Ciao Mondo :)')" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 279, + "status": "ok", + "timestamp": 1699709841586, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "0OX9TkPDjwtm", + "outputId": "236a58da-c29b-46cb-8eab-b2e50a15556d", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:39.125436876Z", + "start_time": "2023-11-13T18:04:38.852521067Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10\n" + ] + } + ], + "source": [ + "print(integer_number)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 5, + "status": "ok", + "timestamp": 1699709841586, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "W70GvccNjwtn", + "outputId": "a87c9464-85b8-4086-a9d4-d5cbceea3b2c", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:39.127965261Z", + "start_time": "2023-11-13T18:04:38.864699852Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pycon 10\n" + ] + } + ], + "source": [ + "print(string, integer_number)" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 2795, + "status": "ok", + "timestamp": 1699709844379, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "sCQu4LkLjwtn", + "outputId": "c5b694ec-2b17-4f51-f402-a6eff4790264", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:40.907090654Z", + "start_time": "2023-11-13T18:04:38.865117857Z" + } + }, + "outputs": [], + "source": [ + "risultato = input('digita un numero?')" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 8, + "status": "ok", + "timestamp": 1699709844379, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "Pslrt8Nwjwto", + "outputId": "57c4624b-b1e5-463a-c625-6e40ba2d13ce", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:40.926291350Z", + "start_time": "2023-11-13T18:04:40.747132030Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5\n" + ] + } + ], + "source": [ + "print(risultato)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 2801, + "status": "ok", + "timestamp": 1699709847174, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "hy51y-owjwto", + "outputId": "a2168225-1f45-49b1-cc33-f2c021a60afa", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:43.165947154Z", + "start_time": "2023-11-13T18:04:40.792637905Z" + } + }, + "outputs": [], + "source": [ + "user_action = input(\"Enter a choice (rock, paper, scissors): \")" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "id": "sO8y1DHqjwto", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:43.166433172Z", + "start_time": "2023-11-13T18:04:43.113625232Z" + } + }, + "outputs": [], + "source": [ + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "NxgXYbZ-jwtp", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:43.166621465Z", + "start_time": "2023-11-13T18:04:43.118715516Z" + } + }, + "outputs": [], + "source": [ + "possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", + "computer_action = random.choice(possible_actions)" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 9, + "status": "ok", + "timestamp": 1699709847174, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "EKBwgQm1jwtp", + "outputId": "14137bef-862d-4d35-9cc8-5e7b0fd9b847", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:43.167020808Z", + "start_time": "2023-11-13T18:04:43.128006488Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "You chose rock, computer chose paper.\n", + "\n" + ] + } + ], + "source": [ + "print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f9faebb5" + }, + "source": [ + "## Task 2\n", + "\n", + "In questa cella confronteremo le mosse del computer e del giocatore per capire **chi ha vinto** e mostrare un messaggio adeguato" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 5, + "status": "ok", + "timestamp": 1699709847174, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "90af3eea", + "outputId": "dd03b6a2-38f4-43e5-9807-ce912ff62e13", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:43.215993559Z", + "start_time": "2023-11-13T18:04:43.172419296Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Paper covers rock! You lose.\n" + ] + } + ], + "source": [ + "if user_action == computer_action:\n", + " print(f\"Both players selected {user_action}. It's a tie!\")\n", + "elif user_action == \"rock\":\n", + " if computer_action == \"scissors\":\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + "elif user_action == \"paper\":\n", + " if computer_action == \"rock\":\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + "elif user_action == \"scissors\":\n", + " if computer_action == \"paper\":\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "f9182a9f" + }, + "source": [ + "### Task 2a - Ripetiamo le manche di gioco per fare una partita vera e propria\n", + "\n", + "In questa cella useremo un **loop** Python (in particolare un ciclo `while`) per **giocare un numero indefinito di manche**. In particolare andremo a ripetere all'interno del ciclo `while` tutto quello che abbiamo fatto finora per la singola manche:\n", + "- prendere in input dall'utente una scelta\n", + "- generare la mossa del computer\n", + "- confrontare le mosse\n", + "- mostrare un output\n", + "\n", + "A queste operazioni ne aggiungeremo una: **chiediamo all'utente se vuole giocare ancora e, in caso negativo, usciamo dal loop di gioco**." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 4668, + "status": "ok", + "timestamp": 1699709851839, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "47580fd9", + "outputId": "921ac4d0-4b70-40ad-b75a-dd8041c5a911", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.636166168Z", + "start_time": "2023-11-13T18:04:43.173013837Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "You chose rock, computer chose rock.\n", + "\n", + "Both players selected rock. It's a tie!\n" + ] + } + ], + "source": [ + "while True:\n", + " user_action = input(\"Enter a choice (rock, paper, scissors): \")\n", + " possible_actions = [\"rock\", \"paper\", \"scissors\"]\n", + " computer_action = random.choice(possible_actions)\n", + " print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")\n", + "\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action}. It's a tie!\")\n", + " elif user_action == \"rock\":\n", + " if computer_action == \"scissors\":\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + " elif user_action == \"paper\":\n", + " if computer_action == \"rock\":\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + " elif user_action == \"scissors\":\n", + " if computer_action == \"paper\":\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")\n", + "\n", + " play_again = input(\"Play again? (y/n): \")\n", + " if play_again.lower() != \"y\":\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dd16cb05" + }, + "source": [ + "## Task 3: Ottimizzazioni nel codice\n", + "\n", + "Ora che abbiamo una versione di base del gioco in cui possiamo giocare contro il computer e anche aumentare la durata di una partita, cerchiamo di essere un po'più **pro**.\n", + "\n", + "Andremo nelle prossime celle ad implementare una serie di ottimizzazioni che serviranno a rendere il nostro codice più manutenibile e leggibile." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "2dfe73b6" + }, + "source": [ + "### Task 3a: Creiamo un enum\n", + "\n", + "In questa cella andiamo a generalizzare il concetto di \"azione\" creando una classe che **eredita** i comportamenti di `IntEnum` di Python" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "id": "0ec721b6", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.649817557Z", + "start_time": "2023-11-13T18:04:46.560784549Z" + } + }, + "outputs": [], + "source": [ + "from enum import IntEnum\n", + "\n", + "class Action(IntEnum):\n", + " Rock = 0\n", + " Paper = 1\n", + " Scissors = 2" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 10, + "status": "ok", + "timestamp": 1699709851839, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "4BTg9ygOjwtq", + "outputId": "fbfc8ae2-0cfe-42cd-ce09-0426001729cc", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.651489119Z", + "start_time": "2023-11-13T18:04:46.605325091Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Action.Rock == Action.Rock True\n", + "Action.Rock == Action(0) True\n", + "Action(0) 0\n" + ] + } + ], + "source": [ + "print('Action.Rock == Action.Rock', Action.Rock == Action.Rock)\n", + "print('Action.Rock == Action(0)', Action.Rock == Action(0))\n", + "print('Action(0)', Action(0))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "92eea47a" + }, + "source": [ + "### Task 3b: Usiamo delle funzioni per ottimizzare il codice\n", + "\n", + "Tramite l'utilizzo di funzioni dividiamo il nostro programma principale in \"blocchi\" di codice che potranno essere richiamati in qualsiasi momento ne abbiamo bisogno. In particolare il nostro gioco si può suddividere in 3 fasi:\n", + "\n", + "- Fai giocare l'utente -> `get_user_selection()`\n", + "- Fai giocare il computer -> `get_computer_selection()`\n", + "- Decidi chi ha vinto -> `determine_winner(user_selection, computer_selection)`" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "id": "08c5263b", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.651716115Z", + "start_time": "2023-11-13T18:04:46.605757408Z" + } + }, + "outputs": [], + "source": [ + "def get_user_selection():\n", + " user_input = input(\"Enter a choice (rock[0], paper[1], scissors[2]): \")\n", + " selection = int(user_input)\n", + " action = Action(selection)\n", + " return action\n", + "\n", + "\n", + "def get_user_selection():\n", + " choices = [f\"{action.name}[{action.value}]\" for action in Action]\n", + " choices_str = \", \".join(choices)\n", + " selection = int(input(f\"Enter a choice ({choices_str}): \"))\n", + " action = Action(selection)\n", + " return action" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "hldiDTxqjwtr", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.651876922Z", + "start_time": "2023-11-13T18:04:46.606029436Z" + } + }, + "outputs": [], + "source": [ + "def get_computer_selection():\n", + " selection = random.randint(0, len(Action) - 1)\n", + " action = Action(selection)\n", + " return action" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "eMYFUSiojwtr", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.652029994Z", + "start_time": "2023-11-13T18:04:46.606307039Z" + } + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", + " elif user_action == Action.Rock:\n", + " if computer_action == Action.Scissors:\n", + " print(\"Rock smashes scissors! You win!\")\n", + " else:\n", + " print(\"Paper covers rock! You lose.\")\n", + " elif user_action == Action.Paper:\n", + " if computer_action == Action.Rock:\n", + " print(\"Paper covers rock! You win!\")\n", + " else:\n", + " print(\"Scissors cuts paper! You lose.\")\n", + " elif user_action == Action.Scissors:\n", + " if computer_action == Action.Paper:\n", + " print(\"Scissors cuts paper! You win!\")\n", + " else:\n", + " print(\"Rock smashes scissors! You lose.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "4ca7428d" + }, + "source": [ + "Una volta create queste funzioni possiamo crearne un'unica che racchiuda tutta la logica di gioco che possiamo invocare (o chiamare) ogni volta che vogliamo iniziare una nuova partita:\n", + "\n", + "- `start_game()`\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "id": "8ebfa484", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:46.652231182Z", + "start_time": "2023-11-13T18:04:46.606599033Z" + } + }, + "outputs": [], + "source": [ + "def start_game():\n", + " while True:\n", + " try:\n", + " user_action = get_user_selection()\n", + " except ValueError:\n", + " range_str = f\"[0, {len(Action) - 1}]\"\n", + " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", + " continue\n", + "\n", + " computer_action = get_computer_selection()\n", + " determine_winner(user_action, computer_action)\n", + "\n", + " play_again = input(\"Play again? (y/n): \")\n", + " if play_again.lower() != \"y\":\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 11137, + "status": "ok", + "timestamp": 1699709862968, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "I3BM0Z4Kjwtr", + "outputId": "a102b536-8581-40b3-9aed-3e9eea5c921d", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:52.606578937Z", + "start_time": "2023-11-13T18:04:46.606959467Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Invalid selection. Enter a value in range [0, 2]\n", + "Paper covers rock! You lose.\n" + ] + } + ], + "source": [ + "start_game()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6955e8bc" + }, + "source": [ + "### Task 3c: Creiamo un dizionario con le mosse vincenti\n", + "\n", + "Creiamo un dizionario in cui avremo una coppia chiave/valore per ogni possibile mossa. In particolare:\n", + "- la **chiave** sarà l'azione specificata nella nostra classe `Action`\n", + "- il **valore** sarà **una lista** contenente le azioni della classe `Action` che *perdono* contro la mossa specificata come chiave" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "96893f8d", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:52.607074048Z", + "start_time": "2023-11-13T18:04:52.518501129Z" + } + }, + "outputs": [], + "source": [ + "victories = {\n", + " Action.Rock: [Action.Scissors], # Rock beats scissors\n", + " Action.Paper: [Action.Rock], # Paper beats rock\n", + " Action.Scissors: [Action.Paper] # Scissors beats paper\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "c3205d3c" + }, + "source": [ + "### Task 3d: Usiamo il dizionario e l'operatore `in` per semplificare i controlli" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "id": "dce77a8a", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:52.607499997Z", + "start_time": "2023-11-13T18:04:52.561389938Z" + } + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " print(f\"You chose {user_action.name}. The computer chose {computer_action.name}.\")\n", + " defeats = victories[user_action]\n", + " if user_action == computer_action:\n", + " print(f\"Both players selected {user_action.name}. It's a tie!\")\n", + " elif computer_action in defeats:\n", + " print(f\"{user_action.name} beats {computer_action.name}! You win!\")\n", + " else:\n", + " print(f\"{computer_action.name} beats {user_action.name}! You lose.\")" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 11858, + "status": "ok", + "timestamp": 1699709874816, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "cv6L7ahtjwtr", + "outputId": "609f516f-00c3-42ae-ba9e-1496fc56cae8", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.398493928Z", + "start_time": "2023-11-13T18:04:52.561931229Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Invalid selection. Enter a value in range [0, 2]\n", + "Invalid selection. Enter a value in range [0, 2]\n", + "Invalid selection. Enter a value in range [0, 2]\n", + "Invalid selection. Enter a value in range [0, 2]\n", + "You chose Rock. The computer chose Scissors.\n", + "Rock beats Scissors! You win!\n" + ] + } + ], + "source": [ + "start_game()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "ee1b1835" + }, + "source": [ + "### Task 3e: Aggiungiamo le altre mosse: `lizard` e `spock`\n", + "\n", + "È importante notare come grazie alle ottimizzazioni già fatte **l'aggiunta di nuove mosse ci viene *quasi* gratis!**" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "id": "60f6e2d5", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.398911279Z", + "start_time": "2023-11-13T18:04:58.355044569Z" + } + }, + "outputs": [], + "source": [ + "class Action(IntEnum):\n", + " Rock = 0\n", + " Paper = 1\n", + " Scissors = 2\n", + " Lizard = 3\n", + " Spock = 4\n", + "\n", + "victories = {\n", + " Action.Scissors: [Action.Lizard, Action.Paper],\n", + " Action.Paper: [Action.Spock, Action.Rock],\n", + " Action.Rock: [Action.Lizard, Action.Scissors],\n", + " Action.Lizard: [Action.Spock, Action.Paper],\n", + " Action.Spock: [Action.Scissors, Action.Rock]\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "67881ce8" + }, + "source": [ + "### Task 3f: Rendiamo più *catchy* il gioco tramite ASCII art\n", + "\n", + "Creeremo due nuovi dizionari:\n", + "- in `ascii_action` metteremo le ascii art delle mosse\n", + "- in `ascii_results` metteremo le ascii art dei possibili risultati" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "id": "4422813d", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.399244580Z", + "start_time": "2023-11-13T18:04:58.363796483Z" + } + }, + "outputs": [], + "source": [ + "ascii_action = {\n", + " Action.Scissors: r\"\"\"\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \"\"\",\n", + " Action.Paper: r\"\"\"\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \"\"\",\n", + " Action.Rock: r\"\"\"\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \"\"\",\n", + " Action.Lizard: r\"\"\"\n", + " _ _ _\n", + " | | (_) | |\n", + " | | _ __________ _ _ __ __| |\n", + " | | | |_ /_ / _` | '__/ _` |\n", + " | |___| |/ / / / (_| | | | (_| |\n", + " \\_____/_/___/___\\__,_|_| \\__,_|\n", + " \"\"\",\n", + " Action.Spock: r\"\"\"\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \"\"\"\n", + "}\n", + "\n", + "COMPUTER_WIN = -1\n", + "HUMAN_WIN = 1\n", + "DRAW = 0\n", + "ascii_result = {\n", + " COMPUTER_WIN: r\"\"\"\n", + " _____ ________ _________ _ _ _____ ___________\n", + "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", + "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", + "| | | | | | |\\/| || __/| | | | | | | __|| /\n", + "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", + " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + " \"\"\",\n", + " HUMAN_WIN: r\"\"\"\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \"\"\",\n", + " DRAW: r\"\"\"\n", + " _ _ _\n", + " | | (_) | |\n", + " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", + " / _` | | __| |/ _ \\/ _` | / _` |/ _` | '_ ` _ \\ / _ \\\\\n", + "| (_| | | |_| | __/ (_| | | (_| | (_| | | | | | | __/\n", + " \\__,_| \\__|_|\\___|\\__,_| \\__, |\\__,_|_| |_| |_|\\___|\n", + " __/ |\n", + " |___/\n", + " ___ _ _ __\n", + " / / | | | (_) \\ \\\\\n", + "| || |__ _____ __ | |__ ___ _ __ _ _ __ __ _ | |\n", + "| || '_ \\ / _ \\ \\ /\\ / / | '_ \\ / _ \\| '__| | '_ \\ / _` || |\n", + "| || | | | (_) \\ V V / | |_) | (_) | | | | | | | (_| || |\n", + "| ||_| |_|\\___/ \\_/\\_/ |_.__/ \\___/|_| |_|_| |_|\\__, || |\n", + " \\_\\ __/ /_/\n", + " |___/ \"\"\"\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "75f2c6d5" + }, + "source": [ + "Dopodichè creeremo due funzioni per visualizzare agevolmente azioni e risultati in ASCII art:\n", + "- `display_action`\n", + "- `display_results`" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "id": "c96921e2", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.399452317Z", + "start_time": "2023-11-13T18:04:58.368943717Z" + } + }, + "outputs": [], + "source": [ + "def display_action(action):\n", + " print(ascii_action[action])\n", + "\n", + "def display_result(result):\n", + " print(ascii_result[result])" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 15, + "status": "ok", + "timestamp": 1699709874816, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "18tMjb3sjwts", + "outputId": "24de5258-e6d3-4a97-8e09-17f6659485f3", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.431764282Z", + "start_time": "2023-11-13T18:04:58.373237609Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + " _____ _\n", + " / ___| | |\n", + " \\ `--. _ __ ___ ___| | __\n", + " `--. \\ '_ \\ / _ \\ / __| |/ /\n", + " /\\__/ / |_) | (_) | (__| <\n", + " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", + " | |\n", + " |_|\n", + " \n" + ] + } + ], + "source": [ + "display_action(Action.Spock)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "c1b643e3" + }, + "source": [ + "Per usare queste funzioni dovremo modificare anche la funzione `determine_winner`" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "id": "252c6e45", + "ExecuteTime": { + "end_time": "2023-11-13T18:04:58.432170640Z", + "start_time": "2023-11-13T18:04:58.417526836Z" + } + }, + "outputs": [], + "source": [ + "def determine_winner(user_action, computer_action):\n", + " print(f\"You chose\")\n", + " display_action(user_action)\n", + " print(f\"The computer chose\")\n", + " display_action(computer_action)\n", + " defeats = victories[user_action]\n", + " if user_action == computer_action:\n", + " display_result(DRAW)\n", + " return DRAW\n", + " elif computer_action in defeats:\n", + " display_result(HUMAN_WIN)\n", + " return HUMAN_WIN\n", + " else:\n", + " display_result(COMPUTER_WIN)\n", + " return COMPUTER_WIN" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 4400, + "status": "ok", + "timestamp": 1699709879202, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "q_y93jZFjwtv", + "outputId": "9a6ba887-29e9-4baa-840d-d98ea434c6d0", + "ExecuteTime": { + "end_time": "2023-11-13T18:05:00.784466515Z", + "start_time": "2023-11-13T18:04:58.418139193Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "The computer chose\n", + "\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n" + ] + } + ], + "source": [ + "start_game()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5e478a36" + }, + "source": [ + "### Conserviamo i punteggi ottenuti manche per manche dagli utenti\n", + "\n", + "Non ci accontenteremo più solo dei messaggi di vittoria della singola manche. Vogliamo proprio fare una partita per capire chi vince fra utente e computer dopo N manche. Ora possiamo fare una vera e propria partita contro il computer e decidere quando finirla!" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "id": "ec5766f6", + "ExecuteTime": { + "end_time": "2023-11-13T18:05:00.784880036Z", + "start_time": "2023-11-13T18:05:00.741917536Z" + } + }, + "outputs": [], + "source": [ + "def print_game_results(game_results):\n", + " num_tied = game_results.count(DRAW) / len(game_results)*100\n", + " num_player_wins = game_results.count(HUMAN_WIN) / len(game_results)*100\n", + " num_computer_wins =game_results.count(COMPUTER_WIN) / len(game_results)*100\n", + "\n", + " print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n", + "\n", + "def start_game(num_games=1):\n", + " game_results = []\n", + " counter=0\n", + " while True:\n", + " try:\n", + " user_action = get_user_selection()\n", + " except ValueError:\n", + " range_str = f\"[0, {len(Action) - 1}]\"\n", + " print(f\"Invalid selection. Enter a value in range {range_str}\")\n", + " continue\n", + "\n", + " computer_action = get_computer_selection()\n", + " game_results.append(determine_winner(user_action, computer_action))\n", + " counter += 1\n", + "\n", + " if counter >= num_games:\n", + " break\n", + " print_game_results(game_results)\n", + " return game_results\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 4689, + "status": "ok", + "timestamp": 1699709883885, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "lcLQZxy3jwtw", + "outputId": "15a53e1a-4624-4a0a-e604-2b687f656fef", + "ExecuteTime": { + "end_time": "2023-11-13T18:05:01.720642511Z", + "start_time": "2023-11-13T18:05:00.746539899Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "The computer chose\n", + "\n", + " ______\n", + " | ___ \\\n", + " | |_/ /_ _ _ __ ___ _ __\n", + " | __/ _` | '_ \\ / _ \\ '__|\n", + " | | | (_| | |_) | __/ |\n", + " \\_| \\__,_| .__/ \\___|_|\n", + " | |\n", + " |_|\n", + " \n", + "\n", + " _____ ________ _________ _ _ _____ ___________\n", + "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", + "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", + "| | | | | | |\\/| || __/| | | | | | | __|| /\n", + "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", + " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + " \n", + "There were 0.0 % tied games \n", + "the player won 0.0 % of games\n", + "the computer won 100.0 % of games\n", + "in a total of 1 games\n" + ] + } + ], + "source": [ + "game_results=start_game(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "aae3e00d" + }, + "source": [ + "### Utilizziamo un'interfaccia grafica!\n", + "\n", + "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", + "\n", + "Concetti connessi:\n", + "- list comprehension\n", + "- `widgets.Dropdown`" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 15258, + "status": "ok", + "timestamp": 1699709899132, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "yE1oRjMn5G0f", + "outputId": "fe2da3a7-4310-44a5-c77d-560c2e9739e5", + "ExecuteTime": { + "end_time": "2023-11-13T18:10:39.999088654Z", + "start_time": "2023-11-13T18:10:27.553051295Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting gdown\r\n", + " Using cached gdown-4.7.1-py3-none-any.whl (15 kB)\r\n", + "Collecting numpy\r\n", + " Using cached numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.2 MB)\r\n", + "Collecting opencv-python\r\n", + " Using cached opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (61.7 MB)\r\n", + "Collecting mediapipe\r\n", + " Using cached mediapipe-0.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (34.5 MB)\r\n", + "Requirement already satisfied: requests in ./.venv/lib/python3.11/site-packages (2.31.0)\r\n", + "Collecting filelock (from gdown)\r\n", + " Using cached filelock-3.13.1-py3-none-any.whl (11 kB)\r\n", + "Requirement already satisfied: six in ./.venv/lib/python3.11/site-packages (from gdown) (1.16.0)\r\n", + "Collecting tqdm (from gdown)\r\n", + " Using cached tqdm-4.66.1-py3-none-any.whl (78 kB)\r\n", + "Requirement already satisfied: beautifulsoup4 in ./.venv/lib/python3.11/site-packages (from gdown) (4.12.2)\r\n", + "Collecting absl-py (from mediapipe)\r\n", + " Using cached absl_py-2.0.0-py3-none-any.whl (130 kB)\r\n", + "Requirement already satisfied: attrs>=19.1.0 in ./.venv/lib/python3.11/site-packages (from mediapipe) (23.1.0)\r\n", + "Collecting flatbuffers>=2.0 (from mediapipe)\r\n", + " Using cached flatbuffers-23.5.26-py2.py3-none-any.whl (26 kB)\r\n", + "Collecting matplotlib (from mediapipe)\r\n", + " Using cached matplotlib-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.6 MB)\r\n", + "Collecting opencv-contrib-python (from mediapipe)\r\n", + " Using cached opencv_contrib_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (67.8 MB)\r\n", + "Collecting protobuf<4,>=3.11 (from mediapipe)\r\n", + " Using cached protobuf-3.20.3-py2.py3-none-any.whl (162 kB)\r\n", + "Collecting sounddevice>=0.4.4 (from mediapipe)\r\n", + " Using cached sounddevice-0.4.6-py3-none-any.whl (31 kB)\r\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in ./.venv/lib/python3.11/site-packages (from requests) (3.3.2)\r\n", + "Requirement already satisfied: idna<4,>=2.5 in ./.venv/lib/python3.11/site-packages (from requests) (3.4)\r\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in ./.venv/lib/python3.11/site-packages (from requests) (2.1.0)\r\n", + "Requirement already satisfied: certifi>=2017.4.17 in ./.venv/lib/python3.11/site-packages (from requests) (2023.7.22)\r\n", + "Requirement already satisfied: CFFI>=1.0 in ./.venv/lib/python3.11/site-packages (from sounddevice>=0.4.4->mediapipe) (1.16.0)\r\n", + "Requirement already satisfied: soupsieve>1.2 in ./.venv/lib/python3.11/site-packages (from beautifulsoup4->gdown) (2.5)\r\n", + "Collecting contourpy>=1.0.1 (from matplotlib->mediapipe)\r\n", + " Using cached contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (313 kB)\r\n", + "Collecting cycler>=0.10 (from matplotlib->mediapipe)\r\n", + " Using cached cycler-0.12.1-py3-none-any.whl (8.3 kB)\r\n", + "Collecting fonttools>=4.22.0 (from matplotlib->mediapipe)\r\n", + " Using cached fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB)\r\n", + "Collecting kiwisolver>=1.3.1 (from matplotlib->mediapipe)\r\n", + " Using cached kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\r\n", + "Requirement already satisfied: packaging>=20.0 in ./.venv/lib/python3.11/site-packages (from matplotlib->mediapipe) (23.2)\r\n", + "Collecting pillow>=8 (from matplotlib->mediapipe)\r\n", + " Using cached Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl (3.6 MB)\r\n", + "Collecting pyparsing>=2.3.1 (from matplotlib->mediapipe)\r\n", + " Using cached pyparsing-3.1.1-py3-none-any.whl (103 kB)\r\n", + "Requirement already satisfied: python-dateutil>=2.7 in ./.venv/lib/python3.11/site-packages (from matplotlib->mediapipe) (2.8.2)\r\n", + "Collecting PySocks!=1.5.7,>=1.5.6 (from requests)\r\n", + " Using cached PySocks-1.7.1-py3-none-any.whl (16 kB)\r\n", + "Requirement already satisfied: pycparser in ./.venv/lib/python3.11/site-packages (from CFFI>=1.0->sounddevice>=0.4.4->mediapipe) (2.21)\r\n", + "Installing collected packages: flatbuffers, tqdm, PySocks, pyparsing, protobuf, pillow, numpy, kiwisolver, fonttools, filelock, cycler, absl-py, sounddevice, opencv-python, opencv-contrib-python, contourpy, matplotlib, gdown, mediapipe\r\n", + "Successfully installed PySocks-1.7.1 absl-py-2.0.0 contourpy-1.2.0 cycler-0.12.1 filelock-3.13.1 flatbuffers-23.5.26 fonttools-4.44.0 gdown-4.7.1 kiwisolver-1.4.5 matplotlib-3.8.1 mediapipe-0.10.8 numpy-1.26.2 opencv-contrib-python-4.8.1.78 opencv-python-4.8.1.78 pillow-10.1.0 protobuf-3.20.3 pyparsing-3.1.1 sounddevice-0.4.6 tqdm-4.66.1\r\n", + "\r\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.1.2\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m23.3.1\u001B[0m\r\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\r\n" + ] + } + ], + "source": [ + "!pip install gdown numpy opencv-python mediapipe requests" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "executionInfo": { + "elapsed": 951, + "status": "ok", + "timestamp": 1699709900079, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "uddtBN5Hj0mh", + "outputId": "5aaf0849-e0d3-48be-fa9e-35bf7473506f", + "ExecuteTime": { + "end_time": "2023-11-13T18:10:52.503377013Z", + "start_time": "2023-11-13T18:10:50.591649692Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Downloading...\r\n", + "From (uriginal): https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\r\n", + "From (redirected): https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N&confirm=t&uuid=0dcea6f1-471f-48c3-810c-0f247832e330\r\n", + "To: /home/debian/develop/personal/pythonpescara/python-beginners-workshop-2023/support.py\r\n", + "100%|██████████████████████████████████████| 13.2k/13.2k [00:00<00:00, 47.5MB/s]\r\n" + ] + } + ], + "source": [ + "!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "id": "Pg1r0Rq14b9f", + "ExecuteTime": { + "end_time": "2023-11-13T18:05:19.754435822Z", + "start_time": "2023-11-13T18:05:19.383326383Z" + } + }, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'mediapipe'", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[39], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01msupport\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;241m*\u001B[39m\n", + "File \u001B[0;32m~/develop/personal/pythonpescara/python-beginners-workshop-2023/support.py:2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mnumpy\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mnp\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmediapipe\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mmp\u001B[39;00m\n\u001B[1;32m 3\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mcv2\u001B[39;00m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mrequests\u001B[39;00m\n", + "\u001B[0;31mModuleNotFoundError\u001B[0m: No module named 'mediapipe'" + ] + } + ], + "source": [ + "from support import *" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 847 + }, + "executionInfo": { + "elapsed": 7, + "status": "ok", + "timestamp": 1699709900079, + "user": { + "displayName": "Moreno Mazzocchetti", + "userId": "18050587376363424786" + }, + "user_tz": -60 + }, + "id": "a6b41097", + "outputId": "aadb9b9b-abec-4391-fe5b-93f908d710c6" + }, + "outputs": [], + "source": [ + "options=[(action.name,action.value) for action in Action]\n", + "output, button, box, menu = create_dropdown(options)\n", + "\n", + "def on_button_clicked(b):\n", + " output.clear_output()\n", + " with output:\n", + " computer_action = get_computer_selection()\n", + " determine_winner(Action(menu.value), computer_action)\n", + "\n", + "button.on_click(on_button_clicked)\n", + "\n", + "display(box)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "d95e966e" + }, + "source": [ + "## Time to use ML!\n", + "\n", + "Nelle celle successive andremo ad utilizzare il Machine Learning per addestrare un modello predittivo in grado di dedurre la mossa dell'utente a partire dall'inquadratura della mano ottenuta con la webcam.\n", + "\n", + "Installiamo le librerie necessarie e importiamole:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "3CCoidG5jwtx" + }, + "outputs": [], + "source": [ + "def start_game(num_games=1):\n", + " game_results = []\n", + " counter = 0\n", + " # Load mediapipe hand class\n", + " pipe = MediaPipeHand(static_image_mode=True, max_num_hands=1)\n", + " # Load gesture recognition class\n", + " gest = GestureRecognition()\n", + " while True:\n", + " try:\n", + " img = take_photo()\n", + " param = pipe.forward(img)\n", + " # Evaluate gesture for all hands\n", + "\n", + " for p in param:\n", + " if p['class'] is not None:\n", + " p['gesture'] = gest.eval(p['angle'])\n", + " action = None\n", + " if p['gesture'] == 'fist':\n", + " action = Action.Rock\n", + " elif p['gesture'] == 'five':\n", + " action = Action.Paper\n", + " elif (p['gesture'] == 'three') or (p['gesture']=='yeah'):\n", + " action = Action.Scissors\n", + " elif (p['gesture'] == 'rock') :\n", + " action = Action.Lizard\n", + " elif (p['gesture'] == 'four'):\n", + " action = Action.Spock\n", + " if action is not None:\n", + " computer_action = get_computer_selection()\n", + " game_results.append(determine_winner(action, computer_action))\n", + " counter += 1\n", + " print_game_results(game_results)\n", + " old_action=action\n", + "\n", + " if counter>=num_games:\n", + " break\n", + " except Exception as err:\n", + " # Errors will be thrown if the user does not have a webcam or if they do not\n", + " # grant the page permission to access it.\n", + " print(str(err))\n", + " raise err\n", + "\n", + " pipe.pipe.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "background_save": true, + "base_uri": "https://localhost:8080/", + "height": 17 + }, + "id": "biwLyBjhjwtx" + }, + "outputs": [], + "source": [ + "start_game(num_games=5)" + ] + } + ], + "metadata": { + "colab": { + "name": "", + "version": "" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.1" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "044c8c12d53c4f80b02a195ee1b10ded": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DropdownModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DropdownModel", + "_options_labels": [ + "Rock", + "Paper", + "Scissors", + "Lizard", + "Spock" + ], + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "DropdownView", + "description": "Chose:", + "description_tooltip": null, + "disabled": false, + "index": 0, + "layout": "IPY_MODEL_249fd3223b024434870c8581f5221f70", + "style": "IPY_MODEL_38d57a4f87494825b29f284516a9c312" + } + }, + "249fd3223b024434870c8581f5221f70": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "38d57a4f87494825b29f284516a9c312": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "DescriptionStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "DescriptionStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "description_width": "" + } + }, + "67200cd7f8924627aa18cc81af0a478d": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": "1px solid black", + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "9181989fa1c943b895c8d8920b57c0d4": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + }, + "bce58963af05485d9e28cc4836e298c7": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "VBoxModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "VBoxModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "VBoxView", + "box_style": "", + "children": [ + "IPY_MODEL_044c8c12d53c4f80b02a195ee1b10ded", + "IPY_MODEL_f698ce0c10b946beb5563253752f3f6b", + "IPY_MODEL_debad6f6bc9c4066bbb98c12cf703d26" + ], + "layout": "IPY_MODEL_9181989fa1c943b895c8d8920b57c0d4" + } + }, + "debad6f6bc9c4066bbb98c12cf703d26": { + "model_module": "@jupyter-widgets/output", + "model_module_version": "1.0.0", + "model_name": "OutputModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/output", + "_model_module_version": "1.0.0", + "_model_name": "OutputModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/output", + "_view_module_version": "1.0.0", + "_view_name": "OutputView", + "layout": "IPY_MODEL_67200cd7f8924627aa18cc81af0a478d", + "msg_id": "", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You chose\n", + "\n", + " ______ _\n", + " | ___ \\ | |\n", + " | |_/ /___ ___| | __\n", + " | // _ \\ / __| |/ /\n", + " | |\\ \\ (_) | (__| <\n", + " \\_| \\_\\___/ \\___|_|\\_\\\n", + "\n", + " \n", + "The computer chose\n", + "\n", + " _____ _\n", + " / ___| (_)\n", + " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", + " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", + " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", + " \\____/ \\___|_|___/___/\\___/|_| |___/\n", + " \n", + "\n", + " _ _ _ ____ ___ ___ _ _\n", + "| | | | | | | \\/ | / _ \\ | \\ | |\n", + "| |_| | | | | . . |/ /_\\ \\| \\| |\n", + "| _ | | | | |\\/| || _ || . ` |\n", + "| | | | |_| | | | || | | || |\\ |\n", + "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", + "\n", + "\n", + " _ _ _____ _ _ _____ _ _ _\n", + "| | | |_ _| \\ | |/ ___| | | | |\n", + "| | | | | | | \\| |\\ `--. | | | |\n", + "| |/\\| | | | | . ` | `--. \\ | | | |\n", + "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", + " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", + "\n", + "\n", + " __\n", + " / _|\n", + " | |_ ___ _ __ _ __ _____ __\n", + " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", + " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", + "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", + "\n", + " \n" + ] + } + ] + } + }, + "f12b87967424418d8f6fed872834a091": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonStyleModel", + "state": { + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonStyleModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "StyleView", + "button_color": null, + "font_weight": "" + } + }, + "f698ce0c10b946beb5563253752f3f6b": { + "model_module": "@jupyter-widgets/controls", + "model_module_version": "1.5.0", + "model_name": "ButtonModel", + "state": { + "_dom_classes": [], + "_model_module": "@jupyter-widgets/controls", + "_model_module_version": "1.5.0", + "_model_name": "ButtonModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/controls", + "_view_module_version": "1.5.0", + "_view_name": "ButtonView", + "button_style": "success", + "description": "Play!", + "disabled": false, + "icon": "check", + "layout": "IPY_MODEL_fcf2583dce504a9c960c73d0492264d5", + "style": "IPY_MODEL_f12b87967424418d8f6fed872834a091", + "tooltip": "" + } + }, + "fcf2583dce504a9c960c73d0492264d5": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "1.2.0", + "model_name": "LayoutModel", + "state": { + "_model_module": "@jupyter-widgets/base", + "_model_module_version": "1.2.0", + "_model_name": "LayoutModel", + "_view_count": null, + "_view_module": "@jupyter-widgets/base", + "_view_module_version": "1.2.0", + "_view_name": "LayoutView", + "align_content": null, + "align_items": null, + "align_self": null, + "border": null, + "bottom": null, + "display": null, + "flex": null, + "flex_flow": null, + "grid_area": null, + "grid_auto_columns": null, + "grid_auto_flow": null, + "grid_auto_rows": null, + "grid_column": null, + "grid_gap": null, + "grid_row": null, + "grid_template_areas": null, + "grid_template_columns": null, + "grid_template_rows": null, + "height": null, + "justify_content": null, + "justify_items": null, + "left": null, + "margin": null, + "max_height": null, + "max_width": null, + "min_height": null, + "min_width": null, + "object_fit": null, + "object_position": null, + "order": null, + "overflow": null, + "overflow_x": null, + "overflow_y": null, + "padding": null, + "right": null, + "top": null, + "visibility": null, + "width": null + } + } + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From edc7d0c0bd49904118fcf260f87e401256c83eac Mon Sep 17 00:00:00 2001 From: Moreno Mazzocchetti Date: Mon, 13 Nov 2023 20:12:19 +0100 Subject: [PATCH 5/6] Code refactoring and refinements --- .gitignore | 3 +- Live Coding Completo.ipynb | 680 +++++++------------------------------ support.py | 622 +++++++++++++++++---------------- 3 files changed, 460 insertions(+), 845 deletions(-) diff --git a/.gitignore b/.gitignore index 0e9cc8f..5d3d8e7 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ .ipynb_checkpoints /.idea /.venv -__pycache__ \ No newline at end of file +__pycache__ +/gesture_train.csv \ No newline at end of file diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index 817f6ba..57d05b4 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -13,9 +13,6 @@ }, { "cell_type": "markdown", - "metadata": { - "id": "78e5f376" - }, "source": [ "## Task 1\n", "\n", @@ -26,29 +23,28 @@ "* come è possible prendere un input da parte dell'utente\n", "* come è possibile creare una lista con le possibili scelte di gioco\n", "* come è possibile generare la mossa del computer in maniera casuale" - ] + ], + "metadata": { + "collapsed": false + } }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { - "id": "6cfa68db", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:38.993136852Z", - "start_time": "2023-11-13T18:04:38.836371914Z" - } + "id": "6cfa68db" }, "outputs": [], "source": [ "integer_number = 10\n", "float_number = 0.13\n", "boolean = True\n", - "string = 'pycon'" + "string = \"pycon\"" ] }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -64,28 +60,16 @@ "user_tz": -60 }, "id": "DLo0HbU8jwtm", - "outputId": "8fb84091-34ba-4dbd-94ea-3e2ccad4f316", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:39.124866047Z", - "start_time": "2023-11-13T18:04:38.851382834Z" - } + "outputId": "8fb84091-34ba-4dbd-94ea-3e2ccad4f316" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Ciao Mondo :)\n" - ] - } - ], + "outputs": [], "source": [ - "print('Ciao Mondo :)')" + "print(\"Ciao Mondo :)\")" ] }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -101,28 +85,16 @@ "user_tz": -60 }, "id": "0OX9TkPDjwtm", - "outputId": "236a58da-c29b-46cb-8eab-b2e50a15556d", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:39.125436876Z", - "start_time": "2023-11-13T18:04:38.852521067Z" - } + "outputId": "236a58da-c29b-46cb-8eab-b2e50a15556d" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10\n" - ] - } - ], + "outputs": [], "source": [ "print(integer_number)" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -138,28 +110,16 @@ "user_tz": -60 }, "id": "W70GvccNjwtn", - "outputId": "a87c9464-85b8-4086-a9d4-d5cbceea3b2c", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:39.127965261Z", - "start_time": "2023-11-13T18:04:38.864699852Z" - } + "outputId": "a87c9464-85b8-4086-a9d4-d5cbceea3b2c" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pycon 10\n" - ] - } - ], + "outputs": [], "source": [ "print(string, integer_number)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -175,20 +135,16 @@ "user_tz": -60 }, "id": "sCQu4LkLjwtn", - "outputId": "c5b694ec-2b17-4f51-f402-a6eff4790264", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:40.907090654Z", - "start_time": "2023-11-13T18:04:38.865117857Z" - } + "outputId": "c5b694ec-2b17-4f51-f402-a6eff4790264" }, "outputs": [], "source": [ - "risultato = input('digita un numero?')" + "risultato = input(\"digita un numero?\")" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -204,28 +160,16 @@ "user_tz": -60 }, "id": "Pslrt8Nwjwto", - "outputId": "57c4624b-b1e5-463a-c625-6e40ba2d13ce", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:40.926291350Z", - "start_time": "2023-11-13T18:04:40.747132030Z" - } + "outputId": "57c4624b-b1e5-463a-c625-6e40ba2d13ce" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n" - ] - } - ], + "outputs": [], "source": [ "print(risultato)" ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -241,11 +185,7 @@ "user_tz": -60 }, "id": "hy51y-owjwto", - "outputId": "a2168225-1f45-49b1-cc33-f2c021a60afa", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:43.165947154Z", - "start_time": "2023-11-13T18:04:40.792637905Z" - } + "outputId": "a2168225-1f45-49b1-cc33-f2c021a60afa" }, "outputs": [], "source": [ @@ -254,13 +194,9 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { - "id": "sO8y1DHqjwto", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:43.166433172Z", - "start_time": "2023-11-13T18:04:43.113625232Z" - } + "id": "sO8y1DHqjwto" }, "outputs": [], "source": [ @@ -269,13 +205,9 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { - "id": "NxgXYbZ-jwtp", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:43.166621465Z", - "start_time": "2023-11-13T18:04:43.118715516Z" - } + "id": "NxgXYbZ-jwtp" }, "outputs": [], "source": [ @@ -285,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -301,23 +233,9 @@ "user_tz": -60 }, "id": "EKBwgQm1jwtp", - "outputId": "14137bef-862d-4d35-9cc8-5e7b0fd9b847", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:43.167020808Z", - "start_time": "2023-11-13T18:04:43.128006488Z" - } + "outputId": "14137bef-862d-4d35-9cc8-5e7b0fd9b847" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "You chose rock, computer chose paper.\n", - "\n" - ] - } - ], + "outputs": [], "source": [ "print(f\"\\nYou chose {user_action}, computer chose {computer_action}.\\n\")" ] @@ -335,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -351,21 +269,9 @@ "user_tz": -60 }, "id": "90af3eea", - "outputId": "dd03b6a2-38f4-43e5-9807-ce912ff62e13", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:43.215993559Z", - "start_time": "2023-11-13T18:04:43.172419296Z" - } + "outputId": "dd03b6a2-38f4-43e5-9807-ce912ff62e13" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Paper covers rock! You lose.\n" - ] - } - ], + "outputs": [], "source": [ "if user_action == computer_action:\n", " print(f\"Both players selected {user_action}. It's a tie!\")\n", @@ -405,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -421,24 +327,9 @@ "user_tz": -60 }, "id": "47580fd9", - "outputId": "921ac4d0-4b70-40ad-b75a-dd8041c5a911", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.636166168Z", - "start_time": "2023-11-13T18:04:43.173013837Z" - } + "outputId": "921ac4d0-4b70-40ad-b75a-dd8041c5a911" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "You chose rock, computer chose rock.\n", - "\n", - "Both players selected rock. It's a tie!\n" - ] - } - ], + "outputs": [], "source": [ "while True:\n", " user_action = input(\"Enter a choice (rock, paper, scissors): \")\n", @@ -495,13 +386,9 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": { - "id": "0ec721b6", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.649817557Z", - "start_time": "2023-11-13T18:04:46.560784549Z" - } + "id": "0ec721b6" }, "outputs": [], "source": [ @@ -515,7 +402,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -531,23 +418,9 @@ "user_tz": -60 }, "id": "4BTg9ygOjwtq", - "outputId": "fbfc8ae2-0cfe-42cd-ce09-0426001729cc", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.651489119Z", - "start_time": "2023-11-13T18:04:46.605325091Z" - } + "outputId": "fbfc8ae2-0cfe-42cd-ce09-0426001729cc" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Action.Rock == Action.Rock True\n", - "Action.Rock == Action(0) True\n", - "Action(0) 0\n" - ] - } - ], + "outputs": [], "source": [ "print('Action.Rock == Action.Rock', Action.Rock == Action.Rock)\n", "print('Action.Rock == Action(0)', Action.Rock == Action(0))\n", @@ -571,13 +444,9 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": { - "id": "08c5263b", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.651716115Z", - "start_time": "2023-11-13T18:04:46.605757408Z" - } + "id": "08c5263b" }, "outputs": [], "source": [ @@ -587,7 +456,6 @@ " action = Action(selection)\n", " return action\n", "\n", - "\n", "def get_user_selection():\n", " choices = [f\"{action.name}[{action.value}]\" for action in Action]\n", " choices_str = \", \".join(choices)\n", @@ -598,13 +466,9 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": { - "id": "hldiDTxqjwtr", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.651876922Z", - "start_time": "2023-11-13T18:04:46.606029436Z" - } + "id": "hldiDTxqjwtr" }, "outputs": [], "source": [ @@ -616,13 +480,9 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": { - "id": "eMYFUSiojwtr", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.652029994Z", - "start_time": "2023-11-13T18:04:46.606307039Z" - } + "id": "eMYFUSiojwtr" }, "outputs": [], "source": [ @@ -659,13 +519,9 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": { - "id": "8ebfa484", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:46.652231182Z", - "start_time": "2023-11-13T18:04:46.606599033Z" - } + "id": "8ebfa484" }, "outputs": [], "source": [ @@ -688,7 +544,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -704,22 +560,9 @@ "user_tz": -60 }, "id": "I3BM0Z4Kjwtr", - "outputId": "a102b536-8581-40b3-9aed-3e9eea5c921d", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:52.606578937Z", - "start_time": "2023-11-13T18:04:46.606959467Z" - } + "outputId": "a102b536-8581-40b3-9aed-3e9eea5c921d" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Invalid selection. Enter a value in range [0, 2]\n", - "Paper covers rock! You lose.\n" - ] - } - ], + "outputs": [], "source": [ "start_game()" ] @@ -739,13 +582,9 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": { - "id": "96893f8d", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:52.607074048Z", - "start_time": "2023-11-13T18:04:52.518501129Z" - } + "id": "96893f8d" }, "outputs": [], "source": [ @@ -767,13 +606,9 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": { - "id": "dce77a8a", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:52.607499997Z", - "start_time": "2023-11-13T18:04:52.561389938Z" - } + "id": "dce77a8a" }, "outputs": [], "source": [ @@ -790,7 +625,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -806,26 +641,9 @@ "user_tz": -60 }, "id": "cv6L7ahtjwtr", - "outputId": "609f516f-00c3-42ae-ba9e-1496fc56cae8", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.398493928Z", - "start_time": "2023-11-13T18:04:52.561931229Z" - } + "outputId": "609f516f-00c3-42ae-ba9e-1496fc56cae8" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Invalid selection. Enter a value in range [0, 2]\n", - "Invalid selection. Enter a value in range [0, 2]\n", - "Invalid selection. Enter a value in range [0, 2]\n", - "Invalid selection. Enter a value in range [0, 2]\n", - "You chose Rock. The computer chose Scissors.\n", - "Rock beats Scissors! You win!\n" - ] - } - ], + "outputs": [], "source": [ "start_game()" ] @@ -843,13 +661,9 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "metadata": { - "id": "60f6e2d5", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.398911279Z", - "start_time": "2023-11-13T18:04:58.355044569Z" - } + "id": "60f6e2d5" }, "outputs": [], "source": [ @@ -884,13 +698,9 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": { - "id": "4422813d", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.399244580Z", - "start_time": "2023-11-13T18:04:58.363796483Z" - } + "id": "4422813d" }, "outputs": [], "source": [ @@ -942,11 +752,13 @@ " \"\"\"\n", "}\n", "\n", - "COMPUTER_WIN = -1\n", - "HUMAN_WIN = 1\n", - "DRAW = 0\n", + "class Result(IntEnum):\n", + " COMPUTER_WIN = -1\n", + " HUMAN_WIN = 1\n", + " DRAW = 0\n", + "\n", "ascii_result = {\n", - " COMPUTER_WIN: r\"\"\"\n", + " Result.COMPUTER_WIN: r\"\"\"\n", " _____ ________ _________ _ _ _____ ___________\n", "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", @@ -963,7 +775,7 @@ " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", "\n", " \"\"\",\n", - " HUMAN_WIN: r\"\"\"\n", + " Result.HUMAN_WIN: r\"\"\"\n", " _ _ _ ____ ___ ___ _ _\n", "| | | | | | | \\/ | / _ \\ | \\ | |\n", "| |_| | | | | . . |/ /_\\ \\| \\| |\n", @@ -988,7 +800,7 @@ "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", "\n", " \"\"\",\n", - " DRAW: r\"\"\"\n", + " Result.DRAW: r\"\"\"\n", " _ _ _\n", " | | (_) | |\n", " __ _ | |_ _ ___ __| | __ _ __ _ _ __ ___ ___\n", @@ -1021,13 +833,9 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": null, "metadata": { - "id": "c96921e2", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.399452317Z", - "start_time": "2023-11-13T18:04:58.368943717Z" - } + "id": "c96921e2" }, "outputs": [], "source": [ @@ -1040,7 +848,7 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1056,30 +864,9 @@ "user_tz": -60 }, "id": "18tMjb3sjwts", - "outputId": "24de5258-e6d3-4a97-8e09-17f6659485f3", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.431764282Z", - "start_time": "2023-11-13T18:04:58.373237609Z" - } + "outputId": "24de5258-e6d3-4a97-8e09-17f6659485f3" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - " _____ _\n", - " / ___| | |\n", - " \\ `--. _ __ ___ ___| | __\n", - " `--. \\ '_ \\ / _ \\ / __| |/ /\n", - " /\\__/ / |_) | (_) | (__| <\n", - " \\____/| .__/ \\___/ \\___|_|\\_\\\\\n", - " | |\n", - " |_|\n", - " \n" - ] - } - ], + "outputs": [], "source": [ "display_action(Action.Spock)" ] @@ -1095,13 +882,9 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": null, "metadata": { - "id": "252c6e45", - "ExecuteTime": { - "end_time": "2023-11-13T18:04:58.432170640Z", - "start_time": "2023-11-13T18:04:58.417526836Z" - } + "id": "252c6e45" }, "outputs": [], "source": [ @@ -1112,19 +895,19 @@ " display_action(computer_action)\n", " defeats = victories[user_action]\n", " if user_action == computer_action:\n", - " display_result(DRAW)\n", - " return DRAW\n", + " display_result(Result.DRAW)\n", + " return Result.DRAW\n", " elif computer_action in defeats:\n", - " display_result(HUMAN_WIN)\n", - " return HUMAN_WIN\n", + " display_result(Result.HUMAN_WIN)\n", + " return Result.HUMAN_WIN\n", " else:\n", - " display_result(COMPUTER_WIN)\n", - " return COMPUTER_WIN" + " display_result(Result.COMPUTER_WIN)\n", + " return Result.HUMAN_WIN" ] }, { "cell_type": "code", - "execution_count": 34, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1140,64 +923,9 @@ "user_tz": -60 }, "id": "q_y93jZFjwtv", - "outputId": "9a6ba887-29e9-4baa-840d-d98ea434c6d0", - "ExecuteTime": { - "end_time": "2023-11-13T18:05:00.784466515Z", - "start_time": "2023-11-13T18:04:58.418139193Z" - } + "outputId": "9a6ba887-29e9-4baa-840d-d98ea434c6d0" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "The computer chose\n", - "\n", - " _____ _\n", - " / ___| (_)\n", - " \\ `--. ___ _ ___ ___ ___ _ __ ___\n", - " `--. \\/ __| / __/ __|/ _ \\| '__/ __|\n", - " /\\__/ / (__| \\__ \\__ \\ (_) | | \\__ \\\\\n", - " \\____/ \\___|_|___/___/\\___/|_| |___/\n", - " \n", - "\n", - " _ _ _ ____ ___ ___ _ _\n", - "| | | | | | | \\/ | / _ \\ | \\ | |\n", - "| |_| | | | | . . |/ /_\\ \\| \\| |\n", - "| _ | | | | |\\/| || _ || . ` |\n", - "| | | | |_| | | | || | | || |\\ |\n", - "\\_| |_/\\___/\\_| |_/\\_| |_/\\_| \\_/\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - "\n", - " __\n", - " / _|\n", - " | |_ ___ _ __ _ __ _____ __\n", - " | _/ _ \\| '__| | '_ \\ / _ \\ \\ /\\ / /\n", - " _ _ _| || (_) | | | | | | (_) \\ V V / _ _ _\n", - "(_|_|_)_| \\___/|_| |_| |_|\\___/ \\_/\\_/ (_|_|_)\n", - "\n", - " \n" - ] - } - ], + "outputs": [], "source": [ "start_game()" ] @@ -1215,22 +943,26 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": null, + "outputs": [], + "source": [], "metadata": { - "id": "ec5766f6", - "ExecuteTime": { - "end_time": "2023-11-13T18:05:00.784880036Z", - "start_time": "2023-11-13T18:05:00.741917536Z" - } + "collapsed": false + } + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "ec5766f6" }, "outputs": [], "source": [ "def print_game_results(game_results):\n", - " num_tied = game_results.count(DRAW) / len(game_results)*100\n", - " num_player_wins = game_results.count(HUMAN_WIN) / len(game_results)*100\n", - " num_computer_wins =game_results.count(COMPUTER_WIN) / len(game_results)*100\n", - "\n", - " print( 'There were ', num_tied, '% tied games', \"\\nthe player won \", num_player_wins, '% of games\\nthe computer won ', num_computer_wins, '% of games\\nin a total of ', len(game_results), ' games')\n", + " num_tied = game_results.count(Result.DRAW) / len(game_results) * 100\n", + " num_player_wins = game_results.count(Result.HUMAN_WIN) / len(game_results) * 100\n", + " num_computer_wins = game_results.count(Result.COMPUTER_WIN) / len(game_results) * 100\n", + " print(f\"There were {num_tied}% tied games\\nthe player won {num_player_wins}% of games\\nthe computer won {num_computer_wins}% of games\\nin a total of {len(game_results)} games\")\n", "\n", "def start_game(num_games=1):\n", " game_results = []\n", @@ -1250,13 +982,12 @@ " if counter >= num_games:\n", " break\n", " print_game_results(game_results)\n", - " return game_results\n", - "\n" + " return game_results" ] }, { "cell_type": "code", - "execution_count": 36, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1272,64 +1003,11 @@ "user_tz": -60 }, "id": "lcLQZxy3jwtw", - "outputId": "15a53e1a-4624-4a0a-e604-2b687f656fef", - "ExecuteTime": { - "end_time": "2023-11-13T18:05:01.720642511Z", - "start_time": "2023-11-13T18:05:00.746539899Z" - } + "outputId": "15a53e1a-4624-4a0a-e604-2b687f656fef" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "You chose\n", - "\n", - " ______ _\n", - " | ___ \\ | |\n", - " | |_/ /___ ___| | __\n", - " | // _ \\ / __| |/ /\n", - " | |\\ \\ (_) | (__| <\n", - " \\_| \\_\\___/ \\___|_|\\_\\\n", - "\n", - " \n", - "The computer chose\n", - "\n", - " ______\n", - " | ___ \\\n", - " | |_/ /_ _ _ __ ___ _ __\n", - " | __/ _` | '_ \\ / _ \\ '__|\n", - " | | | (_| | |_) | __/ |\n", - " \\_| \\__,_| .__/ \\___|_|\n", - " | |\n", - " |_|\n", - " \n", - "\n", - " _____ ________ _________ _ _ _____ ___________\n", - "/ __ \\ _ | \\/ || ___ \\ | | |_ _| ___| ___ \\\\\n", - "| / \\/ | | | . . || |_/ / | | | | | | |__ | |_/ /\n", - "| | | | | | |\\/| || __/| | | | | | | __|| /\n", - "| \\__/\\ \\_/ / | | || | | |_| | | | | |___| |\\ \\\n", - " \\____/\\___/\\_| |_/\\_| \\___/ \\_/ \\____/\\_| \\_|\n", - "\n", - "\n", - " _ _ _____ _ _ _____ _ _ _\n", - "| | | |_ _| \\ | |/ ___| | | | |\n", - "| | | | | | | \\| |\\ `--. | | | |\n", - "| |/\\| | | | | . ` | `--. \\ | | | |\n", - "\\ /\\ /_| |_| |\\ |/\\__/ / |_|_|_|\n", - " \\/ \\/ \\___/\\_| \\_/\\____/ (_|_|_)\n", - "\n", - " \n", - "There were 0.0 % tied games \n", - "the player won 0.0 % of games\n", - "the computer won 100.0 % of games\n", - "in a total of 1 games\n" - ] - } - ], + "outputs": [], "source": [ - "game_results=start_game(1)" + "game_results = start_game(5)" ] }, { @@ -1338,7 +1016,7 @@ "id": "aae3e00d" }, "source": [ - "### Utilizziamo un'interfaccia grafica!\n", + "45### Utilizziamo un'interfaccia grafica!\n", "\n", "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", "\n", @@ -1349,7 +1027,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1365,83 +1043,16 @@ "user_tz": -60 }, "id": "yE1oRjMn5G0f", - "outputId": "fe2da3a7-4310-44a5-c77d-560c2e9739e5", - "ExecuteTime": { - "end_time": "2023-11-13T18:10:39.999088654Z", - "start_time": "2023-11-13T18:10:27.553051295Z" - } + "outputId": "fe2da3a7-4310-44a5-c77d-560c2e9739e5" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Collecting gdown\r\n", - " Using cached gdown-4.7.1-py3-none-any.whl (15 kB)\r\n", - "Collecting numpy\r\n", - " Using cached numpy-1.26.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (18.2 MB)\r\n", - "Collecting opencv-python\r\n", - " Using cached opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (61.7 MB)\r\n", - "Collecting mediapipe\r\n", - " Using cached mediapipe-0.10.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (34.5 MB)\r\n", - "Requirement already satisfied: requests in ./.venv/lib/python3.11/site-packages (2.31.0)\r\n", - "Collecting filelock (from gdown)\r\n", - " Using cached filelock-3.13.1-py3-none-any.whl (11 kB)\r\n", - "Requirement already satisfied: six in ./.venv/lib/python3.11/site-packages (from gdown) (1.16.0)\r\n", - "Collecting tqdm (from gdown)\r\n", - " Using cached tqdm-4.66.1-py3-none-any.whl (78 kB)\r\n", - "Requirement already satisfied: beautifulsoup4 in ./.venv/lib/python3.11/site-packages (from gdown) (4.12.2)\r\n", - "Collecting absl-py (from mediapipe)\r\n", - " Using cached absl_py-2.0.0-py3-none-any.whl (130 kB)\r\n", - "Requirement already satisfied: attrs>=19.1.0 in ./.venv/lib/python3.11/site-packages (from mediapipe) (23.1.0)\r\n", - "Collecting flatbuffers>=2.0 (from mediapipe)\r\n", - " Using cached flatbuffers-23.5.26-py2.py3-none-any.whl (26 kB)\r\n", - "Collecting matplotlib (from mediapipe)\r\n", - " Using cached matplotlib-3.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.6 MB)\r\n", - "Collecting opencv-contrib-python (from mediapipe)\r\n", - " Using cached opencv_contrib_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (67.8 MB)\r\n", - "Collecting protobuf<4,>=3.11 (from mediapipe)\r\n", - " Using cached protobuf-3.20.3-py2.py3-none-any.whl (162 kB)\r\n", - "Collecting sounddevice>=0.4.4 (from mediapipe)\r\n", - " Using cached sounddevice-0.4.6-py3-none-any.whl (31 kB)\r\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in ./.venv/lib/python3.11/site-packages (from requests) (3.3.2)\r\n", - "Requirement already satisfied: idna<4,>=2.5 in ./.venv/lib/python3.11/site-packages (from requests) (3.4)\r\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in ./.venv/lib/python3.11/site-packages (from requests) (2.1.0)\r\n", - "Requirement already satisfied: certifi>=2017.4.17 in ./.venv/lib/python3.11/site-packages (from requests) (2023.7.22)\r\n", - "Requirement already satisfied: CFFI>=1.0 in ./.venv/lib/python3.11/site-packages (from sounddevice>=0.4.4->mediapipe) (1.16.0)\r\n", - "Requirement already satisfied: soupsieve>1.2 in ./.venv/lib/python3.11/site-packages (from beautifulsoup4->gdown) (2.5)\r\n", - "Collecting contourpy>=1.0.1 (from matplotlib->mediapipe)\r\n", - " Using cached contourpy-1.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (313 kB)\r\n", - "Collecting cycler>=0.10 (from matplotlib->mediapipe)\r\n", - " Using cached cycler-0.12.1-py3-none-any.whl (8.3 kB)\r\n", - "Collecting fonttools>=4.22.0 (from matplotlib->mediapipe)\r\n", - " Using cached fonttools-4.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB)\r\n", - "Collecting kiwisolver>=1.3.1 (from matplotlib->mediapipe)\r\n", - " Using cached kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\r\n", - "Requirement already satisfied: packaging>=20.0 in ./.venv/lib/python3.11/site-packages (from matplotlib->mediapipe) (23.2)\r\n", - "Collecting pillow>=8 (from matplotlib->mediapipe)\r\n", - " Using cached Pillow-10.1.0-cp311-cp311-manylinux_2_28_x86_64.whl (3.6 MB)\r\n", - "Collecting pyparsing>=2.3.1 (from matplotlib->mediapipe)\r\n", - " Using cached pyparsing-3.1.1-py3-none-any.whl (103 kB)\r\n", - "Requirement already satisfied: python-dateutil>=2.7 in ./.venv/lib/python3.11/site-packages (from matplotlib->mediapipe) (2.8.2)\r\n", - "Collecting PySocks!=1.5.7,>=1.5.6 (from requests)\r\n", - " Using cached PySocks-1.7.1-py3-none-any.whl (16 kB)\r\n", - "Requirement already satisfied: pycparser in ./.venv/lib/python3.11/site-packages (from CFFI>=1.0->sounddevice>=0.4.4->mediapipe) (2.21)\r\n", - "Installing collected packages: flatbuffers, tqdm, PySocks, pyparsing, protobuf, pillow, numpy, kiwisolver, fonttools, filelock, cycler, absl-py, sounddevice, opencv-python, opencv-contrib-python, contourpy, matplotlib, gdown, mediapipe\r\n", - "Successfully installed PySocks-1.7.1 absl-py-2.0.0 contourpy-1.2.0 cycler-0.12.1 filelock-3.13.1 flatbuffers-23.5.26 fonttools-4.44.0 gdown-4.7.1 kiwisolver-1.4.5 matplotlib-3.8.1 mediapipe-0.10.8 numpy-1.26.2 opencv-contrib-python-4.8.1.78 opencv-python-4.8.1.78 pillow-10.1.0 protobuf-3.20.3 pyparsing-3.1.1 sounddevice-0.4.6 tqdm-4.66.1\r\n", - "\r\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.1.2\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m23.3.1\u001B[0m\r\n", - "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\r\n" - ] - } - ], + "outputs": [], "source": [ "!pip install gdown numpy opencv-python mediapipe requests" ] }, { "cell_type": "code", - "execution_count": 42, + "execution_count": null, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -1457,57 +1068,13 @@ "user_tz": -60 }, "id": "uddtBN5Hj0mh", - "outputId": "5aaf0849-e0d3-48be-fa9e-35bf7473506f", - "ExecuteTime": { - "end_time": "2023-11-13T18:10:52.503377013Z", - "start_time": "2023-11-13T18:10:50.591649692Z" - } + "outputId": "5aaf0849-e0d3-48be-fa9e-35bf7473506f" }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Downloading...\r\n", - "From (uriginal): https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N\r\n", - "From (redirected): https://drive.google.com/uc?id=1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N&confirm=t&uuid=0dcea6f1-471f-48c3-810c-0f247832e330\r\n", - "To: /home/debian/develop/personal/pythonpescara/python-beginners-workshop-2023/support.py\r\n", - "100%|██████████████████████████████████████| 13.2k/13.2k [00:00<00:00, 47.5MB/s]\r\n" - ] - } - ], + "outputs": [], "source": [ "!gdown 1G9WKV8BbGFx5JySQoRQrZ3Y8c_Lg9q3N" ] }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "id": "Pg1r0Rq14b9f", - "ExecuteTime": { - "end_time": "2023-11-13T18:05:19.754435822Z", - "start_time": "2023-11-13T18:05:19.383326383Z" - } - }, - "outputs": [ - { - "ename": "ModuleNotFoundError", - "evalue": "No module named 'mediapipe'", - "output_type": "error", - "traceback": [ - "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[0;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", - "Cell \u001B[0;32mIn[39], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01msupport\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;241m*\u001B[39m\n", - "File \u001B[0;32m~/develop/personal/pythonpescara/python-beginners-workshop-2023/support.py:2\u001B[0m\n\u001B[1;32m 1\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mnumpy\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mnp\u001B[39;00m\n\u001B[0;32m----> 2\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmediapipe\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mmp\u001B[39;00m\n\u001B[1;32m 3\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mcv2\u001B[39;00m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mrequests\u001B[39;00m\n", - "\u001B[0;31mModuleNotFoundError\u001B[0m: No module named 'mediapipe'" - ] - } - ], - "source": [ - "from support import *" - ] - }, { "cell_type": "code", "execution_count": null, @@ -1531,7 +1098,9 @@ }, "outputs": [], "source": [ - "options=[(action.name,action.value) for action in Action]\n", + "from support import *\n", + "\n", + "options=[(action.name, action.value) for action in Action]\n", "output, button, box, menu = create_dropdown(options)\n", "\n", "def on_button_clicked(b):\n", @@ -1587,19 +1156,18 @@ " action = Action.Rock\n", " elif p['gesture'] == 'five':\n", " action = Action.Paper\n", - " elif (p['gesture'] == 'three') or (p['gesture']=='yeah'):\n", + " elif p['gesture'] == 'three' or p['gesture'] == 'yeah':\n", " action = Action.Scissors\n", - " elif (p['gesture'] == 'rock') :\n", + " elif p['gesture'] == 'rock':\n", " action = Action.Lizard\n", - " elif (p['gesture'] == 'four'):\n", + " elif p['gesture'] == 'four':\n", " action = Action.Spock\n", " if action is not None:\n", " computer_action = get_computer_selection()\n", " game_results.append(determine_winner(action, computer_action))\n", " counter += 1\n", " print_game_results(game_results)\n", - " old_action=action\n", - "\n", + " break\n", " if counter>=num_games:\n", " break\n", " except Exception as err:\n", @@ -1624,7 +1192,7 @@ }, "outputs": [], "source": [ - "start_game(num_games=5)" + "start_game(num_games=3)" ] } ], diff --git a/support.py b/support.py index 547c599..f4385e3 100644 --- a/support.py +++ b/support.py @@ -7,288 +7,335 @@ ###################################### + def create_dropdown(actions): - menu = widgets.Dropdown( - options=actions , - description='Chose:') - output = widgets.Output(layout={'border': '1px solid black'}) + menu = widgets.Dropdown(options=actions, description="Chose:") + output = widgets.Output(layout={"border": "1px solid black"}) + + button = widgets.Button(description="Play!", button_style="success", icon="check") + box = widgets.VBox([menu, button, output]) + return output, button, box, menu - button = widgets.Button(description="Play!", button_style='success', icon='check') - box = widgets.VBox([menu, button, output]) - return output, button, box, menu ######################################## + def download_dataset(): - url = "https://raw.githubusercontent.com/ntu-rris/google-mediapipe/main/data/gesture_train.csv" - resp = requests.get(url) - with open('./gesture_train.csv', 'wb') as f: - f.write(resp.content) + url = "https://raw.githubusercontent.com/ntu-rris/google-mediapipe/main/data/gesture_train.csv" + resp = requests.get(url) + with open("./gesture_train.csv", "wb") as f: + f.write(resp.content) + download_dataset() ######################################## # Define default camera intrinsic -img_width = 640 +img_width = 640 img_height = 480 intrin_default = { - 'fx': img_width*0.9, # Approx 0.7w < f < w https://www.learnopencv.com/approximate-focal-length-for-webcams-and-cell-phone-cameras/ - 'fy': img_width*0.9, - 'cx': img_width*0.5, # Approx center of image - 'cy': img_height*0.5, - 'width': img_width, + "fx": img_width + * 0.9, # Approx 0.7w < f < w https://www.learnopencv.com/approximate-focal-length-for-webcams-and-cell-phone-cameras/ + "fy": img_width * 0.9, + "cx": img_width * 0.5, # Approx center of image + "cy": img_height * 0.5, + "width": img_width, } ######################################### + class GestureRecognition: - import numpy as np - import mediapipe as mp - import cv2 - def __init__(self): - # 11 types of gesture 'name':class label - self.gesture = { - 'fist':0,'one':1,'two':2,'three':3,'four':4,'five':5,'six':6, - 'rock':7,'spiderman':8,'yeah':9,'ok':10, - } + import numpy as np + import mediapipe as mp + import cv2 + + def __init__(self): + # 11 types of gesture 'name':class label + self.gesture = { + "fist": 0, + "one": 1, + "two": 2, + "three": 3, + "four": 4, + "five": 5, + "six": 6, + "rock": 7, + "spiderman": 8, + "yeah": 9, + "ok": 10, + } + + # Load training data + file = np.genfromtxt("./gesture_train.csv", delimiter=",") + # Extract input joint angles + angle = file[:, :-1].astype(np.float32) + # Extract output class label + label = file[:, -1].astype(np.float32) + # Use OpenCV KNN + self.knn = cv2.ml.KNearest_create() + self.knn.train(angle, cv2.ml.ROW_SAMPLE, label) + + def eval(self, angle): + # Use KNN for gesture recognition + data = np.asarray([angle], dtype=np.float32) + ret, results, neighbours, dist = self.knn.findNearest(data, 3) + idx = int(results[0][0]) # Index of class label + + return list(self.gesture)[idx] # Return name of class label + - # Load training data - file = np.genfromtxt('./gesture_train.csv', delimiter=',') - # Extract input joint angles - angle = file[:,:-1].astype(np.float32) - # Extract output class label - label = file[:, -1].astype(np.float32) - # Use OpenCV KNN - self.knn = cv2.ml.KNearest_create() - self.knn.train(angle, cv2.ml.ROW_SAMPLE, label) - - def eval(self, angle): - # Use KNN for gesture recognition - data = np.asarray([angle], dtype=np.float32) - ret, results, neighbours ,dist = self.knn.findNearest(data, 3) - idx = int(results[0][0]) # Index of class label - - return list(self.gesture)[idx] # Return name of class label ##################################### + class MediaPipeHand: - def __init__(self, static_image_mode=True, max_num_hands=1, - model_complexity=1, intrin=None): - self.max_num_hands = max_num_hands - if intrin is None: - self.intrin = intrin_default - else: - self.intrin = intrin - - # Access MediaPipe Solutions Python API - mp_hands = mp.solutions.hands - # help(mp_hands.Hands) - - # Initialize MediaPipe Hands - # static_image_mode: - # For video processing set to False: - # Will use previous frame to localize hand to reduce latency - # For unrelated images set to True: - # To allow hand detection to run on every input images - - # max_num_hands: - # Maximum number of hands to detect - - # model_complexity: - # Complexity of the hand landmark model: 0 or 1. - # Landmark accuracy as well as inference latency generally - # go up with the model complexity. Default to 1. - - # min_detection_confidence: - # Confidence value [0,1] from hand detection model - # for detection to be considered successful - - # min_tracking_confidence: - # Minimum confidence value [0,1] from landmark-tracking model - # for hand landmarks to be considered tracked successfully, - # or otherwise hand detection will be invoked automatically on the next input image. - # Setting it to a higher value can increase robustness of the solution, - # at the expense of a higher latency. - # Ignored if static_image_mode is true, where hand detection simply runs on every image. - - self.pipe = mp_hands.Hands( - static_image_mode=static_image_mode, - max_num_hands=max_num_hands, - model_complexity=model_complexity, - min_detection_confidence=0.5, - min_tracking_confidence=0.5) - - # Define hand parameter - self.param = [] - for i in range(max_num_hands): - p = { - 'keypt' : np.zeros((21,2)), # 2D keypt in image coordinate (pixel) - 'joint' : np.zeros((21,3)), # 3D joint in camera coordinate (m) - 'class' : None, # Left / right / none hand - 'score' : 0, # Probability of predicted handedness (always>0.5, and opposite handedness=1-score) - 'angle' : np.zeros(15), # Flexion joint angles in degree - 'gesture' : None, # Type of hand gesture - 'rvec' : np.zeros(3), # Global rotation vector Note: this term is only used for solvepnp initialization - 'tvec' : np.asarray([0,0,0.6]), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve - 'fps' : -1, # Frame per sec - # https://github.com/google/mediapipe/issues/1351 - # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image - # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image - } - self.param.append(p) - - - def result_to_param(self, result, img): - # Convert mediapipe result to my own param - img_height, img_width, _ = img.shape - - # Reset param - for p in self.param: - p['class'] = None - - if result.multi_hand_landmarks is not None: - # Loop through different hands - for i, res in enumerate(result.multi_handedness): - if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand - self.param[i]['class'] = res.classification[0].label - self.param[i]['score'] = res.classification[0].score - - # Loop through different hands - for i, res in enumerate(result.multi_hand_landmarks): - if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand - # Loop through 21 landmark for each hand - for j, lm in enumerate(res.landmark): - self.param[i]['keypt'][j,0] = lm.x * img_width # Convert normalized coor to pixel [0,1] -> [0,width] - self.param[i]['keypt'][j,1] = lm.y * img_height # Convert normalized coor to pixel [0,1] -> [0,height] - - # Ignore it https://github.com/google/mediapipe/issues/1320 - # self.param[i]['visible'][j] = lm.visibility - # self.param[i]['presence'][j] = lm.presence - - if result.multi_hand_world_landmarks is not None: - for i, res in enumerate(result.multi_hand_world_landmarks): - if i>self.max_num_hands-1: break # Note: Need to check if exceed max number of hand - # Loop through 21 landmark for each hand - for j, lm in enumerate(res.landmark): - self.param[i]['joint'][j,0] = lm.x - self.param[i]['joint'][j,1] = lm.y - self.param[i]['joint'][j,2] = lm.z - - # Convert relative 3D joint to angle - self.param[i]['angle'] = self.convert_joint_to_angle(self.param[i]['joint']) - # Convert relative 3D joint to camera coordinate - self.convert_joint_to_camera_coor(self.param[i], self.intrin) - - return self.param - - - def convert_joint_to_angle(self, joint): - # Get direction vector of bone from parent to child - v1 = joint[[0,1,2,3,0,5,6,7,0,9,10,11,0,13,14,15,0,17,18,19],:] # Parent joint - v2 = joint[[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],:] # Child joint - v = v2 - v1 # [20,3] - # Normalize v - v = v/np.linalg.norm(v, axis=1)[:, np.newaxis] - - # Get angle using arcos of dot product - angle = np.arccos(np.einsum('nt,nt->n', - v[[0,1,2,4,5,6,8,9,10,12,13,14,16,17,18],:], - v[[1,2,3,5,6,7,9,10,11,13,14,15,17,18,19],:])) # [15,] - - return np.degrees(angle) # Convert radian to degree - - - def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True): - # MediaPipe version 0.8.9.1 onwards: - # Given real-world 3D joint centered at middle MCP joint -> J_origin - # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec, - # We need to find the unknown translation vector -> tvec = [tx,ty,tz] - # Such that when J_camera is projected to the 2D image plane - # It matches the 2D keypoint locations - - # Considering all 21 keypoints, - # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns - # Since the equations are linear wrt [tx,ty,tz] - # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz] - - # Consider a single keypoint (pixel x) and joint (X,Y,Z) - # Using the perspective projection eq: - # (x - cx)/fx = (X + tx) / (Z + tz) - # Similarly for pixel y: - # (y - cy)/fy = (Y + ty) / (Z + tz) - # Rearranging the above linear equations by keeping constants to the right hand side: - # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z - # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z - # Therefore, we can factor out the unknowns and form a matrix eq: - # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z] - # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z] - # [tz] - - idx = [i for i in range(21)] # Use all landmarks - - if use_solvepnp: - # Method 1: OpenCV solvePnP - fx, fy = intrin['fx'], intrin['fy'] - cx, cy = intrin['cx'], intrin['cy'] - intrin_mat = np.asarray([[fx,0,cx],[0,fy,cy],[0,0,1]]) - dist_coeff = np.zeros(4) - - ret, param['rvec'], param['tvec'] = cv2.solvePnP( - param['joint'][idx], param['keypt'][idx], - intrin_mat, dist_coeff, param['rvec'], param['tvec'], - useExtrinsicGuess=True) - # Add tvec to all joints - param['joint'] += param['tvec'] - - else: - # Method 2: - A = np.zeros((len(idx),2,3)) - b = np.zeros((len(idx),2)) - - A[:,0,0] = intrin['fx'] - A[:,1,1] = intrin['fy'] - A[:,0,2] = -(param['keypt'][idx,0] - intrin['cx']) - A[:,1,2] = -(param['keypt'][idx,1] - intrin['cy']) - - b[:,0] = -intrin['fx'] * param['joint'][idx,0] \ - + (param['keypt'][idx,0] - intrin['cx']) * param['joint'][idx,2] - b[:,1] = -intrin['fy'] * param['joint'][idx,1] \ - + (param['keypt'][idx,1] - intrin['cy']) * param['joint'][idx,2] - - A = A.reshape(-1,3) # [8,3] - b = b.flatten() # [8] - - # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides - x = np.linalg.solve(A.T @ A, A.T @ b) - # Add tvec to all joints - param['joint'] += x - - - - def forward(self, img): - # Extract result - result = self.pipe.process(img) - - # Convert result to my own param - param = self.result_to_param(result, img) - - return param + def __init__( + self, static_image_mode=True, max_num_hands=1, model_complexity=1, intrin=None + ): + self.max_num_hands = max_num_hands + if intrin is None: + self.intrin = intrin_default + else: + self.intrin = intrin + + # Access MediaPipe Solutions Python API + mp_hands = mp.solutions.hands + # help(mp_hands.Hands) + + # Initialize MediaPipe Hands + # static_image_mode: + # For video processing set to False: + # Will use previous frame to localize hand to reduce latency + # For unrelated images set to True: + # To allow hand detection to run on every input images + + # max_num_hands: + # Maximum number of hands to detect + + # model_complexity: + # Complexity of the hand landmark model: 0 or 1. + # Landmark accuracy as well as inference latency generally + # go up with the model complexity. Default to 1. + + # min_detection_confidence: + # Confidence value [0,1] from hand detection model + # for detection to be considered successful + + # min_tracking_confidence: + # Minimum confidence value [0,1] from landmark-tracking model + # for hand landmarks to be considered tracked successfully, + # or otherwise hand detection will be invoked automatically on the next input image. + # Setting it to a higher value can increase robustness of the solution, + # at the expense of a higher latency. + # Ignored if static_image_mode is true, where hand detection simply runs on every image. + + self.pipe = mp_hands.Hands( + static_image_mode=static_image_mode, + max_num_hands=max_num_hands, + model_complexity=model_complexity, + min_detection_confidence=0.5, + min_tracking_confidence=0.5, + ) + + # Define hand parameter + self.param = [] + for i in range(max_num_hands): + p = { + "keypt": np.zeros((21, 2)), # 2D keypt in image coordinate (pixel) + "joint": np.zeros((21, 3)), # 3D joint in camera coordinate (m) + "class": None, # Left / right / none hand + "score": 0, # Probability of predicted handedness (always>0.5, and opposite handedness=1-score) + "angle": np.zeros(15), # Flexion joint angles in degree + "gesture": None, # Type of hand gesture + "rvec": np.zeros( + 3 + ), # Global rotation vector Note: this term is only used for solvepnp initialization + "tvec": np.asarray( + [0, 0, 0.6] + ), # Global translation vector (m) Note: Init z direc to some +ve dist (i.e. in front of camera), to prevent solvepnp from wrongly estimating z as -ve + "fps": -1, # Frame per sec + # https://github.com/google/mediapipe/issues/1351 + # 'visible' : np.zeros(21), # Visibility: Likelihood [0,1] of being visible (present and not occluded) in the image + # 'presence': np.zeros(21), # Presence: Likelihood [0,1] of being present in the image or if its located outside the image + } + self.param.append(p) + + def result_to_param(self, result, img): + # Convert mediapipe result to my own param + img_height, img_width, _ = img.shape + + # Reset param + for p in self.param: + p["class"] = None + + if result.multi_hand_landmarks is not None: + # Loop through different hands + for i, res in enumerate(result.multi_handedness): + if i > self.max_num_hands - 1: + break # Note: Need to check if exceed max number of hand + self.param[i]["class"] = res.classification[0].label + self.param[i]["score"] = res.classification[0].score + + # Loop through different hands + for i, res in enumerate(result.multi_hand_landmarks): + if i > self.max_num_hands - 1: + break # Note: Need to check if exceed max number of hand + # Loop through 21 landmark for each hand + for j, lm in enumerate(res.landmark): + self.param[i]["keypt"][j, 0] = ( + lm.x * img_width + ) # Convert normalized coor to pixel [0,1] -> [0,width] + self.param[i]["keypt"][j, 1] = ( + lm.y * img_height + ) # Convert normalized coor to pixel [0,1] -> [0,height] + + # Ignore it https://github.com/google/mediapipe/issues/1320 + # self.param[i]['visible'][j] = lm.visibility + # self.param[i]['presence'][j] = lm.presence + + if result.multi_hand_world_landmarks is not None: + for i, res in enumerate(result.multi_hand_world_landmarks): + if i > self.max_num_hands - 1: + break # Note: Need to check if exceed max number of hand + # Loop through 21 landmark for each hand + for j, lm in enumerate(res.landmark): + self.param[i]["joint"][j, 0] = lm.x + self.param[i]["joint"][j, 1] = lm.y + self.param[i]["joint"][j, 2] = lm.z + + # Convert relative 3D joint to angle + self.param[i]["angle"] = self.convert_joint_to_angle( + self.param[i]["joint"] + ) + # Convert relative 3D joint to camera coordinate + self.convert_joint_to_camera_coor(self.param[i], self.intrin) + + return self.param + + def convert_joint_to_angle(self, joint): + # Get direction vector of bone from parent to child + v1 = joint[ + [0, 1, 2, 3, 0, 5, 6, 7, 0, 9, 10, 11, 0, 13, 14, 15, 0, 17, 18, 19], : + ] # Parent joint + v2 = joint[ + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], : + ] # Child joint + v = v2 - v1 # [20,3] + # Normalize v + v = v / np.linalg.norm(v, axis=1)[:, np.newaxis] + + # Get angle using arcos of dot product + angle = np.arccos( + np.einsum( + "nt,nt->n", + v[[0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 16, 17, 18], :], + v[[1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19], :], + ) + ) # [15,] + + return np.degrees(angle) # Convert radian to degree + + def convert_joint_to_camera_coor(self, param, intrin, use_solvepnp=True): + # MediaPipe version 0.8.9.1 onwards: + # Given real-world 3D joint centered at middle MCP joint -> J_origin + # To estimate the 3D joint in camera coordinate -> J_camera = J_origin + tvec, + # We need to find the unknown translation vector -> tvec = [tx,ty,tz] + # Such that when J_camera is projected to the 2D image plane + # It matches the 2D keypoint locations + + # Considering all 21 keypoints, + # Each keypoints will form 2 eq, in total we have 42 eq 3 unknowns + # Since the equations are linear wrt [tx,ty,tz] + # We can solve the unknowns using linear algebra A.x = b, where x = [tx,ty,tz] + + # Consider a single keypoint (pixel x) and joint (X,Y,Z) + # Using the perspective projection eq: + # (x - cx)/fx = (X + tx) / (Z + tz) + # Similarly for pixel y: + # (y - cy)/fy = (Y + ty) / (Z + tz) + # Rearranging the above linear equations by keeping constants to the right hand side: + # fx.tx - (x - cx).tz = -fx.X + (x - cx).Z + # fy.ty - (y - cy).tz = -fy.Y + (y - cy).Z + # Therefore, we can factor out the unknowns and form a matrix eq: + # [fx 0 (x - cx)][tx] [-fx.X + (x - cx).Z] + # [ 0 fy (y - cy)][ty] = [-fy.Y + (y - cy).Z] + # [tz] + + idx = [i for i in range(21)] # Use all landmarks + + if use_solvepnp: + # Method 1: OpenCV solvePnP + fx, fy = intrin["fx"], intrin["fy"] + cx, cy = intrin["cx"], intrin["cy"] + intrin_mat = np.asarray([[fx, 0, cx], [0, fy, cy], [0, 0, 1]]) + dist_coeff = np.zeros(4) + + ret, param["rvec"], param["tvec"] = cv2.solvePnP( + param["joint"][idx], + param["keypt"][idx], + intrin_mat, + dist_coeff, + param["rvec"], + param["tvec"], + useExtrinsicGuess=True, + ) + # Add tvec to all joints + param["joint"] += param["tvec"] + + else: + # Method 2: + A = np.zeros((len(idx), 2, 3)) + b = np.zeros((len(idx), 2)) + + A[:, 0, 0] = intrin["fx"] + A[:, 1, 1] = intrin["fy"] + A[:, 0, 2] = -(param["keypt"][idx, 0] - intrin["cx"]) + A[:, 1, 2] = -(param["keypt"][idx, 1] - intrin["cy"]) + + b[:, 0] = ( + -intrin["fx"] * param["joint"][idx, 0] + + (param["keypt"][idx, 0] - intrin["cx"]) * param["joint"][idx, 2] + ) + b[:, 1] = ( + -intrin["fy"] * param["joint"][idx, 1] + + (param["keypt"][idx, 1] - intrin["cy"]) * param["joint"][idx, 2] + ) + + A = A.reshape(-1, 3) # [8,3] + b = b.flatten() # [8] + + # Use the normal equation AT.A.x = AT.b to minimize the sum of the sq diff btw left and right sides + x = np.linalg.solve(A.T @ A, A.T @ b) + # Add tvec to all joints + param["joint"] += x + + def forward(self, img): + # Extract result + result = self.pipe.process(img) + + # Convert result to my own param + param = self.result_to_param(result, img) + + return param + ########################################## try: - from google.colab.output import eval_js - colab = True + from google.colab.output import eval_js + + colab = True except: - colab = False + colab = False if colab: - from IPython.display import display, Javascript - from google.colab.output import eval_js - from base64 import b64decode - from PIL import Image as PIL_Image - - def take_photo(quality=0.8): - js = Javascript(''' + from IPython.display import display, Javascript + from google.colab.output import eval_js + from base64 import b64decode + from PIL import Image as PIL_Image + + def take_photo(quality=0.8): + js = Javascript( + """ async function takePhoto(quality) { const div = document.createElement('div'); const capture = document.createElement('button'); @@ -318,48 +365,47 @@ def take_photo(quality=0.8): div.remove(); return canvas.toDataURL('image/jpeg', quality); } - ''') - display(js) - data = eval_js('takePhoto({})'.format(quality)) - binary = b64decode(data.split(',')[1]) - - - image = PIL_Image.open(io.BytesIO(binary)) - image_np = np.array(image) - return image_np + """ + ) + display(js) + data = eval_js("takePhoto({})".format(quality)) + binary = b64decode(data.split(",")[1]) + + image = PIL_Image.open(io.BytesIO(binary)) + image_np = np.array(image) + return image_np else: - def take_photo(filename='photo.jpg', quality=0.8): - cam = cv2.VideoCapture(0) - - cv2.namedWindow("test") - img_counter = 0 + def take_photo(filename="photo.jpg", quality=0.8): + cam = cv2.VideoCapture(0) - while True: - ret, frame = cam.read() - # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) - if not ret: - print("failed to grab frame") - break - cv2.imshow("test", frame) + cv2.namedWindow("test") - k = cv2.waitKey(1) - if k%256 == 27 or k%256 == 32 : - # ESC pressed - break + img_counter = 0 - cam.release() + while True: + ret, frame = cam.read() + # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses) + if not ret: + print("failed to grab frame") + break + cv2.imshow("test", frame) - cv2.destroyAllWindows() + k = cv2.waitKey(1) + if k % 256 == 27 or k % 256 == 32: + # ESC pressed + break - # Preprocess image - img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) - # Flip image for 3rd person view - img = cv2.flip(img, 1) + cam.release() - # To improve performance, optionally mark image as not writeable to pass by reference - img.flags.writeable = False + cv2.destroyAllWindows() - return img + # Preprocess image + img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + # Flip image for 3rd person view + img = cv2.flip(img, 1) + # To improve performance, optionally mark image as not writeable to pass by reference + img.flags.writeable = False + return img From 3a4da85fd408f9cec51e6e9a4b844e33e66a70d5 Mon Sep 17 00:00:00 2001 From: Moreno Mazzocchetti Date: Mon, 20 Nov 2023 10:31:31 +0100 Subject: [PATCH 6/6] Update Live Coding Completo.ipynb Co-authored-by: Paolo Melchiorre --- Live Coding Completo.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Live Coding Completo.ipynb b/Live Coding Completo.ipynb index 57d05b4..9b4dd1e 100644 --- a/Live Coding Completo.ipynb +++ b/Live Coding Completo.ipynb @@ -1016,7 +1016,7 @@ "id": "aae3e00d" }, "source": [ - "45### Utilizziamo un'interfaccia grafica!\n", + "### Utilizziamo un'interfaccia grafica!\n", "\n", "Nella cella successiva andremo ad utilizzare una feature di Jupyter che ci consente di creare al volo un menu a tendina (dopotutto questa è una pagina HTML, no?) e di associare un comportamento alla scelta della voce dal menu!\n", "\n",