Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created April 23, 2023 09:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rust-play/8d0504c0ffbfe198b0107e49e814315b to your computer and use it in GitHub Desktop.
Save rust-play/8d0504c0ffbfe198b0107e49e814315b to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
/*
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