commit
d874a01da3
28 changed files with 23709 additions and 0 deletions
@ -0,0 +1,25 @@ |
||||
**/.classpath |
||||
**/.dockerignore |
||||
**/.env |
||||
**/.git |
||||
**/.gitignore |
||||
**/.project |
||||
**/.settings |
||||
**/.toolstarget |
||||
**/.vs |
||||
**/.vscode |
||||
**/*.*proj.user |
||||
**/*.dbmdl |
||||
**/*.jfm |
||||
**/azds.yaml |
||||
**/bin |
||||
**/charts |
||||
**/docker-compose* |
||||
**/Dockerfile* |
||||
**/node_modules |
||||
**/npm-debug.log |
||||
**/obj |
||||
**/secrets.dev.yaml |
||||
**/values.dev.yaml |
||||
LICENSE |
||||
README.md |
||||
@ -0,0 +1 @@ |
||||
.vs/ |
||||
@ -0,0 +1,3 @@ |
||||
# Sudoku-Solver |
||||
|
||||
Ein Sudoku-Solver für i2solutions GmbH |
||||
@ -0,0 +1,3 @@ |
||||
bin/ |
||||
obj/ |
||||
*.csproj.user |
||||
@ -0,0 +1,21 @@ |
||||
#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging. |
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:7.0 AS base |
||||
WORKDIR /app |
||||
EXPOSE 80 |
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build |
||||
WORKDIR /src |
||||
COPY ["SolverWebApp/SolverWebApp.csproj", "SolverWebApp/"] |
||||
RUN dotnet restore "SolverWebApp/SolverWebApp.csproj" |
||||
COPY . . |
||||
WORKDIR "/src/SolverWebApp" |
||||
RUN dotnet build "SolverWebApp.csproj" -c Release -o /app/build |
||||
|
||||
FROM build AS publish |
||||
RUN dotnet publish "SolverWebApp.csproj" -c Release -o /app/publish /p:UseAppHost=false |
||||
|
||||
FROM base AS final |
||||
WORKDIR /app |
||||
COPY --from=publish /app/publish . |
||||
ENTRYPOINT ["dotnet", "SolverWebApp.dll"] |
||||
@ -0,0 +1,27 @@ |
||||
using Microsoft.AspNetCore.Mvc; |
||||
using Microsoft.AspNetCore.Mvc.RazorPages; |
||||
using System.Diagnostics; |
||||
|
||||
namespace SolverWebApp.Pages |
||||
{ |
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] |
||||
[IgnoreAntiforgeryToken] |
||||
public class ErrorModel : PageModel |
||||
{ |
||||
public string? RequestId { get; set; } |
||||
|
||||
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); |
||||
|
||||
private readonly ILogger<ErrorModel> _logger; |
||||
|
||||
public ErrorModel(ILogger<ErrorModel> logger) |
||||
{ |
||||
_logger = logger; |
||||
} |
||||
|
||||
public void OnGet() |
||||
{ |
||||
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
using SolverWebApp.Model; |
||||
using System.Net.Security; |
||||
using System.Net; |
||||
using System.Security.Cryptography.X509Certificates; |
||||
|
||||
var builder = WebApplication.CreateBuilder(args); |
||||
|
||||
// Add services to the container. |
||||
builder.Services.AddRazorPages(); |
||||
|
||||
var app = builder.Build(); |
||||
|
||||
// Configure the HTTP request pipeline. |
||||
if (!app.Environment.IsDevelopment()) |
||||
{ |
||||
app.UseExceptionHandler("/Error"); |
||||
} |
||||
app.UseStaticFiles(); |
||||
|
||||
app.UseRouting(); |
||||
|
||||
app.UseAuthorization(); |
||||
|
||||
app.MapRazorPages(); |
||||
|
||||
app.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); |
||||
|
||||
using (var db = new SolutionContext()) |
||||
{ |
||||
db.Database.EnsureCreated(); |
||||
} |
||||
|
||||
app.Run(); |
||||
@ -0,0 +1,34 @@ |
||||
{ |
||||
"profiles": { |
||||
"http": { |
||||
"commandName": "Project", |
||||
"launchBrowser": true, |
||||
"environmentVariables": { |
||||
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
}, |
||||
"dotnetRunMessages": true, |
||||
"applicationUrl": "http://localhost:5151" |
||||
}, |
||||
"IIS Express": { |
||||
"commandName": "IISExpress", |
||||
"launchBrowser": true, |
||||
"environmentVariables": { |
||||
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
} |
||||
}, |
||||
"Docker": { |
||||
"commandName": "Docker", |
||||
"launchBrowser": true, |
||||
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}", |
||||
"publishAllPorts": true |
||||
} |
||||
}, |
||||
"iisSettings": { |
||||
"windowsAuthentication": false, |
||||
"anonymousAuthentication": true, |
||||
"iisExpress": { |
||||
"applicationUrl": "http://localhost:48904", |
||||
"sslPort": 0 |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net7.0</TargetFramework> |
||||
<Nullable>enable</Nullable> |
||||
<ImplicitUsings>enable</ImplicitUsings> |
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<Content Include="Controllers\SolutionController.cs" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" /> |
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.17.0" /> |
||||
</ItemGroup> |
||||
|
||||
</Project> |
||||
@ -0,0 +1,9 @@ |
||||
{ |
||||
"DetailedErrors": true, |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft.AspNetCore": "Warning" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,9 @@ |
||||
{ |
||||
"Logging": { |
||||
"LogLevel": { |
||||
"Default": "Information", |
||||
"Microsoft.AspNetCore": "Warning" |
||||
} |
||||
}, |
||||
"AllowedHosts": "*" |
||||
} |
||||
@ -0,0 +1,55 @@ |
||||
html, body { |
||||
width: 100%; |
||||
height: 100%; |
||||
font-family: Verdana, Arial; |
||||
} |
||||
body { |
||||
margin: 0; |
||||
background: #f0f0f0; |
||||
} |
||||
.box { |
||||
margin: 1em 0; |
||||
width: 100%; |
||||
display:flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
} |
||||
|
||||
#sudoku_board { |
||||
font-size: 5vmin; |
||||
border-top: 1vmin solid #444; |
||||
border-left: 1vmin solid #444; |
||||
border-collapse: collapse; |
||||
} |
||||
|
||||
#sudoku_board tr { |
||||
border-bottom: 0.2vmin solid #444; |
||||
border-right: 1vmin solid #444; |
||||
} |
||||
|
||||
.sudoku_row_separator { |
||||
border-bottom: 1vmin solid #444 !important; |
||||
} |
||||
|
||||
#sudoku_board td { |
||||
width: 9vmin; |
||||
height: 9vmin; |
||||
border-right: 0.2vmin solid #444; |
||||
} |
||||
|
||||
.cell_separator { |
||||
border-right: 1vmin solid #444 !important; |
||||
} |
||||
|
||||
#sudoku_board { |
||||
background: #fff; |
||||
} |
||||
#sudoku_board td { |
||||
overflow: hidden; |
||||
text-align: center; |
||||
transition: all 0.25s; |
||||
} |
||||
#sudoku_board td:focus { |
||||
background: rgba(0, 0, 255, .1); |
||||
outline: none; |
||||
} |
||||
|
After Width: | Height: | Size: 126 B |
|
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,185 @@ |
||||
|
||||
window.onload = setup |
||||
|
||||
var cells_ordered = null |
||||
|
||||
function setup() { |
||||
let table = document.getElementById('sudoku_board') |
||||
cells_ordered = table.getElementsByTagName('td') |
||||
console.log(cells_ordered.length) |
||||
for (let c = 0; c < 81; c++){ |
||||
let cell = cells_ordered[c] |
||||
cell.addEventListener("keypress",check_cell_content) |
||||
cell.setAttribute("contenteditable","") |
||||
cell.innerHTML = '<br>' //Moves caret position to vertical center
|
||||
} |
||||
show_all_solutions() |
||||
} |
||||
|
||||
function fill_default() { |
||||
$('#message').text('') |
||||
publish_board([ |
||||
[9,NaN,5,NaN,NaN,NaN,3,NaN,NaN], |
||||
[NaN,6,NaN,NaN,NaN,1,NaN,5,NaN], |
||||
[3,2,1,9,NaN,NaN,NaN,NaN,NaN], |
||||
[NaN,9,2,5,NaN,NaN,4,1,3], |
||||
[NaN,5,7,4,NaN,NaN,NaN,NaN,NaN], |
||||
[NaN,1,NaN,NaN,NaN,2,NaN,NaN,5], |
||||
[NaN,7,NaN,NaN,NaN,9,1,NaN,6], |
||||
[NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN], |
||||
[NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN] |
||||
]) |
||||
} |
||||
|
||||
function clear_board() { |
||||
$('#message').text('') |
||||
for (let row = 0; row < 9; row++) |
||||
for (let column = 0; column < 9; column++) |
||||
publish_cell(row, column, NaN) |
||||
} |
||||
|
||||
function check_cell_content(e) { |
||||
console.log(e.key) |
||||
let content = parseInt(e.key) |
||||
console.log(content) |
||||
if ((content <= 0) || isNaN(content) || e.target.innerText.trim().length > 0){ |
||||
e.preventDefault() |
||||
} |
||||
} |
||||
|
||||
function get_data() { |
||||
let table = document.getElementById('sudoku_board') |
||||
let cells_ordered = table.getElementsByTagName('td') |
||||
let sudoku_board = [[],[],[],[],[],[],[],[],[]] |
||||
for (let cell = 0;cell<81;cell++){ |
||||
let column = cell%9 |
||||
let row = Math.floor(cell/9) |
||||
let value = parseInt(cells_ordered[cell].textContent.trim()) |
||||
sudoku_board[row][column] = value |
||||
} |
||||
return sudoku_board |
||||
} |
||||
|
||||
function publish_cell(row, column, value) { |
||||
cells_ordered[row*9 + column].innerHTML = "" + (isNaN(value) ? "<br>" : value) |
||||
} |
||||
|
||||
function publish_board(board) { |
||||
for (let row = 0; row < 9; row++) |
||||
for (let column = 0; column < 9; column++) |
||||
publish_cell(row, column, board[row][column]) |
||||
} |
||||
|
||||
function set_cell(board, row, column, value) { |
||||
board[row][column] = value |
||||
publish_cell(row, column, value) |
||||
} |
||||
|
||||
function solve_step(board, cell) { |
||||
let column = cell%9 |
||||
let row = Math.floor(cell/9) |
||||
|
||||
if(cell > 80) |
||||
return true |
||||
|
||||
if(!isNaN(board[row][column])) |
||||
return solve_step(board, cell + 1) |
||||
|
||||
for(let nr = 1;nr<=9;nr++) { |
||||
if(check_cell(board, row, column, nr)) { |
||||
set_cell(board, row, column, nr) |
||||
if(solve_step(board, cell + 1)) { |
||||
return true; |
||||
} else { |
||||
set_cell(board, row, column, NaN) |
||||
} |
||||
} |
||||
} |
||||
return false |
||||
} |
||||
|
||||
function board_to_string(board) { |
||||
let ret = "" |
||||
for (let row = 0; row < 9; row++) |
||||
for (let column = 0; column < 9; column++) |
||||
ret += isNaN(board[row][column]) ? "0" : "" + board[row][column] |
||||
return ret |
||||
} |
||||
|
||||
function store_board(board) { |
||||
$.ajax({ |
||||
url: '/solution', |
||||
type: 'POST', |
||||
contentType: 'application/json', |
||||
data: JSON.stringify({ "Data": board_to_string(board) }), |
||||
success: function () { |
||||
$('#message').text('Stored solution to database') |
||||
show_all_solutions() |
||||
}, |
||||
error: function () { |
||||
$('#message').text('Error on saving the solution to the database.') |
||||
} |
||||
}) |
||||
} |
||||
|
||||
function solve() { |
||||
$('#message').text('') |
||||
let board = get_data() |
||||
if (!check_board(board)) { |
||||
$('#message').text("The numbers on the board are in conflict with the rules of Sudoku") |
||||
return |
||||
} |
||||
|
||||
if (!solve_step(board, 0)) { |
||||
$('#message').text("Unable to solve this Sudoku") |
||||
return |
||||
} |
||||
|
||||
store_board(board) |
||||
} |
||||
|
||||
function show_all_solutions() { |
||||
jQuery.get("/solution", function (data) { |
||||
new DevExpress.ui.dxDataGrid(document.getElementById("allsolutions"), { |
||||
dataSource: data, |
||||
columnAutoWidth: true |
||||
}); |
||||
}).fail(function (e) { console.warn("fetching solution failed: ", e) }) |
||||
} |
||||
|
||||
function check_cell(board, row, col, value) { |
||||
// if already present on the column, not acceptable
|
||||
for (let r = 0; r < 9; ++r) |
||||
if (board[r][ col] == value) return false; |
||||
|
||||
// if already present on the row, not acceptable
|
||||
for (let c = 0; c < 9; ++c) |
||||
if (board[row][ c] == value) return false; |
||||
|
||||
// if already present in the same 3x3 square, also not acceptable
|
||||
let r1 = Math.floor(row / 3) * 3; |
||||
let c1 = Math.floor(col / 3) * 3; |
||||
for (let r = r1; r < r1 + 3; ++r) { |
||||
for (let c = c1; c < c1 + 3; ++c) { |
||||
if (board[r][c] == value) return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
function check_board(board) { |
||||
for (let r = 0; r < 9; ++r) |
||||
for (let c = 0; c < 9; ++c) { |
||||
let value = board[r][c] |
||||
if(isNaN(value)) |
||||
continue |
||||
board[r][c] = NaN |
||||
let res = check_cell(board,r,c, value) |
||||
board[r][c] = value |
||||
if(!res) |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,10 @@ |
||||
services: |
||||
db: |
||||
image: mcr.microsoft.com/mssql/server:2019-latest |
||||
environment: |
||||
ACCEPT_EULA: "1" |
||||
MSSQL_SA_PASSWORD: i2suPers3cret. |
||||
ports: |
||||
- 127.0.0.1:1433:1433 |
||||
expose: |
||||
- "1433" |
||||
Loading…
Reference in new issue