[PYTHON] Simulation d'escalator

introduction

Bonjour, toi qui fais un lycéen de trois ans. Ceci est mon premier article, et je voudrais vous présenter une simulation d'escalator. Le langage est Python3.

À propos de l'escalator

Les utilisateurs d'escalator sont à peu près divisés en deux types: ceux qui s'arrêtent et ceux qui marchent. Au Japon, la position pour s'arrêter diffère selon les régions, comme l'est du Japon à gauche et l'ouest du Japon à droite, et le même phénomène peut être observé à l'étranger. En fait, la position où l'escalator s'arrête est déterminée par l'équilibre de Nash en théorie des jeux. Les personnes immobiles se sentent stressées lorsqu'elles sont heurtées par une personne qui marche par derrière, et elles veulent rouler d'un côté différent à partir de la prochaine fois.

Présentation de la simulation

Dans cette simulation, la moitié des personnes qui s'arrêtent et la moitié des personnes qui marchent sont générées, et si la position initiale est à gauche ou à droite est définie au hasard. De plus, nous mesurons le goût de tous les utilisateurs pour les positions gauche et droite, et déterminons le prochain utilisateur en fonction de l'ampleur de la valeur. Par ces opérations, la position utilisée par la personne qui s'arrête et la position utilisée par la personne qui marche convergent d'un côté de l'escalator.

Code source / description

Ensuite, le code source et son explication sont décrits ci-dessous.

Définition de l'utilisateur

Tout d'abord, définissez les classes de la personne qui s'arrête (= StandHuman) et de la personne qui marche (= WalkHuman). La seule différence entre les deux est de savoir s'il faut s'arrêter ou marcher (= actif) et la vitesse (= v, je pense que la vitesse s est plus appropriée physiquement).

escalator.py


class StandHuman:

    def __init__(self):
        self.active = False
        self.v = 0 #speed
        self.x = 0 #position(left/right)
        self.l_like = 0 #how much a human like to ride on the left
        self.r_like = 0 #how much a human like to ride on the right

class WalkHuman:

    def __init__(self):
        self.active = True
        self.v =1 #speed
        self.x = 0 #position(left/right)
        self.l_like = 0 #how much a human like to ride on the left
        self.r_like = 0 #how much a human like to ride on the right

Génération d'utilisateurs

Nombre de personnes à générer à partir de 0 (= NUMBER_OF_HUMANS) Préparez une liste avec des chaînes de nombres entiers de -1 comme éléments, mélangez les éléments de la liste, puis jugez si les éléments sont pairs ou impairs, afin que tous les utilisateurs puissent les utiliser. La moitié des gens s'arrêtent et la moitié des gens marchent en donnant le hasard dans l'ordre de faire.

escalator.py


def human_random():
    odd_or_even = list(range(NUMBER_OF_HUMANS))
    random.shuffle(odd_or_even)
    for i in range(NUMBER_OF_HUMANS):
        if odd_or_even[i] % 2 == 0:
            human = StandHuman()
        else:
            human = WalkHuman()
        human_list.append(human)

Déterminer la position (gauche et droite) pour monter sur l'escalator

La position à monter sur l'escalator est déterminée en fonction du goût de chacun des côtés gauche et droit à ce moment-là. Si le goût de gauche est élevé, le goût de gauche est déterminé, si le goût de droite est élevé, le droit est déterminé, et si le goût de gauche et de droite sont les mêmes, la gauche et la droite sont déterminées au hasard. Puisque les valeurs initiales du goût gauche et droit sont toutes deux réglées sur 0, la gauche et la droite seront déterminées aléatoirement lors de la première utilisation.

escalator.py


def side_decision(human):
    l = human.l_like
    r = human.r_like
    if l > r:
        human.x = 0
    elif l < r:
        human.x = 1
    else:
        random_x = random.random()
        if random_x <= 0.5:
            human.x = 0
        else:
            human.x = 1

Mettez l'utilisateur sur l'escalator

La fonction add_human met uniquement l'utilisateur sur l'escalator. Cependant, pour plus de commodité, l'escalator comporte quatre rangées: (1) à gauche pour les personnes qui s'arrêtent, (2) à gauche pour les personnes qui marchent, (3) à droite pour les personnes qui s'arrêtent et (4) à droite pour les personnes qui marchent.

escalator.py


def add_human(human):
    if human.active == False:
        if human.x == 0: #if left
            escalator[0][0] = human
        else: #if right
            escalator[2][0] = human
    else:
        if human.x == 0: #if left
            escalator[1][0] = human
        else: #if right
            escalator[3][0] = human

Déplacer l'escalator

Déplacez l'escalator d'une étape. En tant que programme réel, les utilisateurs Il est remonté d'un cran et remis à 0 (valeur initiale) dans le cas du cran le plus élevé.

escalator.py


def shift():
    for i in range(STEPS-1):
        escalator[0][STEPS-i-1] = escalator[0][STEPS-i-2]
        escalator[1][STEPS-i-1] = escalator[1][STEPS-i-2]
        escalator[2][STEPS-i-1] = escalator[2][STEPS-i-2]
        escalator[3][STEPS-i-1] = escalator[3][STEPS-i-2]
    escalator[0][0] = 0
    escalator[1][0] = 0
    escalator[2][0] = 0
    escalator[3][0] = 0

Confirmation de la collision / Traitement au moment de la collision

La fonction crash gère le cas d'une collision. Ici, la position (nombre d'étages) au moment de la collision influe sur le stress ressenti par l'utilisateur, et plus l'étage est bas, plus il est facile de ressentir le stress. De plus, les deux processus sont séparés afin de maintenir le caractère aléatoire du stress ressenti par ceux qui sont debout et ceux qui marchent. Le stress ressenti par l'utilisateur conduit directement à une diminution de la favorabilité. La fonction crash_checker détecte une collision et passe l'utilisateur en collision à la fonction crash.

escalator.py


def crash(front, front_position, behind):
    x = random.random() * STEPS
    if x <= 1-(front_position + 1)/STEPS: 
        if front.x == 0: #if left
            front.l_like -= x
        else: #if right
            front.r_like -= x
    y = random.random() * STEPS
    if y <= 1-(front_position + 1)/STEPS:
        if front.x == 0: #if left
            behind.l_like -= y
        else: #if right
            behind.r_like -= y
        
def crash_checker():
    for i in range(STEPS): #left
        if escalator[0][i] != 0 and escalator[1][i] != 0:
            crash(escalator[0][i], i, escalator[1][i])
    for i in range(STEPS): #right
        if escalator[2][i] != 0 and escalator[3][i] != 0:
            crash(escalator[2][i], i, escalator[3][i])

Traitement uniquement pour les personnes qui marchent

Puisqu'une personne qui marche a besoin d'un processus de «marche», une nouvelle fonction de marche est fournie en plus de la fonction de changement de vitesse qui déplace l'escalator.

escalator.py


def end_checker_for_walker(): 
    escalator[1][STEPS-1] = 0
    escalator[3][STEPS-1] = 0

def walk():
    for i in range(STEPS):
        l = escalator[1][i]
        r = escalator[3][i]
        if l != 0:
            escalator[1][STEPS-i-1+(l.v)] = escalator[1][STEPS-i-1] 
        if r != 0:
            escalator[3][STEPS-i-1+(r.v)] = escalator[3][STEPS-i-1]

Code source complet

Tout est question de code source. Le code source complet est le suivant.

escalator.py


import random
import pandas as pd

NUMBER_OF_HUMANS = 100
TIME_END = 1000000
STEPS = 100

human_list = list()
escalator = [[0] * STEPS for i in range(4)] #[[sl], [wl], [sr], [wr]]

class StandHuman:

    def __init__(self):
        self.active = False
        self.v = 0 #speed
        self.x = 0 #position(left/right)
        self.l_like = 0 #how much a human like to ride on the left
        self.r_like = 0 #how much a human like to ride on the right

class WalkHuman:

    def __init__(self):
        self.active = True
        self.v =1 #speed
        self.x = 0 #position(left/right)
        self.l_like = 0 #how much a human like to ride on the left
        self.r_like = 0 #how much a human like to ride on the right

def human_random():
    odd_or_even = list(range(NUMBER_OF_HUMANS))
    random.shuffle(odd_or_even)
    for i in range(NUMBER_OF_HUMANS):
        if odd_or_even[i] % 2 == 0:
            human = StandHuman()
        else:
            human = WalkHuman()
        human_list.append(human)

def shift():
    for i in range(STEPS-1):
        escalator[0][STEPS-i-1] = escalator[0][STEPS-i-2]
        escalator[1][STEPS-i-1] = escalator[1][STEPS-i-2]
        escalator[2][STEPS-i-1] = escalator[2][STEPS-i-2]
        escalator[3][STEPS-i-1] = escalator[3][STEPS-i-2]
    escalator[0][0] = 0
    escalator[1][0] = 0
    escalator[2][0] = 0
    escalator[3][0] = 0

def crash(front, front_position, behind):
    x = random.random() * STEPS
    if x <= 1-(front_position + 1)/STEPS: 
        if front.x == 0: #if left
            front.l_like -= x
        else: #if right
            front.r_like -= x
    y = random.random() * STEPS
    if y <= 1-(front_position + 1)/STEPS:
        if front.x == 0: #if left
            behind.l_like -= y
        else: #if right
            behind.r_like -= y
        
def crash_checker():
    for i in range(STEPS): #left
        if escalator[0][i] != 0 and escalator[1][i] != 0:
            crash(escalator[0][i], i, escalator[1][i])
    for i in range(STEPS): #right
        if escalator[2][i] != 0 and escalator[3][i] != 0:
            crash(escalator[2][i], i, escalator[3][i])

def walk():
    for i in range(STEPS):
        l = escalator[1][i]
        r = escalator[3][i]
        if l != 0:
            escalator[1][STEPS-i-1+(l.v)] = escalator[1][STEPS-i-1] 
        if r != 0:
            escalator[3][STEPS-i-1+(r.v)] = escalator[3][STEPS-i-1]

def side_decision(human):
    l = human.l_like
    r = human.r_like
    if l > r:
        human.x = 0
    elif l < r:
        human.x = 1
    else:
        random_x = random.random()
        if random_x <= 0.5:
            human.x = 0
        else:
            human.x = 1

def add_human(human):
    if human.active == False:
        if human.x == 0: #if left
            escalator[0][0] = human
        else: #if right
            escalator[2][0] = human
    else:
        if human.x == 0: #if left
            escalator[1][0] = human
        else: #if right
            escalator[3][0] = human
def main():
    for i in range(TIME_END):
        shift() 
        crash_checker()
        walk() 
        crash_checker()
        h = human_list[i % NUMBER_OF_HUMANS]
        side_decision(h)
        add_human(h) 

human_random()
main()

résultat de la simulation

Cette fois, le nombre d'essais a été fixé à 1 million, le nombre d'utilisateurs a été défini sur 100 (debout: 50, étapes: 50) et le nombre d'étages d'escalier mécanique a été défini sur 100. En regardant les résultats ci-dessous, j'ai l'impression qu'ils ont bien convergé.

Résultats de l'escalator

Vous trouverez ci-dessous une simple visualisation de l'escalier mécanique lorsque le nombre d'essais spécifié est atteint. Nous affichons également le nombre total de personnes debout et marchant dans les colonnes gauche et droite et le ratio des deux. (S: personnes qui restent immobiles, w: personnes qui marchent, 0: gratuit)

| s 0 | 0 0 |
| 0 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 w |
| 0 0 | 0 w |
| s 0 | 0 w |
| 0 0 | 0 w |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 w |
| s 0 | 0 w |
| s 0 | 0 w |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 0 | 0 w |
| s 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 w |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 w |
| 0 0 | 0 w |
| s 0 | 0 0 |
| s 0 | 0 w |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 w |
| 0 0 | 0 w |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 w |
| 0 0 | 0 0 |
| 0 0 | 0 w |
| s 0 | 0 0 |
| s 0 | 0 w |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 w |
| 0 w | 0 w |
| 0 0 | 0 w |
| 0 w | 0 0 |
| 0 w | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 w |
| 0 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| s 0 | 0 w |
| 0 0 | 0 0 |
| 0 w | 0 0 |
| 0 0 | 0 w |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| 0 w | 0 w |
| s 0 | 0 0 |
| 0 0 | 0 0 |
| s 0 | 0 w |
| 0 0 | 0 0 |
| s 0 | 0 0 |
| 0 0 | 0 w |
#----------------------------------------------#
WalkHuman/StandHuman of left:  0.1 W:S= 5 50
WalkHuman/StandHuman of right:  34.0 W:S= 34 0

Comparaison de favorabilité (stress)

Tous les utilisateurs (les 100 premières personnes générées) ont comparé les côtés gauche et droit de l'escalier mécanique dans une table (s'ils ne l'aiment pas).

            Left  Right
StandHuman    50      0
WalkHuman      5     45

en conclusion

En conséquence, je pense que c'était une simulation raisonnable. Puisque c'était ma première création de simulation, je pense qu'il y a beaucoup de pièces détachées, mais j'aimerais continuer à m'améliorer autant que possible.

Recommended Posts

Simulation d'escalator
Simulation d'optimisation des enchères
Simulation de double pendule
simulation ambisonique Python
Python - Simulation de mouvement de particules
Simulation de circuit RC
Booster la simulation de courant