Juni
1 year ago
commit
0f22cd789d
7 changed files with 693 additions and 0 deletions
-
160.dockerignore
-
161.gitignore
-
11Dockerfile
-
32app.py
-
19requirements.txt
-
240solver.py
-
70templates/page.html
@ -0,0 +1,160 @@ |
|||
# Byte-compiled / optimized / DLL files |
|||
__pycache__/ |
|||
*.py[cod] |
|||
*$py.class |
|||
|
|||
# C extensions |
|||
*.so |
|||
|
|||
# Distribution / packaging |
|||
.Python |
|||
build/ |
|||
develop-eggs/ |
|||
dist/ |
|||
downloads/ |
|||
eggs/ |
|||
.eggs/ |
|||
lib/ |
|||
lib64/ |
|||
parts/ |
|||
sdist/ |
|||
var/ |
|||
wheels/ |
|||
share/python-wheels/ |
|||
*.egg-info/ |
|||
.installed.cfg |
|||
*.egg |
|||
MANIFEST |
|||
|
|||
# PyInstaller |
|||
# Usually these files are written by a python script from a template |
|||
# before PyInstaller builds the exe, so as to inject date/other infos into it. |
|||
*.manifest |
|||
*.spec |
|||
|
|||
# Installer logs |
|||
pip-log.txt |
|||
pip-delete-this-directory.txt |
|||
|
|||
# Unit test / coverage reports |
|||
htmlcov/ |
|||
.tox/ |
|||
.nox/ |
|||
.coverage |
|||
.coverage.* |
|||
.cache |
|||
nosetests.xml |
|||
coverage.xml |
|||
*.cover |
|||
*.py,cover |
|||
.hypothesis/ |
|||
.pytest_cache/ |
|||
cover/ |
|||
|
|||
# Translations |
|||
*.mo |
|||
*.pot |
|||
|
|||
# Django stuff: |
|||
*.log |
|||
local_settings.py |
|||
db.sqlite3 |
|||
db.sqlite3-journal |
|||
|
|||
# Flask stuff: |
|||
instance/ |
|||
.webassets-cache |
|||
|
|||
# Scrapy stuff: |
|||
.scrapy |
|||
|
|||
# Sphinx documentation |
|||
docs/_build/ |
|||
|
|||
# PyBuilder |
|||
.pybuilder/ |
|||
target/ |
|||
|
|||
# Jupyter Notebook |
|||
.ipynb_checkpoints |
|||
|
|||
# IPython |
|||
profile_default/ |
|||
ipython_config.py |
|||
|
|||
# pyenv |
|||
# For a library or package, you might want to ignore these files since the code is |
|||
# intended to run in multiple environments; otherwise, check them in: |
|||
# .python-version |
|||
|
|||
# pipenv |
|||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. |
|||
# However, in case of collaboration, if having platform-specific dependencies or dependencies |
|||
# having no cross-platform support, pipenv may install dependencies that don't work, or not |
|||
# install all needed dependencies. |
|||
#Pipfile.lock |
|||
|
|||
# poetry |
|||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. |
|||
# This is especially recommended for binary packages to ensure reproducibility, and is more |
|||
# commonly ignored for libraries. |
|||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control |
|||
#poetry.lock |
|||
|
|||
# pdm |
|||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. |
|||
#pdm.lock |
|||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it |
|||
# in version control. |
|||
# https://pdm.fming.dev/#use-with-ide |
|||
.pdm.toml |
|||
|
|||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm |
|||
__pypackages__/ |
|||
|
|||
# Celery stuff |
|||
celerybeat-schedule |
|||
celerybeat.pid |
|||
|
|||
# SageMath parsed files |
|||
*.sage.py |
|||
|
|||
# Environments |
|||
.env |
|||
.venv |
|||
env/ |
|||
venv/ |
|||
ENV/ |
|||
env.bak/ |
|||
venv.bak/ |
|||
|
|||
# Spyder project settings |
|||
.spyderproject |
|||
.spyproject |
|||
|
|||
# Rope project settings |
|||
.ropeproject |
|||
|
|||
# mkdocs documentation |
|||
/site |
|||
|
|||
# mypy |
|||
.mypy_cache/ |
|||
.dmypy.json |
|||
dmypy.json |
|||
|
|||
# Pyre type checker |
|||
.pyre/ |
|||
|
|||
# pytype static type analyzer |
|||
.pytype/ |
|||
|
|||
# Cython debug symbols |
|||
cython_debug/ |
|||
|
|||
# PyCharm |
|||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can |
|||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore |
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear |
|||
# option (not recommended) you can uncomment the following to ignore the entire idea folder. |
|||
#.idea/ |
@ -0,0 +1,161 @@ |
|||
# Byte-compiled / optimized / DLL files |
|||
__pycache__/ |
|||
*.py[cod] |
|||
*$py.class |
|||
|
|||
.DS_Store |
|||
# C extensions |
|||
*.so |
|||
|
|||
# Distribution / packaging |
|||
.Python |
|||
build/ |
|||
develop-eggs/ |
|||
dist/ |
|||
downloads/ |
|||
eggs/ |
|||
.eggs/ |
|||
lib/ |
|||
lib64/ |
|||
parts/ |
|||
sdist/ |
|||
var/ |
|||
wheels/ |
|||
share/python-wheels/ |
|||
*.egg-info/ |
|||
.installed.cfg |
|||
*.egg |
|||
MANIFEST |
|||
|
|||
# PyInstaller |
|||
# Usually these files are written by a python script from a template |
|||
# before PyInstaller builds the exe, so as to inject date/other infos into it. |
|||
*.manifest |
|||
*.spec |
|||
|
|||
# Installer logs |
|||
pip-log.txt |
|||
pip-delete-this-directory.txt |
|||
|
|||
# Unit test / coverage reports |
|||
htmlcov/ |
|||
.tox/ |
|||
.nox/ |
|||
.coverage |
|||
.coverage.* |
|||
.cache |
|||
nosetests.xml |
|||
coverage.xml |
|||
*.cover |
|||
*.py,cover |
|||
.hypothesis/ |
|||
.pytest_cache/ |
|||
cover/ |
|||
|
|||
# Translations |
|||
*.mo |
|||
*.pot |
|||
|
|||
# Django stuff: |
|||
*.log |
|||
local_settings.py |
|||
db.sqlite3 |
|||
db.sqlite3-journal |
|||
|
|||
# Flask stuff: |
|||
instance/ |
|||
.webassets-cache |
|||
|
|||
# Scrapy stuff: |
|||
.scrapy |
|||
|
|||
# Sphinx documentation |
|||
docs/_build/ |
|||
|
|||
# PyBuilder |
|||
.pybuilder/ |
|||
target/ |
|||
|
|||
# Jupyter Notebook |
|||
.ipynb_checkpoints |
|||
|
|||
# IPython |
|||
profile_default/ |
|||
ipython_config.py |
|||
|
|||
# pyenv |
|||
# For a library or package, you might want to ignore these files since the code is |
|||
# intended to run in multiple environments; otherwise, check them in: |
|||
# .python-version |
|||
|
|||
# pipenv |
|||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. |
|||
# However, in case of collaboration, if having platform-specific dependencies or dependencies |
|||
# having no cross-platform support, pipenv may install dependencies that don't work, or not |
|||
# install all needed dependencies. |
|||
#Pipfile.lock |
|||
|
|||
# poetry |
|||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. |
|||
# This is especially recommended for binary packages to ensure reproducibility, and is more |
|||
# commonly ignored for libraries. |
|||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control |
|||
#poetry.lock |
|||
|
|||
# pdm |
|||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. |
|||
#pdm.lock |
|||
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it |
|||
# in version control. |
|||
# https://pdm.fming.dev/#use-with-ide |
|||
.pdm.toml |
|||
|
|||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm |
|||
__pypackages__/ |
|||
|
|||
# Celery stuff |
|||
celerybeat-schedule |
|||
celerybeat.pid |
|||
|
|||
# SageMath parsed files |
|||
*.sage.py |
|||
|
|||
# Environments |
|||
.env |
|||
.venv |
|||
env/ |
|||
venv/ |
|||
ENV/ |
|||
env.bak/ |
|||
venv.bak/ |
|||
|
|||
# Spyder project settings |
|||
.spyderproject |
|||
.spyproject |
|||
|
|||
# Rope project settings |
|||
.ropeproject |
|||
|
|||
# mkdocs documentation |
|||
/site |
|||
|
|||
# mypy |
|||
.mypy_cache/ |
|||
.dmypy.json |
|||
dmypy.json |
|||
|
|||
# Pyre type checker |
|||
.pyre/ |
|||
|
|||
# pytype static type analyzer |
|||
.pytype/ |
|||
|
|||
# Cython debug symbols |
|||
cython_debug/ |
|||
|
|||
# PyCharm |
|||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can |
|||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore |
|||
# and can be added to the global gitignore or merged into this file. For a more nuclear |
|||
# option (not recommended) you can uncomment the following to ignore the entire idea folder. |
|||
#.idea/ |
@ -0,0 +1,11 @@ |
|||
FROM python:latest |
|||
|
|||
WORKDIR /app |
|||
COPY ./requirements.txt /app/ |
|||
EXPOSE 8000 |
|||
|
|||
RUN pip install -r requirements.txt |
|||
|
|||
COPY . /app |
|||
|
|||
CMD ["gunicorn", "app:app", "-w", "3", "-b", "0.0.0.0:8000"] |
@ -0,0 +1,32 @@ |
|||
from flask import Flask, render_template, request |
|||
import solver |
|||
|
|||
app = Flask(__name__) |
|||
|
|||
|
|||
@app.route("/", methods=["GET", "POST"]) |
|||
def index(): |
|||
if request.method == "GET": |
|||
return render_template("page.html") |
|||
else: |
|||
try: |
|||
M = int(request.form["M"]) |
|||
N = int(request.form["N"]) |
|||
except ValueError: |
|||
return render_template("page.html", invalid=True) |
|||
if not (1 <= M <= 40 and 1 <= N <= 40): |
|||
return render_template("page.html", invalid=True) |
|||
|
|||
g = solver.construct(M, N) |
|||
if g is None: |
|||
return render_template("page.html", nosol=True, M=M, N=N) |
|||
else: |
|||
image, works = g.plot() |
|||
return render_template("page.html", image=image, works=works, M=M, N=N) |
|||
|
|||
|
|||
if __name__ == "__main__": |
|||
app.run( |
|||
host="0.0.0.0", |
|||
port=8000 |
|||
) |
@ -0,0 +1,19 @@ |
|||
blinker==1.7.0 |
|||
click==8.1.7 |
|||
contourpy==1.2.0 |
|||
cycler==0.12.1 |
|||
Flask==3.0.0 |
|||
fonttools==4.45.1 |
|||
gunicorn==21.2.0 |
|||
itsdangerous==2.1.2 |
|||
Jinja2==3.1.2 |
|||
kiwisolver==1.4.5 |
|||
MarkupSafe==2.1.3 |
|||
matplotlib==3.8.2 |
|||
numpy==1.26.2 |
|||
packaging==23.2 |
|||
Pillow==10.1.0 |
|||
pyparsing==3.1.1 |
|||
python-dateutil==2.8.2 |
|||
six==1.16.0 |
|||
Werkzeug==3.0.1 |
@ -0,0 +1,240 @@ |
|||
#!/usr/bin/env python3 |
|||
|
|||
import io |
|||
import base64 |
|||
|
|||
from matplotlib import pyplot as plt |
|||
import numpy |
|||
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas |
|||
from matplotlib.figure import Figure |
|||
|
|||
|
|||
class Grid: |
|||
def __init__(self, M, N): |
|||
self.N = N |
|||
self.M = M |
|||
self.grid = [[0 for _ in range(M+N-1)] for _ in range(M+N-1)] |
|||
|
|||
def check_bounds(self, x, y): |
|||
return 1 <= x <= self.M+self.N-1 and\ |
|||
1 <= y <= self.M+self.N-1 and\ |
|||
self.M+1 <= x+y <= 2*self.M + self.N - 1 |
|||
|
|||
def get(self, x, y): |
|||
if not self.check_bounds(x, y): |
|||
return 0 |
|||
return self.grid[x-1][y-1] |
|||
|
|||
def select(self, x, y): |
|||
assert self.check_bounds(x, y) |
|||
self.grid[x-1][y-1] = 1 |
|||
|
|||
def grid_parity(self): |
|||
for x in range(1, self.M+self.N): |
|||
nums = [self.get(x, y) for y in range(1, self.N + self.M)] |
|||
if sum(nums) % 2 != 1: |
|||
print(f"Found a contradiction at x={x}! {nums}") |
|||
return False |
|||
for y in range(1, self.M+self.N): |
|||
nums = [self.get(x, y) for x in range(1, self.N + self.M)] |
|||
if sum(nums) % 2 != 1: |
|||
print(f"Found a contradiction at y={y}! {nums}") |
|||
return False |
|||
for s in range(self.M+1, 2*self.M+self.N): |
|||
nums = [self.get(x, s-x) for x in range(1, s)] |
|||
if sum(nums) % 2 != 1: |
|||
print(f"Found a contradiction at x+y={s}! {nums}") |
|||
return False |
|||
return True |
|||
|
|||
def reflect(self): |
|||
res = [[0 for _ in range(len(self.grid[i]))] |
|||
for i in range(len(self.grid))] |
|||
for x in range(self.M+self.N-1): |
|||
# reflect across x + y = m + n - 2 |
|||
for y in range(self.M+self.N-1): |
|||
# sm = 2 * (self.M+self.N-2) - (x+y) |
|||
# diff = x - y |
|||
res[self.M+self.N-2-x][self.M+self.N-2-y] = self.grid[x][y] |
|||
self.grid = res |
|||
tmp = self.M |
|||
self.M = self.N |
|||
self.N = tmp |
|||
|
|||
def plot(self) -> tuple[str, bool]: |
|||
fig = Figure() |
|||
ax = fig.add_subplot(1, 1, 1) |
|||
ax.set_xticks(numpy.arange(1, self.M+self.N, 1)) |
|||
ax.set_yticks(numpy.arange(1, self.M+self.N, 1)) |
|||
ax.set_aspect("equal") |
|||
|
|||
ax.set_xbound(0, self.M+self.N) |
|||
ax.set_ybound(0, self.M+self.N) |
|||
ax.autoscale(enable=False) |
|||
x = [] |
|||
y = [] |
|||
for i in range(1, self.M+self.N): |
|||
for j in range(1, self.M+self.N): |
|||
if self.get(i, j): |
|||
x.append(i) |
|||
y.append(j) |
|||
ax.scatter(x, y, color='b') |
|||
# plt.title(f"Construction for M={self.M}, N={self.N}") |
|||
ax.grid() |
|||
|
|||
ax.plot([1, self.M], [self.M, 1], color='r') |
|||
ax.plot([self.M, self.N+self.M-1], |
|||
[self.N+self.M-1, self.M], color='r') |
|||
ax.plot([1, 1, self.M], [self.M, self.M + |
|||
self.N-1, self.M+self.N-1], color='r') |
|||
ax.plot([self.M, self.M+self.N-1, self.M+self.N-1], |
|||
[1, 1, self.M], color='r') |
|||
pngImage = io.BytesIO() |
|||
FigureCanvas(fig).print_png(pngImage) |
|||
pngImageB64String = "data:image/png;base64," |
|||
pngImageB64String += base64.b64encode( |
|||
pngImage.getvalue()).decode('utf8') |
|||
return pngImageB64String, self.grid_parity() |
|||
|
|||
|
|||
def one(M, N) -> Grid: |
|||
assert (N-M) % 4 == 0 |
|||
assert M == 1 or N == 1 |
|||
reflect = M == 1 |
|||
if reflect: |
|||
tmp = M |
|||
M = N |
|||
N = tmp |
|||
g = Grid(M, N) |
|||
for k in range(1, M+1): |
|||
g.select(k, M+1-k) |
|||
|
|||
for k in range(1, M//2+1): |
|||
g.select((M+1)//2, (M+1)//2+k) |
|||
g.select(M, (M+1)//2+k) |
|||
|
|||
if reflect: |
|||
g.reflect() |
|||
return g |
|||
|
|||
|
|||
def cong_mod4(M, N) -> Grid: |
|||
assert (N-M) % 4 == 0 and N != 1 and M != 1 |
|||
reflect = M > N |
|||
if reflect: |
|||
tmp = M |
|||
M = N |
|||
N = tmp |
|||
g = Grid(M, N) |
|||
|
|||
if M % 2 == 1: |
|||
g.select(M, M) |
|||
|
|||
# Main Axis points |
|||
for k in range(1, N//2+1): |
|||
g.select(M, M+2*k-1) |
|||
for k in range(1, (M-1)//2+1): |
|||
g.select(M, M-2*k) |
|||
|
|||
for k in range(1, (N-1)//2+1): |
|||
g.select(M+2*k, M) |
|||
for k in range(1, M//2+1): |
|||
g.select(M-2*k+1, M) |
|||
|
|||
# Points on the diagonal |
|||
for k in range(1, M//2 + 1): |
|||
g.select(M+2*k-1, M-2*k+1) # going down |
|||
for k in range(1, (M-1)//2+1): |
|||
g.select(M-2*k, M+2*k) # going up |
|||
|
|||
for k in range(1, (N-M)//2+1): |
|||
g.select( |
|||
M+2*(M//2) - 1 + 2*k, |
|||
M-2*(M//2) + 2, |
|||
) |
|||
g.select( |
|||
M - 2*((M-1)//2) + 1, |
|||
M + 2*((M-1)//2) + 2*k, |
|||
) |
|||
if reflect: |
|||
g.reflect() |
|||
return g |
|||
|
|||
|
|||
def mod_0_1(M, N): |
|||
assert (M+N) % 4 == 1 and M % 4 in [0, 1] |
|||
reflect = (M % 4) == 1 |
|||
if reflect: |
|||
tmp = M |
|||
M = N |
|||
N = tmp |
|||
g = Grid(M, N) |
|||
|
|||
g.select(M, M) |
|||
# Main Axis Points |
|||
for k in range(1, N//2+1): |
|||
g.select(M, M+2*k-1) |
|||
for k in range(1, (M-1)//2+1): |
|||
g.select(M, M-2*k) |
|||
|
|||
for k in range(1, (N-1)//2+1): |
|||
g.select(M+2*k, M) |
|||
for k in range(1, M//2+1): |
|||
g.select(M-2*k+1, M) |
|||
# Step 3 |
|||
for k in range(0, M//2): |
|||
g.select(M-2*k, 1+2*k) |
|||
|
|||
# Tail |
|||
for k in range(1, (N-1)//2+1): |
|||
g.select(2, M+2*k) |
|||
g.select(M+2*k-1, 3) |
|||
|
|||
if reflect: |
|||
g.reflect() |
|||
return g |
|||
|
|||
|
|||
def mod_2_3(M, N): |
|||
assert (M+N) % 4 == 1 and M % 4 in [2, 3] |
|||
reflect = (M % 4) == 2 |
|||
if reflect: |
|||
tmp = M |
|||
M = N |
|||
N = tmp |
|||
g = Grid(M, N) |
|||
|
|||
for k in range(1, M+1): |
|||
g.select(k, M+1-k) |
|||
|
|||
for k in range((M+1)//2+1, M+1): |
|||
g.select((M+1)//2, k) |
|||
g.select(M+1, k) |
|||
g.select((M+1)//2, M+1) |
|||
|
|||
for k in range(1, (N-2)//2 + 1): |
|||
g.select(M+1, M+2*k) |
|||
g.select(M+2*k, M) |
|||
|
|||
g.select(1, M+1+2*k) |
|||
g.select(M+1+2*k, 1) |
|||
|
|||
if reflect: |
|||
g.reflect() |
|||
return g |
|||
|
|||
|
|||
def construct(M, N) -> 'Grid | None': |
|||
if (M-N) % 4 == 0: |
|||
if M != 1 and N != 1: |
|||
return cong_mod4(M, N) |
|||
else: |
|||
return one(M, N) |
|||
elif (M+N) % 4 == 1: |
|||
if (M % 4) in [0, 1]: |
|||
return mod_0_1(M, N) |
|||
else: |
|||
return mod_2_3(M, N) |
|||
else: |
|||
assert ((N+M-1)*(N-M)) % 4 == 2 |
|||
return None |
@ -0,0 +1,70 @@ |
|||
<!DOCTYPE html> |
|||
<html lang="en"> |
|||
<head> |
|||
<title>USAMTS 2/5/35 Solution</title> |
|||
<meta charset="UTF-8"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@1/css/pico.min.css"> |
|||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous"> |
|||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script> |
|||
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous" |
|||
onload="renderMathInElement(document.body);"></script> |
|||
</head> |
|||
<body> |
|||
<main class="container"> |
|||
<strong><h3>Problem</h3></strong> |
|||
<p> |
|||
Let \(m\) and \(n\) be positive integers. Let \(S\) be the set of all points |
|||
\((x, y)\) with integer coordinates such that \(1 \leq x, y \leq m + n − 1\) |
|||
and \(m + 1 \leq x + y \leq 2m + n − 1\). Let L be the set of the \(3m + 3n − |
|||
3\) lines parallel to one of \(x = 0\), \(y = 0\), or \(x + y = 0\) and passing |
|||
through at least one point in \(S\). For which pairs \((m, n)\) does there |
|||
exist a subset \(T\) of \(S\) such that every line in \(L\) intersects an odd |
|||
number of elements of \(T\)? |
|||
</p> |
|||
<strong><h3>Proof</h3></strong> |
|||
<p> |
|||
The answer is just all \((m,n)\) such that \( (m+n-1)(m-n) \) is divisible |
|||
by 4. The sum of all the x and y coordinates should clearly be even, but |
|||
the sum of all \(x+y \mod 2\) is \( \frac{(m+n-1)(3m+n)}{2} \). For a |
|||
construction to even be viable, this quantity clearly needs to be even. |
|||
</p> |
|||
<strong><h3>Constructor</h3></strong> |
|||
{% if invalid %} |
|||
<p> Invalid Input! </p> |
|||
{% endif %} |
|||
{% if nosol %} |
|||
<p> No Valid Solution is Possible! </p> |
|||
{% endif %} |
|||
{% if image %} |
|||
<img src="{{ image }}" alt="Solution Image" /> |
|||
{% endif %} |
|||
{% if works == False %} |
|||
<p> Claimed Construction Fails!!!! </p> |
|||
{% endif %} |
|||
<form method="POST" action="{{url_for ('index')}}"> |
|||
<table role="grid"> |
|||
<tbody> |
|||
<tr> |
|||
<td> |
|||
<label for="M">Value for M:</label> |
|||
</td> |
|||
<td> |
|||
<input type="number" name="M" min="1" max="40" value="{{M}}" required /> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td> |
|||
<label for="N">Value for N:</label> |
|||
</td> |
|||
<td> |
|||
<input type="number" name="N" min="1" max="40" value="{{N}}" required /> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
<input type="submit" value="Construct"> |
|||
</form> |
|||
</main> |
|||
</body> |
|||
</html> |
Write
Preview
Loading…
Cancel
Save
Reference in new issue