1- import { useState } from "react" ;
1+ import { useEffect , useState } from "react" ;
22import { Link , useNavigate } from "react-router-dom" ;
33import { PieceType } from "../engine/board" ;
44import { useGame } from "../GameContext" ;
@@ -12,10 +12,14 @@ export function NewGameScreen() {
1212 const [ whiteName , setWhiteName ] = useState < string > ( activeProfile ?. name ?? "" ) ;
1313 const [ blackName , setBlackName ] = useState < string > ( "" ) ;
1414 // Portal Chess sub-options
15- const [ portalCreator , setPortalCreator ] = useState < PieceType > ( "N" ) ;
16- const [ portalOpponentKind , setPortalOpponentKind ] = useState < "two-player" | "bot" > ( "bot" ) ;
17- const [ portalAdjacencyRule , setPortalAdjacencyRule ] = useState < boolean > ( false ) ;
18- const [ portalMax , setPortalMax ] = useState < 1 | 2 | 3 > ( 1 ) ;
15+ const [ portalCreator , setPortalCreator ] = useState < PieceType > ( store . settings . portalCreatorDefault ) ;
16+ const [ portalOpponentKind , setPortalOpponentKind ] = useState < "two-player" | "bot" > ( store . settings . portalOpponentDefault ) ;
17+ const [ portalMax , setPortalMax ] = useState < 1 | 2 | 3 > ( store . settings . portalMaxDefault ) ;
18+ const maxLevel = kind === "bot" ? 20 : 10 ;
19+
20+ useEffect ( ( ) => {
21+ if ( level > maxLevel ) setLevel ( maxLevel ) ;
22+ } , [ level , maxLevel ] ) ;
1923
2024 const ensureProfile = ( name : string ) : string => {
2125 const trimmed = name . trim ( ) ;
@@ -30,6 +34,9 @@ export function NewGameScreen() {
3034
3135 const start = ( ) => {
3236 updateSetting ( "timerSeconds" , timer ) ;
37+ updateSetting ( "portalCreatorDefault" , portalCreator ) ;
38+ updateSetting ( "portalOpponentDefault" , portalOpponentKind ) ;
39+ updateSetting ( "portalMaxDefault" , portalMax ) ;
3340
3441 // Ensure white profile exists and is active — stats are tied to this name
3542 const w = ensureProfile ( whiteName || "Player 1" ) ;
@@ -46,12 +53,12 @@ export function NewGameScreen() {
4653 if ( portalOpponentKind === "two-player" ) {
4754 const b = ensureProfile ( blackName || "Player 2" ) ;
4855 newGame (
49- { kind : "portal" , opponent : "two-player" , creator : portalCreator , adjacencyRule : portalAdjacencyRule , portalMax } ,
56+ { kind : "portal" , opponent : "two-player" , creator : portalCreator , portalMax } ,
5057 { w, b }
5158 ) ;
5259 } else {
5360 newGame (
54- { kind : "portal" , opponent : { kind : "bot" , level } , creator : portalCreator , adjacencyRule : portalAdjacencyRule , portalMax } ,
61+ { kind : "portal" , opponent : { kind : "bot" , level } , creator : portalCreator , portalMax } ,
5562 { w, b : `Bot Lv ${ level } ` }
5663 ) ;
5764 }
@@ -138,20 +145,6 @@ export function NewGameScreen() {
138145 </ p >
139146 </ section >
140147
141- < section >
142- < h3 > House rules</ h3 >
143- < label >
144- < input type = "checkbox"
145- checked = { portalAdjacencyRule }
146- onChange = { ( e ) => setPortalAdjacencyRule ( e . target . checked ) } />
147- { " " } Prevent teleport next to any piece
148- </ label >
149- < p className = "hint" >
150- When ticked, teleport targets cannot be adjacent to any other piece.
151- When unticked (default), you can teleport anywhere empty — or stay
152- on the portal square (the portal remains active).
153- </ p >
154- </ section >
155148 </ >
156149 ) }
157150
@@ -203,17 +196,48 @@ export function NewGameScreen() {
203196 { showLevel && (
204197 < section >
205198 < h3 > Bot difficulty</ h3 >
206- < div className = "difficulty" >
207- { Array . from ( { length : 10 } , ( _ , i ) => i + 1 ) . map ( ( lv ) => (
208- < button
209- key = { lv }
210- className = { lv === level ? "pill active" : "pill" }
211- onClick = { ( ) => setLevel ( lv ) }
212- > { lv } </ button >
213- ) ) }
214- </ div >
199+ { kind === "bot" ? (
200+ < div className = "bot-level-groups" >
201+ < div className = "bot-level-group" >
202+ < div className = "bot-level-label" > Learn</ div >
203+ < div className = "bot-level-grid learn-grid" >
204+ { Array . from ( { length : 5 } , ( _ , i ) => i + 1 ) . map ( ( lv ) => (
205+ < button
206+ key = { lv }
207+ className = { lv === level ? "pill active" : "pill" }
208+ onClick = { ( ) => setLevel ( lv ) }
209+ > { lv } </ button >
210+ ) ) }
211+ </ div >
212+ </ div >
213+ < div className = "bot-level-group" >
214+ < div className = "bot-level-label" > Challenge</ div >
215+ < div className = "bot-level-grid challenge-grid" >
216+ { Array . from ( { length : 15 } , ( _ , i ) => i + 6 ) . map ( ( lv ) => (
217+ < button
218+ key = { lv }
219+ className = { lv === level ? "pill active" : "pill" }
220+ onClick = { ( ) => setLevel ( lv ) }
221+ > { lv } </ button >
222+ ) ) }
223+ </ div >
224+ </ div >
225+ </ div >
226+ ) : (
227+ < div className = "difficulty" >
228+ { Array . from ( { length : maxLevel } , ( _ , i ) => i + 1 ) . map ( ( lv ) => (
229+ < button
230+ key = { lv }
231+ className = { lv === level ? "pill active" : "pill" }
232+ onClick = { ( ) => setLevel ( lv ) }
233+ > { lv } </ button >
234+ ) ) }
235+ </ div >
236+ ) }
215237 < p className = "hint" >
216- Level 1 is very easy (good for a new learner). Levels 6+ use a stronger engine when available.
238+ { kind === "bot"
239+ ? "Learn levels 1-5 use the local bot and are tuned for practice. Challenge levels 6-20 use Stockfish when online, with local fallback offline."
240+ : "Portal-bot mode uses the in-house engine and supports levels 1-10." }
217241 </ p >
218242 </ section >
219243 ) }
0 commit comments