Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 79cf3240e1 | |||
| 81d689c1ba | |||
| ecfe5c09a8 | |||
| 10e36d9aee | |||
| cb05b091d8 | |||
| 34dfa118d9 |
Binary file not shown.
@@ -1,5 +1,6 @@
|
||||
from flask import Blueprint, render_template
|
||||
from flask import Blueprint, jsonify, render_template, request
|
||||
from flask_login import login_required, current_user
|
||||
import random
|
||||
|
||||
main_bp = Blueprint("main", __name__)
|
||||
|
||||
@@ -11,3 +12,64 @@ def home():
|
||||
@login_required
|
||||
def dashboard():
|
||||
return render_template('dashboard.html', user=current_user)
|
||||
|
||||
@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)
|
||||
|
||||
@main_bp.route("/solve_rooks")
|
||||
def solve_rooks_route():
|
||||
return jsonify(solve_rooks(8))
|
||||
|
||||
def solve_rooks(n=8):
|
||||
solution = list(range(n))
|
||||
random.shuffle(solution)
|
||||
return solution
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
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;
|
||||
}
|
||||
|
||||
.mode-switch {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.mode-switch .btn {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.btn.active {
|
||||
background: #22c55e;
|
||||
}
|
||||
+56
-46
@@ -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 */
|
||||
@@ -0,0 +1,199 @@
|
||||
let mode = "queens"; // oder "rooks"
|
||||
|
||||
function setMode(newMode) {
|
||||
mode = newMode;
|
||||
resetBoard();
|
||||
|
||||
document.getElementById("btnQueens").classList.remove("active");
|
||||
document.getElementById("btnRooks").classList.remove("active");
|
||||
|
||||
if (mode === "queens") {
|
||||
document.getElementById("btnQueens").classList.add("active");
|
||||
} else {
|
||||
document.getElementById("btnRooks").classList.add("active");
|
||||
}
|
||||
|
||||
drawBoard();
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
// 🔴 Türme: nur gleiche Spalte
|
||||
if (mode === "rooks") {
|
||||
if (c1 === c2) {
|
||||
conflicts.push([r1, c1]);
|
||||
conflicts.push([r2, c2]);
|
||||
}
|
||||
}
|
||||
|
||||
// 🔴 Damen: Spalte + Diagonale
|
||||
else if (mode === "queens") {
|
||||
if (
|
||||
c1 === c2 ||
|
||||
Math.abs(c1 - c2) === Math.abs(r1 - r2)
|
||||
) {
|
||||
conflicts.push([r1, c1]);
|
||||
conflicts.push([r2, c2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts;
|
||||
}
|
||||
|
||||
function checkSolution() {
|
||||
const status = document.getElementById("statusMessage");
|
||||
|
||||
const allPlaced = board.every(col => col !== -1);
|
||||
|
||||
if (!allPlaced) {
|
||||
status.textContent = "❗ Noch nicht alle Figuren platziert.";
|
||||
status.style.color = "orange";
|
||||
return;
|
||||
}
|
||||
|
||||
const conflicts = getConflicts();
|
||||
|
||||
if (conflicts.length > 0) {
|
||||
status.textContent = "❌ Es gibt Konflikte!";
|
||||
status.style.color = "red";
|
||||
return;
|
||||
}
|
||||
|
||||
status.textContent = "🎉 Perfekt gelöst!";
|
||||
status.style.color = "green";
|
||||
}
|
||||
|
||||
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 = (mode === "queens") ? "♛" : "♜";
|
||||
|
||||
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() {
|
||||
|
||||
if (mode === "rooks") {
|
||||
const res = await fetch("/solve_rooks");
|
||||
const solution = await res.json();
|
||||
|
||||
board = solution;
|
||||
drawBoard();
|
||||
return;
|
||||
}
|
||||
|
||||
// Damen (wie vorher)
|
||||
const res = await fetch("/solve");
|
||||
const solution = await res.json();
|
||||
|
||||
board = Array.isArray(solution[0]) ? solution[0] : solution;
|
||||
drawBoard();
|
||||
}
|
||||
|
||||
|
||||
function resetBoard() {
|
||||
const status = document.getElementById("statusMessage");
|
||||
board = Array(8).fill(-1);
|
||||
drawBoard();
|
||||
updateQueenList();
|
||||
status.textContent = "";
|
||||
}
|
||||
|
||||
drawBoard();
|
||||
|
||||
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 = `${mode === "queens" ? "Dame" : "Turm"} ${count}: ${pos}`;
|
||||
|
||||
list.appendChild(li);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
-9
@@ -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";
|
||||
});
|
||||
|
||||
@@ -1,51 +1,78 @@
|
||||
<!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>
|
||||
<a href="{{ url_for('main.dashboard') }}">Dashboard</a>
|
||||
<a href="{{ url_for('login.logout') }}">Logout</a>
|
||||
<!-- 🔝 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>
|
||||
<!-- 👤 User Card -->
|
||||
<div class="card">
|
||||
<h2>👋 Willkommen, {{ current_user.username }}</h2>
|
||||
|
||||
<p>Welcome back <strong>{{ current_user.username }}</strong> 👋</p>
|
||||
<div class="user-info">
|
||||
<p><strong>ID:</strong> {{ current_user.id }}</p>
|
||||
<p><strong>Username:</strong> {{ current_user.username }}</p>
|
||||
|
||||
<div class="user-info">
|
||||
<h3>Your Account</h3>
|
||||
{% if current_user.email %}
|
||||
<p><strong>Email:</strong> {{ current_user.email }}</p>
|
||||
{% else %}
|
||||
<p><strong>Email:</strong> Not set</p>
|
||||
{% endif %}
|
||||
|
||||
<p><strong>User ID:</strong> {{ current_user.id }}</p>
|
||||
<p><strong>Username:</strong> {{ current_user.username }}</p>
|
||||
<p><strong>Erstellt:</strong> {{ current_user.created_at }}</p>
|
||||
</div>
|
||||
|
||||
{% if current_user.email %}
|
||||
<p><strong>Email:</strong> {{ current_user.email }}</p>
|
||||
{% else %}
|
||||
<p><strong>Email:</strong> Not set</p>
|
||||
{% endif %}
|
||||
|
||||
<p><strong>Account created:</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>
|
||||
```
|
||||
|
||||
<div class="mode-switch">
|
||||
<button class="btn active" onclick="setMode('queens')" id="btnQueens">♛ Damen</button>
|
||||
<button class="btn secondary" onclick="setMode('rooks')" id="btnRooks">♜ Türme</button>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- ♟️ Game Card -->
|
||||
<div class="card game-card">
|
||||
<h2>♟️ 8-Damen Spiel</h2>
|
||||
|
||||
<p id="statusMessage"></p>
|
||||
<div class="board" id="board"></div>
|
||||
|
||||
<div class="controls">
|
||||
<button class="btn" onclick="solve()">Solve</button>
|
||||
<button class="btn" onclick="checkSolution()">Check</button>
|
||||
<button class="btn secondary" onclick="resetBoard()">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>📋 Damen Positionen</h3>
|
||||
<ul id="queenList"></ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../static/js/dashboard.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user