-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
use dafny_runtime;
use fenwick::_module::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 sum = 0;
for (i, w) in stmt.query_map([], |row| row.get::<_, i32>(0))?.enumerate() {
let w = w?;
a[i + 1] = w;
sum += w;
}
// Example for how to use Dafny-generated Rust:
// https://github.com/dafny-lang/dafny/blob/7bf2d6ad221df94c4a291b58e97a701da441dce0/Source/IntegrationTests/TestFiles/LitTests/LitTest/comp/rust/arc/tokiouser-rust/src/main.rs
let obj = fenwick::_allocate_object();
let seq = a[1..=n]
.into_iter()
.map(|x| dafny_runtime::DafnyInt::from_i32(x.clone()))
.collect();
fenwick::_ctor(&obj, &seq);
let ft = dafny_runtime::rd!(obj);
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);
// ft is 0-indexed so we need to add 1
// Not sure why there's only as_usize() and not as_i32()
let i = ft.search(&dafny_runtime::DafnyInt::from_i32(s)).as_usize() + 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()?;
}
// 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 {
// Skip newline
io::stdin().read_exact(&mut buf)?;
}
stmt.query_row(params![i], |row| {
println!("{}", row.get::<_, String>(1)?);
Ok(())
})?;
if backend {
io::stdout().flush()?;
}
// Read user input
io::stdin().read_exact(&mut buf)?;
let b = buf[0] as char;
if backend {
// Skip newline
io::stdin().read_exact(&mut buf)?;
}
let w = match b {
'y' => a[i] >> 1,
'n' => a[i] << 3,
_ => break,
};
// Update Fenwick tree and database
ft.update(
&dafny_runtime::DafnyInt::from_usize(i),
&dafny_runtime::DafnyInt::from_i32(w - a[i]),
);
sum += w - a[i];
a[i] = w;
conn.execute("UPDATE cards SET weight=? WHERE idx=?", params![w, i])?;
}
Ok(())
}