drop dead solver and pdf code, fix reputation and truncation

This commit is contained in:
2026-08-23 17:51:46 +03:00
parent 093b27f3f4
commit aa70c61abd
3 changed files with 9 additions and 139 deletions
+8 -92
View File
@@ -122,7 +122,7 @@ pub fn to_pdf(puzzle: &Puzzle, title: &str, variant: &str) -> Vec<u8> {
c.push_str(&format!("BT /F2 6 Tf 0.6 0.55 0.5 rg {} {} Td (cruciverb) Tj ET\n", margin, margin - 10.0));
build_pdf_with_fonts(&c, pw, ph, bold_font.as_deref(), regular_font.as_deref())
build_pdf_clean(&c, pw, ph, regular_font.as_deref(), bold_font.as_deref())
}
fn esc(s: &str) -> String {
@@ -130,100 +130,16 @@ fn esc(s: &str) -> String {
}
fn truncate(s: &str, max: usize) -> String {
if s.len() <= max { s.to_string() } else { format!("{}...", &s[..max - 3]) }
if s.chars().count() <= max {
s.to_string()
} else {
let keep = max.saturating_sub(3);
let cut: String = s.chars().take(keep).collect();
format!("{}...", cut)
}
}
fn build_pdf_with_fonts(content: &str, pw: f64, ph: f64, bold_ttf: Option<&[u8]>, regular_ttf: Option<&[u8]>) -> Vec<u8> {
let mut pdf = Vec::new();
let mut offsets = Vec::new();
let mut obj_count = 0;
pdf.extend_from_slice(b"%PDF-1.4\n%\xe2\xe3\xcf\xd3\n");
macro_rules! obj {
($data:expr) => {{
obj_count += 1;
offsets.push(pdf.len());
pdf.extend_from_slice(format!("{} 0 obj\n", obj_count).as_bytes());
pdf.extend_from_slice($data);
pdf.extend_from_slice(b"\nendobj\n");
obj_count
}};
}
// obj 1: catalog
obj!(b"<< /Type /Catalog /Pages 2 0 R >>");
// obj 2: pages
obj!(b"<< /Type /Pages /Kids [3 0 R] /Count 1 >>");
// build font objects
let (f1_ref, f2_ref);
if let Some(reg_data) = regular_ttf {
// embedded TrueType font for F1 (regular/body)
let stream_id = {
obj_count += 1;
offsets.push(pdf.len());
pdf.extend_from_slice(format!("{} 0 obj\n", obj_count).as_bytes());
pdf.extend_from_slice(format!("<< /Length {} /Length1 {} >>\nstream\n", reg_data.len(), reg_data.len()).as_bytes());
pdf.extend_from_slice(reg_data);
pdf.extend_from_slice(b"\nendstream\nendobj\n");
obj_count
};
let desc_id = obj!(format!("<< /Type /FontDescriptor /FontName /DMSans /Flags 32 /FontFile2 {} 0 R /ItalicAngle 0 /Ascent 1000 /Descent -200 /CapHeight 700 /StemV 80 >>", stream_id).as_bytes());
f1_ref = obj!(format!("<< /Type /Font /Subtype /TrueType /BaseFont /DMSans /FirstChar 32 /LastChar 255 /Encoding /WinAnsiEncoding /FontDescriptor {} 0 R >>", desc_id).as_bytes());
} else {
f1_ref = obj!(b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica /Encoding /WinAnsiEncoding >>");
}
if let Some(bold_data) = bold_ttf {
let stream_id = {
obj_count += 1;
offsets.push(pdf.len());
pdf.extend_from_slice(format!("{} 0 obj\n", obj_count).as_bytes());
pdf.extend_from_slice(format!("<< /Length {} /Length1 {} >>\nstream\n", bold_data.len(), bold_data.len()).as_bytes());
pdf.extend_from_slice(bold_data);
pdf.extend_from_slice(b"\nendstream\nendobj\n");
obj_count
};
let desc_id = obj!(format!("<< /Type /FontDescriptor /FontName /PlayfairDisplay-Bold /Flags 32 /FontFile2 {} 0 R /ItalicAngle 0 /Ascent 1000 /Descent -200 /CapHeight 700 /StemV 120 >>", stream_id).as_bytes());
f2_ref = obj!(format!("<< /Type /Font /Subtype /TrueType /BaseFont /PlayfairDisplay-Bold /FirstChar 32 /LastChar 255 /Encoding /WinAnsiEncoding /FontDescriptor {} 0 R >>", desc_id).as_bytes());
} else {
f2_ref = obj!(b"<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding >>");
}
// obj: content stream
let content_id = {
obj_count += 1;
offsets.push(pdf.len());
pdf.extend_from_slice(format!("{} 0 obj\n", obj_count).as_bytes());
pdf.extend_from_slice(format!("<< /Length {} >>\nstream\n", content.len()).as_bytes());
pdf.extend_from_slice(content.as_bytes());
pdf.extend_from_slice(b"\nendstream\nendobj\n");
obj_count
};
// obj 3: page (deferred - write now)
let page_data = format!(
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 {} {}] /Contents {} 0 R /Resources << /Font << /F1 {} 0 R /F2 {} 0 R >> >> >>",
pw, ph, content_id, f1_ref, f2_ref
);
// we need to insert page as obj 3, but we already wrote objects 1,2 then font objects
// so obj 3 wasn't written yet. let's write it now
obj_count += 1;
offsets.push(pdf.len());
pdf.extend_from_slice(format!("{} 0 obj\n{}\nendobj\n", obj_count, page_data).as_bytes());
let _page_obj = obj_count;
// fix pages to reference our page object
// this is hacky but works - we'll just rebuild the whole thing properly
// actually let's just rebuild cleanly
drop(pdf);
drop(offsets);
build_pdf_clean(content, pw, ph, regular_ttf, bold_ttf)
}
fn build_pdf_clean(content: &str, pw: f64, ph: f64, regular_ttf: Option<&[u8]>, bold_ttf: Option<&[u8]>) -> Vec<u8> {
// collect all objects first, then serialize
-46
View File
@@ -1,49 +1,3 @@
use crate::dict::Dictionary;
pub fn score_candidate(
word_idx: usize,
dict: &Dictionary,
used_words: &[bool],
placed_texts: &[String],
) -> f64 {
if used_words[word_idx] {
return -1.0;
}
let word = dict.get(word_idx);
let text = &word.text;
let mut score = word.frequency;
// reject words that are too similar to already-placed words
for placed in placed_texts {
if is_related(text, placed) {
return -1.0;
}
}
// bonus for letter variety
let bytes = text.as_bytes();
let mut seen = [false; 26];
let mut unique = 0;
for &b in bytes {
let idx = (b - b'A') as usize;
if !seen[idx] {
seen[idx] = true;
unique += 1;
}
}
let variety = unique as f64 / bytes.len() as f64;
score += variety * 0.1;
// bonus for common letters
let common = b"ETAOINSHRDLU";
let common_count = bytes.iter().filter(|b| common.contains(b)).count();
let common_ratio = common_count as f64 / bytes.len() as f64;
score += common_ratio * 0.05;
score
}
pub fn is_related(a: &str, b: &str) -> bool {
// one is a prefix of the other (SEAL / SEALS, RUN / RUNNING)
if a.len() >= 3 && b.len() >= 3 {
+1 -1
View File
@@ -890,7 +890,7 @@ async fn handle_leaderboard(state: &Arc<AppState>, activity: &serde_json::Value,
// check instance reputation
let reputation: f64 = dbi.db.query_row(
"SELECT reputation FROM ap_instance_reputation WHERE domain = ?1",
"SELECT score FROM ap_instance_reputation WHERE domain = ?1",
[origin], |row| row.get(0),
).unwrap_or(100.0);
if reputation < 30.0 {