Skip to content

Commit 4b80c1a

Browse files
scoring
1 parent 78b0bfe commit 4b80c1a

File tree

8 files changed

+7788
-20
lines changed

8 files changed

+7788
-20
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ leptos = { version = "0.6.9", features = ["csr", "nightly"] }
1111
stylance = "0.3.0"
1212
rand = "0.9.0-alpha.1"
1313
chrono = "0.4.37"
14+
lazy_static = "1.4.0"
1415

1516
[package.metadata.stylance]
1617

src/letter_gen.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ impl Generator for LetterGenerator {
7676
fn next_n_letters(&mut self, n: usize) -> Vec<char>{
7777
return self.chars[self.seq..std::cmp::min(self.seq + n, self.chars.len())].to_vec()
7878
}
79+
80+
fn calc_score(&self, calc_score: fn(&Vec<&str>) -> u32) -> u32 {
81+
return calc_score(&self.words)
82+
}
7983
}
8084

8185

@@ -103,10 +107,16 @@ impl Generator for TestGenerator {
103107
let substring = &TEST_LETTERS[self.idx..std::cmp::min(self.idx + n, TEST_LETTERS.len())];
104108
substring.chars().collect()
105109
}
110+
111+
fn calc_score(&self, calc_score: fn(&Vec<&str>) -> u32) -> u32 {
112+
return calc_score(&vec![TEST_LETTERS])
113+
}
106114
}
107115

108116
pub trait Generator {
109117
fn next_letter(&mut self) -> Option<char>;
110118

111119
fn next_n_letters(&mut self, n: usize) -> Vec<char>;
120+
121+
fn calc_score(&self, calc_score: fn(&Vec<&str>) -> u32) -> u32;
112122
}

src/main.rs

Lines changed: 71 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,28 @@ use rand::{random, Rng};
33
mod header;
44
mod trie;
55
mod words;
6+
mod scoring;
67

78
use leptos::*;
89
use stylance::import_crate_style;
910
use leptos::logging::log;
1011
use core::time::Duration;
1112
use crate::letter_gen::{Generator, LetterGenerator, TestGenerator, MIN_WORD_SIZE};
13+
use crate::scoring::get_score_single;
1214
use crate::trie::TrieNode;
1315
use crate::words::WORDS;
1416

1517
import_crate_style!(styles, "./src/styles.module.scss");
1618

1719
// NB: The width variable exists separately in scss as well.
1820
const GRID_WIDTH: usize = 9;
19-
const GRID_HEIGHT: usize = 11;
21+
const GRID_HEIGHT: usize = 9;
2022
const GRID_SIZE: usize =GRID_WIDTH * GRID_HEIGHT;
2123

2224
const LOOKAHEAD: usize = 3;
2325

26+
const LAST_WORDS_WINDOW: usize= 3;
27+
2428
const EMPTY: char = ' ';
2529

2630
const TICK: u64 = 1;
@@ -74,22 +78,38 @@ fn make_trie() -> TrieNode {
7478
t
7579
}
7680

81+
#[derive(Clone)]
82+
struct WordWithKey {
83+
word: &'static str,
84+
key: u64,
85+
}
86+
87+
fn make_word_with_key(word: &'static str) -> WordWithKey {
88+
return WordWithKey{
89+
word,
90+
key: random(),
91+
}
92+
}
93+
7794
#[component]
7895
fn App() -> impl IntoView {
7996
let (gen, set_gen) = create_signal(TestGenerator::new());
8097
let (grid, set_grid) = create_signal(make_block_vec(set_gen));
8198
let (current, set_current) = create_signal(GRID_WIDTH / 2);
8299
let (checking, set_checking) = create_signal(false);
83100
let (t, _) = create_signal(make_trie());
84-
let (next_letters, set_next_letters) = create_signal(vec![]);
101+
let (game_meta_text, set_game_meta_text) = create_signal(vec![]);
102+
let (score, set_score) = create_signal(0);
103+
let (last_words, set_last_words) = create_signal(vec![]);
85104

105+
// Set next letters.
86106
create_effect(move |_| {
87107
set_gen.update(|g| {
88-
set_next_letters.update(|nl| *nl = g.next_n_letters(LOOKAHEAD))
108+
set_game_meta_text.update(|nl| *nl = g.next_n_letters(LOOKAHEAD))
89109
});
90110
});
91111

92-
let spawn = move || {
112+
let spawn = move || {
93113
if grid.get()[GRID_WIDTH/2].val.get() != EMPTY {
94114
// TODO: handle user lost the game condition
95115
panic!("TODO: lost")
@@ -103,7 +123,7 @@ fn App() -> impl IntoView {
103123
panic!("TODO: you won")
104124
}
105125
*val = next.unwrap();
106-
set_next_letters.update(|nl| *nl = g.next_n_letters(LOOKAHEAD));
126+
set_game_meta_text.update(|nl| *nl = g.next_n_letters(LOOKAHEAD));
107127
})
108128
});
109129
});
@@ -177,10 +197,11 @@ fn App() -> impl IntoView {
177197
}
178198
match dir {
179199
0 => {
180-
j -= GRID_WIDTH;
181-
if j < 0 {
200+
201+
if j-GRID_WIDTH < 0 {
182202
break
183203
}
204+
j -= GRID_WIDTH;
184205
},
185206
1 => {
186207
if (j+1) % GRID_WIDTH < j % GRID_WIDTH {
@@ -207,6 +228,8 @@ fn App() -> impl IntoView {
207228
}
208229
}
209230
log!("{:?}", words);
231+
232+
let found_words = words.len() > 0;
210233
let idx_final_iter = &indexes_final;
211234
for word_idx_arr in idx_final_iter {
212235
for idx in word_idx_arr {
@@ -218,7 +241,13 @@ fn App() -> impl IntoView {
218241
}
219242
}
220243
let idx_final_clone = indexes_final.clone();
244+
let words_clone = words.clone();
245+
if !found_words {
246+
set_checking(false);
247+
return
248+
}
221249
set_timeout(move || {
250+
// Update grid. TODO: slide letters down.
222251
for word_idx_arr in idx_final_clone {
223252
for idx in word_idx_arr {
224253
grid.with(|blocks: &Vec<BlockState>| {
@@ -227,13 +256,25 @@ fn App() -> impl IntoView {
227256
});
228257
}
229258
}
230-
}, Duration::from_millis(500));
231-
259+
// Set last words.
260+
for word in words_clone {
261+
set_last_words.update(|last_words| {
262+
last_words.insert(0, make_word_with_key(word));
263+
if last_words.len() > LAST_WORDS_WINDOW {
264+
last_words.pop();
265+
}
266+
});
267+
set_score.update(|score| {
268+
*score = *score + get_score_single(word)
269+
});
270+
}
232271

272+
set_checking(false);
273+
}, Duration::from_millis(500));
233274
});
234275
});
235276

236-
set_checking(false);
277+
237278
};
238279

239280
let handle_key_press = move |code: &str| {
@@ -287,9 +328,6 @@ fn App() -> impl IntoView {
287328
</div>
288329
</For>
289330
</div>
290-
<div>
291-
<p class=styles::next_letters>"Up Next: "{move || next_letters.get().iter().map(|&c| c.to_string()).collect::<Vec<_>>().join(", ")}</p>
292-
</div>
293331
<div class=styles::arrow_container>
294332
<button class=styles::arrow_button
295333
on:mouseup=move |_| { handle_key_press(KEY_A); }
@@ -308,6 +346,26 @@ fn App() -> impl IntoView {
308346
on:touchend=move |ev| {ev.prevent_default(); handle_key_press(KEY_D); }
309347
> "➡️"</button>
310348
</div>
349+
<div>
350+
<p class=styles::game_meta_text>"Up Next: "{move || game_meta_text.get().iter().map(|&c| c.to_string())
351+
.collect::<Vec<_>>().join(", ")}</p>
352+
</div>
353+
<div>
354+
<p class=styles::game_meta_text>"Score: "{move || score.get()}</p>
355+
</div>
356+
<div>
357+
<p class=styles::game_meta_text>{"Previous Words:"}</p>
358+
<div class=styles::last_words_indent>
359+
<For
360+
each=last_words
361+
key=|word_with_key| word_with_key.key.clone()
362+
let: wwk
363+
>
364+
<p class=styles::game_meta_text>{format!("{} - {}", wwk.word, get_score_single(wwk.word))}</p>
365+
</For>
366+
</div>
367+
</div>
368+
311369
</div>
312370
}
313371
}

src/scoring.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
use std::collections::HashMap;
2+
use lazy_static::lazy_static;
3+
4+
lazy_static! {
5+
static ref SCRABBLE_POINTS: HashMap<char, u32> = {
6+
let mut map = HashMap::new();
7+
map.insert('A', 1);
8+
map.insert('E', 1);
9+
map.insert('I', 1);
10+
map.insert('O', 1);
11+
map.insert('U', 1);
12+
map.insert('L', 1);
13+
map.insert('N', 1);
14+
map.insert('S', 1);
15+
map.insert('T', 1);
16+
map.insert('R', 1);
17+
map.insert('D', 2);
18+
map.insert('G', 2);
19+
map.insert('B', 3);
20+
map.insert('C', 3);
21+
map.insert('M', 3);
22+
map.insert('P', 3);
23+
map.insert('F', 4);
24+
map.insert('H', 4);
25+
map.insert('V', 4);
26+
map.insert('W', 4);
27+
map.insert('Y', 4);
28+
map.insert('K', 5);
29+
map.insert('J', 8);
30+
map.insert('X', 8);
31+
map.insert('Q', 10);
32+
map.insert('Z', 10);
33+
map
34+
};
35+
}
36+
37+
pub fn get_score_single(word: &str) -> u32 {
38+
let mut sc = 0;
39+
for c in word.chars() {
40+
sc += SCRABBLE_POINTS.get(&c).unwrap()
41+
}
42+
return sc
43+
}

src/styles.module.scss

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ body {
1010

1111
// HEADER
1212
.header {
13-
margin: 1% auto;
13+
margin: 4% auto 2%;
1414
width: 15%;
1515
text-align: center;
1616
font-family: Arial, Helvetica, sans-serif;
17+
font-size: 1.5em;
1718
}
1819

1920
// GRID
@@ -39,11 +40,15 @@ body {
3940
font-family: Arial, Helvetica, sans-serif;
4041
}
4142

42-
// NEXT LETTERS
43-
.next_letters {
43+
// NEXT LETTERS, SCORING, PAST WORDS
44+
.game_meta_text {
4445
font-family: Arial, Helvetica, sans-serif;
4546
}
4647

48+
.last_words_indent {
49+
margin-left: 5%;
50+
}
51+
4752
// ARROWS
4853
.arrow-container {
4954
margin-top: 10px;

src/words.rs

Lines changed: 7646 additions & 1 deletion
Large diffs are not rendered by default.

styles/bundled.scss

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ body {
1010

1111
// HEADER
1212
.header-94e563a {
13-
margin: 1% auto;
13+
margin: 4% auto 2%;
1414
width: 15%;
1515
text-align: center;
1616
font-family: Arial, Helvetica, sans-serif;
17+
font-size: 1.5em;
1718
}
1819

1920
// GRID
@@ -39,11 +40,15 @@ body {
3940
font-family: Arial, Helvetica, sans-serif;
4041
}
4142

42-
// NEXT LETTERS
43-
.next_letters-94e563a {
43+
// NEXT LETTERS, SCORING, PAST WORDS
44+
.game_meta_text-94e563a {
4445
font-family: Arial, Helvetica, sans-serif;
4546
}
4647

48+
.last_words_indent-94e563a {
49+
margin-left: 5%;
50+
}
51+
4752
// ARROWS
4853
.arrow-container-94e563a {
4954
margin-top: 10px;

0 commit comments

Comments
 (0)