From efd5d9bfec15b03060daf4d2997f22a6a71219a5 Mon Sep 17 00:00:00 2001 From: Joshua Saikali <91435428+JoshuaSaikali@users.noreply.github.com> Date: Sat, 20 Nov 2021 16:06:36 -0500 Subject: [PATCH 1/5] Dynamic service routes query (#128) * added route map to router.py * added dynamic service routes query * lint fixes Co-authored-by: JoshuaSaikali --- api/app/graphql/queries/dynamic_routes.rb | 10 ++++++++++ .../graphql/types/dynamic_topic_option_type.rb | 7 +++++++ api/app/graphql/types/dynamic_topic_type.rb | 7 +++++++ api/app/graphql/types/query_type.rb | 1 + api/app/services/fetch_dynamic_routes.rb | 16 ++++++++++++++++ 5 files changed, 41 insertions(+) create mode 100644 api/app/graphql/queries/dynamic_routes.rb create mode 100644 api/app/graphql/types/dynamic_topic_option_type.rb create mode 100644 api/app/graphql/types/dynamic_topic_type.rb create mode 100644 api/app/services/fetch_dynamic_routes.rb diff --git a/api/app/graphql/queries/dynamic_routes.rb b/api/app/graphql/queries/dynamic_routes.rb new file mode 100644 index 00000000..161f64ca --- /dev/null +++ b/api/app/graphql/queries/dynamic_routes.rb @@ -0,0 +1,10 @@ +module Queries + class DynamicRoutes < Queries::BaseQuery + description 'Gets all routes from dynamic service' + type [Types::DynamicTopicType], null: false + + def resolve + FetchDynamicRoutes.new.call + end + end +end diff --git a/api/app/graphql/types/dynamic_topic_option_type.rb b/api/app/graphql/types/dynamic_topic_option_type.rb new file mode 100644 index 00000000..c5303bfa --- /dev/null +++ b/api/app/graphql/types/dynamic_topic_option_type.rb @@ -0,0 +1,7 @@ +module Types + class DynamicTopicOptionType < Types::BaseObject + description 'A type that represents a options for generating a dynamic question.' + field :name, String, null: false + field :route, String, null: false + end +end diff --git a/api/app/graphql/types/dynamic_topic_type.rb b/api/app/graphql/types/dynamic_topic_type.rb new file mode 100644 index 00000000..b5e6f06c --- /dev/null +++ b/api/app/graphql/types/dynamic_topic_type.rb @@ -0,0 +1,7 @@ +module Types + class DynamicTopicType < Types::BaseObject + description 'A type that represents a topic within dynamic service.' + field :name, String, null: false + field :options, [Types::DynamicTopicOptionType], null: false + end +end diff --git a/api/app/graphql/types/query_type.rb b/api/app/graphql/types/query_type.rb index d8abeef6..b39558fc 100644 --- a/api/app/graphql/types/query_type.rb +++ b/api/app/graphql/types/query_type.rb @@ -8,5 +8,6 @@ class QueryType < Types::BaseObject field :tests, resolver: Queries::Tests field :multiple_choice_questions, resolver: Queries::MultipleChoiceQuestions field :questions, resolver: Queries::Questions + field :dynamic_routes, resolver: Queries::DynamicRoutes end end diff --git a/api/app/services/fetch_dynamic_routes.rb b/api/app/services/fetch_dynamic_routes.rb new file mode 100644 index 00000000..2343a439 --- /dev/null +++ b/api/app/services/fetch_dynamic_routes.rb @@ -0,0 +1,16 @@ +class FetchDynamicRoutes + def initialize; end + + def call(path = 'http://127.0.0.1:8000/api/') + data = HTTParty.get(path, + headers: { 'Content-Type' => 'application/json' }) + .parsed_response + topics = [] + data.each_key do |key| + question_routes = data[key.to_s] + questions_list = question_routes.map { |k, v| OpenStruct.new(name: k, route: v) } + topics << OpenStruct.new(name: key, options: questions_list) + end + topics + end +end From f8664234743402ee99ecb2f058bd75641deea546 Mon Sep 17 00:00:00 2001 From: Joshua Saikali <91435428+JoshuaSaikali@users.noreply.github.com> Date: Fri, 26 Nov 2021 12:39:39 -0500 Subject: [PATCH 2/5] Added routes query (#129) --- client/src/data/index.js | 2 +- .../queries/DynamicRoutes/Routes.example.js | 35 +++++++++++++++++++ .../queries/DynamicRoutes/Routes.query.js | 15 ++++++++ .../src/data/queries/DynamicRoutes/index.js | 2 ++ client/src/data/queries/index.js | 1 + .../getDynamicRoutes/Routes.service.js | 14 ++++++++ .../data/services/getDynamicRoutes/index.js | 1 + client/src/data/services/index.js | 1 + 8 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 client/src/data/queries/DynamicRoutes/Routes.example.js create mode 100644 client/src/data/queries/DynamicRoutes/Routes.query.js create mode 100644 client/src/data/queries/DynamicRoutes/index.js create mode 100644 client/src/data/services/getDynamicRoutes/Routes.service.js create mode 100644 client/src/data/services/getDynamicRoutes/index.js diff --git a/client/src/data/index.js b/client/src/data/index.js index f57f9734..91e0a458 100644 --- a/client/src/data/index.js +++ b/client/src/data/index.js @@ -1 +1 @@ -export {getTest, getCourse, getCourseSession} from './services'; +export {getTest, getCourse, getCourseSession, getRoutes} from './services'; diff --git a/client/src/data/queries/DynamicRoutes/Routes.example.js b/client/src/data/queries/DynamicRoutes/Routes.example.js new file mode 100644 index 00000000..dcbcd03d --- /dev/null +++ b/client/src/data/queries/DynamicRoutes/Routes.example.js @@ -0,0 +1,35 @@ +const ROUTES_EXAMPLE_DATA = { + loading: false, + data: { + dynamicRoutes: [ + { + name: 'demo', + options: [ + { + name: 'graph_theory', + route: '/demo/graph-theory' + } + ] + }, + { + name: 'comp2804', + options: [ + { + name: 'bitstrings-of-length', + route: '/comp2804/bitstrings-of-length' + }, + { + name: 'set-theory-question', + route: '/comp2804/set-theory' + }, + { + name: 'num-of-functions', + route: '/comp2804/num-of-functions' + } + ] + } + ] + } +}; + +export {ROUTES_EXAMPLE_DATA}; diff --git a/client/src/data/queries/DynamicRoutes/Routes.query.js b/client/src/data/queries/DynamicRoutes/Routes.query.js new file mode 100644 index 00000000..13800a84 --- /dev/null +++ b/client/src/data/queries/DynamicRoutes/Routes.query.js @@ -0,0 +1,15 @@ +import {gql} from 'graphql-tag'; + +const ROUTES = gql` + query { + dynamicRoutes { + name + options { + name + route + } + } + } +`; + +export {ROUTES}; diff --git a/client/src/data/queries/DynamicRoutes/index.js b/client/src/data/queries/DynamicRoutes/index.js new file mode 100644 index 00000000..de6954c4 --- /dev/null +++ b/client/src/data/queries/DynamicRoutes/index.js @@ -0,0 +1,2 @@ +export {ROUTES} from './Routes.query'; +export {ROUTES_EXAMPLE_DATA} from './Routes.example'; diff --git a/client/src/data/queries/index.js b/client/src/data/queries/index.js index 7d89fd90..f7ad3f92 100644 --- a/client/src/data/queries/index.js +++ b/client/src/data/queries/index.js @@ -1,3 +1,4 @@ export {TEST, TEST_EXAMPLE_DATA} from './Test'; export {COURSE, COURSE_EXAMPLE_DATA} from './Course'; export {COURSESESSION, COURSESESSION_EXAMPLE_DATA} from './CourseSession'; +export {ROUTES, ROUTES_EXAMPLE_DATA} from './DynamicRoutes'; diff --git a/client/src/data/services/getDynamicRoutes/Routes.service.js b/client/src/data/services/getDynamicRoutes/Routes.service.js new file mode 100644 index 00000000..b2d181e2 --- /dev/null +++ b/client/src/data/services/getDynamicRoutes/Routes.service.js @@ -0,0 +1,14 @@ +import {query} from 'svelte-apollo'; +import {ROUTES, ROUTES_EXAMPLE_DATA} from '../../queries'; +import {readable} from 'svelte/store'; + +const getRoutes = () => { + // ENV VAR TO HIT API INSTEAD OF MOCK + if (process.env['USE_API'] === 'true') { + return query(ROUTES); + } else { + return readable(ROUTES_EXAMPLE_DATA, () => {}); + } +}; + +export {getRoutes}; diff --git a/client/src/data/services/getDynamicRoutes/index.js b/client/src/data/services/getDynamicRoutes/index.js new file mode 100644 index 00000000..dc9c49a6 --- /dev/null +++ b/client/src/data/services/getDynamicRoutes/index.js @@ -0,0 +1 @@ +export {getRoutes} from './Routes.service'; diff --git a/client/src/data/services/index.js b/client/src/data/services/index.js index acb7d41d..af83cffe 100644 --- a/client/src/data/services/index.js +++ b/client/src/data/services/index.js @@ -1,3 +1,4 @@ export {getTest} from './getTest'; export {getCourse} from './getCourse'; export {getCourseSession} from './getCourseSession'; +export {getRoutes} from './getDynamicRoutes'; From 67f8edb03348670444094271d731939b20472719 Mon Sep 17 00:00:00 2001 From: Noah Yi <91349811+NoahTheCorgi@users.noreply.github.com> Date: Sat, 27 Nov 2021 17:08:31 -0500 Subject: [PATCH 3/5] Readme updates for other future contributors + Basic Books and Shelves Generator (#119) * readme updates details about exactly how to implement the generators as well as copyright and course material permissions if any. * readme updates in dynamic: wording changes * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * basic books in shelves code * test_main.py updated so that it won't error due to randomized generation * Update main.py * Updated generate_question() in main.py so that three different types of books in shelves problems can be generated The generate_question() in main.py now randomly creates the following three types of books in shelves questions. 1. How many ways to organize $a$ books in $b$ number of book shelves? 2. How many ways to organize $a$ books in $n$ out of $b$ bookshelves? (i.e. exactly $n$ out of $b$ shelves must be used.) 3. How many ways to organize $a$ books in $b$ number of bookshelves? ALL shelves must be used (i.e. there cannot be empty bookshelves.) * question detail debugged * Update main.py * Update main.py * Updated test_main so that it actually tests the properly asserts the proper question and answers dictionary * readme wrong data type mentioned fixed "string data" was fixed to "dictionary" * readme updates details about exactly how to implement the generators as well as copyright and course material permissions if any. * readme updates in dynamic: wording changes * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * Update readme.md * basic books in shelves code * test_main.py updated so that it won't error due to randomized generation * Update main.py * Updated generate_question() in main.py so that three different types of books in shelves problems can be generated The generate_question() in main.py now randomly creates the following three types of books in shelves questions. 1. How many ways to organize $a$ books in $b$ number of book shelves? 2. How many ways to organize $a$ books in $n$ out of $b$ bookshelves? (i.e. exactly $n$ out of $b$ shelves must be used.) 3. How many ways to organize $a$ books in $b$ number of bookshelves? ALL shelves must be used (i.e. there cannot be empty bookshelves.) * question detail debugged * Update main.py * Update main.py * Updated test_main so that it actually tests the properly asserts the proper question and answers dictionary * readme wrong data type mentioned fixed "string data" was fixed to "dictionary" * Update .gitignore * comments clean up * Completed All Books in Shelves Type Questions This updated comprehensively covers all Books in Shelves type questions. The following major changes were implemented in addition to some misc. minor changes. 1. There are 4 different types of "books_shelves_i" type generators that each generate a specific type of Books in Shelves Question. 2. There is a "books_shelves_random" generator that generates one of the 4 types of questions randomly when called. 3. router.py was updated to accommodate all the new generators. * test commit * Create main.py * test_main fix attempt * Update test_main.py * got rid of global attributes of the variables and updated variable name * test_main reworked using new TestOutput.py test_main fix framework Just need to write the "check_mathjax_compatible" method in TestOutput.py * Update TestOutput.py * Cleaned up spacing and empty lines Got rid of print statements that were for debugging. * various fixes for test_output and code reusability * test_output small update * test * Update test_output.py * Update test_output.py * test * test * adjusted test_out.py (there seems to be a bug in the "checks" testing side on github) * helper functions implemented to simplify and clean up each generators' code * stack edit implemented for readme files * final commit (fixed all bugs) * quick test * Update test_main.py * "fixture bug" fixed * Update Navbar.svelte * Update HeaderInformation.svelte * Update HeaderInformation.svelte * add pytest cache * removed uneccesary variables * remove unused functions * add init pys * minor syntax changes * Update books_shelves_helperfunctions.py The answer choices output will have better mathematical mathjax syntax * Update books_shelves_helperfunctions.py deleted the commented out codes * remove package-lock * Fixed import issue Co-authored-by: MathyouMB --- .gitignore | 2 + .../HeaderInformation.svelte | 7 -- dynamic/generators/books_shelves/__init__.py | 0 .../books_shelves/books_shelves_0/__init__.py | 0 .../books_shelves/books_shelves_0/main.py | 67 +++++++++++ .../books_shelves/books_shelves_1/__init__.py | 0 .../books_shelves/books_shelves_1/main.py | 76 ++++++++++++ .../books_shelves/books_shelves_2/__init__.py | 0 .../books_shelves/books_shelves_2/main.py | 69 +++++++++++ .../books_shelves/books_shelves_3/__init__.py | 0 .../books_shelves/books_shelves_3/main.py | 75 ++++++++++++ .../books_shelves_helperfunctions.py | 69 +++++++++++ dynamic/generators/books_shelves/test_main.py | 14 +++ dynamic/generators/books_shelves/test_out.py | 110 ++++++++++++++++++ dynamic/generators/readme.md | 43 +++++++ dynamic/readme.md | 39 +++++++ dynamic/router.py | 58 ++++++--- test_output backup | 99 ++++++++++++++++ 18 files changed, 708 insertions(+), 20 deletions(-) create mode 100644 dynamic/generators/books_shelves/__init__.py create mode 100644 dynamic/generators/books_shelves/books_shelves_0/__init__.py create mode 100644 dynamic/generators/books_shelves/books_shelves_0/main.py create mode 100644 dynamic/generators/books_shelves/books_shelves_1/__init__.py create mode 100644 dynamic/generators/books_shelves/books_shelves_1/main.py create mode 100644 dynamic/generators/books_shelves/books_shelves_2/__init__.py create mode 100644 dynamic/generators/books_shelves/books_shelves_2/main.py create mode 100644 dynamic/generators/books_shelves/books_shelves_3/__init__.py create mode 100644 dynamic/generators/books_shelves/books_shelves_3/main.py create mode 100644 dynamic/generators/books_shelves/books_shelves_helperfunctions.py create mode 100644 dynamic/generators/books_shelves/test_main.py create mode 100644 dynamic/generators/books_shelves/test_out.py create mode 100644 test_output backup diff --git a/.gitignore b/.gitignore index 8e404010..47a6d0e7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,7 @@ stories .env __pycache__ +.pytest_cache .DS_Store + diff --git a/client/src/components/Header/HeaderInformation/HeaderInformation.svelte b/client/src/components/Header/HeaderInformation/HeaderInformation.svelte index c61d2f59..02590248 100644 --- a/client/src/components/Header/HeaderInformation/HeaderInformation.svelte +++ b/client/src/components/Header/HeaderInformation/HeaderInformation.svelte @@ -25,30 +25,25 @@ margin-bottom: 1rem; text-align: center; } - .header-image { height: 5rem; margin-bottom: 1.5rem; } - .header-title { font-size: 75px; font-weight: 700; margin-bottom: 1rem; } - .header-description { max-width: 70rem; margin-bottom: 2rem; font-size: 20px; } - .button-container { display: flex; gap: 1rem; justify-content: center; } - .header-version { width: fit-content; margin: auto; @@ -60,13 +55,11 @@ DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace; margin-bottom: 0.75rem; } - @media only screen and (max-width: 800px) { .header-information { margin-top: 1rem; } } - @media only screen and (max-width: 500px) { .header-image { height: 3rem; diff --git a/dynamic/generators/books_shelves/__init__.py b/dynamic/generators/books_shelves/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/books_shelves/books_shelves_0/__init__.py b/dynamic/generators/books_shelves/books_shelves_0/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/books_shelves/books_shelves_0/main.py b/dynamic/generators/books_shelves/books_shelves_0/main.py new file mode 100644 index 00000000..d4627715 --- /dev/null +++ b/dynamic/generators/books_shelves/books_shelves_0/main.py @@ -0,0 +1,67 @@ +"""How many ways are there to organize " + str(a) + " number of books with " ++ str(b) + " number of bookshelves? (Not all shelves need to be used.)""" + +import random +from .. import books_shelves_helperfunctions + +# generates three different kinds of books and shelves problem +# the kind of problems are determined by the randomized three types of restrictions +def generate_question(): + + a = random.randint(5, 10) + b = random.randint(5, 10) + + question_body = ( + "How many ways are there to organize " + + str(a) + + " number of books with " + + str(b) + + " number of bookshelves? (Not all shelves need to be used.)" + ) + + num_denom_pairs = [ + [a + b - 1, b - 1] + ] # [[1, 2], [3,4], [5, 6]] --> 1/2! * 3!/4! * 5!/6! + answer = books_shelves_helperfunctions.create_factorial_fraction_answer( + num_denom_pairs + ) + + varied_answers = books_shelves_helperfunctions.varied_answers( + num_denom_pairs + ) # or something a little different + + # we will not randomize the order of these choices because that is handled in ruby? + # random.shuffle(answerchoices) + + return { + "title": "books in shelves", + "body": question_body, + "bodyFormat": "text", + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": answer, + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": varied_answers[0], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[1], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[2], + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + +def call(): + return generate_question() diff --git a/dynamic/generators/books_shelves/books_shelves_1/__init__.py b/dynamic/generators/books_shelves/books_shelves_1/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/books_shelves/books_shelves_1/main.py b/dynamic/generators/books_shelves/books_shelves_1/main.py new file mode 100644 index 00000000..99bd7c8c --- /dev/null +++ b/dynamic/generators/books_shelves/books_shelves_1/main.py @@ -0,0 +1,76 @@ +"""How many ways are there to organize " + str(a) + " number of books using exactly " + + str(n) + " shelves out of " + str(b) + " number of bookshelves? (The order of books matter.)""" + +import random +from .. import books_shelves_helperfunctions + +# generates three different kinds of books and shelves problem +# the kind of problems are determined by the randomized three types of restrictions +def generate_question(): + + a = random.randint(5, 10) + b = random.randint(5, 10) + + n = random.randint( + b // 2, b - 1 + ) # sub-number of shelves that will be used to store books #btw, randint is inclusive on bounds + + question_body = ( + "How many ways are there to organize " + + str(a) + + " number of books using exactly " + + str(n) + + " shelves out of " + + str(b) + + " number of bookshelves? (The order of books matter.)" + ) + + num_denom_pairs = [ + [a + n - 1, n - 1], + [b, b - n], + [1, n], + ] # answer = "$\\frac{"+str(a+n-1)+"!}{"+str((n-1))+"!} \\cdot \\frac{"+str(b)+"!}{"+str(n)+"!"+str(b-n)+"!}$" + + answer = books_shelves_helperfunctions.create_factorial_fraction_answer( + num_denom_pairs + ) + + varied_answers = books_shelves_helperfunctions.varied_answers( + num_denom_pairs + ) # or something a little different + + # we will not randomize the order of these choices because that is handled in ruby? + # random.shuffle(answerchoices) + + return { + "title": "books in shelves", + "body": question_body, + "bodyFormat": "text", + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": answer, + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": varied_answers[0], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[1], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[2], + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + +def call(): + return generate_question() diff --git a/dynamic/generators/books_shelves/books_shelves_2/__init__.py b/dynamic/generators/books_shelves/books_shelves_2/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/books_shelves/books_shelves_2/main.py b/dynamic/generators/books_shelves/books_shelves_2/main.py new file mode 100644 index 00000000..9ca9a9d6 --- /dev/null +++ b/dynamic/generators/books_shelves/books_shelves_2/main.py @@ -0,0 +1,69 @@ +"""How many ways are there to organize " + str(a) + " number of books using " ++ str(b) + " number of bookshelves? ALL shelves must be used. (The order of books matter.)""" + +import random +from .. import books_shelves_helperfunctions + +# generates three different kinds of books and shelves problem +# the kind of problems are determined by the randomized three types of restrictions +def generate_question(): + a = random.randint(5, 10) + b = random.randint(5, 10) + a += b # update number of books so that it is more than the available shelves; for this restriction this is necessary. + + question_body = ( + "How many ways are there to organize " + + str(a) + + " number of books using " + + str(b) + + " number of bookshelves? ALL shelves must be used. (The order of books matter.)" + ) + + num_denom_pairs = [ + [a, a - b], + [a - 1, b - 1], + ] # answer = "$\\frac{"+str(a)+"! \\cdot "+str(a-1)+"!}{"+str(a-b)+"! \\cdot "+str(b-1)+"!}$" + + answer = books_shelves_helperfunctions.create_factorial_fraction_answer( + num_denom_pairs + ) + + varied_answers = books_shelves_helperfunctions.varied_answers( + num_denom_pairs + ) # or something a little different + + # we will not randomize the order of these choices because that is handled in ruby side. + # random.shuffle(answerchoices) + + return { + "title": "books in shelves", + "body": question_body, + "bodyFormat": "text", + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": answer, + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": varied_answers[0], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[1], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[2], + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + +def call(): + return generate_question() diff --git a/dynamic/generators/books_shelves/books_shelves_3/__init__.py b/dynamic/generators/books_shelves/books_shelves_3/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/books_shelves/books_shelves_3/main.py b/dynamic/generators/books_shelves/books_shelves_3/main.py new file mode 100644 index 00000000..77737f91 --- /dev/null +++ b/dynamic/generators/books_shelves/books_shelves_3/main.py @@ -0,0 +1,75 @@ +"""How many ways are there to organize " + str(a) + " number of books when given " + str(b) + +" number of bookshelves? " +str(c)+ " out of the " +str(a)+ " number of books are IDENTICAL. (The order of books matter.)""" + +import random +from .. import books_shelves_helperfunctions + +# generates three different kinds of books and shelves problem +# the kind of problems are determined by the randomized three types of restrictions + + +def generate_question(): + a = random.randint(7, 12) + b = random.randint(5, 10) + c = a - random.randint(2, 5) # number of books that are identical + + question_body = ( + "How many ways are there to organize " + + str(a) + + " number of books when given " + + str(b) + + " number of bookshelves? " + + str(c) + + " out of the " + + str(a) + + " number of books are IDENTICAL. (The order of books matter.)" + ) + + num_denom_pairs = [ + [a + b - 1, b - 1], + [1, c], + ] # answer = "$\\frac{"+str(a+b-1)+"!}{" +str(c)+ "! \\cdot "+str((b-1))+"!}$" + + answer = books_shelves_helperfunctions.create_factorial_fraction_answer( + num_denom_pairs + ) + + varied_answers = books_shelves_helperfunctions.varied_answers( + num_denom_pairs + ) # or something a little different + + # we will not randomize the order of these choices because that is handled in ruby side. + # random.shuffle(answerchoices) + + return { + "title": "books in shelves", + "body": question_body, + "bodyFormat": "text", + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": answer, + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": varied_answers[0], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[1], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": varied_answers[2], + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + +def call(): + return generate_question() diff --git a/dynamic/generators/books_shelves/books_shelves_helperfunctions.py b/dynamic/generators/books_shelves/books_shelves_helperfunctions.py new file mode 100644 index 00000000..a62cd01f --- /dev/null +++ b/dynamic/generators/books_shelves/books_shelves_helperfunctions.py @@ -0,0 +1,69 @@ +""" this file contains helper functions for the books_shelves generators """ + +import copy, random + +# takes in list of pairs of numerator string and denominator string and outputs a product of fractions accordingly +# input argument list will have two element lists that contains the numerator and the denominator string to create product of fractions +def create_factorial_fraction_answer( + num_denom_pairs, +): # args[] has length 2 lists as elements that contain a numerator and denominator + out = "$" + for i in range(len(num_denom_pairs)): + n = num_denom_pairs[i][0] + d = num_denom_pairs[i][1] + if i == 0: + if n == 1 and d == 1: + out += "" + elif n == 1: # if only n was 1 and d was not 1 + out += "\\frac{" + str(n) + "}" + out += "{" + str(d) + "!}" + elif d == 1: # if only d was 1 and n was not 1 + out += str(n) + "!" + else: # if n and d are both not 1 + out += "\\frac{" + str(n) + "!}" + out += "{" + str(d) + "!}" + + else: + if n == 1 and d == 1: + out += "" + elif n == 1: # if only n was 1 and d was not 1 + out += " \\cdot \\frac{" + str(n) + "}" + out += "{" + str(d) + "!}" + elif d == 1: # if only d was 1 and n was not 1 + out += " \\cdot " + str(n) + "!" + else: # if n and d are both not 1 + out += " \\cdot \\frac{" + str(n) + "!}" + out += "{" + str(d) + "!}" + + out += "$" + return out + + +# varies the answer in meaningful incremental ways and return 3 varied choices of answers +# takes in the answer in the form of a list of pairs of numerator string and denominator string and creates 3 variations of the answer +# returns a list of length 3 that has 3 varied answers +def varied_answers(num_denom_pairs): + out = [] + keeptrack = ( + [] + ) # keep track of what was varied and make sure that the three varied choices are all unique + while len(out) < 3: ### need to make sure this does not become infinite loop,,, + varied_num_denom_pairs = copy.deepcopy(num_denom_pairs) + v = random.randint( + 1, 2 + ) # how much to vary (for now only going to vary a little bit) + s = random.randint( + 1, 2 + ) # "sign": whether to vary negatively or positively (1 is plus, 2 is minus) + l_1 = random.randint(0, len(num_denom_pairs) - 1) # location of where to vary + l_2 = random.randint(0, 1) + if s == 1: + varied_num_denom_pairs[l_1][l_2] += v + else: + if num_denom_pairs[l_1][l_2] - v > 0: + varied_num_denom_pairs[l_1][l_2] -= v + else: # this is to avoid any "0!" in our output elements # this won't repeat itself + varied_num_denom_pairs[0][0] += 1 + if create_factorial_fraction_answer(varied_num_denom_pairs) not in out: + out.append(create_factorial_fraction_answer(varied_num_denom_pairs)) + return out diff --git a/dynamic/generators/books_shelves/test_main.py b/dynamic/generators/books_shelves/test_main.py new file mode 100644 index 00000000..fac62611 --- /dev/null +++ b/dynamic/generators/books_shelves/test_main.py @@ -0,0 +1,14 @@ +from .test_out import test_output +import sys + +from .books_shelves_0 import main as main_0 +from .books_shelves_1 import main as main_1 +from .books_shelves_2 import main as main_2 +from .books_shelves_3 import main as main_3 + + +def test(): + assert test_output(main_0.call()) + assert test_output(main_1.call()) + assert test_output(main_2.call()) + assert test_output(main_3.call()) diff --git a/dynamic/generators/books_shelves/test_out.py b/dynamic/generators/books_shelves/test_out.py new file mode 100644 index 00000000..aba0121c --- /dev/null +++ b/dynamic/generators/books_shelves/test_out.py @@ -0,0 +1,110 @@ +""" This file contains tools for test_main.py to use. """ + + +def check_mathjax_compatible(output_string): + # for now, checks that the answers start and end with the "$" to be conventionally compatible with mathjax + # could change the conditions to accommodate more types of mathjax compatible examples ... + return output_string[0] == "$" and output_string[len(output_string) - 1] == "$" + + +# returns True if the output dictionary is a valid output for the "ruby side" interpretation +def test_output(cache): + + bodyFormat_options = ["text", "mathjax"] # can add more options in the future + + if type(cache) != type({}): + return False + else: + + answer_type = { + "title": "", + "body": "", + "bodyFormat": "text", # or "mathjax" + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": "", + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + keys_list = list( + answer_type.keys() + ) # the list of keys from the template answer_type dictionary + out_list = list( + cache.keys() + ) # the list of keys from the output dictionary that we are testing + + # checks if the output dictionary that is being tested has the correct type of keys as in the answer_type + for i in range(len(out_list)): + if not out_list[i] in keys_list: + return False + + # if there is "title" key in the ouput dictionary, check that the item of "title" is string type + if "title" in out_list: + if not type(cache["title"]) == type(""): + return False + + # check that the item of the key, "body", is string type + if not type(cache["body"]) == type(""): + return False + + # checks "bodyFormat" key has the correct item types available as in the bodyFormat_options + if not (cache["bodyFormat"] in bodyFormat_options): + return False + + # if there is "pseudocode" key in the output dictionary, check that the item of "pseudocode" is a string type + if "pseudocode" in out_list: + if not type(cache["pseudocode"]) == type(""): + return False + + # tests the item of "multipleChoiceAnswers" key + mult_choice_answers = cache[keys_list[4]] + if len(mult_choice_answers) != 4: + return False + else: + + for i in range(0, 4): + + if type(mult_choice_answers[i]) != type({}): + return False + elif len(mult_choice_answers[i]) != 3: + return False + + for j in range(len(list(mult_choice_answers[i].keys()))): + if not ( + list(mult_choice_answers[i].keys())[j] + in ["body", "bodyFormat", "correct"] + ): + return False + + if not check_mathjax_compatible(mult_choice_answers[i]["body"]): + return False + + if not (mult_choice_answers[i]["bodyFormat"] in bodyFormat_options): + return False + + if not ( + mult_choice_answers[i]["correct"] == "true" + or mult_choice_answers[i]["correct"] == "false" + ): + return False + + return True diff --git a/dynamic/generators/readme.md b/dynamic/generators/readme.md index 1df8f0b8..1561d370 100644 --- a/dynamic/generators/readme.md +++ b/dynamic/generators/readme.md @@ -1,3 +1,46 @@ # Generators Generate questions with these functions. + +## Contributing + +Contributing to the generator is really simple. The only files you need to really worry about are `router.py` and `generators`. If you want to make a new generator, add an endpoint (check `routers.py` for reference), and then have that endpoint call your generator in the `generators` folder. + +## Please note: If your generator is hard-coding or explicitly copying course materials or copyrighted content from external sources, (i.e. not creating an original generator) you must receive permission from the course instructors or the original author. +## (That said, since it is a generator, please avoid hard-coding pre-existing materials. You can be inspired by a problem type, but a generator should create original questions.) + +## To add a generator, make sure that your generator directory's main.py file has the function generate_question() that returns in the following dictionary format: + +(If your not using Latex within your question or body, replay "mathjax" with "text.") + + +```python + { + "title": # description, + "body": # the question in "text" or "mathjax" format, + "bodyFormat": # "text" or "mathjax", + "pseudocode": # pseudocode in "mathjax" format if the questions requires one, + "multipleChoiceAnswers": [ + { + "body": "$\\frac{0}{1}$", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "$\\frac{2}{3}$", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "$\\frac{4}{5}$", + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": "$\\frac{6}{7}$", + "bodyFormat": "mathjax", + "correct": "false", + } + ] + } +``` diff --git a/dynamic/readme.md b/dynamic/readme.md index 304df712..9f510264 100644 --- a/dynamic/readme.md +++ b/dynamic/readme.md @@ -26,3 +26,42 @@ Fire up your server and head to `http://localhost:8000/docs`. ## Contributing Contributing to the generator is really simple. The only files you need to really worry about are `router.py` and `generators`. If you want to make a new generator, add an endpoint (check `routers.py` for reference), and then have that endpoint call your generator in the `generators` folder. + +## Please note: If your generator is hard-coding or explicitly copying course materials or copyrighted content from external sources, (i.e. not creating an original generator) you must receive permission from the course instructors or the original author. +## (That said, since it is a generator, please avoid hard-coding pre-existing materials. You can be inspired by a problem type, but a generator should create original questions.) + +## To add a generator, make sure that your generator directory's main.py file has the function generate_question() that returns in the following dictionary format: + +(If your not using Latex within your question or body, replay "mathjax" with "text.") + + +```python + { + "title": # description, + "body": # the question in "text" or "mathjax" format, + "bodyFormat": # "text" or "mathjax", + "pseudocode": # pseudocode in "mathjax" format if the questions requires one, + "multipleChoiceAnswers": [ + { + "body": "$\\frac{0}{1}$", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "$\\frac{2}{3}$", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "$\\frac{4}{5}$", + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": "$\\frac{6}{7}$", + "bodyFormat": "mathjax", + "correct": "false", + } + ] + } +``` diff --git a/dynamic/router.py b/dynamic/router.py index a9cc4871..325b36ea 100644 --- a/dynamic/router.py +++ b/dynamic/router.py @@ -1,5 +1,11 @@ from fastapi import APIRouter import generators.demo.graph_theory.main as graph_theory_question_generator + +import generators.books_shelves.books_shelves_0.main as books_shelves_0_generator +import generators.books_shelves.books_shelves_1.main as books_shelves_1_generator +import generators.books_shelves.books_shelves_2.main as books_shelves_2_generator +import generators.books_shelves.books_shelves_3.main as books_shelves_3_generator + import generators.comp2804.set_theory_question.main as set_theory_question_generator import generators.comp2804.num_of_functions.main as num_of_functions_generator import generators.comp2804.bitstrings_of_length.main as bitstrings_of_length_generator @@ -8,17 +14,19 @@ prefix="/api", tags=["generate"], responses={404: {"description": "Not found"}} ) - routes = { - 'demo': { - 'graph_theory': "/demo/graph-theory" + "demo": {"graph_theory": "/demo/graph-theory"}, + "books_shelves": { + "books_shelves_0": "/books_shelves/books_shelves_0", + "books_shelves_1": "/books_shelves/books_shelves_1", + "books_shelves_2": "/books_shelves/books_shelves_2", + "books_shelves_3": "/books_shelves/books_shelves_3", + }, + "comp2804": { + "bitstrings-of-length": "/comp2804/bitstrings-of-length", + "set-theory-question": "/comp2804/set-theory", + "num-of-functions": "/comp2804/num-of-functions", }, - 'comp2804': { - 'bitstrings-of-length': "/comp2804/bitstrings-of-length", - 'set-theory-question': "/comp2804/set-theory", - 'num-of-functions': "/comp2804/num-of-functions" - } - } @@ -27,23 +35,47 @@ async def get_generators(): return routes -@router.get(routes['demo']['graph_theory']) +@router.get(routes["demo"]["graph_theory"]) async def generate_graph_theory_question(): return graph_theory_question_generator.call() -@router.get(routes['comp2804']['set-theory-question']) +############___Books_Shelves_Questions___############ +@router.get(routes["books_shelves"]["books_shelves_0"]) +async def generate_books_shelves_0_question(): + return books_shelves_0_generator.call() + + +@router.get(routes["books_shelves"]["books_shelves_1"]) +async def generate_books_shelves_1_question(): + return books_shelves_1_generator.call() + + +@router.get(routes["books_shelves"]["books_shelves_2"]) +async def generate_books_shelves_2_question(): + return books_shelves_2_generator.call() + + +@router.get(routes["books_shelves"]["books_shelves_3"]) +async def generate_books_shelves_3_question(): + return books_shelves_3_generator.call() + + +###################################################### + + +@router.get(routes["comp2804"]["set-theory-question"]) async def generate_set_theory_question(): return set_theory_question_generator.call() -@router.get(routes['comp2804']['num-of-functions']) +@router.get(routes["comp2804"]["num-of-functions"]) async def generate_num_of_functions_question( lower_range: int = 0, upper_range: int = 10 ): return num_of_functions_generator.call(lower_range, upper_range) -@router.get(routes['comp2804']['bitstrings-of-length']) +@router.get(routes["comp2804"]["bitstrings-of-length"]) async def bitstrings_of_length_question(): return bitstrings_of_length_generator.call() diff --git a/test_output backup b/test_output backup new file mode 100644 index 00000000..6ab96db7 --- /dev/null +++ b/test_output backup @@ -0,0 +1,99 @@ +""" This file contains tools for test_main.py to use. """ + +def check_mathjax_compatible(output_string): + # for now, checks that the answers start and end with the "$" to be conventionally compatible with mathjax + # could change the conditions to accommodate more types of mathjax compatible examples ... + return output_string[0] == "$" and output_string[len(output_string)-1] == "$" + +# returns True if the output dictionary is a valid output for the "ruby side" interpretation +def test_output(out): + + bodyFormat_options = ["text", "mathjax"] # can add more options in the future + + if type(out) != type({}): + return False + else: + + answer_type = { + "title": "", + "body": "", + "bodyFormat": "text", # or "mathjax" + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": "", + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": "", + "bodyFormat": "mathjax", + "correct": "false", + } + ] + } + + + keys_list = list(answer_type.keys()) # the list of keys from the template answer_type dictionary + out_list = list(out.keys()) # the list of keys from the output dictionary that we are testing + + # checks if the output dictionary that is being tested has the correct type of keys as in the answer_type + for i in range(len(out_list)): + if not out_list[i] in keys_list: + return False + + # if there is "title" key in the ouput dictionary, check that the item of "title" is string type + if "title" in out_list: + if not type(out["title"])==type(""): + return False + + # check that the item of the key, "body", is string type + if not type(out["body"])==type(""): + return False + + # checks "bodyFormat" key has the correct item types available as in the bodyFormat_options + if not (out["bodyFormat"] in bodyFormat_options): + return False + + # if there is "pseudocode" key in the output dictionary, check that the item of "pseudocode" is a string type + if "pseudocode" in out_list: + if not type(out["pseudocode"])==type(""): + return False + + # tests the item of "multipleChoiceAnswers" key + mult_choice_answers = out[keys_list[4]] + if len(mult_choice_answers) != 4: + return False + else: + + for i in range(0,4): + + if type(mult_choice_answers[i]) != type({}): + return False + elif len(mult_choice_answers[i]) != 3: + return False + + for j in range(len(list(mult_choice_answers[i].keys()))): + if not (list(mult_choice_answers[i].keys())[j] in ["body", "bodyFormat", "correct"]): + return False + + if not check_mathjax_compatible(mult_choice_answers[i]["body"]): + return False + + if not (mult_choice_answers[i]["bodyFormat"] in bodyFormat_options): + return False + + if not (mult_choice_answers[i]["correct"]=="true" or mult_choice_answers[i]["correct"]=="false"): + return False + + return True From 6a06a83905c73af2da50212b516e5d2e535f61f1 Mon Sep 17 00:00:00 2001 From: MathyouMB Date: Thu, 2 Dec 2021 17:54:36 -0500 Subject: [PATCH 4/5] add docker-compose --- api/docker-compose.yml | 49 ++++++++++++++++++++++++++++++++++++++++++ api/entrypoint.sh | 0 2 files changed, 49 insertions(+) create mode 100644 api/docker-compose.yml mode change 100644 => 100755 api/entrypoint.sh diff --git a/api/docker-compose.yml b/api/docker-compose.yml new file mode 100644 index 00000000..ca6cf907 --- /dev/null +++ b/api/docker-compose.yml @@ -0,0 +1,49 @@ +version: '3' + +services: + api: + build: . + command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails db:setup && bundle exec rails s -p 3000 -b '0.0.0.0'" + volumes: + - .:/usr/src/app + ports: + - "3000:3000" + depends_on: + - db + links: + - db + networks: + - discretemath + + db: + image: postgres:12-alpine + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: 1234 + ports: + - "5438:5432" + networks: + - discretemath + + pgadmin: + container_name: pgadmin4_container + image: dpage/pgadmin4 + restart: always + environment: + PGADMIN_DEFAULT_EMAIL: admin@admin.com + PGADMIN_DEFAULT_PASSWORD: root + ports: + - "5050:80" + depends_on: + - db + links: + - db + networks: + - discretemath + +volumes: + database_postgres: + +networks: + discretemath: + driver: bridge diff --git a/api/entrypoint.sh b/api/entrypoint.sh old mode 100644 new mode 100755 From fa0ad9d4f446bb3b7da979cd24b740daeaaeaab2 Mon Sep 17 00:00:00 2001 From: saileshp56 <86889128+saileshp56@users.noreply.github.com> Date: Fri, 28 Jan 2022 12:44:03 -0500 Subject: [PATCH 5/5] Binomial expansion coefficient question (#133) * added binomial expansion question ws/#/tests/13 #4 --- .../__init__.py | 0 .../binomial_expansion_coefficient/main.py | 69 ++++++++++++++++++ .../comp2804/let_m_and_n/__init__.py | 0 .../generators/comp2804/let_m_and_n/main.py | 71 +++++++++++++++++++ dynamic/router.py | 16 ++++- 5 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 dynamic/generators/comp2804/binomial_expansion_coefficient/__init__.py create mode 100644 dynamic/generators/comp2804/binomial_expansion_coefficient/main.py create mode 100644 dynamic/generators/comp2804/let_m_and_n/__init__.py create mode 100644 dynamic/generators/comp2804/let_m_and_n/main.py diff --git a/dynamic/generators/comp2804/binomial_expansion_coefficient/__init__.py b/dynamic/generators/comp2804/binomial_expansion_coefficient/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/comp2804/binomial_expansion_coefficient/main.py b/dynamic/generators/comp2804/binomial_expansion_coefficient/main.py new file mode 100644 index 00000000..8c0c10a0 --- /dev/null +++ b/dynamic/generators/comp2804/binomial_expansion_coefficient/main.py @@ -0,0 +1,69 @@ +import random + + +def generate_question(): + + a_coefficient = random.randint(2, 5) + b_coefficient = random.randint(3, 7) + + x_exponent = random.randint(3, 8) + y_exponent = random.randint(5, 11) + + n = random.randint(11, 15) + + answer = f"-\genfrac(){{n}}{{y_exponent}}\cdot{a_coefficient}^{x_exponent}\cdot{b_coefficient}^{y_exponent}" + + question_body = f"What is the coefficient of x^{x_exponent}y^{y_exponent} in the expansion of ({a_coefficient} - {b_coefficient}y)^{n}" + + return { + "title": "bitstrings of length", + "body": question_body, + "body_format": "text", + "pseudocode": "", + "multiple_choice_answers": [ + { + "body": answerchoice_1( + n, a_coefficient, b_coefficient, x_exponent, y_exponent + ), + "body_format": "mathjax", + "correct": "false", + }, + { + "body": answer, + "body_format": "mathjax", + "correct": "true", + }, + { + "body": answerchoice_3( + n, a_coefficient, b_coefficient, x_exponent, y_exponent + ), + "body_format": "mathjax", + "correct": "false", + }, + { + "body": answerchoice_4( + n, a_coefficient, b_coefficient, x_exponent, y_exponent + ), + "body_format": "mathjax", + "correct": "false", + }, + ], + } + + +def answerchoice_1(n, a_coefficient, b_coefficient, x_exponent, y_exponent): + return f"\genfrac(){{n}}{{y_exponent}}\cdot{a_coefficient}^{x_exponent}\cdot{b_coefficient}^{y_exponent}" + + # answerchoice_2 purposefully omitted + + +def answerchoice_3(n, a_coefficient, b_coefficient, x_exponent, y_exponent): + return f"\genfrac(){{n}}{{y_exponent}}\cdot{a_coefficient}^{y_exponent}\cdot{b_coefficient}^{x_exponent}" + + +def answerchoice_4(n, a_coefficient, b_coefficient, x_exponent, y_exponent): + return f"-\genfrac(){{n}}{{y_exponent}}\cdot{a_coefficient}^{y_exponent}\cdot{b_coefficient}^{x_exponent}" + + +def call(): + return generate_question() diff --git a/dynamic/generators/comp2804/let_m_and_n/__init__.py b/dynamic/generators/comp2804/let_m_and_n/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/dynamic/generators/comp2804/let_m_and_n/main.py b/dynamic/generators/comp2804/let_m_and_n/main.py new file mode 100644 index 00000000..5b1e5d94 --- /dev/null +++ b/dynamic/generators/comp2804/let_m_and_n/main.py @@ -0,0 +1,71 @@ +import random + + +def generate_question(): + # generate required data + k = random.randint(2, 4) # value of k, m and n + + # generate required content + + question_body = ( + "Let $m \geq " + + str(k) + + "$ and $n \geq " + + str(k) + + "$ be integers. What does $${{m}\choose{" + + str(k) + + "}} + {{n}\choose{" + + str(k) + + "}} + m\cdot n$$ count?" + ) + + answer_options = [ + "The number of ways to choose a subset from a set consisting of $m + n$ elements.", + "The number of ways to choose an ordered pair of {} elements from a set consisting of $m + n$ elements.".format( + k + ), + "The number of ways to choose a {}-element subset from a set consisting of $m + n$ elements.".format( + k + ), + "None of the above.", + ] + for answer in answer_options: + if "-element" in answer: + correct_answer = answer + + # return generated question + return { + "title": "set_theory_question", + "body": question_body, + "bodyFormat": "text", + "pseudocode": "", + "multipleChoiceAnswers": [ + { + "body": answer_options[0], + "bodyFormat": "mathjax", + "correct": "true", + }, + { + "body": answer_options[1], + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": correct_answer, + "bodyFormat": "mathjax", + "correct": "false", + }, + { + "body": answer_options[3], + "bodyFormat": "mathjax", + "correct": "false", + }, + ], + } + + +def call(): + return generate_question() + + +print(call()) diff --git a/dynamic/router.py b/dynamic/router.py index 325b36ea..4a71495f 100644 --- a/dynamic/router.py +++ b/dynamic/router.py @@ -8,7 +8,10 @@ import generators.comp2804.set_theory_question.main as set_theory_question_generator import generators.comp2804.num_of_functions.main as num_of_functions_generator +import generators.comp2804.let_m_and_n.main as m_and_n_generator import generators.comp2804.bitstrings_of_length.main as bitstrings_of_length_generator +import generators.comp2804.binomial_expansion_coefficient.main as binomial_expansion_coefficient_generator + router = APIRouter( prefix="/api", tags=["generate"], responses={404: {"description": "Not found"}} @@ -24,8 +27,10 @@ }, "comp2804": { "bitstrings-of-length": "/comp2804/bitstrings-of-length", + "binomial-expansion-coefficient": "/comp2804/binomial-expansion-coefficient", "set-theory-question": "/comp2804/set-theory", "num-of-functions": "/comp2804/num-of-functions", + "let-m-and-n-question": "/comp2804/let-m-and-n", }, } @@ -76,6 +81,15 @@ async def generate_num_of_functions_question( return num_of_functions_generator.call(lower_range, upper_range) +@router.get(routes["comp2804"]["let-m-and-n-question"]) +async def generate_m_and_n_question(): + return m_and_n_generator.call() + + +@router.get(routes["comp2804"]["binomial-expansion-coefficient"]) +async def generate_m_and_n_question(): + return binomial_expansion_coefficient_generator.call() + @router.get(routes["comp2804"]["bitstrings-of-length"]) -async def bitstrings_of_length_question(): +async def generate_bitstrings_of_length_question(): return bitstrings_of_length_generator.call()