5 Commits

Author SHA1 Message Date
ScriptSorcerer 81d689c1ba Added chess board specification (number and cahracters), aswell as a detail view for the damen 2026-03-26 19:38:56 +01:00
ScriptSorcerer ecfe5c09a8 Simple chessboard design + slove button (shows you the solution with the algorithm) and marks conflicts with damen red.
conflict still has some errors (damen despawn somethimes) and css is very simple.
2026-03-26 11:06:27 +01:00
ScriptSorcerer 10e36d9aee Merge pull request #7 from ScriptSorcerer20/main
Update Dev branch
2026-03-23 13:04:40 +01:00
ScriptSorcerer cb05b091d8 Merge pull request #6 from ScriptSorcerer20/1-design-improvement
added gradients to backgroudn added functional button animation
2026-03-23 12:59:50 +01:00
ScriptSorcerer 34dfa118d9 added gradients to backgroudn added functional button animation
chnaged color design (grey style)
2026-03-23 12:55:59 +01:00
11 changed files with 461 additions and 239 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
+51 -4
View File
@@ -1,4 +1,4 @@
from flask import Blueprint, render_template
from flask import Blueprint, jsonify, render_template, request
from flask_login import login_required, current_user
main_bp = Blueprint("main", __name__)
@@ -12,6 +12,53 @@ def home():
def dashboard():
return render_template('dashboard.html', user=current_user)
@main_bp.route('/solver')
def solver():
return render_template('solver.html')
@main_bp.route("/check", methods=["POST"])
def check():
data = request.json
board = data["board"]
row = data["row"]
col = data["col"]
for r in range(len(board)):
c = board[r]
if c == -1 or r == row:
continue
# gleiche Spalte
if c == col:
return jsonify({"valid": False})
# gleiche Diagonale
if abs(c - col) == abs(r - row):
return jsonify({"valid": False})
return jsonify({"valid": True})
@main_bp.route("/solve")
def solve():
n = 8
solutions = []
board = [-1] * n
def is_safe(row, col):
for r in range(row):
c = board[r]
if c == col or abs(c - col) == abs(r - row):
return False
return True
def backtrack(row):
if row == n:
solutions.append(board[:])
return
for col in range(n):
if is_safe(row, col):
board[row] = col
backtrack(row + 1)
board[row] = -1
backtrack(0)
return jsonify(solutions)
+143
View File
@@ -0,0 +1,143 @@
body {
margin: 0;
font-family: Arial, sans-serif;
background: #f5f7fa;
}
/* 🔝 Navbar */
.navbar {
display: flex;
justify-content: space-between;
align-items: center;
background: #1e293b;
color: white;
padding: 15px 30px;
}
.navbar a {
color: white;
margin-left: 15px;
text-decoration: none;
}
.navbar a:hover {
text-decoration: underline;
}
/* 📦 Layout */
.container {
max-width: 900px;
margin: 30px auto;
padding: 10px;
}
/* 📇 Cards */
.card {
background: white;
padding: 20px;
margin-bottom: 25px;
border-radius: 12px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
.game-card {
text-align: center;
}
/* ♟️ Board */
.board-grid {
display: grid;
grid-template-columns: 30px repeat(8, 60px);
grid-template-rows: 30px repeat(8, 60px);
margin: 20px auto;
width: max-content;
border: 6px solid #1e293b;
border-radius: 10px;
overflow: hidden;
}
.label {
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
background: #aec8eb;
color: #1e293b;
}
.cell {
width: 60px;
height: 60px;
display: flex;
align-items: center;
justify-content: center;
font-size: 30px;
cursor: pointer;
transition: 0.2s;
}
.cell:hover {
transform: scale(1.05);
}
.white {
background: #e2e8f0;
}
.black {
background: #475569;
color: white;
}
.invalid {
background: #ef4444 !important;
}
/* 🎛️ Buttons */
.controls {
margin-top: 15px;
}
.btn {
padding: 10px 15px;
margin: 5px;
border: none;
border-radius: 8px;
background: #3b82f6;
color: white;
cursor: pointer;
}
.btn:hover {
background: #2563eb;
}
.btn.secondary {
background: #64748b;
}
.btn.secondary:hover {
background: #475569;
}
.btn.danger {
background: #ef4444;
}
.btn.danger:hover {
background: #dc2626;
}
#queenList {
list-style: none;
padding: 0;
}
#queenList li {
padding: 5px;
background: #f1f5f9;
margin: 4px 0;
border-radius: 6px;
}
+56 -46
View File
@@ -21,40 +21,11 @@ body {
display: grid;
place-items: center;
font-family: "Geist Sans", system-ui, sans-serif;
background: linear-gradient(135deg, #c6dff4, #7c8384);
}
/* MAGNET EFFECT */
.magnetic {
padding: 10px 20px;
border: none;
background: #4facfe;
color: white;
border-radius: 6px;
cursor: pointer;
font-size: 16px;
transition: transform 0.2s ease;
}
.magnetic:hover {
background: #2d8cf0;
}
/* Reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
}
/* Page setup */
body {
min-height: 100vh;
background: var(--primary-bg-color);
}
/* Navbar */
nav {
width: 100%;
background: var(--nav-bg-color);
@@ -93,17 +64,38 @@ main h1 {
margin-bottom: 20px;
}
main {
animation: fadeIn 0.8s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(15px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Form box */
form {
background: var(--secondary-bg-color);
padding: 30px;
border-radius: 8px;
width: 300px;
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(12px);
padding: 35px;
border-radius: 12px;
width: 320px;
display: flex;
flex-direction: column;
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Labels */
label {
margin-top: 10px;
@@ -112,30 +104,48 @@ label {
}
/* Inputs */
input {
padding: 10px;
border: 1px solid #ccc;
border-radius: 6px;
form {
background: rgba(255, 255, 255, 0.15);
backdrop-filter: blur(12px);
padding: 35px;
border-radius: 12px;
width: 320px;
display: flex;
flex-direction: column;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
border: 1px solid rgba(255, 255, 255, 0.2);
}
/* Button */
.button {
button {
margin-top: 20px;
padding: 10px;
padding: 12px;
border: none;
background: #4facfe;
color: white;
border-radius: 6px;
background: linear-gradient(135deg, #e9eff5, #daebf0);
color: rgb(0, 0, 0);
border-radius: 8px;
cursor: pointer;
font-size: 16px;
transition: all 0.2s ease;
}
button:hover {
background: #2d8cf0;
transform: translateY(-2px);
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
}
button:active {
transform: scale(0.97);
}
/* Error message */
.error {
color: red;
margin-bottom: 15px;
}
/* button anim */
-125
View File
@@ -1,125 +0,0 @@
:root {
--bg-color: #f4f6f8;
--text-color: #333;
--board-border: #2c3e50;
--square-light: #ecf0f1;
--square-dark: #95a5a6;
--accent-color: #3498db;
--btn-hover: #2980b9;
--shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: var(--bg-color);
color: var(--text-color);
margin: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
min-height: 100vh;
}
h1 {
font-weight: 300;
letter-spacing: -0.5px;
margin-bottom: 2rem;
color: var(--board-border);
}
.container {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
align-items: center;
gap: 1.5rem;
}
.chessboard {
display: grid;
grid-template-columns: repeat(8, 50px);
grid-template-rows: repeat(8, 50px);
border: 5px solid var(--board-border);
user-select: none;
}
.square {
width: 50px;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
}
.square.light {
background-color: var(--square-light);
}
.square.dark {
background-color: var(--square-dark);
}
.queen {
color: var(--board-border);
text-shadow: 0 2px 2px rgba(0,0,0,0.2);
cursor: pointer;
transition: transform 0.2s ease;
}
.queen:hover {
transform: scale(1.1);
}
.controls {
display: flex;
gap: 1rem;
margin-top: 1rem;
}
button {
background-color: var(--accent-color);
color: white;
border: none;
padding: 0.6rem 1.2rem;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s ease;
}
button:hover {
background-color: var(--btn-hover);
}
button.secondary {
background-color: transparent;
border: 1px solid var(--accent-color);
color: var(--accent-color);
}
button.secondary:hover {
background-color: rgba(52, 152, 219, 0.1);
}
@media (max-width: 600px) {
.chessboard {
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(8, 1fr);
width: 100%;
max-width: 400px;
height: auto;
aspect-ratio: 1/1;
}
.square {
width: 100%;
height: 100%;
font-size: 1.5rem;
}
}
+27 -9
View File
@@ -1,14 +1,32 @@
const button = document.querySelector(".magnetic")
const button = document.querySelector(".magnetic");
button.addEventListener("mousemove", (e) => {
const rect = button.getBoundingClientRect()
const rect = button.getBoundingClientRect();
const x = e.clientX - rect.left - rect.width / 2;
const y = e.clientY - rect.top - rect.height / 2;
const x = e.clientX - rect.left - rect.width / 2
const y = e.clientY - rect.top - rect.height / 2
button.style.transform = `translate(${x * 0.3}px, ${y * 0.3}px)`
})
button.style.transform = `translate(${x * 0.2}px, ${y * 0.2}px)`;
});
button.addEventListener("mouseleave", () => {
button.style.transform = "translate(0,0)"
})
button.style.transform = "translate(0,0)";
});
const inputs = document.querySelectorAll("input");
inputs.forEach(input => {
input.addEventListener("input", () => {
input.style.boxShadow = "0 0 8px rgba(79,172,254,0.6)";
setTimeout(() => {
input.style.boxShadow = "";
}, 300);
});
});
const form = document.querySelector("form");
form.addEventListener("submit", () => {
button.innerText = "Logging in...";
button.style.opacity = "0.7";
});
+171 -14
View File
@@ -1,31 +1,34 @@
<!DOCTYPE html>
<html lang="en">
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dashboard</title>
<link rel="stylesheet" href="../static/css/dashboard.css">
</head>
<body>
<nav>
<!-- 🔝 Navbar -->
<nav class="navbar">
<div class="nav-left">♛ 8-Queens App</div>
<div class="nav-right">
<a href="{{ url_for('main.dashboard') }}">Dashboard</a>
<a href="{{ url_for('login.logout') }}">Logout</a>
</div>
</nav>
<!-- 📦 Container -->
<div class="container">
```
<h1>Dashboard</h1>
<p>Welcome back <strong>{{ current_user.username }}</strong> 👋</p>
<!-- 👤 User Card -->
<div class="card">
<h2>👋 Willkommen, {{ current_user.username }}</h2>
<div class="user-info">
<h3>Your Account</h3>
<p><strong>User ID:</strong> {{ current_user.id }}</p>
<p><strong>ID:</strong> {{ current_user.id }}</p>
<p><strong>Username:</strong> {{ current_user.username }}</p>
{% if current_user.email %}
@@ -34,18 +37,172 @@
<p><strong>Email:</strong> Not set</p>
{% endif %}
<p><strong>Account created:</strong> {{ current_user.created_at }}</p>
<p><strong>Erstellt:</strong> {{ current_user.created_at }}</p>
</div>
<div class="logout">
<form action="{{ url_for('login.logout') }}" method="post">
<button type="submit">Logout</button>
<button class="btn danger" type="submit">Logout</button>
</form>
</div>
```
<!-- ♟️ Game Card -->
<div class="card game-card">
<h2>♟️ 8-Damen Spiel</h2>
<div class="board" id="board"></div>
<div class="controls">
<button class="btn" onclick="solve()">Solve</button>
<button class="btn secondary" onclick="resetBoard()">Reset</button>
</div>
</div>
</div>
<script>
let board = Array(8).fill(-1);
const boardDiv = document.getElementById("board");
function getConflicts() {
let conflicts = [];
for (let r1 = 0; r1 < 8; r1++) {
if (board[r1] === -1) continue;
for (let r2 = r1 + 1; r2 < 8; r2++) {
if (board[r2] === -1) continue;
let c1 = board[r1];
let c2 = board[r2];
if (
c1 === c2 ||
Math.abs(c1 - c2) === Math.abs(r1 - r2)
) {
conflicts.push([r1, c1]);
conflicts.push([r2, c2]);
}
}
}
return conflicts;
}
function drawBoard() {
boardDiv.innerHTML = "";
boardDiv.className = "board-grid";
const conflicts = getConflicts();
const letters = ["A", "B", "C", "D", "E", "F", "G", "H"];
for (let row = -1; row < 8; row++) {
for (let col = -1; col < 8; col++) {
const cell = document.createElement("div");
// 🔹 Ecke oben links
if (row === -1 && col === -1) {
cell.classList.add("label");
}
// 🔹 Buchstaben (oben)
else if (row === -1) {
cell.textContent = letters[col];
cell.classList.add("label");
}
// 🔹 Zahlen (links)
else if (col === -1) {
cell.textContent = 8 - row;
cell.classList.add("label");
}
// 🔹 echtes Spielfeld
else {
cell.classList.add("cell");
if ((row + col) % 2 === 0) {
cell.classList.add("white");
} else {
cell.classList.add("black");
}
if (board[row] === col) {
cell.textContent = "♛";
if (conflicts.some(([r, c]) => r === row && c === col)) {
cell.classList.add("invalid");
}
}
cell.onclick = () => placeQueen(row, col);
}
boardDiv.appendChild(cell);
}
}
updateQueenList();
}
function placeQueen(row, col) {
if (board[row] === col) {
board[row] = -1;
} else {
board[row] = col;
}
drawBoard();
updateQueenList();
}
async function solve() {
const res = await fetch("/solve");
const solutions = await res.json();
board = solutions[0];
drawBoard();
}
function resetBoard() {
board = Array(8).fill(-1);
drawBoard();
updateQueenList();
}
drawBoard();
</script>
<div class="card">
<h3>📋 Damen Positionen</h3>
<ul id="queenList"></ul>
</div>
<script>
function updateQueenList() {
const list = document.getElementById("queenList");
list.innerHTML = "";
const letters = ["A", "B", "C", "D", "E", "F", "G", "H"];
let count = 1;
for (let row = 0; row < 8; row++) {
if (board[row] !== -1) {
let col = board[row];
let pos = letters[col] + (8 - row);
const li = document.createElement("li");
li.textContent = `Dame ${count}: ${pos}`;
list.appendChild(li);
count++;
}
}
}
</script>
</body>
</html>
+1 -1
View File
@@ -21,7 +21,7 @@
<nav>
<a href="/">Home</a>
<a href="/solver">Solver</a>
<a href="/dashboard">Solver</a>
{% if session.get('user_id') %}
<a href="/dashboard">Dashboard</a>
+1 -1
View File
@@ -14,7 +14,7 @@
<nav>
<ul>
<li><a href="{{ url_for('login.login') }}"><span>Login</span></a></li>
<li><a href="{{ url_for('login.register') }}"><span></span>Create account</span></a></li>
<li><a href="{{ url_for('login.register') }}"><span>Create account</span></a></li>
</ul>
</nav>
-28
View File
@@ -1,28 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>8-Damen-Problem</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/solver.css') }}">
</head>
<body>
<div class="container">
<h1>8-Damen-Problem Test</h1>
<div class="chessboard">
{% for row in range(8) %}
{% for col in range(8) %}
<div class="square {{ 'light' if (row + col) % 2 == 0 else 'dark' }}" data-row="{{ row }}" data-col="{{ col }}">
<!-- Queens will be placed here -->
</div>
{% endfor %}
{% endfor %}
</div>
<div class="controls">
<button id="solveBtn">Solve</button>
<button id="resetBtn" class="secondary">Reset</button>
</div>
</div>
</body>
</html>