|
1 | 1 | import gc |
| 2 | +import json |
2 | 3 | import os |
3 | 4 | import re |
4 | 5 | from datetime import datetime |
|
39 | 40 | from term_timer.interface.console import console |
40 | 41 | from term_timer.methods import METHOD_ANALYSERS |
41 | 42 | from term_timer.methods.base import get_step_config |
| 43 | +from term_timer.methods.cases import CASES |
42 | 44 | from term_timer.orientation import ORIENTATION_MOVES |
43 | 45 | from term_timer.solve import Solve |
44 | 46 | from term_timer.stats import Statistics |
@@ -676,6 +678,160 @@ def __init__(self, cube, session, solve_id): |
676 | 678 | redirect(f'/{ cube }/{ session }/') |
677 | 679 |
|
678 | 680 |
|
| 681 | +class AcademyView(View): |
| 682 | + template_name = 'academy/overview.html' |
| 683 | + methods = { |
| 684 | + 'CFOP': { |
| 685 | + 'name': 'CFOP', |
| 686 | + 'description': ( |
| 687 | + 'Cross, F2L, OLL, PLL - The most popular speedcubing method' |
| 688 | + ), |
| 689 | + 'steps': { |
| 690 | + 'F2L': { |
| 691 | + 'name': 'F2L', |
| 692 | + 'description': ( |
| 693 | + 'First Two Layers - ' |
| 694 | + 'Solve cross and first two layers simultaneously' |
| 695 | + ), |
| 696 | + 'description_alt': ( |
| 697 | + 'Solve the cross and first two layers simultaneously ' |
| 698 | + 'using corner-edge pairs.' |
| 699 | + ), |
| 700 | + }, |
| 701 | + 'OLL': { |
| 702 | + 'name': 'OLL', |
| 703 | + 'description': ( |
| 704 | + 'Orientation of Last Layer - ' |
| 705 | + 'Orient all pieces on the last layer' |
| 706 | + ), |
| 707 | + 'description_alt': ( |
| 708 | + 'Orient all pieces on the last layer ' |
| 709 | + 'to show the same color on top.' |
| 710 | + ), |
| 711 | + }, |
| 712 | + 'PLL': { |
| 713 | + 'name': 'PLL', |
| 714 | + 'description': ( |
| 715 | + 'Permutation of Last Layer - ' |
| 716 | + 'Permute all pieces on the last layer' |
| 717 | + ), |
| 718 | + 'description_alt': ( |
| 719 | + 'Permute all pieces on the last layer ' |
| 720 | + 'to their correct positions.' |
| 721 | + ), |
| 722 | + }, |
| 723 | + }, |
| 724 | + }, |
| 725 | + } |
| 726 | + |
| 727 | + def get_context(self): |
| 728 | + return { |
| 729 | + 'methods': self.methods, |
| 730 | + } |
| 731 | + |
| 732 | + |
| 733 | +class AcademyStepView(AcademyView): |
| 734 | + template_name = 'academy/step.html' |
| 735 | + |
| 736 | + def __init__(self, step): |
| 737 | + self.step = step.upper() |
| 738 | + |
| 739 | + try: |
| 740 | + self.cases_data = CASES[self.step] |
| 741 | + except KeyError: |
| 742 | + abort(404, f'{ self.step } does not exist') |
| 743 | + |
| 744 | + def get_context(self): |
| 745 | + cases = [] |
| 746 | + |
| 747 | + for case_id, case_data in self.cases_data.items(): |
| 748 | + case_info = { |
| 749 | + 'id': case_id, |
| 750 | + 'name': case_data['name'], |
| 751 | + 'main_algorithm': case_data['main'], |
| 752 | + 'masks_count': len(case_data['masks']), |
| 753 | + } |
| 754 | + if self.step == 'OLL': |
| 755 | + try: |
| 756 | + case_info['code'], case_info['name'], _ = parse_case_name( |
| 757 | + case_data['name'], self.step, |
| 758 | + ) |
| 759 | + except: |
| 760 | + case_info['code'] = case_id |
| 761 | + case_info['name'] = case_id |
| 762 | + elif self.step == 'PLL': |
| 763 | + case_info['code'] = case_id |
| 764 | + case_info['name'] = f'PLL {case_id}' |
| 765 | + elif self.step == 'F2L': |
| 766 | + case_info['code'] = case_id |
| 767 | + case_info['name'] = f'F2L {case_id}' |
| 768 | + |
| 769 | + cases.append(case_info) |
| 770 | + |
| 771 | + return { |
| 772 | + 'step': self.step, |
| 773 | + 'step_info': self.methods['CFOP']['steps'][self.step], |
| 774 | + 'cases': cases, |
| 775 | + 'cases_count': len(cases), |
| 776 | + } |
| 777 | + |
| 778 | + |
| 779 | +class AcademyCaseView(AcademyView): |
| 780 | + template_name = 'academy/case.html' |
| 781 | + |
| 782 | + def __init__(self, step, case_id): |
| 783 | + self.step = step.upper() |
| 784 | + self.case_id = case_id |
| 785 | + |
| 786 | + try: |
| 787 | + self.case_data = CASES[self.step][self.case_id] |
| 788 | + except KeyError: |
| 789 | + abort(404, f'{ self.step } { self.case_id } does not exist') |
| 790 | + |
| 791 | + def get_context(self): |
| 792 | + case_info = { |
| 793 | + 'id': self.case_id, |
| 794 | + 'name': self.case_id, |
| 795 | + 'main_algorithm': self.case_data['main'], |
| 796 | + 'probability': self.case_data['probability_label'], |
| 797 | + } |
| 798 | + |
| 799 | + if self.step == 'OLL': |
| 800 | + try: |
| 801 | + case_info['code'], case_info['name'], _ = parse_case_name(self.case_id, self.step) |
| 802 | + except: |
| 803 | + case_info['code'] = self.case_id |
| 804 | + case_info['name'] = self.case_id |
| 805 | + elif self.step == 'PLL': |
| 806 | + case_info['code'] = self.case_id |
| 807 | + case_info['name'] = f'PLL {self.case_id}' |
| 808 | + elif self.step == 'F2L': |
| 809 | + case_info['code'] = self.case_id |
| 810 | + case_info['name'] = f'F2L {self.case_id}' |
| 811 | + |
| 812 | + # Process masks for different orientations |
| 813 | + orientations = [] |
| 814 | + masks = self.case_data.get('masks', {}) |
| 815 | + for mask, aufs in masks.items(): |
| 816 | + orientations.append({ |
| 817 | + 'mask': mask, |
| 818 | + 'aufs': aufs, |
| 819 | + }) |
| 820 | + |
| 821 | + # Process setup algorithms |
| 822 | + setups = self.case_data.get('setups', []) |
| 823 | + |
| 824 | + return { |
| 825 | + 'step': self.step, |
| 826 | + 'step_info': self.methods['CFOP']['steps'][self.step], |
| 827 | + 'case': case_info, |
| 828 | + 'orientations': orientations, |
| 829 | + 'orientations_count': len(orientations), |
| 830 | + 'setups': setups, |
| 831 | + 'setups_count': len(setups), |
| 832 | + } |
| 833 | + |
| 834 | + |
679 | 835 | class Server: |
680 | 836 |
|
681 | 837 | def run_server(self, host, port, debug): |
@@ -720,6 +876,18 @@ def add_trailing_slash(): |
720 | 876 | def session_list(): |
721 | 877 | return SessionListView().as_view(debug) |
722 | 878 |
|
| 879 | + @app.route('/academy/') |
| 880 | + def academy_overview(): |
| 881 | + return AcademyView().as_view(debug) |
| 882 | + |
| 883 | + @app.route('/academy/<step>/') |
| 884 | + def academy_step(step): |
| 885 | + return AcademyStepView(step).as_view(debug) |
| 886 | + |
| 887 | + @app.route('/academy/<step>/<case_id>/') |
| 888 | + def academy_case(step, case_id): |
| 889 | + return AcademyCaseView(step, case_id).as_view(debug) |
| 890 | + |
723 | 891 | @app.route('/<cube:int>/<session:path>/<solve:int>/update/', |
724 | 892 | method='POST') |
725 | 893 | def solve_update(cube, session, solve): |
|
0 commit comments