|
import React, { useState, useEffect } from 'react'; |
|
|
|
function PredefinedPuzzlePage() { |
|
|
|
const [puzzleIndex, setPuzzleIndex] = useState(0); |
|
const [puzzleText, setPuzzleText] = useState(""); |
|
const [expectedSolution, setExpectedSolution] = useState(null); |
|
|
|
|
|
const [sysContent, setSysContent] = useState(""); |
|
|
|
|
|
const [generatedCode, setGeneratedCode] = useState(""); |
|
const [executionSuccess, setExecutionSuccess] = useState(null); |
|
const [attempts, setAttempts] = useState(0); |
|
const [isSolving, setIsSolving] = useState(false); |
|
const [problematicConstraints, setProblematicConstraints] = useState(""); |
|
|
|
|
|
const [currentStep, setCurrentStep] = useState(1); |
|
const [expandedSections, setExpandedSections] = useState({ |
|
puzzle: true, |
|
sysContent: false, |
|
result: false |
|
}); |
|
|
|
|
|
useEffect(() => { |
|
fetch(`/default_sys_content`) |
|
.then(res => res.json()) |
|
.then(data => { |
|
if(data.success) { |
|
setSysContent(data.sysContent); |
|
} |
|
}) |
|
.catch(e => console.error(e)); |
|
}, []); |
|
|
|
|
|
useEffect(() => { |
|
fetch(`/get_puzzle?index=${puzzleIndex}`) |
|
.then(res => res.json()) |
|
.then(data => { |
|
if(data.success) { |
|
setPuzzleText(data.puzzle); |
|
setExpectedSolution(data.expected_solution); |
|
} else { |
|
console.error("Failed to fetch puzzle", data.error); |
|
setPuzzleText(""); |
|
setExpectedSolution(null); |
|
} |
|
}) |
|
.catch(e => console.error(e)); |
|
}, [puzzleIndex]); |
|
|
|
const handleSolve = () => { |
|
if(!puzzleText || !expectedSolution) { |
|
alert("puzzle or expectedSolution incomplete"); |
|
return; |
|
} |
|
const payload = { |
|
index: puzzleIndex, |
|
puzzle: puzzleText, |
|
expected_solution: expectedSolution, |
|
sys_content: sysContent, |
|
problematic_constraints: problematicConstraints |
|
}; |
|
|
|
setIsSolving(true); |
|
setCurrentStep(3); |
|
setExpandedSections({...expandedSections, result: true}); |
|
|
|
fetch(`/solve`, { |
|
method: "POST", |
|
headers: { "Content-Type": "application/json" }, |
|
body: JSON.stringify(payload) |
|
}) |
|
.then(res => res.json()) |
|
.then(data => { |
|
if(!data.success) { |
|
alert("Backend error: " + data.error); |
|
return; |
|
} |
|
const result = data.result; |
|
setGeneratedCode(result.generatedCode || ""); |
|
setExecutionSuccess(result.success); |
|
setAttempts(result.attempts || 0); |
|
setProblematicConstraints(result.problematicConstraints || ""); |
|
}) |
|
.catch(e => console.error(e)) |
|
.finally(() => { |
|
setIsSolving(false); |
|
}); |
|
}; |
|
|
|
const toggleSection = (section) => { |
|
setExpandedSections({ |
|
...expandedSections, |
|
[section]: !expandedSections[section] |
|
}); |
|
}; |
|
|
|
const nextStep = () => { |
|
if (currentStep < 3) { |
|
setCurrentStep(currentStep + 1); |
|
if (currentStep === 1) { |
|
setExpandedSections({puzzle: false, sysContent: true, result: false}); |
|
} else if (currentStep === 2) { |
|
setExpandedSections({puzzle: false, sysContent: false, result: true}); |
|
} |
|
} |
|
}; |
|
|
|
const prevStep = () => { |
|
if (currentStep > 1) { |
|
setCurrentStep(currentStep - 1); |
|
if (currentStep === 2) { |
|
setExpandedSections({puzzle: true, sysContent: false, result: false}); |
|
} else if (currentStep === 3) { |
|
setExpandedSections({puzzle: false, sysContent: true, result: false}); |
|
} |
|
} |
|
}; |
|
|
|
return ( |
|
<> |
|
{/* Progress Steps */} |
|
<div className="progress-container"> |
|
<div className="progress-steps"> |
|
<div className={`step ${currentStep >= 1 ? 'active' : ''}`}> |
|
<div className="step-number">1</div> |
|
<div className="step-label">Select Puzzle</div> |
|
</div> |
|
<div className={`step ${currentStep >= 2 ? 'active' : ''}`}> |
|
<div className="step-number">2</div> |
|
<div className="step-label">Configure System</div> |
|
</div> |
|
<div className={`step ${currentStep >= 3 ? 'active' : ''}`}> |
|
<div className="step-number">3</div> |
|
<div className="step-label">Solve & Results</div> |
|
</div> |
|
</div> |
|
</div> |
|
|
|
<main className="main-content"> |
|
{/* Step 1: Puzzle Selection */} |
|
<section className={`content-section ${expandedSections.puzzle ? 'expanded' : 'collapsed'}`}> |
|
<div className="section-header" onClick={() => toggleSection('puzzle')}> |
|
<h2>📋 Puzzle Selection</h2> |
|
<span className="toggle-icon">{expandedSections.puzzle ? '▼' : '▶'}</span> |
|
</div> |
|
|
|
{expandedSections.puzzle && ( |
|
<div className="section-content"> |
|
<div className="puzzle-selector"> |
|
<label htmlFor="puzzle-index">Choose puzzle index (0 - 999):</label> |
|
<div className="input-group"> |
|
<input |
|
id="puzzle-index" |
|
type="number" |
|
value={puzzleIndex} |
|
onChange={(e) => setPuzzleIndex(Number(e.target.value))} |
|
min={0} |
|
max={999} |
|
className="number-input" |
|
/> |
|
<button |
|
onClick={() => setPuzzleIndex(puzzleIndex)} |
|
className="btn btn-secondary" |
|
> |
|
Load Puzzle |
|
</button> |
|
</div> |
|
</div> |
|
|
|
<div className="puzzle-display"> |
|
<div className="puzzle-text"> |
|
<h3>📄 Puzzle Text</h3> |
|
<div className="text-display"> |
|
{puzzleText || "Loading puzzle..."} |
|
</div> |
|
</div> |
|
|
|
<div className="expected-solution"> |
|
<h3>🎯 Expected Solution</h3> |
|
<div className="json-display"> |
|
{expectedSolution ? ( |
|
<pre>{JSON.stringify(expectedSolution, null, 2)}</pre> |
|
) : ( |
|
"Loading solution..." |
|
)} |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
)} |
|
</section> |
|
|
|
{/* Step 2: System Configuration */} |
|
<section className={`content-section ${expandedSections.sysContent ? 'expanded' : 'collapsed'}`}> |
|
<div className="section-header" onClick={() => toggleSection('sysContent')}> |
|
<h2>⚙️ System Configuration</h2> |
|
<span className="toggle-icon">{expandedSections.sysContent ? '▼' : '▶'}</span> |
|
</div> |
|
|
|
{expandedSections.sysContent && ( |
|
<div className="section-content"> |
|
<div className="sys-content-editor"> |
|
<h3>📝 System Content</h3> |
|
<p className="description"> |
|
Edit the system prompt that will guide the AI in solving the puzzle: |
|
</p> |
|
<textarea |
|
value={sysContent} |
|
onChange={(e) => setSysContent(e.target.value)} |
|
className="sys-content-textarea" |
|
placeholder="Enter system content..." |
|
/> |
|
</div> |
|
</div> |
|
)} |
|
</section> |
|
|
|
{/* Step 3: Solve & Results */} |
|
<section className={`content-section ${expandedSections.result ? 'expanded' : 'collapsed'}`}> |
|
<div className="section-header" onClick={() => toggleSection('result')}> |
|
<h2>🚀 Solve & Results</h2> |
|
<span className="toggle-icon">{expandedSections.result ? '▼' : '▶'}</span> |
|
</div> |
|
|
|
{expandedSections.result && ( |
|
<div className="section-content"> |
|
<div className="solve-section"> |
|
<button |
|
onClick={handleSolve} |
|
disabled={isSolving || !puzzleText || !expectedSolution} |
|
className={`btn btn-primary solve-btn ${isSolving ? 'loading' : ''}`} |
|
> |
|
{isSolving ? '🔄 Solving...' : '🧠 Solve Puzzle with AI'} |
|
</button> |
|
</div> |
|
|
|
<div className="results-section"> |
|
<div className="result-summary"> |
|
<div className="result-item"> |
|
<span className="result-label">Status:</span> |
|
<span className={`result-value ${executionSuccess === true ? 'success' : executionSuccess === false ? 'error' : 'pending'}`}> |
|
{executionSuccess === null ? "⏳ Pending" : executionSuccess ? "✅ Success" : "❌ Failed"} |
|
</span> |
|
</div> |
|
<div className="result-item"> |
|
<span className="result-label">Attempts:</span> |
|
<span className="result-value">{attempts}</span> |
|
</div> |
|
</div> |
|
|
|
{problematicConstraints && ( |
|
<div className="issues-section"> |
|
<h3>⚠️ Issues & Analysis</h3> |
|
<div className="issues-display"> |
|
<pre>{problematicConstraints}</pre> |
|
</div> |
|
</div> |
|
)} |
|
|
|
{generatedCode && ( |
|
<div className="code-section"> |
|
<h3>💻 Generated Code</h3> |
|
<div className="code-display"> |
|
<pre><code>{generatedCode}</code></pre> |
|
</div> |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
)} |
|
</section> |
|
</main> |
|
|
|
{/* Navigation */} |
|
<nav className="navigation"> |
|
<button |
|
onClick={prevStep} |
|
disabled={currentStep <= 1} |
|
className="btn btn-outline" |
|
> |
|
← Previous |
|
</button> |
|
<span className="step-indicator"> |
|
Step {currentStep} of 3 |
|
</span> |
|
<button |
|
onClick={nextStep} |
|
disabled={currentStep >= 3} |
|
className="btn btn-outline" |
|
> |
|
Next → |
|
</button> |
|
</nav> |
|
</> |
|
); |
|
} |
|
|
|
export default PredefinedPuzzlePage; |