Changes
5 changed files (+432/-0)
-
.gitignore (new)
-
@@ -0,0 +1,1 @@/target
-
-
Cargo.lock (new)
-
@@ -0,0 +1,243 @@# This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 4 [[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", "version_check", "zerocopy", ] [[package]] name = "bitflags" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1be3f42a67d6d345ecd59f675f3f012d6974981560836e938c22b424b85ce1be" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "fallible-iterator" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] [[package]] name = "hashlink" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown", ] [[package]] name = "libc" version = "0.2.169" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" [[package]] name = "libsqlite3-sys" version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" dependencies = [ "pkg-config", "vcpkg", ] [[package]] name = "once_cell" version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "pkg-config" version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "ppv-lite86" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ "zerocopy", ] [[package]] name = "proc-macro2" version = "1.0.93" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" dependencies = [ "unicode-ident", ] [[package]] name = "quote" version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rusqlite" version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" dependencies = [ "bitflags", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", "smallvec", ] [[package]] name = "sdrs" version = "0.1.0" dependencies = [ "rand", "rusqlite", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "syn" version = "2.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "unicode-ident" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", "syn", ]
-
-
Cargo.toml (new)
-
@@ -0,0 +1,8 @@[package] name = "sdrs" version = "0.1.0" edition = "2021" [dependencies] rand = "0.8.5" rusqlite = "0.32.1"
-
-
src/fenwick.rs (new)
-
@@ -0,0 +1,49 @@// https://git.unnamed.website/sdc/plain/fenwick.c // Convert Vec into Fenwick tree pub fn build(f: &mut Vec<i32>) { for i in 1..f.len() { // -i doesn't work since i is unsigned let j = i + (i & i.wrapping_neg()); if j < f.len() { f[j] += f[i]; } } } // Add value to index i pub fn update(f: &mut Vec<i32>, mut i: usize, v: i32) { while i < f.len() { f[i as usize] += v; i += i & i.wrapping_neg(); } } // Query for prefix sum at index i pub fn query(f: &[i32], mut i: usize) -> i32 { let mut ret = 0; while i > 0 { ret += f[i]; i -= i & i.wrapping_neg(); } ret } // Query for sum between indices i and j inclusive pub fn range_query(f: &[i32], i: usize, j: usize) -> i32 { query(f, j) - query(f, i - 1) } // Search for largest index with prefix sum less than or equal to s pub fn search(f: &[i32], mut s: i32) -> usize { let mut j = 0; let mut step = 1 << (usize::BITS - (f.len() - 1).leading_zeros() - 1); while step > 0 { if j + step < f.len() && f[j + step] <= s { s -= f[j + step]; j += step; } step >>= 1; } j }
-
-
src/main.rs (new)
-
@@ -0,0 +1,131 @@mod fenwick; use rand::Rng; use rusqlite::{params, Connection, Result}; use std::env; use std::error::Error; use std::io::{self, Read, Write}; use std::process::Command; fn main() -> Result<(), Box<dyn Error>> { let mut file = "cards".to_string(); let mut verbose = false; let mut backend = false; // Process args let args: Vec<String> = env::args().collect(); for arg in &args[1..] { match arg.as_str() { "-v" => verbose = true, "-b" => backend = true, _ => file = arg.clone(), } } // Connect to db let conn = Connection::open(file)?; // Get number of cards let mut stmt = conn.prepare("SELECT COUNT(*) FROM cards")?; let n: usize = stmt.query_row([], |row| row.get(0))?; // Get card weights let mut stmt = conn.prepare("SELECT weight FROM cards")?; let mut a = vec![0; n + 1]; let mut f = vec![0; n + 1]; let mut sum = 0; for (i, w) in stmt.query_map([], |row| row.get::<_, i32>(0))?.enumerate() { let w = w?; a[i + 1] = w; f[i + 1] = w; sum += w; } fenwick::build(&mut f); if verbose { println!("{:?}", &a[1..=n]); } if !backend { Command::new("stty") .arg("-F") .arg("/dev/tty") .arg("cbreak") .arg("min") .arg("1") .status() .expect("Failed to disable input buffering"); Command::new("stty") .arg("-F") .arg("/dev/tty") .arg("-echo") .status() .expect("Failed to disable echo"); } loop { assert!(sum > 0); let s = rand::thread_rng().gen_range(0..sum); let i = fenwick::search(&f, s) + 1; if verbose { println!("{} {} {} {}", sum, s, i, a[i]); } // Get card contents from database let mut stmt = conn.prepare("SELECT key, val FROM cards WHERE idx=?")?; stmt.query_row(params![i], |row| { println!("> {}", row.get::<_, String>(0)?); Ok(()) })?; if backend { io::stdout().flush().unwrap(); } // Wait for confirmation let mut buf = [0; 1]; io::stdin().read_exact(&mut buf)?; let b = buf[0] as char; if b == 'q' { break; } if backend { io::stdin().read_exact(&mut buf)?; // Skip newline } stmt.query_row(params![i], |row| { println!("{}", row.get::<_, String>(1)?); Ok(()) })?; if backend { io::stdout().flush().unwrap(); } // Read user input io::stdin().read_exact(&mut buf)?; let b = buf[0] as char; if backend { io::stdin().read_exact(&mut buf)?; // Skip newline } let w = match b { 'y' => a[i] >> 1, 'n' => a[i] << 3, _ => break, }; // Update Fenwick tree and database fenwick::update(&mut f, i, w - a[i]); sum += w - a[i]; a[i] = w; conn.execute("UPDATE cards SET weight=? WHERE idx=?", params![w, i])?; } Ok(()) }
-