1
1
import { invalid } from '@sveltejs/kit' ;
2
- import { Game } from './game ' ;
2
+ import { words , allowed } from './words.server ' ;
3
3
import type { PageServerLoad , Actions } from './$types' ;
4
4
5
5
/** @type {import('./$types').PageServerLoad } */
6
- export const load : PageServerLoad = ( { cookies } ) => {
6
+ export const load = ( ( { cookies } ) => {
7
7
const game = new Game ( cookies . get ( 'sverdle' ) ) ;
8
8
9
9
return {
@@ -23,10 +23,10 @@ export const load: PageServerLoad = ({ cookies }) => {
23
23
*/
24
24
answer : game . answers . length >= 6 ? game . answer : null
25
25
} ;
26
- } ;
26
+ } ) satisfies PageServerLoad ;
27
27
28
28
/** @type {import('./$types').Actions } */
29
- export const actions : Actions = {
29
+ export const actions = {
30
30
/**
31
31
* Modify game state in reaction to a keypress. If client-side JavaScript
32
32
* is available, this will happen in the browser instead of here
@@ -68,4 +68,80 @@ export const actions: Actions = {
68
68
restart : async ( { cookies } ) => {
69
69
cookies . delete ( 'sverdle' ) ;
70
70
}
71
- } ;
71
+ } satisfies Actions ;
72
+
73
+ class Game {
74
+ index : number ;
75
+ guesses : string [ ] ;
76
+ answers : string [ ] ;
77
+ answer : string ;
78
+
79
+ /**
80
+ * Create a game object from the player's cookie, or initialise a new game
81
+ * @param {string | undefined } serialized
82
+ */
83
+ constructor ( serialized : string | undefined ) {
84
+ if ( serialized ) {
85
+ const [ index , guesses , answers ] = serialized . split ( '-' ) ;
86
+
87
+ this . index = + index ;
88
+ this . guesses = guesses ? guesses . split ( ' ' ) : [ ] ;
89
+ this . answers = answers ? answers . split ( ' ' ) : [ ] ;
90
+ } else {
91
+ this . index = Math . floor ( Math . random ( ) * words . length ) ;
92
+ this . guesses = [ '' , '' , '' , '' , '' , '' ] ;
93
+ this . answers = /** @type {string[] } */ [ ] /***/ ;
94
+ }
95
+
96
+ this . answer = words [ this . index ] ;
97
+ }
98
+
99
+ /**
100
+ * Update game state based on a guess of a five-letter word. Returns
101
+ * true if the guess was valid, false otherwise
102
+ * @param {string[] } letters
103
+ */
104
+ enter ( letters : string [ ] ) {
105
+ const word = letters . join ( '' ) ;
106
+ const valid = allowed . has ( word ) ;
107
+
108
+ if ( ! valid ) return false ;
109
+
110
+ this . guesses [ this . answers . length ] = word ;
111
+
112
+ const available = Array . from ( this . answer ) ;
113
+ const answer = Array ( 5 ) . fill ( '_' ) ;
114
+
115
+ // first, find exact matches
116
+ for ( let i = 0 ; i < 5 ; i += 1 ) {
117
+ if ( letters [ i ] === available [ i ] ) {
118
+ answer [ i ] = 'x' ;
119
+ available [ i ] = ' ' ;
120
+ }
121
+ }
122
+
123
+ // then find close matches (this has to happen
124
+ // in a second step, otherwise an early close
125
+ // match can prevent a later exact match)
126
+ for ( let i = 0 ; i < 5 ; i += 1 ) {
127
+ if ( answer [ i ] === '_' ) {
128
+ const index = available . indexOf ( letters [ i ] ) ;
129
+ if ( index !== - 1 ) {
130
+ answer [ i ] = 'c' ;
131
+ available [ index ] = ' ' ;
132
+ }
133
+ }
134
+ }
135
+
136
+ this . answers . push ( answer . join ( '' ) ) ;
137
+
138
+ return true ;
139
+ }
140
+
141
+ /**
142
+ * Serialize game state so it can be set as a cookie
143
+ */
144
+ toString ( ) {
145
+ return `${ this . index } -${ this . guesses . join ( ' ' ) } -${ this . answers . join ( ' ' ) } ` ;
146
+ }
147
+ }
0 commit comments