From d0ca2bfc9766707f4fd3ff0f126d91f1929797cb Mon Sep 17 00:00:00 2001 From: ross Date: Tue, 31 Mar 2020 23:17:13 +0100 Subject: [PATCH] More refactoring and documenting --- rota.ipynb | 165 ++++++++++++++++++----------------------------------- shifts.py | 122 ++++++++++++++++++++++++++++++++++----- workers.py | 60 +++++++++++++++++++ 3 files changed, 223 insertions(+), 124 deletions(-) create mode 100644 workers.py diff --git a/rota.ipynb b/rota.ipynb index ec28828..9bfe7be 100644 --- a/rota.ipynb +++ b/rota.ipynb @@ -31,7 +31,8 @@ "source": [ "from pyomo.environ import *\n", "from pyomo.opt import SolverFactory\n", - "from shifts import ShiftsClass, ShiftCollection, days, sites\n", + "from shifts import SingleShift, ShiftCollection, days, sites\n", + "from workers import Worker\n", "\n", "import datetime\n", "import itertools" @@ -45,7 +46,7 @@ "source": [ "night_balance_offset = 2\n", "twilight_balance_offset = 1\n", - "weeks_to_rota = 26\n", + "weeks_to_rota = 8\n", "use_test_workers = False" ] }, @@ -63,16 +64,16 @@ "\n", "Shifts = ShiftCollection(weeks_to_rota=weeks_to_rota)\n", "\n", - "Shifts.AddShifts(\n", - " ShiftsClass((\"exeter\",), \"exeter_twilight\", 12.5, days[:5]),\n", - " ShiftsClass((\"truro\",), \"truro_twilight\", 12.5, days[:5]),\n", - " ShiftsClass((\"torquay\",), \"torquay_twilight\", 12.5, days[:5]),\n", - " ShiftsClass((\"plymouth\",), \"plymouth_twilight\", 12.5, days[:5]), \n", - " ShiftsClass((\"exeter\",), \"weekend_exeter\", 12.5, days[5:]), \n", - " ShiftsClass((\"truro\",), \"weekend_truro\", 12.5, days[5:]), \n", - " ShiftsClass((\"torquay\",), \"weekend_torquay\", 12.5, days[5:]), \n", - " ShiftsClass((\"plymouth\",), \"weekend_plymouth\", 8, days[5:], workers_required=2), \n", - " ShiftsClass((sites), \"night\", 12.5, days, balance_by_site=False, workers_required=3, rota_on_nwds=True), \n", + "Shifts.add_shifts(\n", + " SingleShift((\"exeter\",), \"exeter_twilight\", 12.5, days[:5]),\n", + " SingleShift((\"truro\",), \"truro_twilight\", 12.5, days[:5]),\n", + " SingleShift((\"torquay\",), \"torquay_twilight\", 12.5, days[:5]),\n", + " SingleShift((\"plymouth\",), \"plymouth_twilight\", 12.5, days[:5]), \n", + " SingleShift((\"exeter\",), \"weekend_exeter\", 12.5, days[5:]), \n", + " SingleShift((\"truro\",), \"weekend_truro\", 12.5, days[5:]), \n", + " SingleShift((\"torquay\",), \"weekend_torquay\", 12.5, days[5:]), \n", + " SingleShift((\"plymouth\",), \"weekend_plymouth\", 8, days[5:], workers_required=2), \n", + " SingleShift((sites), \"night\", 12.5, days, balance_by_site=False, workers_required=3, rota_on_nwds=True), \n", ")\n", "\n", "# Enter shifts of each day\n", @@ -103,64 +104,8 @@ "\n", "unavailable_to_work = set()\n", "\n", - "class workerClass:\n", - " def __init__(self, id, name, site, grade, fte=100, nwd=[], end_date=None, oop=None):\n", - " self.id = id\n", - " self.name = name\n", - " self.site = site\n", - " self.grade = grade\n", - " self.fte = fte\n", - " self.nwd = nwd\n", - " self.proportion_rota_to_work = 1\n", - "\n", - " days_to_work = Shifts.rota_days_length\n", - "\n", - " if end_date is None:\n", - " self.end_date = None\n", - " else:\n", - " #y, m, d = [int(i) for i in end_date.split(\"/\")]\n", - " self.end_date = datetime.datetime.strptime(end_date, '%Y/%m/%d').date()\n", - "\n", - " if self.end_date > Shifts.rota_end_date:\n", - " self.end_date = Shifts.rota_end_date\n", - " else:\n", - " days_to_work = (self.end_date - Shifts.start_date).days\n", - "\n", - " # add unavalabilities\n", - " for weeks_days in Shifts.weeks_days_product[days_to_work:]:\n", - " week, day = weeks_days\n", - " unavailable_to_work.add((self.id, week, day))\n", - " \n", - " if oop is not None:\n", - " start_oop, end_oop = oop\n", - " start_oop_date = datetime.datetime.strptime(start_oop, '%Y/%m/%d').date()\n", - " end_oop_date = datetime.datetime.strptime(end_oop, '%Y/%m/%d').date()\n", - "\n", - " if end_oop_date > Shifts.rota_end_date:\n", - " end_oop_date = Shifts.rota_end_date\n", - " \n", - " oop_length = (end_oop_date - start_oop_date).days\n", - " days_to_work = days_to_work - oop_length\n", - "\n", - " days_until_oop = (start_oop_date - Shifts.start_date).days\n", - "\n", - " for weeks_days in Shifts.weeks_days_product[days_until_oop:days_until_oop+oop_length]:\n", - " week, day = weeks_days\n", - " unavailable_to_work.add((self.id, week, day))\n", - "\n", - " \n", - " self.proportion_rota_to_work = days_to_work / Shifts.rota_days_length\n", - "\n", - " # We had to adjust the full time equivalent for people who CCT / leave the rota early\n", - " self.fte_adj = self.fte * self.proportion_rota_to_work\n", - "\n", - " def __lt__(self, other):\n", - " return (self.site, self.grade, self.name) < (other.site, other.grade, other.name)\n", - " \n", - " def GetDetails(self):\n", - " return \"{} {} {}\".format(self.id, self.site[0], self.grade)\n", - "\n", "\n", + "#Shifts.GetAllDayShiftsAsClass()\n", "#unavailable_to_work.update([(\"W1\", 1, \"Mon\"),(\"W1\", 1, \"Fri\"),(\"W1\", 1, \"Thu\"),(\"W3\", 1, \"Mon\"),(\"W2\", 1, \"Mon\"),(\"W2\", 1, \"Tue\"),(\"W2\", 1, \"Wed\"),(\"W6\", 1, \"Thu\"),(\"W5\", 1, \"Fri\"),(\"W9\", 1, \"Fri\"),(\"W14\", 1, \"Fri\"),(\"W21\", 1, \"Fri\")])\n", "\n", "#for i in range(11,30):" @@ -174,15 +119,19 @@ { "output_type": "stream", "name": "stdout", - "text": "['Wijhdan Abusrewil', 'Exeter', 'ST2', '100', '', '', '', '']\n['Seren Peters', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Hannah Lewis', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Christian Greer', 'Torquay', 'ST2', '100', '', '', '', '']\n['Nicolas Dziad', 'Truro', 'ST2', '100', '', '', '', '']\n['Michal Tomek', 'Exeter', 'ST2', '100', '', '', '', '']\n['Alex Wood', 'Exeter', 'ST2', '100', '', '', '', '']\n['Alexander Sanchez- Cabello', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Max Ireland', 'Torquay', 'ST2', '100', '', '', '', '']\n['Vilim Kalamar', 'Truro', 'ST2', '100', '', '', '', '']\n['Salma Aslam', 'Exeter', 'ST3', '0', '', '', '', 'IDT']\n['Adeola Omotade', 'Plymouth', 'ST3', '0', '', '', '', 'IDT']\n['Amina Odeh', 'Plymouth', 'ST3', '100', '', '', '', '']\n['Charles Finan', 'Torquay', 'ST3', '100', '', '', '', '']\n['Alan Eccles', 'Torquay', 'ST3', '80', '', '', '', '']\n['Sarath Vennam', 'Truro', 'ST3', '100', '', '', '', '']\n['Paul Ward', 'Truro', 'ST3', '100', '', '', '', '']\n['Sayed Alqarooni', 'Exeter', 'ST3', '100', '', '', '', '']\n['Jean Sukumar', 'Plymouth', 'ST3', '60', '', '', '', '']\n['Jenn Fong', 'Plymouth', 'ST3', '100', '', '', '', '']\n['Chong Ng', 'Torquay', 'ST3', '100', '', '', '', '']\n['Matthew Thorley', 'Torquay', 'ST3', '100', '', '', '', '']\n['Jenna Millington', 'Truro', 'ST3', '60', '', '', '', '']\n['Chi Leung', 'Truro', 'ST3', '100', '', '', '', '']\n['Tom Welsh', 'Exeter', 'ST4', '100', '', '', '', '']\n['Rebecca Murphy', 'Exeter', 'ST4', '100', '', '', '', '']\n['Delilah Trimmer', 'Exeter', 'ST4', '50', '', '', '', 'Back Nov 20']\n['Sophie McGlade', 'Plymouth', 'ST4', '100', '', '', '', '']\n['S Ghauri', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Khalil Madbak', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Natasha Hougham', 'Plymouth', 'ST4', '60', '', '', '', '']\n['Richard Chaytor', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Safi Rahman', 'Plymouth', 'ST4', '0', '', '', '', 'IDT']\n['George Edwards', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Neil McIntyre', 'Torquay', 'ST4', '100', '', '', '', '']\n['Mo Babsail', 'Torquay', 'ST4', '100', '', '', '', '']\n['Paul Jenkins', 'Torquay', 'ST4', '100', '', '', '', '']\n['Ross Kruger', 'Truro', 'ST4', '100', '', '', '', '']\n['Amoolya Mannava', 'Truro', 'ST4', '100', '', '', '', '']\n['Tom Davies', 'Exeter', 'ST5', '42', '', '', '2020/09/01-2021/04/12', '']\n['Tania King Mohammed', 'Exeter', 'ST5', '30', '', '', '', 'Back sep till end of Feb']\n['Jin Virdi', 'Exeter', 'ST5', '100', '', '2020/12/01', '', '']\n['Huub Witt', 'Plymouth', 'ST5', '100', '', '2021/04/01', '', '']\n['Mirna Long', 'Plymouth', 'ST5', '100', '', '2020/11/01', '', '']\n['Jon Stokes', 'Plymouth', 'ST5', '6', '', '', '', '']\n['Karis McFeely', 'Plymouth', 'ST5', '100', '', '', '', '']\n['Harriet Conley', 'Torquay', 'ST5', '0', '', '', '', '']\n['Jon Skinner', 'Torquay', 'ST5', '100', '', '', '', '']\n['Gana Kugathasan', 'Torquay', 'ST5', '100', '', '2020/12/01', '', '']\n['Jack Looker', 'Truro', 'ST5', '100', '', '', '', '']\n['Pete Abernethy', 'Truro', 'ST5', '100', '', '2020/12/01', '', '']\n" + "text": "['Wijhdan Abusrewil', 'Exeter', 'ST2', '100', '', '', '', '']\n['Seren Peters', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Hannah Lewis', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Christian Greer', 'Torquay', 'ST2', '100', '', '', '', '']\n['Nicolas Dziad', 'Truro', 'ST2', '100', '', '', '', '']\n['Michal Tomek', 'Exeter', 'ST2', '100', '', '', '', '']\n['Alex Wood', 'Exeter', 'ST2', '100', '', '', '', '']\n['Alexander Sanchez- Cabello', 'Plymouth', 'ST2', '100', '', '', '', '']\n['Max Ireland', 'Torquay', 'ST2', '100', '', '', '', '']\n['Vilim Kalamar', 'Truro', 'ST2', '100', '', '', '', '']\n['Salma Aslam', 'Exeter', 'ST3', '0', '', '', '', 'IDT']\n['Adeola Omotade', 'Plymouth', 'ST3', '0', '', '', '', 'IDT']\n['Amina Odeh', 'Plymouth', 'ST3', '100', '', '', '', '']\n['Charles Finan', 'Torquay', 'ST3', '100', '', '', '', '']\n['Alan Eccles', 'Torquay', 'ST3', '80', '', '', '', '']\n['Sarath Vennam', 'Truro', 'ST3', '100', '', '', '', '']\n['Paul Ward', 'Truro', 'ST3', '100', '', '', '', '']\n['Sayed Alqarooni', 'Exeter', 'ST3', '100', '', '', '', '']\n['Jean Sukumar', 'Plymouth', 'ST3', '60', '', '', '', '']\n['Jenn Fong', 'Plymouth', 'ST3', '100', '', '', '', '']\n['Chong Ng', 'Torquay', 'ST3', '100', '', '', '', '']\n['Matthew Thorley', 'Torquay', 'ST3', '100', '', '', '', '']\n['Jenna Millington', 'Truro', 'ST3', '60', '', '', '', '']\n['Chi Leung', 'Truro', 'ST3', '100', '', '', '', '']\n['Tom Welsh', 'Exeter', 'ST4', '100', '', '', '', '']\n['Rebecca Murphy', 'Exeter', 'ST4', '100', '', '', '', '']\n['Delilah Trimmer', 'Exeter', 'ST4', '50', '', '', '', 'Back Nov 20']\n['Sophie McGlade', 'Plymouth', 'ST4', '100', '', '', '', '']\n['S Ghauri', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Khalil Madbak', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Natasha Hougham', 'Plymouth', 'ST4', '60', '', '', '', '']\n['Richard Chaytor', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Safi Rahman', 'Plymouth', 'ST4', '0', '', '', '', 'IDT']\n['George Edwards', 'Plymouth', 'ST4', '100', '', '', '', '']\n['Neil McIntyre', 'Torquay', 'ST4', '100', '', '', '', '']\n['Mo Babsail', 'Torquay', 'ST4', '100', '', '', '', '']\n['Paul Jenkins', 'Torquay', 'ST4', '100', '', '', '', '']\n['Ross Kruger', 'Truro', 'ST4', '100', '', '', '', '']\n['Amoolya Mannava', 'Truro', 'ST4', '100', '', '', '', '']\n['Tom Davies', 'Exeter', 'ST5', '42', '', '', '2020/09/01-2021/04/12', '']\n" }, { - "output_type": "execute_result", - "data": { - "text/plain": "['Alex Wood',\n 'Michal Tomek',\n 'Wijhdan Abusrewil',\n 'Salma Aslam',\n 'Sayed Alqarooni',\n 'Delilah Trimmer',\n 'Rebecca Murphy',\n 'Tom Welsh',\n 'Jin Virdi',\n 'Tania King Mohammed',\n 'Tom Davies',\n 'Alexander Sanchez- Cabello',\n 'Hannah Lewis',\n 'Seren Peters',\n 'Adeola Omotade',\n 'Amina Odeh',\n 'Jean Sukumar',\n 'Jenn Fong',\n 'George Edwards',\n 'Khalil Madbak',\n 'Natasha Hougham',\n 'Richard Chaytor',\n 'S Ghauri',\n 'Safi Rahman',\n 'Sophie McGlade',\n 'Huub Witt',\n 'Jon Stokes',\n 'Karis McFeely',\n 'Mirna Long',\n 'Christian Greer',\n 'Max Ireland',\n 'Alan Eccles',\n 'Charles Finan',\n 'Chong Ng',\n 'Matthew Thorley',\n 'Mo Babsail',\n 'Neil McIntyre',\n 'Paul Jenkins',\n 'Gana Kugathasan',\n 'Harriet Conley',\n 'Jon Skinner',\n 'Nicolas Dziad',\n 'Vilim Kalamar',\n 'Chi Leung',\n 'Jenna Millington',\n 'Paul Ward',\n 'Sarath Vennam',\n 'Amoolya Mannava',\n 'Ross Kruger',\n 'Jack Looker',\n 'Pete Abernethy']" - }, - "metadata": {}, - "execution_count": 4 + "output_type": "error", + "ename": "NameError", + "evalue": "name 'unavailable_to_work' is not defined", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 30\u001b[0m \u001b[0moop\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0moop\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msplit\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m\"-\"\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0moop\u001b[0m \u001b[0;32melse\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 31\u001b[0m \u001b[0;31m#print(nwds, end_date, oop)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 32\u001b[0;31m \u001b[0mworkers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mWorker\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mShifts\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mn\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0msite\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mlower\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgrade\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfte\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mnwds\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mend_date\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moop\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 33\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 34\u001b[0m \u001b[0mworkers\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msorted\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mworkers\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;32m~/scripts/rota/workers.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, Shifts, id, name, site, grade, fte, nwd, end_date, oop)\u001b[0m\n\u001b[1;32m 46\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mweeks_days\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mShifts\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mweeks_days_product\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mdays_until_oop\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mdays_until_oop\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0moop_length\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[1;32m 47\u001b[0m \u001b[0mweek\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mday\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mweeks_days\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 48\u001b[0;31m \u001b[0munavailable_to_work\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mid\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mweek\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mday\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 49\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 50\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mNameError\u001b[0m: name 'unavailable_to_work' is not defined" + ] } ], "source": [ @@ -190,10 +139,10 @@ "\n", "if use_test_workers:\n", " # Enter workers ids (name, number, ...)\n", - " workers.extend([workerClass(i, \"Test Person {}\".format(i), \"truro\", 2, nwd=['Fri', \"Sat\", \"Sun\"]) for i in range(1, 2)])\n", - " workers.extend([workerClass(i, \"Test Person {}\".format(i), \"truro\", 2, nwd=[\"Sat\", \"Sun\"]) for i in range(2, 10)])\n", - " workers.extend([workerClass(i, \"Test Person {}\".format(i), \"plymouth\", 4) for i in range(10, 20)])\n", - " workers.extend([workerClass(i, \"Test Person {}\".format(i), \"exeter\", 4) for i in range(20, 30)])\n", + " workers.extend([Worker(Shifts, i, \"Test Person {}\".format(i), \"truro\", 2, nwd=['Fri', \"Sat\", \"Sun\"]) for i in range(1, 2)])\n", + " workers.extend([Worker(Shifts,i, \"Test Person {}\".format(i), \"truro\", 2, nwd=[\"Sat\", \"Sun\"]) for i in range(2, 10)])\n", + " workers.extend([Worker(Shifts,i, \"Test Person {}\".format(i), \"plymouth\", 4) for i in range(10, 20)])\n", + " workers.extend([Worker(Shifts,i, \"Test Person {}\".format(i), \"exeter\", 4) for i in range(20, 30)])\n", " #workers.extend([workerClass(i, \"Test Person {}\".format(i), 4, 200, \"\") for i in range(48, 49)])\n", "else:\n", " # Import trainee data\n", @@ -208,14 +157,19 @@ " n = n + 1\n", " print(row)\n", " name, site, grade, fte, nwd, end_date, oop, extra = row\n", + "\n", + " # Ignore trainees if fte == 0 (what are they doing here anyway)\n", + " if fte == 0:\n", + " continue\n", + "\n", " nwds = nwd.split(\",\").title() if nwd else None\n", " end_date = end_date if end_date else None\n", " oop = oop.split(\"-\") if oop else None\n", " #print(nwds, end_date, oop)\n", - " workers.append(workerClass(n, name, site.lower(), int(grade[2]), int(fte), nwds, end_date, oop))\n", + " workers.append(Worker(Shifts, n, name, site.lower(), int(grade[2]), int(fte), nwds, end_date, oop))\n", "\n", "workers = sorted(workers)\n", - "[w.name for w in workers]" + "" ] }, { @@ -259,14 +213,17 @@ "model = ConcreteModel()\n", "\n", "# binary variables representing if a worker is scheduled somewhere\n", + "# NOTE: this will assign to all possible shift combinations (which we probably don't want)\n", "model.works = Var(((worker.id, week, day, shift) for worker in workers for week, day in Shifts.GetAllWeeksDays() for shift in Shifts.GetShiftNames()),\n", " within=Binary, initialize=0)\n", "\n", + "# The nights model is used to ensure nights are assigned as a block (and limit the number of workers required)\n", "model.nights = Var(((worker.id, week, block) for worker in workers for week in Shifts.weeks for block in night_blocks),\n", " within=Binary, initialize=0)\n", "\n", "#model.unavailable = Var(((worker, week, day) for worker in workers for week in weeks for day in days),\n", "# within=Binary, initialize=0)\n", + "\n", "def availability_init(model, wid, week, day):\n", " if (wid, week, day) in unavailable_to_work:\n", " #print((wid, week, day))\n", @@ -529,7 +486,7 @@ { "output_type": "stream", "name": "stdout", - "text": "18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n1.0 -1.0\n1.0 -1.0\n18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n9.961578086176596 7.961578086176596\n4.584631234470638 2.584631234470638\n18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n18.923156172353192 16.923156172353192\n8.169262468941277 6.169262468941276\n9.370704805769346 7.370704805769346\n4.348281922307739 2.3482819223077387\n6.3769468517059575 4.3769468517059575\n3.150778740682383 1.1507787406823828\n0.7518332222289559 -1.2481667777710441\n0.9007332888915823 -1.0992667111084176\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n1.0 -1.0\n1.0 -1.0\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n6.751280222985675 4.751280222985675\n5.60102417838854 3.60102417838854\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n6.751280222985675 4.751280222985675\n5.60102417838854 3.60102417838854\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n1.0 -1.0\n1.0 -1.0\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n1.5751280222985673 -0.4248719777014326\n1.460102417838854 -0.539897582161146\n10.585467038309456 8.585467038309456\n8.668373630647567 6.668373630647567\n3.896707072016594 1.8967070720165942\n3.3173656576132755 1.3173656576132755\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n11.12950872310821 9.12950872310821\n5.051803489243284 3.0518034892432837\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n6.913518141924435 4.913518141924435\n3.365407256769774 1.3654072567697741\n1.0 -1.0\n1.0 -1.0\n13.661885903885262 11.661885903885262\n6.064754361554105 4.064754361554105\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n9.60259362501515 7.60259362501515\n4.4410374500060605 2.44103745000606\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n15.337656041691915 13.337656041691915\n6.735062416676766 4.735062416676766\n7.696158041449521 5.696158041449521\n3.6784632165798086 1.6784632165798086\n" + "text": "4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n1.0 -1.0\n1.0 -1.0\n1.0 -1.0\n1.0 -1.0\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n2.8181818181818183 0.8181818181818183\n1.7272727272727273 -0.2727272727272727\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n2.071428571428571 0.0714285714285714\n1.8571428571428572 -0.1428571428571429\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n2.5789473684210527 0.5789473684210527\n1.631578947368421 -0.368421052631579\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n4.076923076923077 2.076923076923077\n2.230769230769231 0.23076923076923084\n2.5384615384615383 0.5384615384615385\n1.6153846153846154 -0.3846153846153846\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n2.071428571428571 0.0714285714285714\n1.8571428571428572 -0.1428571428571429\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n1.0 -1.0\n1.0 -1.0\n2.7857142857142856 0.7857142857142856\n2.428571428571429 0.4285714285714286\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.272727272727273 1.272727272727273\n1.9090909090909092 -0.09090909090909094\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n3.631578947368421 1.6315789473684208\n2.052631578947368 0.05263157894736836\n" } ], "source": [ @@ -593,7 +550,7 @@ { "output_type": "execute_result", "data": { - "text/plain": "[7, 6, 1, 11, 18, 27, 26, 25, 42, 41, 40]" + "text/plain": "[1, 6, 7, 11, 18, 25, 26, 27]" }, "metadata": {}, "execution_count": 14 @@ -745,25 +702,11 @@ "cell_type": "code", "execution_count": 16, "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": "0\n0\n" - }, - { - "output_type": "execute_result", - "data": { - "text/plain": "{'exeter_twilight',\n 'night',\n 'plymouth_twilight',\n 'torquay_twilight',\n 'truro_twilight'}" - }, - "metadata": {}, - "execution_count": 16 - } - ], + "outputs": [], "source": [ - "print(model.works[18,6, \"Fri\", \"night\"].value)\n", - "print(model.works[18,7, \"Mon\", \"truro_twilight\"].value * 0)\n", - "Shifts.GetShiftNamesByDay(\"Mon\")" + "#print(model.works[18,6, \"Fri\", \"night\"].value)\n", + "#print(model.works[18,7, \"Mon\", \"truro_twilight\"].value * 0)\n", + "#Shifts.GetShiftNamesByDay(\"Mon\")" ] }, { @@ -774,7 +717,7 @@ { "output_type": "stream", "name": "stdout", - "text": "WARNING: Constant objective detected, replacing with a placeholder to prevent\n solver failure.\n" + "text": "WARNING: Constant objective detected, replacing with a placeholder to prevent\n solver failure.\nWARNING: Loading a SolverResults object with a warning status into\n model=unknown;\n message from solver=\n" } ], "source": [ @@ -795,7 +738,7 @@ { "output_type": "stream", "name": "stdout", - "text": "7 exeter_twilight\n7 truro_twilight\n7 torquay_twilight\n7 plymouth_twilight\n7 weekend_exeter\n7 weekend_truro\n7 weekend_torquay\n7 weekend_plymouth\n7 night\n6 exeter_twilight\n6 truro_twilight\n6 torquay_twilight\n6 plymouth_twilight\n6 weekend_exeter\n6 weekend_truro\n6 weekend_torquay\n6 weekend_plymouth\n6 night\n1 exeter_twilight\n1 truro_twilight\n1 torquay_twilight\n1 plymouth_twilight\n1 weekend_exeter\n1 weekend_truro\n1 weekend_torquay\n1 weekend_plymouth\n1 night\n11 exeter_twilight\n11 truro_twilight\n11 torquay_twilight\n11 plymouth_twilight\n11 weekend_exeter\n11 weekend_truro\n11 weekend_torquay\n11 weekend_plymouth\n11 night\n18 exeter_twilight\n18 truro_twilight\n18 torquay_twilight\n18 plymouth_twilight\n18 weekend_exeter\n18 weekend_truro\n18 weekend_torquay\n18 weekend_plymouth\n18 night\n27 exeter_twilight\n27 truro_twilight\n27 torquay_twilight\n27 plymouth_twilight\n27 weekend_exeter\n27 weekend_truro\n27 weekend_torquay\n27 weekend_plymouth\n27 night\n26 exeter_twilight\n26 truro_twilight\n26 torquay_twilight\n26 plymouth_twilight\n26 weekend_exeter\n26 weekend_truro\n26 weekend_torquay\n26 weekend_plymouth\n26 night\n25 exeter_twilight\n25 truro_twilight\n25 torquay_twilight\n25 plymouth_twilight\n25 weekend_exeter\n25 weekend_truro\n25 weekend_torquay\n25 weekend_plymouth\n25 night\n42 exeter_twilight\n42 truro_twilight\n42 torquay_twilight\n42 plymouth_twilight\n42 weekend_exeter\n42 weekend_truro\n42 weekend_torquay\n42 weekend_plymouth\n42 night\n41 exeter_twilight\n41 truro_twilight\n41 torquay_twilight\n41 plymouth_twilight\n41 weekend_exeter\n41 weekend_truro\n41 weekend_torquay\n41 weekend_plymouth\n41 night\n40 exeter_twilight\n40 truro_twilight\n40 torquay_twilight\n40 plymouth_twilight\n40 weekend_exeter\n40 weekend_truro\n40 weekend_torquay\n40weekend_plymouth\n40 night\n8 exeter_twilight\n8 truro_twilight\n8 torquay_twilight\n8 plymouth_twilight\n8 weekend_exeter\n8 weekend_truro\n8 weekend_torquay\n8 weekend_plymouth\n8 night\n3 exeter_twilight\n3 truro_twilight\n3 torquay_twilight\n3 plymouth_twilight\n3 weekend_exeter\n3 weekend_truro\n3 weekend_torquay\n3 weekend_plymouth\n3 night\n2 exeter_twilight\n2 truro_twilight\n2 torquay_twilight\n2 plymouth_twilight\n2 weekend_exeter\n2 weekend_truro\n2 weekend_torquay\n2 weekend_plymouth\n2 night\n12 exeter_twilight\n12 truro_twilight\n12 torquay_twilight\n12 plymouth_twilight\n12 weekend_exeter\n12 weekend_truro\n12 weekend_torquay\n12 weekend_plymouth\n12 night\n13 exeter_twilight\n13 truro_twilight\n13 torquay_twilight\n13 plymouth_twilight\n13 weekend_exeter\n13 weekend_truro\n13 weekend_torquay\n13 weekend_plymouth\n13 night\n19 exeter_twilight\n19 truro_twilight\n19 torquay_twilight\n19 plymouth_twilight\n19 weekend_exeter\n19 weekend_truro\n19 weekend_torquay\n19 weekend_plymouth\n19 night\n20 exeter_twilight\n20 truro_twilight\n20 torquay_twilight\n20 plymouth_twilight\n20 weekend_exeter\n20 weekend_truro\n20 weekend_torquay\n20 weekend_plymouth\n20 night\n34 exeter_twilight\n34 truro_twilight\n34 torquay_twilight\n34 plymouth_twilight\n34 weekend_exeter\n34 weekend_truro\n34 weekend_torquay\n34 weekend_plymouth\n34 night\n30 exeter_twilight\n30 truro_twilight\n30 torquay_twilight\n30 plymouth_twilight\n30 weekend_exeter\n30 weekend_truro\n30 weekend_torquay\n30 weekend_plymouth\n30 night\n31 exeter_twilight\n31 truro_twilight\n31 torquay_twilight\n31 plymouth_twilight\n31 weekend_exeter\n31 weekend_truro\n31 weekend_torquay\n31 weekend_plymouth\n31 night\n32 exeter_twilight\n32 truro_twilight\n32 torquay_twilight\n32 plymouth_twilight\n32 weekend_exeter\n32 weekend_truro\n32 weekend_torquay\n32 weekend_plymouth\n32 night\n29 exeter_twilight\n29 truro_twilight\n29 torquay_twilight\n29 plymouth_twilight\n29 weekend_exeter\n29 weekend_truro\n29 weekend_torquay\n29 weekend_plymouth\n29 night\n33 exeter_twilight\n33 truro_twilight\n33 torquay_twilight\n33 plymouth_twilight\n33 weekend_exeter\n33 weekend_truro\n33 weekend_torquay\n33weekend_plymouth\n33 night\n28 exeter_twilight\n28 truro_twilight\n28 torquay_twilight\n28 plymouth_twilight\n28 weekend_exeter\n28 weekend_truro\n28 weekend_torquay\n28 weekend_plymouth\n28 night\n43 exeter_twilight\n43 truro_twilight\n43 torquay_twilight\n43 plymouth_twilight\n43 weekend_exeter\n43 weekend_truro\n43 weekend_torquay\n43 weekend_plymouth\n43 night\n45 exeter_twilight\n45 truro_twilight\n45 torquay_twilight\n45 plymouth_twilight\n45 weekend_exeter\n45 weekend_truro\n45 weekend_torquay\n45 weekend_plymouth\n45 night\n46 exeter_twilight\n46 truro_twilight\n46 torquay_twilight\n46 plymouth_twilight\n46 weekend_exeter\n46 weekend_truro\n46 weekend_torquay\n46 weekend_plymouth\n46 night\n44 exeter_twilight\n44 truro_twilight\n44 torquay_twilight\n44 plymouth_twilight\n44 weekend_exeter\n44 weekend_truro\n44 weekend_torquay\n44 weekend_plymouth\n44 night\n4 exeter_twilight\n4 truro_twilight\n4 torquay_twilight\n4 plymouth_twilight\n4 weekend_exeter\n4 weekend_truro\n4 weekend_torquay\n4 weekend_plymouth\n4 night\n9 exeter_twilight\n9 truro_twilight\n9 torquay_twilight\n9 plymouth_twilight\n9 weekend_exeter\n9 weekend_truro\n9 weekend_torquay\n9 weekend_plymouth\n9 night\n15 exeter_twilight\n15 truro_twilight\n15 torquay_twilight\n15 plymouth_twilight\n15 weekend_exeter\n15 weekend_truro\n15 weekend_torquay\n15 weekend_plymouth\n15 night\n14 exeter_twilight\n14 truro_twilight\n14 torquay_twilight\n14 plymouth_twilight\n14 weekend_exeter\n14 weekend_truro\n14 weekend_torquay\n14 weekend_plymouth\n14 night\n21 exeter_twilight\n21 truro_twilight\n21 torquay_twilight\n21 plymouth_twilight\n21 weekend_exeter\n21 weekend_truro\n21 weekend_torquay\n21 weekend_plymouth\n21 night\n22 exeter_twilight\n22 truro_twilight\n22 torquay_twilight\n22 plymouth_twilight\n22 weekend_exeter\n22 weekend_truro\n22 weekend_torquay\n22 weekend_plymouth\n22 night\n36 exeter_twilight\n36 truro_twilight\n36 torquay_twilight\n36 plymouth_twilight\n36 weekend_exeter\n36 weekend_truro\n36 weekend_torquay\n36 weekend_plymouth\n36 night\n35 exeter_twilight\n35 truro_twilight\n35 torquay_twilight\n35 plymouth_twilight\n35 weekend_exeter\n35 weekend_truro\n35 weekend_torquay\n35 weekend_plymouth\n35 night\n37 exeter_twilight\n37 truro_twilight\n37 torquay_twilight\n37 plymouth_twilight\n37 weekend_exeter\n37 weekend_truro\n37 weekend_torquay\n37 weekend_plymouth\n37 night\n49 exeter_twilight\n49 truro_twilight\n49 torquay_twilight\n49 plymouth_twilight\n49 weekend_exeter\n49 weekend_truro\n49 weekend_torquay\n49 weekend_plymouth\n49 night\n47 exeter_twilight\n47 truro_twilight\n47 torquay_twilight\n47 plymouth_twilight\n47 weekend_exeter\n47 weekend_truro\n47 weekend_torquay\n47 weekend_plymouth\n47 night\n48 exeter_twilight\n48 truro_twilight\n48 torquay_twilight\n48 plymouth_twilight\n48 weekend_exeter\n48 weekend_truro\n48 weekend_torquay\n48 weekend_plymouth\n48 night\n5 exeter_twilight\n5 truro_twilight\n5 torquay_twilight\n5 plymouth_twilight\n5 weekend_exeter\n5 weekend_truro\n5 weekend_torquay\n5 weekend_plymouth\n5 night\n10 exeter_twilight\n10 truro_twilight\n10 torquay_twilight\n10 plymouth_twilight\n10 weekend_exeter\n10 weekend_truro\n10 weekend_torquay\n10 weekend_plymouth\n10 night\n24 exeter_twilight\n24 truro_twilight\n24 torquay_twilight\n24 plymouth_twilight\n24 weekend_exeter\n24 weekend_truro\n24 weekend_torquay\n24 weekend_plymouth\n24 night\n23 exeter_twilight\n23 truro_twilight\n23 torquay_twilight\n23 plymouth_twilight\n23 weekend_exeter\n23 weekend_truro\n23 weekend_torquay\n23 weekend_plymouth\n23 night\n17 exeter_twilight\n17 truro_twilight\n17 torquay_twilight\n17 plymouth_twilight\n17 weekend_exeter\n17 weekend_truro\n17 weekend_torquay\n17 weekend_plymouth\n17 night\n16 exeter_twilight\n16 truro_twilight\n16 torquay_twilight\n16 plymouth_twilight\n16 weekend_exeter\n16 weekend_truro\n16 weekend_torquay\n16 weekend_plymouth\n16 night\n39 exeter_twilight\n39 truro_twilight\n39 torquay_twilight\n39 plymouth_twilight\n39 weekend_exeter\n39 weekend_truro\n39 weekend_torquay\n39 weekend_plymouth\n39 night\n38 exeter_twilight\n38 truro_twilight\n38 torquay_twilight\n38 plymouth_twilight\n38 weekend_exeter\n38 weekend_truro\n38 weekend_torquay\n38 weekend_plymouth\n38 night\n50 exeter_twilight\n50 truro_twilight\n50 torquay_twilight\n50 plymouth_twilight\n50 weekend_exeter\n50 weekend_truro\n50 weekend_torquay\n50 weekend_plymouth\n50 night\n51 exeter_twilight\n51 truro_twilight\n51 torquay_twilight\n51 plymouth_twilight\n51 weekend_exeter\n51 weekend_truro\n51 weekend_torquay\n51 weekend_plymouth\n51 night\n" + "text": "1 exeter_twilight\n1 truro_twilight\n1 torquay_twilight\n1 plymouth_twilight\n1 weekend_exeter\n1 weekend_truro\n1 weekend_torquay\n1 weekend_plymouth\n1 night\n2 exeter_twilight\n2 truro_twilight\n2 torquay_twilight\n2 plymouth_twilight\n2 weekend_exeter\n2 weekend_truro\n2 weekend_torquay\n2 weekend_plymouth\n2 night\n3 exeter_twilight\n3 truro_twilight\n3 torquay_twilight\n3 plymouth_twilight\n3 weekend_exeter\n3 weekend_truro\n3 weekend_torquay\n3 weekend_plymouth\n3 night\n4 exeter_twilight\n4 truro_twilight\n4 torquay_twilight\n4 plymouth_twilight\n4 weekend_exeter\n4 weekend_truro\n4 weekend_torquay\n4 weekend_plymouth\n4 night\n5 exeter_twilight\n5 truro_twilight\n5 torquay_twilight\n5 plymouth_twilight\n5 weekend_exeter\n5 weekend_truro\n5 weekend_torquay\n5 weekend_plymouth\n5 night\n6 exeter_twilight\n6 truro_twilight\n6 torquay_twilight\n6 plymouth_twilight\n6 weekend_exeter\n6 weekend_truro\n6 weekend_torquay\n6 weekend_plymouth\n6 night\n7 exeter_twilight\n7 truro_twilight\n7 torquay_twilight\n7 plymouth_twilight\n7 weekend_exeter\n7 weekend_truro\n7 weekend_torquay\n7 weekend_plymouth\n7 night\n8 exeter_twilight\n8 truro_twilight\n8 torquay_twilight\n8 plymouth_twilight\n8 weekend_exeter\n8 weekend_truro\n8 weekend_torquay\n8 weekend_plymouth\n8 night\n9 exeter_twilight\n9 truro_twilight\n9 torquay_twilight\n9 plymouth_twilight\n9 weekend_exeter\n9 weekend_truro\n9 weekend_torquay\n9 weekend_plymouth\n9 night\n10 exeter_twilight\n10 truro_twilight\n10 torquay_twilight\n10 plymouth_twilight\n10 weekend_exeter\n10 weekend_truro\n10weekend_torquay\n10 weekend_plymouth\n10 night\n11 exeter_twilight\n11 truro_twilight\n11 torquay_twilight\n11 plymouth_twilight\n11 weekend_exeter\n11 weekend_truro\n11 weekend_torquay\n11 weekend_plymouth\n11 night\n12 exeter_twilight\n12 truro_twilight\n12 torquay_twilight\n12 plymouth_twilight\n12 weekend_exeter\n12 weekend_truro\n12 weekend_torquay\n12 weekend_plymouth\n12 night\n13 exeter_twilight\n13 truro_twilight\n13 torquay_twilight\n13 plymouth_twilight\n13 weekend_exeter\n13 weekend_truro\n13 weekend_torquay\n13 weekend_plymouth\n13 night\n14 exeter_twilight\n14 truro_twilight\n14 torquay_twilight\n14 plymouth_twilight\n14 weekend_exeter\n14 weekend_truro\n14 weekend_torquay\n14 weekend_plymouth\n14 night\n15 exeter_twilight\n15 truro_twilight\n15 torquay_twilight\n15 plymouth_twilight\n15 weekend_exeter\n15 weekend_truro\n15 weekend_torquay\n15 weekend_plymouth\n15 night\n16 exeter_twilight\n16 truro_twilight\n16 torquay_twilight\n16 plymouth_twilight\n16 weekend_exeter\n16 weekend_truro\n16 weekend_torquay\n16 weekend_plymouth\n16 night\n17 exeter_twilight\n17 truro_twilight\n17 torquay_twilight\n17 plymouth_twilight\n17 weekend_exeter\n17 weekend_truro\n17 weekend_torquay\n17 weekend_plymouth\n17 night\n18 exeter_twilight\n18 truro_twilight\n18 torquay_twilight\n18 plymouth_twilight\n18 weekend_exeter\n18 weekend_truro\n18 weekend_torquay\n18 weekend_plymouth\n18 night\n19 exeter_twilight\n19 truro_twilight\n19 torquay_twilight\n19 plymouth_twilight\n19 weekend_exeter\n19 weekend_truro\n19 weekend_torquay\n19 weekend_plymouth\n19 night\n20 exeter_twilight\n20 truro_twilight\n20 torquay_twilight\n20 plymouth_twilight\n20 weekend_exeter\n20 weekend_truro\n20 weekend_torquay\n20 weekend_plymouth\n20 night\n21 exeter_twilight\n21 truro_twilight\n21 torquay_twilight\n21 plymouth_twilight\n21 weekend_exeter\n21 weekend_truro\n21 weekend_torquay\n21 weekend_plymouth\n21 night\n22 exeter_twilight\n22 truro_twilight\n22 torquay_twilight\n22 plymouth_twilight\n22 weekend_exeter\n22 weekend_truro\n22 weekend_torquay\n22 weekend_plymouth\n22 night\n23 exeter_twilight\n23 truro_twilight\n23 torquay_twilight\n23 plymouth_twilight\n23 weekend_exeter\n23 weekend_truro\n23 weekend_torquay\n23 weekend_plymouth\n23 night\n24 exeter_twilight\n24 truro_twilight\n24 torquay_twilight\n24 plymouth_twilight\n24 weekend_exeter\n24 weekend_truro\n24 weekend_torquay\n24 weekend_plymouth\n24 night\n25 exeter_twilight\n25 truro_twilight\n25 torquay_twilight\n25 plymouth_twilight\n25 weekend_exeter\n25 weekend_truro\n25 weekend_torquay\n25 weekend_plymouth\n25 night\n26 exeter_twilight\n26 truro_twilight\n26 torquay_twilight\n26 plymouth_twilight\n26 weekend_exeter\n26 weekend_truro\n26 weekend_torquay\n26 weekend_plymouth\n26 night\n27 exeter_twilight\n27 truro_twilight\n27 torquay_twilight\n27 plymouth_twilight\n27 weekend_exeter\n27 weekend_truro\n27 weekend_torquay\n27 weekend_plymouth\n27 night\n28 exeter_twilight\n28 truro_twilight\n28 torquay_twilight\n28 plymouth_twilight\n28 weekend_exeter\n28 weekend_truro\n28 weekend_torquay\n28 weekend_plymouth\n28 night\n29 exeter_twilight\n29 truro_twilight\n29 torquay_twilight\n29 plymouth_twilight\n29 weekend_exeter\n29 weekend_truro\n29 weekend_torquay\n29 weekend_plymouth\n29 night\n30 exeter_twilight\n30 truro_twilight\n30 torquay_twilight\n30 plymouth_twilight\n30 weekend_exeter\n30 weekend_truro\n30 weekend_torquay\n30 weekend_plymouth\n30 night\n31 exeter_twilight\n31 truro_twilight\n31 torquay_twilight\n31 plymouth_twilight\n31 weekend_exeter\n31 weekend_truro\n31 weekend_torquay\n31 weekend_plymouth\n31 night\n32 exeter_twilight\n32 truro_twilight\n32 torquay_twilight\n32 plymouth_twilight\n32 weekend_exeter\n32 weekend_truro\n32 weekend_torquay\n32 weekend_plymouth\n32 night\n33 exeter_twilight\n33 truro_twilight\n33 torquay_twilight\n33 plymouth_twilight\n33 weekend_exeter\n33 weekend_truro\n33 weekend_torquay\n33 weekend_plymouth\n33 night\n34 exeter_twilight\n34 truro_twilight\n34 torquay_twilight\n34 plymouth_twilight\n34 weekend_exeter\n34 weekend_truro\n34 weekend_torquay\n34 weekend_plymouth\n34 night\n35 exeter_twilight\n35 truro_twilight\n35 torquay_twilight\n35 plymouth_twilight\n35 weekend_exeter\n35 weekend_truro\n35 weekend_torquay\n35 weekend_plymouth\n35 night\n36 exeter_twilight\n36 truro_twilight\n36 torquay_twilight\n36 plymouth_twilight\n36 weekend_exeter\n36 weekend_truro\n36 weekend_torquay\n36 weekend_plymouth\n36 night\n37 exeter_twilight\n37 truro_twilight\n37 torquay_twilight\n37 plymouth_twilight\n37 weekend_exeter\n37 weekend_truro\n37 weekend_torquay\n37 weekend_plymouth\n37 night\n38 exeter_twilight\n38 truro_twilight\n38 torquay_twilight\n38 plymouth_twilight\n38 weekend_exeter\n38 weekend_truro\n38 weekend_torquay\n38 weekend_plymouth\n38 night\n39 exeter_twilight\n39 truro_twilight\n39 torquay_twilight\n39 plymouth_twilight\n39 weekend_exeter\n39 weekend_truro\n39 weekend_torquay\n39 weekend_plymouth\n39 night\n" } ], "source": [ @@ -815,7 +758,7 @@ " for worker in workers:\n", " for day, shift in Shifts.GetAllDayShiftsAsNames():\n", " if works[worker.id, week, day, shift].value == 1:\n", - " week_table[week][day][shift].append(worker.GetDetails())\n", + " week_table[week][day][shift].append(worker.get_details())\n", " return week_table\n", "\n", "def get_worker_timetable(works):\n", @@ -843,11 +786,11 @@ " return \"\\n\".join(timetable)\n", "\n", "def get_shift_summary(works):\n", - " timetable = { worker.GetDetails() : { shift[0] : \"\" for shift in Shifts.GetShiftNames() } for worker in workers }\n", - " #timetable = { worker.GetDetails() : { shift : \"\" for shift in [\"truro_twilight\"] } for worker in workers } \n", + " timetable = { worker.get_details() : { shift[0] : \"\" for shift in Shifts.GetShiftNames() } for worker in workers }\n", + " #timetable = { worker.get_details() : { shift : \"\" for shift in [\"truro_twilight\"] } for worker in workers } \n", " t = []\n", " for worker in workers:\n", - " l = [worker.GetDetails()+\": \"]\n", + " l = [worker.get_details()+\": \"]\n", "\n", " for shift in Shifts.GetShiftNames():\n", " #for shift in [\"truro_twilight\"]:\n", @@ -855,7 +798,7 @@ " if c > 0:\n", " l.append(\"{} ({})\".format(shift,c))\n", " print(worker.id, shift)\n", - " timetable[worker.GetDetails()][shift[0]] = c\n", + " timetable[worker.get_details()][shift[0]] = c\n", " t.append(\",\".join(l))\n", " return \"\\n\".join(t) \n", "\n", @@ -932,7 +875,7 @@ { "output_type": "stream", "name": "stdout", - "text": "Worker 11111112222222333333344444445555555666666677777778888888999999900000001111111222222233333334444444555555566666667777777888888899999990000000111111122222223333333444444455555556666666\nAlex Wood --e-------e-------e-------w-nnnn-----e------e---w-----------e---e----w-------nnnn--w--------e---w---e------e------e----e-------------e---e--nnnn--w-----w-----e----e-----e--nnn--e----\nMichal Tomek ---e---------w---e-------e-------w--------e------nnnn-----e------e--------------e-------e-----e---nnnn--w---e--------w----e--------w----e----e-----e---e---e---w-nnnn---e----w----e---\nWijhdan Abusrewil -e-----e------e----w-nnnn---e------e----------e---e------------e---nnn---------------e---w-----------e-------e---e-------e---w---e----e-----e----w-nnnn--w---e---------w------w----nnn\nSalma Aslam ---------------------e----------------------------------------------------------------------------------------w-----------------------------------------------------------------------\nSayed Alqarooni e----w-nnnn----e-------e-nnn---e---nnnn--w------------w------w----e---e-----w-------e-----w-------e---e------------e----------e---e--nnnn--w--------------e------e---e------e------e--\nDelilah Trimmer ----e-----------------------------------w----------e---w---e-------------e-----e------e----------------------------------------e---------nnn---------e----------w---e---nnnn----------\nRebecca Murphy ------------------------e----e---------e-------w-----e--nnnn--w-----w---e----e---nnn---e-----e---w--------e----w----e---e---w---e-nnn--e-------e----e--nnn--e--------------e---------w\nTom Welsh --------e---w---e---w---------e-nnn---e------e-----------e-----nnnn-------e---e---w--------e---e---e---w--------e-----w----e--------w-----------e-----e---nnnn----e---w---e----e---nnn\nJin Virdi nnnn--w----e----------e----w----e---e------e-----e------e----------e---e---w-nnnn-----------------------------------------------------------------------------------------------------\nTania King Mohammed ---------e------------------nnnn--w-----------------e----------------------------e-----------------------e--------------------------------w---e---------------------------------e---w-\nTom Davies --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\nAlexander Sanchez- Cabello--------p---w------w-----nnn-----w--------nnnn---------w----nnn-------p--------p----------w---p-------p----p--------nnn----p-------w------------p--------w---p-------p--------------w-\nHannah Lewis ------w------w---p-----p------------p--nnn-----------nnn-----------p----------p----w-----w--------p------------w--------------p-----w----nnn---p-------nnn------------w----p---p------\nSeren Peters --p-----------------w---p---p---nnn------w---p-------p----------------nnnn---p----w-----nnn------------w-----p-----p---------w--------p----w------------w-----nnn-----w---------------\nAdeola Omotade ---------------------------------------------------------------------w--------------------------------------------------------------------------------------------p-------------------\nAmina Odeh -------p---------------------------p-----------w-------w-----w----------p-------p---p------nnnn---------w-------------w-------nnnn---p----w-nnnn------------p---w-----------p---p-----\nJean Sukumar ---------p--------------------p--------nnn-----------------p-----------p---w----------p----------------------nnn----p-------w-----nnn------w------w----------------------------------w\nJenn Fong ---p-----------p--nnn------------------p--nnnn---p-------------------------w-nnnn------p----p---w--------------------w---p-----p----w----p-------w-nnnn---p-----w-------------w-----w-\nGeorge Edwards -------------w-----------p-----p-------nnn----p---p---w-----nnn-----w-------w----nnn---------p-----p---w---------p---------------------------p-------p---w----nnn------w----nnn-------\nKhalil Madbak p---nnn-------------w------------w---------p--------p----------p---nnn----p--------w-----w------w---------------p---nnn-----w----------p----------------------nnn---p---p----w----p---\nNatasha Hougham -------------------w-----------------p---w----------------p-----------nnnn--------w--------------w------------w---------p-----------------------nnn-----------p-----------p-----------\nRichard Chaytor ---------------------------w------w-----w-----nnn-----w------w----p-----------------nnnn--w---------------p-------p-nnn------------w----p---p---------p----p---w-nnnn----p-------p----\nS Ghauri ------w---p-----p----------w----------------------------------w------w-----------p--nnnn---p--------p----p-----w-----w--------nnnn------------p----p-------------nnnn---------w----p--\nSafi Rahman ------------------------------------------p----------------------------------------------------------------------------------------------------------------------------w--------------\nSophie McGlade -p---w------w---------p------------nnnn---------w----nnn------w-----w----p-----------p--nnn----p------nnn---p-------------p------p--------w-------w----p-----------------------------w\nHuub Witt -----w--------p------p-------p--------------p-----------p---p---p-----------w----nnn-------nnnn--w------w-------nnnn--w------w----p---------nnnn----p---w--------p--------------------\nJon Stokes ----p-----------------------------w---------------------------------------------------------------------------------------------------------------------------------------------------\nKaris McFeely -----------p------p-------w-------------w-nnnn--w--------p-------p--------nnn-----------p------nnn---p--------w--------p--------p----------------w-------------w---p-nnn-----w--------\nMirna Long -----------nnn------------w-----p-----p--------w---p----------------------------------------------------------------------------------------------------------------------------------\nChristian Greer nnnn-------t------nnn--t------t----------w---t---t------------------------t-------------t---------t----w-nnnn--------w----t---t---------------t----t------t-----w----nnn------w-------\nMax Ireland -t----w----nnn-------------w---t--------------t----t--------t----t-----------t---t--------w-----------nnn--t-------t---nnnn------t--------------nnn------------w------w----t---t------\nAlan Eccles ----------t--------w------w---------------t------------w-------t---------t-------------t--------------nnn---t---nnnn--w--------------t-----------------t---t--------------t-nnn--t----\nCharles Finan ---t--------------------t---------w--------t---w---------t-----nnnn---t-----w------------w----t------t---nnnn--------------nnn----t------nnn---t------t-----------t------t-----------w\nChong Ng t------------w----t----------t--------------t-nnn-------t----------nnn------------w-----nnn-----------t------t----------t--nnn-----w---t---w---------------------t------t-------t---w-\nMatthew Thorley ----t----t-nnn---t--------------t------t--------w---t--------------t----------t-------------t---w---t----------w--------------nnnn----------t-------t---w-nnnn---------w-------nnnn---\nMo Babsail ----nnn-------nnnn---------------w----t--------------t-----t---------w----------t----t-----------w------w----nnn--t------t-nnn--t--------t---t----w---------t-------t-------------t---\nNeil McIntyre -----w--------------w----nnn---------t------------t--nnn--------t------t---w--------t------t---t--nnnn----------t---t-------w---------t---------t--------w---t-------nnn----t---------\nPaul Jenkins nnnn----------t-------t------------t------------------w------------------------t------------------nnnn----t------t-----t---t---t----w-----w------w---t----nnnn-----t---------w-----t--\nGana Kugathasan -------t----w---t----t---t------nnn--------------------------w----t---nnnn---------w--------------------------------------------------------------------------------------------------\nHarriet Conley ---------------------------------------------------------------------------------------------t----------------------------------------------------------------------------------------\nJon Skinner --t-----t------t--nnn-------t-------t---w--------nnnn-----t---w-----w---t-nnn---------t------------t-----t----w--------------w----------t----------nnnn-------t------t----------------\nNicolas Dziad -------t------nnnn-------------t----t----w------w---------------t----w------w-------nnnn------t------t------t-------t-------------nnn--t---w---t---t---t-------w-----t----t----nnnn---\nVilim Kalamar ------w----t-----t---t--------t----nnnn--------------------t--------w----------t--------t--nnnn--w---------t-nnn-----w-----t------t--nnnn---t-----------w---t------------t----w----t--\nChi Leung t------nnnn--w---------t----nnnn-----t-------t---t----w-nnnn------------------t--------t-----t-nnn----t-------w---------t----w---t------t-----------------------------------t---t---w-\nJenna Millington ---------------t----------------t--------------------t--------w---t-----t----------------w---------------t------nnnn---t------t-----------w---------------------w-------nnnn------t---\nPaul Ward --t-nnn-----w---t-------t---t-----w---------------t-------t---------------nnn---t---------w------------------------t---nnnn-----t---w--------t--------t----t------t---w-nnnn-----t----\nSarath Vennam -t------------------w------------------t---t----------------nnn--------------t------t----------nnn--t---w-------t-----w---t----t---w----------t-nnn--t---w---t---t------t----------nnn\nAmoolya Mannava ---t----t-----t---t---t---w--------t----------nnn---t---nnnn---t------t---t-------w---t----t----w--------nnnn--w-------nnnn-----------t----------w--------t---------t--------w--------\nRoss Kruger -----w-nnnn----------nnnn--w--------------t---t----------t---w-nnnn------t---------w-----------t---t------t------t-------t-----------t---t--------w----nnn----t--------w---t---t------\nJack Looker ---------t---------w-nnnn-------------t--------w---t----t---t------t-------w-----t---t------t-----t----w-----t----t---------w--------nnnn-------t---t--------------t-----------nnnn--w\nPete Abernethy ----t-----t---nnnn-------t---t---w------w---t----nnnn--w---------t-----t--------------------------------------------------------------------------------------------------------------\n7 e 2: ,exeter_twilight (18),weekend_exeter (7),night (15)\n6 e 2: ,exeter_twilight (18),weekend_exeter (7),night (12)\n1 e 2: ,exeter_twilight (17),weekend_exeter (7),night (14)\n11 e 3: ,exeter_twilight (1),weekend_exeter (1)\n18 e 3: ,exeter_twilight (17),weekend_exeter (7),night (15)\n27 e 4: ,exeter_twilight (9),weekend_exeter (3),night (7)\n26 e 4: ,exeter_twilight (17),weekend_exeter (7),night (13)\n25 e 4: ,exeter_twilight (18),weekend_exeter (7),night (14)\n42 e 5: ,exeter_twilight (9),weekend_exeter (3),night (8)\n41 e 5: ,exeter_twilight (6),weekend_exeter (3),night (4)\n40 e 5: \n8 p 2: ,plymouth_twilight (10),weekend_plymouth (8),night (13)\n3 p 2: ,plymouth_twilight (10),weekend_plymouth (7),night (12)\n2 p 2: ,plymouth_twilight (9),weekend_plymouth (8),night (13)\n12 p 3: ,plymouth_twilight (1),weekend_plymouth (1)\n13 p 3: ,plymouth_twilight (9),weekend_plymouth (7),night (12)\n19 p 3: ,plymouth_twilight (6),weekend_plymouth (5),night (9)\n20 p 3: ,plymouth_twilight (10),weekend_plymouth (8),night (15)\n34 p 4: ,plymouth_twilight (9),weekend_plymouth (7),night (15)\n30 p 4: ,plymouth_twilight (10),weekend_plymouth (7),night (12)\n31 p 4: ,plymouth_twilight (5),weekend_plymouth (5),night (7)\n32 p 4: ,plymouth_twilight (9),weekend_plymouth (8),night (14)\n29 p 4: ,plymouth_twilight (9),weekend_plymouth (7),night (12)\n33 p 4: ,plymouth_twilight (1),weekend_plymouth (1)\n28 p 4: ,plymouth_twilight (9),weekend_plymouth (8),night (13)\n43 p 5: ,plymouth_twilight (10),weekend_plymouth (7),night (15)\n45 p 5: ,plymouth_twilight (1),weekend_plymouth (1)\n46 p 5: ,plymouth_twilight (9),weekend_plymouth (7),night (13)\n44 p 5: ,plymouth_twilight (3),weekend_plymouth (2),night (3)\n4 t 2: ,torquay_twilight (13),weekend_torquay (5),night (14)\n9 t 2: ,torquay_twilight (13),weekend_torquay (5),night (13)\n15 t 3: ,torquay_twilight (11),weekend_torquay (4),night (10)\n14 t 3: ,torquay_twilight (12),weekend_torquay (5),night (14)\n21 t 3: ,torquay_twilight (12),weekend_torquay (5),night (12)\n22 t 3: ,torquay_twilight (12),weekend_torquay (5),night (15)\n36 t 4: ,torquay_twilight (13),weekend_torquay (5),night (13)\n35 t 4: ,torquay_twilight (13),weekend_torquay (5),night (13)\n37 t 4: ,torquay_twilight (12),weekend_torquay (5),night (12)\n49 t 5: ,torquay_twilight (5),weekend_torquay (3),night (7)\n47 t 5: ,torquay_twilight (1)\n48 t 5: ,torquay_twilight (13),weekend_torquay (5),night (14)\n5 t 2: ,truro_twilight (14),weekend_truro (6),night (15)\n10 t 2: ,truro_twilight (14),weekend_truro (6),night (15)\n24 t 3: ,truro_twilight (14),weekend_truro (5),night (15)\n23 t 3: ,truro_twilight (9),weekend_truro (4),night (8)\n17 t 3: ,truro_twilight (14),weekend_truro (5),night (14)\n16 t 3: ,truro_twilight (14),weekend_truro (5),night (12)\n39 t 4: ,truro_twilight (15),weekend_truro (6),night (15)\n38 t 4: ,truro_twilight (14),weekend_truro (6),night (15)\n50 t 5: ,truro_twilight (15),weekend_truro (6),night (12)\n51 t 5: ,truro_twilight (7),weekend_truro (3),night (8)\n" + "text": "Worker 1111111222222233333334444444\nWijhdan Abusrewil ----------------------------\nSeren Peters ----------------------------\nHannah Lewis ----------------------------\nChristian Greer ----------------------------\nNicolas Dziad ----------------------------\nMichal Tomek ----------------------------\nAlex Wood ----------------------------\nAlexander Sanchez- Cabello----------------------------\nMax Ireland ----------------------------\nVilim Kalamar ----------------------------\nSalma Aslam ----------------------------\nAdeola Omotade ----------------------------\nAmina Odeh ----------------------------\nCharles Finan ----------------------------\nAlan Eccles ----------------------------\nSarath Vennam ----------------------------\nPaul Ward ----------------------------\nSayed Alqarooni ----------------------------\nJean Sukumar ----------------------------\nJenn Fong ----------------------------\nChong Ng ----------------------------\nMatthew Thorley ----------------------------\nJenna Millington ----------------------------\nChi Leung ----------------------------\nTom Welsh ----------------------------\nRebecca Murphy ----------------------------\nDelilah Trimmer ----------------------------\nSophie McGlade ----------------------------\nS Ghauri ----------------------------\nKhalil Madbak ----------------------------\nNatasha Hougham ----------------------------\nRichard Chaytor ----------------------------\nSafi Rahman ----------------------------\nGeorge Edwards ----------------------------\nNeil McIntyre ----------------------------\nMo Babsail ----------------------------\nPaul Jenkins ----------------------------\nRoss Kruger ----------------------------\nAmoolya Mannava ----------------------------\n1 e 2: \n2 p 2: \n3 p 2: \n4 t 2: \n5 t 2: \n6 e 2: \n7 e 2: \n8 p 2: \n9 t 2: \n10 t 2: \n11 e 3: \n12 p 3: \n13 p 3: \n14 t 3: \n15 t 3: \n16 t 3: \n17 t 3: \n18 e 3: \n19 p 3: \n20 p 3: \n21 t 3: \n22 t 3: \n23 t 3: \n24 t 3: \n25 e 4: \n26 e 4: \n27 e 4: \n28 p 4: \n29 p 4: \n30 p 4: \n31 p 4: \n32 p 4: \n33 p 4: \n34 p 4: \n35 t 4: \n36 t 4: \n37 t 4: \n38 t 4: \n39 t 4: \n" } ], "source": [ @@ -968,7 +911,7 @@ { "output_type": "execute_result", "data": { - "text/plain": "5 t 3', '23 t 3']},\n 'Wed': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['50 t 5'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['43 p 5', '15 t 3', '23 t 3']},\n 'Thu': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['9 t 2'],\n 'plymouth_twilight': ['2 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['43 p 5', '15 t 3', '23 t 3']},\n 'Fri': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['35 t 4'],\n 'plymouth_twilight': ['19 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['8 p 2', '30 p 4', '32 p 4']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['6 e 2'],\n 'weekend_truro': ['10 t 2'],\n 'weekend_torquay': ['4 t 2'],\n 'weekend_plymouth': ['20 p 3', '29 p 4'],\n 'night': ['8 p 2', '30 p 4', '32 p 4']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['25 e 4'],\n 'weekend_truro': ['16 t 3'],\n 'weekend_torquay': ['15 t 3'],\n 'weekend_plymouth': ['13 p 3', '43 p 5'],\n 'night': ['8 p 2', '30 p 4', '32 p 4']}},\n 18: {'Mon': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['23 t 3'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['46 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['9 t 2', '17 t 3', '39 t 4']},\n 'Tue': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['24 t 3'],\n 'torquay_twilight': ['21 t 3'],\n 'plymouth_twilight': ['31 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['9 t 2', '17 t 3', '39 t 4']},\n 'Wed': {'exeter_twilight': ['1 e 2'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['20 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['9 t 2', '17 t 3', '39 t 4']},\n 'Thu': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['4 t 2'],\n 'plymouth_twilight': ['28 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['9 t 2', '17 t 3', '39 t 4']},\n 'Fri': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['8 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['14 t 3', '21 t 3', '36 t 4']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['26 e 4'],\n 'weekend_truro': ['50 t 5'],\n 'weekend_torquay': ['35 t 4'],\n 'weekend_plymouth': ['19 p 3', '30 p 4'],\n 'night': ['14 t 3', '21 t 3', '36 t 4']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['1 e 2'],\n 'weekend_truro': ['24 t 3'],\n 'weekend_torquay': ['48 t 5'],\n 'weekend_plymouth': ['2 p 2', '43 p 5'],\n 'night': ['14 t 3', '21 t 3', '36 t 4']}},\n 19: {'Mon': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['23 t 3'],\n 'torquay_twilight': ['4 t 2'],\n 'plymouth_twilight': ['3 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['13 p 3', '29 p 4', '22 t 3']},\n 'Tue': {'exeter_twilight': ['27 e 4'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['20 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['13 p 3', '29 p 4', '22 t 3']},\n 'Wed': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['46 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['13 p 3', '29 p 4', '22 t 3']},\n 'Thu': {'exeter_twilight': ['1 e 2'],\n 'truro_twilight': ['24 t 3'],\n 'torquay_twilight': ['9 t 2'],\n 'plymouth_twilight': ['28 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['13 p 3', '29 p 4', '22 t 3']},\n 'Fri': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['14 t 3'],\n 'plymouth_twilight': ['43 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['26 e 4', '19 p 3', '5 t 2']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['6 e 2'],\n 'weekend_truro': ['16 t 3'],\n 'weekend_torquay': ['21 t 3'],\n 'weekend_plymouth': ['8 p 2', '32 p 4'],\n 'night': ['26 e 4', '19 p 3', '5 t 2']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['25 e 4'],\n 'weekend_truro': ['17 t 3'],\n 'weekend_torquay': ['37 t 4'],\n 'weekend_plymouth': ['3 p 2', '20 p 3'],\n 'night': ['26 e 4', '19 p 3', '5 t 2']}},\n 20: {'Mon': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['15 t 3'],\n 'plymouth_twilight': ['13 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['18 e 3', '10 t 2', '50 t 5']},\n 'Tue': {'exeter_twilight': ['1 e 2'],\n 'truro_twilight': ['39 t 4'],\n 'torquay_twilight': ['35 t 4'],\n 'plymouth_twilight': ['2 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['18 e 3', '10 t 2', '50 t 5']},\n 'Wed': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['21 t 3'],\n 'plymouth_twilight': ['30 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['18 e 3', '10 t 2', '50 t 5']},\n 'Thu': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['24 t 3'],\n 'torquay_twilight': ['48 t 5'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['18 e 3', '10 t 2', '50 t 5']},\n 'Fri': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['20 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['27 e 4', '3 p 2', '14 t 3']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['41 e 5'],\n 'weekend_truro': ['23 t 3'],\n 'weekend_torquay': ['37 t 4'],\n 'weekend_plymouth': ['13 p 3', '28 p 4'],\n 'night': ['27 e 4', '3 p 2', '14 t 3']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['18 e 3'],\n 'weekend_truro': ['5 t 2'],\n 'weekend_torquay': ['21 t 3'],\n 'weekend_plymouth': ['2 p 2', '19 p 3'],\n 'night': ['27 e 4', '3 p 2', '14 t 3']}},\n 21: {'Mon': {'exeter_twilight': ['1 e 2'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['22 t 3'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['7 e 2', '13 p 3', '43 p 5']},\n 'Tue': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['34 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['7 e 2', '13 p 3', '43 p 5']},\n 'Wed': {'exeter_twilight': ['41 e 5'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['4 t 2'],\n 'plymouth_twilight': ['29 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['7 e 2', '13 p 3', '43 p 5']},\n 'Thu': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['14 t 3'],\n 'plymouth_twilight': ['3 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['7 e 2', '13 p 3', '43 p 5']},\n 'Fri': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['50 t 5'],\n 'torquay_twilight': ['35 t 4'],\n 'plymouth_twilight': ['8 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['31 p 4', '9 t 2', '16 t 3']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['1 e 2'],\n 'weekend_truro': ['39 t 4'],\n 'weekend_torquay': ['37 t 4'],\n 'weekend_plymouth': ['20 p 3', '46 p 5'],\n 'night': ['31 p 4', '9 t 2', '16 t 3']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['7 e 2'],\n 'weekend_truro': ['38 t 4'],\n 'weekend_torquay': ['36 t 4'],\n 'weekend_plymouth': ['19 p 3', '28 p 4'],\n 'night': ['31 p 4', '9 t 2', '16 t 3']}},\n 22: {'Mon': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['4 t 2'],\n 'plymouth_twilight': ['29 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['1 e 2', '20 p 3', '48 t 5']},\n 'Tue': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['50 t 5'],\n 'torquay_twilight': ['22 t 3'],\n 'plymouth_twilight': ['43 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['1 e 2', '20 p 3', '48 t 5']},\n 'Wed': {'exeter_twilight': ['27 e 4'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['34 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['1 e 2', '20 p 3', '48 t 5']},\n 'Thu': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['14 t 3'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['1 e 2', '20 p 3', '48 t 5']},\n 'Fri': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['15 t 3'],\n 'plymouth_twilight': ['28 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['26 e 4', '3 p 2', '38 t 4']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['7 e 2'],\n 'weekend_truro': ['10 t 2'],\n 'weekend_torquay': ['22 t 3'],\n 'weekend_plymouth': ['2 p 2', '43 p 5'],\n 'night': ['26 e 4', '3 p 2', '38 t 4']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['1 e 2'],\n 'weekend_truro': ['16 t 3'],\n 'weekend_torquay': ['35 t 4'],\n 'weekend_plymouth': ['8 p 2', '34 p 4'],\n 'night': ['26 e 4', '3 p 2', '38 t 4']}},\n 23: {'Mon': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['39 t 4'],\n 'torquay_twilight': ['4 t 2'],\n 'plymouth_twilight': ['20 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['25 e 4', '22 t 3', '37 t 4']},\n 'Tue': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['15 t 3'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['25 e 4', '22 t 3', '37 t 4']},\n 'Wed': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['13 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['25 e 4', '22 t 3', '37 t 4']},\n 'Thu': {'exeter_twilight': ['1 e 2'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['35 t 4'],\n 'plymouth_twilight': ['8 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['25 e 4', '22 t 3', '37 t 4']},\n 'Fri': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['48 t 5'],\n 'plymouth_twilight': ['31 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['2 p 2', '34 p 4', '30 p 4']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['6 e 2'],\n 'weekend_truro': ['5 t 2'],\n 'weekend_torquay': ['9 t 2'],\n 'weekend_plymouth': ['32 p 4', '46 p 5'],\n 'night': ['2 p 2', '34 p 4', '30 p 4']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['27 e 4'],\n 'weekend_truro': ['23 t 3'],\n 'weekend_torquay': ['4 t 2'],\n 'weekend_plymouth': ['13 p 3', '20 p 3'],\n 'night': ['2 p 2', '34 p 4', '30 p 4']}},\n 24: {'Mon': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['21 t 3'],\n 'plymouth_twilight': ['43 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['6 e 2', '32 p 4', '29 p 4']},\n 'Tue': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['14 t 3'],\n 'plymouth_twilight': ['12 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['6 e 2', '32 p 4', '29 p 4']},\n 'Wed': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['50 t 5'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['46 p 5'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['6 e 2', '32 p 4', '29 p 4']},\n 'Thu': {'exeter_twilight': ['27 e 4'],\n 'truro_twilight': ['39 t 4'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['30 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['6 e 2', '32 p 4', '29 p 4']},\n 'Fri': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['48 t 5'],\n 'plymouth_twilight': ['8 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['46 p 5', '4 t 2', '35 t 4']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['25 e 4'],\n 'weekend_truro': ['17 t 3'],\n 'weekend_torquay': ['9 t 2'],\n 'weekend_plymouth': ['3 p 2', '2 p 2'],\n 'night': ['46 p 5', '4 t 2', '35 t 4']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['1 e 2'],\n 'weekend_truro': ['38 t 4'],\n 'weekend_torquay': ['22 t 3'],\n 'weekend_plymouth': ['34 p 4', '33 p 4'],\n 'night': ['46 p 5', '4 t 2', '35 t 4']}},\n 25: {'Mon': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['16 t 3'],\n 'torquay_twilight': ['21 t 3'],\n 'plymouth_twilight': ['30 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['27 e 4', '23 t 3', '17 t 3']},\n 'Tue': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['14 t 3'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['27 e 4', '23 t 3', '17 t 3']},\n 'Wed': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['5 t 2'],\n 'torquay_twilight': ['15 t 3'],\n 'plymouth_twilight': ['31 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['27 e 4', '23 t 3', '17 t 3']},\n 'Thu': {'exeter_twilight': ['26 e 4'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['9 t 2'],\n 'plymouth_twilight': ['3 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['27 e 4', '23 t 3', '17 t 3']},\n 'Fri': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['24 t 3'],\n 'torquay_twilight': ['35 t 4'],\n 'plymouth_twilight': ['13 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['7 e 2', '34 p 4', '15 t 3']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['6 e 2'],\n 'weekend_truro': ['39 t 4'],\n 'weekend_torquay': ['37 t 4'],\n 'weekend_plymouth': ['30 p 4', '46 p 5'],\n 'night': ['7 e 2', '34 p 4', '15 t 3']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['1 e 2'],\n 'weekend_truro': ['10 t 2'],\n 'weekend_torquay': ['4 t 2'],\n 'weekend_plymouth': ['20 p 3', '29 p 4'],\n 'night': ['7 e 2', '34 p 4', '15 t 3']}},\n 26: {'Mon': {'exeter_twilight': ['25 e 4'],\n 'truro_twilight': ['38 t 4'],\n 'torquay_twilight': ['9 t 2'],\n 'plymouth_twilight': ['3 p 2'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['22 t 3', '5 t 2', '50 t 5']},\n 'Tue': {'exeter_twilight': ['41 e 5'],\n 'truro_twilight': ['24 t 3'],\n 'torquay_twilight': ['21 t 3'],\n 'plymouth_twilight': ['13 p 3'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['22 t 3', '5 t 2', '50 t 5']},\n 'Wed': {'exeter_twilight': ['7 e 2'],\n 'truro_twilight': ['17 t 3'],\n 'torquay_twilight': ['15 t 3'],\n 'plymouth_twilight': ['32 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['22 t 3', '5 t 2', '50 t 5']},\n 'Thu': {'exeter_twilight': ['6 e 2'],\n 'truro_twilight': ['23 t 3'],\n 'torquay_twilight': ['36 t 4'],\n 'plymouth_twilight': ['30 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['22 t 3', '5 t 2', '50 t 5']},\n 'Fri': {'exeter_twilight': ['18 e 3'],\n 'truro_twilight': ['10 t 2'],\n 'torquay_twilight': ['37 t 4'],\n 'plymouth_twilight': ['29 p 4'],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': ['1 e 2', '25 e 4', '16 t 3']},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['41 e 5'],\n 'weekend_truro': ['24 t 3'],\n 'weekend_torquay': ['21 t 3'],\n 'weekend_plymouth': ['8 p 2', '20 p 3'],\n 'night': ['1 e 2', '25 e 4', '16 t 3']},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': ['26 e 4'],\n 'weekend_truro': ['50 t 5'],\n 'weekend_torquay': ['14 t 3'],\n 'weekend_plymouth': ['19 p 3', '28 p 4'],\n 'night': ['1 e 2', '25 e 4', '16 t 3']}}}" + "text/plain": "{1: {'Mon': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Tue': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Wed': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Thu': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Fri': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []}},\n 2: {'Mon': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Tue': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Wed': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Thu': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Fri': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []}},\n 3: {'Mon': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Tue': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Wed': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Thu': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Fri': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []}},\n 4: {'Mon': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Tue': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Wed': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Thu': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Fri': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sat': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []},\n 'Sun': {'exeter_twilight': [],\n 'truro_twilight': [],\n 'torquay_twilight': [],\n 'plymouth_twilight': [],\n 'weekend_exeter': [],\n 'weekend_truro': [],\n 'weekend_torquay': [],\n 'weekend_plymouth': [],\n 'night': []}}}" }, "metadata": {}, "execution_count": 22 diff --git a/shifts.py b/shifts.py index e4d109e..0fee533 100644 --- a/shifts.py +++ b/shifts.py @@ -1,6 +1,10 @@ import datetime import itertools +from typing import List, Tuple +ShiftName = str +DayStr = str +WeekInt = int days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] @@ -11,7 +15,9 @@ days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] sites = ("truro", "exeter", "torquay", "barnstaple", "plymouth") -class ShiftsClass(object): +class SingleShift(object): + """Class to hold all details for a shift""" + def __init__( self, sites, @@ -32,8 +38,10 @@ class ShiftsClass(object): class ShiftCollection(object): + """Class to hold and manipulate shifts""" + def __init__(self, weeks_to_rota=26): - self.shifts = [] + self.shifts = [] # type List[SingleShift] self.weeks = [i for i in range(1, weeks_to_rota + 1)] @@ -43,27 +51,56 @@ class ShiftCollection(object): self.rota_days_length = len(self.weeks) * 7 self.rota_end_date = self.start_date + datetime.timedelta(self.rota_days_length) - def AddShift(self, shift): - """Add a shift to the collection""" + def add_shift(self, shift): + """Add a shift to the collection + + :param SingleShift shift: Shift object + + """ self.shifts.append(shift) self.BuildShifts() - def AddShifts(self, *shifts): + def add_shifts(self, *shifts: SingleShift): + """Add multiple shifts + + Returns: + None + """ self.shifts.extend(shifts) self.BuildShifts() - def GetShiftNamesByDay(self, day): + def GetShiftNamesByDay(self, day: DayStr): + """Returns the shifts required for a specific day + + Returns: + set: Set of ShiftName + + """ return self.day_shifts_dict[day] def GetShiftByName(self, name): + """ + + :param name: + + """ return self.shifts_by_name[name] def GetShiftLengthByName(self, name): + """Get the length of a shift + + Args: + name (str): Name of a shift + + Returns: + int: Length of the shift + """ return self.shifts_by_name[name].length def BuildShifts(self): + """ """ self.shifts_by_name = {} - self.shift_names = [] + self.shift_names = [] # type: List[ShiftName] self.day_shifts_dict = {day: set() for day in days} @@ -91,33 +128,85 @@ class ShiftCollection(object): self.day_shiftclass_product.append((day, s)) def GetAllDayShiftsAsNames(self): + """Returns a list of all required day / shift combinations + + Returns: + list: list of in the following format (str->day, str->shift) + """ return self.day_shift_product - def GetAllDayShiftsAsClass(self): + def GetAllDayShiftsAsClass(self) -> List[Tuple[DayStr, SingleShift]]: + """Returns a list of all required day / shift combinations + + Returns: + list: list of in the following format (str->day, shiftObject->shift) + """ return self.day_shiftclass_product - def GetAllShiftsAsNames(self): + def GetAllShiftsAsNames(self) -> List[Tuple[WeekInt, DayStr, ShiftName]]: + """Returns a list of all possible week / day / shift combinations + + Returns: + list: contains tuple of all possible week / day / shift combinations + """ return self.week_day_shift_product - def GetAllShiftsAsClass(self): + def GetAllShiftsAsClass(self) -> List[SingleShift]: + """ """ return self.week_day_shiftclass_product - def GetAllWeeksDays(self): + def GetAllWeeksDays(self) -> list: + """Returns a list of all week / day tuple combinations + + Returns: + list: list of possible week day combinations + [(1, "Mon"), (1, "Tue"), ... (n, "Fri")] + """ return self.weeks_days_product - def GetShiftOptions(self): + def GetShiftOptions(self) -> List[SingleShift]: + """Returns a list of all the registered shifts + + Returns: + List[SingleShift]: list of registered shifts (as SingleShift) + """ return self.shifts - def GetShiftNames(self): + def GetShiftNames(self) -> List[ShiftName]: + """Returns a list of all the registered shift names + + Returns: + List[ShiftName]: List of names of all available shifts + """ """ """ return self.shift_names def GetWeeksInBlocks(self, block_length): + """Gets a two dimensional list of week blocks in specified length + + e.g. block_length = 4 + [ + [ 1, 2, 3, 4], + [ 2, 3, 4, 5], + ... + ] + + Args: + block_length (int): length of blocks to create + + Returns: + list: two dimensional list containing weeks in blocks + """ blocks = [] for i in range(len(self.weeks)): blocks.append(self.weeks[i : i + block_length]) return blocks def GetRequiredShiftsWorkersAndSites(self): + """Returns a list of all possible shifts, the workers required and site + + Returns: + list: list (week, day, shift name, workers required, shift site) + """ l = [] for week, day, shift in self.week_day_shiftclass_product: if day in shift.shift_days: @@ -126,6 +215,13 @@ class ShiftCollection(object): return l def GetNotRequiredShifts(self): + """Returns a set of all possible shifts combinations that are not required + + Includes those on days + + Returns: + list: (week, day, shift) + """ l = set() for week in self.weeks: diff --git a/workers.py b/workers.py new file mode 100644 index 0000000..d423065 --- /dev/null +++ b/workers.py @@ -0,0 +1,60 @@ +import datetime + +from shifts import SingleShift, ShiftCollection, days, sites + + +class Worker: + def __init__(self, Shifts, id, name, site, grade, fte=100, nwd=[], end_date=None, oop=None): + self.id = id + self.name = name + self.site = site + self.grade = grade + self.fte = fte + self.nwd = nwd + self.proportion_rota_to_work = 1 + + days_to_work = Shifts.rota_days_length + + if end_date is None: + self.end_date = None + else: + self.end_date = datetime.datetime.strptime(end_date, '%Y/%m/%d').date() + + if self.end_date > Shifts.rota_end_date: + self.end_date = Shifts.rota_end_date + else: + days_to_work = (self.end_date - Shifts.start_date).days + + # add unavalabilities + for weeks_days in Shifts.weeks_days_product[days_to_work:]: + week, day = weeks_days + unavailable_to_work.add((self.id, week, day)) + + if oop is not None: + start_oop, end_oop = oop + start_oop_date = datetime.datetime.strptime(start_oop, '%Y/%m/%d').date() + end_oop_date = datetime.datetime.strptime(end_oop, '%Y/%m/%d').date() + + if end_oop_date > Shifts.rota_end_date: + end_oop_date = Shifts.rota_end_date + + oop_length = (end_oop_date - start_oop_date).days + days_to_work = days_to_work - oop_length + + days_until_oop = (start_oop_date - Shifts.start_date).days + + for weeks_days in Shifts.weeks_days_product[days_until_oop:days_until_oop+oop_length]: + week, day = weeks_days + unavailable_to_work.add((self.id, week, day)) + + + self.proportion_rota_to_work = days_to_work / Shifts.rota_days_length + + # We had to adjust the full time equivalent for people who CCT / leave the rota early + self.fte_adj = self.fte * self.proportion_rota_to_work + + def __lt__(self, other): + return (self.site, self.grade, self.name) < (other.site, other.grade, other.name) + + def get_details(self): + return "{} {} {}".format(self.id, self.site[0], self.grade) \ No newline at end of file