|
|
|
<!-- Copyright 2022 by Alexei Bezborodov <AlexeiBv@narod.ru> -->
|
|
|
|
<!-- public domain -->
|
|
|
|
|
|
|
|
<html lang="ru">
|
|
|
|
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<title>Распределение участников по столам</title>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Загрузка скриптов из интернета
|
|
|
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython.min.js"></script>
|
|
|
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython_stdlib.js"></script>
|
|
|
|
-->
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Загрузка скриптов из локальной папки (рядом с файлом html)
|
|
|
|
-->
|
|
|
|
<script type="text/javascript" src="brython.min.js"></script>
|
|
|
|
<script type="text/javascript" src="brython_stdlib.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body onload="brython()">
|
|
|
|
|
|
|
|
<details open>
|
|
|
|
<summary>Начальные данные</summary>
|
|
|
|
<div>
|
|
|
|
<p>
|
|
|
|
<label>Номер распределения:</label>
|
|
|
|
<input id = "step_id" type="number" value="1" step="1"/>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<label>Входные данные:<br/></label>
|
|
|
|
<textarea id="input_data" cols="40" rows="5"></textarea>
|
|
|
|
<p>Данные должны быть в таком формате:<br/>
|
|
|
|
1; ФИО 1; {3,4}<br/>
|
|
|
|
2; ФИО 2; {3,4}<br/>
|
|
|
|
3; ФИО 3; {1,2}<br/>
|
|
|
|
4; ФИО 4; {1,2}<br/>
|
|
|
|
, где первое число - номер посетителя<br/>
|
|
|
|
второе - имя посетителя<br/>
|
|
|
|
третье - номера участников, с которыми посетитель уже знаком<br/>
|
|
|
|
</p>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<button id="load_data">Загрузить</button>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<details open>
|
|
|
|
<summary>Таблица знакомств</summary>
|
|
|
|
<div>
|
|
|
|
<p id="meet_table" class="text-center"></p>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Расстановка</summary>
|
|
|
|
<div>
|
|
|
|
<p>
|
|
|
|
<label>Размеры столов (через запятую):</label>
|
|
|
|
<input id = "table_size"/>
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
<label>Имена столов:</label>
|
|
|
|
<input id = "table_name" value="АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ"/>
|
|
|
|
</p>
|
|
|
|
<textarea id="result_table_txt" cols="40" rows="5"></textarea>
|
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<button id="table_distrib">Расставить по столам</button>
|
|
|
|
<button id="table_distrib_load">Загрузить расстановку</button>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Таблица</summary>
|
|
|
|
<div>
|
|
|
|
<p id="result_table" class="text-center"></p>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Конечные данные</summary>
|
|
|
|
<label>Входные данные для нового шага:<br/></label>
|
|
|
|
<textarea id="output_data" cols="40" rows="5"></textarea>
|
|
|
|
<div>
|
|
|
|
<button id="next_step">Перейти на следующий шаг</button>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
<details>
|
|
|
|
<summary>Полная таблица всех шагов</summary>
|
|
|
|
<label>Входные данные:<br/></label>
|
|
|
|
<textarea id="all_output_data" cols="40" rows="25"></textarea>
|
|
|
|
</details>
|
|
|
|
|
|
|
|
|
|
|
|
<script type="text/python">
|
|
|
|
|
|
|
|
from browser import document, html, window
|
|
|
|
import random
|
|
|
|
|
|
|
|
|
|
|
|
class Table:
|
|
|
|
def __init__(self, a_id, person_set):
|
|
|
|
self.id = a_id
|
|
|
|
self.person_set = person_set
|
|
|
|
|
|
|
|
id = 0
|
|
|
|
person_set = set()
|
|
|
|
|
|
|
|
|
|
|
|
class Person:
|
|
|
|
def __init__(self, beig_id, name, meet_set):
|
|
|
|
self.beig_id = beig_id
|
|
|
|
self.name = name
|
|
|
|
self.meet_set = meet_set
|
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return str(self.beig_id) + ", " + self.name + "\n" + str(self.meet_set)
|
|
|
|
|
|
|
|
beig_id = 0
|
|
|
|
name = ""
|
|
|
|
meet_set = set()
|
|
|
|
|
|
|
|
|
|
|
|
global people
|
|
|
|
people = []
|
|
|
|
|
|
|
|
global tables
|
|
|
|
tables = []
|
|
|
|
|
|
|
|
|
|
|
|
def add_to_all_data(val):
|
|
|
|
document["all_output_data"].value += "\n\n#Шаг " + document["step_id"].value + "\n" + val
|
|
|
|
|
|
|
|
|
|
|
|
def load_input(val):
|
|
|
|
global people
|
|
|
|
people = []
|
|
|
|
input_data = val
|
|
|
|
for p in input_data.split("\n"):
|
|
|
|
if p == "":
|
|
|
|
continue
|
|
|
|
tmp = p.split(";")
|
|
|
|
cur_beig_id = int(tmp[0])
|
|
|
|
cur_name = ""
|
|
|
|
if len(tmp) > 1:
|
|
|
|
cur_name = tmp[1]
|
|
|
|
str_meet_list = []
|
|
|
|
if len(tmp) > 2:
|
|
|
|
str_meet_list = tmp[2].replace(" ", "").replace("{", "").replace("}", "").split(",")
|
|
|
|
cur_meet_list = set()
|
|
|
|
for s in str_meet_list:
|
|
|
|
if len(s) != 0:
|
|
|
|
cur_meet_list = cur_meet_list | {int(s)}
|
|
|
|
p = Person(cur_beig_id, cur_name, cur_meet_list)
|
|
|
|
people.append(p)
|
|
|
|
|
|
|
|
|
|
|
|
def get_present_people():
|
|
|
|
global people
|
|
|
|
return list(filter(lambda p: p.beig_id > 0, people))
|
|
|
|
|
|
|
|
|
|
|
|
def show_meet_table_data():
|
|
|
|
global people
|
|
|
|
|
|
|
|
html = "Всего участников: " + str(len(people)) + "<br/>"
|
|
|
|
html += "Присутствуют участников: " + str(len(get_present_people())) + "<br/>"
|
|
|
|
|
|
|
|
html += "Номер распределения: " + document["step_id"].value + "<br/>"
|
|
|
|
|
|
|
|
meet_count = 0
|
|
|
|
html += "<table border = 1>"
|
|
|
|
# Первая строка
|
|
|
|
html += "<tr>"
|
|
|
|
html += "<td></td>"
|
|
|
|
for p in people:
|
|
|
|
html += "<th" + " title='" + p.name + "'>" + str(abs(p.beig_id)) + "</th>"
|
|
|
|
html += "</tr>"
|
|
|
|
# Остальные строки
|
|
|
|
for p in people:
|
|
|
|
html += "<tr>"
|
|
|
|
html += "<th" + " title='" + p.name + "'>" + str(abs(p.beig_id)) + "</th>"
|
|
|
|
for ip in people:
|
|
|
|
if abs(p.beig_id) in ip.meet_set:
|
|
|
|
html += "<td bgcolor='red'></td>"
|
|
|
|
meet_count += 1
|
|
|
|
else:
|
|
|
|
html += "<td></td>"
|
|
|
|
html += "</tr>"
|
|
|
|
html += "</table>"
|
|
|
|
|
|
|
|
html += "<br/>Знакомств: " + str(meet_count) + "/" + str(len(people) ** 2) + "<br/>"
|
|
|
|
|
|
|
|
document["meet_table"].innerHTML = html
|
|
|
|
|
|
|
|
|
|
|
|
def get_result():
|
|
|
|
global people
|
|
|
|
result = ""
|
|
|
|
for p in people:
|
|
|
|
result += str(p.beig_id) + ";" + p.name + ";"
|
|
|
|
if len(p.meet_set):
|
|
|
|
result += str(p.meet_set)
|
|
|
|
result += "\n"
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def result_table_fill():
|
|
|
|
global tables
|
|
|
|
result_txt = ""
|
|
|
|
for t in tables:
|
|
|
|
result_txt += str(t.id) + ";"
|
|
|
|
if len(t.person_set):
|
|
|
|
result_txt += str(t.person_set)
|
|
|
|
result_txt += "\n"
|
|
|
|
return result_txt
|
|
|
|
|
|
|
|
|
|
|
|
def print_result_table():
|
|
|
|
table_names = document["table_name"].value
|
|
|
|
|
|
|
|
global tables
|
|
|
|
html = ""
|
|
|
|
html += "<table border = 1>"
|
|
|
|
# Первая строка
|
|
|
|
html += "<tr>"
|
|
|
|
html += "<th>Номер стола</th>"
|
|
|
|
html += "<th>Участники</th>"
|
|
|
|
html += "</tr>"
|
|
|
|
# Остальные строки
|
|
|
|
for t in tables:
|
|
|
|
html += "<tr>"
|
|
|
|
if t.id >= len(table_names):
|
|
|
|
html += "<td>" + str(t.id) + "</td>"
|
|
|
|
else:
|
|
|
|
html += "<td>" + str(table_names[t.id]) + "</td>"
|
|
|
|
|
|
|
|
if len(t.person_set):
|
|
|
|
html += "<td>" + str(t.person_set).replace("{", "").replace("}", "") + "</td>"
|
|
|
|
else:
|
|
|
|
html += "<td></td>"
|
|
|
|
html += "</tr>"
|
|
|
|
html += "</table>"
|
|
|
|
document["result_table"].innerHTML = html
|
|
|
|
|
|
|
|
document["result_table_txt"].value = result_table_fill()
|
|
|
|
|
|
|
|
|
|
|
|
def get_person_by_id(id):
|
|
|
|
global people
|
|
|
|
for p in people:
|
|
|
|
if abs(p.beig_id) == id:
|
|
|
|
return p
|
|
|
|
print("Error", id)
|
|
|
|
|
|
|
|
|
|
|
|
def fill_next_table(start_person_id, people_set, table_size_count, people):
|
|
|
|
result_people = [get_person_by_id(start_person_id)]
|
|
|
|
result_set = {start_person_id}
|
|
|
|
|
|
|
|
while len(result_set) < table_size_count:
|
|
|
|
search_success = False
|
|
|
|
for p in people:
|
|
|
|
cur_id = abs(p.beig_id)
|
|
|
|
if cur_id in people_set:
|
|
|
|
continue
|
|
|
|
if cur_id in result_set:
|
|
|
|
continue
|
|
|
|
pers_free = True
|
|
|
|
for ip in result_people:
|
|
|
|
if cur_id in ip.meet_set:
|
|
|
|
pers_free = False
|
|
|
|
break
|
|
|
|
if pers_free:
|
|
|
|
result_set = result_set | {cur_id}
|
|
|
|
result_people.append(p)
|
|
|
|
search_success = True
|
|
|
|
break
|
|
|
|
|
|
|
|
if not search_success:
|
|
|
|
for p in people:
|
|
|
|
cur_id = abs(p.beig_id)
|
|
|
|
if cur_id in people_set:
|
|
|
|
continue
|
|
|
|
if cur_id in result_set:
|
|
|
|
continue
|
|
|
|
result_set = result_set | {cur_id}
|
|
|
|
result_people.append(p)
|
|
|
|
break
|
|
|
|
|
|
|
|
return result_set
|
|
|
|
|
|
|
|
|
|
|
|
def get_beig_id_set(people):
|
|
|
|
result = set()
|
|
|
|
for p in people:
|
|
|
|
result = result | {abs(p.beig_id)}
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
|
|
|
def fill_tables():
|
|
|
|
global tables
|
|
|
|
tables = []
|
|
|
|
cur_table_id = 0
|
|
|
|
|
|
|
|
sort_people = sorted(get_present_people(), key=lambda person: len(person.meet_set))
|
|
|
|
|
|
|
|
all_table_size = 0
|
|
|
|
str_table_size = document["table_size"].value.replace(" ", "").split(",")
|
|
|
|
table_size = []
|
|
|
|
for s in str_table_size:
|
|
|
|
if len(s) != 0:
|
|
|
|
t = int(s)
|
|
|
|
all_table_size += t
|
|
|
|
table_size += [t]
|
|
|
|
|
|
|
|
beig_id_set = get_beig_id_set(sort_people)
|
|
|
|
|
|
|
|
people_set = set()
|
|
|
|
while len(people_set) != len(sort_people):
|
|
|
|
if len(people_set) >= all_table_size:
|
|
|
|
break
|
|
|
|
|
|
|
|
new_person_id = random.sample(list(beig_id_set - people_set), 1)[0]
|
|
|
|
|
|
|
|
cur_set = fill_next_table(new_person_id, people_set,
|
|
|
|
min(table_size[cur_table_id], len(sort_people) - len(people_set)), sort_people)
|
|
|
|
people_set = people_set | cur_set
|
|
|
|
tables.append(Table(cur_table_id, cur_set))
|
|
|
|
cur_table_id += 1
|
|
|
|
|
|
|
|
|
|
|
|
def fill_people():
|
|
|
|
global people
|
|
|
|
global tables
|
|
|
|
for t in tables:
|
|
|
|
for p in people:
|
|
|
|
if abs(p.beig_id) in t.person_set:
|
|
|
|
p.meet_set = t.person_set | p.meet_set
|
|
|
|
|
|
|
|
|
|
|
|
def load_input_table(val):
|
|
|
|
global tables
|
|
|
|
tables = []
|
|
|
|
input_data = val
|
|
|
|
for t in input_data.split("\n"):
|
|
|
|
if t == "":
|
|
|
|
continue
|
|
|
|
tmp = t.split(";")
|
|
|
|
cur_id = int(tmp[0])
|
|
|
|
str_meet_list = []
|
|
|
|
if len(tmp) > 1:
|
|
|
|
str_meet_list = tmp[1].replace(" ", "").replace("{", "").replace("}", "").split(",")
|
|
|
|
cur_meet_list = set()
|
|
|
|
for s in str_meet_list:
|
|
|
|
if len(s) != 0:
|
|
|
|
cur_meet_list = cur_meet_list | {int(s)}
|
|
|
|
t = Table(cur_id, cur_meet_list)
|
|
|
|
tables.append(t)
|
|
|
|
|
|
|
|
|
|
|
|
def make_result():
|
|
|
|
fill_tables()
|
|
|
|
fill_people()
|
|
|
|
|
|
|
|
|
|
|
|
def load_data(event):
|
|
|
|
val = document["input_data"].value
|
|
|
|
load_input(val)
|
|
|
|
add_to_all_data("#Таблица знакомств\n" + val)
|
|
|
|
show_meet_table_data()
|
|
|
|
|
|
|
|
|
|
|
|
def table_distrib(event):
|
|
|
|
load_input(document["input_data"].value)
|
|
|
|
make_result()
|
|
|
|
print_result_table()
|
|
|
|
document["output_data"].value = get_result()
|
|
|
|
show_meet_table_data()
|
|
|
|
|
|
|
|
|
|
|
|
def table_distrib_load(event):
|
|
|
|
load_input(document["input_data"].value)
|
|
|
|
load_input_table(document["result_table_txt"].value)
|
|
|
|
fill_people()
|
|
|
|
print_result_table()
|
|
|
|
document["output_data"].value = get_result()
|
|
|
|
show_meet_table_data()
|
|
|
|
|
|
|
|
|
|
|
|
def next_step(event):
|
|
|
|
document["step_id"].value = str(int(document["step_id"].value) + 1)
|
|
|
|
|
|
|
|
val = document["output_data"].value
|
|
|
|
document["input_data"].value = val
|
|
|
|
load_input(val)
|
|
|
|
add_to_all_data("#Столы\n" + result_table_fill())
|
|
|
|
add_to_all_data("#Таблица знакомств\n" + val)
|
|
|
|
show_meet_table_data()
|
|
|
|
|
|
|
|
|
|
|
|
document["load_data"].bind("click", load_data)
|
|
|
|
document["table_distrib"].bind("click", table_distrib)
|
|
|
|
document["next_step"].bind("click", next_step)
|
|
|
|
document["table_distrib_load"].bind("click", table_distrib_load)
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
|
|
|
</html>
|