-
-
Save rust-play/8d0504c0ffbfe198b0107e49e814315b to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Hanoi C/C++ https://ideone.com/iPWHR0 | |
tcltk https://peterlane.codeberg.page/rstk/ | |
rstk needs tcltk >= 8.5 | |
*NOT USE* ActiveTcl | |
download tcltk 20221209 8.6.13 https://www.magicsplat.com/tcl-installer/ | |
( set path ) | |
[dependencies] | |
tokio = { version = "1.12.0", features = ["full"] } | |
async-recursion = "1.0.4" | |
lazy_static = "1.4.0" | |
rstk = "0.1.0" | |
*/ | |
#![allow(unused)] | |
#[macro_use] | |
extern crate lazy_static; | |
mod hanoi { | |
use async_recursion::async_recursion; | |
use std::error::Error; | |
use std::collections::BTreeMap; | |
use std::collections::VecDeque; | |
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | |
pub const PEGS_STACK_MAX: u8 = 15; | |
pub const PEGS_MAX: u8 = 3; | |
lazy_static! { | |
pub static ref PEGS_MUT: RwLock<BTreeMap<u8, Vec<u8>>> = | |
RwLock::new((0..PEGS_MAX).map(|i| | |
(Hanoi::key(i), Vec::with_capacity(PEGS_STACK_MAX as usize))).collect()); | |
pub static ref DEQ_MUT: RwLock<VecDeque<HanoiMove>> = | |
RwLock::new(VecDeque::new()); | |
} | |
pub struct HanoiMove { | |
src: u8, | |
dst: u8 | |
} | |
pub struct Hanoi { | |
src: u8, | |
dst: u8, | |
work: u8, | |
discs: u8 | |
} | |
impl Hanoi { | |
pub fn key(i: u8) -> u8 { b'A' + i } | |
pub fn num(k: u8) -> u8 { k - b'A' } | |
pub fn init(discs: u8, src: u8, dst: u8) -> Result<Self, Box<dyn Error>> { | |
let mut pegs = PEGS_MUT.write().map_err(|e| e.to_string())?; | |
let npegs = pegs.len() as u8; | |
if discs > PEGS_STACK_MAX || src >= npegs || dst >= npegs || src == dst { | |
return Err(Box::<dyn Error>::from("illegal parameter")); | |
} | |
let k = Hanoi::key(src); | |
let v = pegs.get_mut(&k).ok_or("no key")?; | |
for i in (1..=discs).rev() { v.push((i & 0x0ff) as u8); } | |
drop(pegs); | |
Ok(Hanoi::create(src, dst, npegs - (src + dst), discs)) | |
} | |
pub fn create(src: u8, dst: u8, work: u8, discs: u8) -> Hanoi { | |
Hanoi{src: src, dst: dst, work: work, discs: discs} | |
} | |
pub fn stat(&self, cb: &dyn Fn(&RwLockReadGuard<'_, BTreeMap<u8, Vec<u8>>>) -> ()) -> Result<(), Box<dyn Error>> { | |
let pegs = PEGS_MUT.read().map_err(|e| e.to_string())?; | |
println!("Pegs"); | |
for k in pegs.keys() { | |
println!(" {}: {:?}", *k as char, pegs[k]); | |
} | |
cb(&pegs); | |
drop(pegs); | |
Ok(()) | |
} | |
pub fn walk(&self) -> Result<(), Box<dyn Error>> { | |
let mut deq = DEQ_MUT.write().map_err(|e| e.to_string())?; | |
let mv = deq.pop_front().unwrap_or_else(|| HanoiMove{src: 0, dst: 0}); | |
drop(deq); | |
if mv.src == 0 && mv.dst == 0 { return Err(Box::<dyn Error>::from("end")); } | |
let s = Hanoi::key(mv.src); | |
let d = Hanoi::key(mv.dst); | |
let mut pegs = PEGS_MUT.write().map_err(|e| e.to_string())?; | |
let w = pegs.get_mut(&s).ok_or("src no key")?; | |
let u = w.pop().ok_or("src empty")?; // mut access pegs[&s] before pegs[&d] | |
let v = pegs.get_mut(&d).ok_or("dst no key")?; | |
v.push(u); | |
drop(pegs); | |
Ok(()) | |
} | |
pub fn mv(&self, src: u8, dst: u8) -> Result<(), Box<dyn Error>> { | |
let mut deq = DEQ_MUT.write().map_err(|e| e.to_string())?; | |
deq.push_back(HanoiMove{src: src, dst: dst}); | |
drop(deq); | |
Ok(()) | |
} | |
pub async fn _hanoi(&self) -> Result<Hanoi, Box<dyn Error>> { | |
Ok(self.hanoi(self.src, self.dst, self.work, self.discs).await?) | |
} | |
#[async_recursion(?Send)] | |
pub async fn hanoi(&self, src: u8, dst: u8, work: u8, discs: u8) -> Result<Hanoi, Box<dyn Error>> { | |
if discs == 0 { return Ok(Hanoi::create(src, dst, work, discs)); } | |
let mut m = self.hanoi(src, work, dst, discs - 1).await?; | |
if m.discs != 0 { self.mv(m.src, m.dst)?; } | |
self.mv(src, dst)?; | |
let mut m = self.hanoi(work, dst, src, discs - 1).await?; | |
if m.discs != 0 { self.mv(m.src, m.dst)?; } | |
Ok(Hanoi::create(0, 0, 0, 0)) // discs = 0 for stop recursion | |
} | |
} // Impl Hanoi | |
} // mod hanoi | |
use hanoi::{Hanoi}; | |
use std::error::Error; | |
use std::collections::BTreeMap; | |
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; | |
use timer::Timer; | |
use chrono::{Utc, Local, DateTime, NaiveDateTime, Duration}; | |
use chrono::{NaiveDate, NaiveTime}; | |
use chrono::{offset::{FixedOffset, TimeZone}}; | |
use rstk::*; | |
lazy_static! { | |
pub static ref GUARD_MUT: RwLock<Vec<timer::Guard>> = | |
RwLock::new(Vec::new()); | |
} | |
fn stop_schedule() { | |
let mut _guard = GUARD_MUT.write().map_err(|e| e.to_string()).unwrap(); | |
if _guard.len() > 0 { | |
drop(&_guard[0]); | |
_guard.pop(); | |
} | |
drop(_guard); | |
} | |
pub struct TblPwLbl { | |
p: Vec<Vec<TkPanedWindow>>, | |
l: Vec<Vec<TkLabel>> | |
} | |
impl TblPwLbl { | |
pub fn hw(&self) -> (usize, usize) { | |
(self.p.len(), self.p[0].len()) | |
} | |
pub fn pl(&self, j: usize, i: usize) -> (&TkPanedWindow, &TkLabel) { | |
(&self.p[j][i], &self.l[j][i]) | |
} | |
} | |
lazy_static! { | |
pub static ref FGC: Vec<&'static str> = vec![ | |
"#996633", "#ffcc33", "#ffcc33", "#ffcc33", | |
"#ffcc33", "#ffcc33", "#ffcc33", "#ffcc33", | |
"#ffcc33", "#ffcc33", "#ffcc33", "#ffcc33", | |
"#ffcc33", "#ffcc33", "#ffcc33", "#ffcc33"]; | |
pub static ref BGC: Vec<&'static str> = vec![ | |
"#f0f0f0", "#cc9933", "#33cc99", "#9933cc", | |
"#3399cc", "#99cc33", "#cc3399", "#999999", | |
"#666666", "#996633", "#339966", "#663399", | |
"#336699", "#669933", "#993366", "#333333"]; | |
} | |
fn tk_fgbgtx(pl: (&TkPanedWindow, &TkLabel), c: usize, tx: &str) { | |
let (pw, lbl) = pl; | |
lbl.padding(&vec![1u64, 2u64, 1u64, 2u64]); // L T R B | |
lbl.anchor(Anchor::Centre); // N NE E SE S SW W NW Center | |
let w = if c == 0 { hanoi::PEGS_STACK_MAX as i64 - 1 } else { c as i64 }; | |
lbl.width(w); // characters // not redraw | |
// lbl.configure("width", &format!("{}", w)); // not redraw | |
pw.forget(lbl); // to redraw, must forget and add | |
pw.add(lbl); // but flicker (adjusting by reso) | |
lbl.foreground(FGC[c]); // overlap configure -fg | |
lbl.background(BGC[c]); // overlap configure -bg | |
lbl.text(tx); | |
} | |
fn tk_setup(rt: &impl rstk::TkWidget) -> Result<TblPwLbl, Box<dyn Error>> { | |
rstk::tell_wish(&format!("wm title . Hanoi")); | |
rstk::tell_wish(&format!("wm geometry . {}x{}+{}+{}", 640, 480, 80, 60)); | |
let mut pw_tbl: Vec<Vec<TkPanedWindow>> = Vec::from_iter((0..16).map(|_| | |
Vec::with_capacity(7))); | |
let mut l_tbl: Vec<Vec<TkLabel>> = Vec::from_iter((0..16).map(|_| | |
Vec::with_capacity(7))); | |
for j in 0..l_tbl.len() { | |
for i in 0..l_tbl[0].capacity() { // l_tbl[0].len() may be 0 | |
pw_tbl[j].push(rstk::make_paned_window(rt, rstk::Orientation::Horizontal)); | |
let pw = &pw_tbl[j][i]; | |
l_tbl[j].push(rstk::make_label(pw)); | |
let lbl = &l_tbl[j][i]; | |
pw.add(lbl); | |
rstk::tell_wish(&format!("{} configure -takefocus 0", lbl.id)); | |
let txt = if j == 0 && i == 3 { "Hello Rust/Tk".to_string() } else { | |
"".to_string() }; // format!("{}", j * l_tbl[0].len() + i) }; | |
tk_fgbgtx((pw, lbl), 0, txt.as_str()); | |
pw.grid().row(j as u64).column(i as u64).pady(1).padx(1).layout(); | |
} | |
} | |
Ok(TblPwLbl{p: pw_tbl, l: l_tbl}) | |
} | |
// tokio for "async fn main" | |
#[tokio::main] | |
async fn main() -> Result<(), Box<dyn Error>> { | |
println!("Hello, Hanoi"); | |
let rt = rstk::start_wish().unwrap(); | |
let pw_lbl: TblPwLbl = tk_setup(&rt)?; | |
// uses &rt as rt: &impl rstk::TkWidget, pw_lbl: TblPwLbl | |
let cb = move |pegs: &RwLockReadGuard<'_, BTreeMap<u8, Vec<u8>>>| -> () { | |
let utc_dt: DateTime<Utc> = Utc::now(); | |
rstk::tell_wish(&format!("wm title {} \"Hanoi {}\"", &rt.id(), utc_dt)); | |
/* | |
let (h, w) = pw_lbl.hw(); | |
let sz = h * w; | |
let tm = utc_dt.timestamp() as usize % sz; | |
tk_fgbgtx(pw_lbl.pl(tm / w, tm % w), hanoi::PEGS_STACK_MAX as usize - 1, | |
&format!("{} {:?}", tm, pegs.keys())); | |
*/ | |
let m = hanoi::PEGS_STACK_MAX as usize; | |
for (j, k) in pegs.keys().enumerate() { | |
let v = &pegs[k]; | |
for (i, d) in v.iter().enumerate() { | |
tk_fgbgtx(pw_lbl.pl(m - i, j * 2 + 1), *d as usize, &format!("{}", d)); | |
} | |
for i in v.len()..m { | |
tk_fgbgtx(pw_lbl.pl(m - i, j * 2 + 1), 0, ""); | |
} | |
} | |
() | |
}; | |
let reso = 2; // 1(1s): slow, 10(0.1s): fast, 20(0.05s): skipped drawing ? | |
let mut delay = 5 * reso; // 5sec | |
// let mut h = Hanoi::init(4, 0, 1)?; | |
let mut h = Hanoi::init(15, 0, 1).unwrap_or_else(|e| { | |
println!("Error: {}", e); | |
delay *= 2; | |
Hanoi::init(4, 0, 1).unwrap() | |
}); | |
println!("start after {}sec", delay / reso); | |
h.stat(&cb); | |
h._hanoi().await?; | |
let ti = Timer::new(); | |
let ns = 1_000_000_000 / reso; | |
let mut _guard = GUARD_MUT.write().map_err(|e| e.to_string())?; | |
_guard.push(ti.schedule_repeating(Duration::nanoseconds(ns), move || { | |
if delay > 0 { delay -= 1; return; } // skip repeating before start | |
match h.walk() { | |
Err(e) => { | |
println!("{}", e); | |
stop_schedule(); | |
return; | |
}, | |
_ => {} | |
} | |
h.stat(&cb); | |
})); | |
drop(_guard); | |
rstk::mainloop(); | |
stop_schedule(); | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment