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.
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.
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.
Ensuite, le code source et son explication sont décrits ci-dessous.
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
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)
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
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é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
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])
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]
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()
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é.
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
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 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.