From 8bec1637e85cfd3630c9add32bf4feb297f256a1 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 18 Oct 2023 15:27:16 -0700 Subject: [PATCH 01/48] Pull in cl23 optimizer --- src/compiler/evaluate.rs | 2 +- src/compiler/frontend.rs | 29 + src/compiler/lambda.rs | 2 +- src/compiler/optimize/above22.rs | 240 +++++++++ src/compiler/optimize/bodyform.rs | 430 +++++++++++++++ src/compiler/optimize/brief.rs | 180 +++++++ src/compiler/optimize/cse.rs | 737 ++++++++++++++++++++++++++ src/compiler/optimize/deinline.rs | 225 ++++++++ src/compiler/optimize/depgraph.rs | 212 ++++++++ src/compiler/optimize/double_apply.rs | 161 ++++++ src/compiler/optimize/mod.rs | 221 ++++++-- src/compiler/optimize/strategy.rs | 4 +- src/compiler/sexp.rs | 59 +++ 13 files changed, 2465 insertions(+), 37 deletions(-) create mode 100644 src/compiler/optimize/above22.rs create mode 100644 src/compiler/optimize/bodyform.rs create mode 100644 src/compiler/optimize/brief.rs create mode 100644 src/compiler/optimize/cse.rs create mode 100644 src/compiler/optimize/deinline.rs create mode 100644 src/compiler/optimize/depgraph.rs create mode 100644 src/compiler/optimize/double_apply.rs diff --git a/src/compiler/evaluate.rs b/src/compiler/evaluate.rs index 940b5fe92..866bcd07e 100644 --- a/src/compiler/evaluate.rs +++ b/src/compiler/evaluate.rs @@ -490,7 +490,7 @@ fn is_quote_atom(h: Rc) -> bool { match_atom_to_prim(vec![b'q'], 1, h) } -fn is_apply_atom(h: Rc) -> bool { +pub fn is_apply_atom(h: Rc) -> bool { match_atom_to_prim(vec![b'a'], 2, h) } diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index a2c1727bd..f7b5ae1d3 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -878,6 +878,35 @@ fn frontend_start( } } +/// Given the available helper list and the main expression, compute the list of +/// reachable helpers. +pub fn compute_live_helpers( + opts: Rc, + helper_list: &[HelperForm], + main_exp: Rc, + ) -> Vec { + let expr_names: HashSet> = collect_used_names_bodyform(main_exp.borrow()) + .iter() + .map(|x| x.to_vec()) + .collect(); + + let mut helper_map = HashMap::new(); + + for h in helper_list.iter() { + helper_map.insert(h.name().clone(), h.clone()); + } + + let helper_names = calculate_live_helpers(&HashSet::new(), &expr_names, &helper_map); + + helper_list + .iter() + .filter(|h| { + !opts.frontend_check_live() || helper_names.contains(h.name()) + }) + .cloned() + .collect() +} + /// Entrypoint for compilation. This yields a CompileForm which represents a full /// program. /// diff --git a/src/compiler/lambda.rs b/src/compiler/lambda.rs index 1ce93538f..9e65c4c17 100644 --- a/src/compiler/lambda.rs +++ b/src/compiler/lambda.rs @@ -65,7 +65,7 @@ fn make_operator(loc: Srcloc, op: u8, arg1: Rc, arg2: Rc) -> ) } -fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { +pub fn make_cons(loc: Srcloc, arg1: Rc, arg2: Rc) -> BodyForm { make_operator(loc, 4, arg1, arg2) } diff --git a/src/compiler/optimize/above22.rs b/src/compiler/optimize/above22.rs new file mode 100644 index 000000000..7cf01aab2 --- /dev/null +++ b/src/compiler/optimize/above22.rs @@ -0,0 +1,240 @@ +use std::borrow::Borrow; +use std::collections::HashMap; +use std::rc::Rc; + +use clvmr::allocator::Allocator; + +use crate::classic::clvm_tools::stages::stage_0::TRunProgram; + +use crate::compiler::comptypes::{ + BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, +}; +use crate::compiler::frontend::compute_live_helpers; +use crate::compiler::optimize::brief::brief_path_selection; +use crate::compiler::optimize::cse::cse_optimize_bodyform; +use crate::compiler::optimize::deinline::deinline_opt; +use crate::compiler::optimize::double_apply::remove_double_apply; +use crate::compiler::optimize::{ + null_optimization, optimize_expr, run_optimizer, CompileContextWrapper, Optimization, +}; +use crate::compiler::sexp::SExp; +use crate::compiler::StartOfCodegenOptimization; + +/// Captures the strategy for cl23 and above. +/// Until formally released, we can take action in here. +#[derive(Default, Clone)] +pub struct Strategy23 {} + +impl Strategy23 { + pub fn new() -> Self { + Strategy23 {} + } +} + +impl Optimization for Strategy23 { + fn frontend_optimization( + &mut self, + _allocator: &mut Allocator, + _runner: Rc, + _opts: Rc, + mut p0: CompileForm, + ) -> Result { + let mut rebuilt_helpers = Vec::new(); + for h in p0.helpers.iter() { + if let HelperForm::Defun(inline, d) = h { + let function_body = cse_optimize_bodyform(&h.loc(), h.name(), d.body.borrow())?; + // Ok we've got a body that is now a let stack. + let new_helper = HelperForm::Defun( + *inline, + Box::new(DefunData { + body: Rc::new(function_body), + ..*d.clone() + }), + ); + + rebuilt_helpers.push(new_helper); + } else { + rebuilt_helpers.push(h.clone()); + } + } + + p0.helpers = rebuilt_helpers; + Ok(p0) + } + + fn post_desugar_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + cf: CompileForm, + ) -> Result { + let mut symbols = HashMap::new(); + let mut wrapper = + CompileContextWrapper::new(allocator, runner, &mut symbols, self.duplicate()); + deinline_opt(&mut wrapper.context, opts.clone(), cf) + } + + fn start_of_codegen_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + mut to_optimize: StartOfCodegenOptimization, + ) -> Result { + let new_helpers: Vec = to_optimize + .program + .helpers + .iter() + .map(|h| { + if let HelperForm::Defun(inline, defun) = h { + let new_body = optimize_expr( + allocator, + opts.clone(), + runner.clone(), + &to_optimize.code_generator, + defun.body.clone(), + ) + .map(|x| x.1) + .unwrap_or_else(|| defun.body.clone()); + HelperForm::Defun( + *inline, + Box::new(DefunData { + body: new_body, + ..*defun.clone() + }), + ) + } else { + h.clone() + } + }) + .collect(); + + to_optimize.program.helpers = new_helpers; + to_optimize.program.exp = optimize_expr( + allocator, + opts.clone(), + runner.clone(), + &to_optimize.code_generator, + to_optimize.program.exp.clone(), + ) + .map(|x| x.1) + .unwrap_or_else(|| to_optimize.program.exp.clone()); + + let used_helpers = compute_live_helpers( + opts, + &to_optimize.program.helpers, + to_optimize.program.exp.clone(), + ); + + to_optimize.program.helpers = used_helpers; + + Ok(to_optimize) + } + + fn macro_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + _opts: Rc, + code: Rc, + ) -> Result, CompileErr> { + run_optimizer(allocator, runner, code) + } + + fn defun_body_optimization( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + defun: &DefunData, + ) -> Result, CompileErr> { + // Run optimizer on frontend style forms. + let mut changed = true; + let mut new_body = defun.body.clone(); + + while changed { + if let Some((did_optimize, optimized_form)) = optimize_expr( + allocator, + opts.clone(), + runner.clone(), + codegen, + new_body.clone(), + ) { + changed = did_optimize && optimized_form.to_sexp() != new_body.to_sexp(); + new_body = optimized_form; + } else { + changed = false; + } + } + + Ok(new_body) + } + + fn post_codegen_function_optimize( + &mut self, + _allocator: &mut Allocator, + _runner: Rc, + _opts: Rc, + _helper: Option<&HelperForm>, + code: Rc, + ) -> Result, CompileErr> { + let (null_worked, result) = null_optimization(code.clone(), true); + let (double_worked, dbl_result) = remove_double_apply(result, true); + let (brief_worked, brief_result) = brief_path_selection(dbl_result); + if null_worked || double_worked || brief_worked { + Ok(brief_result) + } else { + Ok(code) + } + } + + fn pre_final_codegen_optimize( + &mut self, + allocator: &mut Allocator, + runner: Rc, + opts: Rc, + codegen: &PrimaryCodegen, + ) -> Result, CompileErr> { + let mut changed = true; + let mut new_body = codegen.final_expr.clone(); + + while changed { + if let Some((did_optimize, optimized_form)) = optimize_expr( + allocator, + opts.clone(), + runner.clone(), + codegen, + new_body.clone(), + ) { + changed = did_optimize && optimized_form.to_sexp() != new_body.to_sexp(); + new_body = optimized_form; + } else { + changed = false; + } + } + + Ok(new_body) + } + + fn post_codegen_output_optimize( + &mut self, + _opts: Rc, + generated: SExp, + ) -> Result { + let (null_worked, result) = null_optimization(Rc::new(generated.clone()), true); + let (double_worked, dbl_result) = remove_double_apply(result, true); + let (brief_worked, brief_result) = brief_path_selection(dbl_result); + if null_worked || double_worked || brief_worked { + let borrowed: &SExp = brief_result.borrow(); + Ok(borrowed.clone()) + } else { + Ok(generated) + } + } + + fn duplicate(&self) -> Box { + Box::new(self.clone()) + } +} diff --git a/src/compiler/optimize/bodyform.rs b/src/compiler/optimize/bodyform.rs new file mode 100644 index 000000000..73109bb8d --- /dev/null +++ b/src/compiler/optimize/bodyform.rs @@ -0,0 +1,430 @@ +use std::borrow::Borrow; +use std::cmp::{min, Ordering}; +use std::rc::Rc; + +use crate::compiler::comptypes::{Binding, BodyForm, CompileForm, LambdaData, LetData}; + +// Rewriting and matching on bodyforms. +// Allows a convenient bodyform path description. + +/// A path in a bodyform. Allows us to find and potentially replace the bodyform +/// in a larger expression. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum BodyformPathArc { + LetBinding(usize), // In (let ((a 1) (b 2)) LetBinding(1) points to 2 + CallArgument(usize), // in (x0 x1 x2 x3 x4 x5) CallArgument(3) points to x3 + BodyOf, // In the body of a lambda, mod or let. +} + +/// True if b is contained in a. +pub fn path_overlap_one_way(a: &[BodyformPathArc], b: &[BodyformPathArc]) -> bool { + let a_len = a.len(); + let b_len = b.len(); + + // a is longer than b, so b can't be in a. + if a_len > b_len { + return false; + } + + let iter_until = min(a.len(), b.len()); + for idx in 0..iter_until { + if a[idx] != b[idx] { + // They diverged. + return false; + } + } + + true +} + +/// Determines whether a and b conflict (a is a superset of b or vice versa). +pub fn path_overlap(a: &[BodyformPathArc], b: &[BodyformPathArc]) -> bool { + path_overlap_one_way(a, b) || path_overlap_one_way(b, a) +} + +/// A single valid result from visit_detect_in_bodyform noting the path to the +/// bodyform, the form itself and the returned context from the visitor function. +#[derive(Clone)] +pub struct PathDetectVisitorResult { + pub path: Vec, + pub subexp: BodyForm, + pub context: R, +} + +/// Visit over a bodyform offering the path, original and current bodyforms to the +/// visitor. The vistor returns Ok(None) to just go on, Ok(Some(R)) to accept and +/// record the path and can return error to abort. +fn visit_detect_in_bodyform_inner( + path: &mut Vec, + res: &mut Vec>, + f: &F, + original: &BodyForm, + bf: &BodyForm, +) -> Result<(), E> +where + F: Fn(&[BodyformPathArc], &BodyForm, &BodyForm) -> Result, E>, +{ + let path_idx = path.len(); + match bf { + BodyForm::Call(_l, args, tail) => { + for (i, a) in args.iter().enumerate() { + path.push(BodyformPathArc::CallArgument(i)); + visit_detect_in_bodyform_inner(path, res, f, original, a)?; + path.truncate(path_idx); + } + if let Some(t) = tail.as_ref() { + path.push(BodyformPathArc::CallArgument(args.len())); + visit_detect_in_bodyform_inner(path, res, f, original, t)?; + path.truncate(path_idx); + } + } + BodyForm::Let(_k, b) => { + for (i, a) in b.bindings.iter().enumerate() { + path.push(BodyformPathArc::LetBinding(i)); + visit_detect_in_bodyform_inner(path, res, f, original, a.body.borrow())?; + path.truncate(path_idx); + } + path.push(BodyformPathArc::BodyOf); + visit_detect_in_bodyform_inner(path, res, f, original, b.body.borrow())?; + path.truncate(path_idx); + } + BodyForm::Lambda(ldata) => { + path.push(BodyformPathArc::BodyOf); + visit_detect_in_bodyform_inner(path, res, f, original, ldata.body.borrow())?; + path.truncate(path_idx); + } + BodyForm::Mod(_, form) => { + path.push(BodyformPathArc::BodyOf); + visit_detect_in_bodyform_inner(path, res, f, original, form.exp.borrow())?; + path.truncate(path_idx); + } + _ => {} + } + + // And for this node, call the visitor. + if let Some(r) = f(path, original, bf)? { + res.push(PathDetectVisitorResult { + path: path.clone(), + subexp: bf.clone(), + context: r, + }); + } + + Ok(()) +} + +pub fn visit_detect_in_bodyform( + f: &F, + bf: &BodyForm, +) -> Result>, E> +where + F: Fn(&[BodyformPathArc], &BodyForm, &BodyForm) -> Result, E>, +{ + let mut path = vec![]; + let mut res = vec![]; + visit_detect_in_bodyform_inner(&mut path, &mut res, f, bf, bf)?; + Ok(res) +} + +#[allow(clippy::too_many_arguments)] +fn replace_in_bodyform_inner_list<'a, L, P, F, F1, G, H, R>( + current_path: &mut Vec, + replacements: &[PathDetectVisitorResult], + list_of: &'a [L], + tail_of: &'a Option, + make_path_comp: &P, + extract_body: &G, + compose_wrap: &H, + make_f: &F1, + f: &F, +) -> BodyForm +where + R: Clone, + L: Clone + 'a, + P: Fn(usize) -> BodyformPathArc, + F1: Fn(Vec, Option) -> BodyForm, + G: Fn(&'a L) -> &'a BodyForm, + H: Fn(&'a L, BodyForm) -> L, + F: Fn(&PathDetectVisitorResult, &BodyForm) -> BodyForm, +{ + let mut collection = vec![]; + let path_idx = current_path.len(); + let list_len = list_of.len(); + let mut replacement_list: Vec<(usize, &L)> = list_of.iter().enumerate().collect(); + let mut maybe_tail: Option = None; + if let Some(t) = tail_of.as_ref() { + replacement_list.push((list_len, t)); + } + for (i, a) in replacement_list.into_iter() { + current_path.push(make_path_comp(i)); + + // Continue only with potentially matching replacements. + let pass_on_replacements: Vec> = replacements + .iter() + .filter(|r| path_overlap(current_path, &r.path)) + .cloned() + .collect(); + + // No replacements down this argument. + if pass_on_replacements.is_empty() { + if i == list_len { + maybe_tail = Some(a.clone()); + } else { + collection.push(a.clone()); + } + current_path.truncate(path_idx); + continue; + } + + let wrapper = compose_wrap( + a, + replace_in_bodyform_subset(current_path, &pass_on_replacements, extract_body(a), f), + ); + if i == list_of.len() { + maybe_tail = Some(wrapper); + } else { + collection.push(wrapper); + } + + current_path.truncate(path_idx); + } + + make_f(collection, maybe_tail) +} + +fn replace_in_bodyform_inner_body( + current_path: &mut Vec, + replacements: &[PathDetectVisitorResult], + new_path_elt: BodyformPathArc, + outer_body: &BodyForm, + inner_body: &BodyForm, + make_f: &F1, + f: &F, +) -> BodyForm +where + R: Clone, + F1: Fn(BodyForm) -> BodyForm, + F: Fn(&PathDetectVisitorResult, &BodyForm) -> BodyForm, +{ + let path_idx = current_path.len(); + current_path.push(new_path_elt); + let pass_on_replacements: Vec> = replacements + .iter() + .filter(|r| path_overlap(current_path, &r.path)) + .cloned() + .collect(); + + if pass_on_replacements.is_empty() { + current_path.truncate(path_idx); + return outer_body.clone(); + } + + let new_binding_body = + replace_in_bodyform_subset(current_path, &pass_on_replacements, inner_body, f); + current_path.truncate(path_idx); + make_f(new_binding_body) +} + +/// For some partially matched subset of the replacement set at index idx in their +/// paths, do the child replacements. +fn replace_in_bodyform_subset( + current_path: &mut Vec, + replacements: &[PathDetectVisitorResult], + bf: &BodyForm, + f: &F, +) -> BodyForm +where + R: Clone, + F: Fn(&PathDetectVisitorResult, &BodyForm) -> BodyForm, +{ + // We already checked for overlaps, so there'll be only one if any. + let exact_match_replacements: Vec> = replacements + .iter() + .filter(|r| &r.path == current_path) + .cloned() + .collect(); + + if !exact_match_replacements.is_empty() { + // Return the object + return f(&exact_match_replacements[0], bf); + } + + match bf { + BodyForm::Call(l, args, tail) => replace_in_bodyform_inner_list( + current_path, + replacements, + args, + tail, + &BodyformPathArc::CallArgument, + &|e: &Rc| e.borrow(), + &|_w, b| Rc::new(b), + &|args, tail| BodyForm::Call(l.clone(), args, tail), + f, + ), + BodyForm::Let(k, b) => { + let path_idx = current_path.len(); + current_path.push(BodyformPathArc::BodyOf); + let pass_on_replacements: Vec> = replacements + .iter() + .filter(|r| path_overlap(current_path, &r.path)) + .cloned() + .collect(); + + let new_lambda_body = + replace_in_bodyform_subset(current_path, &pass_on_replacements, b.body.borrow(), f); + + current_path.truncate(path_idx); + + replace_in_bodyform_inner_list( + current_path, + replacements, + &b.bindings, + &None, + &BodyformPathArc::LetBinding, + &|e: &Rc| &e.body, + &|w: &Rc, b: BodyForm| { + let wb: &Binding = w.borrow(); + Rc::new(Binding { + body: Rc::new(b), + ..wb.clone() + }) + }, + &|bindings, _| { + BodyForm::Let( + k.clone(), + Box::new(LetData { + bindings, + body: Rc::new(new_lambda_body.clone()), + ..*b.clone() + }), + ) + }, + f, + ) + } + BodyForm::Lambda(l) => replace_in_bodyform_inner_body( + current_path, + replacements, + BodyformPathArc::BodyOf, + bf, + &l.body, + &|b| { + BodyForm::Lambda(Box::new(LambdaData { + body: Rc::new(b), + ..*l.clone() + })) + }, + f, + ), + BodyForm::Mod(l, m) => replace_in_bodyform_inner_body( + current_path, + replacements, + BodyformPathArc::BodyOf, + bf, + &m.exp, + &|b| { + BodyForm::Mod( + l.clone(), + CompileForm { + exp: Rc::new(b), + ..m.clone() + }, + ) + }, + f, + ), + _ => bf.clone(), + } +} + +/// Replace subexpressions in a bodyform given a set of PathDetectVisitorResult<_>. +pub fn replace_in_bodyform( + replacements: &[PathDetectVisitorResult], + bf: &BodyForm, + f: &F, +) -> Option +where + R: Clone, + F: Fn(&PathDetectVisitorResult, &BodyForm) -> BodyForm, +{ + if replacements.is_empty() { + return Some(bf.clone()); + } + + // We should not have any overlapping paths... if we do, that seems like a + // failure since a replacement would be lost. + for (i, p) in replacements.iter().enumerate() { + for q in replacements.iter().skip(i + 1) { + if path_overlap(&p.path, &q.path) { + return None; // An overlap + } + } + } + + let mut current_path = vec![]; + // There are no overlaps, start replacing + Some(replace_in_bodyform_subset( + &mut current_path, + replacements, + bf, + f, + )) +} + +/// Retrieve bodyform by path +pub fn retrieve_bodyform(path: &[BodyformPathArc], mut found: &BodyForm, f: &F) -> Option +where + F: Fn(&BodyForm) -> R, +{ + for p in path.iter() { + match p { + BodyformPathArc::LetBinding(n) => { + if let BodyForm::Let(_, l) = found { + if *n >= l.bindings.len() { + return None; + } + found = l.bindings[*n].body.borrow(); + } else { + return None; + } + } + BodyformPathArc::CallArgument(n) => { + if let BodyForm::Call(_, a, tail) = found { + match n.cmp(&a.len()) { + Ordering::Greater => { + return None; + } + Ordering::Equal => { + if let Some(t) = tail { + found = t.borrow(); + } else { + return None; + } + } + _ => { + found = a[*n].borrow(); + } + } + } else { + return None; + } + } + BodyformPathArc::BodyOf => match found { + BodyForm::Let(_, b) => { + found = b.body.borrow(); + } + BodyForm::Lambda(l) => { + found = l.body.borrow(); + } + BodyForm::Mod(_, m) => { + found = m.exp.borrow(); + } + _ => { + return None; + } + }, + } + } + + Some(f(found)) +} diff --git a/src/compiler/optimize/brief.rs b/src/compiler/optimize/brief.rs new file mode 100644 index 000000000..f8cac9a9d --- /dev/null +++ b/src/compiler/optimize/brief.rs @@ -0,0 +1,180 @@ +use num_bigint::ToBigInt; +use std::borrow::Borrow; +use std::rc::Rc; + +use crate::classic::clvm::__type_compatibility__::bi_one; +use crate::classic::clvm_tools::node_path::compose_paths; + +#[cfg(test)] +use crate::compiler::sexp::parse_sexp; +use crate::compiler::sexp::SExp; + +#[cfg(test)] +use crate::compiler::srcloc::Srcloc; + +fn is_quote_atom(a: &SExp) -> bool { + if let SExp::Atom(_, n) = a.atomize() { + return n.len() == 1 && n[0] == 1; + } + + false +} + +fn is_first_atom(a: &SExp) -> bool { + if let SExp::Atom(_, n) = a.atomize() { + return n.len() == 1 && n[0] == 5; + } + + false +} + +fn is_rest_atom(a: &SExp) -> bool { + if let SExp::Atom(_, n) = a.atomize() { + return n.len() == 1 && n[0] == 6; + } + + false +} + +// Collapse sequences of (f (r (f ... X))) representing (a P1 X) +// into (a P1 X) if X is not a path +// or P1 || X if X is a path +fn brief_path_selection_single(mut body: Rc) -> (bool, Rc) { + let orig_body = body.clone(); + let mut found_stack = 0; + let mut target_path = bi_one(); + + while let Some(lst) = body.proper_list() { + if let [cmd, arg] = &lst[..] { + if is_quote_atom(cmd) { + break; + } + + let is_first = is_first_atom(cmd); + if is_first || is_rest_atom(cmd) { + found_stack += 1; + target_path *= 2_u32.to_bigint().unwrap(); + if !is_first { + target_path += bi_one(); + } + body = Rc::new(arg.clone()); + continue; + } + } + + break; + } + + if found_stack > 0 { + let intval = if let SExp::Integer(_l, i) = body.borrow() { + Some(i.clone()) + } else { + None + }; + + if let Some(i) = intval { + // The number to the left is "closer to the root". + // These bits are selected first. + let final_path = compose_paths(&i, &target_path); + return (true, Rc::new(SExp::Integer(body.loc(), final_path))); + } + + /* + if found_stack > 2 { + let apply_atom = Rc::new(SExp::Atom(body.loc(), vec![2])); + let at_atom = Rc::new(SExp::Atom(body.loc(), vec![1])); + + return (true, Rc::new(SExp::Cons( + body.loc(), + apply_atom.clone(), + Rc::new(SExp::Cons( + body.loc(), + Rc::new(SExp::Cons( + body.loc(), + at_atom.clone(), + Rc::new(SExp::Integer(body.loc(), target_path)) + )), + Rc::new(SExp::Cons( + body.loc(), + Rc::new(SExp::Cons( + body.loc(), + apply_atom, + Rc::new(SExp::Cons( + body.loc(), + body.clone(), + Rc::new(SExp::Cons( + body.loc(), + at_atom.clone(), + Rc::new(SExp::Nil(body.loc())) + )) + )) + )), + Rc::new(SExp::Nil(body.loc())) + )) + )) + ))); + } + */ + } + + (false, orig_body) +} + +pub fn brief_path_selection(body: Rc) -> (bool, Rc) { + let (changed, new_body) = brief_path_selection_single(body.clone()); + if changed { + return (true, new_body); + } + + if let Some(lst) = body.proper_list() { + if lst.len() < 2 || is_quote_atom(&lst[0]) { + return (false, body); + } + + let mut end = Rc::new(SExp::Nil(body.loc())); + let mut updated = false; + for f in lst.iter().rev() { + let (mod_a, a) = brief_path_selection(Rc::new(f.clone())); + updated = updated || mod_a; + end = Rc::new(SExp::Cons(body.loc(), a, end)); + } + return (updated, end); + } + + (false, body) +} + +#[test] +fn test_brief_path_selection_none() { + let filename = "*test*"; + let loc = Srcloc::start(filename); + let parsed = parse_sexp(loc.clone(), "(2 (1 (1) (1) (1)) (3))".bytes()).expect("should parse"); + let (did_work, optimized) = brief_path_selection(parsed[0].clone()); + assert!(!did_work); + assert_eq!(optimized.to_string(), "(2 (1 (1) (1) (1)) (3))"); +} + +/* +#[test] +fn test_brief_path_selection_one_first_unknown_body() { + let filename = "*test*"; + let loc = Srcloc::start(filename); + let parsed = parse_sexp(loc.clone(), "(5 (5 (5 (+ 3 2))))".bytes()).expect("should parse"); + let (did_work, optimized) = brief_path_selection(parsed[0].clone()); + assert!(did_work); + assert_eq!(optimized.to_string(), "(2 8 (2 (+ 3 2) 1))"); +} +*/ + +#[test] +fn test_brief_path_selection_one_first_path_body_1() { + let filename = "*test*"; + let loc = Srcloc::start(filename); + let parsed = parse_sexp(loc.clone(), "(5 (5 (6 (5 11))))".bytes()).expect("should parse"); + let (did_work, optimized) = brief_path_selection(parsed[0].clone()); + assert!(did_work); + // f f r f -> path 18 (0100[1]) + // 11 -> (110[1]) + // Joined so that 11's path occupies the inner (low) bits: 1100100[1] + assert_eq!(optimized.to_string(), "147"); +} diff --git a/src/compiler/optimize/cse.rs b/src/compiler/optimize/cse.rs new file mode 100644 index 000000000..bfa0e9d0b --- /dev/null +++ b/src/compiler/optimize/cse.rs @@ -0,0 +1,737 @@ +use std::borrow::Borrow; +use std::cmp::min; +use std::collections::{BTreeMap, HashSet}; +use std::rc::Rc; + +use crate::compiler::clvm::sha256tree; +use crate::compiler::comptypes::{ + Binding, BindingPattern, BodyForm, CompileErr, LambdaData, LetData, LetFormInlineHint, + LetFormKind, +}; +use crate::compiler::evaluate::{is_apply_atom, is_i_atom}; +use crate::compiler::gensym::gensym; +use crate::compiler::lambda::make_cons; +use crate::compiler::optimize::bodyform::{ + path_overlap_one_way, replace_in_bodyform, retrieve_bodyform, visit_detect_in_bodyform, + BodyformPathArc, PathDetectVisitorResult, +}; +use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::srcloc::Srcloc; + +// Common subexpression elimintation. +// catalog subexpressions of the given bodyform and +#[derive(Debug, Clone)] +pub struct CSEInstance { + pub path: Vec, +} + +#[derive(Debug, Clone)] +pub struct CSEDetectionWithoutConditions { + pub hash: Vec, + pub subexp: BodyForm, + pub instances: Vec, +} + +#[derive(Debug, Clone)] +pub struct CSEDetection { + pub hash: Vec, + pub root: Vec, + pub saturated: bool, + pub subexp: BodyForm, + pub instances: Vec, +} + +#[derive(Debug, Clone)] +pub struct CSECondition { + pub path: Vec, + pub canonical: bool, +} + +// in a chain of conditions: +// +// (if a *b *c) // Can precompute. +// +// (if a *b (if c (if d *e *f) h)) // Can't precompute; might not be safe in h. +// +// The question we have to ask for each condition is: +// does every branch use the cse? +// +// If it is used in every branch of a condition, then it dominates that condition +// and it can be computed definitely above the condition. +// +// If it is missing from some downstream elements of a condition, then we must +// pass it on as a lambda that can be applied. +// +fn is_constant(bf: &BodyForm) -> bool { + matches!( + bf, + BodyForm::Value(SExp::Nil(_)) + | BodyForm::Value(SExp::Integer(_, _)) + | BodyForm::Value(SExp::QuotedString(_, _, _)) + | BodyForm::Quoted(_) + ) +} + +// A detection is fully dominated if every instance of it is used in the same +// other detection. +fn is_fully_dominated( + cse: &CSEDetectionWithoutConditions, + detections: &[CSEDetectionWithoutConditions], +) -> bool { + let mut host_set = HashSet::new(); + + for i in cse.instances.iter() { + for d in detections.iter() { + if d.hash == cse.hash { + continue; + } + for d_i in d.instances.iter() { + if path_overlap_one_way(&d_i.path, &i.path) { + host_set.insert(d.hash.clone()); + } + } + } + } + + // No overlaps means all uses are unique, otherwise it is fully dominated if + // if all uses are in the same host. If there are multiple hosts then it is + // not fully dominated since we can still deduplicate it among other hosts + // which are themselves going to be deduplicated. + host_set.len() == 1 +} + +pub fn cse_detect(fe: &BodyForm) -> Result, CompileErr> { + let found_exprs = visit_detect_in_bodyform( + &|path, _original, form| { + // The whole expression isn't a repeat. + if path.is_empty() { + return Ok(None); + } + + // Skip the function name of a call. + if path[path.len() - 1] == BodyformPathArc::CallArgument(0) { + return Ok(None); + } + + // Skip individual variable references. + if let BodyForm::Value(SExp::Atom(_, _)) = form { + return Ok(None); + } + + // Skip cheap constants. + if is_constant(form) { + return Ok(None); + } + + let hash_of = sha256tree(form.to_sexp()); + let res: Result>, CompileErr> = Ok(Some(hash_of)); + res + }, + fe, + )?; + + // Group them by hash since we've renamed variables. + let mut by_hash: BTreeMap, Vec>>> = BTreeMap::new(); + for expr in found_exprs.iter() { + if let Some(lst) = by_hash.get_mut(&expr.context) { + lst.push(expr.clone()); + } else { + by_hash.insert(expr.context.clone(), vec![expr.clone()]); + } + } + + let detections: Vec = by_hash + .into_iter() + .filter_map(|(k, v)| { + if v.len() < 2 { + return None; + } + + let subexp = v[0].subexp.clone(); + + let instances = v + .into_iter() + .map(|item| CSEInstance { path: item.path }) + .collect(); + + Some(CSEDetectionWithoutConditions { + hash: k, + subexp, + instances, + }) + }) + .collect(); + + let useful_detections = detections + .iter() + .filter(|d| !is_fully_dominated(d, &detections)) + .cloned() + .collect(); + + Ok(useful_detections) +} + +// Number of other CSE detections this one depends on. +// We can't apply it until the ones it depends on are applied. +fn number_of_overlaps(detections: &[CSEDetection], cse: &CSEDetection) -> usize { + cse.instances + .iter() + .map(|i: &CSEInstance| { + detections + .iter() + .filter(|d| d.hash != cse.hash) + .map(|d| { + d.instances + .iter() + .filter(|j: &&CSEInstance| path_overlap_one_way(&i.path, &j.path)) + .count() + }) + .sum::() + }) + .sum() +} + +fn sorted_cse_detections_by_applicability( + cse_detections: &[CSEDetection], +) -> Vec<(usize, CSEDetection)> { + let mut detections_with_dependencies: Vec<(usize, CSEDetection)> = cse_detections + .iter() + .map(|a| (number_of_overlaps(cse_detections, a), a.clone())) + .collect(); + detections_with_dependencies.sort_by(|(a, _), (b, _)| a.cmp(b)); + detections_with_dependencies +} + +fn is_one_env_ref(bf: &BodyForm) -> bool { + bf.to_sexp() == Rc::new(SExp::Atom(bf.loc(), vec![1])) + || bf.to_sexp() == Rc::new(SExp::Atom(bf.loc(), vec![b'@'])) + || bf.to_sexp() == Rc::new(SExp::Atom(bf.loc(), b"@*env*".to_vec())) +} + +pub fn is_canonical_apply_parent( + p: &[BodyformPathArc], + root: &BodyForm, +) -> Result { + if p.is_empty() { + return Ok(false); + } + + let last_idx = p.len() - 1; + if p[last_idx] != BodyformPathArc::CallArgument(1) { + return Ok(false); // Not the right position in the parent. + } + + let path_to_parent: Vec = p.iter().take(last_idx).cloned().collect(); + let parent_exp = + if let Some(parent) = retrieve_bodyform(&path_to_parent, root, &|bf| bf.clone()) { + parent + } else { + return Err(CompileErr( + root.loc(), + format!( + "Impossible: could not retrieve parent of existing expression (root {})", + root.to_sexp() + ), + )); + }; + + // Checking for a primitive, so no tail. + if let BodyForm::Call(_, parts, None) = &parent_exp { + if parts.len() != 3 { + return Ok(false); + } + + if !is_apply_atom(parts[0].to_sexp()) { + return Ok(false); + } + + Ok(is_one_env_ref(&parts[2])) + } else { + Ok(false) + } +} + +fn get_com_body(bf: &BodyForm) -> Option<&BodyForm> { + // Checking for com so no tail. + if let BodyForm::Call(_, parts, None) = bf { + if parts.len() != 2 { + return None; + } + + if parts[0].to_sexp() != Rc::new(SExp::Atom(bf.loc(), b"com".to_vec())) { + return None; + } + + return Some(&parts[1]); + } + + None +} + +// Detect uses of the 'i' operator in chialisp code. +// When written (a (i x (com A) (com B)) 1) +// it is canonical. +pub fn detect_conditions(bf: &BodyForm) -> Result, CompileErr> { + let found_conditions = visit_detect_in_bodyform( + &|path, root, form| -> Result, CompileErr> { + // Must have (a ... 1) surrounding it to be canonical. + if !is_canonical_apply_parent(path, root)? { + return Ok(None); + } + + // Checking for a primitive so no tail. + if let BodyForm::Call(_, parts, None) = form { + if parts.len() != 4 { + return Ok(None); + } + + if !is_i_atom(parts[0].to_sexp()) { + return Ok(None); + } + + // We're expecting (com A) and (com B) for the last two + // arguments. + // XXX also recognize a tree of (i ...) forms whose leaves + // are all (com X). + let a_body = get_com_body(parts[2].borrow()); + let b_body = get_com_body(parts[3].borrow()); + if let (Some(_), Some(_)) = (a_body, b_body) { + return Ok(Some(true)); + } + + // It is a proper conditional expression, but not in the + // canonical form. + return Ok(Some(false)); + } + + Ok(None) + }, + bf, + )?; + + let results = found_conditions + .into_iter() + .map(|f| CSECondition { + path: f.path, + canonical: f.context, + }) + .collect(); + + Ok(results) +} + +// True if for some condition path c_path there are matching instance paths +// for either c_path + [CallArgument(1)] or both +// c_path + [CallArgument(2)] and c_path + [CallArgument(3)] +fn cse_is_covering(c_path: &[BodyformPathArc], instances: &[CSEInstance]) -> bool { + let mut target_paths = vec![c_path.to_vec(), c_path.to_vec(), c_path.to_vec()]; + target_paths[0].push(BodyformPathArc::CallArgument(1)); + target_paths[1].push(BodyformPathArc::CallArgument(2)); + target_paths[2].push(BodyformPathArc::CallArgument(3)); + + let have_targets: Vec = target_paths + .iter() + .map(|t| instances.iter().any(|i| path_overlap_one_way(t, &i.path))) + .collect(); + + have_targets[0] || (have_targets[1] && have_targets[2]) +} + +pub fn cse_classify_by_conditions( + conditions: &[CSECondition], + detections: &[CSEDetectionWithoutConditions], +) -> Vec { + detections + .iter() + .filter_map(|d| { + // Detect the common root of all instances. + if d.instances.is_empty() { + return None; + } + + let mut path_limit = 0; + let possible_root = d.instances[0].path.clone(); + for i in d.instances.iter().skip(1) { + path_limit = min(path_limit, i.path.len()); + for (idx, item) in possible_root.iter().take(path_limit).enumerate() { + if &i.path[idx] != item { + path_limit = idx; + break; + } + } + } + + // path_limit points to the common root of all instances of this + // cse detection. + // + // now find conditions that are downstream of the cse root. + let applicable_conditions: Vec = conditions + .iter() + .filter(|c| path_overlap_one_way(&c.path, &possible_root)) + .cloned() + .collect(); + + // We don't need to delay the CSE if 1) all conditions below it + // are canonical and 2) it appears downstream of all conditions + // it encloses. + let fully_canonical = applicable_conditions + .iter() + .all(|c| c.canonical && cse_is_covering(&c.path, &d.instances)); + + Some(CSEDetection { + hash: d.hash.clone(), + subexp: d.subexp.clone(), + instances: d.instances.clone(), + saturated: fully_canonical, + root: possible_root, + }) + }) + .collect() +} + +fn detect_common_cse_root(instances: &[CSEInstance]) -> Vec { + // No instances, we can choose the root. + let min_size = if let Some(m) = instances.iter().map(|i| i.path.len()).min() { + m + } else { + return Vec::new(); + }; + + let mut target_path = instances[0].path.clone(); + let mut last_match = min_size; + for idx in 0..min_size { + for i in instances.iter() { + if i.path[idx] != instances[0].path[idx] { + // If we don't match here, then the common root is up to here. + last_match = last_match.min(idx); + target_path = instances[0].path.iter().take(last_match).cloned().collect(); + break; + } + } + } + + // Back it up to the body of a let binding. + for (idx, f) in target_path.iter().enumerate().rev() { + if f == &BodyformPathArc::BodyOf { + return target_path.iter().take(idx + 1).cloned().collect(); + } + } + + // No internal root if there was no let traversal. + Vec::new() +} + +// Finds lambdas that contain CSE detection instances from the provided list. +fn find_affected_lambdas( + instances: &[CSEInstance], + common_root: &[BodyformPathArc], + bf: &BodyForm, +) -> Result>, CompileErr> { + visit_detect_in_bodyform( + &|path, _root, form| -> Result, CompileErr> { + // The common root is inside this lambda. + if path_overlap_one_way(path, common_root) { + return Ok(None); + } + if let BodyForm::Lambda(_) = form { + if instances + .iter() + .any(|i| path_overlap_one_way(path, &i.path)) + { + return Ok(Some(())); + } + } + + Ok(None) + }, + bf, + ) +} + +// Adds a new variable on the left of the lambda captures. +// "x" + (lambda ((& a b) z) ...) -> (lambda ((& x a b) z) ...) +fn add_variable_to_lambda_capture(vn: &[u8], bf: &BodyForm) -> BodyForm { + let new_var_sexp = SExp::Atom(bf.loc(), vn.to_vec()); + if let BodyForm::Lambda(ldata) = bf { + let ldata_borrowed: &LambdaData = ldata.borrow(); + let new_captures = Rc::new(make_cons( + bf.loc(), + Rc::new(BodyForm::Value(new_var_sexp.clone())), + ldata.captures.clone(), + )); + BodyForm::Lambda(Box::new(LambdaData { + capture_args: Rc::new(SExp::Cons( + bf.loc(), + Rc::new(new_var_sexp), + ldata.capture_args.clone(), + )), + captures: new_captures, + ..ldata_borrowed.clone() + })) + } else { + bf.clone() + } +} + +#[derive(Clone, Debug)] +struct CSEBindingSite { + target_path: Vec, + binding: Binding, +} + +#[derive(Default, Debug)] +struct CSEBindingInfo { + info: BTreeMap, Vec>, +} + +impl CSEBindingInfo { + fn push(&mut self, site: CSEBindingSite) { + if let Some(reference) = self.info.get_mut(&site.target_path) { + reference.push(site.clone()); + } else { + self.info.insert(site.target_path.clone(), vec![site]); + } + } +} + +type CSEReplacementTargetAndBindings<'a> = Vec<&'a (Vec, Vec>)>; + +pub fn cse_optimize_bodyform( + loc: &Srcloc, + name: &[u8], + b: &BodyForm, +) -> Result { + let conditions = detect_conditions(b)?; + let cse_raw_detections = cse_detect(b)?; + + let cse_detections = cse_classify_by_conditions(&conditions, &cse_raw_detections); + + // While we have them, apply any detections that overlap no others. + let mut detections_with_dependencies: Vec<(usize, CSEDetection)> = + sorted_cse_detections_by_applicability(&cse_detections); + + let mut function_body = b.clone(); + let mut new_binding_stack: Vec<(Vec, Vec>)> = Vec::new(); + + while !detections_with_dependencies.is_empty() { + let detections_to_apply: Vec = detections_with_dependencies + .iter() + .take_while(|(c, _d)| *c == 0) + .map(|(_c, d)| d.clone()) + .collect(); + let keep_detections: Vec = detections_with_dependencies + .iter() + .skip_while(|(c, _d)| *c == 0) + .map(|(_c, d)| d.clone()) + .collect(); + + // It's an error if applications are deadlocked. + // I don't think it's possible but this will prevent infinite + // looping. + if detections_to_apply.is_empty() && !keep_detections.is_empty() { + return Err(CompileErr( + loc.clone(), + format!("CSE optimization failed in helper {}", decode_string(name)), + )); + } + + let mut binding_set: CSEBindingInfo = Default::default(); + + for d in detections_to_apply.iter() { + // If for some reason there are none to apply, we can + // skip it. That should not be possible. + if d.instances.is_empty() { + break; + } + + // Skip unsaturated conditional CSE clauses at the moment. + // This is improvable in the future. + if !d.saturated { + continue; + } + + // All detections should have been transformed equally. + // Therefore, we can pick one out and use its form. + // + // These might have changed from when they were detected + // because other common subexpressions were substuted. + let prototype_instance = if let Some(r) = + retrieve_bodyform(&d.instances[0].path, &function_body, &|b: &BodyForm| { + b.clone() + }) { + r + } else { + return Err(CompileErr( + loc.clone(), + format!( + "CSE Error in {}: could not find form to replace for path {:?}", + decode_string(name), + d.instances[0].path + ), + )); + }; + + // We'll assign a fresh variable for each of the detections + // that are applicable now. + let new_variable_name = gensym(b"cse".to_vec()); + let new_variable_bf_alone = BodyForm::Value(SExp::Atom( + prototype_instance.loc(), + new_variable_name.clone(), + )); + + let new_variable_bf = new_variable_bf_alone; + + let replacement_spec: Vec> = d + .instances + .iter() + .map(|i| PathDetectVisitorResult { + path: i.path.clone(), + subexp: new_variable_bf.clone(), + context: (), + }) + .collect(); + + // Detect the root of the CSE as the innermost expression that covers + // all uses. + let replace_path = detect_common_cse_root(&d.instances); + + // Route the captured repeated subexpression into intervening lambdas. + // This means that the lambdas will gain a capture on the left side of + // their captures. + // + // Ensure that lambdas above replace_path aren't targeted. + let affected_lambdas = find_affected_lambdas(&d.instances, &replace_path, b)?; + if let Some(res) = replace_in_bodyform( + &affected_lambdas, + &function_body, + &|_v: &PathDetectVisitorResult<()>, b| { + add_variable_to_lambda_capture(&new_variable_name, b) + }, + ) { + function_body = res; + } else { + return Err(CompileErr( + loc.clone(), + "error forwarding cse capture into lambda, which should work".to_string(), + )); + } + + if let Some(res) = replace_in_bodyform( + &replacement_spec, + &function_body, + &|v: &PathDetectVisitorResult<()>, _b| v.subexp.clone(), + ) { + function_body = res; + } else { + return Err(CompileErr( + loc.clone(), + format!( + "cse replacement failed in helper {}, which shouldn't be possible", + decode_string(name) + ), + )); + } + + // Put aside the definition in this binding set. + let name_atom = SExp::Atom(prototype_instance.loc(), new_variable_name.clone()); + binding_set.push(CSEBindingSite { + target_path: replace_path, + binding: Binding { + loc: prototype_instance.loc(), + nl: prototype_instance.loc(), + pattern: BindingPattern::Complex(Rc::new(name_atom)), + body: Rc::new(prototype_instance), + }, + }); + } + + detections_with_dependencies = sorted_cse_detections_by_applicability(&keep_detections); + + new_binding_stack.append( + &mut binding_set + .info + .iter() + .rev() + .map(|(target_path, sites)| { + let bindings: Vec> = sites + .iter() + .map(|site| Rc::new(site.binding.clone())) + .collect(); + (target_path.clone(), bindings) + }) + .collect(), + ); + } + + // We might not have completely sorted sites anymore due to joining up each + // site set under a common target path (which themselves need sorting). + if new_binding_stack.is_empty() { + return Ok(function_body); + } + + // We need to topologically sort the CSE insertions by dominance otherwise + // The inserted let bindings farther up the tree will disrupt lower down + // replacements. + // + // Sort the target paths so we put in deeper paths before outer ones. + let mut sorted_bindings: Vec<(Vec, Vec>)> = Vec::new(); + + // We'll do this by finding bindings that are not dominated and processing + // them last. + while !new_binding_stack.is_empty() { + let (still_dominated, not_dominated): ( + CSEReplacementTargetAndBindings<'_>, + CSEReplacementTargetAndBindings<'_>, + ) = new_binding_stack.iter().partition(|(t, _)| { + new_binding_stack.iter().any(|(t_other, _)| { + // t is dominated if t_other contains it. + t_other != t && path_overlap_one_way(t_other, t) + }) + }); + let mut not_dominated_vec: Vec<(Vec, Vec>)> = + not_dominated.into_iter().cloned().collect(); + sorted_bindings.append(&mut not_dominated_vec); + let still_dominated_vec: Vec<(Vec, Vec>)> = + still_dominated.into_iter().cloned().collect(); + new_binding_stack = still_dominated_vec; + } + + // All CSE replacements are done. We unwind the new bindings + // into a stack of parallel let forms. + for (target_path, binding_list) in sorted_bindings.into_iter().rev() { + let replacement_spec = &[PathDetectVisitorResult { + path: target_path.clone(), + subexp: function_body.clone(), + context: (), + }]; + if let Some(res) = replace_in_bodyform( + replacement_spec, + &function_body, + &|_v: &PathDetectVisitorResult<()>, b| { + BodyForm::Let( + LetFormKind::Parallel, + Box::new(LetData { + loc: function_body.loc(), + kw: None, + inline_hint: Some(LetFormInlineHint::NonInline(loc.clone())), + bindings: binding_list.clone(), + body: Rc::new(b.clone()), + }), + ) + }, + ) { + assert!(res.to_sexp() != function_body.to_sexp()); + function_body = res; + } else { + return Err(CompileErr( + function_body.loc(), + format!( + "Could not find the target to replace for path {target_path:?} in {}", + b.to_sexp() + ), + )); + } + } + + Ok(function_body) +} diff --git a/src/compiler/optimize/deinline.rs b/src/compiler/optimize/deinline.rs new file mode 100644 index 000000000..5b1b9b86c --- /dev/null +++ b/src/compiler/optimize/deinline.rs @@ -0,0 +1,225 @@ +use std::collections::{BTreeSet, HashMap, HashSet}; +use std::rc::Rc; + +use crate::compiler::codegen::codegen; +use crate::compiler::optimize::depgraph::{DepgraphKind, FunctionDependencyGraph}; +use crate::compiler::optimize::{sexp_scale, SyntheticType}; +use crate::compiler::{BasicCompileContext, CompileErr, CompileForm, CompilerOpts, HelperForm}; + +// Find the roots for the given function. +fn find_roots( + visited: &mut HashSet>, + root_set: &mut BTreeSet>, + depgraph: &FunctionDependencyGraph, + function: &[u8], +) { + if visited.contains(function) { + return; + } + + visited.insert(function.to_vec()); + + // If it's non-inline, it's a root. + if let Some(f) = depgraph.helpers.get(function) { + if matches!(f.status, DepgraphKind::UserNonInline) { + root_set.insert(function.to_vec()); + return; + } + } + + if let Some(parents) = depgraph.parents(function) { + for p in parents.iter() { + find_roots(visited, root_set, depgraph, p); + } + } +} + +// Should take a desugared program. +pub fn deinline_opt( + context: &mut BasicCompileContext, + opts: Rc, + mut compileform: CompileForm, +) -> Result { + // Short circuit return: no helpers. + if compileform.helpers.is_empty() { + return Ok(compileform); + } + + let depgraph = FunctionDependencyGraph::new(&compileform); + + let mut best_compileform = compileform.clone(); + let generated_program = codegen(context, opts.clone(), &best_compileform)?; + let mut metric = sexp_scale(&generated_program); + let flip_helper = |h: &mut HelperForm| { + if let HelperForm::Defun(inline, defun) = h { + if matches!(&defun.synthetic, Some(SyntheticType::NoInlinePreference)) { + *h = HelperForm::Defun(!*inline, defun.clone()); + return true; + } + } + + false + }; + + let helper_to_index: HashMap, usize> = compileform + .helpers + .iter() + .enumerate() + .map(|(i, h)| (h.name().to_vec(), i)) + .collect(); + + // defun F -> Synthetic letbinding_$_1 + // Synthetic letbinding_$_2 -> Synthetic letbinding_$_3 + // + // defun H_inline -> + // Synthetic letbinding_$_4 -> Synthetic letbinding_$_5 + // Synthetic letbinding_$_6 + // + // defun G -> Synthetic letbinding_$_7 -> H_inline + // + // - Synthetic Roots - + // + // letbinding_$_1, letbinding_$_2, letbinding_$_7 + // letbinding_$_4 is not a root, because it's in H_inline, called from G. + // + // So for each synthetic function, we traverse functions that depend on + // it as long as it's a synthetic function or a non-synthetic inline. + // The functions we reach are the roots. + // + // If any two roots share dependencies, they must be merged. + // + // So we take the set of each root and every synthetic function reachable + // from it and for each of those sets, we do the normal optimizataion loop. + + // Find leaf synthetic functions by first finding leaf functions, then + // until we find a synthetic function, go up to each depended_on_by function + // until we reach a root. + // + // Remember the root this function belongs to. + let leaves: Vec> = depgraph + .leaves() + .iter() + .filter(|l| { + depgraph + .helpers + .get(&l.to_vec()) + .map(|l| !matches!(l.status, DepgraphKind::UserNonInline)) + .unwrap_or(false) + }) + .cloned() + .collect(); + + let mut roots: HashMap, BTreeSet>> = HashMap::new(); + + // For each leaf, find roots. + for l in leaves.iter() { + let mut visited = HashSet::new(); + let mut leaf_roots = BTreeSet::new(); + find_roots(&mut visited, &mut leaf_roots, &depgraph, l); + if leaf_roots.is_empty() { + leaf_roots.insert(l.to_vec()); + } + roots.insert(l.to_vec(), leaf_roots); + } + + // Make a set of root sets to coalesce them. + let mut roots_set: HashSet>> = HashSet::new(); + for (_, common_roots) in roots.iter() { + roots_set.insert(common_roots.clone()); + } + + // roots is a map from leaf inline to root container. We can use the roots_set + // with this collection to make a set of leaves reachable from each root set. + // Each root set is a set of functions that will change representation when + // inlining is changed so we have to handle each root set as a unit. + let mut root_set_to_leaf: HashMap>, BTreeSet>> = roots_set + .iter() + .map(|root_set| (root_set.clone(), BTreeSet::new())) + .collect(); + + for l in leaves.iter() { + let root = if let Some(root) = roots.get(l) { + root.clone() + } else { + return Err(CompileErr( + compileform.loc.clone(), + "Error in deinline, depgraph gave a leaf that didn't yield a root".to_string(), + )); + }; + + let from_root_set: Vec>> = roots_set + .iter() + .filter(|r| { + let intersection_of_roots: HashSet> = + r.intersection(&root).cloned().collect(); + !intersection_of_roots.is_empty() + }) + .cloned() + .collect(); + + for root_set in from_root_set.iter() { + if let Some(leaf_set) = root_set_to_leaf.get_mut(root_set) { + leaf_set.insert(l.to_vec()); + } + } + } + + // Now collect the tree of synthetic functions rooted at any of the roots in + // each root set. + let root_set_to_inline_tree: HashMap>, HashSet>> = root_set_to_leaf + .iter() + .map(|(root_set, leaves)| { + let mut full_tree_set = HashSet::new(); + for root in root_set.iter() { + let mut full_tree = HashSet::new(); + depgraph.get_full_depends_on(&mut full_tree, root); + full_tree_set = full_tree.union(&full_tree_set).cloned().collect(); + } + if full_tree_set.is_empty() { + full_tree_set = leaves.iter().cloned().collect(); + } + (root_set.clone(), full_tree_set) + }) + .collect(); + + for (_, function_set) in root_set_to_inline_tree.iter() { + loop { + let start_metric = metric; + + for f in function_set.iter() { + // Get index of helper identified by this leaf name. + let i = if let Some(i) = helper_to_index.get(f) { + *i + } else { + return Err(CompileErr( + compileform.loc.clone(), + "We have a helper name that has no index?".to_string(), + )); + }; + + // Try flipped. + let old_helper = compileform.helpers[i].clone(); + if !flip_helper(&mut compileform.helpers[i]) { + continue; + } + + let maybe_smaller_program = codegen(context, opts.clone(), &compileform)?; + let new_metric = sexp_scale(&maybe_smaller_program); + + // Don't keep this change if it made things worse. + if new_metric >= metric { + compileform.helpers[i] = old_helper; + } else { + metric = new_metric; + best_compileform = compileform.clone(); + } + } + + if start_metric == metric { + break; + } + } + } + + Ok(best_compileform) +} diff --git a/src/compiler/optimize/depgraph.rs b/src/compiler/optimize/depgraph.rs new file mode 100644 index 000000000..b99256849 --- /dev/null +++ b/src/compiler/optimize/depgraph.rs @@ -0,0 +1,212 @@ +use std::borrow::Borrow; +use std::collections::{HashMap, HashSet}; +use std::rc::Rc; + +use crate::compiler::optimize::SyntheticType; +use crate::compiler::sexp::enlist; +use crate::compiler::srcloc::Srcloc; +use crate::compiler::{BodyForm, CompileForm, DefunData, HelperForm, SExp}; + +#[derive(Debug)] +pub enum DepgraphKind { + UserNonInline, + UserInline, + Synthetic(SyntheticType), +} + +pub struct FunctionDependencyEntry { + pub loc: Srcloc, + pub name: Vec, + pub status: DepgraphKind, + pub depends_on: HashSet>, + pub is_depended_on_by: HashSet>, +} + +impl FunctionDependencyEntry { + pub fn to_sexp(&self) -> Rc { + let depends_on: Vec> = self + .depends_on + .iter() + .map(|x| Rc::new(SExp::Atom(self.loc.clone(), x.clone()))) + .collect(); + + let is_depended_on_by: Vec> = self + .is_depended_on_by + .iter() + .map(|x| Rc::new(SExp::Atom(self.loc.clone(), x.clone()))) + .collect(); + + Rc::new(enlist( + self.loc.clone(), + &[ + Rc::new(SExp::Atom(self.loc.clone(), self.name.clone())), + Rc::new(SExp::Atom( + self.loc.clone(), + format!("{:?}", self.status).as_bytes().to_vec(), + )), + Rc::new(SExp::Atom( + self.loc.clone(), + "depends_on".as_bytes().to_vec(), + )), + Rc::new(enlist(self.loc.clone(), &depends_on)), + Rc::new(SExp::Atom( + self.loc.clone(), + "is_depended_on_by".as_bytes().to_vec(), + )), + Rc::new(enlist(self.loc.clone(), &is_depended_on_by)), + ], + )) + } + + pub fn new(name: &[u8], loc: Srcloc, status: DepgraphKind) -> Self { + FunctionDependencyEntry { + loc, + name: name.to_vec(), + status, + depends_on: HashSet::default(), + is_depended_on_by: HashSet::default(), + } + } +} + +pub struct FunctionDependencyGraph { + pub loc: Srcloc, + pub helpers: HashMap, FunctionDependencyEntry>, +} + +fn status_from_defun(inline: bool, defun: &DefunData) -> DepgraphKind { + match (inline, defun.synthetic.as_ref()) { + (true, None) => DepgraphKind::UserInline, + (false, None) => DepgraphKind::UserNonInline, + (_, Some(st)) => DepgraphKind::Synthetic(st.clone()), + } +} + +impl FunctionDependencyGraph { + /// Find leaf functions. + pub fn leaves(&self) -> HashSet> { + self.helpers + .iter() + .filter(|(_k, h)| h.depends_on.is_empty()) + .map(|(k, _h)| k.clone()) + .collect() + } + + pub fn parents(&self, helper: &[u8]) -> Option>> { + self.helpers.get(helper).map(|h| { + let mut result_set = h.is_depended_on_by.clone(); + result_set.remove(helper); + result_set + }) + } + + pub fn get_full_depended_on_by( + &self, + depended_on_by: &mut HashSet>, + helper_name: &[u8], + ) { + if let Some(helper) = self.helpers.get(helper_name) { + for d in helper.is_depended_on_by.iter() { + if !depended_on_by.contains(d) { + depended_on_by.insert(d.to_vec()); + self.get_full_depended_on_by(depended_on_by, d); + } + } + } + } + + pub fn get_full_depends_on(&self, depends_on_fun: &mut HashSet>, helper_name: &[u8]) { + if let Some(helper) = self.helpers.get(helper_name) { + for d in helper.depends_on.iter() { + if !depends_on_fun.contains(d) { + depends_on_fun.insert(d.clone()); + self.get_full_depends_on(depends_on_fun, d); + } + } + } + } + + fn add_depends_on_relationship(&mut self, helper_name: &[u8], name: &[u8]) { + if !self.helpers.contains_key(helper_name) || !self.helpers.contains_key(name) { + return; + } + + if let Some(function_entry) = self.helpers.get_mut(helper_name) { + function_entry.depends_on.insert(name.to_vec()); + } + + if let Some(function_entry) = self.helpers.get_mut(name) { + function_entry + .is_depended_on_by + .insert(helper_name.to_vec()); + } + } + + fn process_expr(&mut self, helper_name: &[u8], expr: Rc) { + match expr.borrow() { + BodyForm::Value(SExp::Atom(_, name)) => { + // This introduces a function dependency. + self.add_depends_on_relationship(helper_name, name); + } + BodyForm::Value(_) => {} + BodyForm::Let(_, letdata) => { + for b in letdata.bindings.iter() { + self.process_expr(helper_name, b.body.clone()); + } + + self.process_expr(helper_name, letdata.body.clone()); + } + BodyForm::Call(_, args, tail) => { + if let Some(t) = tail.as_ref() { + self.process_expr(helper_name, t.clone()); + } + + for a in args.iter() { + self.process_expr(helper_name, a.clone()); + } + } + BodyForm::Lambda(ldata) => { + self.process_expr(helper_name, ldata.captures.clone()); + self.process_expr(helper_name, ldata.body.clone()); + } + BodyForm::Quoted(_) => {} + BodyForm::Mod(_, _) => {} + } + } + + fn process_helper(&mut self, h: &HelperForm) { + if let HelperForm::Defun(_, defun) = h { + self.process_expr(&defun.name, defun.body.clone()); + } + } + + pub fn new(program: &CompileForm) -> Self { + let mut helpers: HashMap, FunctionDependencyEntry> = HashMap::new(); + + for h in program.helpers.iter() { + if let HelperForm::Defun(inline, d) = h { + helpers.insert( + h.name().to_vec(), + FunctionDependencyEntry::new(h.name(), h.loc(), status_from_defun(*inline, d)), + ); + } + } + + let mut graph = FunctionDependencyGraph { + loc: program.loc.clone(), + helpers, + }; + + for h in program.helpers.iter() { + graph.process_helper(h); + } + + graph + } + + pub fn to_sexp(&self) -> Rc { + let helpers: Vec> = self.helpers.values().map(|v| v.to_sexp()).collect(); + + Rc::new(enlist(self.loc.clone(), &helpers)) + } +} diff --git a/src/compiler/optimize/double_apply.rs b/src/compiler/optimize/double_apply.rs new file mode 100644 index 000000000..013da7d11 --- /dev/null +++ b/src/compiler/optimize/double_apply.rs @@ -0,0 +1,161 @@ +use crate::compiler::clvm::truthy; +use crate::compiler::prims::primquote; +use crate::compiler::sexp::{AtomValue, NodeSel, SExp, SelectNode, ThisNode}; +use std::borrow::Borrow; +use std::rc::Rc; + +// Turn: +// +// (a (q any) 1) +// +// into +// +// any +// +// I now realize this is exactly cons_q_a_optimizer from classic :-) +pub fn change_double_to_single_apply(sexp: Rc) -> (bool, Rc) { + if let Ok(NodeSel::Cons( + _, + NodeSel::Cons( + NodeSel::Cons( + // quoted program + _, + inner_program, + ), + NodeSel::Cons(_, _), + ), + )) = NodeSel::Cons( + AtomValue::Here(&[2]), + NodeSel::Cons( + NodeSel::Cons( + // quoted program + AtomValue::Here(&[1]), + ThisNode::Here, + ), + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here), + ), + ) + .select_nodes(sexp.clone()) + { + return (true, inner_program); + } + + (false, sexp) +} + +fn change_apply_double_quote(sexp: Rc) -> (bool, Rc) { + if let Ok(NodeSel::Cons( + _, // apply + NodeSel::Cons( + NodeSel::Cons( + _, // q + NodeSel::Cons( + _, // 1 + body, + ), + ), + _, + ), + )) = NodeSel::Cons( + AtomValue::Here(&[2]), + NodeSel::Cons( + NodeSel::Cons( + AtomValue::Here(&[1]), + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here), + ), + ThisNode::Here, + ), + ) + .select_nodes(sexp.clone()) + { + return (true, Rc::new(primquote(body.loc(), body.clone()))); + } + + (false, sexp) +} + +fn collapse_constant_condition(sexp: Rc) -> (bool, Rc) { + if let Ok(NodeSel::Cons( + _, // i + NodeSel::Cons(cond, NodeSel::Cons(a, NodeSel::Cons(b, _))), + )) = NodeSel::Cons( + AtomValue::Here(&[3]), + NodeSel::Cons( + ThisNode::Here, + NodeSel::Cons( + ThisNode::Here, + NodeSel::Cons(ThisNode::Here, ThisNode::Here), + ), + ), + ) + .select_nodes(sexp.clone()) + { + // There are two cases here we care about: + // Either cond is () or it's (1 . something) + // The following filters away a non-const condition and leaves + // the remaining as either Some(true) or Some(false), then + // chooses a wing based on that. + return NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here) + .select_nodes(cond.clone()) + .ok() + .map(|NodeSel::Cons(_, cond_quoted)| Some(truthy(cond_quoted))) + .unwrap_or_else(|| if !truthy(cond) { Some(false) } else { None }) + .map(|use_cond| if use_cond { (true, a) } else { (true, b) }) + .unwrap_or_else(|| (false, sexp)); + } + + (false, sexp) +} + +// Recognize some optimizations: +// +// specific: (a (q 1 . x) _) => (q . x) +// classic optimizer: (a (op SEXP) ENV) => (op (a SEXP ENV)) <- wip +// classic optimizer: (a (q SEXP) 1) => SEXP +pub fn remove_double_apply(mut sexp: Rc, spine: bool) -> (bool, Rc) { + // Don't descend into quoted expressions. + if spine { + if let Ok(NodeSel::Cons(_, _)) = + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here).select_nodes(sexp.clone()) + { + return (false, sexp); + } + } + + let mut any_transformation = true; + let mut was_transformed = false; + + while any_transformation { + if let SExp::Cons(l, a, b) = sexp.borrow() { + // These transformations play on each other but finalize together. + let (a_changed, new_a) = remove_double_apply(a.clone(), true); + let (b_changed, new_b) = remove_double_apply(b.clone(), false); + + let result = Rc::new(SExp::Cons(l.clone(), new_a, new_b)); + if spine { + let (root_transformed_dq, result_dq) = change_apply_double_quote(result); + let (root_transformed_unapply, result_single_apply) = + change_double_to_single_apply(result_dq); + + let (constant_collapse, result_end) = + collapse_constant_condition(result_single_apply); + + any_transformation = a_changed + || b_changed + || root_transformed_dq + || root_transformed_unapply + || constant_collapse; + was_transformed |= any_transformation; + sexp = result_end; + } else { + any_transformation = a_changed || b_changed; + was_transformed |= any_transformation; + sexp = result; + } + } else { + break; + } + } + + (was_transformed, sexp) +} diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 7758eb911..38bc2f159 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -1,3 +1,10 @@ +pub mod above22; +pub mod bodyform; +pub mod brief; +pub mod cse; +pub mod deinline; +pub mod depgraph; +pub mod double_apply; pub mod strategy; #[cfg(test)] @@ -17,17 +24,20 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::classic::clvm_tools::stages::stage_2::optimize::optimize_sexp; use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs, run}; -use crate::compiler::codegen::{codegen, get_callable}; +use crate::compiler::codegen::{codegen, do_mod_codegen, get_callable}; use crate::compiler::comptypes::{ BodyForm, CallSpec, Callable, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, SyntheticType, }; -use crate::compiler::evaluate::{build_reflex_captures, Evaluator, EVAL_STACK_LIMIT}; +use crate::compiler::evaluate::{ + build_reflex_captures, dequote, is_i_atom, is_not_atom, Evaluator, EVAL_STACK_LIMIT, +}; +use crate::compiler::optimize::above22::Strategy23; use crate::compiler::optimize::strategy::ExistingStrategy; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::SExp; #[cfg(test)] -use crate::compiler::sexp::{enlist, parse_sexp}; +use crate::compiler::sexp::parse_sexp; +use crate::compiler::sexp::{AtomValue, NodeSel, SExp, SelectNode, ThisNode}; use crate::compiler::srcloc::Srcloc; use crate::compiler::BasicCompileContext; use crate::compiler::CompileContextWrapper; @@ -196,28 +206,51 @@ fn test_sexp_scale_increases_with_atom_size() { ); } -#[test] -fn test_sexp_scale_increases_with_list_of_atoms() { - let l = Srcloc::start("*test*"); - let one_atom = Rc::new(SExp::Integer(l.clone(), bi_one())); - let target_scale = 4 + 3 * sexp_scale(one_atom.borrow()); - let list_of_atom = enlist( - l.clone(), - &[one_atom.clone(), one_atom.clone(), one_atom.clone()], - ); - assert_eq!(target_scale, sexp_scale(&list_of_atom)); +fn is_not_condition(bf: &BodyForm) -> Option> { + // Checking for a primitive so no tail. + if let BodyForm::Call(_, parts, None) = bf { + if parts.len() != 2 { + return None; + } + + if is_not_atom(parts[0].to_sexp()) { + return Some(parts[1].clone()); + } + } + + None } /// Changes (i (not c) a b) into (i c b a) fn condition_invert_optimize( opts: Rc, - _loc: &Srcloc, - _forms: &[Rc], + loc: &Srcloc, + forms: &[Rc], ) -> Option { if let Some(res) = opts.dialect().stepping { - // Only perform on chialisp above stepping 23. - if res < 23 { - return None; + // Only perform on chialisp above the appropriate stepping. + if res >= 23 { + if forms.len() != 4 { + return None; + } + + if !is_i_atom(forms[0].to_sexp()) { + return None; + } + + // We have a (not cond) + if let Some(condition) = is_not_condition(forms[1].borrow()) { + return Some(BodyForm::Call( + loc.clone(), + vec![ + forms[0].clone(), + condition, + forms[3].clone(), + forms[2].clone(), + ], + None, + )); + } } } @@ -229,15 +262,115 @@ fn condition_invert_optimize( /// /// The result is the constant result of invoking the function. fn constant_fun_result( - _allocator: &mut Allocator, + allocator: &mut Allocator, opts: Rc, - _runner: Rc, - _compiler: &PrimaryCodegen, - _call_spec: &CallSpec, + runner: Rc, + compiler: &PrimaryCodegen, + call_spec: &CallSpec, ) -> Option> { if let Some(res) = opts.dialect().stepping { - if res < 23 { - return None; + if res >= 23 { + let mut constant = true; + let optimized_args: Vec<(bool, Rc)> = call_spec + .args + .iter() + .skip(1) + .map(|a| { + let optimized = + optimize_expr(allocator, opts.clone(), runner.clone(), compiler, a.clone()); + constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); + optimized + .map(|x| (x.0, x.1)) + .unwrap_or_else(|| (false, a.clone())) + }) + .collect(); + + let optimized_tail: Option<(bool, Rc)> = call_spec.tail.as_ref().map(|t| { + let optimized = + optimize_expr(allocator, opts.clone(), runner.clone(), compiler, t.clone()); + constant = constant && optimized.as_ref().map(|x| x.0).unwrap_or_else(|| false); + optimized + .map(|x| (x.0, x.1)) + .unwrap_or_else(|| (false, t.clone())) + }); + + if !constant { + return None; + } + + let compiled_body = { + let to_compile = CompileForm { + loc: call_spec.loc.clone(), + include_forms: Vec::new(), + helpers: compiler.original_helpers.clone(), + args: Rc::new(SExp::Atom(call_spec.loc.clone(), b"__ARGS__".to_vec())), + exp: Rc::new(BodyForm::Call( + call_spec.loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), + Rc::new(BodyForm::Value(SExp::Atom( + call_spec.loc.clone(), + call_spec.name.to_vec(), + ))), + Rc::new(BodyForm::Value(SExp::Atom( + call_spec.loc.clone(), + b"__ARGS__".to_vec(), + ))), + ], + // Proper call: we're calling 'a' on behalf of our + // single capture argument. + None, + )), + }; + let optimizer = if let Ok(res) = get_optimizer(&call_spec.loc, opts.clone()) { + res + } else { + return None; + }; + + let mut symbols = HashMap::new(); + let mut wrapper = + CompileContextWrapper::new(allocator, runner.clone(), &mut symbols, optimizer); + + if let Ok(code) = codegen(&mut wrapper.context, opts.clone(), &to_compile) { + code + } else { + return None; + } + }; + + // Reified args reflect the actual ABI shape with a tail if any. + let mut reified_args = if let Some((_, t)) = optimized_tail { + if let Ok(res) = dequote(call_spec.loc.clone(), t) { + res + } else { + return None; + } + } else { + Rc::new(SExp::Nil(call_spec.loc.clone())) + }; + for (_, v) in optimized_args.iter().rev() { + let unquoted = if let Ok(res) = dequote(call_spec.loc.clone(), v.clone()) { + res + } else { + return None; + }; + reified_args = Rc::new(SExp::Cons(call_spec.loc.clone(), unquoted, reified_args)); + } + let borrowed_args: &SExp = reified_args.borrow(); + let new_body = BodyForm::Call( + call_spec.loc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(call_spec.loc.clone(), vec![2]))), + Rc::new(BodyForm::Quoted(compiled_body)), + Rc::new(BodyForm::Quoted(borrowed_args.clone())), + ], + // The constructed call is proper because we're feeding something + // we constructed above. + None, + ); + + return Some(Rc::new(new_body)); } } @@ -387,10 +520,31 @@ pub fn optimize_expr( true, Rc::new(BodyForm::Quoted(SExp::Integer(l.clone(), i.clone()))), )), - BodyForm::Mod(_l, _cf) => { + BodyForm::Mod(l, cf) => { if let Some(stepping) = opts.dialect().stepping { - if stepping < 23 { - return None; + if stepping >= 23 { + let mut throwaway_symbols = HashMap::new(); + if let Ok(optimizer) = get_optimizer(l, opts.clone()) { + let mut wrapper = CompileContextWrapper::new( + allocator, + runner, + &mut throwaway_symbols, + optimizer, + ); + if let Ok(compiled) = do_mod_codegen(&mut wrapper.context, opts.clone(), cf) + { + if let Ok(NodeSel::Cons(_, body)) = + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here) + .select_nodes(compiled.1) + { + let borrowed_body: &SExp = body.borrow(); + return Some(( + true, + Rc::new(BodyForm::Quoted(borrowed_body.clone())), + )); + } + } + } } } @@ -569,7 +723,7 @@ fn fe_opt( }) } -fn run_optimizer( +pub fn run_optimizer( allocator: &mut Allocator, runner: Rc, r: Rc, @@ -602,11 +756,13 @@ pub fn get_optimizer( loc.clone(), format!("minimum language stepping is 21, {s} specified"), )); - } else if s > 22 { + } else if s > 23 { return Err(CompileErr( loc.clone(), - format!("maximum language stepping is 22 at this time, {s} specified"), + format!("maximum language stepping is 23 at this time, {s} specified"), )); + } else if s == 23 && opts.optimize() { + return Ok(Box::new(Strategy23::new())); } } @@ -620,8 +776,7 @@ pub fn maybe_finalize_program_via_classic_optimizer( runner: Rc, _opts: Rc, // Currently unused but I want this interface // to consider opts in the future when required. - opt_flag: bool, // Command line flag and other features control this in oldest - // versions + opt_flag: bool, // Command line flag and other features control this in oldest- // versions unopt_res: &SExp, ) -> Result, CompileErr> { if opt_flag { diff --git a/src/compiler/optimize/strategy.rs b/src/compiler/optimize/strategy.rs index 9b7ecd6d9..7ea7ef668 100644 --- a/src/compiler/optimize/strategy.rs +++ b/src/compiler/optimize/strategy.rs @@ -9,9 +9,9 @@ use crate::classic::clvm_tools::stages::stage_0::TRunProgram; use crate::compiler::comptypes::{ BodyForm, CompileErr, CompileForm, CompilerOpts, DefunData, HelperForm, PrimaryCodegen, }; +use crate::compiler::optimize::deinline::deinline_opt; use crate::compiler::optimize::{ - deinline_opt, fe_opt, null_optimization, optimize_expr, run_optimizer, CompileContextWrapper, - Optimization, + fe_opt, null_optimization, optimize_expr, run_optimizer, CompileContextWrapper, Optimization, }; use crate::compiler::sexp::SExp; use crate::compiler::StartOfCodegenOptimization; diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 605bf48d0..905fba87e 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -1015,6 +1015,10 @@ pub enum Atom { Here(T), } +pub enum AtomValue { + Here(T), +} + pub trait SelectNode { fn select_nodes(&self, s: Rc) -> Result; } @@ -1048,6 +1052,61 @@ impl SelectNode for Atom<&str> { } } +impl SelectNode for AtomValue<&[u8; N]> { + fn select_nodes(&self, s: Rc) -> Result { + let AtomValue::Here(name) = self; + match s.borrow() { + SExp::Nil(l) => { + if name.is_empty() { + return Ok(l.clone()); + } + } + SExp::Atom(l, n) => { + if n == name { + return Ok(l.clone()); + } + } + SExp::QuotedString(l, _, n) => { + if n == name { + return Ok(l.clone()); + } + } + SExp::Integer(l, i) => { + if &u8_from_number(i.clone()) == name { + return Ok(l.clone()); + } + } + _ => {} + } + + Err((s.loc(), format!("Not an atom with content {name:?}"))) + } +} + +impl SelectNode<(Srcloc, Vec), (Srcloc, String)> for AtomValue<()> { + fn select_nodes(&self, s: Rc) -> Result<(Srcloc, Vec), (Srcloc, String)> { + let AtomValue::Here(name) = self; + match s.borrow() { + SExp::Nil(l) => { + return Ok((l.clone(), vec![])); + } + SExp::Atom(l, n) => { + return Ok((l.clone(), n.clone())); + } + SExp::QuotedString(l, _, n) => { + return Ok((l.clone(), n.clone())); + } + SExp::Integer(l, i) => { + let u8_vec = u8_from_number(i.clone()); + return Ok((l.clone(), u8_vec)); + } + _ => {} + } + + Err((s.loc(), format!("Not an atom with content {name:?}"))) + } +} + impl SelectNode<(), E> for () { fn select_nodes(&self, _n: Rc) -> Result<(), E> { Ok(()) From af7644882c45c46523bf8aa9c19679f151e2dd40 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 19 Oct 2023 11:22:57 -0700 Subject: [PATCH 02/48] Bring in some tests, test data --- Cargo.lock | 45 +++ Cargo.toml | 1 + .../tests/strict/cse-complex-1-lambda.clsp | 33 ++ resources/tests/strict/cse-test-no-dom.clsp | 23 ++ resources/tests/strict/csecond.clsp | 33 ++ resources/tests/strict/test_atomsort.clsp | 5 + resources/tests/test_assign_path_opt.clsp | 8 + resources/tests/test_recursion_subexp.clsp | 10 + resources/tests/test_user_path_opt_0.clsp | 5 + src/tests/compiler/mod.rs | 1 + src/tests/compiler/optimizer/bodyform.rs | 316 +++++++++++++++ src/tests/compiler/optimizer/cse.rs | 192 +++++++++ src/tests/compiler/optimizer/depgraph.rs | 68 ++++ src/tests/compiler/optimizer/mod.rs | 4 + src/tests/compiler/optimizer/output.rs | 381 ++++++++++++++++++ 15 files changed, 1125 insertions(+) create mode 100644 resources/tests/strict/cse-complex-1-lambda.clsp create mode 100644 resources/tests/strict/cse-test-no-dom.clsp create mode 100644 resources/tests/strict/csecond.clsp create mode 100644 resources/tests/strict/test_atomsort.clsp create mode 100644 resources/tests/test_assign_path_opt.clsp create mode 100644 resources/tests/test_recursion_subexp.clsp create mode 100644 resources/tests/test_user_path_opt_0.clsp create mode 100644 src/tests/compiler/optimizer/bodyform.rs create mode 100644 src/tests/compiler/optimizer/cse.rs create mode 100644 src/tests/compiler/optimizer/depgraph.rs create mode 100644 src/tests/compiler/optimizer/mod.rs create mode 100644 src/tests/compiler/optimizer/output.rs diff --git a/Cargo.lock b/Cargo.lock index ca77d6836..563a70902 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -139,6 +148,7 @@ dependencies = [ "pyo3-build-config 0.15.2", "rand", "rand_chacha", + "regex", "serde", "serde_json", "sha2 0.9.9", @@ -505,6 +515,12 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + [[package]] name = "num" version = "0.4.1" @@ -828,6 +844,35 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "rfc6979" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 6fd6b6888..a7d03a6ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ binascii = "0.1.4" yaml-rust = "0.4" linked-hash-map = "0.5.6" serde = { version = "1.0", features = ["derive", "rc"] } +regex = "1.8.4" [dependencies.pyo3] version = "0.14.2" diff --git a/resources/tests/strict/cse-complex-1-lambda.clsp b/resources/tests/strict/cse-complex-1-lambda.clsp new file mode 100644 index 000000000..7e2c62202 --- /dev/null +++ b/resources/tests/strict/cse-complex-1-lambda.clsp @@ -0,0 +1,33 @@ +(mod (X) + (include *standard-cl-23*) + + (defun mess (X) ;; 11 41 + (assign + Y (+ X 1) ;; 12 42 + Z (+ Y 2) ;; 14 44 + + (if (> X 10) + (lambda ((& X Y Z) Q) + (if (= X 11) + (assign + Y (* X 2) ;; 22 82 + Z (+ Y 1) ;; 23 83 + + (* Q Y Z) ;; 11 * 22 * 23 = 506 + ) + + (assign + Y (* X 3) ;; 33 123 + Z (+ Y 2) ;; 35 125 + + (* Q Y Z) ;; 41 * 123 * 125 = 630375 + ) + ) + ) + (lambda ((& Y Z) Q) (* Q Y Z)) ;; 5 * 6 * 8 + ) + ) + ) + + (a (mess X) (list X)) + ) diff --git a/resources/tests/strict/cse-test-no-dom.clsp b/resources/tests/strict/cse-test-no-dom.clsp new file mode 100644 index 000000000..32758101d --- /dev/null +++ b/resources/tests/strict/cse-test-no-dom.clsp @@ -0,0 +1,23 @@ +(mod (X) + (include *standard-cl-23*) + + (defun S (C) + (if C + (assign-lambda + Z (f (f C)) + Y (r (f C)) + R (r C) + (if (= Z 2) + (if (= 1 (f Y)) + (r Y) + (S R) + ) + (S R) + ) + ) + () + ) + ) + + (S X) + ) diff --git a/resources/tests/strict/csecond.clsp b/resources/tests/strict/csecond.clsp new file mode 100644 index 000000000..6d82de756 --- /dev/null +++ b/resources/tests/strict/csecond.clsp @@ -0,0 +1,33 @@ +(mod (X) + (include *standard-cl-23*) + + (defun asort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (if (> first second) + (if (> first third) + "test1" + (if (> second third) + "test2" + "test3" + ) + ) + (if (> first second) + "test4" + "test5" + ) + ) + (if (> first second) + "test6" + "test7" + ) + ) + firstpos + ) + 0 + ) + ) + + (asort X) + ) diff --git a/resources/tests/strict/test_atomsort.clsp b/resources/tests/strict/test_atomsort.clsp new file mode 100644 index 000000000..229c4275e --- /dev/null +++ b/resources/tests/strict/test_atomsort.clsp @@ -0,0 +1,5 @@ +(mod (X) + (include *standard-cl-23*) + (include atomsort.clinc) + (atomsort X) + ) diff --git a/resources/tests/test_assign_path_opt.clsp b/resources/tests/test_assign_path_opt.clsp new file mode 100644 index 000000000..81072f2ee --- /dev/null +++ b/resources/tests/test_assign_path_opt.clsp @@ -0,0 +1,8 @@ +(mod (Z) + (include *strict-cl-21*) + (defun F (X) (* X 5)) + (assign + (_0 _1 _2 _3 _4 (_50 (_51 _52 _53 Q))) Z + (F Q) + ) + ) diff --git a/resources/tests/test_recursion_subexp.clsp b/resources/tests/test_recursion_subexp.clsp new file mode 100644 index 000000000..4fdac1fbb --- /dev/null +++ b/resources/tests/test_recursion_subexp.clsp @@ -0,0 +1,10 @@ +(mod (Q R) + (include *standard-cl-23*) + (defun G (Q R) + (if Q + (G (- Q 1) (* (+ 1 Q) R)) + (* (+ 1 Q) R) + ) + ) + (G Q R) + ) diff --git a/resources/tests/test_user_path_opt_0.clsp b/resources/tests/test_user_path_opt_0.clsp new file mode 100644 index 000000000..2a5a15c89 --- /dev/null +++ b/resources/tests/test_user_path_opt_0.clsp @@ -0,0 +1,5 @@ +(mod (Q) + (include *strict-cl-21*) + (defun F (X) (f (f (f (f (f (f (r X)))))))) + (F Q) + ) diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index f7e502ead..a3098ce49 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -9,6 +9,7 @@ mod cldb; mod clvm; mod compiler; mod evaluate; +mod optimizer; mod preprocessor; mod repl; mod restargs; diff --git a/src/tests/compiler/optimizer/bodyform.rs b/src/tests/compiler/optimizer/bodyform.rs new file mode 100644 index 000000000..bb09b500d --- /dev/null +++ b/src/tests/compiler/optimizer/bodyform.rs @@ -0,0 +1,316 @@ +use std::borrow::Borrow; +use std::rc::Rc; + +use regex::Regex; + +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::{BodyForm, CompileForm, CompilerOpts}; +use crate::compiler::frontend::{compile_bodyform, frontend}; +use crate::compiler::optimize::bodyform::{ + replace_in_bodyform, retrieve_bodyform, visit_detect_in_bodyform, BodyformPathArc, + PathDetectVisitorResult, +}; +use crate::compiler::sexp::parse_sexp; +use crate::compiler::srcloc::Srcloc; + +#[test] +fn test_bodyform_simple_traversal_0() { + let progfile = "*test*"; + let srcloc = Srcloc::start(progfile); + let parsed = parse_sexp( + srcloc, + indoc! {" +(mod () + (call1 + (let ((A 99) (B test)) (+ A B)) + (call2 + (mod () z) + (lambda () r) + ) + (call3 9) + ) + )"} + .bytes(), + ) + .expect("should parse"); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(progfile)); + let compiled = frontend(opts.clone(), &parsed).expect("should fe"); + + let tests: &[(Vec, Option<&str>)] = &[ + ( + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::LetBinding(0), + ], + Some(r"99"), + ), + ( + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(1), + ], + Some(r"\(mod \(\) z\)"), + ), + ( + vec![BodyformPathArc::CallArgument(1), BodyformPathArc::BodyOf], + Some(r"\([+] A_[$]_[0-9]+ B_[$]_[0-9]+\)"), + ), + ( + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::LetBinding(10), + ], + None, + ), + ( + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::BodyOf, + BodyformPathArc::BodyOf, + ], + None, + ), + ]; + for (traversal1, want) in tests.iter() { + let retrieved1 = retrieve_bodyform(&traversal1, compiled.exp.borrow(), &|b| b.clone()); + if let Some(r) = want { + let re = Regex::new(r).unwrap(); + assert!(re.is_match(&retrieved1.unwrap().to_sexp().to_string())); + } else { + assert!(retrieved1.is_none()); + } + } +} + +#[test] +fn test_replace_in_bodyform() { + let progfile = "*test*"; + let srcloc = Srcloc::start(progfile); + let parsed = parse_sexp( + srcloc.clone(), + indoc! {" +(mod () + (call1 + (let ((A 99) (B test)) (+ A B)) + (call2 + (mod () z) + (lambda () r) + ) + (call3 9) + ) + )"} + .bytes(), + ) + .expect("should parse"); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(progfile)); + let compiled = frontend(opts.clone(), &parsed).expect("should fe"); + let compile_body = |b: &str| { + let new_parsed = parse_sexp(srcloc.clone(), b.bytes()).unwrap(); + compile_bodyform(opts.clone(), new_parsed[0].clone()).unwrap() + }; + + // replacement-list, replace_with, expect + let tests: &[(Vec, &str, Option<&str>)] = &[ + ( + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::BodyOf, + BodyformPathArc::CallArgument(2), + ], + "()", + Some( + r"(call1 (let ((A_[$]_[0-9]+ 99) (B_[$]_[0-9]+ test)) ([+] A_[$]_[0-9]+ ())) (call2 (mod () z) (lambda () r)) (call3 9))", + ), + ), + ( + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::LetBinding(1), + ], + "()", + Some( + r"(call1 (let ((A_[$]_[0-9]+ 99) (B_[$]_[0-9]+ ())) ([+] A_[$]_[0-9]+ B_[$]_[0-9]+)) (call2 (mod () z) (lambda () r)) (call3 9))", + ), + ), + ( + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(1), + BodyformPathArc::BodyOf, + ], + "()", + Some( + r"(call1 (let ((A_[$]_[0-9]+ 99) (B_[$]_[0-9]+ test)) ([+] A_[$]_[0-9]+ B_[$]_[0-9]+)) (call2 (mod () ()) (lambda () r)) (call3 9))", + ), + ), + ( + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(2), + BodyformPathArc::BodyOf, + ], + "()", + Some( + r"(call1 (let ((A_[$]_[0-9]+ 99) (B_[$]_[0-9]+ test)) ([+] A_[$]_[0-9]+ B_[$]_[0-9]+)) (call2 (mod () z) (lambda () ())) (call3 9))", + ), + ), + ]; + + for (path, replacement, expect) in tests.iter() { + eprintln!("replacement {replacement}"); + let replace_spec = vec![PathDetectVisitorResult { + path: path.clone(), + subexp: compile_body(*replacement), + context: (), + }]; + let replaced = replace_in_bodyform( + &replace_spec, + compiled.exp.borrow(), + &|spec: &PathDetectVisitorResult<()>, _old: &BodyForm| spec.subexp.clone(), + ); + if let Some(r) = expect { + let got = replaced.unwrap().to_sexp().to_string(); + eprintln!("got {got}"); + eprintln!("want {r}"); + let escaped_re = r.replace("(", r"\(").replace(")", r"\)"); + let re = Regex::new(&escaped_re).unwrap(); + assert!(re.is_match(&got)); + } else { + assert!(replaced.is_none()); + } + } +} + +fn make_test_case_for_visitor(program: &str) -> CompileForm { + let progfile = "*test*"; + let srcloc = Srcloc::start(progfile); + let parsed = parse_sexp(srcloc.clone(), program.bytes()).expect("should parse"); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(progfile)); + frontend(opts.clone(), &parsed).expect("should fe") +} + +#[test] +fn test_visitor_0() { + let compiled = make_test_case_for_visitor(indoc! {" +(mod () + (call1 + (let ((A 99) (B test)) (+ A B)) + (call2 + (mod () z) + (lambda () r) + ) + (call3 9) + ) + )"}); + let res = visit_detect_in_bodyform( + &|_path, _orig, _here| { + let e: Result, ()> = Err(()); + e + }, + compiled.exp.borrow(), + ); + assert!(res.is_err()); + let res = visit_detect_in_bodyform( + &|_path, _orig, here| { + if here.to_sexp().to_string() == "z" { + let res: Result, ()> = Ok(Some(())); + return res; + } + Ok(None) + }, + compiled.exp.borrow(), + ) + .unwrap(); + assert_eq!(res.len(), 1); + assert_eq!(res[0].subexp.to_sexp().to_string(), "z"); + assert_eq!( + res[0].path, + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(1), + BodyformPathArc::BodyOf + ] + ); + let res = visit_detect_in_bodyform( + &|_path, _orig, here| { + if here.to_sexp().to_string() == "r" || here.to_sexp().to_string() == "99" { + let res: Result, ()> = Ok(Some(())); + return res; + } + Ok(None) + }, + compiled.exp.borrow(), + ) + .unwrap(); + assert_eq!(res.len(), 2); + assert_eq!(res[0].subexp.to_sexp().to_string(), "99"); + assert_eq!( + res[0].path, + vec![ + BodyformPathArc::CallArgument(1), + BodyformPathArc::LetBinding(0) + ] + ); + assert_eq!(res[1].subexp.to_sexp().to_string(), "r"); + assert_eq!( + res[1].path, + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(2), + BodyformPathArc::BodyOf + ] + ); +} + +#[test] +fn test_visitor_rest_alone() { + let compiled = make_test_case_for_visitor(indoc! {" + (mod (X) + (F &rest X) + ) + "}); + let res = visit_detect_in_bodyform( + &|_path, _orig, here| { + if here.to_sexp().to_string() == "X" { + let res: Result, ()> = Ok(Some(())); + return res; + } + + Ok(None) + }, + compiled.exp.borrow(), + ) + .unwrap(); + assert_eq!(res.len(), 1); + assert_eq!(res[0].path, vec![BodyformPathArc::CallArgument(1)]); +} + +#[test] +fn test_visitor_rest_with_list() { + let compiled = make_test_case_for_visitor(indoc! {" + (mod (X) + (F X &rest (F &rest X)) + ) + "}); + let res = visit_detect_in_bodyform( + &|_path, _orig, here| { + if here.to_sexp().to_string() == "X" { + let res: Result, ()> = Ok(Some(())); + return res; + } + + Ok(None) + }, + compiled.exp.borrow(), + ) + .unwrap(); + assert_eq!(res.len(), 2); + assert_eq!(res[0].path, vec![BodyformPathArc::CallArgument(1)]); + assert_eq!( + res[1].path, + vec![ + BodyformPathArc::CallArgument(2), + BodyformPathArc::CallArgument(1) + ] + ); +} diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs new file mode 100644 index 000000000..d000b92ea --- /dev/null +++ b/src/tests/compiler/optimizer/cse.rs @@ -0,0 +1,192 @@ +use std::rc::Rc; + +use regex::Regex; + +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::CompilerOpts; +use crate::compiler::frontend::compile_bodyform; +use crate::compiler::optimize::cse::cse_optimize_bodyform; +use crate::compiler::sexp::parse_sexp; +use crate::compiler::srcloc::Srcloc; + +use crate::tests::classic::run::{do_basic_brun, do_basic_run}; + +#[test] +fn smoke_test_cse_optimization() { + let filename = "*test*"; + let source = indoc! {" + (a (i Q + (com (G (- Q 1) (* (+ 1 Q) R))) + (com (* (+ 1 Q) R)) + ) 1)"} + .to_string(); + let srcloc = Srcloc::start(filename); + let opts: Rc = Rc::new(DefaultCompilerOpts::new(filename)); + let parsed = parse_sexp(srcloc.clone(), source.bytes()).expect("should parse"); + let bodyform = compile_bodyform(opts.clone(), parsed[0].clone()).expect("should compile"); + let cse_transformed = + cse_optimize_bodyform(&srcloc, b"test", &bodyform).expect("should cse optimize"); + let re_def = r"(let ((cse_[$]_[0-9]+ ([*] ([+] 1 Q) R))) (a (i Q (com (G (- Q 1) cse_[$]_[0-9]+)) (com cse_[$]_[0-9]+)) 1))".replace("(", r"\(").replace(")",r"\)"); + eprintln!("re_def {re_def}"); + let re = Regex::new(&re_def).expect("should become a regex"); + assert!(re.is_match(&cse_transformed.to_sexp().to_string())); +} + +#[test] +fn test_cse_tricky() { + let filename = "resources/tests/strict/cse-complex-1.clsp"; + let program = do_basic_run(&vec!["run".to_string(), filename.to_string()]) + .trim() + .to_string(); + + let run_result_11 = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(11)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(run_result_11, "506"); + + let run_result_41 = do_basic_brun(&vec!["brun".to_string(), program, "(41)".to_string()]) + .trim() + .to_string(); + assert_eq!(run_result_41, "15375"); +} + +#[test] +fn test_cse_tricky_lambda() { + let filename = "resources/tests/strict/cse-complex-1-lambda.clsp"; + let program = do_basic_run(&vec!["run".to_string(), filename.to_string()]) + .trim() + .to_string(); + + let run_result_11 = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(11)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(run_result_11, "5566"); + + let run_result_41 = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(41)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(run_result_41, "0x099e67"); + + let run_result_5 = do_basic_brun(&vec!["brun".to_string(), program, "(5)".to_string()]) + .trim() + .to_string(); + assert_eq!(run_result_5, "240"); +} + +// Ensure that we're sorting CSE rounds to apply by dominance so we do inner +// replacements before outer ones. Any that aren't dominated don't have an +// order that matters. +#[test] +fn test_cse_dominance_sorting() { + let filename = "resources/tests/strict/cse-test-no-dom.clsp"; + let program = do_basic_run(&vec!["run".to_string(), filename.to_string()]) + .trim() + .to_string(); + let run_result = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program, + "(((3 3) (2 1 13 19) (5 5) (7 7)))".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(run_result, "(13 19)"); +} + +// Test out atomsort from bram's chialisp +#[test] +fn test_atomsort_bad_ref_simplified() { + let filename = "resources/tests/strict/csecond.clsp"; + + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + filename.to_string(), + ]) + .trim() + .to_string(); + + let run_result = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program, + "((99 101 103))".to_string(), + ]) + .trim() + .to_string(); + + // Expect test5 + assert_eq!(run_result, "\"test5\""); +} + +#[test] +fn test_atomsort_bad_ref() { + let filename = "resources/tests/strict/test_atomsort.clsp"; + + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + filename.to_string(), + ]) + .trim() + .to_string(); + + let run_result_empty = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program.clone(), + "(())".to_string(), + ]) + .trim() + .to_string(); + + // Expect a sorted list, descending order. + assert_eq!(run_result_empty, "()"); + + let run_result_one_item = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program.clone(), + "((0x100001))".to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(run_result_one_item, "(0x100001)"); + + let run_result_two_items = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program.clone(), + "((0x100001 0x100002))".to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(run_result_two_items, "(0x100002 0x100001)"); + + let run_result_three_items = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program, + "((0x100001 0x100003 0x100002))".to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(run_result_three_items, "(0x100003 0x100002 0x100001)"); +} diff --git a/src/tests/compiler/optimizer/depgraph.rs b/src/tests/compiler/optimizer/depgraph.rs new file mode 100644 index 000000000..977762caa --- /dev/null +++ b/src/tests/compiler/optimizer/depgraph.rs @@ -0,0 +1,68 @@ +use std::collections::HashSet; + +use crate::compiler::compiler::DefaultCompilerOpts; +use crate::compiler::comptypes::CompilerOpts; +use crate::compiler::dialect::AcceptedDialect; +use crate::compiler::frontend::frontend; +use crate::compiler::optimize::depgraph::FunctionDependencyGraph; +use crate::compiler::sexp::parse_sexp; +use crate::compiler::srcloc::Srcloc; + +fn get_depgraph_for_program(prog: &str) -> FunctionDependencyGraph { + let filename = "*test*"; + let forms = parse_sexp(Srcloc::start(filename), prog.bytes()).expect("should parse"); + let opts = DefaultCompilerOpts::new(filename).set_dialect(AcceptedDialect { + stepping: Some(21), + strict: true, + }); + let compileform = frontend(opts.clone(), &forms).expect("should frontend"); + + FunctionDependencyGraph::new(&compileform) +} + +#[test] +fn test_dependency_graph_smoke() { + let depgraph = get_depgraph_for_program(indoc! {" + (mod (X) + (include *strict-cl-21*) + + (defun DependedOnByFGAndH (X) (+ 1 X)) + + (defun F (X) (DependedOnByFGAndH X)) + + (defun H (X) (+ (G X) (* X 2))) + + (defun G (X) (DependedOnByFGAndH X)) + + (+ (F X) (G X) (H X)) + ) + "}); + + let mut depended_on_by = HashSet::default(); + depgraph.get_full_depended_on_by(&mut depended_on_by, b"DependedOnByFGAndH"); + + let want_depended_on_by_set: HashSet> = [b"F".to_vec(), b"G".to_vec(), b"H".to_vec()] + .iter() + .cloned() + .collect(); + assert_eq!(want_depended_on_by_set, depended_on_by); + + let mut g_depended_on_by = HashSet::default(); + depgraph.get_full_depended_on_by(&mut g_depended_on_by, b"G"); + let want_g_depended_on_by_set = [b"H".to_vec()].iter().cloned().collect(); + assert_eq!(g_depended_on_by, want_g_depended_on_by_set); + + let mut f_depends_on = HashSet::default(); + depgraph.get_full_depends_on(&mut f_depends_on, b"F"); + let want_f_depends_on_set = [b"DependedOnByFGAndH".to_vec()].iter().cloned().collect(); + assert_eq!(f_depends_on, want_f_depends_on_set); + + let mut h_depends_on = HashSet::default(); + depgraph.get_full_depends_on(&mut h_depends_on, b"H"); + + let want_h_depends_on_set = [b"DependedOnByFGAndH".to_vec(), b"G".to_vec()] + .iter() + .cloned() + .collect(); + assert_eq!(h_depends_on, want_h_depends_on_set); +} diff --git a/src/tests/compiler/optimizer/mod.rs b/src/tests/compiler/optimizer/mod.rs new file mode 100644 index 000000000..5b41e594b --- /dev/null +++ b/src/tests/compiler/optimizer/mod.rs @@ -0,0 +1,4 @@ +mod bodyform; +mod cse; +mod depgraph; +mod output; diff --git a/src/tests/compiler/optimizer/output.rs b/src/tests/compiler/optimizer/output.rs new file mode 100644 index 000000000..0c2b1ba78 --- /dev/null +++ b/src/tests/compiler/optimizer/output.rs @@ -0,0 +1,381 @@ +use std::collections::HashMap; +use std::fs; +use std::rc::Rc; + +use clvm_rs::allocator::Allocator; + +use crate::classic::clvm::sexp::sexp_as_bin; +use crate::classic::clvm_tools::stages::stage_0::{ + DefaultProgramRunner, RunProgramOption, TRunProgram, +}; +use crate::compiler::clvm::{convert_from_clvm_rs, convert_to_clvm_rs}; +use crate::compiler::compiler::{compile_file, DefaultCompilerOpts}; +use crate::compiler::comptypes::{CompileErr, CompilerOpts}; +use crate::compiler::dialect::AcceptedDialect; +use crate::compiler::runtypes::RunFailure; +use crate::compiler::sexp::{parse_sexp, SExp}; +use crate::compiler::srcloc::Srcloc; + +const MAX_RUN_COST: u64 = 1000000; + +#[derive(Debug)] +struct CompileRunResult { + pub compiled: Rc, + pub compiled_hex: String, + pub run_result: Rc, +} + +#[derive(Debug)] +struct OptRunResult { + unopt: CompileRunResult, + opt: CompileRunResult, +} + +fn run_with_cost( + allocator: &mut Allocator, + runner: Rc, + sexp: Rc, + env: Rc, +) -> Result { + let as_classic_program = convert_to_clvm_rs(allocator, sexp.clone())?; + let as_classic_env = convert_to_clvm_rs(allocator, env.clone())?; + let compiled_hex = sexp_as_bin(allocator, as_classic_program).hex(); + runner + .run_program( + allocator, + as_classic_program, + as_classic_env, + Some(RunProgramOption { + max_cost: Some(MAX_RUN_COST), + pre_eval_f: None, + strict: false, + }), + ) + .map_err(|e| RunFailure::RunErr(sexp.loc(), format!("{} in {} {}", e.1, sexp, env))) + .and_then(|reduction| { + Ok(CompileRunResult { + compiled: sexp.clone(), + compiled_hex, + run_result: convert_from_clvm_rs(allocator, sexp.loc(), reduction.1)?, + }) + }) +} + +#[derive(Clone, Debug)] +struct OptimizationRunSpec { + dialect: AcceptedDialect, + optimize: bool, + fe_opt: bool, +} + +fn run_string_get_program_and_output_dialect( + content: &str, + args: &str, + include_dirs: &[String], + spec: OptimizationRunSpec, +) -> Result { + let mut allocator = Allocator::new(); + let runner = Rc::new(DefaultProgramRunner::new()); + let mut opts: Rc = Rc::new(DefaultCompilerOpts::new(&"*test*".to_string())); + let srcloc = Srcloc::start(&"*test*".to_string()); + opts = opts + .set_optimize(spec.optimize) + .set_frontend_opt(spec.fe_opt) + .set_dialect(spec.dialect) + .set_search_paths(include_dirs); + let sexp_args = + parse_sexp(srcloc.clone(), args.bytes()).map_err(|e| CompileErr(e.0, e.1))?[0].clone(); + + compile_file( + &mut allocator, + runner.clone(), + opts, + &content, + &mut HashMap::new(), + ) + .and_then(|program| { + run_with_cost(&mut allocator, runner, Rc::new(program), sexp_args).map_err(|e| match e { + RunFailure::RunErr(l, s) => CompileErr(l, s), + RunFailure::RunExn(l, s) => CompileErr(l, s.to_string()), + }) + }) +} + +fn run_string_get_program_and_output_with_includes( + content: &str, + args: &str, + include_dirs: &[String], + fe_opt: bool, +) -> Result { + run_string_get_program_and_output_dialect( + content, + args, + include_dirs, + OptimizationRunSpec { + dialect: AcceptedDialect { + stepping: Some(23), + strict: false, + }, + optimize: false, + fe_opt, + }, + ) +} + +fn do_compile_and_run_opt_size_test_with_includes( + prog: &str, + env: &str, + includes: &[String], +) -> Result { + let unopt_run = run_string_get_program_and_output_with_includes(prog, env, includes, false)?; + let opt_run = run_string_get_program_and_output_with_includes(prog, env, includes, true)?; + + // Ensure the runs had the same output. + assert_eq!(unopt_run.run_result, opt_run.run_result); + + Ok(OptRunResult { + unopt: unopt_run, + opt: opt_run, + }) +} + +fn do_compile_and_run_opt_size_test_dialect( + prog: &str, + env: &str, + includes: &[String], + mut dialect: OptimizationRunSpec, +) -> Result { + let opt_run = run_string_get_program_and_output_dialect(prog, env, includes, dialect.clone())?; + dialect.optimize = false; + dialect.fe_opt = false; + let unopt_run = run_string_get_program_and_output_dialect(prog, env, includes, dialect)?; + + // Ensure the runs had the same output. + assert_eq!(unopt_run.run_result, opt_run.run_result); + + Ok(OptRunResult { + unopt: unopt_run, + opt: opt_run, + }) +} + +fn do_compile_and_run_opt_size_test(prog: &str, env: &str) -> Result { + do_compile_and_run_opt_size_test_with_includes(prog, env, &["resources/tests".to_string()]) +} + +#[test] +fn test_optimizer_tables_big_constants() { + let res = do_compile_and_run_opt_size_test( + indoc! {" + (mod (A) + (include *standard-cl-22*) + (defconstant X \"hi there this is a test\") + (c X (c X A)) + ) + "}, + "(test)", + ) + .expect("should compile and run"); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn smoke_test_optimizer() { + let res = do_compile_and_run_opt_size_test( + indoc! {" + (mod () + (include *standard-cl-22*) + (defun-inline F (X Y) (+ X Y)) + (let ((A 2) (B 4)) (F A B)) + ) + "}, + "()", + ) + .expect("should compile and run"); + eprintln!("opt {}", res.opt.compiled); + eprintln!("unopt {}", res.unopt.compiled); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn test_optimizer_shrinks_inlines() { + let res = do_compile_and_run_opt_size_test( + indoc! {" + (mod (A) + (include *standard-cl-22*) + (defun-inline F (N) (* 3 (+ 1 N))) + (let* ((FN (F A))) + (let ((FA (+ FN 1)) (FB (- FN 1)) (FC (* FN 2))) + (+ FA FB FC) + ) + ) + ) + "}, + "(3)", + ) + .expect("should compile and run"); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn test_optimizer_shrinks_repeated_lets() { + let res = do_compile_and_run_opt_size_test( + indoc! {" + (mod (X) + (include *standard-cl-22*) + (defconstant Z 1000000) + (let + ((X1 (+ X Z))) + (+ X1 X1 X1 X1 X1 X1) + ) + )"}, + "(3)", + ) + .expect("should compile and run"); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn test_optimizer_shrinks_q_test_1() { + let program = fs::read_to_string("resources/tests/optimization/merkle_tree_a2c.clsp") + .expect("test file should exist"); + let res = do_compile_and_run_opt_size_test_with_includes( + &program, + "(0x79539b34c33bc90bdaa6f9a28d3993a1e34025e5f2061fc57f8ff3edb9fb3b85 0x47194347579b7aa1ede51c52ddfd4200d8b560828051608ce599c763fd99291a (() 0xfb3b5605bc59e423b7df9c3bcfa7f559d6cdfcb9a49645dd801b3b24d6e9c439 0xe925a16b925dc355611f46c900ff0c182a3ed29a32d76394ea85b14d760d91c6))", + &["resources/tests/bridge-includes".to_string()] + ).expect("should compile and run"); + assert!(res.opt.compiled_hex.len() <= res.unopt.compiled_hex.len()); +} + +#[test] +fn test_optimizer_shrinks_q_test_2() { + let program = fs::read_to_string("resources/tests/optimization/validation_taproot.clsp") + .expect("test file should exist"); + let res = do_compile_and_run_opt_size_test_with_includes( + &program, + indoc!{"( + ;; Curried + ( + 0x7faa3253bfddd1e0decb0906b2dc6247bbc4cf608f58345d173adb63e8b47c9f + 0x0303030303030303030303030303030303030303030303030303030303030303 . + 0xeff07522495060c066f66f32acc2a77e3a3e737aca8baea4d1a64ea4cdc13da9 + ) + 0xa04d9f57764f54a43e4030befb4d80026e870519aaa66334aef8304f5d0393c2 + 0xb521509a3e089e25b66b3e272aa88b19851778eefebbea13e6be63a471ebf12a + ;; Args + () 0x78305c9b8b52ec71ebdd6db292fd106dbfdee8c061314658e13bf2436fa66a71 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2 1 (((1 . 0x0000000000000000000000000000000000000000000000000000000000000000) 2 . 0x0101010101010101010101010101010101010101010101010101010101010101) . 0x15966a8a80f66c1eb2547b2dcc42b1fccdb7d6c1c787a888b9fdc19bf72ac58b) + )"}, + &["resources/tests/bridge-includes".to_string()] + ).expect("should compile and run"); + assert!(res.opt.compiled_hex.len() <= res.unopt.compiled_hex.len()); +} + +// Tests from program builder. +#[test] +fn test_optimizer_stack_overflow_1() { + let program = indoc! {" + (mod C + (include *standard-cl-21*) + (defun helper_0 E (helper_0 (q))) + (if (helper_0 (q)) (helper_0 (q)) (helper_0 (q)))) + "} + .to_string(); + let res = do_compile_and_run_opt_size_test_with_includes(&program, "33", &[]); + if let Err(e) = &res { + assert!(e.1.starts_with("cost exceeded")); + } else { + assert!(false); + } +} + +#[test] +fn test_optimizer_stack_overflow_2() { + let program = indoc! {" + (mod C + (include *standard-cl-21*) + (defun helper_0 E (helper_0 (17 (q) (q)))) + (if (q) + (helper_0 (17 (q) (q))) + (helper_0 (17 (q) (q))) + ) + ) + "} + .to_string(); + let res = do_compile_and_run_opt_size_test_with_includes(&program, "33", &[]); + if let Err(e) = &res { + assert!(e.1.starts_with("cost exceeded")); + } else { + assert!(false); + } +} + +const SPEC_23: OptimizationRunSpec = OptimizationRunSpec { + dialect: AcceptedDialect { + stepping: Some(23), + strict: true, + }, + optimize: true, + fe_opt: true, +}; + +#[test] +fn test_optimizer_shrinks_repeated_lets_23() { + let res = do_compile_and_run_opt_size_test_dialect( + indoc! {" + (mod (X) + (include *standard-cl-22*) + (defconstant Z 1000000) + (let + ((X1 (+ X Z))) + (+ X1 X1 X1 X1 X1 X1) + ) + )"}, + "(3)", + &[], + SPEC_23.clone(), + ) + .expect("should compile and run"); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn test_brief_path_optimization() { + let program = + fs::read_to_string("resources/tests/test_user_path_opt_0.clsp").expect("should exist"); + let res = do_compile_and_run_opt_size_test_dialect( + &program, + "((1111111 ((((((987))))))))", + &[], + SPEC_23.clone(), + ) + .expect("should compile and run"); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +// Tests the path optimizer on a tricky assign extraction. +#[test] +fn test_brief_path_optimization_assign() { + let program = + fs::read_to_string("resources/tests/test_assign_path_opt.clsp").expect("should exist"); + let res = do_compile_and_run_opt_size_test_dialect( + &program, + "((_0 _1 _2 _3 _4 (_50 (_51 _52 _53 99))))", + &[], + SPEC_23.clone(), + ) + .expect("should compile and run"); + eprintln!("res.opt.compiled {}", res.opt.compiled); + eprintln!("res.unopt.compiled {}", res.unopt.compiled); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} + +#[test] +fn test_subexp_elimination_smoke_0() { + let program = + fs::read_to_string("resources/tests/test_recursion_subexp.clsp").expect("should exist"); + let res = do_compile_and_run_opt_size_test_dialect(&program, "(13 15)", &[], SPEC_23.clone()) + .expect("should compile and run"); + eprintln!("res.opt.compiled {}", res.opt.compiled); + eprintln!("res.unopt.compiled {}", res.unopt.compiled); + assert!(res.opt.compiled_hex.len() < res.unopt.compiled_hex.len()); +} From ffc74fae80ab0c287401692f5b75d2b187955f72 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 20 Oct 2023 01:41:16 -0700 Subject: [PATCH 03/48] More changes from codegen and comptypes --- src/compiler/codegen.rs | 224 ++++++++++++++++++++-------- src/compiler/comptypes.rs | 10 ++ src/compiler/frontend.rs | 5 +- src/compiler/preprocessor/macros.rs | 2 +- src/compiler/rename.rs | 13 +- src/compiler/sexp.rs | 18 +-- 6 files changed, 185 insertions(+), 87 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 589cecaf1..c665b4744 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -8,7 +8,7 @@ use num_bigint::ToBigInt; use crate::classic::clvm::__type_compatibility__::bi_one; -use crate::compiler::clvm::run; +use crate::compiler::clvm::{run, truthy}; use crate::compiler::compiler::is_at_capture; use crate::compiler::comptypes::{ fold_m, join_vecs_to_string, list_to_cons, Binding, BindingPattern, BodyForm, CallSpec, @@ -24,7 +24,7 @@ use crate::compiler::inline::{replace_in_inline, synthesize_args}; use crate::compiler::lambda::lambda_codegen; use crate::compiler::prims::{primapply, primcons, primquote}; use crate::compiler::runtypes::RunFailure; -use crate::compiler::sexp::{decode_string, SExp}; +use crate::compiler::sexp::{decode_string, printable, SExp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::StartOfCodegenOptimization; use crate::compiler::{BasicCompileContext, CompileContextWrapper}; @@ -69,6 +69,33 @@ fn cons_bodyform(loc: Srcloc, left: Rc, right: Rc) -> BodyFo ) } +fn empty_left_env(env: Rc) -> Option> { + if let SExp::Cons(_, l, r) = env.borrow() { + if truthy(l.clone()) { + None + } else { + Some(r.clone()) + } + } else { + // It's an unusual env, so be conservative. + None + } +} + +fn enable_nil_env_mode_for_stepping_23_or_greater( + opts: Rc, + code_generator: &mut PrimaryCodegen, +) { + if let Some(s) = opts.dialect().stepping { + if s >= 23 && opts.optimize() { + if let Some(whole_env) = empty_left_env(code_generator.env.clone()) { + code_generator.left_env = false; + code_generator.env = whole_env; + } + } + } +} + /* * Produce a structure that mimics the expected environment if the current inline * context had been a function. @@ -187,6 +214,7 @@ fn create_name_lookup_( // will make variable references to it capture the program's function // environment. fn is_defun_in_codegen(compiler: &PrimaryCodegen, name: &[u8]) -> bool { + // Check for an input defun that matches the name. for h in compiler.original_helpers.iter() { if matches!(h, HelperForm::Defun(false, _)) && h.name() == name { return true; @@ -311,7 +339,8 @@ pub fn get_callable( let defun = create_name_lookup(compiler, l.clone(), name, false); let prim = get_prim(l.clone(), compiler.prims.clone(), name); let atom_is_com = *name == "com".as_bytes().to_vec(); - let atom_is_at = *name == "@".as_bytes().to_vec(); + let atom_is_at = + *name == "@".as_bytes().to_vec() || *name == "@*env*".as_bytes().to_vec(); match (macro_def, inline, defun, prim, atom_is_com, atom_is_at) { (Some(macro_def), _, _, _, _, _) => { let macro_def_clone: &SExp = macro_def.borrow(); @@ -535,6 +564,10 @@ fn compile_call( l.clone(), Rc::new(SExp::Integer(l.clone(), i.clone())), )), + BodyForm::Quoted(SExp::Integer(l, i)) => Ok(CompiledCode( + l.clone(), + Rc::new(SExp::Integer(l.clone(), i.clone())), + )), _ => Err(CompileErr( al.clone(), "@ form only accepts integers at present".to_string(), @@ -629,6 +662,30 @@ pub fn do_mod_codegen( )) } +fn is_cons(bf: &BodyForm) -> bool { + if let BodyForm::Value(v) = bf { + if let SExp::Atom(_, vec) = v.atomize() { + return vec == [4] || vec == b"r"; + } + } + + false +} + +fn is_at_env(bf: &BodyForm) -> bool { + if let BodyForm::Value(v) = bf { + if let SExp::Atom(_, vec) = v.atomize() { + return vec == b"@*env*"; + } + } + + false +} + +fn addresses_user_env(call: &[Rc]) -> bool { + call.len() == 2 && is_cons(call[0].borrow()) && is_at_env(call[1].borrow()) +} + pub fn generate_expr_code( context: &mut BasicCompileContext, opts: Rc, @@ -651,7 +708,7 @@ pub fn generate_expr_code( BodyForm::Value(v) => { match v { SExp::Atom(l, atom) => { - if *atom == "@".as_bytes().to_vec() { + if *atom == "@".as_bytes().to_vec() || *atom == "@*env*".as_bytes().to_vec() { Ok(CompiledCode( l.clone(), Rc::new(SExp::Integer(l.clone(), bi_one())), @@ -663,17 +720,17 @@ pub fn generate_expr_code( create_name_lookup(compiler, l.clone(), atom, true) .map(|f| Ok(CompiledCode(l.clone(), f))) .unwrap_or_else(|_| { - // Finally enable strictness for variable names. - // This is possible because the modern macro system - // takes great care to preserve as much information - // from the source code as possible. - // - // When we come here in strict mode, we have - // a string, integer or atom depending on the - // user's desire and the explicitly generated - // result from the macro, therefore we can return - // an error if this atom didn't have a binding. - if opts.dialect().strict { + if opts.dialect().strict && printable(atom, false) { + // Finally enable strictness for variable names. + // This is possible because the modern macro system + // takes great care to preserve as much information + // from the source code as possible. + // + // When we come here in strict mode, we have + // a string, integer or atom depending on the + // user's desire and the explicitly generated + // result from the macro, therefore we can return + // an error if this atom didn't have a binding. return Err(CompileErr( l.clone(), format!( @@ -730,6 +787,13 @@ pub fn generate_expr_code( } } BodyForm::Call(l, list, tail) => { + // Recognize attempts to get the input arguments. They're paired with + // a left env in the usual case, but it can be omitted if there are no + // freestanding functions. In that case, the user args are just the + // whole env. + if !compiler.left_env && addresses_user_env(list) { + return generate_expr_code(context, opts, compiler, list[1].clone()); + } if list.is_empty() { Err(CompileErr( l.clone(), @@ -862,8 +926,12 @@ fn codegen_( } } -fn is_defun(b: &HelperForm) -> bool { - matches!(b, HelperForm::Defun(false, _)) +fn is_defun_or_tabled_constant(b: &HelperForm) -> bool { + match b { + HelperForm::Defun(false, _) => true, + HelperForm::Defconstant(cdata) => cdata.tabled, + _ => false, + } } pub fn empty_compiler(prim_map: Rc, Rc>>, l: Srcloc) -> PrimaryCodegen { @@ -873,6 +941,7 @@ pub fn empty_compiler(prim_map: Rc, Rc>>, l: Srcloc) -> Pr PrimaryCodegen { prims: prim_map, constants: HashMap::new(), + tabled_constants: HashMap::new(), inlines: HashMap::new(), macros: HashMap::new(), defuns: HashMap::new(), @@ -883,6 +952,7 @@ pub fn empty_compiler(prim_map: Rc, Rc>>, l: Srcloc) -> Pr final_expr: Rc::new(BodyForm::Quoted(nil)), final_code: None, function_symbols: HashMap::new(), + left_env: true, } } @@ -1170,7 +1240,7 @@ pub fn hoist_body_let_binding( ))), Rc::new(BodyForm::Value(SExp::Atom( letdata.loc.clone(), - "@".as_bytes().to_vec(), + "@*env*".as_bytes().to_vec(), ))), ], None, @@ -1364,8 +1434,12 @@ fn start_codegen( ) }) .map(|res| { - let quoted = primquote(defc.loc.clone(), res); - code_generator.add_constant(&defc.name, Rc::new(quoted)) + if defc.tabled { + code_generator.add_tabled_constant(&defc.name, res) + } else { + let quoted = primquote(defc.loc.clone(), res); + code_generator.add_constant(&defc.name, Rc::new(quoted)) + } })? } ConstantKind::Complex => { @@ -1380,14 +1454,13 @@ fn start_codegen( Some(EVAL_STACK_LIMIT), )?; if let BodyForm::Quoted(q) = constant_result.borrow() { - code_generator.add_constant( - &defc.name, - Rc::new(SExp::Cons( - defc.loc.clone(), - Rc::new(SExp::Atom(defc.loc.clone(), vec![1])), - Rc::new(q.clone()), - )), - ) + let res = Rc::new(q.clone()); + if defc.tabled { + code_generator.add_tabled_constant(&defc.name, res) + } else { + let quoted = primquote(defc.loc.clone(), res); + code_generator.add_constant(&defc.name, Rc::new(quoted)) + } } else { return Err(CompileErr( defc.loc.clone(), @@ -1434,7 +1507,7 @@ fn start_codegen( let only_defuns: Vec = program .helpers .iter() - .filter(|x| is_defun(x)) + .filter(|x| is_defun_or_tabled_constant(x)) .cloned() .collect(); @@ -1484,40 +1557,40 @@ fn finalize_env_( ) -> Result, CompileErr> { match env.borrow() { SExp::Atom(l, v) => { - match c.defuns.get(v) { - Some(res) => Ok(res.code.clone()), - None => { - match c.inlines.get(v) { - Some(res) => { - let (arg_list, arg_tail) = synthesize_args(res.args.clone()); - replace_in_inline( - context, - opts.clone(), - c, - l.clone(), - res, - res.args.loc(), - &arg_list, - arg_tail, - ) - .map(|x| x.1) - } - None => { - /* Parentfns are functions in progress in the parent */ - if c.parentfns.get(v).is_some() { - Ok(Rc::new(SExp::Nil(l.clone()))) - } else { - Err(CompileErr( - l.clone(), - format!( - "A defun was referenced in the defun env but not found {}", - decode_string(v) - ), - )) - } - } - } - } + if let Some(res) = c.defuns.get(v) { + return Ok(res.code.clone()); + } + + if let Some(res) = c.tabled_constants.get(v) { + return Ok(res.clone()); + } + + if let Some(res) = c.inlines.get(v) { + let (arg_list, arg_tail) = synthesize_args(res.args.clone()); + return replace_in_inline( + context, + opts.clone(), + c, + l.clone(), + res, + res.args.loc(), + &arg_list, + arg_tail, + ) + .map(|x| x.1); + } + + /* Parentfns are functions in progress in the parent */ + if c.parentfns.get(v).is_some() { + Ok(Rc::new(SExp::Nil(l.clone()))) + } else { + Err(CompileErr( + l.clone(), + format!( + "A defun was referenced in the defun env but not found {}", + decode_string(v) + ), + )) } } @@ -1537,7 +1610,13 @@ fn finalize_env( c: &PrimaryCodegen, ) -> Result, CompileErr> { match c.env.borrow() { - SExp::Cons(l, h, _) => finalize_env_(context, opts.clone(), c, l.clone(), h.clone()), + SExp::Cons(l, h, _) => { + if c.left_env { + finalize_env_(context, opts.clone(), c, l.clone(), h.clone()) + } else { + Ok(c.env.clone()) + } + } _ => Ok(c.env.clone()), } } @@ -1567,6 +1646,15 @@ fn dummy_functions(compiler: &PrimaryCodegen) -> Result { + if cdata.tabled { + let mut c_copy = compiler.clone(); + c_copy.parentfns.insert(cdata.name.clone()); + Ok(c_copy) + } else { + Ok(compiler.clone()) + } + } _ => Ok(compiler.clone()), }, compiler.clone(), @@ -1625,6 +1713,9 @@ pub fn codegen( code_generator = codegen_(context, opts.clone(), &code_generator, &f)?; } + // If stepping 23 or greater, we support no-env mode. + enable_nil_env_mode_for_stepping_23_or_greater(opts.clone(), &mut code_generator); + *context.symbols() = code_generator.function_symbols.clone(); context .symbols() @@ -1652,7 +1743,7 @@ pub fn codegen( ); Ok(final_code) - } else { + } else if code_generator.left_env { let final_code = primapply( code.0.clone(), Rc::new(primquote(code.0.clone(), code.1)), @@ -1664,6 +1755,9 @@ pub fn codegen( ); Ok(final_code) + } else { + let code_borrowed: &SExp = code.1.borrow(); + Ok(code_borrowed.clone()) } } } diff --git a/src/compiler/comptypes.rs b/src/compiler/comptypes.rs index 8f5b2bb62..5d5cf41e1 100644 --- a/src/compiler/comptypes.rs +++ b/src/compiler/comptypes.rs @@ -272,6 +272,8 @@ pub struct DefconstData { pub nl: Srcloc, /// The location of the body expression, whatever it is. pub body: Rc, + /// This constant should exist in the left env rather than be inlined. + pub tabled: bool, } /// Specifies where a constant is the classic kind (unevaluated) or a proper @@ -365,6 +367,7 @@ pub struct DefunCall { pub struct PrimaryCodegen { pub prims: Rc, Rc>>, pub constants: HashMap, Rc>, + pub tabled_constants: HashMap, Rc>, pub macros: HashMap, Rc>, pub inlines: HashMap, InlineFunction>, pub defuns: HashMap, DefunCall>, @@ -375,6 +378,7 @@ pub struct PrimaryCodegen { pub final_expr: Rc, pub final_code: Option, pub function_symbols: HashMap, + pub left_env: bool, } /// The CompilerOpts specifies global options used during compilation. @@ -894,6 +898,12 @@ impl PrimaryCodegen { codegen_copy } + pub fn add_tabled_constant(&self, name: &[u8], value: Rc) -> Self { + let mut codegen_copy = self.clone(); + codegen_copy.tabled_constants.insert(name.to_owned(), value); + codegen_copy + } + pub fn add_macro(&self, name: &[u8], value: Rc) -> Self { let mut codegen_copy = self.clone(); codegen_copy.macros.insert(name.to_owned(), value); diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index f7b5ae1d3..0e3099995 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -514,7 +514,7 @@ fn compile_defconst( name: Vec, body: Rc, ) -> Result { - let bf = compile_bodyform(opts, body)?; + let bf = compile_bodyform(opts.clone(), body)?; Ok(HelperForm::Defconstant(DefconstData { kw: kl, nl, @@ -522,6 +522,7 @@ fn compile_defconst( kind: ConstantKind::Complex, name: name.to_vec(), body: Rc::new(bf), + tabled: opts.frontend_opt() || opts.dialect().stepping.unwrap_or(0) > 22, })) } @@ -542,6 +543,7 @@ fn compile_defconstant( kind: ConstantKind::Simple, name: name.to_vec(), body: Rc::new(BodyForm::Value(body_borrowed.clone())), + tabled: false, })) } else { compile_bodyform(opts, body).map(|bf| { @@ -552,6 +554,7 @@ fn compile_defconstant( kind: ConstantKind::Simple, name: name.to_vec(), body: Rc::new(bf), + tabled: false, }) }) } diff --git a/src/compiler/preprocessor/macros.rs b/src/compiler/preprocessor/macros.rs index 2267018e4..eb9ea3de9 100644 --- a/src/compiler/preprocessor/macros.rs +++ b/src/compiler/preprocessor/macros.rs @@ -52,7 +52,7 @@ fn match_number(body: Rc) -> Result, CompileErr> { } SExp::Atom(al, b) => { // An atom with unprintable characters is rendered as an integer. - if !printable(b) { + if !printable(b, false) { let to_integer = number_from_u8(b); return Ok(Some(MatchedNumber::MatchedInt(al.clone(), to_integer))); } diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index b88cbd638..8b2849929 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -408,12 +408,9 @@ fn rename_in_helperform( ) -> Result { match h { HelperForm::Defconstant(defc) => Ok(HelperForm::Defconstant(DefconstData { - loc: defc.loc.clone(), - kind: defc.kind.clone(), - name: defc.name.to_vec(), - nl: defc.nl.clone(), - kw: defc.kw.clone(), body: Rc::new(rename_in_bodyform(namemap, defc.body.clone())?), + ..defc.clone() + })), HelperForm::Defmacro(mac) => Ok(HelperForm::Defmacro(DefmacData { program: Rc::new(rename_in_compileform(namemap, mac.program.clone())?), @@ -432,12 +429,8 @@ fn rename_in_helperform( pub fn rename_args_helperform(h: &HelperForm) -> Result { match h { HelperForm::Defconstant(defc) => Ok(HelperForm::Defconstant(DefconstData { - loc: defc.loc.clone(), - kind: defc.kind.clone(), - nl: defc.nl.clone(), - kw: defc.kw.clone(), - name: defc.name.clone(), body: Rc::new(rename_args_bodyform(defc.body.borrow())?), + ..defc.clone() })), HelperForm::Defmacro(mac) => { let mut new_names: HashMap, Vec> = HashMap::new(); diff --git a/src/compiler/sexp.rs b/src/compiler/sexp.rs index 905fba87e..002227850 100644 --- a/src/compiler/sexp.rs +++ b/src/compiler/sexp.rs @@ -136,7 +136,7 @@ impl Display for SExp { formatter.write_str(&v.to_string())?; } SExp::QuotedString(_, q, s) => { - if printable(s) { + if printable(s, true) { formatter.write_str("\"")?; formatter.write_str(&escape_quote(*q, s))?; formatter.write_str("\"")?; @@ -153,7 +153,7 @@ impl Display for SExp { SExp::Atom(l, a) => { if a.is_empty() { formatter.write_str("()")?; - } else if printable(a) { + } else if printable(a, false) { formatter.write_str(&decode_string(a))?; } else { formatter @@ -356,14 +356,12 @@ pub fn decode_string(v: &[u8]) -> String { return String::from_utf8_lossy(v).as_ref().to_string(); } -pub fn printable(a: &[u8]) -> bool { - for ch in a.iter() { - if (*ch as char).is_control() || !(*ch as char).is_ascii() { - return false; - } - } - - true +pub fn printable(a: &[u8], quoted: bool) -> bool { + !a.iter().any(|ch| { + (*ch as char).is_control() + || !(*ch as char).is_ascii() + || (!quoted && ch.is_ascii_whitespace()) + }) } impl SExp { From 8481aa6e935f97c0cf0bb37cb6413b0724180c5a Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 20 Oct 2023 02:31:21 -0700 Subject: [PATCH 04/48] One failing test --- .../tests/more_exhaustive/lambda_cse_1.clsp | 9 ++++ .../lambda_cse_1_desugared_form.clsp | 8 +++ .../lambda_cse_1_optimized_form.clsp | 11 ++++ .../more_exhaustive/lambda_cse_desugar_2.clsp | 10 ++++ .../lambda_cse_simple_desugar_1.clsp | 6 +++ .../lambda_cse_simple_desugar_2.clsp | 8 +++ resources/tests/strict/atomsort.clinc | 53 +++++++++++++++++++ src/compiler/inline.rs | 30 ++++++++++- 8 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 resources/tests/more_exhaustive/lambda_cse_1.clsp create mode 100644 resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp create mode 100644 resources/tests/more_exhaustive/lambda_cse_1_optimized_form.clsp create mode 100644 resources/tests/more_exhaustive/lambda_cse_desugar_2.clsp create mode 100644 resources/tests/more_exhaustive/lambda_cse_simple_desugar_1.clsp create mode 100644 resources/tests/more_exhaustive/lambda_cse_simple_desugar_2.clsp create mode 100644 resources/tests/strict/atomsort.clinc diff --git a/resources/tests/more_exhaustive/lambda_cse_1.clsp b/resources/tests/more_exhaustive/lambda_cse_1.clsp new file mode 100644 index 000000000..0fb2c2939 --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_1.clsp @@ -0,0 +1,9 @@ +(mod (A B) + (include *standard-cl-23*) + (defun F (X Y) + (let ((L (lambda ((& X Y) Z) (* Z (* X Y))))) + (* (a L (list X)) (* X Y)) + ) + ) + (F A B) + ) diff --git a/resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp b/resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp new file mode 100644 index 000000000..95cd90123 --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp @@ -0,0 +1,8 @@ +(mod (A B) + (include *standard-cl-23*) + (defun lambda_$_53 ((cse_$_50 X_$_46 Y_$_47) Z_$_49) (* Z_$_49 cse_$_50)) + (defun-inline letbinding_$_52 (((X_$_46 Y_$_47) cse_$_50) L_$_48) (* (a L_$_48 (4 X_$_46 ())) cse_$_50)) + (defun letbinding_$_51 ((X_$_46 Y_$_47) cse_$_50) (letbinding_$_52 (r @) (4 2 (4 (4 1 lambda_$_53) (4 (4 4 (4 (4 1 (4 cse_$_50 (c X_$_46 (c Y_$_47 (q))))) (4 1 (q)))) (q)))))) + (defun F (X_$_46 Y_$_47) (letbinding_$_51 (r @) (* X_$_46 Y_$_47))) + (F A B) + ) diff --git a/resources/tests/more_exhaustive/lambda_cse_1_optimized_form.clsp b/resources/tests/more_exhaustive/lambda_cse_1_optimized_form.clsp new file mode 100644 index 000000000..443a0049c --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_1_optimized_form.clsp @@ -0,0 +1,11 @@ +(mod (A B) + (include *standard-cl-23*) + (defun F (X_$_37 Y_$_38) + (let ((cse_$_41 (* X_$_37 Y_$_38))) + (let ((L_$_39 (lambda ((& cse_$_41 X_$_37 Y_$_38) Z_$_40) (* Z_$_40 cse_$_41)))) + (* (a L_$_39 (4 X_$_37 ())) cse_$_41) + ) + ) + ) + (F A B) + ) diff --git a/resources/tests/more_exhaustive/lambda_cse_desugar_2.clsp b/resources/tests/more_exhaustive/lambda_cse_desugar_2.clsp new file mode 100644 index 000000000..20f6b4f1a --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_desugar_2.clsp @@ -0,0 +1,10 @@ +(mod (A B) + (include *standard-cl-23*) + + (defun F (X_$_37_$_17 Y_$_38_$_18) (letbinding_$_56 (r @) (* X_$_37_$_17 Y_$_38_$_18))) + (defun-inline letbinding_$_56 ((X_$_37_$_17 Y_$_38_$_18) cse_$_41_$_19) + (letbinding_$_57 (c (c X_$_37_$_17 (c Y_$_38_$_18 ())) (c cse_$_41_$_19 ())) (4 2 (4 (4 1 lambda_$_58) (4 (4 4 (4 (4 1 (c cse_$_41_$_19 (c X_$_37_$_17 (c Y_$_38_$_18 (q))))) (4 1 (q)))) (q)))))) + (defun lambda_$_58 ((cse_$_41_$_19 X_$_37_$_17 Y_$_38_$_18) Z_$_40_$_20_$_21) (* Z_$_40_$_20_$_21 cse_$_41_$_19)) + (defun letbinding_$_57 (((X_$_37_$_17 Y_$_38_$_18) cse_$_41_$_19) L_$_39) (* (a L_$_39 (4 X_$_37_$_17 ())) cse_$_41_$_19)) + (F A B) + ) diff --git a/resources/tests/more_exhaustive/lambda_cse_simple_desugar_1.clsp b/resources/tests/more_exhaustive/lambda_cse_simple_desugar_1.clsp new file mode 100644 index 000000000..d31279044 --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_simple_desugar_1.clsp @@ -0,0 +1,6 @@ +(mod (A B) + (include *standard-cl-23*) + (defun letbinding_$_51 ((X_$_46 Y_$_47) cse_$_50) (list X_$_46 Y_$_47 cse_$_50)) + (defun F (X_$_46 Y_$_47) (letbinding_$_51 (r @) (* X_$_46 Y_$_47))) + (F A B) + ) diff --git a/resources/tests/more_exhaustive/lambda_cse_simple_desugar_2.clsp b/resources/tests/more_exhaustive/lambda_cse_simple_desugar_2.clsp new file mode 100644 index 000000000..95cd90123 --- /dev/null +++ b/resources/tests/more_exhaustive/lambda_cse_simple_desugar_2.clsp @@ -0,0 +1,8 @@ +(mod (A B) + (include *standard-cl-23*) + (defun lambda_$_53 ((cse_$_50 X_$_46 Y_$_47) Z_$_49) (* Z_$_49 cse_$_50)) + (defun-inline letbinding_$_52 (((X_$_46 Y_$_47) cse_$_50) L_$_48) (* (a L_$_48 (4 X_$_46 ())) cse_$_50)) + (defun letbinding_$_51 ((X_$_46 Y_$_47) cse_$_50) (letbinding_$_52 (r @) (4 2 (4 (4 1 lambda_$_53) (4 (4 4 (4 (4 1 (4 cse_$_50 (c X_$_46 (c Y_$_47 (q))))) (4 1 (q)))) (q)))))) + (defun F (X_$_46 Y_$_47) (letbinding_$_51 (r @) (* X_$_46 Y_$_47))) + (F A B) + ) diff --git a/resources/tests/strict/atomsort.clinc b/resources/tests/strict/atomsort.clinc new file mode 100644 index 000000000..1eb66c9d7 --- /dev/null +++ b/resources/tests/strict/atomsort.clinc @@ -0,0 +1,53 @@ +( + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + + ;; Sorts atoms into descending order + ;; This is optimized for sorting short lists + ;; A more general function would return a list of lists of ascending sizes + ;; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) +) diff --git a/src/compiler/inline.rs b/src/compiler/inline.rs index d3b88440c..5111ddd41 100644 --- a/src/compiler/inline.rs +++ b/src/compiler/inline.rs @@ -12,6 +12,7 @@ use crate::compiler::comptypes::{ ArgsAndTail, BodyForm, CallSpec, Callable, CompileErr, CompiledCode, CompilerOpts, InlineFunction, LambdaData, PrimaryCodegen, }; +use crate::compiler::lambda::make_cons; use crate::compiler::sexp::{decode_string, SExp}; use crate::compiler::srcloc::Srcloc; use crate::compiler::{BasicCompileContext, CompileContextWrapper}; @@ -440,7 +441,34 @@ fn replace_inline_body( } } } - BodyForm::Value(SExp::Atom(_, a)) => { + BodyForm::Value(SExp::Atom(l, a)) => { + if a == b"@*env*" { + // Reify the environment as it looks from here. + let left_env = Rc::new(BodyForm::Call( + l.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(l.clone(), b"@".to_vec()))), + Rc::new(BodyForm::Value(SExp::Integer( + l.clone(), + 2_u32.to_bigint().unwrap(), + ))), + ], + // Builtin + None, + )); + let mut env = Rc::new(BodyForm::Quoted(SExp::Nil(l.clone()))); + for arg in args.iter().rev() { + env = Rc::new(make_cons(l.clone(), arg.clone(), env)); + } + env = Rc::new(make_cons(l.clone(), left_env, env)); + return Ok(env); + } else if a == b"@" { + return Ok(Rc::new(BodyForm::Value(SExp::Atom( + l.clone(), + b"@".to_vec(), + )))); + } + let alookup = arg_lookup(callsite, inline.args.clone(), args, tail, a.clone())? .unwrap_or_else(|| expr.clone()); Ok(alookup) From 2fda897877dc970ddd8fbb40ff55d5b93ca13674 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 08:09:38 -0700 Subject: [PATCH 05/48] Fixed remaining imported test. Will import more tests --- resources/tests/strict/cse-complex-1.clsp | 28 +++++++++++ src/compiler/optimize/mod.rs | 59 +---------------------- src/compiler/rename.rs | 9 ++-- 3 files changed, 35 insertions(+), 61 deletions(-) create mode 100644 resources/tests/strict/cse-complex-1.clsp diff --git a/resources/tests/strict/cse-complex-1.clsp b/resources/tests/strict/cse-complex-1.clsp new file mode 100644 index 000000000..29b69a214 --- /dev/null +++ b/resources/tests/strict/cse-complex-1.clsp @@ -0,0 +1,28 @@ +(mod (X) + (include *standard-cl-23*) + + (defun mess (X) ;; 11 41 + (assign + Y (+ X 1) ;; 12 42 + Z (+ Y 2) ;; 14 44 + + (if (= X 11) + (assign + Y (* X 2) ;; 22 82 + Z (+ Y 1) ;; 23 83 + + (* Y Z) ;; 22 * 23 = 506 + ) + + (assign + Y (* X 3) ;; 33 123 + Z (+ Y 2) ;; 35 125 + + (* Y Z) ;; 123 * 125 = 15375 + ) + ) + ) + ) + + (mess X) + ) diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 38bc2f159..b173539e3 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -39,7 +39,6 @@ use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::parse_sexp; use crate::compiler::sexp::{AtomValue, NodeSel, SExp, SelectNode, ThisNode}; use crate::compiler::srcloc::Srcloc; -use crate::compiler::BasicCompileContext; use crate::compiler::CompileContextWrapper; use crate::compiler::StartOfCodegenOptimization; use crate::util::u8_from_number; @@ -614,56 +613,6 @@ fn test_null_optimization_ok_not_doing_anything() { assert_eq!(optimized.to_string(), "(2 (1 (1) (1) (1)) (3))"); } -// Should take a desugared program. -pub fn deinline_opt( - context: &mut BasicCompileContext, - opts: Rc, - mut compileform: CompileForm, -) -> Result { - let mut best_compileform = compileform.clone(); - let generated_program = codegen(context, opts.clone(), &best_compileform)?; - let mut metric = sexp_scale(&generated_program); - let flip_helper = |h: &mut HelperForm| { - if let HelperForm::Defun(inline, defun) = h { - if matches!(&defun.synthetic, Some(SyntheticType::NoInlinePreference)) { - *h = HelperForm::Defun(!*inline, defun.clone()); - return true; - } - } - - false - }; - - loop { - let start_metric = metric; - - for i in 0..compileform.helpers.len() { - // Try flipped. - let old_helper = compileform.helpers[i].clone(); - if !flip_helper(&mut compileform.helpers[i]) { - continue; - } - - let maybe_smaller_program = codegen(context, opts.clone(), &compileform)?; - let new_metric = sexp_scale(&maybe_smaller_program); - - // Don't keep this change if it made things worse. - if new_metric >= metric { - compileform.helpers[i] = old_helper; - } else { - metric = new_metric; - best_compileform = compileform.clone(); - } - } - - if start_metric == metric { - break; - } - } - - Ok(best_compileform) -} - fn fe_opt( allocator: &mut Allocator, runner: Rc, @@ -688,14 +637,8 @@ fn fe_opt( let new_helper = HelperForm::Defun( *inline, Box::new(DefunData { - loc: defun.loc.clone(), - nl: defun.nl.clone(), - kw: defun.kw.clone(), - name: defun.name.clone(), - args: defun.args.clone(), - orig_args: defun.orig_args.clone(), - synthetic: defun.synthetic.clone(), body: body_rc.clone(), + .. *defun.clone() }), ); optimized_helpers.push(new_helper); diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 8b2849929..1c21317f3 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -164,7 +164,7 @@ pub fn rename_assign_bindings( ) -> Result<(BodyForm, Vec>), CompileErr> { // Order the bindings. let sorted_bindings = toposort_assign_bindings(l, bindings)?; - let mut renames = HashMap::new(); + let mut renames: HashMap, Vec> = HashMap::new(); // Process in reverse order so we rename from inner to outer. let bindings_to_rename: Vec> = sorted_bindings.to_vec(); let renamed_bindings = map_m_reverse( @@ -175,9 +175,11 @@ pub fn rename_assign_bindings( for (name, renamed) in new_names.iter() { renames.insert(name.clone(), renamed.clone()); } + + let renamed_in_body = Rc::new(rename_args_bodyform(b.body.borrow())?); Ok(Rc::new(Binding { pattern: BindingPattern::Complex(rename_in_cons(&renames, p.clone(), false)), - body: Rc::new(rename_in_bodyform(&renames, b.body.clone())?), + body: Rc::new(rename_in_bodyform(&renames, renamed_in_body)?), ..b.clone() })) } else { @@ -186,7 +188,8 @@ pub fn rename_assign_bindings( }, &bindings_to_rename, )?; - Ok((rename_in_bodyform(&renames, body)?, renamed_bindings)) + let new_body = Rc::new(rename_args_bodyform(body.borrow())?); + Ok((rename_in_bodyform(&renames, new_body)?, renamed_bindings)) } fn rename_in_bodyform( From 55f5ec2ee942bb1d82196b39c16b31ba456aa641 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 10:18:17 -0700 Subject: [PATCH 06/48] Update for upstream changes --- src/compiler/optimize/double_apply.rs | 18 +++++++++--------- src/compiler/optimize/mod.rs | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/optimize/double_apply.rs b/src/compiler/optimize/double_apply.rs index 013da7d11..4f9a2a667 100644 --- a/src/compiler/optimize/double_apply.rs +++ b/src/compiler/optimize/double_apply.rs @@ -30,9 +30,9 @@ pub fn change_double_to_single_apply(sexp: Rc) -> (bool, Rc) { NodeSel::Cons( // quoted program AtomValue::Here(&[1]), - ThisNode::Here, + ThisNode, ), - NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here), + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode), ), ) .select_nodes(sexp.clone()) @@ -61,9 +61,9 @@ fn change_apply_double_quote(sexp: Rc) -> (bool, Rc) { NodeSel::Cons( NodeSel::Cons( AtomValue::Here(&[1]), - NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here), + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode), ), - ThisNode::Here, + ThisNode, ), ) .select_nodes(sexp.clone()) @@ -81,10 +81,10 @@ fn collapse_constant_condition(sexp: Rc) -> (bool, Rc) { )) = NodeSel::Cons( AtomValue::Here(&[3]), NodeSel::Cons( - ThisNode::Here, + ThisNode, NodeSel::Cons( - ThisNode::Here, - NodeSel::Cons(ThisNode::Here, ThisNode::Here), + ThisNode, + NodeSel::Cons(ThisNode, ThisNode), ), ), ) @@ -95,7 +95,7 @@ fn collapse_constant_condition(sexp: Rc) -> (bool, Rc) { // The following filters away a non-const condition and leaves // the remaining as either Some(true) or Some(false), then // chooses a wing based on that. - return NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here) + return NodeSel::Cons(AtomValue::Here(&[1]), ThisNode) .select_nodes(cond.clone()) .ok() .map(|NodeSel::Cons(_, cond_quoted)| Some(truthy(cond_quoted))) @@ -116,7 +116,7 @@ pub fn remove_double_apply(mut sexp: Rc, spine: bool) -> (bool, Rc) // Don't descend into quoted expressions. if spine { if let Ok(NodeSel::Cons(_, _)) = - NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here).select_nodes(sexp.clone()) + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode).select_nodes(sexp.clone()) { return (false, sexp); } diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index b173539e3..05043e135 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -533,7 +533,7 @@ pub fn optimize_expr( if let Ok(compiled) = do_mod_codegen(&mut wrapper.context, opts.clone(), cf) { if let Ok(NodeSel::Cons(_, body)) = - NodeSel::Cons(AtomValue::Here(&[1]), ThisNode::Here) + NodeSel::Cons(AtomValue::Here(&[1]), ThisNode) .select_nodes(compiled.1) { let borrowed_body: &SExp = body.borrow(); From 2be878b1a87085df7216a665c228c926ef2ec7a3 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 10:18:45 -0700 Subject: [PATCH 07/48] fmt --- src/compiler/frontend.rs | 14 ++++++-------- src/compiler/optimize/double_apply.rs | 5 +---- src/compiler/optimize/mod.rs | 2 +- src/compiler/rename.rs | 1 - 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/compiler/frontend.rs b/src/compiler/frontend.rs index 0e3099995..970b70cbf 100644 --- a/src/compiler/frontend.rs +++ b/src/compiler/frontend.rs @@ -884,11 +884,11 @@ fn frontend_start( /// Given the available helper list and the main expression, compute the list of /// reachable helpers. pub fn compute_live_helpers( - opts: Rc, - helper_list: &[HelperForm], - main_exp: Rc, - ) -> Vec { - let expr_names: HashSet> = collect_used_names_bodyform(main_exp.borrow()) + opts: Rc, + helper_list: &[HelperForm], + main_exp: Rc, +) -> Vec { + let expr_names: HashSet> = collect_used_names_bodyform(main_exp.borrow()) .iter() .map(|x| x.to_vec()) .collect(); @@ -903,9 +903,7 @@ pub fn compute_live_helpers( helper_list .iter() - .filter(|h| { - !opts.frontend_check_live() || helper_names.contains(h.name()) - }) + .filter(|h| !opts.frontend_check_live() || helper_names.contains(h.name())) .cloned() .collect() } diff --git a/src/compiler/optimize/double_apply.rs b/src/compiler/optimize/double_apply.rs index 4f9a2a667..9beb70942 100644 --- a/src/compiler/optimize/double_apply.rs +++ b/src/compiler/optimize/double_apply.rs @@ -82,10 +82,7 @@ fn collapse_constant_condition(sexp: Rc) -> (bool, Rc) { AtomValue::Here(&[3]), NodeSel::Cons( ThisNode, - NodeSel::Cons( - ThisNode, - NodeSel::Cons(ThisNode, ThisNode), - ), + NodeSel::Cons(ThisNode, NodeSel::Cons(ThisNode, ThisNode)), ), ) .select_nodes(sexp.clone()) diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 05043e135..ca7b19fb0 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -638,7 +638,7 @@ fn fe_opt( *inline, Box::new(DefunData { body: body_rc.clone(), - .. *defun.clone() + ..*defun.clone() }), ); optimized_helpers.push(new_helper); diff --git a/src/compiler/rename.rs b/src/compiler/rename.rs index 1c21317f3..f0c5ae0dd 100644 --- a/src/compiler/rename.rs +++ b/src/compiler/rename.rs @@ -413,7 +413,6 @@ fn rename_in_helperform( HelperForm::Defconstant(defc) => Ok(HelperForm::Defconstant(DefconstData { body: Rc::new(rename_in_bodyform(namemap, defc.body.clone())?), ..defc.clone() - })), HelperForm::Defmacro(mac) => Ok(HelperForm::Defmacro(DefmacData { program: Rc::new(rename_in_compileform(namemap, mac.program.clone())?), From 3ab7d7a67e8016f85a6f8543ea7cff6875211526 Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 10:26:06 -0700 Subject: [PATCH 08/48] More diff minimization --- src/tests/classic/run.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 22313ecb4..89f934fcb 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1007,6 +1007,23 @@ fn test_lambda_with_capture_defines_word() { assert!(!compiled.contains("new_puzzle_hash")); } +#[test] +fn test_cost_reporting_0() { + let program = "(2 (1 2 6 (4 2 (4 (1 . 1) ()))) (4 (1 (2 (1 2 (3 (7 5) (1 2 (1 11 (1 . 2) (2 4 (4 2 (4 (5 5) ()))) (2 4 (4 2 (4 (6 5) ())))) 1) (1 2 (1 11 (1 . 1) 5) 1)) 1) 1) 2 (1 16 5 (1 . 50565442356047746631413349885570059132562040184787699607120092457326103992436)) 1) 1))"; + let result = do_basic_brun(&vec![ + "brun".to_string(), + "-c".to_string(), + program.to_string(), + "()".to_string(), + ]) + .trim() + .to_string(); + assert_eq!( + result, + "cost = 1978\n0x6fcb06b1fe29d132bb37f3a21b86d7cf03d636bf6230aa206486bef5e68f9875" + ); +} + #[test] fn test_assign_lambda_code_generation() { let tname = "test_assign_lambda_code_generation.sym".to_string(); @@ -1061,23 +1078,6 @@ fn test_assign_lambda_code_generation_normally_inlines() { .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); } -#[test] -fn test_cost_reporting_0() { - let program = "(2 (1 2 6 (4 2 (4 (1 . 1) ()))) (4 (1 (2 (1 2 (3 (7 5) (1 2 (1 11 (1 . 2) (2 4 (4 2 (4 (5 5) ()))) (2 4 (4 2 (4 (6 5) ())))) 1) (1 2 (1 11 (1 . 1) 5) 1)) 1) 1) 2 (1 16 5 (1 . 50565442356047746631413349885570059132562040184787699607120092457326103992436)) 1) 1))"; - let result = do_basic_brun(&vec![ - "brun".to_string(), - "-c".to_string(), - program.to_string(), - "()".to_string(), - ]) - .trim() - .to_string(); - assert_eq!( - result, - "cost = 1978\n0x6fcb06b1fe29d132bb37f3a21b86d7cf03d636bf6230aa206486bef5e68f9875" - ); -} - #[test] fn test_strict_smoke_0() { let result = do_basic_run(&vec![ From 7af167c13d3db67ae63a30f28561b22326e0ea9d Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 10:36:38 -0700 Subject: [PATCH 09/48] More diff reduction --- .../tests/strict/rps-referee-uncaptured.clsp | 31 +++++++++++++ src/tests/classic/run.rs | 43 +++++++++++++------ 2 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 resources/tests/strict/rps-referee-uncaptured.clsp diff --git a/resources/tests/strict/rps-referee-uncaptured.clsp b/resources/tests/strict/rps-referee-uncaptured.clsp new file mode 100644 index 000000000..01e90e55e --- /dev/null +++ b/resources/tests/strict/rps-referee-uncaptured.clsp @@ -0,0 +1,31 @@ +(mod ((VALIDATION_PROGRAM_HASH AMOUNT) action . args) + + (include *strict-cl-21*) + + (defconstant CREATE_COIN 51) + + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) + + (let + ((new_puzzle_hash 38911) + ) + (reduce + (lambda ((@ condition (condname arg1 arg2)) agg) + (if agg + 1 + (if (= condname CREATE_COIN) + (logand (= arg1 new_puzzle_hash) (= arg2 100)) + 0 + ) + ) + ) + conditions + 0 + ) + ) + ) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 89f934fcb..525e67517 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -992,6 +992,21 @@ fn test_lambda_without_capture_reproduces_bare_word_in_output() { assert!(compiled.contains("new_puzzle_hash")); } +// Test that strict cl21 throws an error rather than compiling the above. +#[test] +fn test_lambda_without_capture_strict() { + let compiler_result = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/strict/rps-referee-uncaptured.clsp".to_string(), + ]) + .trim() + .to_string(); + assert!(compiler_result.contains("Unbound")); + assert!(compiler_result.contains("new_puzzle_hash")); +} + // Test that having a lambda capture captures all the associated words. #[test] fn test_lambda_with_capture_defines_word() { @@ -1078,6 +1093,20 @@ fn test_assign_lambda_code_generation_normally_inlines() { .contains(&"ccd5be506752cebf01f9930b4c108fe18058c65e1ab57a72ca0a00d9788c7ca6".to_string())); } +#[test] +fn test_assign_fancy_final_dot_rest() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/chia-gaming".to_string(), + "resources/tests/chia-gaming/test-last.clsp".to_string(), + ]); + let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) + .trim() + .to_string(); + assert_eq!(result, "101"); +} + #[test] fn test_strict_smoke_0() { let result = do_basic_run(&vec![ @@ -1266,20 +1295,6 @@ fn test_defmac_assert_smoke_preprocess() { assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); } -#[test] -fn test_assign_fancy_final_dot_rest() { - let result_prog = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests/chia-gaming".to_string(), - "resources/tests/chia-gaming/test-last.clsp".to_string(), - ]); - let result = do_basic_brun(&vec!["brun".to_string(), result_prog, "()".to_string()]) - .trim() - .to_string(); - assert_eq!(result, "101"); -} - #[test] fn test_g1_map_op_modern() { let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; From 71bc8fc31d9db4504879ce0078be4e2504840c9a Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 24 Oct 2023 10:57:57 -0700 Subject: [PATCH 10/48] More synchronization --- resources/tests/deinline/test-basic-deinline.clsp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 resources/tests/deinline/test-basic-deinline.clsp diff --git a/resources/tests/deinline/test-basic-deinline.clsp b/resources/tests/deinline/test-basic-deinline.clsp new file mode 100644 index 000000000..67dd10e5b --- /dev/null +++ b/resources/tests/deinline/test-basic-deinline.clsp @@ -0,0 +1,15 @@ +;; This program should ideally become very terse when compiled since everything +;; is constant in it, which means we won't necessarily get a runnable program +;; from chialisp compilation. +;; +;; This is used as one test for --test-deinline. +(mod () + (include *standard-cl-22*) + (include utility_macros.clib) + (defun-inline test-me (X) (* 3 X)) + (assert + (= (test-me 5) 15) + (= (test-me 0) 0) + () + ) + ) From 07adf7b75bcfe1689862d09deda63156977c4fb8 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 09:04:29 -0700 Subject: [PATCH 11/48] Add test file --- resources/tests/simple_deinline_case_23.clsp | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 resources/tests/simple_deinline_case_23.clsp diff --git a/resources/tests/simple_deinline_case_23.clsp b/resources/tests/simple_deinline_case_23.clsp new file mode 100644 index 000000000..2dd68fae8 --- /dev/null +++ b/resources/tests/simple_deinline_case_23.clsp @@ -0,0 +1,8 @@ +(mod (X) + (include *standard-cl-23*) + (defconstant Z 1000000) + (let + ((X1 (+ X Z))) + (+ X1 X1 X1 X1 X1 X1) + ) + ) From ee4ff5cea480a5a8c1fa09c7cf67d48aea7f03a2 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 09:34:55 -0700 Subject: [PATCH 12/48] Fix flags, should refactor that --- src/classic/clvm_tools/cmds.rs | 4 ++-- src/compiler/optimize/mod.rs | 1 + src/tests/classic/run.rs | 43 ++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/classic/clvm_tools/cmds.rs b/src/classic/clvm_tools/cmds.rs index 2b4aa6b3e..7a6915943 100644 --- a/src/classic/clvm_tools/cmds.rs +++ b/src/classic/clvm_tools/cmds.rs @@ -1355,9 +1355,9 @@ pub fn launch_tool(stdout: &mut Stream, args: &[String], tool_name: &str, defaul let use_filename = input_file.unwrap_or_else(|| "*command*".to_string()); let opts = Rc::new(DefaultCompilerOpts::new(&use_filename)) .set_dialect(dialect.unwrap_or_default()) - .set_optimize(do_optimize) + .set_optimize(do_optimize || stepping > 22) .set_search_paths(&search_paths) - .set_frontend_opt(stepping > 21) + .set_frontend_opt(stepping == 22) .set_disassembly_ver(get_disassembly_ver(&parsed_args)); let mut symbol_table = HashMap::new(); diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index ca7b19fb0..36a760909 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -693,6 +693,7 @@ pub fn get_optimizer( loc: &Srcloc, opts: Rc, ) -> Result, CompileErr> { + eprintln!("dialect {:?} opt {} fe {}", opts.dialect(), opts.optimize(), opts.frontend_opt()); if let Some(s) = opts.dialect().stepping { if s < 21 { return Err(CompileErr( diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 525e67517..425fa4ef5 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1235,6 +1235,32 @@ fn test_check_symbol_kinds_nested_if() { assert_eq!(result_0, "(q 1 2 3 4 4)"); } +// Check for successful deinlining of a large constant. +// The result program tables the constant. +#[test] +fn test_basic_deinlining_smoke_0() { + let fname = "resources/tests/simple_deinline_case_23.clsp"; + let file_content = fs::read_to_string(fname).expect("should exist"); + let result_prog = do_basic_run(&vec!["run".to_string(), fname.to_string()]); + eprintln!("result_prog 23 {result_prog}"); + assert_eq!(result_prog.matches("1000000").count(), 1); + let old_prog = file_content.to_string().replace("23", "21"); + let result_prog_21 = do_basic_run(&vec!["run".to_string(), old_prog]); + eprintln!("result_prog 21 {result_prog_21}"); + assert_eq!(result_prog_21.matches("1000000").count(), 6); + assert!(result_prog.len() < result_prog_21.len()); +} + +// Check for the optimizer to reduce a fully constant program to a constant. +#[test] +fn test_optimizer_fully_reduces_constant_outcome_0() { + let res = do_basic_run(&vec![ + "run".to_string(), + "(mod () (include *standard-cl-23*) (defun F (X) (+ X 1)) (F 3))".to_string(), + ]); + assert_eq!(res, "(1 . 4)"); +} + // Note: this program is intentionally made to properly preprocess but trigger // an error in strict compilation as a demonstration and test that the preprocessor // is a mechanically separate step from compilation. Separating them like this @@ -1312,6 +1338,23 @@ fn test_g1_map_op_modern() { ); } +#[test] +fn test_optimizer_fully_reduces_constant_outcome_let_0() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (A) (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (defun G (Q) (let ((R (F Q))) (+ R 1))) (+ A (G 3)))".to_string(), + ]); + // Tree shaking will remove the functions that became unused due to constant + // reduction. We now support suppressing the left env in stepping 23 and + // above. + assert_eq!( + res, + "(16 2 (1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410))" + ); +} + #[test] fn test_g1_map_op_classic() { let program = "(mod (S) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; From 2c4450064a2f78d6ded11c0d397efe4494678619 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 09:46:51 -0700 Subject: [PATCH 13/48] Pull in more tests --- src/tests/classic/run.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 425fa4ef5..88f7a32b0 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1261,6 +1261,22 @@ fn test_optimizer_fully_reduces_constant_outcome_0() { assert_eq!(res, "(1 . 4)"); } + +// Check for the optimizer to reduce a fully constant program to a constant. +#[test] +fn test_optimizer_fully_reduces_constant_outcome_sha256tree() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (F 3))".to_string(), + ]); + assert_eq!( + res, + "(1 . -39425664269051251592384450451821132878837081010681666327853404714379049572411)" + ); +} + // Note: this program is intentionally made to properly preprocess but trigger // an error in strict compilation as a demonstration and test that the preprocessor // is a mechanically separate step from compilation. Separating them like this From c0fdbaf5febadc31871802464fe30f652e1a2953 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 09:53:43 -0700 Subject: [PATCH 14/48] Pull in more tests --- src/tests/classic/run.rs | 164 +++++++++++++++++++++++++++++++-------- 1 file changed, 130 insertions(+), 34 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 88f7a32b0..124783019 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1277,6 +1277,136 @@ fn test_optimizer_fully_reduces_constant_outcome_sha256tree() { ); } +// Check for the optimizer to reduce a fully constant function call to a constant +// and propogate through another expression. +#[test] +fn test_optimizer_fully_reduces_constant_outcome_sha256tree_1() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))".to_string(), + ]); + assert_eq!( + res, + "(1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410)" + ); +} + +#[test] +fn test_g1_map_op_modern() { + let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; + let compiled = do_basic_run(&vec!["run".to_string(), program.to_string()]); + let output = do_basic_brun(&vec![ + "brun".to_string(), + compiled, + "(abcdef0123456789)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!( + output, + "0x88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a" + ); +} + +#[test] +fn test_optimizer_fully_reduces_constant_outcome_let_0() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (A) (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (defun G (Q) (let ((R (F Q))) (+ R 1))) (+ A (G 3)))".to_string(), + ]); + // Tree shaking will remove the functions that became unused due to constant + // reduction. We now support suppressing the left env in stepping 23 and + // above. + assert_eq!( + res, + "(16 2 (1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410))" + ); +} + +// Test that the optimizer inverts (i (not x) a b) to (i x b a) +#[test] +fn test_not_inversion_body() { + let res = do_basic_run(&vec![ + "run".to_string(), + "(mod (X) (include *standard-cl-23*) (if (not X) (+ X 1) (* X 2)))".to_string(), + ]); + assert_eq!(res, "(2 (3 2 (1 18 2 (1 . 2)) (1 16 2 (1 . 1))) 1)"); +} + +// Test that we can test chialisp outcomes in chialisp. +#[test] +fn test_chialisp_in_chialisp_test_pos() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), + ]); + assert_eq!(compiled, "(1 . \"worked\")"); +} + +// Test that we can test chialisp outcomes in chialisp. +#[test] +fn test_chialisp_in_chialisp_test_neg() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ (list X) 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), + ]); + assert_eq!(compiled, "(1 . \"didnt work\")"); +} + +// Test CSE when detections are inside a lambda. It's necessary to add a capture for +// the replaced expression. +#[test] +fn test_cse_replacement_inside_lambda_23_0() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/more_exhaustive/lambda_cse_1.clsp".to_string(), + ]); + let res = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(17 17)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(res, "0x15aa51"); + let res = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(17 19)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(res, "0x1b1019"); + let res = do_basic_brun(&vec!["brun".to_string(), program, "(19 17)".to_string()]) + .trim() + .to_string(); + assert_eq!(res, "0x1e3f2b"); +} + +#[test] +fn test_cse_replacement_inside_lambda_test_desugared_form_23() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp".to_string(), + ]); + let res = do_basic_brun(&vec!["brun".to_string(), program, "(17 17)".to_string()]) + .trim() + .to_string(); + assert_eq!(res, "0x15aa51"); +} + // Note: this program is intentionally made to properly preprocess but trigger // an error in strict compilation as a demonstration and test that the preprocessor // is a mechanically separate step from compilation. Separating them like this @@ -1337,40 +1467,6 @@ fn test_defmac_assert_smoke_preprocess() { assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); } -#[test] -fn test_g1_map_op_modern() { - let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; - let compiled = do_basic_run(&vec!["run".to_string(), program.to_string()]); - let output = do_basic_brun(&vec![ - "brun".to_string(), - compiled, - "(abcdef0123456789)".to_string(), - ]) - .trim() - .to_string(); - assert_eq!( - output, - "0x88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a" - ); -} - -#[test] -fn test_optimizer_fully_reduces_constant_outcome_let_0() { - let res = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "(mod (A) (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (defun G (Q) (let ((R (F Q))) (+ R 1))) (+ A (G 3)))".to_string(), - ]); - // Tree shaking will remove the functions that became unused due to constant - // reduction. We now support suppressing the left env in stepping 23 and - // above. - assert_eq!( - res, - "(16 2 (1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410))" - ); -} - #[test] fn test_g1_map_op_classic() { let program = "(mod (S) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; From 5bac184485d7b5af2fbef6d8ccca6be5f930f557 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 10:04:15 -0700 Subject: [PATCH 15/48] more tests from the future --- resources/tests/strict/assert23.clsp | 11 + src/tests/classic/run.rs | 340 ++++++++++++++++++++++++++- 2 files changed, 350 insertions(+), 1 deletion(-) create mode 100644 resources/tests/strict/assert23.clsp diff --git a/resources/tests/strict/assert23.clsp b/resources/tests/strict/assert23.clsp new file mode 100644 index 000000000..1a9d8ff39 --- /dev/null +++ b/resources/tests/strict/assert23.clsp @@ -0,0 +1,11 @@ +(mod (A) + (include *standard-cl-23*) + + (include defmac_assert.clib) + + (assert + 1 + A + 13 + ) + ) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 124783019..55d1d71a1 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1261,7 +1261,6 @@ fn test_optimizer_fully_reduces_constant_outcome_0() { assert_eq!(res, "(1 . 4)"); } - // Check for the optimizer to reduce a fully constant program to a constant. #[test] fn test_optimizer_fully_reduces_constant_outcome_sha256tree() { @@ -1277,6 +1276,345 @@ fn test_optimizer_fully_reduces_constant_outcome_sha256tree() { ); } +#[test] +fn test_defmac_assert_smoke_preprocess_23() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "-E".to_string(), + "resources/tests/strict/assert23.clsp".to_string(), + ]); + assert_eq!( + result_prog, + "(mod (A) (include *standard-cl-23*) (a (i 1 (com (a (i A (com 13) (com (x))) @)) (com (x))) @))" + ); + let result_after_preproc = do_basic_run(&vec!["run".to_string(), result_prog]); + let result_with_preproc = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/assert23.clsp".to_string(), + ]); + assert_eq!(result_after_preproc, result_with_preproc); + let run_result_true = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(15)".to_string(), + ]); + assert_eq!(run_result_true.trim(), "13"); + let run_result_false = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(0)".to_string(), + ]); + assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_0() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (X) (r @*env*)) ;; X = ((3)), returns (((3))) + (defun B (X) (A (r @*env*))) ;; X = (3) + (defun C (X) (B (r @*env*))) ;; X = 3 + (C Y) ;; Y = 3 + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_1() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (X) (r @*env*)) + (defun B (X) (A (r @*env*))) + (defun C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_2() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (X) (r @*env*)) + (defun-inline B (X) (A (r @*env*))) + (defun C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_3() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (X) (r @*env*)) + (defun-inline B (X) (A (r @*env*))) + (defun C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_4() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (X) (r @*env*)) + (defun B (X) (A (r @*env*))) + (defun-inline C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_5() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (X) (r @*env*)) + (defun B (X) (A (r @*env*))) + (defun-inline C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_6() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (X) (r @*env*)) + (defun-inline B (X) (A (r @*env*))) + (defun-inline C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_23_7() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (X) (r @*env*)) + (defun-inline B (X) (A (r @*env*))) + (defun-inline C (X) (B (r @*env*))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(((i)))"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_0() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (((PPX) PX) X) (list PPX PX X)) + (defun B ((PX) X) (A (r @*env*) (+ X 1))) + (defun C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_1() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (((PPX) PX) X) (list PPX PX X)) + (defun B ((PX) X) (A (r @*env*) (+ X 1))) + (defun C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_2() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (((PPX) PX) X) (list PPX PX X)) + (defun-inline B ((PX) X) (A (r @*env*) (+ X 1))) + (defun C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_3() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (((PPX) PX) X) (list PPX PX X)) + (defun-inline B ((PX) X) (A (r @*env*) (+ X 1))) + (defun C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_4() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (((PPX) PX) X) (list PPX PX X)) + (defun B ((PX) X) (A (r @*env*) (+ X 1))) + (defun-inline C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_5() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (((PPX) PX) X) (list PPX PX X)) + (defun B ((PX) X) (A (r @*env*) (+ X 1))) + (defun-inline C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_6() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun A (((PPX) PX) X) (list PPX PX X)) + (defun-inline B ((PX) X) (A (r @*env*) (+ X 1))) + (defun-inline C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + +#[test] +fn test_smoke_inline_at_expansion_var_23_7() { + let prog = do_basic_run(&vec![ + "run".to_string(), + indoc! {" + (mod (Y) + (include *standard-cl-23*) + (defun-inline A (((PPX) PX) X) (list PPX PX X)) + (defun-inline B ((PX) X) (A (r @*env*) (+ X 1))) + (defun-inline C (X) (B (r @*env*) (+ X 1))) + (C Y) + ) + "} + .to_string(), + ]); + let run_result = do_basic_brun(&vec!["brun".to_string(), prog, "(3)".to_string()]); + assert_eq!(run_result.trim(), "(i 4 5)"); +} + // Check for the optimizer to reduce a fully constant function call to a constant // and propogate through another expression. #[test] From cb9d95df788bc8e2d5e484024150076f971925ad Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 10:18:48 -0700 Subject: [PATCH 16/48] More tests from the future --- src/tests/classic/run.rs | 260 +++++++++++++++++++-------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 55d1d71a1..da281f0c3 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1276,6 +1276,136 @@ fn test_optimizer_fully_reduces_constant_outcome_sha256tree() { ); } +// Check for the optimizer to reduce a fully constant function call to a constant +// and propogate through another expression. +#[test] +fn test_optimizer_fully_reduces_constant_outcome_sha256tree_1() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))".to_string(), + ]); + assert_eq!( + res, + "(1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410)" + ); +} + +#[test] +fn test_g1_map_op_modern() { + let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; + let compiled = do_basic_run(&vec!["run".to_string(), program.to_string()]); + let output = do_basic_brun(&vec![ + "brun".to_string(), + compiled, + "(abcdef0123456789)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!( + output, + "0x88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a" + ); +} + +#[test] +fn test_optimizer_fully_reduces_constant_outcome_let_0() { + let res = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (A) (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (defun G (Q) (let ((R (F Q))) (+ R 1))) (+ A (G 3)))".to_string(), + ]); + // Tree shaking will remove the functions that became unused due to constant + // reduction. We now support suppressing the left env in stepping 23 and + // above. + assert_eq!( + res, + "(16 2 (1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410))" + ); +} + +// Test that the optimizer inverts (i (not x) a b) to (i x b a) +#[test] +fn test_not_inversion_body() { + let res = do_basic_run(&vec![ + "run".to_string(), + "(mod (X) (include *standard-cl-23*) (if (not X) (+ X 1) (* X 2)))".to_string(), + ]); + assert_eq!(res, "(2 (3 2 (1 18 2 (1 . 2)) (1 16 2 (1 . 1))) 1)"); +} + +// Test that we can test chialisp outcomes in chialisp. +#[test] +fn test_chialisp_in_chialisp_test_pos() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), + ]); + assert_eq!(compiled, "(1 . \"worked\")"); +} + +// Test that we can test chialisp outcomes in chialisp. +#[test] +fn test_chialisp_in_chialisp_test_neg() { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ (list X) 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), + ]); + assert_eq!(compiled, "(1 . \"didnt work\")"); +} + +// Test CSE when detections are inside a lambda. It's necessary to add a capture for +// the replaced expression. +#[test] +fn test_cse_replacement_inside_lambda_23_0() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/more_exhaustive/lambda_cse_1.clsp".to_string(), + ]); + let res = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(17 17)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(res, "0x15aa51"); + let res = do_basic_brun(&vec![ + "brun".to_string(), + program.clone(), + "(17 19)".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(res, "0x1b1019"); + let res = do_basic_brun(&vec!["brun".to_string(), program, "(19 17)".to_string()]) + .trim() + .to_string(); + assert_eq!(res, "0x1e3f2b"); +} + +#[test] +fn test_cse_replacement_inside_lambda_test_desugared_form_23() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests".to_string(), + "resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp".to_string(), + ]); + let res = do_basic_brun(&vec!["brun".to_string(), program, "(17 17)".to_string()]) + .trim() + .to_string(); + assert_eq!(res, "0x15aa51"); +} + #[test] fn test_defmac_assert_smoke_preprocess_23() { let result_prog = do_basic_run(&vec![ @@ -1615,136 +1745,6 @@ fn test_smoke_inline_at_expansion_var_23_7() { assert_eq!(run_result.trim(), "(i 4 5)"); } -// Check for the optimizer to reduce a fully constant function call to a constant -// and propogate through another expression. -#[test] -fn test_optimizer_fully_reduces_constant_outcome_sha256tree_1() { - let res = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "(mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))".to_string(), - ]); - assert_eq!( - res, - "(1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410)" - ); -} - -#[test] -fn test_g1_map_op_modern() { - let program = "(mod (S) (include *standard-cl-21*) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; - let compiled = do_basic_run(&vec!["run".to_string(), program.to_string()]); - let output = do_basic_brun(&vec![ - "brun".to_string(), - compiled, - "(abcdef0123456789)".to_string(), - ]) - .trim() - .to_string(); - assert_eq!( - output, - "0x88e7302bf1fa8fcdecfb96f6b81475c3564d3bcaf552ccb338b1c48b9ba18ab7195c5067fe94fb216478188c0a3bef4a" - ); -} - -#[test] -fn test_optimizer_fully_reduces_constant_outcome_let_0() { - let res = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "(mod (A) (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (defun G (Q) (let ((R (F Q))) (+ R 1))) (+ A (G 3)))".to_string(), - ]); - // Tree shaking will remove the functions that became unused due to constant - // reduction. We now support suppressing the left env in stepping 23 and - // above. - assert_eq!( - res, - "(16 2 (1 . -39425664269051251592384450451821132878837081010681666327853404714379049572410))" - ); -} - -// Test that the optimizer inverts (i (not x) a b) to (i x b a) -#[test] -fn test_not_inversion_body() { - let res = do_basic_run(&vec![ - "run".to_string(), - "(mod (X) (include *standard-cl-23*) (if (not X) (+ X 1) (* X 2)))".to_string(), - ]); - assert_eq!(res, "(2 (3 2 (1 18 2 (1 . 2)) (1 16 2 (1 . 1))) 1)"); -} - -// Test that we can test chialisp outcomes in chialisp. -#[test] -fn test_chialisp_in_chialisp_test_pos() { - let compiled = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ X 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), - ]); - assert_eq!(compiled, "(1 . \"worked\")"); -} - -// Test that we can test chialisp outcomes in chialisp. -#[test] -fn test_chialisp_in_chialisp_test_neg() { - let compiled = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "(mod (X) (include *standard-cl-23*) (if (= (f (mod () (include *standard-cl-23*) (include sha256tree.clib) (defun F (X) (sha256tree (+ (list X) 1))) (+ (F 3) 1))) 1) \"worked\" \"didnt work\"))".to_string(), - ]); - assert_eq!(compiled, "(1 . \"didnt work\")"); -} - -// Test CSE when detections are inside a lambda. It's necessary to add a capture for -// the replaced expression. -#[test] -fn test_cse_replacement_inside_lambda_23_0() { - let program = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "resources/tests/more_exhaustive/lambda_cse_1.clsp".to_string(), - ]); - let res = do_basic_brun(&vec![ - "brun".to_string(), - program.clone(), - "(17 17)".to_string(), - ]) - .trim() - .to_string(); - assert_eq!(res, "0x15aa51"); - let res = do_basic_brun(&vec![ - "brun".to_string(), - program.clone(), - "(17 19)".to_string(), - ]) - .trim() - .to_string(); - assert_eq!(res, "0x1b1019"); - let res = do_basic_brun(&vec!["brun".to_string(), program, "(19 17)".to_string()]) - .trim() - .to_string(); - assert_eq!(res, "0x1e3f2b"); -} - -#[test] -fn test_cse_replacement_inside_lambda_test_desugared_form_23() { - let program = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests".to_string(), - "resources/tests/more_exhaustive/lambda_cse_1_desugared_form.clsp".to_string(), - ]); - let res = do_basic_brun(&vec!["brun".to_string(), program, "(17 17)".to_string()]) - .trim() - .to_string(); - assert_eq!(res, "0x15aa51"); -} - // Note: this program is intentionally made to properly preprocess but trigger // an error in strict compilation as a demonstration and test that the preprocessor // is a mechanically separate step from compilation. Separating them like this From 68b418af1dd7c408f4c91c6a61521ba97ad6a459 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 10:56:47 -0700 Subject: [PATCH 17/48] Bring in more tests --- resources/tests/strict/big-maybe.clsp | 9 + .../tests/strict/chialisp-web-example.clsp | 71 +++++ .../tests/strict/cse_doesnt_dominate.clsp | 10 + .../cse_doesnt_dominate_superior_let.clsp | 12 + ...cse_doesnt_dominate_superior_let_iodi.clsp | 20 ++ .../cse_doesnt_dominate_superior_let_odi.clsp | 18 ++ ..._doesnt_dominate_superior_let_outside.clsp | 12 + ...ominate_superior_let_outside_in_defun.clsp | 16 ++ ...minate_superior_let_outside_in_inline.clsp | 16 ++ resources/tests/strict/defconst.clsp | 16 ++ resources/tests/strict/embed.clsp | 8 + resources/tests/strict/hello.txt | 1 + resources/tests/strict/map-example.clsp | 15 + resources/tests/strict/rosetta_code_abc.clsp | 76 +++++ .../strict/rosetta_code_abc_preprocessed.clsp | 13 + .../strict/rosetta_code_babbage_problem.clsp | 61 ++++ resources/tests/strict/use-w2.clsp | 9 + resources/tests/strict/use-w3.clsp | 9 + src/tests/classic/run.rs | 262 ++++++++++++++++++ 19 files changed, 654 insertions(+) create mode 100644 resources/tests/strict/big-maybe.clsp create mode 100644 resources/tests/strict/chialisp-web-example.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let_iodi.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let_odi.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let_outside.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_defun.clsp create mode 100644 resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_inline.clsp create mode 100644 resources/tests/strict/defconst.clsp create mode 100644 resources/tests/strict/embed.clsp create mode 100644 resources/tests/strict/hello.txt create mode 100644 resources/tests/strict/map-example.clsp create mode 100644 resources/tests/strict/rosetta_code_abc.clsp create mode 100644 resources/tests/strict/rosetta_code_abc_preprocessed.clsp create mode 100644 resources/tests/strict/rosetta_code_babbage_problem.clsp create mode 100644 resources/tests/strict/use-w2.clsp create mode 100644 resources/tests/strict/use-w3.clsp diff --git a/resources/tests/strict/big-maybe.clsp b/resources/tests/strict/big-maybe.clsp new file mode 100644 index 000000000..e40e180be --- /dev/null +++ b/resources/tests/strict/big-maybe.clsp @@ -0,0 +1,9 @@ +(mod (p) + + (include *standard-cl-23*) + + (defun fromMaybe (v (@ m (content))) (if m content v)) + (defun mapMaybe (f (@ m (content))) (if m (list (a f (list content))) ())) + + (fromMaybe 0 (mapMaybe (lambda ((@ pt (x y))) (+ x y)) p)) + ) diff --git a/resources/tests/strict/chialisp-web-example.clsp b/resources/tests/strict/chialisp-web-example.clsp new file mode 100644 index 000000000..1caf8427c --- /dev/null +++ b/resources/tests/strict/chialisp-web-example.clsp @@ -0,0 +1,71 @@ + (mod (X) + + ;; Specify that this program is compiled with *standard-cl-23*. + ;; After release, the chialisp compiler guarantees that programs + ;; with a specific sigil (including no sigil) compile to the + ;; same representation forever (it is a bug that must be fixed + ;; if a program changes representation in a future compiler + ;; release). In this way, program source code can also provide + ;; enough information to re-produce a puzzle hash from source + ;; code. + (include *standard-cl-23*) + + (defun n-additions-inner (n value i) + (if (> i n) + () + (qq (c (+ (unquote i) (unquote value)) (unquote (n-additions-inner n value (+ 1 i))))) + ) + ) + + (defmac n-additions (n value) (n-additions-inner n value 1)) + + (defun F (X) (n-additions 3 X)) + + (defun odd (X) (logand X 1)) + + ;; Usual higher order functions work like you might hope. + ;; This filter function takes a predicate, "pred", which + ;; returns a truthy value to include the result or nil. + ;; (@ lst (first . rest)) is similar to a similar + ;; destructuring form in haskell. + ;; (@ lst (first . rest)) + ;; generates the same bindings as simultaneously having + ;; (pred lst) + ;; and + ;; (pred (first . rest)) + ;; as an argument list. + (defun filter (pred (@ lst (first . rest))) + (if lst + (if (a pred (list first)) + (c first (filter pred rest)) + (filter pred rest) + ) + () + ) + ) + + ;; @ destructuring here takes the place of the + ;; whole argument list. + (defun sum (@ the-list (first . rest)) + (if the-list + (+ first (a sum rest)) + 0 + ) + ) + + (assign + ;; We can destructure the result based on its shape. + ;; Assign reorders and groups assignments based on their dependencies. + (A B C) result-list + + ;; The bindings can be in any order, like the let forms in elm, haskell + ;; and others. + result-list (F X) + + summed (a sum result-list) + odds (filter odd result-list) + + ;; Result of this form. + (list summed odds) + ) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate.clsp b/resources/tests/strict/cse_doesnt_dominate.clsp new file mode 100644 index 000000000..2c5f1d197 --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate.clsp @@ -0,0 +1,10 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (if X + (* (+ X 1) (+ X 1) (+ X 1)) + 17 + ) + ) \ No newline at end of file diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let.clsp new file mode 100644 index 000000000..505653d8b --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let.clsp @@ -0,0 +1,12 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (if X + (let ((Z X)) + (* (+ Z 1) (+ Z 1) (+ Z 1)) + ) + 17 + ) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let_iodi.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let_iodi.clsp new file mode 100644 index 000000000..aa27f8795 --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let_iodi.clsp @@ -0,0 +1,20 @@ +(mod (X) + (include *standard-cl-23*) + + (defun-inline L (Z X) (* (+ Z 1) (+ Z 1) (+ Z 1) (+ X 1) (+ X 1) (+ X 1))) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (defun-inline F1 (X) + (let ((Z X)) + (if X + (L Z X) + 17 + ) + ) + ) + + (defun F (X) (F1 X)) + + (F X) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let_odi.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let_odi.clsp new file mode 100644 index 000000000..595a08019 --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let_odi.clsp @@ -0,0 +1,18 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (defun-inline F1 (X) + (let ((Z X)) + (if X + (* (+ Z 1) (+ Z 1) (+ Z 1) (+ X 1) (+ X 1) (+ X 1)) + 17 + ) + ) + ) + + (defun F (X) (F1 X)) + + (F X) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let_outside.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside.clsp new file mode 100644 index 000000000..1c970b850 --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside.clsp @@ -0,0 +1,12 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (let ((Z X)) + (if X + (* (+ Z 1) (+ Z 1) (+ Z 1) (+ X 1) (+ X 1) (+ X 1)) + 17 + ) + ) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_defun.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_defun.clsp new file mode 100644 index 000000000..3ed8f182f --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_defun.clsp @@ -0,0 +1,16 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (defun F (X) + (let ((Z X)) + (if X + (* (+ Z 1) (+ Z 1) (+ Z 1) (+ X 1) (+ X 1) (+ X 1)) + 17 + ) + ) + ) + + (F X) + ) diff --git a/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_inline.clsp b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_inline.clsp new file mode 100644 index 000000000..6790877fc --- /dev/null +++ b/resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_inline.clsp @@ -0,0 +1,16 @@ +(mod (X) + (include *standard-cl-23*) + + ;; (+ X 1) should be an eliminated subexpression but it doesn't dominate the + ;; condition. + (defun-inline F (X) + (let ((Z X)) + (if X + (* (+ Z 1) (+ Z 1) (+ Z 1) (+ X 1) (+ X 1) (+ X 1)) + 17 + ) + ) + ) + + (F X) + ) diff --git a/resources/tests/strict/defconst.clsp b/resources/tests/strict/defconst.clsp new file mode 100644 index 000000000..97c90794d --- /dev/null +++ b/resources/tests/strict/defconst.clsp @@ -0,0 +1,16 @@ +(mod (Z) + + (include *standard-cl-23*) + ; takes a lisp tree and returns the hash of it + + (defun sha256tree1 (TREE) + (if (l TREE) + (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) + (sha256 1 TREE) + ) + ) + + (defconst HELLO_HASH (sha256tree1 (c "hello" "world"))) + + (sha256 HELLO_HASH Z) + ) diff --git a/resources/tests/strict/embed.clsp b/resources/tests/strict/embed.clsp new file mode 100644 index 000000000..72e3fcca9 --- /dev/null +++ b/resources/tests/strict/embed.clsp @@ -0,0 +1,8 @@ +(mod (Z) + + (include *standard-cl-23*) + + (embed-file hello-data bin "hello.txt") + + (sha256 hello-data Z) + ) diff --git a/resources/tests/strict/hello.txt b/resources/tests/strict/hello.txt new file mode 100644 index 000000000..ce0136250 --- /dev/null +++ b/resources/tests/strict/hello.txt @@ -0,0 +1 @@ +hello diff --git a/resources/tests/strict/map-example.clsp b/resources/tests/strict/map-example.clsp new file mode 100644 index 000000000..79eb30dff --- /dev/null +++ b/resources/tests/strict/map-example.clsp @@ -0,0 +1,15 @@ +(mod (Z) + + (include *standard-cl-23*) + + (defun add-one (X) (+ X 1)) + + (defun map (F L) + (if L + (c (a F (list (f L))) (map F (r L))) + () + ) + ) + + (map add-one Z) + ) diff --git a/resources/tests/strict/rosetta_code_abc.clsp b/resources/tests/strict/rosetta_code_abc.clsp new file mode 100644 index 000000000..d460f8ea2 --- /dev/null +++ b/resources/tests/strict/rosetta_code_abc.clsp @@ -0,0 +1,76 @@ +;; Adapted from https://rosettacode.org/wiki/ABC_problem#Scheme +(mod (word) + + (include *standard-cl-23*) + + (defconst *blocks* + (list + (c "B" "O") (c "X" "K") (c "D" "Q") (c "C" "P") (c "N" "A") + (c "G" "T") (c "R" "E") (c "T" "G") (c "Q" "D") (c "F" "S") + (c "J" "W") (c "H" "U") (c "V" "I") (c "A" "N") (c "O" "B") + (c "E" "R") (c "F" "S") (c "L" "Y") (c "P" "C") (c "Z" "M"))) + + (defun-inline block-member (e s) + (logior (= e (f s)) (= e (r s))) + ) + + ;; Make short-circuiting and. + (defun and_ (CLAUSES) + (if (r CLAUSES) + (qq (if (unquote (f CLAUSES)) (unquote (and_ (r CLAUSES))) ())) + (f CLAUSES) + ) + ) + + (defmac and CLAUSES (if CLAUSES (and_ CLAUSES) 1)) + + ;; Make short-circuiting or. + (defun or_ (CLAUSES) + (if (r CLAUSES) + (qq (if (unquote (f CLAUSES)) 1 (unquote (or_ (r CLAUSES))))) + (f CLAUSES) + ) + ) + + (defmac or CLAUSES (if CLAUSES (or_ CLAUSES) ())) + + (defun exists (p? li) + (and li (or (a p? (list (f li))) (exists p? (r li)))) + ) + + (defun remove-one (x li) + (or + (not li) + (if (and (= (f (f li)) (f x)) (= (r (f li)) (r x))) + (r li) + (c (f li) (remove-one x (r li))) + ) + ) + ) + + (defun can-make-list? (li blocks) + (or + (not li) + (exists + (lambda ((& li blocks) block) + (and + (block-member (f li) block) + (can-make-list? (r li) (remove-one block blocks)) + ) + ) + blocks + ) + ) + ) + + (defun can-make-word? (word) (can-make-list? word *blocks*)) + + (defun wordify (W) + (if W + (c (substr W 0 1) (wordify (substr W 1))) + () + ) + ) + + (can-make-word? (wordify word)) + ) diff --git a/resources/tests/strict/rosetta_code_abc_preprocessed.clsp b/resources/tests/strict/rosetta_code_abc_preprocessed.clsp new file mode 100644 index 000000000..d07e850b2 --- /dev/null +++ b/resources/tests/strict/rosetta_code_abc_preprocessed.clsp @@ -0,0 +1,13 @@ +(mod (word) + (include *standard-cl-23*) + + (defconst *blocks* (4 (c "B" "O") (4 (c "X" "K") (4 (c "D" "Q") (4 (c "C" "P") (4 (c "N" "A") (4 (c "G" "T") (4 (c "R" "E") (4 (c "T" "G") (4 (c "Q" "D") (4 (c "F" "S") (4 (c "J" "W") (4 (c "H" "U") (4 (c "V" "I") (4 (c "A" "N") (4 (c "O" "B") (4 (c "E" "R") (4 (c "F" "S") (4 (c "L" "Y") (4 (c "P" "C") (4 (c "Z" "M") ()))))))))))))))))))))) + + (defun-inline block-member (e_$_420 s_$_421) (logior (= e_$_420 (f s_$_421)) (= e_$_420 (r s_$_421)))) + (defun exists (p?_$_428 li_$_429) (a (i li_$_429 (com (a (i (a p?_$_428 (4 (f li_$_429) ())) (com 1) (com (exists p?_$_428 (r li_$_429)))) @)) (com ())) @)) + (defun remove-one (x_$_430 li_$_431) (a (i (not li_$_431) (com 1) (com (a (i (a (i (= (f (f li_$_431)) (f x_$_430)) (com (= (r (f li_$_431)) (r x_$_430))) (com ())) @) (com (r li_$_431)) (com (c (f li_$_431) (remove-one x_$_430 (r li_$_431))))) @))) @)) + (defun can-make-list? (li_$_432 blocks_$_433) (a (i (not li_$_432) (com 1) (com (exists (lambda ((& li_$_432 blocks_$_433) block_$_434) (a (i (block-member (f li_$_432) block_$_434) (com (can-make-list? (r li_$_432) (remove-one block_$_434 blocks_$_433))) (com ())) @)) blocks_$_433))) @)) + (defun can-make-word? (word_$_435) (can-make-list? word_$_435 *blocks*)) (defun wordify (W_$_436) (a (i W_$_436 (com (c (substr W_$_436 () 1) (wordify (substr W_$_436 1)))) (com ())) @)) + + (can-make-word? (wordify word)) + ) diff --git a/resources/tests/strict/rosetta_code_babbage_problem.clsp b/resources/tests/strict/rosetta_code_babbage_problem.clsp new file mode 100644 index 000000000..55b00b455 --- /dev/null +++ b/resources/tests/strict/rosetta_code_babbage_problem.clsp @@ -0,0 +1,61 @@ +;; Adapted from: https://rosettacode.org/wiki/Babbage_problem#Scheme +(mod (N) + (include *standard-cl-23*) + + (defun digits_ (result n) + (assign + (d . r) (divmod n 10) + (if d + (digits_ (c r result) d) + (c r result) + ) + ) + ) + + (defun digits (n) (if n (digits_ () n) ())) + + (defun reverse_ (result lst) + (if lst + (reverse_ (c (f lst) result) (r lst)) + result + ) + ) + + (defun reverse (lst) (reverse_ () lst)) + + (defun starts-with (lst prefix) + (if prefix + (if lst + (if (= (f prefix) (f lst)) + (starts-with (r lst) (r prefix)) + () + ) + () + ) + 1 + ) + ) + + (defun ends-with (lst tail) + ;; does list end with tail? + (starts-with (reverse lst) (reverse tail)) + ) + + (defun loop (start fun) + (let ((res (a fun (list start)))) + (if res + (f res) + (loop (+ 1 start) fun) + ) + ) + ) + + (loop 1 + (lambda ((& N) idx) + (if (ends-with (digits (* idx idx)) (digits N)) + (list idx) + () + ) + ) + ) + ) diff --git a/resources/tests/strict/use-w2.clsp b/resources/tests/strict/use-w2.clsp new file mode 100644 index 000000000..63da2fd7c --- /dev/null +++ b/resources/tests/strict/use-w2.clsp @@ -0,0 +1,9 @@ +(mod (items) + (include *standard-cl-23*) + + (defun assert_ (items_$_41) (letbinding_$_44 (r @*env*) (f items_$_41))) + (defun-inline letbinding_$_44 ((items_$_41) cse_$_43) + (a (com cse_$_43) @) + ) + (assert_ items) + ) diff --git a/resources/tests/strict/use-w3.clsp b/resources/tests/strict/use-w3.clsp new file mode 100644 index 000000000..742707d58 --- /dev/null +++ b/resources/tests/strict/use-w3.clsp @@ -0,0 +1,9 @@ +(mod (items) + (include *standard-cl-23*) + + (defun assert_ (items_$_41) (letbinding_$_44 (r @*env*) (f items_$_41))) + (defun letbinding_$_44 ((items_$_41) cse_$_43) + (a (com cse_$_43) @) + ) + (assert_ items) + ) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index da281f0c3..5578e1741 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1745,6 +1745,268 @@ fn test_smoke_inline_at_expansion_var_23_7() { assert_eq!(run_result.trim(), "(i 4 5)"); } +// +// Inside assert_ (items): +// items @ 5 +// +// Inside letbinding_$_44 ((items) cse_$_43_$_24) +// +// items @ 9 +// cse_$_43_$_24 @ 11 +// +#[test] +fn test_inline_vs_deinline_23() { + eprintln!("=== W2 ==="); + let compiled_2 = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/use-w2.clsp".to_string(), + ]); + eprintln!("=== W3 ==="); + let compiled_3 = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/use-w3.clsp".to_string(), + ]); + eprintln!("=== RUN W2 ==="); + let result_2 = do_basic_brun(&vec![ + "brun".to_string(), + compiled_2, + "((1 2 3))".to_string(), + ]); + eprintln!("=== RUN W3 ==="); + let result_3 = do_basic_brun(&vec![ + "brun".to_string(), + compiled_3, + "((1 2 3))".to_string(), + ]); + assert_eq!(result_2, result_3); +} + +#[test] +fn test_rosetta_code_abc_example() { + let test_words = &[ + ("A", true), + ("BARK", true), + ("TREAT", true), + ("BOOK", false), + ("COMMON", false), + ("SQUAD", true), + ("CONFUSE", true), + ]; + let prog_pp = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/rosetta_code_abc.clsp".to_string(), + ]); + let prog_np = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/rosetta_code_abc_preprocessed.clsp".to_string(), + ]); + eprintln!("{prog_pp}"); + assert_eq!(prog_pp, prog_np); + for (w, success) in test_words.iter() { + eprintln!("{} {}", w, success); + let result = do_basic_brun(&vec![ + "brun".to_string(), + prog_pp.clone(), + format!("({})", w), + ]) + .trim() + .to_string(); + if *success { + assert_eq!(result, "1"); + } else { + assert_eq!(result, "()"); + } + } +} + +#[test] +fn test_rosetta_code_babbage_problem() { + let preprocessed = do_basic_run(&vec![ + "run".to_string(), + "-E".to_string(), + "resources/tests/strict/rosetta_code_babbage_problem.clsp".to_string(), + ]); + assert!(!preprocessed.contains("*macros*")); + assert!(!preprocessed.contains("(defmacro list")); + let compiled = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/rosetta_code_babbage_problem.clsp".to_string(), + ]); + let output = do_basic_brun(&vec!["brun".to_string(), compiled, "(269696)".to_string()]) + .trim() + .to_string(); + assert_eq!(output, "25264"); +} + +#[test] +fn test_cse_when_not_dominating_conditions() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x009988"); // 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x009988"); // 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let_outside() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let_outside.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x5c13d840"); // 34 * 34 * 34 * 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let_outside_in_inline() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_inline.clsp" + .to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x5c13d840"); // 34 * 34 * 34 * 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let_outside_in_defun() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let_outside_in_defun.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x5c13d840"); // 34 * 34 * 34 * 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let_odi() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let_odi.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x5c13d840"); // 34 * 34 * 34 * 34 * 34 * 34 +} + +#[test] +fn test_cse_not_dominating_conditions_with_superior_let_iodi() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/cse_doesnt_dominate_superior_let_iodi.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(33)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "0x5c13d840"); // 34 * 34 * 34 * 34 * 34 * 34 +} + +#[test] +fn test_chialisp_web_example() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/chialisp-web-example.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(100)".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "(306 (101 103))"); +} + +#[test] +fn test_chialisp_web_example_defconst() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/defconst.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(3)".to_string()]) + .trim() + .to_string(); + assert_eq!( + outcome, + "0xf60efb25b9e6e3587acd9cf01c332707bb771801bdb5e4f50ea957a29c8dde89" + ); +} + +#[test] +fn test_chialisp_web_example_big_maybe() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/big-maybe.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(((3 5)))".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "8"); +} + +#[test] +fn test_chialisp_web_example_map() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/map-example.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "((1 2 3))".to_string()]) + .trim() + .to_string(); + assert_eq!(outcome, "(a 3 4)"); +} + +#[test] +fn test_chialisp_web_example_map_lambda() { + let program = do_basic_run(&vec![ + "run".to_string(), + "resources/tests/strict/map-example.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec![ + "brun".to_string(), + program, + "((100 101 102))".to_string(), + ]) + .trim() + .to_string(); + assert_eq!(outcome, "(101 102 103)"); +} + +#[test] +fn test_chialisp_web_example_embed() { + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/embed.clsp".to_string(), + ]); + let outcome = do_basic_brun(&vec!["brun".to_string(), program, "(world)".to_string()]) + .trim() + .to_string(); + assert_eq!( + outcome, + "0x26c60a61d01db5836ca70fefd44a6a016620413c8ef5f259a6c5612d4f79d3b8" + ); +} + // Note: this program is intentionally made to properly preprocess but trigger // an error in strict compilation as a demonstration and test that the preprocessor // is a mechanically separate step from compilation. Separating them like this From e37ea0d113452829ecbee2790414208f4d1a9c4a Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 25 Oct 2023 11:15:26 -0700 Subject: [PATCH 18/48] Pin down repr more with singleton test --- .../strict/includes/condition_codes.clib | 38 +++ .../strict/includes/curry-and-treehash.clib | 72 ++++ .../strict/includes/singleton_truths.clib | 21 ++ .../tests/strict/singleton_top_layer.clsp | 168 ++++++++++ src/compiler/optimize/mod.rs | 1 - src/tests/classic/run.rs | 120 +++---- src/tests/compiler/mod.rs | 1 + src/tests/compiler/singleton.rs | 314 ++++++++++++++++++ 8 files changed, 674 insertions(+), 61 deletions(-) create mode 100644 resources/tests/strict/includes/condition_codes.clib create mode 100644 resources/tests/strict/includes/curry-and-treehash.clib create mode 100644 resources/tests/strict/includes/singleton_truths.clib create mode 100644 resources/tests/strict/singleton_top_layer.clsp create mode 100644 src/tests/compiler/singleton.rs diff --git a/resources/tests/strict/includes/condition_codes.clib b/resources/tests/strict/includes/condition_codes.clib new file mode 100644 index 000000000..f8f607ccd --- /dev/null +++ b/resources/tests/strict/includes/condition_codes.clib @@ -0,0 +1,38 @@ +; See chia/types/condition_opcodes.py + +( + (defconstant AGG_SIG_UNSAFE 49) + (defconstant AGG_SIG_ME 50) + + ; the conditions below reserve coin amounts and have to be accounted for in output totals + + (defconstant CREATE_COIN 51) + (defconstant RESERVE_FEE 52) + + ; the conditions below deal with announcements, for inter-coin communication + + ; coin announcements + (defconstant CREATE_COIN_ANNOUNCEMENT 60) + (defconstant ASSERT_COIN_ANNOUNCEMENT 61) + + ; puzzle announcements + (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) + (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) + + ; the conditions below let coins inquire about themselves + + (defconstant ASSERT_MY_COIN_ID 70) + (defconstant ASSERT_MY_PARENT_ID 71) + (defconstant ASSERT_MY_PUZZLEHASH 72) + (defconstant ASSERT_MY_AMOUNT 73) + + ; the conditions below ensure that we're "far enough" in the future + + ; wall-clock time + (defconstant ASSERT_SECONDS_RELATIVE 80) + (defconstant ASSERT_SECONDS_ABSOLUTE 81) + + ; block index + (defconstant ASSERT_HEIGHT_RELATIVE 82) + (defconstant ASSERT_HEIGHT_ABSOLUTE 83) +) diff --git a/resources/tests/strict/includes/curry-and-treehash.clib b/resources/tests/strict/includes/curry-and-treehash.clib new file mode 100644 index 000000000..8f985ffe9 --- /dev/null +++ b/resources/tests/strict/includes/curry-and-treehash.clib @@ -0,0 +1,72 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `sha256tree`. + + (defconstant ONE 1) + (defconstant TWO 2) + (defconstant A_KW #a) + (defconstant Q_KW #q) + (defconstant C_KW #c) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 TWO (sha256 ONE C_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash`, updating `environment-hash` + ;; along the way. + + (defun build-curry-list (reversed-curry-parameter-hashes environment-hash) + (if reversed-curry-parameter-hashes + (build-curry-list (r reversed-curry-parameter-hashes) + (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash)) + environment-hash + ) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `function-hash` of a function tree F + ;; return the tree hash of the tree corresponding to + ;; `(a (q . F) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . F) E)` = `(a . ((q . F) . (E . 0)))` + + (defun-inline tree-hash-of-apply (function-hash environment-hash) + (sha256 TWO (sha256 ONE A_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; function-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; reversed-curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; Note that this must be applied in REVERSED order. This may seem strange, but it greatly simplifies + ;; the underlying code, since we calculate the tree hash from the bottom nodes up, and the last + ;; parameters curried must have their hashes calculated first. + ;; + ;; we return the hash of the curried expression + ;; (a (q . function-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the acutal curried program. + + (defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) + (tree-hash-of-apply function-hash + (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))) + ) +) diff --git a/resources/tests/strict/includes/singleton_truths.clib b/resources/tests/strict/includes/singleton_truths.clib new file mode 100644 index 000000000..fe673eedc --- /dev/null +++ b/resources/tests/strict/includes/singleton_truths.clib @@ -0,0 +1,21 @@ +( + (defun-inline truth_data_to_truth_struct (my_id full_puzhash innerpuzhash my_amount lineage_proof singleton_struct) (c (c my_id full_puzhash) (c (c innerpuzhash my_amount) (c lineage_proof singleton_struct)))) + + (defun-inline my_id_truth (Truths) (f (f Truths))) + (defun-inline my_full_puzzle_hash_truth (Truths) (r (f Truths))) + (defun-inline my_inner_puzzle_hash_truth (Truths) (f (f (r Truths)))) + (defun-inline my_amount_truth (Truths) (r (f (r Truths)))) + (defun-inline my_lineage_proof_truth (Truths) (f (r (r Truths)))) + (defun-inline singleton_struct_truth (Truths) (r (r (r Truths)))) + + (defun-inline singleton_mod_hash_truth (Truths) (f (singleton_struct_truth Truths))) + (defun-inline singleton_launcher_id_truth (Truths) (f (r (singleton_struct_truth Truths)))) + (defun-inline singleton_launcher_puzzle_hash_truth (Truths) (f (r (r (singleton_struct_truth Truths))))) + + (defun-inline parent_info_for_lineage_proof (lineage_proof) (f lineage_proof)) + (defun-inline puzzle_hash_for_lineage_proof (lineage_proof) (f (r lineage_proof))) + (defun-inline amount_for_lineage_proof (lineage_proof) (f (r (r lineage_proof)))) + (defun-inline is_not_eve_proof (lineage_proof) (r (r lineage_proof))) + (defun-inline parent_info_for_eve_proof (lineage_proof) (f lineage_proof)) + (defun-inline amount_for_eve_proof (lineage_proof) (f (r lineage_proof))) +) \ No newline at end of file diff --git a/resources/tests/strict/singleton_top_layer.clsp b/resources/tests/strict/singleton_top_layer.clsp new file mode 100644 index 000000000..805c0a485 --- /dev/null +++ b/resources/tests/strict/singleton_top_layer.clsp @@ -0,0 +1,168 @@ +(mod (SINGLETON_STRUCT INNER_PUZZLE lineage_proof my_amount inner_solution) + + ;; SINGLETON_STRUCT = (MOD_HASH . (LAUNCHER_ID . LAUNCHER_PUZZLE_HASH)) + + ; SINGLETON_STRUCT, INNER_PUZZLE are curried in by the wallet + + ; EXAMPLE SOLUTION '(0xfadeddab 0xdeadbeef 1 (0xdeadbeef 200) 50 ((51 0xfadeddab 100) (60 "trash") (51 deadbeef 0)))' + + + ; This puzzle is a wrapper around an inner smart puzzle which guarantees uniqueness. + ; It takes its singleton identity from a coin with a launcher puzzle which guarantees that it is unique. + (include *standard-cl-23*) + + (include condition_codes.clib) + (include curry-and-treehash.clib) + (include singleton_truths.clib) + + ; takes a lisp tree and returns the hash of it + (defun sha256tree1 (TREE) + (if (l TREE) + (sha256 2 (sha256tree1 (f TREE)) (sha256tree1 (r TREE))) + (sha256 1 TREE) + ) + ) + + (include defmac_assert.clib) + + (defun-inline mod_hash_for_singleton_struct (SINGLETON_STRUCT) (f SINGLETON_STRUCT)) + (defun-inline launcher_id_for_singleton_struct (SINGLETON_STRUCT) (f (r SINGLETON_STRUCT))) + (defun-inline launcher_puzzle_hash_for_singleton_struct (SINGLETON_STRUCT) (r (r SINGLETON_STRUCT))) + + ;; return the full puzzlehash for a singleton with the innerpuzzle curried in + ; puzzle-hash-of-curried-function is imported from curry-and-treehash.clib + (defun-inline calculate_full_puzzle_hash (SINGLETON_STRUCT inner_puzzle_hash) + (puzzle-hash-of-curried-function (mod_hash_for_singleton_struct SINGLETON_STRUCT) + inner_puzzle_hash + (sha256tree1 SINGLETON_STRUCT) + ) + ) + + ; assembles information from the solution to create our own full ID including asserting our parent is a singleton + (defun create_my_ID (SINGLETON_STRUCT full_puzzle_hash parent_parent parent_inner_puzzle_hash parent_amount my_amount) + (sha256 (sha256 parent_parent (calculate_full_puzzle_hash SINGLETON_STRUCT parent_inner_puzzle_hash) parent_amount) + full_puzzle_hash + my_amount) + ) + + ;; take a boolean and a non-empty list of conditions + ;; strip off the first condition if a boolean is set + ;; this is used to remove `(CREATE_COIN xxx -113)` + ;; pretty sneaky, eh? + (defun strip_first_condition_if (boolean condition_list) + (if boolean + (r condition_list) + condition_list + ) + ) + + (defun-inline morph_condition (condition SINGLETON_STRUCT) + (list (f condition) (calculate_full_puzzle_hash SINGLETON_STRUCT (f (r condition))) (f (r (r condition)))) + ) + + ;; return the value of the coin created if this is a `CREATE_COIN` condition, or 0 otherwise + (defun-inline created_coin_value_or_0 (condition) + (if (= (f condition) CREATE_COIN) + (f (r (r condition))) + 0 + ) + ) + + ;; Returns a (bool . bool) + (defun odd_cons_m113 (output_amount) + (c + (= (logand output_amount 1) 1) ;; is it odd? + (= output_amount -113) ;; is it the escape value? + ) + ) + + ; Assert exactly one output with odd value exists - ignore it if value is -113 + + ;; this function iterates over the output conditions from the inner puzzle & solution + ;; and both checks that exactly one unique singleton child is created (with odd valued output), + ;; and wraps the inner puzzle with this same singleton wrapper puzzle + ;; + ;; The special case where the output value is -113 means a child singleton is intentionally + ;; *NOT* being created, thus forever ending this singleton's existence + + (defun check_and_morph_conditions_for_singleton (SINGLETON_STRUCT conditions has_odd_output_been_found) + (if conditions + (morph_next_condition SINGLETON_STRUCT conditions has_odd_output_been_found (odd_cons_m113 (created_coin_value_or_0 (f conditions)))) + (if has_odd_output_been_found + 0 + (x) ;; no odd output found + ) + ) + ) + + ;; a continuation of `check_and_morph_conditions_for_singleton` with booleans `is_output_odd` and `is_output_m113` + ;; precalculated + (defun morph_next_condition (SINGLETON_STRUCT conditions has_odd_output_been_found (is_output_odd . is_output_m113)) + (assert + (not (all is_output_odd has_odd_output_been_found)) + (strip_first_condition_if + is_output_m113 + (c (if is_output_odd + (morph_condition (f conditions) SINGLETON_STRUCT) + (f conditions) + ) + (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (r conditions) (any is_output_odd has_odd_output_been_found)) + ) + ) + ) + ) + + ; this final stager asserts our ID + ; it also runs the innerpuz with the innersolution with the "truths" added + ; it then passes that output conditions from the innerpuz to the morph conditions function + (defun stager_three (SINGLETON_STRUCT lineage_proof my_id full_puzhash innerpuzhash my_amount INNER_PUZZLE inner_solution) + (c (list ASSERT_MY_COIN_ID my_id) (check_and_morph_conditions_for_singleton SINGLETON_STRUCT (a INNER_PUZZLE (c (truth_data_to_truth_struct my_id full_puzhash innerpuzhash my_amount lineage_proof SINGLETON_STRUCT) inner_solution)) 0)) + ) + + ; this checks whether we are an eve spend or not and calculates our full coin ID appropriately and passes it on to the final stager + ; if we are the eve spend it also adds the additional checks that our parent's puzzle is the standard launcher format and that out parent ID is the same as our singleton ID + + (defun stager_two (SINGLETON_STRUCT lineage_proof full_puzhash innerpuzhash my_amount INNER_PUZZLE inner_solution) + (stager_three + SINGLETON_STRUCT + lineage_proof + (if (is_not_eve_proof lineage_proof) + (create_my_ID + SINGLETON_STRUCT + full_puzhash + (parent_info_for_lineage_proof lineage_proof) + (puzzle_hash_for_lineage_proof lineage_proof) + (amount_for_lineage_proof lineage_proof) + my_amount + ) + (if (= + (launcher_id_for_singleton_struct SINGLETON_STRUCT) + (sha256 (parent_info_for_eve_proof lineage_proof) (launcher_puzzle_hash_for_singleton_struct SINGLETON_STRUCT) (amount_for_eve_proof lineage_proof)) + ) + (sha256 (launcher_id_for_singleton_struct SINGLETON_STRUCT) full_puzhash my_amount) + (x) + ) + ) + full_puzhash + innerpuzhash + my_amount + INNER_PUZZLE + inner_solution + ) + ) + + ; this calculates our current full puzzle hash and passes it to stager two + (defun stager_one (SINGLETON_STRUCT lineage_proof my_innerpuzhash my_amount INNER_PUZZLE inner_solution) + (stager_two SINGLETON_STRUCT lineage_proof (calculate_full_puzzle_hash SINGLETON_STRUCT my_innerpuzhash) my_innerpuzhash my_amount INNER_PUZZLE inner_solution) + ) + + + ; main + + ; if our value is not an odd amount then we are invalid + ; this calculates my_innerpuzhash and passes all values to stager_one + (if (logand my_amount 1) + (stager_one SINGLETON_STRUCT lineage_proof (sha256tree1 INNER_PUZZLE) my_amount INNER_PUZZLE inner_solution) + (x) + ) +) diff --git a/src/compiler/optimize/mod.rs b/src/compiler/optimize/mod.rs index 36a760909..ca7b19fb0 100644 --- a/src/compiler/optimize/mod.rs +++ b/src/compiler/optimize/mod.rs @@ -693,7 +693,6 @@ pub fn get_optimizer( loc: &Srcloc, opts: Rc, ) -> Result, CompileErr> { - eprintln!("dialect {:?} opt {} fe {}", opts.dialect(), opts.optimize(), opts.frontend_opt()); if let Some(s) = opts.dialect().stepping { if s < 21 { return Err(CompileErr( diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 5578e1741..206f9d7ba 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1406,6 +1406,66 @@ fn test_cse_replacement_inside_lambda_test_desugared_form_23() { assert_eq!(res, "0x15aa51"); } +// Note: this program is intentionally made to properly preprocess but trigger +// an error in strict compilation as a demonstration and test that the preprocessor +// is a mechanically separate step from compilation. Separating them like this +// has the advantage that you can emit preprocessed compiler input on its own +// and also that it internally untangles the stages and makes compilation simpler. +#[test] +fn test_defmac_if_smoke_preprocess() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "-E".to_string(), + "resources/tests/strict/defmac_if_smoke.clsp".to_string(), + ]); + assert_eq!( + result_prog, + "(mod () (include *strict-cl-21*) (a (i t1 (com t2) (com t3)) @))" + ); + let result2 = do_basic_run(&vec!["run".to_string(), result_prog]); + assert!(result2.contains("Unbound use")); + // Ensure that we're identifying one of the actually misused variables, but + // do not make a claim about which one is identified first. + assert!(result2.contains("of t1") || result2.contains("of t2") || result2.contains("of t3")); +} + +#[test] +fn test_defmac_assert_smoke_preprocess() { + let result_prog = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "-E".to_string(), + "resources/tests/strict/assert.clsp".to_string(), + ]); + assert_eq!( + result_prog, + "(mod (A) (include *strict-cl-21*) (a (i 1 (com (a (i A (com 13) (com (x))) @)) (com (x))) @))" + ); + let result_after_preproc = do_basic_run(&vec!["run".to_string(), result_prog]); + let result_with_preproc = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + "resources/tests/strict/assert.clsp".to_string(), + ]); + assert_eq!(result_after_preproc, result_with_preproc); + let run_result_true = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(15)".to_string(), + ]); + assert_eq!(run_result_true.trim(), "13"); + let run_result_false = do_basic_brun(&vec![ + "brun".to_string(), + result_with_preproc.clone(), + "(0)".to_string(), + ]); + assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); +} + #[test] fn test_defmac_assert_smoke_preprocess_23() { let result_prog = do_basic_run(&vec![ @@ -2007,66 +2067,6 @@ fn test_chialisp_web_example_embed() { ); } -// Note: this program is intentionally made to properly preprocess but trigger -// an error in strict compilation as a demonstration and test that the preprocessor -// is a mechanically separate step from compilation. Separating them like this -// has the advantage that you can emit preprocessed compiler input on its own -// and also that it internally untangles the stages and makes compilation simpler. -#[test] -fn test_defmac_if_smoke_preprocess() { - let result_prog = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests/strict".to_string(), - "-E".to_string(), - "resources/tests/strict/defmac_if_smoke.clsp".to_string(), - ]); - assert_eq!( - result_prog, - "(mod () (include *strict-cl-21*) (a (i t1 (com t2) (com t3)) @))" - ); - let result2 = do_basic_run(&vec!["run".to_string(), result_prog]); - assert!(result2.contains("Unbound use")); - // Ensure that we're identifying one of the actually misused variables, but - // do not make a claim about which one is identified first. - assert!(result2.contains("of t1") || result2.contains("of t2") || result2.contains("of t3")); -} - -#[test] -fn test_defmac_assert_smoke_preprocess() { - let result_prog = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests/strict".to_string(), - "-E".to_string(), - "resources/tests/strict/assert.clsp".to_string(), - ]); - assert_eq!( - result_prog, - "(mod (A) (include *strict-cl-21*) (a (i 1 (com (a (i A (com 13) (com (x))) @)) (com (x))) @))" - ); - let result_after_preproc = do_basic_run(&vec!["run".to_string(), result_prog]); - let result_with_preproc = do_basic_run(&vec![ - "run".to_string(), - "-i".to_string(), - "resources/tests/strict".to_string(), - "resources/tests/strict/assert.clsp".to_string(), - ]); - assert_eq!(result_after_preproc, result_with_preproc); - let run_result_true = do_basic_brun(&vec![ - "brun".to_string(), - result_with_preproc.clone(), - "(15)".to_string(), - ]); - assert_eq!(run_result_true.trim(), "13"); - let run_result_false = do_basic_brun(&vec![ - "brun".to_string(), - result_with_preproc.clone(), - "(0)".to_string(), - ]); - assert_eq!(run_result_false.trim(), "FAIL: clvm raise ()"); -} - #[test] fn test_g1_map_op_classic() { let program = "(mod (S) (g1_map S \"BLS_SIG_BLS12381G1_XMD:SHA-256_SSWU_RO_AUG_\"))"; diff --git a/src/tests/compiler/mod.rs b/src/tests/compiler/mod.rs index a3098ce49..4fb8e437f 100644 --- a/src/tests/compiler/mod.rs +++ b/src/tests/compiler/mod.rs @@ -14,6 +14,7 @@ mod preprocessor; mod repl; mod restargs; mod runtypes; +mod singleton; mod srcloc; mod usecheck; diff --git a/src/tests/compiler/singleton.rs b/src/tests/compiler/singleton.rs new file mode 100644 index 000000000..68aaedacf --- /dev/null +++ b/src/tests/compiler/singleton.rs @@ -0,0 +1,314 @@ +use sha2::{Digest, Sha256}; +use std::rc::Rc; + +use clvmr::allocator::Allocator; + +use num_bigint::ToBigInt; + +use crate::classic::clvm::__type_compatibility__::{bi_one, Bytes, BytesFromType, Stream}; +use crate::classic::clvm::serialize::{sexp_from_stream, SimpleCreateCLVMObject}; +use crate::classic::clvm_tools::binutils::disassemble; +use crate::compiler::clvm::sha256tree; +use crate::compiler::prims::{primapply, primcons, primquote}; +use crate::compiler::sexp::{enlist, parse_sexp, SExp}; +use crate::compiler::srcloc::Srcloc; +use crate::tests::classic::run::{do_basic_brun, do_basic_run}; +use crate::util::u8_from_number; + +// Tests of a strict compile of singleton_top_layer.clsp +// +// Includes ported code from singleton_top_layer.py and +// my test-singleton.py +// const SINGLETON_MOD_HASH: &[u8] = &[ +// 0x24, 0xe0, 0x44, 0x10, 0x1e, 0x57, 0xb3, 0xd8, 0xc9, 0x08, 0xb8, 0xa3, 0x8a, 0xd5, 0x78, 0x48, 0xaf, 0xd2, 0x9d, 0x3e, 0xec, 0xc4, 0x39, 0xdb, 0xa4, 0x5f, 0x44, 0x12, 0xdf, 0x49, 0x54, 0xfd +// ]; +const SINGLETON_LAUNCHER_BYTES: &[u8] = &[ + 0xff, 0x02, 0xff, 0xff, 0x01, 0xff, 0x04, 0xff, 0xff, 0x04, 0xff, 0x04, 0xff, 0xff, 0x04, 0xff, + 0x05, 0xff, 0xff, 0x04, 0xff, 0x0b, 0xff, 0x80, 0x80, 0x80, 0x80, 0xff, 0xff, 0x04, 0xff, 0xff, + 0x04, 0xff, 0x0a, 0xff, 0xff, 0x04, 0xff, 0xff, 0x02, 0xff, 0x0e, 0xff, 0xff, 0x04, 0xff, 0x02, + 0xff, 0xff, 0x04, 0xff, 0xff, 0x04, 0xff, 0x05, 0xff, 0xff, 0x04, 0xff, 0x0b, 0xff, 0xff, 0x04, + 0xff, 0x17, 0xff, 0x80, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, 0x80, 0xff, 0x80, 0x80, 0x80, + 0xff, 0x80, 0x80, 0x80, 0xff, 0xff, 0x04, 0xff, 0xff, 0x01, 0xff, 0x33, 0xff, 0x3c, 0xff, 0x02, + 0xff, 0xff, 0x03, 0xff, 0xff, 0x07, 0xff, 0x05, 0x80, 0xff, 0xff, 0x01, 0xff, 0x0b, 0xff, 0xff, + 0x01, 0x02, 0xff, 0xff, 0x02, 0xff, 0x0e, 0xff, 0xff, 0x04, 0xff, 0x02, 0xff, 0xff, 0x04, 0xff, + 0x09, 0xff, 0x80, 0x80, 0x80, 0x80, 0xff, 0xff, 0x02, 0xff, 0x0e, 0xff, 0xff, 0x04, 0xff, 0x02, + 0xff, 0xff, 0x04, 0xff, 0x0d, 0xff, 0x80, 0x80, 0x80, 0x80, 0x80, 0xff, 0xff, 0x01, 0xff, 0x0b, + 0xff, 0xff, 0x01, 0x01, 0xff, 0x05, 0x80, 0x80, 0xff, 0x01, 0x80, 0xff, 0x01, 0x80, 0x80, +]; + +lazy_static! { + pub static ref SINGLETON_LAUNCHER: String = { + let mut stream = Stream::new(Some(Bytes::new(Some(BytesFromType::Raw( + SINGLETON_LAUNCHER_BYTES.to_vec(), + ))))); + let mut allocator = Allocator::new(); + let code = sexp_from_stream( + &mut allocator, + &mut stream, + Box::new(SimpleCreateCLVMObject {}), + ) + .expect("should be able to parse binary"); + disassemble(&mut allocator, code.1, Some(0)) + }; +} + +const SINGLETON_LAUNCHER_HASH: &[u8] = &[ + 0xef, 0xf0, 0x75, 0x22, 0x49, 0x50, 0x60, 0xc0, 0x66, 0xf6, 0x6f, 0x32, 0xac, 0xc2, 0xa7, 0x7e, + 0x3a, 0x3e, 0x73, 0x7a, 0xca, 0x8b, 0xae, 0xa4, 0xd1, 0xa6, 0x4e, 0xa4, 0xcd, 0xc1, 0x3d, 0xa9, +]; +const FIRST_COIN_PARENT: &[u8] = &[ + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, + 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, +]; +const CREATE_COIN: usize = 51; + +#[derive(Clone, Debug)] +struct Coin { + parent_coin_id: Vec, + puzzle_hash: Vec, + amount: u64, +} + +fn std_hash(form: &[u8]) -> Vec { + let mut hasher = Sha256::new(); + hasher.update(&form); + hasher.finalize().to_vec() +} + +// Ported code from singleton_top_layer.py +fn generate_launcher_coin(parent_hash: &[u8], amount: u64) -> Coin { + Coin { + parent_coin_id: parent_hash.to_vec(), + puzzle_hash: SINGLETON_LAUNCHER_HASH.to_vec(), + amount, + } +} + +impl Coin { + fn name(&self) -> Vec { + let mut form = self.parent_coin_id.clone(); + form.append(&mut self.puzzle_hash.clone()); + let mut size_atom_bytes = u8_from_number(self.amount.to_bigint().unwrap()); + form.append(&mut size_atom_bytes); + std_hash(&form) + } +} + +fn curry(the_mod: Rc, new_args: &[Rc]) -> Rc { + let mut fixed_args = SExp::Integer(the_mod.loc(), bi_one()); + for arg in new_args.iter().rev() { + fixed_args = primcons( + the_mod.loc(), + Rc::new(primquote(the_mod.loc(), arg.clone())), + Rc::new(fixed_args), + ); + } + Rc::new(primapply( + the_mod.loc(), + Rc::new(primquote(the_mod.loc(), the_mod)), + Rc::new(fixed_args), + )) +} + +struct LineageProof { + parent_name: Vec, + inner_puzzle_hash: Option>, + amount: u64, +} + +struct SingletonLaunch { + inner_puzzle: Rc, + inner_puzzle_hash: Vec, + inner_puzzle_hash_atom: Rc, + curried_singleton: Rc, + curried_singleton_hash_atom: Rc, + amount: u64, + amount_atom: Rc, +} + +impl SingletonLaunch { + fn new(launcher_coin: Coin, program_file: &str, inner_puzzle: Rc, amount: u64) -> Self { + let compiled = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/strict/includes".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), // defmac_assert.clib + program_file.to_string(), + ]); + let amount_atom = Rc::new(SExp::Integer(inner_puzzle.loc(), bi_one())); + let parsed_compiled = + parse_sexp(inner_puzzle.loc(), compiled.bytes()).expect("should parse")[0].clone(); + let singleton_mod_hash = sha256tree(parsed_compiled.clone()); + let curried_singleton = curry( + parsed_compiled.clone(), + &[ + Rc::new(SExp::Cons( + inner_puzzle.loc(), + Rc::new(SExp::Atom(inner_puzzle.loc(), singleton_mod_hash.clone())), + Rc::new(SExp::Cons( + inner_puzzle.loc(), + Rc::new(SExp::Atom(inner_puzzle.loc(), launcher_coin.name())), + Rc::new(SExp::Atom( + inner_puzzle.loc(), + SINGLETON_LAUNCHER_HASH.to_vec(), + )), + )), + )), + inner_puzzle.clone(), + ], + ); + let inner_puzzle_hash = sha256tree(inner_puzzle.clone()); + let inner_puzzle_hash_atom = + Rc::new(SExp::Atom(inner_puzzle.loc(), inner_puzzle_hash.clone())); + let curried_singleton_hash = sha256tree(curried_singleton.clone()); + SingletonLaunch { + inner_puzzle_hash, + inner_puzzle_hash_atom, + curried_singleton_hash_atom: Rc::new(SExp::Atom( + inner_puzzle.loc(), + curried_singleton_hash.clone(), + )), + curried_singleton, + amount, + amount_atom, + inner_puzzle, + } + } + + fn loc(&self) -> Srcloc { + self.inner_puzzle.loc() + } + + fn launcher_solution(&self) -> Rc { + Rc::new(enlist( + self.loc(), + &[ + self.curried_singleton_hash_atom.clone(), + self.amount_atom.clone(), + Rc::new(SExp::Nil(self.loc())), + ], + )) + } + + fn lineage_proof(&self, parent_coin: &Coin) -> LineageProof { + let inner_puzzle_hash = if parent_coin.puzzle_hash == SINGLETON_LAUNCHER_HASH { + None + } else { + Some(self.inner_puzzle_hash.clone()) + }; + LineageProof { + parent_name: parent_coin.parent_coin_id.clone(), + inner_puzzle_hash, + amount: parent_coin.amount, + } + } + + fn solution_for_singleton( + &self, + lineage_proof: &LineageProof, + inner_solution: Rc, + ) -> Rc { + let parent_name = Rc::new(SExp::Atom(self.loc(), lineage_proof.parent_name.clone())); + let amount_atom = Rc::new(SExp::Integer( + self.loc(), + lineage_proof.amount.to_bigint().unwrap(), + )); + + let parent_info = if let Some(_inner_puzzle_hash) = &lineage_proof.inner_puzzle_hash { + enlist( + self.loc(), + &[ + parent_name, + self.inner_puzzle_hash_atom.clone(), + amount_atom.clone(), + ], + ) + } else { + enlist(self.loc(), &[parent_name, amount_atom.clone()]) + }; + Rc::new(enlist( + self.loc(), + &[Rc::new(parent_info), amount_atom, inner_solution], + )) + } + + fn get_next_coin(&self, parent: &Coin) -> Coin { + Coin { + parent_coin_id: parent.name(), + puzzle_hash: sha256tree(self.curried_singleton.clone()), + amount: self.amount, + } + } +} + +// singleton_top_layer in cl23 (just replacing the assert macro). +#[test] +fn test_singleton_top_layer_23() { + let program_file = "resources/tests/strict/singleton_top_layer.clsp"; + let loc = Srcloc::start(program_file); + let inner_puzzle = Rc::new(SExp::Integer(loc.clone(), 5_u32.to_bigint().unwrap())); + let launcher_coin = generate_launcher_coin(FIRST_COIN_PARENT, 1); + let launch = SingletonLaunch::new(launcher_coin.clone(), program_file, inner_puzzle, 1); + + let launcher_solution = launch.launcher_solution(); + let bootstrap_singleton = do_basic_brun(&vec![ + "brun".to_string(), + "--operators-version".to_string(), + "0".to_string(), + SINGLETON_LAUNCHER.to_string(), + launcher_solution.to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(bootstrap_singleton, "((51 0xe435c0e8158464c825adb748900108adba4877bcd960c485f3effd3b8438f7e9 1) (60 0x8117fb4c6939a70936ab1d4f6ffe1daf24333978f0302c0464cbdd98fc346f65))"); + + // (((51 0xZZZZ... 1))) + let inner_solution = Rc::new(enlist( + launch.loc(), + &[Rc::new(enlist( + launch.loc(), + &[Rc::new(enlist( + launch.loc(), + &[ + Rc::new(SExp::Integer( + launch.loc(), + CREATE_COIN.to_bigint().unwrap(), + )), + launch.inner_puzzle_hash_atom.clone(), + launch.amount_atom.clone(), + ], + ))], + ))], + )); + let lineage_proof = launch.lineage_proof(&launcher_coin); + let solution_for_singleton = + launch.solution_for_singleton(&lineage_proof, inner_solution.clone()); + let singleton_eve_run = do_basic_brun(&vec![ + "brun".to_string(), + "--operators-version".to_string(), + "0".to_string(), + launch.curried_singleton.to_string(), + solution_for_singleton.to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(singleton_eve_run, "((70 0xf5ab253587c5eee301cfe877321e662612f85f993a31616df45ef0f80a686fe8) (51 0xe435c0e8158464c825adb748900108adba4877bcd960c485f3effd3b8438f7e9 1))"); + let parent_of_eve_spend_coin = launch.get_next_coin(&launcher_coin); + let next_lineage_proof = launch.lineage_proof(&parent_of_eve_spend_coin); + let solution_for_next_singleton = + launch.solution_for_singleton(&next_lineage_proof, inner_solution.clone()); + let singleton_next_run = do_basic_brun(&vec![ + "brun".to_string(), + "--operators-version".to_string(), + "0".to_string(), + launch.curried_singleton.to_string(), + solution_for_next_singleton.to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(singleton_next_run, "((70 0xff1dd6715c5de8101added4088b446308432f6f96f7ad95add6ec884834d7206) (51 0xe435c0e8158464c825adb748900108adba4877bcd960c485f3effd3b8438f7e9 1))"); +} From 79d67d508901e51d29eb21efce6dc5ccb8aa9f10 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 26 Oct 2023 13:15:01 -0700 Subject: [PATCH 19/48] Add cl23 game tests. There is no terse mode yet in this timeline, but it might make sense to move it up. --- .../game-referee-after-cl21/handcalc.clinc | 140 +++++ .../game-referee-after-cl21/handcalc_a.clinc | 256 ++++++++++ .../smoke_test_deep_compare.clsp | 28 + .../smoke_test_deep_compare.clvm.hex | 1 + .../smoke_test_deep_compare.sym | 1 + .../smoke_test_permutations.clsp | 9 + .../smoke_test_permutations.clvm.hex | 1 + .../smoke_test_permutations.sym | 1 + .../smoke_test_sort.clsp | 11 + .../smoke_test_sort.clvm.hex | 1 + .../smoke_test_sort.sym | 1 + .../spacehandcalc.clinc | 104 ++++ .../test_handcalc.clsp | 379 ++++++++++++++ .../test_handcalc.clvm.hex | 1 + .../game-referee-after-cl21/test_handcalc.sym | 1 + .../test_handcalc_b.clsp | 377 ++++++++++++++ .../test_library_basics.py | 165 ++++++ .../test_permutations.clsp | 63 +++ .../test_permutations.clvm.hex | 1 + .../test_permutations.sym | 1 + .../game-referee-after-cl21/test_prepend.clsp | 5 + .../test_prepend.clvm.hex | 1 + .../game-referee-after-cl21/test_prepend.sym | 1 + .../game-referee-after-cl21/test_range.clsp | 6 + .../test_range.clvm.hex | 1 + .../game-referee-after-cl21/test_range.sym | 1 + .../game-referee-after-cl21/test_reverse.clsp | 6 + .../test_reverse.clvm.hex | 1 + .../game-referee-after-cl21/test_reverse.sym | 1 + .../game-referee-after-cl21/test_sort.clsp | 37 ++ .../test_sort.clvm.hex | 1 + .../game-referee-after-cl21/test_sort.sym | 1 + .../game-referee-after-cl21/testnoncegame.py | 33 ++ .../game-referee-after-cl21/testreferee.py | 479 ++++++++++++++++++ .../testrockpaperscissors.py | 48 ++ .../smoke_test_deep_compare.clvm.hex | 1 + .../smoke_test_permutations.clvm.hex | 1 + .../smoke_test_sort.clvm.hex | 1 + .../test_handcalc.clvm.hex | 1 + .../test_permutations.clvm.hex | 1 + .../test_prepend.clvm.hex | 1 + .../game-referee-in-cl21/test_range.clvm.hex | 1 + .../test_reverse.clvm.hex | 1 + .../game-referee-in-cl21/test_sort.clvm.hex | 1 + resources/tests/lib/steprun.py | 8 +- 45 files changed, 2177 insertions(+), 4 deletions(-) create mode 100644 resources/tests/game-referee-after-cl21/handcalc.clinc create mode 100644 resources/tests/game-referee-after-cl21/handcalc_a.clinc create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_deep_compare.sym create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_permutations.sym create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_sort.clsp create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_sort.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/smoke_test_sort.sym create mode 100644 resources/tests/game-referee-after-cl21/spacehandcalc.clinc create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc.sym create mode 100644 resources/tests/game-referee-after-cl21/test_handcalc_b.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_library_basics.py create mode 100644 resources/tests/game-referee-after-cl21/test_permutations.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_permutations.sym create mode 100644 resources/tests/game-referee-after-cl21/test_prepend.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_prepend.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_prepend.sym create mode 100644 resources/tests/game-referee-after-cl21/test_range.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_range.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_range.sym create mode 100644 resources/tests/game-referee-after-cl21/test_reverse.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_reverse.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_reverse.sym create mode 100644 resources/tests/game-referee-after-cl21/test_sort.clsp create mode 100644 resources/tests/game-referee-after-cl21/test_sort.clvm.hex create mode 100644 resources/tests/game-referee-after-cl21/test_sort.sym create mode 100644 resources/tests/game-referee-after-cl21/testnoncegame.py create mode 100644 resources/tests/game-referee-after-cl21/testreferee.py create mode 100644 resources/tests/game-referee-after-cl21/testrockpaperscissors.py create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_prepend.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_range.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_reverse.clvm.hex create mode 100644 resources/tests/game-referee-in-cl21/test_sort.clvm.hex diff --git a/resources/tests/game-referee-after-cl21/handcalc.clinc b/resources/tests/game-referee-after-cl21/handcalc.clinc new file mode 100644 index 000000000..6317733f4 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/handcalc.clinc @@ -0,0 +1,140 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun find_flush_inner (suits last count) + (if (not suits) + 0 + (if (= (f suits) last) + (if (= count 4) + last + (find_flush_inner (r suits) last (+ count 1)) + ) + (find_flush_inner (r suits) (f suits) 1) + ) + ) + ) + ; returns the flush suit or 0 if there isn't any + ; suits must be clustered/sorted + (defun find_flush (suits) + (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) + ) + (defun straight_high_inner (ranks started_ace last count) + (if (not ranks) + ; at the end of the list + (if (logand (= last 2) (= count 4) started_ace) + ; ace to five + 5 + ; no straight + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner ranks (= (f ranks) 14) 0 0) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (c count last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (c (c count last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + 0 + (assign-lambda + fnosuits + (sort + (lambda (x y) (deep> x y)) + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + ) + + fsh (straight_high fnosuits) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice fnosuits 5)) + ) + ) + ) + nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) + sh (straight_high nosuits) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/handcalc_a.clinc b/resources/tests/game-referee-after-cl21/handcalc_a.clinc new file mode 100644 index 000000000..06c326392 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/handcalc_a.clinc @@ -0,0 +1,256 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun hand_compare (a b) + (if (= (f a) (f b)) + (if (r a) + (hand_compare (r a) (r b)) + 0 + ) + (- (* 2 (> (f a) (f b))) 1) + ) + ) + (defun hand< (a b) + (= (hand_compare a b) -1) + ) + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + ; Sorts atoms into descending order + ; This is optimized for sorting short lists + ; A more general function would return a list of lists of ascending sizes + ; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) + (defun count_suits_2 ((@ suits (firstsuit . remaining))) + (if (not suits) + (c (c 0 0) (c 0 0)) + (assign-lambda ((@ cd (clubs . diamonds)) . (@ hs (hearts . spades))) (count_suits remaining) + (if (= firstsuit 1) + (c (c (+ clubs 1) diamonds) hs) + (if (= firstsuit 2) + (c (c clubs (+ diamonds 1)) hs) + (if (= firstsuit 3) + (c cd (c (+ hearts 1) spades)) + (c cd (c hearts (+ spades 1))) + ) + ) + ) + ) + ) + ) + (defun find_flush_2 (suits) + (assign-lambda ((clubs . diamonds) . (hearts . spades)) (count_suits suits) + (if (> clubs 4) + 1 + (if (> diamonds 4) + 2 + (if (> hearts 4) + 3 + (if (> spades 4) + 4 + 0 + ) + ) + ) + ) + ) + ) + (defun count_suits (suits) + (if suits + (+ (count_suits (r suits)) (ash 1 (* 4 (- (f suits) 1)))) + 0 + ) + ) + (defun find_flush (suits) + (assign-lambda + myvals (count_suits suits) + (if (> (logand myvals 0xF000) 0x4000) + 4 + (if (> (logand myvals 0x0F00) 0x0400) + 3 + (if (> (logand myvals 0x00F0) 0x0040) + 2 + (if (> (logand myvals 0x0F) 0x04) + 1 + 0 + ) + ) + ) + ) + ) + ) + (defun straight_high_inner (ranks last count) + (if (not ranks) + (if (logand (= last 2) (= count 4)) + ; maybe ace to five + 5 + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (assign-lambda high (straight_high_inner ranks 0 0) + (if (= high 5) + (* (= (f ranks) 14) 5) + high + ) + ) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (logior (lsh count 4) last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign-inline val (group_by_count_inner (r items) (f items) 1) + (c (logior (lsh count 4) last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush (map rest cards)) + max_flush (if (not fsuit) + (list 0) + (assign-lambda + flushcards + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + flushranks (atomsort flushcards) + fsh (straight_high flushranks) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice flushranks 5)) + ) + ) + ) + ranks (atomsort (map first cards)) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + (list 0) + ) + groups (map + (lambda (myval) (c (lsh myval -4) (logand myval 0x0F))) + (atomsort (group_by_count ranks)) + ) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + ; max of max_flush max_straight and max_group + (if (> (f max_flush) (f max_straight)) + (if (> (f max_flush) (f max_group)) + max_flush + max_group + ) + (if (> (f max_straight) (f max_group)) + max_straight + max_group + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..8df629518 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clvm.hex b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clvm.hex new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.sym b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.sym new file mode 100644 index 000000000..f9bcf963b --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.sym @@ -0,0 +1 @@ +{"4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160": "lambda_$_199", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687": "deep_compare", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_arguments": "(a b)", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_arguments": "((a_$_181 b_$_182) inner_result_$_183)", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_left_env": "1", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_arguments": "(() (want_cmp_val_$_196 cmp_a_$_197 cmp_b_$_198))", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_left_env": "1", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743": "letbinding_$_200", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/smoke_test_deep_compare.clsp", "__chia__main_arguments": "()"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp new file mode 100644 index 000000000..2ed3fbbcc --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-21*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_permutations.clvm.hex b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clvm.hex new file mode 100644 index 000000000..813027e6d --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-after-cl21/smoke_test_permutations.sym b/resources/tests/game-referee-after-cl21/smoke_test_permutations.sym new file mode 100644 index 000000000..ce21d4fac --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_permutations.sym @@ -0,0 +1 @@ +{"ce9e2b2b4940b8e6b74f2eb0935a66717ce0f8ae750cea80407fdc2f89650833_arguments": "((pre_$_1375 post_$_1376 agg_$_1377) newrest_$_1379 myatom_$_1378)", "__chia__main_arguments": "(X)", "bdc4b151632158e39adf669800ccfaa731e9f01d6adbfe935422aecdd4c4088b_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_1378) x_$_1380)", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_left_env": "1", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b_arguments": "(a b)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/smoke_test_permutations.clsp", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "bdc4b151632158e39adf669800ccfaa731e9f01d6adbfe935422aecdd4c4088b": "permutations_inner", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_1383", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_left_env": "1", "ce9e2b2b4940b8e6b74f2eb0935a66717ce0f8ae750cea80407fdc2f89650833": "letbinding_$_1382", "bdc4b151632158e39adf669800ccfaa731e9f01d6adbfe935422aecdd4c4088b_arguments": "(pre post agg)", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf_arguments": "(vals)", "048d5413ce5265ab36813735bc75ba7b7c5e9454553198bfdafef009677e420b": "prepend", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "ce9e2b2b4940b8e6b74f2eb0935a66717ce0f8ae750cea80407fdc2f89650833_left_env": "1", "e209270f1dc5e9d4b9d3c077d401c47f47bb866e87d1707551d101b8717f4edf": "permutations"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp b/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp new file mode 100644 index 000000000..59b8a886e --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-21*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/game-referee-after-cl21/smoke_test_sort.clvm.hex b/resources/tests/game-referee-after-cl21/smoke_test_sort.clvm.hex new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-after-cl21/smoke_test_sort.sym b/resources/tests/game-referee-after-cl21/smoke_test_sort.sym new file mode 100644 index 000000000..0a2b030b8 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/smoke_test_sort.sym @@ -0,0 +1 @@ +{"f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4": "letbinding_$_369", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_left_env": "1", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_arguments": "(reversed rest)", "__chia__main_arguments": "(X)", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b": "lambda_$_368", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_arguments": "(vals)", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47": "letbinding_$_370", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_left_env": "1", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_left_env": "1", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53": "split", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_arguments": "(mylist)", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299": "reverse_inner", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_arguments": "(myless a b)", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_left_env": "1", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_left_env": "1", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_arguments": "(a b)", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_arguments": "(() a_$_366 b_$_367)", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_arguments": "(myless mylist)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_arguments": "((myless_$_347 mylist_$_348) (a_$_349 b_$_350))", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_left_env": "1", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_left_env": "1", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_arguments": "(myless A B agg)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_left_env": "1", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_arguments": "(@ everything (rest aggl aggr))", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_left_env": "1", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3": "sort", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/smoke_test_sort.clsp", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa": "merge", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140": "reverse", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8": "prepend", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_left_env": "1", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3": "split_inner", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1": "merge_inner", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_left_env": "1", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_arguments": "(((myless_$_347 mylist_$_348) (a_$_349 b_$_350)) sa_$_351 sb_$_352)"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/spacehandcalc.clinc b/resources/tests/game-referee-after-cl21/spacehandcalc.clinc new file mode 100644 index 000000000..3bfae65ca --- /dev/null +++ b/resources/tests/game-referee-after-cl21/spacehandcalc.clinc @@ -0,0 +1,104 @@ + +; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace +; there are no suits, flushes, or ace-to-four straights +; takes a list of card ranks and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; all sorting is done highest to lowest +( + (include *standard-cl-22*) + (include sort.clinc) + (include deep_compare.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include max.clinc) + (defconstant FIVE_OF_A_KIND 10) + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun straight_high_inner (ranks last count) + (if (not ranks) + ; at the end of the list + 0 + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner (ranks (= (f ranks) 13) 0 0)) + ) + (defun group_by_count_inner (items last count) + (if (not items) + 0 + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (if last + (c (c count last) val) + val + ) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items 0 0) + ) + (defun space_hand_calc (cards) + (assign + rest (lambda (x) (r x)) + greater (lambda (x y) (> x y)) + ranks (sort greater cards) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort deep> (group_by_count ranks)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (if (= top_count 4) + (c FOUR_OF_A_KIND (slice topcards 2)) + (c FIVE_OF_A_KIND (slice topcards 1)) + ) + ) + ) + ) + (max deep< (list max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clsp b/resources/tests/game-referee-after-cl21/test_handcalc.clsp new file mode 100644 index 000000000..16c46f664 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc.clsp @@ -0,0 +1,379 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include sort.clinc) + (include max.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clvm.hex b/resources/tests/game-referee-after-cl21/test_handcalc.clvm.hex new file mode 100644 index 000000000..8a8aedd7f --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff1b13ffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff8080808080ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff80808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff0bff80808080ff8080808080ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ffff04ffff02ffff03ffff20ff1780ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200e680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff8200b6ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff2bffff04ff13ffff04ffff02ff8200e8ffff04ff02ffff04ff29ffff04ff0bffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff4fffff010280ffff01ff02ffff01ff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff4fffff010380ffff01ff02ffff01ff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff8200b9ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff17ffff04ff0bff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.sym b/resources/tests/game-referee-after-cl21/test_handcalc.sym new file mode 100644 index 000000000..082402ad3 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc.sym @@ -0,0 +1 @@ +{"ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_left_env": "1", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_arguments": "(items)", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_arguments": "tests", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_handcalc.clsp", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_left_env": "1", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_left_env": "1", "cbfdd91c91e2fc43ef49a82e173f49c6cc73a6a022b1378b885ff9ea94f373b0_arguments": "(((((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752) groups_$_1764 sh_$_1763 max_flush_$_1756) max_straight_$_1767 (second_count_$_1770 . second_card_$_1771) (top_count_$_1768 . top_card_$_1769) topcards_$_1772)", "d3a1931b023b08bc00d8335c069b7d488fa1930ee6c312dcf11cb54a6d5761b1_arguments": "((myfunc firstarg secondarg . remaining))", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6": "straight_high", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_arguments": "(myless a b)", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367": "deep_compare", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65": "merge", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e": "lambda_$_1791", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_left_env": "1", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_arguments": "(() x_$_1774 y_$_1775)", "68a51341b984c77341ffa8fd755e2b80544914c95cd78caf10312d7e818b48d9": "letbinding_$_1794", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_left_env": "1", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_left_env": "1", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca": "filtermap", "2df345b9e040f0cdefc0db6e59e9ea40894c26003d4bb35d4c0b88bfdc5d2d8f": "letbinding_$_1801", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_arguments": "((fsuit_$_1752) (card_rank_$_1760 . card_suit_$_1761))", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_arguments": "(F L R)", "8afd8fa01ef33b8744033203c10bd0c52e1da692d02ff4094f7b42d5ef7ddd47": "letbinding_$_1803", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_arguments": "(a b)", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901": "split", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_arguments": "(myless mylist)", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3": "letbinding_$_1786", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_left_env": "1", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_arguments": "(suits last count)", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e": "handcalc", "9d29b02858791632bc362c1460848641e331d92b120c8b18e241a6a7375b387e": "letbinding_$_1796", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_arguments": "(process remaining init)", "2df345b9e040f0cdefc0db6e59e9ea40894c26003d4bb35d4c0b88bfdc5d2d8f_left_env": "1", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_left_env": "1", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3": "find_flush", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_left_env": "1", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_arguments": "(ranks)", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa_left_env": "1", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060": "find_flush_inner", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_arguments": "(items last count)", "cbfdd91c91e2fc43ef49a82e173f49c6cc73a6a022b1378b885ff9ea94f373b0_left_env": "1", "76751a9c95444501c3ad57278f9ace3e6a1e41fca43bd93d6e5a8ca125e8c4a3_arguments": "(((myless_$_1720 mylist_$_1721) (a_$_1722 b_$_1723)) sa_$_1724 sb_$_1725)", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed_left_env": "1", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8": "lambda_$_1802", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485": "merge_inner", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854": "lambda_$_1790", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_left_env": "1", "ff5f6181808cb059cffecd54a408a6b4566b861a8905208bbeb87a10e3c8ec65_left_env": "1", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263_left_env": "1", "d013fcaaa576d263aa86406509a11272424931651d958cff6ba9be6d2b9a7fed": "group_by_count_inner", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9": "reverse", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36": "lambda_$_1798", "d8c50d6282a1ba47f0a23430d177bbfbb72e2b84713745e894f575570f1f3d6e_arguments": "(() x_$_1749)", "64499f3fb4ed1322a24ece83ce5664a10e41b8cb291c4c395d961004680802ca_left_env": "1", "145bfb83f7b3ef33ac1eada788c187e4d1feb7326bcf340bb060a62e75434854_arguments": "(() x_$_1751)", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_left_env": "1", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_arguments": "(myless best_so_far mylist)", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_left_env": "1", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f_arguments": "(a b)", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_left_env": "1", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_arguments": "(@ everything (rest aggl aggr))", "ca3aa00f92cd656fbf2e7c7863a2bd3ebfcdf0bdb05ca8f00ce9d51648d38b1f": "deep=", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_arguments": "(vals)", "c64b0acdb9bfc5a1bec80732d64bee90fd12e869207674a220042725441f9cb3_arguments": "(suits)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd": "max", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_left_env": "1", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_arguments": "(a b)", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c": "slice", "f4c3c71dddb1c7ee50bc104032f26172d61ff77f9bca9876d1846c47cd72020e_arguments": "(cards)", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_arguments": "(mylist count)", "cbfdd91c91e2fc43ef49a82e173f49c6cc73a6a022b1378b885ff9ea94f373b0": "letbinding_$_1800", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_arguments": "((a_$_1669 b_$_1670) inner_result_$_1671)", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b_left_env": "1", "d121f71fcb5513b6d2b097255deb884ff40c26dd366b0ba7cf2eea1440b07901_arguments": "(mylist)", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108": "straight_high_inner", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66_left_env": "1", "8afd8fa01ef33b8744033203c10bd0c52e1da692d02ff4094f7b42d5ef7ddd47_arguments": "(((myfunc_$_1776 firstarg_$_1777 secondarg_$_1778 . remaining_$_1779)) secondval_$_1781 firstval_$_1780)", "faf326970cccbdcee02916d1e40ff5146aa7b1e2dfcac2bfaee7ceaaa3d5965e_left_env": "1", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374": "reverse_inner", "4b216afca35845442571c30c6d827724285ca82490dbdae1b27f2d082e85ff66": "runtests", "8afd8fa01ef33b8744033203c10bd0c52e1da692d02ff4094f7b42d5ef7ddd47_left_env": "1", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958_arguments": "(() x_$_1758 y_$_1759)", "2df345b9e040f0cdefc0db6e59e9ea40894c26003d4bb35d4c0b88bfdc5d2d8f_arguments": "((((((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752) groups_$_1764 sh_$_1763 max_flush_$_1756) max_straight_$_1767 (second_count_$_1770 . second_card_$_1771) (top_count_$_1768 . top_card_$_1769) topcards_$_1772) max_group_$_1773)", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661_left_env": "1", "9d29b02858791632bc362c1460848641e331d92b120c8b18e241a6a7375b387e_left_env": "1", "d3a1931b023b08bc00d8335c069b7d488fa1930ee6c312dcf11cb54a6d5761b1_left_env": "1", "e51e3ecc739e0c9b646889ad797fa268d9acbb09f42f70b1a75be411440dcf36_left_env": "1", "c64dc59aae25053fe8d872e13fca4e2c43765a1a83335d520435180f3ab55485_arguments": "(myless A B agg)", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25": "letbinding_$_1784", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004_arguments": "((myless_$_1720 mylist_$_1721) (a_$_1722 b_$_1723))", "36900466483b112787abffe419202a499c8e5467e750cf3aec03ac5fd0ba9cfd_arguments": "(myless mylist)", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897": "split_inner", "5c2c8bfc9ac6c103562c9017a5cee2634da7ee43d44bd4f3d46d11e519942ea6_left_env": "1", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9_arguments": "((items_$_1742 last_$_1743 count_$_1744) val_$_1745)", "24d45638962c8ac6b0923f0f2c912177b1b1c710bbcd3e10fccf01fc6f771263": "sort", "a87d2e2e13539c8f9f66137bdee9a7fd750b8bdb6a07fc1e6cd8416d771d9958": "lambda_$_1797", "471488bbd4b64848f0c6592900ef2a751e8907a72557b0ba794e0d6f1252c374_arguments": "(reversed rest)", "68a51341b984c77341ffa8fd755e2b80544914c95cd78caf10312d7e818b48d9_arguments": "((((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752) groups_$_1764 sh_$_1763 max_flush_$_1756)", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d": "deep<", "3ac370c3d91282c6eb94742d40cdb371de392eaca8a0a213d3d3ade6d1b03367_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_left_env": "1", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27_left_env": "1", "24d7dbd0fece56391d516812ca037a910985789b424144b4dc8f8c57cf3ce108_arguments": "(ranks started_ace last count)", "724d50ee95e66b90e255e2cecc58cc35c2eb27302b1952948538ad95f7387a4b": "map-with-rest", "53480b9619c61ae7111a964382f8a884a6ec22e384b92025271b48d1fe231b1e_arguments": "((cards_$_1747) rest_$_1750 first_$_1748)", "faf326970cccbdcee02916d1e40ff5146aa7b1e2dfcac2bfaee7ceaaa3d5965e_arguments": "(((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752)", "ea58983a62a5d0a526c32f3423717af26c6d9d5963eb4831a0d1049227eba060_left_env": "1", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_left_env": "1", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6_arguments": "(((((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752) fnosuits_$_1757) fsh_$_1762)", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba": "deep>", "40fe864fddcab141770d7e0c0be5d5d07bcb8efd496a6f4bb2cdc3834e94eab9": "letbinding_$_1788", "1bde90fbef9d7a4c5cb7133780d4275aa03dfc0a54a905b899d65b4b578f6661": "letbinding_$_1783", "c60f4e2e12ab7285ef437f63bb24f4e5e6267fc76479893a179ebae738aca004": "letbinding_$_1785", "53480b9619c61ae7111a964382f8a884a6ec22e384b92025271b48d1fe231b1e": "letbinding_$_1789", "01ed928ebc640669bfdc000b292962b919f6635176dd9119325f5f912d7567b8_left_env": "1", "7245d12b7785f1ee23a0ec0d3a03432057ec41fb0561d373d91cda267f44c3e9_left_env": "1", "dd3953423ae82b313d5361cb4c9ea7d18b43294e1c0801e1c021d101a7ce58f6": "letbinding_$_1799", "79f3cf5c572162105f8688174041050314a154956ef27d7ea6414a9dcd402faa": "group_by_count", "d3a1931b023b08bc00d8335c069b7d488fa1930ee6c312dcf11cb54a6d5761b1": "runtests_inner", "68a51341b984c77341ffa8fd755e2b80544914c95cd78caf10312d7e818b48d9_left_env": "1", "00c86eab1caeadaaf967420becbefef7170e5e996890edc355d16c263ea32e27": "max_inner", "9d29b02858791632bc362c1460848641e331d92b120c8b18e241a6a7375b387e_arguments": "((((cards_$_1747) rest_$_1750 first_$_1748) nosuits_$_1753 fsuit_$_1752) fnosuits_$_1757)", "53480b9619c61ae7111a964382f8a884a6ec22e384b92025271b48d1fe231b1e_left_env": "1", "faf326970cccbdcee02916d1e40ff5146aa7b1e2dfcac2bfaee7ceaaa3d5965e": "letbinding_$_1792", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09": "prepend", "8bda8ccb43702a3e1a1b2354adfb39e9a229ae4dc896e7481a569ecc19dd2d6d_arguments": "(a b)", "f5470fda7b930fc12a27be2810e4c48ad7e35ceda81273ba026cd6da98d94c3c_left_env": "1", "26df51fddc60f80f199438e505e3832df819036418c8bf439a572679ebfd1897_left_env": "1", "c4e96a2219a3d6389693cfb81c4309f5bf5f1a89f300c7c12d019e08d14cde09_arguments": "(a b)", "0dda9e9f845e653fbb9f1065f098a0c439bf605b2e8830546184c95eae822f25_arguments": "((process_$_1697 remaining_$_1698 init_$_1699) next_$_1700)", "__chia__main_arguments": "()", "2379a74341919286585b51fa8ff2bf5a2e76254197c786fdcd96d4b004be17ba_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp b/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp new file mode 100644 index 000000000..674bbd414 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_handcalc_b.clsp @@ -0,0 +1,377 @@ + +(mod () + (include *standard-cl-21*) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include handcalc.clinc) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + firstval (handcalc firstarg) + secondval (handcalc secondarg) + (assert + (a myfunc (list firstval secondval)) + (deep= firstval (handcalc (reverse firstarg))) + (deep= secondval (handcalc (reverse secondarg))) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_library_basics.py b/resources/tests/game-referee-after-cl21/test_library_basics.py new file mode 100644 index 000000000..926ddde7a --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_library_basics.py @@ -0,0 +1,165 @@ +import os +import pytest +import random +from itertools import permutations +from typing import List +#from hsms.streamables.program import Program +#from steprun import diag_run_clvm, compile_module_with_symbols +#from lib.program import Program +from pathlib import Path +from clvm_rs import Program +from lib.steprun import diag_run_clvm, compile_module_with_symbols +from clvm_tools_rs import get_version + +print(f"clvm_tools_rs version is {get_version()}") +#include_dirs = os.getcwd() +include_dirs = [Path(__file__).parent, Path(__file__).parent.parent / "lib"] +Program.set_run_unsafe_max_cost(11000000000) + +print(f"XXX: {include_dirs}") +compile_module_with_symbols(include_dirs, 'smoke_test_deep_compare.clsp') +compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_sort.clsp') +sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_sort.clsp') +test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_permutations.clsp') +test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_reverse.clsp') +test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_prepend.clsp') +test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_range.clsp') +test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'smoke_test_permutations.clsp') +smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) + +compile_module_with_symbols(include_dirs, 'test_handcalc.clsp') +test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) + +def as_atom_list(prg: Program) -> List[bytes]: + """ + Pretend `prg` is a list of atoms. Return the corresponding + python list of atoms. + + At each step, we always assume a node to be an atom or a pair. + If the assumption is wrong, we exit early. This way we never fail + and always return SOMETHING. + """ + items = [] + obj = prg + while True: + pair = obj.pair + if pair is None: + break + atom = pair[0].atom + if atom is None: + break + items.append(atom) + obj = pair[1] + return items + +def test_smoke_compare(): + compare_program.run(Program.to([])) + +def test_handcalc(): + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + +def proper_list_inner(result,cl): + if hasattr(cl, 'pair') and cl.pair is not None: + result.append(cl.pair[0]) + return proper_list_inner(result,cl.pair[1]) + else: + return result + +def proper_list(cl): + result = [] + return proper_list_inner(result,cl) + +def int_list(cl): + return [Program.to(x).as_int() for x in as_atom_list(Program.to(cl))] + +def de_none_list(l): + return [x if x is not None else [] for x in l] + +def with_random_lists(n,f): + for length in range(n): # 0-10 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + f(orig_list) + +def test_prepend(): + for length1 in range(5): + list_1 = list(range(length1)) + for length2 in range(length1): + prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) + assert list_1 == int_list(prepend_result) + +def test_reverse(): + def test_reverse_list(l): + rev_args = Program.to([l]) + reversed_result = Program.to(list(reversed(l))) + reversed_by_prog = test_reverse_program.run(rev_args) + assert reversed_result == reversed_by_prog + + with_random_lists(10,test_reverse_list) + +def test_range(): + for length in range(10): + want_list = list(range(length)) + result = test_range_program.run(Program.to([length])) + assert want_list == result + +def do_test_permutations_of_size_n(n): + try_list = [random.randint(0,100) for x in range(n)] + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = smoke_test_permutations_program.run(Program.to([try_list])) + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_permutations_0(): + do_test_permutations_of_size_n(0) + +def test_permutations_1(): + do_test_permutations_of_size_n(1) + +def test_permutations_2(): + n = 2 + all_a_string = 0x616161616161 + all_b_string = 0x626262626262 + for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_chialisp_sort_program(): + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + +def test_permutations_n(): + for i in range(3,6): + do_test_permutations_of_size_n(i) + +def test_chialisp_permutations_program(): + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + +def test_smoke_sort(): + for length in range(7): # 0-7 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + sort_args = Program.to([orig_list]) + sorted_list = Program.to(sorted(orig_list)) + sort_res = sort_program.run(sort_args) + assert sort_res == sorted_list + +if __name__ == '__main__': + test_smoke_sort() diff --git a/resources/tests/game-referee-after-cl21/test_permutations.clsp b/resources/tests/game-referee-after-cl21/test_permutations.clsp new file mode 100644 index 000000000..d5b6d125f --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_permutations.clsp @@ -0,0 +1,63 @@ +(mod (M N) + (include *standard-cl-21*) + (include prepend.clinc) + (include reverse.clinc) + (include map.clinc) + (include len.clinc) + (include range.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include all-in-list.clinc) + (include print.clinc) + + (defun ! (x) + (if x + (* x (! (- x 1))) + 1 + ) + ) + (defun no_repeats_inner ((first . remainder)) + (if remainder + (if (deep= first (f remainder)) + 0 + (no_repeats_inner remainder) + ) + 1 + ) + ) + (defun no_repeats (mylist) + (if mylist + (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) + 1 + ) + ) + (assert + ;; Is permutations expected to collapse equal alternatives when two of + ;; the items to shuffle are equal? + (= (* (! M) 4) (len (permutations (c 0 (range M))))) + (busy + (lambda (listlen) + (assign + mylist (range listlen) + permed (permutations mylist) + (assert + (= (len permed) (! listlen)) + ;; ensure we didn't produce any permutations that have + ;; repeated elements in them, which would indicate that + ;; the permutation function misbehaved + (all-in-list (map (lambda (L) (no_repeats L)) permed)) + (no_repeats permed) + ) + ) + ) + (reverse (range N)) + 1 + ) + (deep= (permutations 0) (q ())) + 0 + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_permutations.clvm.hex b/resources/tests/game-referee-after-cl21/test_permutations.clvm.hex new file mode 100644 index 000000000..ccbc2f4aa --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_permutations.sym b/resources/tests/game-referee-after-cl21/test_permutations.sym new file mode 100644 index 000000000..5822e3a17 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_permutations.sym @@ -0,0 +1 @@ +{"9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_arguments": "(() a_$_1091 b_$_1092)", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682": "no_repeats", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a": "len", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977": "reverse", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_1065) x_$_1067)", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_arguments": "(L)", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_arguments": "(F L R)", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e": "all-in-list", "791c1745272da279ba038d8a0f093ab9076ff98d02ff09a3b35888c454f9d203_left_env": "1", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d": "letbinding_$_1105", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e": "split", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_left_env": "1", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_arguments": "(a b)", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9_left_env": "1", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f": "merge_inner", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff": "letbinding_$_1101", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8_left_env": "1", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_left_env": "1", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "42e1f82cf8542a5f31de7edcd596df9a08e48bcf0aa637f866be044a0c96841f_arguments": "(myless A B agg)", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_left_env": "1", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53_arguments": "(reversed rest)", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_arguments": "(vals)", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_arguments": "(i)", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08": "merge", "53fd31d2089bb8aa123a7e81215cafd80d667659bf3a51447a5cc7d80346e193_arguments": "(pre post agg)", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522": "no_repeats_inner", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_arguments": "((myless_$_1039 mylist_$_1040) (a_$_1041 b_$_1042))", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_left_env": "1", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_arguments": "((a_$_1047 b_$_1048) inner_result_$_1049)", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_arguments": "(mylist)", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_left_env": "1", "791c1745272da279ba038d8a0f093ab9076ff98d02ff09a3b35888c454f9d203": "letbinding_$_1102", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_arguments": "(L)", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_arguments": "(x)", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_arguments": "((() listlen_$_1093) mylist_$_1094)", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047_left_env": "1", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_arguments": "(myless a b)", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_arguments": "(a b)", "791c1745272da279ba038d8a0f093ab9076ff98d02ff09a3b35888c454f9d203_arguments": "((pre_$_1062 post_$_1063 agg_$_1064) newrest_$_1066 myatom_$_1065)", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_left_env": "1", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_arguments": "((first . remainder))", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_arguments": "(a b)", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61_left_env": "1", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_left_env": "1", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe": "range", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565": "sort", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79_arguments": "((next . remainder))", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68": "lambda_$_1106", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860": "letbinding_$_1100", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c_arguments": "(next final)", "ae7e4ed6da640a7bd1e9ef3b1d683440bf9297b217bf0743328f9ae54bbc5b53": "reverse_inner", "78956ca35a10cbc40b04bd0a14ca12faae5f292d70b9e072da61ef82f3677522_left_env": "1", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_arguments": "(((() listlen_$_1093) mylist_$_1094) permed_$_1095)", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_arguments": "(() L_$_1096)", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_arguments": "(() listlen_$_1093)", "__chia__main_arguments": "(M N)", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_arguments": "(L)", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_arguments": "(myless mylist)", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202": "split_inner", "0871deba30de6d95a0b04a45e6e036162f8abe844ae21b31f7d7cd518845fe9c": "range_inner", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de_left_env": "1", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87_left_env": "1", "61f9f86f9df2ce0986b2ae605b74b6111f767e89b83729af6f34110bf65bdeb2": "!", "7381ec0d3e15950009d8b999a34b828e9964b79470270e7ed6c5409cf2f69bb9": "enquote-rest", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c_left_env": "1", "6c37e5a9ce5bcf0ae750dd4bb1db5898f49d63eadcdf27fbe04c787362459f5d_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_permutations.clsp", "02c081d44a600583556699febd4e3bc2eb117b61bd5cfc612c2bf091c952fa0a_left_env": "1", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706": "lambda_$_1097", "1443073ed355cb83607d1c2a6d5612f28a038d3887fa750de973e6aa0ed83f08_left_env": "1", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238": "letbinding_$_1098", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_arguments": "(((myless_$_1039 mylist_$_1040) (a_$_1041 b_$_1042)) sa_$_1043 sb_$_1044)", "1c9d01e44e9c5f35a282358422033e4e960609d9f5ef0efc7c7b48bf311208ff_left_env": "1", "bde59c348f4163416518c666a1c5a1d39560d2b09c9b2b38b047e4da574c745e_left_env": "1", "9acbd39570d133bd1318e96254949ed3f9d84fb6796324d393b68b898c4999c8": "map-with-rest", "858e89b0997add55f954ceda806d5a77e9914f6d31bed3dedd1e9b67581ee202_arguments": "(@ everything (rest aggl aggr))", "c6e0bf4deaac4dc5ac02244c56fcaba2652b33bfb38f812ba0a6ef67d3049f61": "permutations", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_arguments": "(vals)", "2e3d155705dec0e05e5d4c87c93395ffe98fffe9f21542faca3c5c8751a18047": "deep=", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7_arguments": "(myfunc mylist returnval)", "657a0532257810b1c203d201026eccd16b845b156e25600b57a7ed5429c59682_arguments": "(mylist)", "53fd31d2089bb8aa123a7e81215cafd80d667659bf3a51447a5cc7d80346e193_left_env": "1", "5087819cc352ab86b0b64eebf0a29725fb6306291a42ac51f17253919f7b899c": "letbinding_$_1099", "ae16459987997a1c9872031a855e1dfe8138fde4d1d5b9a5f188d3292ea97565_left_env": "1", "85c5c955b32be4fef52509b26fe07ce1c3086244572fde3f3bc47636c20f86de": "deep_compare", "53fd31d2089bb8aa123a7e81215cafd80d667659bf3a51447a5cc7d80346e193": "permutations_inner", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_1103", "a0c582b1c6b05c8a3f5d5d7afd51404b874bb63f21ef73f31c383007fce81e87": "prepend", "19f60e08ef187986cf06532ba696b5b91efeb5c043318b9e6b731f1cd80adf79": "last_inner", "0ebdfa3c097ba5b3ef741e8a33b6af2f741209b3e29d94c1c55deb599e4c41d7": "busy", "a91dc4bec838278871d09bbe4a7206242b852404596d71f8e7962df872da447e_left_env": "1", "5f7a25198045f0621cc78620e8739d731e1761a379e94ee1dae0717e4192e860_left_env": "1", "9fbce34b16a7c4618d5816009b42c6e661cb7efbcaf90314a2f840362f175793": "lambda_$_1104"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/test_prepend.clsp b/resources/tests/game-referee-after-cl21/test_prepend.clsp new file mode 100644 index 000000000..9f0d45819 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_prepend.clsp @@ -0,0 +1,5 @@ +(mod (X Y) + (include *standard-cl-21*) + (include prepend.clinc) + (prepend X Y) + ) diff --git a/resources/tests/game-referee-after-cl21/test_prepend.clvm.hex b/resources/tests/game-referee-after-cl21/test_prepend.clvm.hex new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_prepend.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_prepend.sym b/resources/tests/game-referee-after-cl21/test_prepend.sym new file mode 100644 index 000000000..71e8d1cc4 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_prepend.sym @@ -0,0 +1 @@ +{"source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_prepend.clsp", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987": "prepend", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_arguments": "(a b)", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_left_env": "1", "__chia__main_arguments": "(X Y)"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/test_range.clsp b/resources/tests/game-referee-after-cl21/test_range.clsp new file mode 100644 index 000000000..a7dc5edd9 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_range.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include range.clinc) + + (range X) + ) diff --git a/resources/tests/game-referee-after-cl21/test_range.clvm.hex b/resources/tests/game-referee-after-cl21/test_range.clvm.hex new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_range.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_range.sym b/resources/tests/game-referee-after-cl21/test_range.sym new file mode 100644 index 000000000..5a414f20e --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_range.sym @@ -0,0 +1 @@ +{"6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556": "range_inner", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "range", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_arguments": "(next final)", "__chia__main_arguments": "(X)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(i)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_range.clsp", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/test_reverse.clsp b/resources/tests/game-referee-after-cl21/test_reverse.clsp new file mode 100644 index 000000000..b1d843648 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_reverse.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-21*) + (include reverse.clinc) + + (reverse X) + ) diff --git a/resources/tests/game-referee-after-cl21/test_reverse.clvm.hex b/resources/tests/game-referee-after-cl21/test_reverse.clvm.hex new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_reverse.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_reverse.sym b/resources/tests/game-referee-after-cl21/test_reverse.sym new file mode 100644 index 000000000..c8868f67d --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_reverse.sym @@ -0,0 +1 @@ +{"0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(vals)", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_left_env": "1", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "reverse", "__chia__main_arguments": "(X)", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_reverse.clsp", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_arguments": "(reversed rest)", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01": "reverse_inner", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/test_sort.clsp b/resources/tests/game-referee-after-cl21/test_sort.clsp new file mode 100644 index 000000000..8185024d0 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_sort.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-21*) + (include print.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) + (print "sort all these" (permutations (print "mylist" mylist))) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (range 15) (range 15)) + (try_list (range 15) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-after-cl21/test_sort.clvm.hex b/resources/tests/game-referee-after-cl21/test_sort.clvm.hex new file mode 100644 index 000000000..cf5d0409c --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 diff --git a/resources/tests/game-referee-after-cl21/test_sort.sym b/resources/tests/game-referee-after-cl21/test_sort.sym new file mode 100644 index 000000000..29ae5f0b1 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/test_sort.sym @@ -0,0 +1 @@ +{"6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d": "deep<", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_arguments": "(i)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d": "merge_inner", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c": "map-with-rest", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5": "sort", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24": "permutations", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329": "split_inner", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_left_env": "1", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_left_env": "1", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f": "reverse_inner", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_719", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7": "deep=", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_left_env": "1", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_arguments": "(myless mylist)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_left_env": "1", "b1f7d740362f526a0b859fb374c75a41ed23c0e463ae675bf7b4f6176e9cb517": "permutations_inner", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_arguments": "((next . remainder))", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_left_env": "1", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_arguments": "(a b)", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_left_env": "1", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_left_env": "1", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_arguments": "(next final)", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b_left_env": "1", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22": "merge", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872": "letbinding_$_717", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_left_env": "1", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_arguments": "(myfunc mylist returnval)", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_arguments": "(a b)", "cff048daaf258f18d48b6c65fe30a7391599f4689e75b054472943dee16c5904_arguments": "((pre_$_686 post_$_687 agg_$_688) newrest_$_690 myatom_$_689)", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2": "letbinding_$_716", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219": "try_list", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_arguments": "(mylist)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_arguments": "(() i_$_713)", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5_left_env": "1", "b1f7d740362f526a0b859fb374c75a41ed23c0e463ae675bf7b4f6176e9cb517_arguments": "(pre post agg)", "e31ef9039be21ebbff9fca105dadf444914415d83cf1f74f6e299ccc760ca58c_arguments": "(F L R)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560": "lambda_$_721", "cff048daaf258f18d48b6c65fe30a7391599f4689e75b054472943dee16c5904_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e": "print", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_left_env": "1", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3_arguments": "(vals)", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141": "split", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b_arguments": "((myless_$_649 mylist_$_650) (a_$_651 b_$_652))", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_arguments": "(a b)", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5_arguments": "(() A_$_709 B_$_710)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_left_env": "1", "d76bbcd6d3800803e66cb762aa942d5836553c18a50638e3dfcf3deca86f4141_left_env": "1", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_left_env": "1", "1a3f28c2eeaf6c592d86f46dc96c10910a05739bbeda09e147e67fa64927c6f5_left_env": "1", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_left_env": "1", "bcf06844cee9589ac2df23d9cf5d9a372b71fc3725db9c7249f0db72a2c7fdc3": "reverse", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679": "prepend", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_689) x_$_691)", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_left_env": "1", "042c55b626937b8d6be258a97f8d25cdedeee2e712dbddef9438fa900eff883e_arguments": "(R P)", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb_left_env": "1", "1d6bc99de7f858798725d96803a52ef1fa5cf7315c337ea51e560209f7366de5": "last_inner", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499": "try_permuted_list", "02eae9c80ab3ae5e70fcb788e6753ac557297c5b882f6318db705b18b766e872_arguments": "((a_$_657 b_$_658) inner_result_$_659)", "d2b16ed82a656d685d88e5e248fe3221b20f9082377d1263d95076bda402dd8d_arguments": "(myless A B agg)", "cff048daaf258f18d48b6c65fe30a7391599f4689e75b054472943dee16c5904": "letbinding_$_718", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7": "lambda_$_714", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_arguments": "(vals)", "e9570c55a298e52c75e1ab676bdb601ab3a9939994f3f50be22ce4ebe6a1cc24_left_env": "1", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_arguments": "(mylist newlist)", "85734bcc0a0243b28bb41bedb69f548a97a473bd3e87b1b5c8acb3a1140ba3d5": "lambda_$_720", "d155f473544dcda36e0bfa2a3f1579d2e32e251b1b2683a1a1eb73f919eefef2_arguments": "(((myless_$_649 mylist_$_650) (a_$_651 b_$_652)) sa_$_653 sb_$_654)", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d_left_env": "1", "source_file": "/home/arty/dev/chia/clvm_tools_rs/resources/tests/game-referee-after-cl21/test_sort.clsp", "__chia__main_arguments": "()", "2d2168734160822b5569309f8541a5b632b035f41c89907e79cb1983fc851a7b": "letbinding_$_715", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_arguments": "((mylist_$_711) newlist_$_712)", "ca9b60a19af98d1290d1161582331f43d6518cbe383dcb87452e253773cf9329_arguments": "(@ everything (rest aggl aggr))", "5b656ea16b982e0b3da35bd883c9ff6407dadbbf05faeca2d53f4348dad67679_arguments": "(a b)", "2a7aff98de69b1fef1b6bc350cb81e2dd99d40254e7f541ef22f8837937ffdbb": "busy", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "27306e11834170f40679ff25b0e24deeb74c7a9b32495134103d6f952600b48d": "deep_compare", "131cca40e81a7248781e5edf321f83b96282a9cf4e5ff0151b8dd2fdd5078499_arguments": "(mylist)", "24c1a323b918bc0b01064cb6171c20899e9d4e4e08a81d7e88013815e7c3fc22_arguments": "(myless a b)", "aff6f9e4b1d082994645068345db6e378e1839b24b4947111b4fd5d77bef5b4b": "range_inner", "7aaf175b403f21a9b93e40356ff378a531810f127922e726506b07915393384f_arguments": "(reversed rest)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b": "range", "d2586583545bb886183ab7b08b5c6561b6fdd931d8ee8e12b993d114579e6219_left_env": "1", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_left_env": "1", "b1f7d740362f526a0b859fb374c75a41ed23c0e463ae675bf7b4f6176e9cb517_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/testnoncegame.py b/resources/tests/game-referee-after-cl21/testnoncegame.py new file mode 100644 index 000000000..3b4cd2c2a --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testnoncegame.py @@ -0,0 +1,33 @@ +import hashlib + +from hsms.streamables.program import Program + +from clvm.EvalError import EvalError + +noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) +noncehash = noncegame.tree_hash() + +def drun(prog: Program, args: Program): + try: + return prog.run(args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(args)}") + raise + +def testnonce(startnonce, maxnonce): + for i in range(startnonce, maxnonce): + mygame = noncegame.curry(i, noncehash) + good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] + bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] + assert drun(mygame, good_parameters) == b'g' + for j in range(len(good_parameters)): + try: + p = list(good_parameters) + p[j] = bad_parameters[j] + mygame.run(p) + assert False + except EvalError as ee: + pass + +if __name__ == '__main__': + testnonce(3, 7) diff --git a/resources/tests/game-referee-after-cl21/testreferee.py b/resources/tests/game-referee-after-cl21/testreferee.py new file mode 100644 index 000000000..01eb53643 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testreferee.py @@ -0,0 +1,479 @@ +import pytest +from hashlib import sha256 +from contextlib import asynccontextmanager +from chia.clvm.spend_sim import SimClient, SpendSim +from pathlib import Path +from clvm.casts import int_to_bytes, int_from_bytes + +from hsms.streamables.program import Program +from clvm_tools_rs import compile_clvm +from clvm_tools.binutils import disassemble + +from clvm.EvalError import EvalError +from chia.types.mempool_inclusion_status import MempoolInclusionStatus +from chia.util.errors import Err +from dataclasses import dataclass +from typing import Any +from chia_rs import Coin +from chia.types.spend_bundle import SpendBundle +from chia.types.coin_spend import CoinSpend +from blspy import G2Element + +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'],'referee.clsp') +referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) +refhash = referee.tree_hash() +compile_module_with_symbols(['.'],'referee_accuse.clsp') +referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) +refaccusehash = referee.tree_hash() +compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + +move = 0 +accuse = 1 +timeout = 2 + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha(blob:bytes) -> bytes: + return sha256(blob).digest() + +@pytest.fixture(scope="function") +@asynccontextmanager +async def setup_sim() : + sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) + sim_client = SimClient(sim) + await sim.farm_block() + + try: + yield sim, sim_client + finally: + await sim.close() + +def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, + amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): + """ + returns referee_wrap + """ + puzzle_hash = referee.curry( + [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), + waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() + coin = Coin(parent_coin_id, puzzle_hash, amount) + return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), + initial_validation_program_hash, 0, initial_split, timeout, max_move_size, + mover_puzzle, waiter_puzzle) + +@dataclass +class RefereeWrap: + coin: Any + grandparent_id: Any + parent_validation_program_hash: Any + parent_everything_else_hash: Any + validation_program_hash: Any + move: Any + split: Any + timeout: Any + max_move_size: Any + mover_puzzle: Any + waiter_puzzle: Any + + def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): + result = Program.to([ + validation_program_hash, + move_to_make, + split, + self.coin.amount, + self.timeout, + self.max_move_size, + self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), + self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), + refhash + ]) + print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') + return result + + def get_puzzle(self): + return referee.curry(self.curried_parameters_for_our_puzzle( + "GET_PUZZLE", + True, + self.move, + self.split, + self.validation_program_hash + )) + + def SpendMove(self, password, move_to_make, split, validation_program_hash): + """ + returns (solution, new RefereeWrap) + """ + print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + curried_parameters = self.curried_parameters_for_our_puzzle( + "SPEND_MOVE", + False, + move_to_make, + split, + validation_program_hash + ) + print(f"MOVE referee curried parameters {curried_parameters}") + new_puzzle_hash = referee.curry(curried_parameters).tree_hash() + print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") + solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, + [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, + self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), + referee.tree_hash()]).tree_hash() + return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, + validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, + self.waiter_puzzle, self.mover_puzzle)) + + def SpendAccuse(self, password): + """ + returns (solution, RefereeAccuse) + """ + print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") + print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") + print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + new_puzzle_hash = referee_accuse.curry([ + self.parent_validation_program_hash, + self.validation_program_hash, + self.move, + self.split, + self.coin.amount, + self.timeout, + self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash() + ]).tree_hash() + solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, + self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, + self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash())) + + def SpendTimeout(self): + """ + returns (solution, movercoinid, waitercoinid) + """ + movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() + waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), + self.coin.amount - self.split).name() + return (Program.to((timeout, 0)), movercoinid, waitercoinid) + +@dataclass +class RefereeAccuseWrap: + coin: Any + old_validation_puzzle_hash: Any + new_validation_puzzle_hash: Any + move: Any + split: Any + timeout: Any + accused_puzzle_hash: Any + accuser_puzzle_hash: Any + + def get_puzzle(self): + return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, + self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, + self.accuser_puzzle_hash]) + + def SpendTimeout(self): + """ + returns (solution, coinid) + """ + coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) + return (Program.to(0), coin.name()) + + def SpendDefend(self, validation_program_reveal, validation_program_solution): + """ + returns (solution, coinid) + """ + solution = Program.to([validation_program_reveal, validation_program_solution]) + coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) + return (solution, coin.name()) + +@pytest.mark.asyncio +@pytest.mark.parametrize('amove', [0, 1, 2]) +@pytest.mark.parametrize('bmove', [0, 1, 2]) +async def test_rps(amove, bmove, setup_sim): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = int_to_bytes(60 + amove) + alice_image = sha(alice_preimage) + bob_preimage = int_to_bytes(60 + bmove) + bob_image = sha(bob_preimage) + alice_move = int_to_bytes(amove) + nil = Program.to(0) + + # (mod (password . conditions) (if (= password 'alice') conditions (x))) + alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) + alice_puzzle_hash = alice_puzzle.tree_hash() + # (mod (password . conditions) (if (= password 'bob') conditions (x))) + bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) + bob_puzzle_hash = bob_puzzle.tree_hash() + + async with setup_sim as (sym, client): + acs = Program.to(1) + acs_hash = acs.tree_hash() + await sym.farm_block(acs_hash) + mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin + # make a coin for a game + referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, + referee.coin.amount]]))], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse Bob of cheating (negative test, should fail) + solution, accuse = referee.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_MY_PARENT_ID_FAILED + # timeout too early fail + solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() + spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # timeout succeeds + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 + await sym.rewind(savepoint) + # Alice makes an illegally large move, fails + solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with negative split, fails + solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with split greater than amount, fails + solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice move 1 commit to image + bpuz = MOD_B.curry(alice_image) + solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuse Alice of cheating + solution, accuse = ref2.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint2 = sym.block_height + # Alice accusation defend, gets everything + solution, reward_id = accuse.SpendDefend(MOD_A, nil) + print(solution) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == alice_puzzle_hash + await sym.rewind(savepoint2) + # accusation timeout too early fail + solution, reward_id = accuse.SpendTimeout() + spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # accusation timeout succeed, Bob gets everything + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Bob move 2 commit to image + cpuz = MOD_C.curry([alice_image, bob_image]) + solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse + solution, accuse = ref3.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(bpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = + False))[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Alice reveals wrong preimage + alice_bad_preimage = int_to_bytes(61 + amove) + dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends, fails + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Alice move 3 reveal preimage + dpuz = MOD_D.curry([alice_move, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.rewind(savepoint) + # Bob move 4 reveal wrong preimage + bob_bad_preimage = int_to_bytes(121 + amove) + solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Bob attempts defense with wrong validation program, fails + solution, reward_id = accuse.SpendDefend(acs, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + if amove == bmove: + # Bob move 4 gives wrong split + solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Bob move 4 reveal preimage + solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice attempts move, fails + solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # timeout, split correct + sym.pass_time(2000) + await sym.farm_block() + solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() + spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + if alice_final != 0: + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final + else: + assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 + if alice_final != ref5.coin.amount: + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final + else: + assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 + await sym.rewind(savepoint) + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-after-cl21/testrockpaperscissors.py b/resources/tests/game-referee-after-cl21/testrockpaperscissors.py new file mode 100644 index 000000000..ed45dbccc --- /dev/null +++ b/resources/tests/game-referee-after-cl21/testrockpaperscissors.py @@ -0,0 +1,48 @@ +import hashlib + +from hsms.streamables.program import Program +from hsms.puzzles.load_clvm import load_clvm + +from clvm.EvalError import EvalError + + +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha256(blob:bytes) -> bytes: + return hashlib.sha256(blob).digest() + +def testrps(amove, bmove): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = Program.to(60 + amove) + bob_preimage = Program.to(60 + bmove) + alice_image = sha256(alice_preimage.atom) + bob_image = sha256(bob_preimage.atom) + alice_move = Program.to(amove) + + cd = MOD_D.curry(alice_move, bob_image) + assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' + cc = MOD_C.curry(alice_image, bob_image) + assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' + cb = MOD_B.curry(alice_image) + assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' + assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' + +def testall(): + for i in range(3): + for j in range(3): + testrps(i, j) + +if __name__ == '__main__': + testall() diff --git a/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_deep_compare.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex new file mode 100644 index 000000000..813027e6d --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff14ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff14ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff1cffff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ffff01ff02ff1cffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-in-cl21/smoke_test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex new file mode 100644 index 000000000..8a8aedd7f --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_handcalc.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff8200feffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff010effff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010dffff010380ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0103ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff0180808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0104ffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff01808080808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0107ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010280ffff04ffff04ffff010affff010280ffff04ffff04ffff0108ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010180ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0106ffff010180ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0108ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff0106ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff010dffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0107ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0104ffff010380ffff04ffff04ffff0103ffff010280ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0105ffff010180ffff04ffff04ffff0105ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff010effff010480ffff04ffff04ffff010dffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0105ffff010480ffff04ffff04ffff0104ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff01808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff0180808080808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0107ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010cffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0102ffff010380ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0106ffff010380ffff04ffff04ffff0106ffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010affff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff04ffff04ffff010affff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff0106ffff010380ffff01808080808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010effff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0104ffff010180ffff04ffff04ffff0104ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0107ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff0106ffff010180ffff04ffff04ffff0106ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff0109ffff010480ffff04ffff04ffff0108ffff010180ffff018080808080808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff0102ffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff01808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010bffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010bffff010280ffff0180808080808080ffff04ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0109ffff010280ffff04ffff04ffff010effff010380ffff04ffff04ffff010dffff010480ffff04ffff04ffff010cffff010180ffff04ffff04ffff010affff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff0102ffff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0105ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff0102ffff010280ffff04ffff04ffff0103ffff010380ffff04ffff04ffff0104ffff010480ffff04ffff04ffff0106ffff010180ffff01808080808080ffff04ffff04ffff04ffff010dffff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff04ffff04ffff0107ffff010280ffff04ffff04ffff0105ffff010380ffff018080808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff0102ffff010380ffff04ffff04ffff0103ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010cffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff0102ffff010480ffff04ffff04ffff0104ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010bffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0103ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010affff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff5080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0108ffff010180ffff01808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0102ffff010280ffff0180808080808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff04ffff04ffff0108ffff010280ffff0180808080808080ffff04ffff04ffff0102ffff04ffff04ffff0101ff8200b080ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff80808080ffff04ffff04ffff04ffff010effff010180ffff04ffff04ffff010dffff010280ffff04ffff04ffff010cffff010380ffff04ffff04ffff010bffff010480ffff04ffff04ffff0109ffff010180ffff01808080808080ffff04ffff04ffff04ffff010effff010280ffff04ffff04ffff010dffff010380ffff04ffff04ffff010cffff010480ffff04ffff04ffff010bffff010180ffff04ffff04ffff0109ffff010280ffff01808080808080ff808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080ffff04ffff01ffffffffffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff8200a0ffff04ff02ffff04ffff06ff0180ffff04ffff02ff40ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff010180ffff09ffff02ff40ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ffff01ff02ff8200f0ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffffff02ff8200f0ffff04ff02ffff04ff80ffff04ff05ff8080808080ffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200a8ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff8200e8ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff8200b8ffff04ff02ffff04ffff06ff0180ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ff8080808080ff0180ffff01ff02ffff0117ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ff0bffff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff80808080808080ff0180ffff01ff02ffff01ff02ff58ffff04ff02ffff04ff09ffff04ffff06ff1580ffff04ff2dff808080808080ff018080ff0180ff02ffff03ffff02ff44ffff04ff02ffff04ffff04ffff018c736c69636520696e70757473ffff04ffff01866e796c697374ffff04ff0bff80808080ffff04ffff20ff0b80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ffff05ff0580ffff02ff8200f8ffff04ff02ffff04ffff06ff0580ffff04ffff11ff0bffff010180ff808080808080ff018080ff0180ffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff8200a4ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff8200a4ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff8200a8ffff04ff02ffff04ffff02ff48ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff54ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200e4ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff8200acffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff8200f4ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff8200b4ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ff02ffff03ffff20ff1780ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ff0bffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ffff05ff1780ffff04ffff06ff1780ff808080808080ff0180ffff01ff02ffff01ff02ff8200ecffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ff808080808080ff018080ff0180ff018080ff0180ffff02ff8200ecffff04ff02ffff04ff05ffff04ff13ffff04ff1bff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ffff03ffff09ff17ffff010480ffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200bcffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff018080ff0180ff018080ff0180ff02ff8200bcffff04ff02ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff05ff8080808080ffff01ff80ff8080808080ffffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff02ffff03ffff18ffff09ff17ffff010280ffff09ff2fffff010480ff0b80ffff01ff02ffff01ff0105ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff17ffff05ff058080ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ff17ffff04ff2fff80808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ffff11ff17ffff01018080ffff01ff02ffff01ff02ffff03ffff09ff2fffff010480ffff01ff02ffff01ff10ff17ffff010380ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff10ff2fffff010180ff80808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ff8200a2ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff05ff0580ffff04ffff0101ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff8200a2ffff04ff02ffff04ff05ffff04ffff09ff09ffff010e80ffff01ff80ff808080808080ffff02ffff03ffff20ff0580ffff01ff02ffff01ff04ffff04ff17ff0b80ffff018080ff0180ffff01ff02ffff01ff02ffff03ffff09ffff05ff0580ff0b80ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0580ffff04ff0bffff04ffff10ff17ffff010180ff808080808080ff0180ffff01ff02ffff01ff02ff8200b2ffff04ff02ffff04ffff06ff0180ffff04ffff02ff52ffff04ff02ffff04ffff06ff0580ffff04ffff05ff0580ffff04ffff0101ff808080808080ff8080808080ff018080ff0180ff018080ff0180ffff04ffff04ff2dff1580ff0b80ff02ff52ffff04ff02ffff04ff05ffff04ff09ffff01ff808080808080ffffff02ff5affff04ff02ffff04ff03ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200aa80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ea80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ff808080808080ff1b13ffff02ff8200faffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ba80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200e8ffff04ff02ffff04ff17ffff04ff09ffff01ff808080808080ff8080808080ffff04ffff02ff8200fcffff04ff02ffff04ffff02ff8200e8ffff04ff02ffff04ff0bffff04ff09ffff01ff808080808080ff80808080ff808080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff8200f6ffff04ff02ffff04ff03ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff02ff8200f2ffff04ff02ffff04ff0bff80808080ff8080808080ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ffff04ffff02ffff03ffff20ff1780ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff06ff0180ffff04ffff02ff8200f4ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200a680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200e680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ffff01808080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff11ffff04ffff0180ff808080808080ff8080808080ff8080808080ff018080ff0180ff80808080808080ffffffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff50ffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ffff03ffff09ff09ff1b80ffff01ff02ffff0113ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff8200b6ffff04ff02ffff04ff03ffff04ffff02ff8200e2ffff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ff0bffff01ff02ffff01ff04ffff0109ffff04ff0bffff01808080ff0180ffff01ff02ffff01ff04ffff0106ffff02ff8200f8ffff04ff02ffff04ff15ffff04ffff0105ff808080808080ff018080ff0180ff02ff4effff04ff02ffff04ff03ffff04ffff02ffff03ff17ffff01ff02ffff01ff04ffff0105ffff04ff17ffff01808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff04ff2bffff04ff13ffff04ffff02ff8200e8ffff04ff02ffff04ff29ffff04ff0bffff01ff808080808080ff8080808080808080ffffff02ff8200aeffff04ff02ffff04ff03ffff04ffff02ffff03ffff09ff4fffff010180ffff01ff02ffff01ff04ffff0101ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0105ff808080808080ff0180ffff01ff02ffff01ff02ffff03ffff09ff4fffff010280ffff01ff02ffff01ff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0102ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0104ff808080808080ff0180ffff01ff02ffff01ff04ffff0103ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff09ff4fffff010380ffff01ff02ffff01ff02ffff03ffff09ff27ffff010180ffff01ff02ffff01ff04ffff0104ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0103ff808080808080ff0180ffff01ff02ffff01ff04ffff0107ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff0180ffff01ff02ffff01ff04ffff0108ffff02ff8200f8ffff04ff02ffff04ff5fffff04ffff0102ff808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff8080808080ffff02ff5cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200ee80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ffff04ff8200b9ffff04ff15ffff04ff0bff80808080ff8080808080ff02ff8200e0ffff04ff02ffff04ff0bffff04ff17ff8080808080ffff02ff8200beffff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff2dff80808080ffff04ffff02ff4affff04ff02ffff04ff15ff80808080ff808080808080ffff02ffff03ffff02ff11ffff04ff17ffff04ff0bff80808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff17ffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff29ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff8200b0ffff04ff02ffff04ff0bffff04ffff02ff4affff04ff02ffff04ffff02ff48ffff04ff02ffff04ff59ff80808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ff79ffff01ff02ffff01ff02ff5effff04ff02ffff04ff79ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff02ffff03ff03ffff01ff02ffff01ff02ff5effff04ff02ffff04ff03ff80808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex new file mode 100644 index 000000000..ccbc2f4aa --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ffff0180ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff5affff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff0180ff80808080ffff04ffff01ff8080ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff40ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff0bffff01ff02ffff01ff02ff60ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff70ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ffffff02ffff03ff05ffff01ff02ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff01ff80ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff40ffff04ff02ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff4cffff04ff02ffff04ffff06ff0180ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffff02ff6cffff04ff02ffff04ff03ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff74ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff54ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff7cffff04ff02ffff04ffff06ff0180ffff04ffff02ff5cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffffffff09ffff02ff5cffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff52ffff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff62ffff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ffff01ff02ff62ffff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff6affff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff6affff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff5affff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff04ffff04ffff0101ffff05ff058080ffff02ff7affff04ff02ffff04ffff06ff0580ff8080808080ff0180ffff01ff02ffff01ff0180ff018080ff0180ffffffff02ffff04ffff0122ffff02ff7affff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff02ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffff02ffff03ff0dffff01ff02ffff01ff02ffff03ffff02ff42ffff04ff02ffff04ff09ffff04ffff05ff0d80ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff02ff56ffff04ff02ffff04ff0dff80808080ff018080ff0180ff0180ffff01ff02ffff01ff0101ff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff56ffff04ff02ffff04ffff02ff74ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ff80808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ffffff09ffff02ff5cffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff0bffff04ffff0180ff808080808080ff80808080ffff01ff02ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ff0180ffff01ff02ffff01ff0880ff018080ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_prepend.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_range.clvm.hex b/resources/tests/game-referee-in-cl21/test_range.clvm.hex new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_range.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_reverse.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl21/test_sort.clvm.hex b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex new file mode 100644 index 000000000..cf5d0409c --- /dev/null +++ b/resources/tests/game-referee-in-cl21/test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ffff0180ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ffff0180ffff04ffff0180ffff04ffff0102ffff01808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff7cffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff0180ffff04ffff0180ff8080808080ffff04ffff0101ffff0180808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff01ff02ffff010bff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff05ffff01ff02ffff01ff02ff50ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ff02ff50ffff04ff02ffff04ff05ffff01ff80ff8080808080ffffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff22ffff04ff02ffff04ffff02ff7cffff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff78ffff04ff02ffff04ffff06ff0180ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ff02ff24ffff04ff02ffff04ff03ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff58ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffffff02ff68ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff74ffff04ff02ffff04ffff06ff0180ffff04ffff02ff54ffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff54ffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ffffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ffff01ff02ff5cffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff5cffff04ff02ffff04ff80ffff04ff05ff8080808080ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff22ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff52ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ffff20ff0b80ffff01ff02ffff0117ff0180ffff01ff02ffff01ff02ff5affff04ff02ffff04ffff06ff0180ffff04ffff06ff0b80ffff04ffff05ff0b80ff808080808080ff018080ff0180ffff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff17ff808080ffff01ff01808080ff80808080ffff04ffff02ff46ffff04ff02ffff04ffff02ff22ffff04ff02ffff04ff09ffff04ff0bff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff17ff0980ffff04ff0bffff04ff2dff808080808080ff808080808080ff04ff09ff0b80ffffffff02ffff03ff05ffff01ff02ffff01ff02ff6affff04ff02ffff04ffff0180ffff04ff05ffff04ffff0180ff808080808080ff0180ffff01ff02ffff01ff01ff8080ff018080ff0180ff02ffff03ff0dffff01ff02ffff01ff02ff66ffff04ff02ffff04ff0dff80808080ff0180ffff01ff02ffff0109ff018080ff0180ffff02ffff03ff0bffff01ff02ffff01ff02ff66ffff04ff02ffff04ffff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff808080808080ffff01808080ff80808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff02ff6cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff58ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff01ffff04ffff0180ff0180808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff0880ff018080ff0180ffffff02ff4cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff01ff01808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff01ff01808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff46ffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 diff --git a/resources/tests/lib/steprun.py b/resources/tests/lib/steprun.py index 02db51339..a8bd8f658 100644 --- a/resources/tests/lib/steprun.py +++ b/resources/tests/lib/steprun.py @@ -22,10 +22,10 @@ def compile_module_with_symbols(include_paths: List[Path], source: Path): str(path_obj.resolve()), str(target_file.absolute()), [str(p) for p in include_paths], True ) print(f"Writing to {target_file} {compile_result}") - # symbols = compile_result["symbols"] - # if len(symbols) != 0: - # with open(str(sym_file.absolute()), "w") as symfile: - # symfile.write(json.dumps(symbols)) + symbols = compile_result["symbols"] + if len(symbols) != 0: + with open(str(sym_file.absolute()), "w") as symfile: + symfile.write(json.dumps(symbols)) def run_until_end(p): From 3556dc0809eac6b11b47ba90d11b255347cca520 Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 26 Oct 2023 13:15:39 -0700 Subject: [PATCH 20/48] Add cl23 game tests. There is no terse mode yet in this timeline, but it might make sense to move it up. --- .github/workflows/extensive-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml index 6bf997da7..86d328ea4 100644 --- a/.github/workflows/extensive-tests.yml +++ b/.github/workflows/extensive-tests.yml @@ -118,3 +118,4 @@ jobs: . ./activate cp support/test-game-referee.sh . sh test-game-referee.sh resources/tests/game-referee-in-cl21 + sh test-game-referee.sh resources/tests/game-referee-after-cl21 From 0dff998337a9af61a19bd21a9dbb449f90997cab Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 26 Oct 2023 13:22:31 -0700 Subject: [PATCH 21/48] fmt --- src/tests/classic/run.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/classic/run.rs b/src/tests/classic/run.rs index 206f9d7ba..cbf09ab89 100644 --- a/src/tests/classic/run.rs +++ b/src/tests/classic/run.rs @@ -1001,8 +1001,8 @@ fn test_lambda_without_capture_strict() { "resources/tests".to_string(), "resources/tests/strict/rps-referee-uncaptured.clsp".to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); assert!(compiler_result.contains("Unbound")); assert!(compiler_result.contains("new_puzzle_hash")); } @@ -1031,8 +1031,8 @@ fn test_cost_reporting_0() { program.to_string(), "()".to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); assert_eq!( result, "cost = 1978\n0x6fcb06b1fe29d132bb37f3a21b86d7cf03d636bf6230aa206486bef5e68f9875" From 2456e658ca69ce1be3924ad356404f203ff4179b Mon Sep 17 00:00:00 2001 From: arty Date: Thu, 26 Oct 2023 14:44:07 -0700 Subject: [PATCH 22/48] Move include files --- .../game-referee-after-cl21/all-in-list.clinc | 12 ++ .../game-referee-after-cl21/assert.clinc | 8 ++ .../tests/game-referee-after-cl21/busy.clinc | 11 ++ .../condition_codes.clinc | 41 +++++++ .../curry-and-treehash.clinc | 92 ++++++++++++++++ .../tests/game-referee-after-cl21/curry.clinc | 104 ++++++++++++++++++ .../deep_compare.clinc | 41 +++++++ .../game-referee-after-cl21/filtermap.clinc | 14 +++ .../game-referee-after-cl21/flatten.clinc | 12 ++ .../tests/game-referee-after-cl21/last.clinc | 39 +++++++ .../tests/game-referee-after-cl21/len.clinc | 3 + .../tests/game-referee-after-cl21/map.clinc | 17 +++ .../tests/game-referee-after-cl21/match.clinc | 12 ++ .../tests/game-referee-after-cl21/max.clinc | 13 +++ .../permutations.clinc | 21 ++++ .../game-referee-after-cl21/prefix.clinc | 16 +++ .../game-referee-after-cl21/prepend.clinc | 8 ++ .../tests/game-referee-after-cl21/print.clinc | 3 + .../tests/game-referee-after-cl21/range.clinc | 11 ++ .../game-referee-after-cl21/reduce.clinc | 10 ++ .../game-referee-after-cl21/reverse.clinc | 11 ++ .../game-referee-after-cl21/shatree.clinc | 11 ++ .../tests/game-referee-after-cl21/slice.clinc | 10 ++ .../tests/game-referee-after-cl21/sort.clinc | 44 ++++++++ .../tests/game-referee-after-cl21/utils.clinc | 17 +++ 25 files changed, 581 insertions(+) create mode 100644 resources/tests/game-referee-after-cl21/all-in-list.clinc create mode 100644 resources/tests/game-referee-after-cl21/assert.clinc create mode 100644 resources/tests/game-referee-after-cl21/busy.clinc create mode 100644 resources/tests/game-referee-after-cl21/condition_codes.clinc create mode 100644 resources/tests/game-referee-after-cl21/curry-and-treehash.clinc create mode 100644 resources/tests/game-referee-after-cl21/curry.clinc create mode 100644 resources/tests/game-referee-after-cl21/deep_compare.clinc create mode 100644 resources/tests/game-referee-after-cl21/filtermap.clinc create mode 100644 resources/tests/game-referee-after-cl21/flatten.clinc create mode 100644 resources/tests/game-referee-after-cl21/last.clinc create mode 100644 resources/tests/game-referee-after-cl21/len.clinc create mode 100644 resources/tests/game-referee-after-cl21/map.clinc create mode 100644 resources/tests/game-referee-after-cl21/match.clinc create mode 100644 resources/tests/game-referee-after-cl21/max.clinc create mode 100644 resources/tests/game-referee-after-cl21/permutations.clinc create mode 100644 resources/tests/game-referee-after-cl21/prefix.clinc create mode 100644 resources/tests/game-referee-after-cl21/prepend.clinc create mode 100644 resources/tests/game-referee-after-cl21/print.clinc create mode 100644 resources/tests/game-referee-after-cl21/range.clinc create mode 100644 resources/tests/game-referee-after-cl21/reduce.clinc create mode 100644 resources/tests/game-referee-after-cl21/reverse.clinc create mode 100644 resources/tests/game-referee-after-cl21/shatree.clinc create mode 100644 resources/tests/game-referee-after-cl21/slice.clinc create mode 100644 resources/tests/game-referee-after-cl21/sort.clinc create mode 100644 resources/tests/game-referee-after-cl21/utils.clinc diff --git a/resources/tests/game-referee-after-cl21/all-in-list.clinc b/resources/tests/game-referee-after-cl21/all-in-list.clinc new file mode 100644 index 000000000..1db5f26ad --- /dev/null +++ b/resources/tests/game-referee-after-cl21/all-in-list.clinc @@ -0,0 +1,12 @@ +( + (defun enquote-rest (L) + (if L + (c (c 1 (f L)) (enquote-rest (r L))) + () + ) + ) + + (defun all-in-list (L) + (a (c 34 (enquote-rest L)) ()) + ) +) diff --git a/resources/tests/game-referee-after-cl21/assert.clinc b/resources/tests/game-referee-after-cl21/assert.clinc new file mode 100644 index 000000000..c9f212394 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/assert.clinc @@ -0,0 +1,8 @@ +( + (defmacro assert items + (if (r items) + (list if (f items) (c assert (r items)) (q . (x))) + (f items) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/busy.clinc b/resources/tests/game-referee-after-cl21/busy.clinc new file mode 100644 index 000000000..e534d2125 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/busy.clinc @@ -0,0 +1,11 @@ +( + (defun busy (myfunc mylist returnval) + (if mylist + (last + (a myfunc (list (f mylist))) + (busy myfunc (r mylist) returnval) + ) + returnval + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/condition_codes.clinc b/resources/tests/game-referee-after-cl21/condition_codes.clinc new file mode 100644 index 000000000..45f3265da --- /dev/null +++ b/resources/tests/game-referee-after-cl21/condition_codes.clinc @@ -0,0 +1,41 @@ +; See chia/types/condition_opcodes.py + +( + (defconstant AGG_SIG_UNSAFE 49) + (defconstant AGG_SIG_ME 50) + + ; the conditions below reserve coin amounts and have to be accounted for in output totals + + (defconstant CREATE_COIN 51) + (defconstant RESERVE_FEE 52) + + ; the conditions below deal with announcements, for inter-coin communication + + ; coin announcements + (defconstant CREATE_COIN_ANNOUNCEMENT 60) + (defconstant ASSERT_COIN_ANNOUNCEMENT 61) + + ; puzzle announcements + (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) + (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) + + ; the conditions below let coins inquire about themselves + + (defconstant ASSERT_MY_COIN_ID 70) + (defconstant ASSERT_MY_PARENT_ID 71) + (defconstant ASSERT_MY_PUZZLEHASH 72) + (defconstant ASSERT_MY_AMOUNT 73) + + ; the conditions below ensure that we're "far enough" in the future + + ; wall-clock time + (defconstant ASSERT_SECONDS_RELATIVE 80) + (defconstant ASSERT_SECONDS_ABSOLUTE 81) + + ; block index + (defconstant ASSERT_HEIGHT_RELATIVE 82) + (defconstant ASSERT_HEIGHT_ABSOLUTE 83) + + ; A condition that is always true and always ignore all arguments + (defconstant REMARK 1) +) diff --git a/resources/tests/game-referee-after-cl21/curry-and-treehash.clinc b/resources/tests/game-referee-after-cl21/curry-and-treehash.clinc new file mode 100644 index 000000000..6a63e9364 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/curry-and-treehash.clinc @@ -0,0 +1,92 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant ONE 1) + (defconstant TWO 2) + (defconstant A_KW #a) + (defconstant Q_KW #q) + (defconstant C_KW #c) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 TWO (sha256 ONE C_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash`, updating `environment-hash` + ;; along the way. + + (defun build-curry-list (reversed-curry-parameter-hashes environment-hash) + (if reversed-curry-parameter-hashes + (build-curry-list (r reversed-curry-parameter-hashes) + (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash)) + environment-hash + ) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `function-hash` of a function tree F + ;; return the tree hash of the tree corresponding to + ;; `(a (q . F) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . F) E)` = `(a . ((q . F) . (E . 0)))` + + (defun-inline tree-hash-of-apply (function-hash environment-hash) + (sha256 TWO (sha256 ONE A_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; function-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; reversed-curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; Note that this must be applied in REVERSED order. This may seem strange, but it greatly simplifies + ;; the underlying code, since we calculate the tree hash from the bottom nodes up, and the last + ;; parameters curried must have their hashes calculated first. + ;; + ;; we return the hash of the curried expression + ;; (a (q . function-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the actual curried program. + + (defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) + (tree-hash-of-apply function-hash + (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))) + ) + + (defconstant b32 32) + + (defun-inline size_b32 (var) + (= (strlen var) b32) + ) + + (defun calculate_coin_id (parent puzzlehash amount) + (if (all (size_b32 parent) (size_b32 puzzlehash) (> amount -1)) + (sha256 parent puzzlehash amount) + (x) + ) + ) + + ; takes a lisp tree and returns the hash of it + (defun shatree (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE))) + +) diff --git a/resources/tests/game-referee-after-cl21/curry.clinc b/resources/tests/game-referee-after-cl21/curry.clinc new file mode 100644 index 000000000..81a1ec3a6 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/curry.clinc @@ -0,0 +1,104 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant TWO 2) + (defconstant constant-tree ( + (0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a . ; = `(sha256 1)` + 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) . ; = `(sha256 1 1)` = `(sha256 1 #q)` + (0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . ; = `(concat 2 (sha256 1 #a))` + 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5) ; = `(concat 2 (sha256 1 #c))` + ) + ) + + ; I looked into calculating the values of `constant-tree` because it's pretty easy to code-golf + ; out an implementation that produces the values cheaper than just inlining them. The problem is, + ; when do we calculate them? If there were a way to calculate it "before main" and include it in + ; the globally-accessible constant table, we could do that. But we can't which means to be optimal, + ; client code should call the "build table" code once, then pass it around to anyone that wants to + ; call `curry` or `curry2`. This is pretty intrusive, so for now we'll just use the existing + ; global constant infrastructure, and include it as a fixed table so the tree of four values will + ; appear in all code that includes this file, and it will compress better in generators. + + (defun-inline sha256_one _noargs (f (f constant-tree))) + (defun-inline sha256_one_one _noargs (r (f constant-tree))) + (defun-inline two_sha256_one_a_kw _noargs (f (r constant-tree))) + (defun-inline two_sha256_one_c_kw _noargs (r (r constant-tree))) + + ;; this returns the sha256 tree hash of expression F = `((q . a1) a2)` + (defun hash-expression-F (a1 a2) + (sha256 TWO (sha256 TWO (sha256_one_one) a1) + (sha256 TWO a2 (sha256_one))) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 (two_sha256_one_c_kw) (hash-expression-F parameter-hash environment-hash)) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `mod-hash` of a mod M + ;; return the tree hash of the tree corresponding to + ;; `(a (q . M) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . M) E)` = `(a . ((q . M) . (E . 0)))` + + (defun-inline tree-hash-of-apply (mod-hash environment-hash) + (sha256 (two_sha256_one_a_kw) (hash-expression-F mod-hash environment-hash)) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash` + + (defun calculate-hash-of-curried-parameters (curry-parameter-hashes) + (if curry-parameter-hashes + (update-hash-for-parameter-hash (f curry-parameter-hashes) (calculate-hash-of-curried-parameters (r curry-parameter-hashes))) + (sha256_one_one) + ) + ) + + ;; mod-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; + ;; we return the hash of the curried expression + ;; (a (q . mod-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the acutal curried program. + + ;; inline functions that take varargs don't seem to work, so we can't inline `curry` + + (defun curry_hashes (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + + ;; this is included for future compilers that handle it properly. If you get weird + ;; errors using this, it may be your tooling. Use `curry` above instead, or inline manually. + + (defun-inline curry_hashes_inline (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + ;; `curry_mod_hashes_inline` takes exactly two parameters rather than varags, and it can be inlined + + (defun-inline curry_mod_hashes_inline (mod-hash curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/deep_compare.clinc b/resources/tests/game-referee-after-cl21/deep_compare.clinc new file mode 100644 index 000000000..0a863ae33 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/deep_compare.clinc @@ -0,0 +1,41 @@ + +( + (defun deep_compare (a b) + (if (l a) + (if (l b) + (assign-lambda inner_result (deep_compare (f a) (f b)) + (if inner_result + inner_result + (deep_compare (r a) (r b)) + ) + ) + 1 + ) + (if (l b) + -1 + (if (> a b) + 1 + (- 0 (> b a)) + ) + ) + ) + ) + (defun deep< (a b) + (= (deep_compare a b) -1) + ) + (defun deep> (a b) + (= (deep_compare a b) 1) + ) + (defun deep= (a b) + (= (deep_compare a b) 0) + ) + (defun deep<= (a b) + (not (deep> a b)) + ) + (defun deep>= (a b) + (not (deep< a b)) + ) + (defun deep!= (a b) + (not (deep= a b)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/filtermap.clinc b/resources/tests/game-referee-after-cl21/filtermap.clinc new file mode 100644 index 000000000..59c827858 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/filtermap.clinc @@ -0,0 +1,14 @@ + +( + (defun filtermap (process remaining init) + (if remaining + (assign next (a process (list (f remaining))) + (if next + (c next (filtermap process (r remaining) init)) + (filtermap process (r remaining) init) + ) + ) + init + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/flatten.clinc b/resources/tests/game-referee-after-cl21/flatten.clinc new file mode 100644 index 000000000..ab3815abd --- /dev/null +++ b/resources/tests/game-referee-after-cl21/flatten.clinc @@ -0,0 +1,12 @@ +( + (defun flatten_list (everything) + (if + (not everything) 0 + (prepend (f everything) (flatten_list (r everything))) + ) + ) + (defun flatten everything + (flatten_list everything) + ) + +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/last.clinc b/resources/tests/game-referee-after-cl21/last.clinc new file mode 100644 index 000000000..5a6ffd73e --- /dev/null +++ b/resources/tests/game-referee-after-cl21/last.clinc @@ -0,0 +1,39 @@ +( + (defun last_inner ((next . remainder)) + (if remainder + (last_inner remainder) + next + ) + ) + + (defmacro last ARGS + (defun snoc (L agg) + (if L + (if (r L) + (snoc (r L) (c (f L) agg)) + (c (f L) agg) + ) + (c () ()) + ) + ) + + (defun prefix (L P) + (if L + (c (f L) (prefix (r L) P)) + P + ) + ) + + (if ARGS + (if (r ARGS) + (assign + (final . rest) (snoc ARGS ()) + reversed (prefix rest (list final)) + (qq (last_inner (unquote (c list reversed)))) + ) + (qq (last_inner (unquote (f ARGS)))) + ) + (x "Last takes at least one argument") + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/len.clinc b/resources/tests/game-referee-after-cl21/len.clinc new file mode 100644 index 000000000..407c36694 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/len.clinc @@ -0,0 +1,3 @@ +( + (defun len (L) (if L (+ 1 (len (r L))) 0)) +) diff --git a/resources/tests/game-referee-after-cl21/map.clinc b/resources/tests/game-referee-after-cl21/map.clinc new file mode 100644 index 000000000..016c3a0e4 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/map.clinc @@ -0,0 +1,17 @@ +( + (defun map-with-rest (F L R) + (if L + (c (a F (list (f L))) (map-with-rest F (r L) R)) + R + ) + ) + + (defmacro map ARGS + (defun list-len (X) (if X (+ 1 (list-len (r X))) 0)) + + (if (= (list-len ARGS) 3) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) (unquote (f (r (r ARGS)))))) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) ())) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/match.clinc b/resources/tests/game-referee-after-cl21/match.clinc new file mode 100644 index 000000000..d66593c55 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/match.clinc @@ -0,0 +1,12 @@ + +( + (defun match (process remaining) + (if remaining + (if (a process (list (f remaining))) + (f remaining) + (match process (r remaining)) + ) + 0 + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/max.clinc b/resources/tests/game-referee-after-cl21/max.clinc new file mode 100644 index 000000000..5ec6d54f6 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/max.clinc @@ -0,0 +1,13 @@ +( + (defun max_inner (myless best_so_far mylist) + (if (not mylist) best_so_far + (if (a myless (list best_so_far (f mylist))) + (max_inner myless (f mylist) (r mylist)) + (max_inner myless best_so_far (r mylist)) + ) + ) + ) + (defun max (myless mylist) + (max_inner myless (f mylist) (r mylist)) + ) +) diff --git a/resources/tests/game-referee-after-cl21/permutations.clinc b/resources/tests/game-referee-after-cl21/permutations.clinc new file mode 100644 index 000000000..9664c6aff --- /dev/null +++ b/resources/tests/game-referee-after-cl21/permutations.clinc @@ -0,0 +1,21 @@ +( + (defun permutations_inner (pre post agg) + (if (not post) + agg + (assign + myatom (f post) + newrest (r post) + (map (lambda ((& myatom) x) (c myatom x)) + (permutations (prepend pre newrest)) + (permutations_inner (c myatom pre) newrest agg) + ) + ) + ) + ) + (defun permutations (vals) + (if vals + (permutations_inner 0 vals 0) + (q ()) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/prefix.clinc b/resources/tests/game-referee-after-cl21/prefix.clinc new file mode 100644 index 000000000..641723dad --- /dev/null +++ b/resources/tests/game-referee-after-cl21/prefix.clinc @@ -0,0 +1,16 @@ +( + (defmacro prefix ARGS + (defun compile-list (args) + (if args + (if (r args) + ;; We have at least 2 things left... recurse once. + (qq (c (unquote (f args)) (unquote (compile-list (r args))))) + ;; This is the last item, so we return it whole (improper list form). + (qq (unquote (f args))) + ) + 0 + ) + ) + (compile-list ARGS) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/prepend.clinc b/resources/tests/game-referee-after-cl21/prepend.clinc new file mode 100644 index 000000000..2ea293409 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/prepend.clinc @@ -0,0 +1,8 @@ +( + (defun prepend (a b) + (if a + (c (f a) (prepend (r a) b)) + b + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/print.clinc b/resources/tests/game-referee-after-cl21/print.clinc new file mode 100644 index 000000000..95d459b36 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/print.clinc @@ -0,0 +1,3 @@ +( + (defun print (R P) (if (all "$print$" R P) P P)) +) diff --git a/resources/tests/game-referee-after-cl21/range.clinc b/resources/tests/game-referee-after-cl21/range.clinc new file mode 100644 index 000000000..dc1e61ca3 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/range.clinc @@ -0,0 +1,11 @@ +( + (defun range_inner (next final) + (if (= next final) + 0 + (c next (range_inner (+ next 1) final)) + ) + ) + (defun range (i) + (range_inner 0 i) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/reduce.clinc b/resources/tests/game-referee-after-cl21/reduce.clinc new file mode 100644 index 000000000..3251c79a7 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/reduce.clinc @@ -0,0 +1,10 @@ + +( + ; From here to the meat should be in a standard library + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/reverse.clinc b/resources/tests/game-referee-after-cl21/reverse.clinc new file mode 100644 index 000000000..389963ee9 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/reverse.clinc @@ -0,0 +1,11 @@ +( + (defun reverse_inner (reversed rest) + (if rest + (reverse_inner (c (f rest) reversed) (r rest)) + reversed + ) + ) + (defun reverse (vals) + (reverse_inner 0 vals) + ) +) diff --git a/resources/tests/game-referee-after-cl21/shatree.clinc b/resources/tests/game-referee-after-cl21/shatree.clinc new file mode 100644 index 000000000..05bdb2699 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/shatree.clinc @@ -0,0 +1,11 @@ +( + ;; hash a tree + ;; This is used to calculate a puzzle hash given a puzzle program. + (defun shatree + (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE) + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-after-cl21/slice.clinc b/resources/tests/game-referee-after-cl21/slice.clinc new file mode 100644 index 000000000..2c98a09c5 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/slice.clinc @@ -0,0 +1,10 @@ + +( + ; returns the first count elements of mylist + (defun slice (mylist count) + (if (print (list "slice inputs" nylist count) (not count)) + 0 + (c (f mylist) (slice (r mylist) (- count 1))) + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/sort.clinc b/resources/tests/game-referee-after-cl21/sort.clinc new file mode 100644 index 000000000..a9afed46a --- /dev/null +++ b/resources/tests/game-referee-after-cl21/sort.clinc @@ -0,0 +1,44 @@ + +( + (defun split_inner (@ everything (rest aggl aggr)) + (if rest + (split_inner (r rest) aggr (c (f rest) aggl)) + (r everything) + ) + ) + (defun split (mylist) + (split_inner mylist 0 0) + ) + (defun merge_inner (myless A B agg) + ; this should use continued if + (if (not A) + (prepend (reverse agg) B) + (if (not B) + (prepend (reverse agg) A) + (if (a myless (list (f A) (f B))) + (merge_inner myless (r A) B (c (f A) agg)) + (merge_inner myless A (r B) (c (f B) agg)) + ) + ) + ) + ) + (defun merge (myless a b) + (merge_inner myless a b 0) + ) + (defun sort-split (myless (a b)) + (merge myless (sort myless a) (sort myless b)) + ) + (defun sort (myless mylist) + (if mylist + (if (r mylist) + (assign (a b) (split mylist) + sa (sort myless a) + sb (sort myless b) + (merge myless sa sb) + ) + mylist + ) + () + ) + ) +) diff --git a/resources/tests/game-referee-after-cl21/utils.clinc b/resources/tests/game-referee-after-cl21/utils.clinc new file mode 100644 index 000000000..7d754e001 --- /dev/null +++ b/resources/tests/game-referee-after-cl21/utils.clinc @@ -0,0 +1,17 @@ +( + (defmacro ifc ARGS + (defun list-length (lst) + (if (l lst) + (+ 1 (list-length (r lst))) + 0 + ) + ) + (defun do-continued-if (ARGS) + (if (= (list-length ARGS) 3) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (com (unquote (f (r (r ARGS))))))) + (qq (i (unquote (f ARGS)) (com (unquote (f (r ARGS)))) (unquote (do-continued-if (r (r ARGS)))))) + ) + ) + (qq (a (unquote (do-continued-if ARGS)) @)) + ) +) From 882ba95554ec226bedffc6348f1c5c5ecb387b9d Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Oct 2023 11:06:42 -0700 Subject: [PATCH 23/48] Add tricky cse test series --- Cargo.lock | 148 +++++- Cargo.toml | 1 + src/compiler/compiler.rs | 18 +- src/tests/compiler/clvm.rs | 2 +- src/tests/compiler/optimizer/cse.rs | 671 +++++++++++++++++++++++++++- src/tests/util.rs | 55 ++- 6 files changed, 862 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 563a70902..96a8debce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -140,6 +140,7 @@ dependencies = [ "indoc 1.0.9", "js-sys", "lazy_static", + "lfsr", "linked-hash-map", "num", "num-bigint", @@ -242,8 +243,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", ] @@ -288,6 +289,12 @@ dependencies = [ "spki", ] +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + [[package]] name = "elliptic-curve" version = "0.13.5" @@ -431,8 +438,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce046d161f000fffde5f432a0d034d0341dc152643b2598ed5bfce44c4f3a8f0" dependencies = [ "proc-macro-hack", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 1.0.109", "unindent", ] @@ -446,6 +453,15 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itertools" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.9" @@ -481,6 +497,61 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lfsr" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1408c5559fc91f522a78aa46b85647f5bcbeee9e64e4b7d8e7b0d259d0047c57" +dependencies = [ + "lfsr-base", + "lfsr-instances", + "lfsr-macro-generate", + "lfsr-macro-lookup", +] + +[[package]] +name = "lfsr-base" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1355f8e4ef0c69b2f41f154716197b1027a75afb094dbc1b5d96cd124b2d946c" + +[[package]] +name = "lfsr-instances" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c2fd4e3b24c4c995c6d89cffb1f346b68bfa37466bfde5023975af945bfb75" +dependencies = [ + "lfsr-base", + "lfsr-macro-generate", +] + +[[package]] +name = "lfsr-macro-generate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b797be749e5d7d013b3e18954049468c228841a5068ceb55dd9da23a300ecff6" +dependencies = [ + "itertools", + "lfsr-base", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + +[[package]] +name = "lfsr-macro-lookup" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3a3a6a85a7aac81c9f94adc14ab565eaaac8fd91460d06b89e4dd93462cdf8" +dependencies = [ + "itertools", + "lfsr-base", + "lfsr-instances", + "proc-macro2 0.4.30", + "quote 0.6.13", + "syn 0.15.44", +] + [[package]] name = "libc" version = "0.2.147" @@ -715,6 +786,15 @@ version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +dependencies = [ + "unicode-xid", +] + [[package]] name = "proc-macro2" version = "1.0.66" @@ -765,7 +845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc0bc5215d704824dfddddc03f93cb572e1155c68b6761c37005e1c288808ea8" dependencies = [ "pyo3-macros-backend", - "quote", + "quote 1.0.32", "syn 1.0.109", ] @@ -775,19 +855,28 @@ version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71623fc593224afaab918aa3afcaf86ed2f43d34f6afde7f3922608f253240df" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.66", "pyo3-build-config 0.14.5", - "quote", + "quote 1.0.32", "syn 1.0.109", ] +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +dependencies = [ + "proc-macro2 0.4.30", +] + [[package]] name = "quote" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ - "proc-macro2", + "proc-macro2 1.0.66", ] [[package]] @@ -943,8 +1032,8 @@ version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 2.0.28", ] @@ -1015,14 +1104,25 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +dependencies = [ + "proc-macro2 0.4.30", + "quote 0.6.13", + "unicode-xid", +] + [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] @@ -1032,8 +1132,8 @@ version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "unicode-ident", ] @@ -1074,6 +1174,12 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" + [[package]] name = "unindent" version = "0.1.11" @@ -1113,8 +1219,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 2.0.28", "wasm-bindgen-shared", ] @@ -1137,7 +1243,7 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ - "quote", + "quote 1.0.32", "wasm-bindgen-macro-support", ] @@ -1147,8 +1253,8 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -1180,8 +1286,8 @@ version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecb993dd8c836930ed130e020e77d9b2e65dd0fbab1b67c790b0f5d80b11a575" dependencies = [ - "proc-macro2", - "quote", + "proc-macro2 1.0.66", + "quote 1.0.32", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a7d03a6ab..3b3af48cf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ optional = true [dev-dependencies] rand = "0.8.5" rand_chacha = "0.3.1" +lfsr = "0.3.0" [lib] name = "clvm_tools_rs" diff --git a/src/compiler/compiler.rs b/src/compiler/compiler.rs index bc5cde0cd..e02c2f5cd 100644 --- a/src/compiler/compiler.rs +++ b/src/compiler/compiler.rs @@ -127,14 +127,11 @@ pub fn desugar_pre_forms( do_desugar(&p1) } -pub fn compile_pre_forms( +pub fn compile_from_compileform( context: &mut BasicCompileContext, opts: Rc, - pre_forms: &[Rc], + p2: CompileForm, ) -> Result { - // Resolve includes, convert program source to lexemes - let p2 = desugar_pre_forms(context, opts.clone(), pre_forms)?; - let p3 = context.post_desugar_optimization(opts.clone(), p2)?; // generate code from AST, optionally with optimization @@ -145,6 +142,17 @@ pub fn compile_pre_forms( Ok(g2) } +pub fn compile_pre_forms( + context: &mut BasicCompileContext, + opts: Rc, + pre_forms: &[Rc], +) -> Result { + // Resolve includes, convert program source to lexemes + let p2 = desugar_pre_forms(context, opts.clone(), pre_forms)?; + + compile_from_compileform(context, opts, p2) +} + pub fn compile_file( allocator: &mut Allocator, runner: Rc, diff --git a/src/tests/compiler/clvm.rs b/src/tests/compiler/clvm.rs index 1354c27c9..e7542ad57 100644 --- a/src/tests/compiler/clvm.rs +++ b/src/tests/compiler/clvm.rs @@ -25,7 +25,7 @@ use crate::tests::classic::run::RandomClvmNumber; use crate::util::Number; -const TEST_TIMEOUT: usize = 1000000; +pub const TEST_TIMEOUT: usize = 1000000; fn test_compiler_clvm(to_run: &String, args: &String) -> Result, RunFailure> { let mut allocator = Allocator::new(); diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs index d000b92ea..7596d761b 100644 --- a/src/tests/compiler/optimizer/cse.rs +++ b/src/tests/compiler/optimizer/cse.rs @@ -1,15 +1,30 @@ +use num_bigint::ToBigInt; +use rand::prelude::*; +use regex::Regex; + +use std::borrow::Borrow; +use std::collections::{BTreeSet, BTreeMap, HashMap}; use std::rc::Rc; -use regex::Regex; +use clvmr::allocator::Allocator; -use crate::compiler::compiler::DefaultCompilerOpts; -use crate::compiler::comptypes::CompilerOpts; +use crate::classic::clvm::__type_compatibility__::bi_one; +use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; + +use crate::compiler::CompileContextWrapper; +use crate::compiler::clvm::run; +use crate::compiler::compiler::{compile_from_compileform, DefaultCompilerOpts}; +use crate::compiler::comptypes::{BodyForm, CompileForm, CompilerOpts, DefunData, HelperForm}; +use crate::compiler::dialect::AcceptedDialect; use crate::compiler::frontend::compile_bodyform; +use crate::compiler::optimize::get_optimizer; use crate::compiler::optimize::cse::cse_optimize_bodyform; -use crate::compiler::sexp::parse_sexp; +use crate::compiler::sexp::{enlist, parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; use crate::tests::classic::run::{do_basic_brun, do_basic_run}; +use crate::tests::compiler::clvm::TEST_TIMEOUT; +use crate::tests::util::RngLFSR; #[test] fn smoke_test_cse_optimization() { @@ -27,7 +42,6 @@ fn smoke_test_cse_optimization() { let cse_transformed = cse_optimize_bodyform(&srcloc, b"test", &bodyform).expect("should cse optimize"); let re_def = r"(let ((cse_[$]_[0-9]+ ([*] ([+] 1 Q) R))) (a (i Q (com (G (- Q 1) cse_[$]_[0-9]+)) (com cse_[$]_[0-9]+)) 1))".replace("(", r"\(").replace(")",r"\)"); - eprintln!("re_def {re_def}"); let re = Regex::new(&re_def).expect("should become a regex"); assert!(re.is_match(&cse_transformed.to_sexp().to_string())); } @@ -190,3 +204,650 @@ fn test_atomsort_bad_ref() { assert_eq!(run_result_three_items, "(0x100003 0x100002 0x100001)"); } + +// Produce trees of CSE eligible forms and challenge the CSE optimizer. +// +// Things that might trip up CSE: +// +// A cse occurrence is in a lambda +// A cse occurrence is in an assign or let binding +// A cse occurrence is in an assign or let body +// A cse occurrence is in an if condition +// A cse occurrence is in a conditional branch of an if +// A cse occurrence dominates another +// apply is weird + +// Generate expressions of the form +// +// Imagining a random tree structure, we'll generate a program that retrieves +// a few particular values in the tree based on the presence or absence of other +// values. +// +// If we evaluate it in the wrong order, it'll fail, because we'll ensure that +// earlier checks gate later checks at runtime. +// +// Imagine +// +// 50 +// 25 75 +// 12 37 62 87 +// 6 18 31 43 56 68 81 93 +// +// Each tree node is (v l . r) +// +// So we can write a function like: +// +// (if (select-tree tree "") +// (if (select-tree tree "l") +// (if (all (select-tree tree "ll") (select-tree "llr") (select-tree tree "r") (select-tree tree "rl")) +// (select-tree tree "llrl") +// (select-tree tree "ll") +// ) +// ... +// +// Choose a few nodes from the tree along with nodes to return when those nodes are +// present. +// +// ((37 . 18) (75 . 56) (87 . 18) (56 . 68)) +// +// We choose points along the paths to each node to insert checks +// +// paths: +// +// -- checks +// (50 25 37 31 . 50) +// (50 25 37 . 18) +// (50 75 . 56) +// (50 75 62 56 . 68) +// (50 75 87 . 18) +// -- returns +// (50) +// (50 25 12 18) +// (50 75 62 56) +// (50 75 62 68) +// -- set +// (12 18 25 37 50 56 62 68 75 87) +// -- choose gates (not leaves) +// ((12) 18 25 37 50 56 62 68 (75) 87) +// +// Then organize them by their relationships to the gates +// +// ((12 18) (75 56 62 68 87) 25 37 50) +// +// Find out which rows are gated by which gates: +// +// Must be sorted by dominance +// (50 25 37 31 . 50) -- not gated +// (50 25 37 . 18) -- gated by 12 +// (50 75 62 56 . 68) -- gated by 75 +// (50 75 87 . 18) -- gated by 12 and 75 +// (50 75 . 56) -- gated by 75 +// +// First write out a skeleton that mirrors these choices: +// (if +// (all +// ;; path to check +// (select-tree tree "") (select-tree tree "l") (select-tree tree "lr") (select-tree tree "lrl") +// ;; path to target (if not subsumed) +// ;; checks here if needed. +// ) +// +// (select-tree tree "") +// +// Next paths (gated by 12) +// (if +// (all (select-tree tree "") (select-tree tree "l") (select-tree tree "ll")) +// ;; Expressions gated by 12 +// (if (all (select-tree tree "") (select-tree tree "l") (select-tree tree "lr") (select-tree tree "lllr")) +// (select-tree tree "lllr") +// ;; also gated by 75 +// (if (all (select-tree tree "") (select-tree tree "r")) +// (if (all (select-tree tree "") (select-tree tree "r") (select-tree tree "rl") (select-tree tree "rll") (select-tree tree "rlr")) +// (select-tree tree "rlr") +// ;; Others downstream (50 75 . 56) is after gated by 12 and 75 +// (if (all (select-tree tree "") (select-tree tree "r") (select-tree tree "rl") (select-tree tree "rll")) +// (select-tree tree "rll") +// ... + +struct GenerateTrickyCSE { + pub numbers: BTreeSet, + pub tree: TreeNode, + pub choices: Vec, +} + +#[derive(Default, Clone, Debug)] +struct TreeNode { + pub number: u16, + pub left: Option>, + pub right: Option>, +} + +fn generate_option(srcloc: Srcloc, opt: Option<&Rc>, filter: &F) -> SExp +where + F: Fn(&TreeNode) -> bool +{ + if let Some(r) = opt { + if filter(r) { + return r.generate(srcloc, filter); + } + } + + SExp::Nil(srcloc) +} + +impl TreeNode { + fn generate(&self, srcloc: Srcloc, filter: &F) -> SExp + where + F: Fn(&TreeNode) -> bool + { + let n = SExp::Integer(srcloc.clone(), self.number.to_bigint().unwrap()); + if self.left.is_none() && self.right.is_none() { + n + } else { + let a = generate_option(srcloc.clone(), self.left.as_ref(), filter); + let b = generate_option(srcloc.clone(), self.right.as_ref(), filter); + enlist(srcloc, &[Rc::new(a), Rc::new(b), Rc::new(n)]) + } + } +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] +enum Direction { + L, + R, +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] +struct TreeChoice { + pub path: Vec, +} + +impl TreeChoice { + pub fn prerequisites(&self) -> BTreeSet { + self.path.iter().enumerate().map(|(i,_)| { + TreeChoice { path: self.path.iter().take(i).cloned().collect() } + }).collect() + } + + pub fn contains(&self, other: &TreeChoice) -> bool { + self.prerequisites().contains(other) + } + + pub fn condition(&self) -> Rc { + let srcloc = Srcloc::start("*tree-choice-condition*"); + let mut condition = Rc::new(BodyForm::Value(SExp::Atom(srcloc.clone(), b"arg".to_vec()))); + for p in self.path.iter() { + let op = match p { + Direction::L => b"f", + Direction::R => b"r", + }; + condition = Rc::new(BodyForm::Call( + srcloc.clone(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(srcloc.clone(), op.to_vec()))), + condition + ], + None, + )); + } + condition + } + + pub fn conditions(&self, myself: bool, prev: Option>) -> Vec> { + let mut condition_vec = + prev.map(|b| vec![b.clone()]).unwrap_or_else(|| vec![]); + let mut prerequisite_conditions = self.prerequisites().iter().map(|p| p.condition()).collect(); + condition_vec.append(&mut prerequisite_conditions); + if myself { + condition_vec.push(self.condition()); + } + condition_vec + } +} + +fn all_conditions(c: &[Rc]) -> Rc { + if c.is_empty() { + return Rc::new(BodyForm::Quoted(SExp::Integer(Srcloc::start("*all-conditions-empty*"), bi_one()))); + } + let mut copy_vec = c.to_vec(); + copy_vec.insert(0, Rc::new(BodyForm::Value(SExp::Atom(c[0].loc(), b"all".to_vec())))); + Rc::new(BodyForm::Call( + c[0].loc(), + copy_vec, + None, + )) +} + +fn if_expr(cond: Rc, then_clause: Rc, else_clause: Rc) -> Rc { + Rc::new(BodyForm::Call( + cond.loc(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(cond.loc(), b"a".to_vec()))), + Rc::new(BodyForm::Call( + cond.loc(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(cond.loc(), b"i".to_vec()))), + cond.clone(), + Rc::new(BodyForm::Call( + cond.loc(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(cond.loc(), b"com".to_vec()))), + then_clause, + ], + None, + )), + Rc::new(BodyForm::Call( + cond.loc(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(cond.loc(), b"com".to_vec()))), + else_clause, + ], + None, + )), + ], + None, + )), + Rc::new(BodyForm::Value(SExp::Atom(cond.loc(), b"@".to_vec()))), + ], + None, + )) +} + +#[test] +fn test_tree_choice_conditions() { + let tree = TreeChoice { path: vec![Direction::L, Direction::L, Direction::R] }; + let conditions_of = all_conditions(&tree.conditions(false, None)); + assert_eq!(conditions_of.to_sexp().to_string(), "(all arg (f arg) (f (f arg)))"); +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] +struct CheckAndRetrieve { + pub gate: Option, + pub retrieve: TreeChoice, + pub checks: Vec, +} + +impl CheckAndRetrieve { + // generate an if of the native checks and the check of the retrievable + // itself for this object, otherwise doing the else clause. + pub fn generate_body_if(&self, else_clause: Rc) -> Rc { + let check_conditions: Vec> = + self.checks.iter().map(|c| { + all_conditions(&c.conditions(true, None)) + }).collect(); + let retrieve_condition = all_conditions(&self.retrieve.conditions(false, Some(all_conditions(&check_conditions)))); + let what_to_do = self.retrieve.condition(); + + if_expr(retrieve_condition, what_to_do, else_clause) + } +} + +#[test] +fn test_check_and_retrieve_1() { + let car = CheckAndRetrieve { + gate: None, + retrieve: TreeChoice { path: vec![Direction::L, Direction::R] }, + checks: vec![] + }; + let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); + assert_eq!(car.generate_body_if(else_clause).to_sexp().to_string(), "(if (all (q . 1) arg (f arg) (r (f arg))) (r (f arg)) ())"); +} + +#[test] +fn test_check_and_retrieve_2() { + let car = CheckAndRetrieve { + gate: None, + retrieve: TreeChoice { path: vec![Direction::L, Direction::R] }, + checks: vec![TreeChoice { path: vec![Direction::R] }] + }; + let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); + assert_eq!(car.generate_body_if(else_clause).to_sexp().to_string(), "(if (all (all (all arg (r arg))) arg (f arg) (r (f arg))) (r (f arg)) ())"); +} + +fn create_number_tree(tree: &mut TreeNode, numbers: &[u16]) { + assert!(!numbers.is_empty()); + let len = numbers.len(); + if len == 1 { + tree.number = numbers[0]; + return; + } + + let mid = len / 2; + tree.number = numbers[mid]; + if mid > 0 { + let left_slice = &numbers[0..mid]; + let mut left_node = TreeNode::default(); + create_number_tree(&mut left_node, left_slice); + tree.left = Some(Rc::new(left_node)); + } + if len > mid+1 { + let right_slice = &numbers[mid+1..len]; + let mut right_node = TreeNode::default(); + create_number_tree(&mut right_node, right_slice); + tree.right = Some(Rc::new(right_node)); + } +} + +fn choose_in_tree(tree: &TreeNode, number: u16) -> TreeChoice { + let mut path: Vec = Vec::new(); + let mut tn: &TreeNode = tree; + while tn.number != number { + if number < tn.number { + path.push(Direction::L); + if let Some(t) = tn.left.as_ref().borrow() { + tn = t; + } else { + panic!("should have existed"); + } + } else { + path.push(Direction::R); + if let Some(t) = tn.right.as_ref().borrow() { + tn = t; + } else { + panic!("should have existed"); + } + } + } + TreeChoice { path } +} + +#[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Debug)] +struct IfWithGate { + gate: TreeChoice, + in_gate: BTreeSet, + otherwise_reachable: BTreeSet, +} + +impl IfWithGate { + fn generate(&self) -> Rc { + let srcloc = Srcloc::start("*if-with-gate*"); + let gate_conditions = all_conditions(&self.gate.conditions(false, None)); + let mut maybe_also_these = Rc::new(BodyForm::Quoted(SExp::Nil(srcloc.clone()))); + for reachable in self.otherwise_reachable.iter().rev() { + maybe_also_these = reachable.generate_body_if(maybe_also_these); + } + + let mut gated = maybe_also_these.clone(); + for new_gated in self.in_gate.iter().rev() { + gated = new_gated.generate_body_if(gated); + } + + if_expr( + gate_conditions, + gated, + maybe_also_these, + ) + } +} + +#[test] +fn test_if_with_gate_generate_0() { + let mut in_gate_set = BTreeSet::new(); + in_gate_set.insert(CheckAndRetrieve { + gate: Some(TreeChoice { path: vec![Direction::R, Direction::L, Direction::R, Direction::L] }), + retrieve: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R, Direction::R, Direction::L, Direction::L] }, + checks: vec![], + }); + let mut otherwise_set = BTreeSet::new(); + otherwise_set.insert(CheckAndRetrieve { + gate: None, + retrieve: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R, Direction::R, Direction::L, Direction::R] }, + checks: vec![], + }); + let iwg = IfWithGate { + gate: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R] }, + in_gate: in_gate_set, + otherwise_reachable: otherwise_set, + }; + assert_eq!(iwg.generate().to_sexp().to_string(), "(if (all arg (r arg) (r (r arg))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (f (f (r (r (r (r arg)))))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (r (f (r (r (r (r arg)))))) (q))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (r (f (r (r (r (r arg)))))) (q)))"); +} + +impl GenerateTrickyCSE { + fn new(rng: &mut R) -> Self { + // Generate number tree. + let number_of_numbers = 5 + rng.gen::() % 11; + let numbers_set: BTreeSet = (0..number_of_numbers).map(|_| rng.gen()).collect(); + let numbers: Vec = numbers_set.iter().copied().collect(); + let mut number_tree = TreeNode::default(); + create_number_tree(&mut number_tree, &numbers); + + // Now we have a number tree. Choose some random values and find their + // paths in the tree. + let num_choices = 3 + (rng.gen::() % 7); + let mut choices: Vec = (0..num_choices) + .map(|_| { + let retrieve = choose_in_tree( + &number_tree, + numbers[rng.gen::() % number_of_numbers], + ); + let gate = + if rng.gen() { + Some(choose_in_tree( + &number_tree, + numbers[rng.gen::() % number_of_numbers], + )) + } else { + None + }; + let num_checks = rng.gen::() % 3; + let checks: Vec = (0..num_checks).map(|_| { + choose_in_tree( + &number_tree, + numbers[rng.gen::() % number_of_numbers], + ) + }).collect(); + CheckAndRetrieve { + gate, + retrieve, + checks, + } + }) + .collect(); + + // Actually, we can just sort the choices since ones that dominate will + // come before ones that are dominated (longer path with same prefix). + choices.sort(); + + eprintln!("choices {choices:?}"); + GenerateTrickyCSE { choices, tree: number_tree.clone(), numbers: numbers_set } + } + + fn generate_expr(&self) -> Rc { + let srcloc = Srcloc::start("*tree-generate*"); + + // Generate if statements for each tier of gate + let mut choice_by_gate: BTreeMap = BTreeMap::new(); + + // Make a list of distinct gates and the directly gated choices. + for choice in self.choices.iter() { + if let Some(choice_gate) = choice.gate.as_ref() { + if let Some(gated_by_choice) = choice_by_gate.get_mut(choice_gate) { + gated_by_choice.in_gate.insert(choice.clone()); + } else { + let mut in_gate = BTreeSet::new(); + in_gate.insert(choice.clone()); + choice_by_gate.insert(choice_gate.clone(), IfWithGate { + gate: choice_gate.clone(), + in_gate, + otherwise_reachable: BTreeSet::default(), + }); + } + } + } + + // For each gate, filter all the remaining checks into in_gate or + // otherwise_reachable. + for (gate, ifwith) in choice_by_gate.iter_mut() { + let (in_gate, otherwise_reachable) = self.choices.iter().cloned().partition::, _>(|choice| { + choice.gate.as_ref().map(|g| gate.contains(g)) + .unwrap_or(false) + }); + for g in in_gate.iter() { + ifwith.in_gate.insert(g.clone()); + } + for g in otherwise_reachable.iter() { + ifwith.otherwise_reachable.insert(g.clone()); + } + } + + // Generate the full expression. + let mut final_value = Rc::new(BodyForm::Quoted(SExp::Nil(srcloc.clone()))); + for (gate, ifwith) in choice_by_gate.iter().rev() { + let this_gate = ifwith.generate(); + let gate_conditions = all_conditions(&gate.conditions(true, None)); + final_value = if_expr( + gate_conditions, + this_gate, + final_value, + ); + } + + final_value + } + + fn generate_helper(&self) -> HelperForm { + let srcloc = Srcloc::start("*helper*"); + let args = Rc::new(SExp::Cons( + srcloc.clone(), + Rc::new(SExp::Atom(srcloc.clone(), b"arg".to_vec())), + Rc::new(SExp::Nil(srcloc.clone())) + )); + HelperForm::Defun(false, Box::new(DefunData { + nl: srcloc.clone(), + loc: srcloc.clone(), + name: b"tricky-cse".to_vec(), + args: args.clone(), + orig_args: args.clone(), + body: self.generate_expr(), + kw: None, + synthetic: None, + })) + } + + fn generate_program(&self) -> CompileForm { + let helper = self.generate_helper(); + let args = Rc::new(SExp::Atom(helper.loc(), b"arg".to_vec())); + CompileForm { + loc: helper.loc(), + include_forms: vec![], + args, + exp: Rc::new(BodyForm::Call( + helper.loc(), + vec![ + Rc::new(BodyForm::Value(SExp::Atom(helper.loc(), helper.name().to_vec()))), + Rc::new(BodyForm::Value(SExp::Atom(helper.loc(), b"arg".to_vec()))), + ], + None, + )), + helpers: vec![helper], + } + } +} + +fn test_generated_cse(n: u32) { + eprintln!("=== SEED {n} ==="); + let mut rng = RngLFSR::new(n); + let tcse = GenerateTrickyCSE::new(&mut rng); + let generated = tcse.generate_program(); + eprintln!("{}", generated.to_sexp()); + let runner = Rc::new(DefaultProgramRunner::new()); + let opts: Rc = Rc::new(DefaultCompilerOpts::new("*tricky-cse*")); + let opts21 = opts.set_dialect(AcceptedDialect { + stepping: Some(21), + strict: true, + }); + let opts23 = opts.set_dialect(AcceptedDialect { + stepping: Some(23), + strict: true, + }).set_optimize(true); + let mut allocator = Allocator::new(); + let mut symbols = HashMap::new(); + let compiled21; + let compiled23; + + // Get strict cl21 compile + { + let mut wrapper21 = CompileContextWrapper::new( + &mut allocator, + runner.clone(), + &mut symbols, + get_optimizer(&generated.loc(), opts21.clone()).expect("should be ok dialect"), + ); + eprintln!("21 compile"); + compiled21 = Rc::new(compile_from_compileform( + &mut wrapper21.context, + opts21, + generated.clone(), + ).expect("compiled")) + } + + // Get cl23 compile + { + let mut wrapper23 = CompileContextWrapper::new( + &mut allocator, + runner.clone(), + &mut symbols, + get_optimizer(&generated.loc(), opts23.clone()).expect("should be ok dialect"), + ); + eprintln!("23 compile"); + compiled23 = Rc::new(compile_from_compileform( + &mut wrapper23.context, + opts23, + generated.clone(), + ).expect("compiled")) + } + + eprintln!("generate tree numbers"); + let check_numbers: BTreeSet = tcse.numbers.iter().filter(|_| { + let check: u8 = rng.gen(); + check & 15 >= 1 + }).copied().collect(); + eprintln!("generate tree"); + let tree = Rc::new(tcse.tree.generate(generated.loc(), &move |tn| { + check_numbers.contains(&tn.number) + })); + + eprintln!("compiled21 {compiled21}"); + eprintln!("compiled23 {compiled23}"); + eprintln!("tree {tree}"); + + let mut allocator = Allocator::new(); + let clvm21 = run( + &mut allocator, + runner.clone(), + opts.prim_map(), + compiled21.clone(), + tree.clone(), + None, + Some(TEST_TIMEOUT), + ); + let clvm23 = run( + &mut allocator, + runner, + opts.prim_map(), + compiled23.clone(), + tree.clone(), + None, + Some(TEST_TIMEOUT), + ); + if let Ok(res21) = clvm21.as_ref() { + eprintln!("cl21 {res21}"); + } + if let Ok(res23) = clvm23.as_ref() { + eprintln!("cl23 {res23}"); + } + if clvm21.is_err() || clvm23.is_err() { + // Precise errors might change due to differences in ordering and + // locations and such. + assert_eq!(clvm21.is_err(), clvm23.is_err()); + return; + } + assert_eq!(clvm21, clvm23); +} + +#[test] +fn test_generate_tricky_cse() { + for i in 0..16 { + test_generated_cse(10000 + i); + } +} diff --git a/src/tests/util.rs b/src/tests/util.rs index 5585a2ba0..b0bec8303 100644 --- a/src/tests/util.rs +++ b/src/tests/util.rs @@ -1,5 +1,8 @@ -use crate::util::toposort; use std::collections::HashSet; +use rand::prelude::*; +use rand::Error; + +use crate::util::toposort; #[derive(Debug, Clone)] struct TopoSortCheckItem { @@ -94,3 +97,53 @@ fn test_topo_sort_1() { assert!(result.is_err()); } + +// A simple pseudo RNG based on an lfsr. Good enough to generate interesting +// deterministic patterns. +pub struct RngLFSR { + generator: u32 +} + +impl RngLFSR { + pub fn new(state: u32) -> Self { RngLFSR { generator: state } } + fn next(&mut self) -> u32 { + self.generator = lfsr::galois::Galois16::up(self.generator); + self.generator + } +} + +impl RngCore for RngLFSR { + fn next_u32(&mut self) -> u32 { + let a = self.next(); + let b = self.next(); + (a << 16) | b + } + + fn next_u64(&mut self) -> u64 { + let a = self.next_u32() as u64; + let b = self.next_u32() as u64; + (a << 32) | b + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + if dest.is_empty() { + return; + } + + for i in 0..(dest.len() / 2) { + let a = self.next(); + dest[i * 2] = (a & 0xff) as u8; + dest[i * 2 + 1] = ((a >> 8) & 0xff) as u8; + } + + if (dest.len() & 1) != 0 { + let a = self.next(); + dest[dest.len() - 1] = (a & 0xff) as u8; + } + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> { + self.fill_bytes(dest); + Ok(()) + } +} From 10e043a26e406e4ea65a37f05ea8fc4694112cde Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Oct 2023 11:08:17 -0700 Subject: [PATCH 24/48] fmt + clippy --- src/tests/compiler/optimizer/cse.rs | 280 +++++++++++++++++----------- src/tests/util.rs | 8 +- 2 files changed, 181 insertions(+), 107 deletions(-) diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs index 7596d761b..2cc593fcd 100644 --- a/src/tests/compiler/optimizer/cse.rs +++ b/src/tests/compiler/optimizer/cse.rs @@ -3,7 +3,7 @@ use rand::prelude::*; use regex::Regex; use std::borrow::Borrow; -use std::collections::{BTreeSet, BTreeMap, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::rc::Rc; use clvmr::allocator::Allocator; @@ -11,16 +11,16 @@ use clvmr::allocator::Allocator; use crate::classic::clvm::__type_compatibility__::bi_one; use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner; -use crate::compiler::CompileContextWrapper; use crate::compiler::clvm::run; use crate::compiler::compiler::{compile_from_compileform, DefaultCompilerOpts}; use crate::compiler::comptypes::{BodyForm, CompileForm, CompilerOpts, DefunData, HelperForm}; use crate::compiler::dialect::AcceptedDialect; use crate::compiler::frontend::compile_bodyform; -use crate::compiler::optimize::get_optimizer; use crate::compiler::optimize::cse::cse_optimize_bodyform; +use crate::compiler::optimize::get_optimizer; use crate::compiler::sexp::{enlist, parse_sexp, SExp}; use crate::compiler::srcloc::Srcloc; +use crate::compiler::CompileContextWrapper; use crate::tests::classic::run::{do_basic_brun, do_basic_run}; use crate::tests::compiler::clvm::TEST_TIMEOUT; @@ -324,7 +324,7 @@ struct TreeNode { fn generate_option(srcloc: Srcloc, opt: Option<&Rc>, filter: &F) -> SExp where - F: Fn(&TreeNode) -> bool + F: Fn(&TreeNode) -> bool, { if let Some(r) = opt { if filter(r) { @@ -338,7 +338,7 @@ where impl TreeNode { fn generate(&self, srcloc: Srcloc, filter: &F) -> SExp where - F: Fn(&TreeNode) -> bool + F: Fn(&TreeNode) -> bool, { let n = SExp::Integer(srcloc.clone(), self.number.to_bigint().unwrap()); if self.left.is_none() && self.right.is_none() { @@ -364,9 +364,13 @@ struct TreeChoice { impl TreeChoice { pub fn prerequisites(&self) -> BTreeSet { - self.path.iter().enumerate().map(|(i,_)| { - TreeChoice { path: self.path.iter().take(i).cloned().collect() } - }).collect() + self.path + .iter() + .enumerate() + .map(|(i, _)| TreeChoice { + path: self.path.iter().take(i).cloned().collect(), + }) + .collect() } pub fn contains(&self, other: &TreeChoice) -> bool { @@ -385,7 +389,7 @@ impl TreeChoice { srcloc.clone(), vec![ Rc::new(BodyForm::Value(SExp::Atom(srcloc.clone(), op.to_vec()))), - condition + condition, ], None, )); @@ -394,9 +398,9 @@ impl TreeChoice { } pub fn conditions(&self, myself: bool, prev: Option>) -> Vec> { - let mut condition_vec = - prev.map(|b| vec![b.clone()]).unwrap_or_else(|| vec![]); - let mut prerequisite_conditions = self.prerequisites().iter().map(|p| p.condition()).collect(); + let mut condition_vec = prev.map(|b| vec![b.clone()]).unwrap_or_else(|| vec![]); + let mut prerequisite_conditions = + self.prerequisites().iter().map(|p| p.condition()).collect(); condition_vec.append(&mut prerequisite_conditions); if myself { condition_vec.push(self.condition()); @@ -407,18 +411,24 @@ impl TreeChoice { fn all_conditions(c: &[Rc]) -> Rc { if c.is_empty() { - return Rc::new(BodyForm::Quoted(SExp::Integer(Srcloc::start("*all-conditions-empty*"), bi_one()))); + return Rc::new(BodyForm::Quoted(SExp::Integer( + Srcloc::start("*all-conditions-empty*"), + bi_one(), + ))); } let mut copy_vec = c.to_vec(); - copy_vec.insert(0, Rc::new(BodyForm::Value(SExp::Atom(c[0].loc(), b"all".to_vec())))); - Rc::new(BodyForm::Call( - c[0].loc(), - copy_vec, - None, - )) + copy_vec.insert( + 0, + Rc::new(BodyForm::Value(SExp::Atom(c[0].loc(), b"all".to_vec()))), + ); + Rc::new(BodyForm::Call(c[0].loc(), copy_vec, None)) } -fn if_expr(cond: Rc, then_clause: Rc, else_clause: Rc) -> Rc { +fn if_expr( + cond: Rc, + then_clause: Rc, + else_clause: Rc, +) -> Rc { Rc::new(BodyForm::Call( cond.loc(), vec![ @@ -455,9 +465,14 @@ fn if_expr(cond: Rc, then_clause: Rc, else_clause: Rc) -> Rc { - let check_conditions: Vec> = - self.checks.iter().map(|c| { - all_conditions(&c.conditions(true, None)) - }).collect(); - let retrieve_condition = all_conditions(&self.retrieve.conditions(false, Some(all_conditions(&check_conditions)))); + let check_conditions: Vec> = self + .checks + .iter() + .map(|c| all_conditions(&c.conditions(true, None))) + .collect(); + let retrieve_condition = all_conditions( + &self + .retrieve + .conditions(false, Some(all_conditions(&check_conditions))), + ); let what_to_do = self.retrieve.condition(); if_expr(retrieve_condition, what_to_do, else_clause) @@ -486,22 +506,34 @@ impl CheckAndRetrieve { fn test_check_and_retrieve_1() { let car = CheckAndRetrieve { gate: None, - retrieve: TreeChoice { path: vec![Direction::L, Direction::R] }, - checks: vec![] + retrieve: TreeChoice { + path: vec![Direction::L, Direction::R], + }, + checks: vec![], }; let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); - assert_eq!(car.generate_body_if(else_clause).to_sexp().to_string(), "(if (all (q . 1) arg (f arg) (r (f arg))) (r (f arg)) ())"); + assert_eq!( + car.generate_body_if(else_clause).to_sexp().to_string(), + "(if (all (q . 1) arg (f arg) (r (f arg))) (r (f arg)) ())" + ); } #[test] fn test_check_and_retrieve_2() { let car = CheckAndRetrieve { gate: None, - retrieve: TreeChoice { path: vec![Direction::L, Direction::R] }, - checks: vec![TreeChoice { path: vec![Direction::R] }] + retrieve: TreeChoice { + path: vec![Direction::L, Direction::R], + }, + checks: vec![TreeChoice { + path: vec![Direction::R], + }], }; let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); - assert_eq!(car.generate_body_if(else_clause).to_sexp().to_string(), "(if (all (all (all arg (r arg))) arg (f arg) (r (f arg))) (r (f arg)) ())"); + assert_eq!( + car.generate_body_if(else_clause).to_sexp().to_string(), + "(if (all (all (all arg (r arg))) arg (f arg) (r (f arg))) (r (f arg)) ())" + ); } fn create_number_tree(tree: &mut TreeNode, numbers: &[u16]) { @@ -520,8 +552,8 @@ fn create_number_tree(tree: &mut TreeNode, numbers: &[u16]) { create_number_tree(&mut left_node, left_slice); tree.left = Some(Rc::new(left_node)); } - if len > mid+1 { - let right_slice = &numbers[mid+1..len]; + if len > mid + 1 { + let right_slice = &numbers[mid + 1..len]; let mut right_node = TreeNode::default(); create_number_tree(&mut right_node, right_slice); tree.right = Some(Rc::new(right_node)); @@ -572,11 +604,7 @@ impl IfWithGate { gated = new_gated.generate_body_if(gated); } - if_expr( - gate_conditions, - gated, - maybe_also_these, - ) + if_expr(gate_conditions, gated, maybe_also_these) } } @@ -584,18 +612,40 @@ impl IfWithGate { fn test_if_with_gate_generate_0() { let mut in_gate_set = BTreeSet::new(); in_gate_set.insert(CheckAndRetrieve { - gate: Some(TreeChoice { path: vec![Direction::R, Direction::L, Direction::R, Direction::L] }), - retrieve: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R, Direction::R, Direction::L, Direction::L] }, + gate: Some(TreeChoice { + path: vec![Direction::R, Direction::L, Direction::R, Direction::L], + }), + retrieve: TreeChoice { + path: vec![ + Direction::R, + Direction::R, + Direction::R, + Direction::R, + Direction::L, + Direction::L, + ], + }, checks: vec![], }); let mut otherwise_set = BTreeSet::new(); otherwise_set.insert(CheckAndRetrieve { gate: None, - retrieve: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R, Direction::R, Direction::L, Direction::R] }, + retrieve: TreeChoice { + path: vec![ + Direction::R, + Direction::R, + Direction::R, + Direction::R, + Direction::L, + Direction::R, + ], + }, checks: vec![], }); let iwg = IfWithGate { - gate: TreeChoice { path: vec![Direction::R, Direction::R, Direction::R] }, + gate: TreeChoice { + path: vec![Direction::R, Direction::R, Direction::R], + }, in_gate: in_gate_set, otherwise_reachable: otherwise_set, }; @@ -620,22 +670,23 @@ impl GenerateTrickyCSE { &number_tree, numbers[rng.gen::() % number_of_numbers], ); - let gate = - if rng.gen() { - Some(choose_in_tree( - &number_tree, - numbers[rng.gen::() % number_of_numbers], - )) - } else { - None - }; - let num_checks = rng.gen::() % 3; - let checks: Vec = (0..num_checks).map(|_| { - choose_in_tree( + let gate = if rng.gen() { + Some(choose_in_tree( &number_tree, numbers[rng.gen::() % number_of_numbers], - ) - }).collect(); + )) + } else { + None + }; + let num_checks = rng.gen::() % 3; + let checks: Vec = (0..num_checks) + .map(|_| { + choose_in_tree( + &number_tree, + numbers[rng.gen::() % number_of_numbers], + ) + }) + .collect(); CheckAndRetrieve { gate, retrieve, @@ -649,7 +700,11 @@ impl GenerateTrickyCSE { choices.sort(); eprintln!("choices {choices:?}"); - GenerateTrickyCSE { choices, tree: number_tree.clone(), numbers: numbers_set } + GenerateTrickyCSE { + choices, + tree: number_tree.clone(), + numbers: numbers_set, + } } fn generate_expr(&self) -> Rc { @@ -666,11 +721,14 @@ impl GenerateTrickyCSE { } else { let mut in_gate = BTreeSet::new(); in_gate.insert(choice.clone()); - choice_by_gate.insert(choice_gate.clone(), IfWithGate { - gate: choice_gate.clone(), - in_gate, - otherwise_reachable: BTreeSet::default(), - }); + choice_by_gate.insert( + choice_gate.clone(), + IfWithGate { + gate: choice_gate.clone(), + in_gate, + otherwise_reachable: BTreeSet::default(), + }, + ); } } } @@ -678,10 +736,17 @@ impl GenerateTrickyCSE { // For each gate, filter all the remaining checks into in_gate or // otherwise_reachable. for (gate, ifwith) in choice_by_gate.iter_mut() { - let (in_gate, otherwise_reachable) = self.choices.iter().cloned().partition::, _>(|choice| { - choice.gate.as_ref().map(|g| gate.contains(g)) - .unwrap_or(false) - }); + let (in_gate, otherwise_reachable) = self + .choices + .iter() + .cloned() + .partition::, _>(|choice| { + choice + .gate + .as_ref() + .map(|g| gate.contains(g)) + .unwrap_or(false) + }); for g in in_gate.iter() { ifwith.in_gate.insert(g.clone()); } @@ -695,11 +760,7 @@ impl GenerateTrickyCSE { for (gate, ifwith) in choice_by_gate.iter().rev() { let this_gate = ifwith.generate(); let gate_conditions = all_conditions(&gate.conditions(true, None)); - final_value = if_expr( - gate_conditions, - this_gate, - final_value, - ); + final_value = if_expr(gate_conditions, this_gate, final_value); } final_value @@ -710,18 +771,21 @@ impl GenerateTrickyCSE { let args = Rc::new(SExp::Cons( srcloc.clone(), Rc::new(SExp::Atom(srcloc.clone(), b"arg".to_vec())), - Rc::new(SExp::Nil(srcloc.clone())) + Rc::new(SExp::Nil(srcloc.clone())), )); - HelperForm::Defun(false, Box::new(DefunData { - nl: srcloc.clone(), - loc: srcloc.clone(), - name: b"tricky-cse".to_vec(), - args: args.clone(), - orig_args: args.clone(), - body: self.generate_expr(), - kw: None, - synthetic: None, - })) + HelperForm::Defun( + false, + Box::new(DefunData { + nl: srcloc.clone(), + loc: srcloc.clone(), + name: b"tricky-cse".to_vec(), + args: args.clone(), + orig_args: args.clone(), + body: self.generate_expr(), + kw: None, + synthetic: None, + }), + ) } fn generate_program(&self) -> CompileForm { @@ -734,7 +798,10 @@ impl GenerateTrickyCSE { exp: Rc::new(BodyForm::Call( helper.loc(), vec![ - Rc::new(BodyForm::Value(SExp::Atom(helper.loc(), helper.name().to_vec()))), + Rc::new(BodyForm::Value(SExp::Atom( + helper.loc(), + helper.name().to_vec(), + ))), Rc::new(BodyForm::Value(SExp::Atom(helper.loc(), b"arg".to_vec()))), ], None, @@ -756,10 +823,12 @@ fn test_generated_cse(n: u32) { stepping: Some(21), strict: true, }); - let opts23 = opts.set_dialect(AcceptedDialect { - stepping: Some(23), - strict: true, - }).set_optimize(true); + let opts23 = opts + .set_dialect(AcceptedDialect { + stepping: Some(23), + strict: true, + }) + .set_optimize(true); let mut allocator = Allocator::new(); let mut symbols = HashMap::new(); let compiled21; @@ -774,34 +843,37 @@ fn test_generated_cse(n: u32) { get_optimizer(&generated.loc(), opts21.clone()).expect("should be ok dialect"), ); eprintln!("21 compile"); - compiled21 = Rc::new(compile_from_compileform( - &mut wrapper21.context, - opts21, - generated.clone(), - ).expect("compiled")) + compiled21 = Rc::new( + compile_from_compileform(&mut wrapper21.context, opts21, generated.clone()) + .expect("compiled"), + ) } // Get cl23 compile { let mut wrapper23 = CompileContextWrapper::new( - &mut allocator, + &mut allocator, runner.clone(), &mut symbols, get_optimizer(&generated.loc(), opts23.clone()).expect("should be ok dialect"), ); eprintln!("23 compile"); - compiled23 = Rc::new(compile_from_compileform( - &mut wrapper23.context, - opts23, - generated.clone(), - ).expect("compiled")) + compiled23 = Rc::new( + compile_from_compileform(&mut wrapper23.context, opts23, generated.clone()) + .expect("compiled"), + ) } eprintln!("generate tree numbers"); - let check_numbers: BTreeSet = tcse.numbers.iter().filter(|_| { - let check: u8 = rng.gen(); - check & 15 >= 1 - }).copied().collect(); + let check_numbers: BTreeSet = tcse + .numbers + .iter() + .filter(|_| { + let check: u8 = rng.gen(); + check & 15 >= 1 + }) + .copied() + .collect(); eprintln!("generate tree"); let tree = Rc::new(tcse.tree.generate(generated.loc(), &move |tn| { check_numbers.contains(&tn.number) diff --git a/src/tests/util.rs b/src/tests/util.rs index b0bec8303..0f98ece39 100644 --- a/src/tests/util.rs +++ b/src/tests/util.rs @@ -1,6 +1,6 @@ -use std::collections::HashSet; use rand::prelude::*; use rand::Error; +use std::collections::HashSet; use crate::util::toposort; @@ -101,11 +101,13 @@ fn test_topo_sort_1() { // A simple pseudo RNG based on an lfsr. Good enough to generate interesting // deterministic patterns. pub struct RngLFSR { - generator: u32 + generator: u32, } impl RngLFSR { - pub fn new(state: u32) -> Self { RngLFSR { generator: state } } + pub fn new(state: u32) -> Self { + RngLFSR { generator: state } + } fn next(&mut self) -> u32 { self.generator = lfsr::galois::Galois16::up(self.generator); self.generator From 9d70c525a94088a58de8b7651e22a12ec8bc812d Mon Sep 17 00:00:00 2001 From: arty Date: Tue, 31 Oct 2023 11:17:51 -0700 Subject: [PATCH 25/48] Fix up intermediate tests --- src/tests/compiler/optimizer/cse.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs index 2cc593fcd..b627a2a28 100644 --- a/src/tests/compiler/optimizer/cse.rs +++ b/src/tests/compiler/optimizer/cse.rs @@ -514,7 +514,7 @@ fn test_check_and_retrieve_1() { let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); assert_eq!( car.generate_body_if(else_clause).to_sexp().to_string(), - "(if (all (q . 1) arg (f arg) (r (f arg))) (r (f arg)) ())" + "(a (i (all (q . 1) arg (f arg)) (com (r (f arg))) (com ())) @)" ); } @@ -532,7 +532,7 @@ fn test_check_and_retrieve_2() { let else_clause = Rc::new(BodyForm::Value(SExp::Nil(Srcloc::start("*test*")))); assert_eq!( car.generate_body_if(else_clause).to_sexp().to_string(), - "(if (all (all (all arg (r arg))) arg (f arg) (r (f arg))) (r (f arg)) ())" + "(a (i (all (all (all arg (r arg))) arg (f arg)) (com (r (f arg))) (com ())) @)" ); } @@ -649,7 +649,7 @@ fn test_if_with_gate_generate_0() { in_gate: in_gate_set, otherwise_reachable: otherwise_set, }; - assert_eq!(iwg.generate().to_sexp().to_string(), "(if (all arg (r arg) (r (r arg))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (f (f (r (r (r (r arg)))))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (r (f (r (r (r (r arg)))))) (q))) (if (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (r (f (r (r (r (r arg)))))) (q)))"); + assert_eq!(iwg.generate().to_sexp().to_string(), "(a (i (all arg (r arg) (r (r arg))) (com (a (i (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (com (f (f (r (r (r (r arg))))))) (com (a (i (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (com (r (f (r (r (r (r arg))))))) (com (q))) @))) @)) (com (a (i (all (q . 1) arg (r arg) (r (r arg)) (r (r (r arg))) (r (r (r (r arg)))) (f (r (r (r (r arg)))))) (com (r (f (r (r (r (r arg))))))) (com (q))) @))) @)"); } impl GenerateTrickyCSE { From 85b34c0be8ebb8d1b320f3dd03e207721ba00367 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 10:39:28 -0700 Subject: [PATCH 26/48] Fix cse bug which allowed com forms to migrate to other scopes --- .../test_handcalc.clsp | 2 +- src/compiler/codegen.rs | 7 ++++ src/compiler/optimize/cse.rs | 7 +++- src/tests/compiler/optimizer/cse.rs | 38 +++++++++++++++++-- 4 files changed, 48 insertions(+), 6 deletions(-) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clsp b/resources/tests/game-referee-after-cl21/test_handcalc.clsp index 16c46f664..a9312e187 100644 --- a/resources/tests/game-referee-after-cl21/test_handcalc.clsp +++ b/resources/tests/game-referee-after-cl21/test_handcalc.clsp @@ -1,6 +1,6 @@ (mod () - (include *standard-cl-21*) + (include *standard-cl-23*) (include deep_compare.clinc) (include assert.clinc) (include reverse.clinc) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index fd9d9cb85..0e542c92d 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -713,6 +713,13 @@ pub fn generate_expr_code( l.clone(), Rc::new(SExp::Integer(l.clone(), bi_one())), )) + } else if atom.is_empty() { + generate_expr_code( + context, + opts, + compiler, + Rc::new(BodyForm::Value(SExp::Nil(v.loc()))) + ) } else { // This is as a variable access, given that we've got // a Value bodyform containing an Atom, so if a defun diff --git a/src/compiler/optimize/cse.rs b/src/compiler/optimize/cse.rs index bfa0e9d0b..b86c2b94b 100644 --- a/src/compiler/optimize/cse.rs +++ b/src/compiler/optimize/cse.rs @@ -114,7 +114,12 @@ pub fn cse_detect(fe: &BodyForm) -> Result, C } // Skip individual variable references. - if let BodyForm::Value(SExp::Atom(_, _)) = form { + if matches!(form, BodyForm::Value(SExp::Atom(_, _))) { + return Ok(None); + } + + // We can't take a com directly, but we can take parents or children. + if matches!(get_com_body(form), Some(_)) { return Ok(None); } diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs index b627a2a28..172810e83 100644 --- a/src/tests/compiler/optimizer/cse.rs +++ b/src/tests/compiler/optimizer/cse.rs @@ -130,8 +130,8 @@ fn test_atomsort_bad_ref_simplified() { "resources/tests/strict".to_string(), filename.to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); let run_result = do_basic_brun(&vec![ "brun".to_string(), @@ -139,8 +139,8 @@ fn test_atomsort_bad_ref_simplified() { program, "((99 101 103))".to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); // Expect test5 assert_eq!(run_result, "\"test5\""); @@ -205,6 +205,36 @@ fn test_atomsort_bad_ref() { assert_eq!(run_result_three_items, "(0x100003 0x100002 0x100001)"); } +#[test] +fn test_tricky_handcalc_example() { + let filename = "resources/tests/strict/cse_tricky_assign.clsp"; + + let program = do_basic_run(&vec![ + "run".to_string(), + "-i".to_string(), + "resources/tests/game-referee-after-cl21".to_string(), + "-i".to_string(), + "resources/tests/strict".to_string(), + filename.to_string(), + ]) + .trim() + .to_string(); + + eprintln!("{program}"); + assert!(!program.contains(":")); + + let run_result = do_basic_brun(&vec![ + "brun".to_string(), + "-n".to_string(), + program, + "((13 . 1) (12 . 1) (10 . 1) (6 . 2) (5 . 2))".to_string(), + ]) + .trim() + .to_string(); + + assert_eq!(run_result, "31"); +} + // Produce trees of CSE eligible forms and challenge the CSE optimizer. // // Things that might trip up CSE: From 09bcc825fafdca38de7b1b0e4d0af7000009238e Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 10:40:33 -0700 Subject: [PATCH 27/48] fmt + clippy --- src/compiler/codegen.rs | 2 +- src/compiler/optimize/cse.rs | 2 +- src/tests/compiler/optimizer/cse.rs | 16 ++++++++-------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/codegen.rs b/src/compiler/codegen.rs index 0e542c92d..abe7c99a4 100644 --- a/src/compiler/codegen.rs +++ b/src/compiler/codegen.rs @@ -718,7 +718,7 @@ pub fn generate_expr_code( context, opts, compiler, - Rc::new(BodyForm::Value(SExp::Nil(v.loc()))) + Rc::new(BodyForm::Value(SExp::Nil(v.loc()))), ) } else { // This is as a variable access, given that we've got diff --git a/src/compiler/optimize/cse.rs b/src/compiler/optimize/cse.rs index b86c2b94b..ca85a4c27 100644 --- a/src/compiler/optimize/cse.rs +++ b/src/compiler/optimize/cse.rs @@ -119,7 +119,7 @@ pub fn cse_detect(fe: &BodyForm) -> Result, C } // We can't take a com directly, but we can take parents or children. - if matches!(get_com_body(form), Some(_)) { + if get_com_body(form).is_some() { return Ok(None); } diff --git a/src/tests/compiler/optimizer/cse.rs b/src/tests/compiler/optimizer/cse.rs index 172810e83..bad0a812b 100644 --- a/src/tests/compiler/optimizer/cse.rs +++ b/src/tests/compiler/optimizer/cse.rs @@ -130,8 +130,8 @@ fn test_atomsort_bad_ref_simplified() { "resources/tests/strict".to_string(), filename.to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); let run_result = do_basic_brun(&vec![ "brun".to_string(), @@ -139,8 +139,8 @@ fn test_atomsort_bad_ref_simplified() { program, "((99 101 103))".to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); // Expect test5 assert_eq!(run_result, "\"test5\""); @@ -217,8 +217,8 @@ fn test_tricky_handcalc_example() { "resources/tests/strict".to_string(), filename.to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); eprintln!("{program}"); assert!(!program.contains(":")); @@ -229,8 +229,8 @@ fn test_tricky_handcalc_example() { program, "((13 . 1) (12 . 1) (10 . 1) (6 . 2) (5 . 2))".to_string(), ]) - .trim() - .to_string(); + .trim() + .to_string(); assert_eq!(run_result, "31"); } From 71c5cc0659af1e87161d69ec1686efca5f80a663 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 11:24:16 -0700 Subject: [PATCH 28/48] Add test files --- resources/tests/strict/append.clinc | 8 +++ resources/tests/strict/cse_tricky_assign.clsp | 57 +++++++++++++++++++ resources/tests/strict/partition.clinc | 15 +++++ resources/tests/strict/truncate.clinc | 8 +++ 4 files changed, 88 insertions(+) create mode 100644 resources/tests/strict/append.clinc create mode 100644 resources/tests/strict/cse_tricky_assign.clsp create mode 100644 resources/tests/strict/partition.clinc create mode 100644 resources/tests/strict/truncate.clinc diff --git a/resources/tests/strict/append.clinc b/resources/tests/strict/append.clinc new file mode 100644 index 000000000..885a90bb2 --- /dev/null +++ b/resources/tests/strict/append.clinc @@ -0,0 +1,8 @@ +( + (defun append (L R) + (if L + (c (f L) (append (r L) R)) + R + ) + ) +) \ No newline at end of file diff --git a/resources/tests/strict/cse_tricky_assign.clsp b/resources/tests/strict/cse_tricky_assign.clsp new file mode 100644 index 000000000..b77eb7a82 --- /dev/null +++ b/resources/tests/strict/cse_tricky_assign.clsp @@ -0,0 +1,57 @@ +(mod X + + (include *standard-cl-23*) + + (include truncate.clinc) + (include partition.clinc) + (include append.clinc) + + (defun find_hand_indices ((@ numbered-cards ((number . card) . rest))) + (if numbered-cards + (logior (lsh 1 number) (find_hand_indices rest)) + 0 + ) + ) + + (defun number_cards (num cards) + (if cards + (c (c num (f cards)) (number_cards (+ num 1) (r cards))) + () + ) + ) + + ;; Sorts the cards by group size according to hand. + ;; Hand has pairs of count and rank. We pull out cards based on their rank + ;; until each bucket is empty in hand and then give the remaining cards. + (defun bucket_cards_by_frequency_groups (hand cards) + (if hand + (assign + (hand_freq . want_rank) (f hand) + + (cards_with_rank . cards_without_rank) (partition (lambda ((& want_rank) (num . (rank . suit))) (= rank want_rank)) cards) + + ;; We have the cards with this rank... go to the next wanted rank. + (append cards_with_rank (bucket_cards_by_frequency_groups (r hand) cards_without_rank)) + ) + cards + ) + ) + + (defun handcalc (cards sorted_ranks hand firstcount firstrank secondcount secondrank flush_suit) + (if ;; Full house + (logand (= firstcount 3) (= secondcount 2)) + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + + ;; Flush + (if + flush_suit + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + + ;; Else + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + ) + ) + ) + + (handcalc (q (14 . 1) (12 . 1) (11 . 1) (10 . 1) (9 . 1)) (list 14 12 11 10 9) (q (14 . 1) (12 . 1) (11 . 1) (10 . 1) (9 . 1)) 1 14 1 12 1) +) diff --git a/resources/tests/strict/partition.clinc b/resources/tests/strict/partition.clinc new file mode 100644 index 000000000..8c8c268f6 --- /dev/null +++ b/resources/tests/strict/partition.clinc @@ -0,0 +1,15 @@ +( + (defun partition_inner (matched not-matched F L) + (if L + (if (a F (list (f L))) + (partition_inner (c (f L) matched) not-matched F (r L)) + (partition_inner matched (c (f L) not-matched) F (r L)) + ) + (c matched not-matched) + ) + ) + + (defun partition (F L) + (partition_inner () () F L) + ) +) diff --git a/resources/tests/strict/truncate.clinc b/resources/tests/strict/truncate.clinc new file mode 100644 index 000000000..e4557f31c --- /dev/null +++ b/resources/tests/strict/truncate.clinc @@ -0,0 +1,8 @@ +( +(defun truncate (N (@ L (LF . LR))) + (if (all N L) + (c LF (truncate (- N 1) LR)) + () + ) +) +) \ No newline at end of file From 7ae4413bd42649bc44edb8b4db6b48807523d7a9 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 13:12:08 -0700 Subject: [PATCH 29/48] My error: this was written at a time before strict was brought in. I'll add a current 23 exhaustive test as well --- resources/tests/game-referee-after-cl21/test_handcalc.clsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/tests/game-referee-after-cl21/test_handcalc.clsp b/resources/tests/game-referee-after-cl21/test_handcalc.clsp index a9312e187..16c46f664 100644 --- a/resources/tests/game-referee-after-cl21/test_handcalc.clsp +++ b/resources/tests/game-referee-after-cl21/test_handcalc.clsp @@ -1,6 +1,6 @@ (mod () - (include *standard-cl-23*) + (include *standard-cl-21*) (include deep_compare.clinc) (include assert.clinc) (include reverse.clinc) From 1c5eec888ecf6751ea9134d23e8430f70ea58475 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 14:51:42 -0700 Subject: [PATCH 30/48] Add cl23 tests --- .github/workflows/extensive-tests.yml | 1 + .../game-referee-in-cl23/all-in-list.clinc | 12 + .../tests/game-referee-in-cl23/append.clinc | 8 + .../tests/game-referee-in-cl23/assert.clinc | 10 + .../tests/game-referee-in-cl23/busy.clinc | 11 + .../calpoker_generate.clinc | 466 +++++++++++++++++ .../calpoker_include.clsp | 1 + .../condition_codes.clinc | 41 ++ .../curry-and-treehash.clinc | 92 ++++ .../tests/game-referee-in-cl23/curry.clinc | 104 ++++ .../game-referee-in-cl23/deep_compare.clinc | 41 ++ .../game-referee-in-cl23/deep_compare_t2.clsp | 6 + .../game-referee-in-cl23/detectwrap.clinc | 17 + .../game-referee-in-cl23/filtermap.clinc | 21 + .../tests/game-referee-in-cl23/flatten.clinc | 12 + .../game-referee-in-cl23/handbitmap.clinc | 66 +++ .../tests/game-referee-in-cl23/handcalc.clinc | 232 +++++++++ .../game-referee-in-cl23/handcalc2.clinc | 233 +++++++++ .../game-referee-in-cl23/krunk_generate.clinc | 404 +++++++++++++++ .../game-referee-in-cl23/krunk_include.clsp | 1 + .../krunk_make_clue.clinc | 58 +++ .../tests/game-referee-in-cl23/last.clinc | 44 ++ .../tests/game-referee-in-cl23/len.clinc | 3 + resources/tests/game-referee-in-cl23/main.sym | 1 + .../tests/game-referee-in-cl23/map.clinc | 17 + .../tests/game-referee-in-cl23/match.clinc | 12 + .../tests/game-referee-in-cl23/max.clinc | 13 + .../tests/game-referee-in-cl23/noncegame.clsp | 17 + .../game-referee-in-cl23/onehandcalc.clinc | 147 ++++++ .../game-referee-in-cl23/partition.clinc | 15 + .../game-referee-in-cl23/permutations.clinc | 21 + .../tests/game-referee-in-cl23/prefix.clinc | 15 + .../tests/game-referee-in-cl23/prepend.clinc | 8 + .../tests/game-referee-in-cl23/print.clinc | 3 + .../tests/game-referee-in-cl23/range.clinc | 11 + .../tests/game-referee-in-cl23/reduce.clinc | 10 + .../tests/game-referee-in-cl23/referee.clsp | 83 +++ .../tests/game-referee-in-cl23/relops.clinc | 5 + .../tests/game-referee-in-cl23/reverse.clinc | 11 + .../rockpaperscissorsa.clsp | 18 + .../rockpaperscissorsb.clsp | 20 + .../rockpaperscissorsc.clsp | 27 + .../tests/game-referee-in-cl23/shatree.clinc | 11 + .../tests/game-referee-in-cl23/slice.clinc | 10 + .../game-referee-in-cl23/slice_runner.clsp | 6 + .../smoke_test_deep_compare.clsp | 28 + .../smoke_test_deep_compare.clvm.hex | 1 + .../smoke_test_deep_compare.sym | 1 + .../smoke_test_permutations.clsp | 9 + .../smoke_test_permutations.clvm.hex | 1 + .../smoke_test_permutations.sym | 1 + .../game-referee-in-cl23/smoke_test_sort.clsp | 11 + .../smoke_test_sort.clvm.hex | 1 + .../game-referee-in-cl23/smoke_test_sort.sym | 1 + .../tests/game-referee-in-cl23/sort.clinc | 44 ++ .../game-referee-in-cl23/space_poker.clinc | 214 ++++++++ .../game-referee-in-cl23/spacehandcalc.clinc | 107 ++++ .../spacepoker_include.clsp | 1 + .../tests/game-referee-in-cl23/steprun.py | 55 ++ .../game-referee-in-cl23/test_detectwrap.clsp | 8 + .../game-referee-in-cl23/test_handbitmap.clsp | 13 + .../game-referee-in-cl23/test_handcalc.clsp | 444 ++++++++++++++++ .../test_library_basics.py | 130 +++++ .../test_onehandcalc.clsp | 37 ++ .../test_permutations.clsp | 63 +++ .../test_permutations.clvm.hex | 1 + .../test_permutations.sym | 1 + .../game-referee-in-cl23/test_prepend.clsp | 5 + .../test_prepend.clvm.hex | 1 + .../game-referee-in-cl23/test_prepend.sym | 1 + .../game-referee-in-cl23/test_range.clsp | 6 + .../game-referee-in-cl23/test_range.clvm.hex | 1 + .../tests/game-referee-in-cl23/test_range.sym | 1 + .../game-referee-in-cl23/test_reverse.clsp | 6 + .../test_reverse.clvm.hex | 1 + .../game-referee-in-cl23/test_reverse.sym | 1 + .../game-referee-in-cl23/test_slice.clsp | 14 + .../tests/game-referee-in-cl23/test_sort.clsp | 37 ++ .../game-referee-in-cl23/test_sort.clvm.hex | 1 + .../tests/game-referee-in-cl23/test_sort.sym | 1 + .../game-referee-in-cl23/testnoncegame.py | 33 ++ .../tests/game-referee-in-cl23/testreferee.py | 479 ++++++++++++++++++ .../testrockpaperscissors.py | 48 ++ .../tests/game-referee-in-cl23/truncate.clinc | 8 + .../tests/game-referee-in-cl23/utils.clinc | 2 + 85 files changed, 4183 insertions(+) create mode 100644 resources/tests/game-referee-in-cl23/all-in-list.clinc create mode 100644 resources/tests/game-referee-in-cl23/append.clinc create mode 100644 resources/tests/game-referee-in-cl23/assert.clinc create mode 100644 resources/tests/game-referee-in-cl23/busy.clinc create mode 100644 resources/tests/game-referee-in-cl23/calpoker_generate.clinc create mode 100644 resources/tests/game-referee-in-cl23/calpoker_include.clsp create mode 100644 resources/tests/game-referee-in-cl23/condition_codes.clinc create mode 100644 resources/tests/game-referee-in-cl23/curry-and-treehash.clinc create mode 100644 resources/tests/game-referee-in-cl23/curry.clinc create mode 100644 resources/tests/game-referee-in-cl23/deep_compare.clinc create mode 100644 resources/tests/game-referee-in-cl23/deep_compare_t2.clsp create mode 100644 resources/tests/game-referee-in-cl23/detectwrap.clinc create mode 100644 resources/tests/game-referee-in-cl23/filtermap.clinc create mode 100644 resources/tests/game-referee-in-cl23/flatten.clinc create mode 100644 resources/tests/game-referee-in-cl23/handbitmap.clinc create mode 100644 resources/tests/game-referee-in-cl23/handcalc.clinc create mode 100644 resources/tests/game-referee-in-cl23/handcalc2.clinc create mode 100644 resources/tests/game-referee-in-cl23/krunk_generate.clinc create mode 100644 resources/tests/game-referee-in-cl23/krunk_include.clsp create mode 100644 resources/tests/game-referee-in-cl23/krunk_make_clue.clinc create mode 100644 resources/tests/game-referee-in-cl23/last.clinc create mode 100644 resources/tests/game-referee-in-cl23/len.clinc create mode 100644 resources/tests/game-referee-in-cl23/main.sym create mode 100644 resources/tests/game-referee-in-cl23/map.clinc create mode 100644 resources/tests/game-referee-in-cl23/match.clinc create mode 100644 resources/tests/game-referee-in-cl23/max.clinc create mode 100644 resources/tests/game-referee-in-cl23/noncegame.clsp create mode 100644 resources/tests/game-referee-in-cl23/onehandcalc.clinc create mode 100644 resources/tests/game-referee-in-cl23/partition.clinc create mode 100644 resources/tests/game-referee-in-cl23/permutations.clinc create mode 100644 resources/tests/game-referee-in-cl23/prefix.clinc create mode 100644 resources/tests/game-referee-in-cl23/prepend.clinc create mode 100644 resources/tests/game-referee-in-cl23/print.clinc create mode 100644 resources/tests/game-referee-in-cl23/range.clinc create mode 100644 resources/tests/game-referee-in-cl23/reduce.clinc create mode 100644 resources/tests/game-referee-in-cl23/referee.clsp create mode 100644 resources/tests/game-referee-in-cl23/relops.clinc create mode 100644 resources/tests/game-referee-in-cl23/reverse.clinc create mode 100644 resources/tests/game-referee-in-cl23/rockpaperscissorsa.clsp create mode 100644 resources/tests/game-referee-in-cl23/rockpaperscissorsb.clsp create mode 100644 resources/tests/game-referee-in-cl23/rockpaperscissorsc.clsp create mode 100644 resources/tests/game-referee-in-cl23/shatree.clinc create mode 100644 resources/tests/game-referee-in-cl23/slice.clinc create mode 100644 resources/tests/game-referee-in-cl23/slice_runner.clsp create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clsp create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_deep_compare.sym create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_permutations.clsp create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_permutations.sym create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_sort.clsp create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_sort.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/smoke_test_sort.sym create mode 100644 resources/tests/game-referee-in-cl23/sort.clinc create mode 100644 resources/tests/game-referee-in-cl23/space_poker.clinc create mode 100644 resources/tests/game-referee-in-cl23/spacehandcalc.clinc create mode 100644 resources/tests/game-referee-in-cl23/spacepoker_include.clsp create mode 100644 resources/tests/game-referee-in-cl23/steprun.py create mode 100644 resources/tests/game-referee-in-cl23/test_detectwrap.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_handbitmap.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_handcalc.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_library_basics.py create mode 100644 resources/tests/game-referee-in-cl23/test_onehandcalc.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_permutations.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_permutations.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/test_permutations.sym create mode 100644 resources/tests/game-referee-in-cl23/test_prepend.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_prepend.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/test_prepend.sym create mode 100644 resources/tests/game-referee-in-cl23/test_range.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_range.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/test_range.sym create mode 100644 resources/tests/game-referee-in-cl23/test_reverse.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_reverse.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/test_reverse.sym create mode 100644 resources/tests/game-referee-in-cl23/test_slice.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_sort.clsp create mode 100644 resources/tests/game-referee-in-cl23/test_sort.clvm.hex create mode 100644 resources/tests/game-referee-in-cl23/test_sort.sym create mode 100644 resources/tests/game-referee-in-cl23/testnoncegame.py create mode 100644 resources/tests/game-referee-in-cl23/testreferee.py create mode 100644 resources/tests/game-referee-in-cl23/testrockpaperscissors.py create mode 100644 resources/tests/game-referee-in-cl23/truncate.clinc create mode 100644 resources/tests/game-referee-in-cl23/utils.clinc diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml index 86d328ea4..d9ea44687 100644 --- a/.github/workflows/extensive-tests.yml +++ b/.github/workflows/extensive-tests.yml @@ -119,3 +119,4 @@ jobs: cp support/test-game-referee.sh . sh test-game-referee.sh resources/tests/game-referee-in-cl21 sh test-game-referee.sh resources/tests/game-referee-after-cl21 + sh test-game-referee.sh resources/tests/game-referee-in-cl23 diff --git a/resources/tests/game-referee-in-cl23/all-in-list.clinc b/resources/tests/game-referee-in-cl23/all-in-list.clinc new file mode 100644 index 000000000..1db5f26ad --- /dev/null +++ b/resources/tests/game-referee-in-cl23/all-in-list.clinc @@ -0,0 +1,12 @@ +( + (defun enquote-rest (L) + (if L + (c (c 1 (f L)) (enquote-rest (r L))) + () + ) + ) + + (defun all-in-list (L) + (a (c 34 (enquote-rest L)) ()) + ) +) diff --git a/resources/tests/game-referee-in-cl23/append.clinc b/resources/tests/game-referee-in-cl23/append.clinc new file mode 100644 index 000000000..885a90bb2 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/append.clinc @@ -0,0 +1,8 @@ +( + (defun append (L R) + (if L + (c (f L) (append (r L) R)) + R + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/assert.clinc b/resources/tests/game-referee-in-cl23/assert.clinc new file mode 100644 index 000000000..67376b08a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/assert.clinc @@ -0,0 +1,10 @@ +( + (defun assert_ (items) + (if (r items) + (qq (if (unquote (f items)) (unquote (assert_ (r items))) (x))) + (f items) + ) + ) + + (defmac assert items (assert_ items)) +) diff --git a/resources/tests/game-referee-in-cl23/busy.clinc b/resources/tests/game-referee-in-cl23/busy.clinc new file mode 100644 index 000000000..e534d2125 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/busy.clinc @@ -0,0 +1,11 @@ +( + (defun busy (myfunc mylist returnval) + (if mylist + (last + (a myfunc (list (f mylist))) + (busy myfunc (r mylist) returnval) + ) + returnval + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/calpoker_generate.clinc b/resources/tests/game-referee-in-cl23/calpoker_generate.clinc new file mode 100644 index 000000000..4bbf26f7c --- /dev/null +++ b/resources/tests/game-referee-in-cl23/calpoker_generate.clinc @@ -0,0 +1,466 @@ +( +; Proposer function takes readable_info and returns (player_contribution, +; [(whether_my_move driver validation_program_hash state mover_share)]) +; Accepter function takes (player_contribution +; [(whether_opponent_move validation_program_hash state mover_share)]) and returns +; (UNHANDLED) or (ERROR) or (ACCEPTABLE readable_info initial_driver) +; Driver functions are either moving or waiting type +; Moving driver takes (local_move amount state entropy) and returns +; (move validation_program_hash state split waiting_driver message_parser) +; Waiting driver takes (amount state move split) and returns +; (MAKE_MOVE readable_info validation_program_hash state moving_driver message) or +; (SLASH evidence) +; Message parsers take a message and return readable_info or asserts + +(include assert.clinc) +(include shatree.clinc) + +(defconst MAKE_MOVE 0) +(defconst SLASH 1) +(defconst ERROR 0) +(defconst UNHANDLED 1) +(defconst ACCEPTABLE 2) + +(defun calpoker_alice_proposer (bet_size) + (list + bet_size + (list + (list + 1 + calpoker_alice_driver_a + AHASH + 0 + bet_size + ) + ) + ) +) + +; state is empty +; local_move is nil +; makes a move using entropy +(defun calpoker_alice_driver_a (local_move amount validation_program_hash state entropy) + (assign + preimage (substr entropy 0 16) + image (sha256 preimage) + (list + image + BHASH + image + 0 + (curry calpoker_alice_driver_b preimage) + ) + ) +) + +; state is alice's commit +; move is bob's seed +; immediately sends a message giving Alice's seed +(defun calpoker_alice_driver_b (PREIMAGE amount image move split) + (list MAKE_MOVE (make_cards_readable (make_cards (sha256 PREIMAGE move))) CHASH (list image move) calpokerc + (curry calpoker_alice_driver_c PREIMAGE) PREIMAGE) +) + +(defun bitify (mylist) + (if (not mylist) + 0 + (logior (f mylist) (lsh (bitify (r mylist)) 1)) + ) +) + +; state is alice's commit and bob's seed +; move is alice's reveal of her card generating seed and her commit to which cards she's picking +(defun calpoker_alice_driver_c (PREIMAGE local_move amount (alice_commit bob_seed) entropy) + (assign + cards (make_cards (sha256 PREIMAGE bob_seed)) + my_picks (bitify local_move) + salt (substr entropy 0 16) + new_commit (sha256 (concat salt my_picks)) + (list + new_commit + DHASH + (list CARDS new_commit) + 0 + (curry calpoker_alice_driver_d salt my_picks) + PREIMAGE + ) + ) +) + +(defun split_cards (cards picks) + (if (not cards) + (list 0 0) + (assign + (inner_my_cards inner_other_cards) (split_cards (r cards) (r picks)) + (if (f picks) + (list (c (f cards) inner_my_cards) inner_other_cards) + (list inner_my_cards (c (f cards) inner_other_cards)) + ) + ) + ) +) + +; state is the cards for both players and alice's card pick commitment +; move is Bob's picks +; should immediately respond with a move revealing picks and selecting best cards and final split +(defun calpoker_alice_driver_d (MY_SALT MY_PICKS amount + (@ state (cards my_commit)) move split) + (assign + (my_cards_me my_cards_bob) (split_cards (f cards) MY_PICKS) + (bob_cards_bob bob_cards_me) (split_cards (r cards) move) + my_all_cards (map make_card (append my_cards_me bob_cards_me)) + bob_all_cards (map make_card (append bob_cards_bob my_cards_bob)) + my_picks (handcalc my_all_cards) + bob_picks (handcalc bob_all_cards) + my_hand_value (onehandcalc (pull_out_cards my_picks my_all_cards)) + bob_hand_value (onehandcalc (pull_out_cards bob_picks bob_all_cards)) + win_result (hand_compare my_hand_value bob_hand_value) + split (if (= win_result 1) 0 (= win_result 0) (lsh amount -1) amount) + (list MAKE_MOVE + (list (to_bitfield move) (to_bitfield my_picks) (to_bitfield bob_picks) + my_hand_value bob_hand_value win_result) + EHASH + 0 + (lambda (& MY_SALT MY_PICKS split) (list (concat MY_SALT MY_PICKS) 0 0 split)) + ) + ) +) + +(defun calpoker_bob_accepter (player_contribution ((whether_opponent_move + validation_program_hash state mover_share) . extra)) + (if (!= validation_program_hash AHASH) + (list UNHANDLED) + (any + extra + (not whether_opponent_move) + state + (!= player_contribution mover_share) + ) + (list ERROR) + (list ACCEPTABLE 0 calpoker_bob_driver_a) + ) +) + +; state is empty +; move is alice commit to a salted word +(defun calpoker_bob_driver_a (amount state move split) + (list MAKE_MOVE 0 BHASH move calpoker_alice_driver_b) +) + +; state is alice_commit +; move is bob_seed +(defun calpoker_bob_driver_b (amount alice_commit local_move entropy) + (assign + seed (substr entropy 0 16) + (list + seed + CHASH + (list alice_commit seed) + 0 + calpoker_alice_driver_c + parse_message + ) + ) +) + +; state is alice's commit and bob's seed +; move is alice's reveal of her card generating seed and her commit to which cards she's picking +; expecting a message revealing Alice's seed which results in local display once verified +(defun calpoker_bob_driver_c (amount (@ state (alice_commit bob_seed)) move split) + (assign + (@ cards (alice_cards bob_cards)) (make_cards (sha256 (substr move 0 16) bob_seed)) + alice_picks_commit (substr move 16 48) + (list MAKE_MOVE (make_cards_readable cards) DHASH (list cards alice_picks_commit) calpoker_alice_driver_d) + ) +) + +(defun parse_message (message (alice_commit bob_seed)) + (assert + (= (sha256 message) alice_commit) + (make_cards_readable (make_cards (sha256 message bob_seed))) + ) +) + +(defun slashable (amount validater state move new_validation_hash split evidence) + (assign + (returnval . exception) (run validater (list 0 (list move new_validation_hash split 0 0 0 amount) + state 0 0 0 evidence)) + (not exception) + ) +) + +; state is ((alice_cards bob_cards) alice_pick_commitment) +; move is Bob's picks +(defun calpoker_bob_driver_d (local_move amount ((alice_cards bob_cards) alice_commit_2)) + (assign + my_move (bitify local_move) + (list + my_move + EHASH + (list my_move (list alice_cards bob_cards) alice_commit_2) + 0 + calpoker_bob_driver_e + ) + ) +) + +; state is (Bob's picks (alice_cards bob_cards) alice_commit) +; move is alice_salted_picks +; either fraud proves or accepts split +(defun calpoker_bob_driver_e (amount (@ state (bob_selects (alice_cards_bob_cards) alice_commit_2)) move split) + (assign + alice_selects (substr move 16 17) + (alice_cards_alice alice_cards_bob) (split_cards alice_cards alice_picks) + (bob_cards_bob bob_cards_alice) (split_cards bob_cards bob_selects) + alice_all_cards (map make_card (append alice_cards_alice bob_cards_alice)) + bob_all_cards (map make_card (append bob_cards_bob alice_cards_bob)) + alice_picks (handcalc my_all_cards) + bob_picks (handcalc bob_all_cards) + alice_hand_value (onehandcalc (pull_out_cards alice_picks alice_all_cards)) + bob_hand_value (onehandcalc (pull_out_cards bob_picks bob_all_cards)) + win_result (hand_compare alice_hand_value bob_hand_value) + correct_split (if (= win_result 1) 0 (= win_result 0) (lsh amount -1) amount) + (if (< split correct_split) + (list SLASH bob_picks) + (list MAKE_MOVE + (list (to_bitfield alice_selects) (to_bitfield bob_picks) (to_bitfield alice_picks) + bob_hand_value alice_hand_value (- 0 win_result)) + 0 + ) + ) + ) +) + +(defconst EHASH (shatree calpokere)) +(defconst DHASH (shatree calpokerd)) +(defconst CHASH (shatree calpokerc)) +(defconst BHASH (shatree calpokerb)) +(defconst AHASH (shatree calpokera)) + +; Bob challenging +; state is empty +; move is alice commit to a salted word +; evidence is empty +(defun calpokera (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + state me mover_puzzle solution evidence) + + (assert + (not + (all + (= new_validation_hash (sha256 BHASH (sha256 1 move))) + (= (strlen move) 32) + ) + ) + 0 + ) +) + +; Alice challenging +; state is alice's commit +; move is bob's seed +; evidence is empty +(defun calpokerb (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + alice_commit me mover_puzzle solution evidence) + (assert + (not + (all + (= new_validation_hash (sha256 CHASH (shatree (list alice_commit bob_seed)))) + (= (strlen bob_seed) 16) + ) + ) + 0 + ) +) + +(defun make_card_readable (val) + (assign + (rank . suit) (divmod val 4) + (if (= rank 12) + (list 1 (+ 1 suit)) + (list (+ 2 rank) (+ 1 suit)) + ) + ) +) + +(defun make_cards_readable ((cardsa cardsb)) + (list (map make_card_readable cardsa) (map make_card cardsb)) +) + +(defun make_cards (randomness) + (assign + (handa newrandomness) (choose 52 8 randomness) + (handb newrandomness2) (choose (- 52 8) newrandomness) + (list handa (mergeover handa handb)) + ) +) + +(defun <= (a b) + (not (> a b)) +) + +; like mergein but only calculates the contents of inner with offsets +; applied and doesn't interleave the contents of outer +(defun mergeover (outer inner offset) + (if (not inner) + 0 + (assign first (+ (f inner) offset) + (if (not outer) + (c first (mergeover 0 (r inner) offset)) + (if (<= (f outer) first) + (mergeover (r outer) inner (+ offset 1)) + (c first (mergeover outer (r inner) offset)) + ) + ) + ) + ) +) + +; slide the things in inner in between the things in outer assuming +; things in inner are already bumped up by offset things from outer which +; came before +(defun mergein (outer inner offset) + (if (not inner) + outer + (assign first (+ (f inner) offset) + (if (not outer) + (c first (mergein 0 (r inner) offset)) + (if (<= (f outer) first) + (c (f outer) (mergein (r outer) inner (+ offset 1))) + (c first (mergein outer (r inner) offset)) + ) + ) + ) + ) +) + +; pick numchoose things out of numcards options with randomness extracted from vals +; returns (cards newvals) cards are always in sorted order +(defun choose (numcards numchoose randomness) + (if (= numchoose 1) + (assign (newrandomness card) (divmod randomness numcards) + (list (list card) newrandomness) + ) + (assign + half (lsh numchoose -1) + (cards1 newrandomness2) (choose numcards half randomness) + (cards2 newrandomness3) (choose (- numcards half) (- numchoose half) newrandomness2) + (list (mergein cards1 cards2 0) newrandomness3) + ) + ) +) + +; Bob challenging +; state is alice's commit and bob's seed +; move is alice's reveal of her card generating seed and her commit to which cards she's picking +; evidence is empty +(defun calpokerc (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (alice_commit bob_seed) me mover_puzzle solution evidence) + (assert + (not + (all + (= (strlen move) 48) + (= (sha256 (substr move 0 16)) alice_commit) + (= new_validation (sha256 DHASH (shatree (list (make_cards + (sha256 (substr move 0 16) bob_seed)) (substr move 16 48))))) + ) + ) + 0 + ) +) + +(defun onecount (mymask) + (if mymask + (+ (logand mymask 1) (onecount (lsh mymask -1))) + 0 + ) +) + +; Alice challenging +; state is the cards for both players and alice's card pick commitment +; move is Bob's picks +; evidence is empty +(defun calpokerd (mod_hash (bob_picks next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (cards alice_commit) me mover_puzzle solution evidence) + (assert + (not + (all + (= (strlen bob_picks) 1) + (= (onecount bob_picks) 4) + (= new_validation_hash (sha256 EHASH (shatree (list bob_picks cards alice_commit)))) + ) + ) + 0 + ) +) + +(include handcalc.clinc) +(include map.clinc) + +; Use mask to determine which cards are prepended to leftcards and which to rightcards +(defun extract_cards (mask cards leftcards rightcards) + (if (not cards) + (list leftcards rightcards) + (if (logand mask 1) + (extract_cards (lsh mask -1) (r cards) leftcards (c (f cards) rightcards)) + (extract_cards (lsh mask -1) (r cards) (c (f cards) leftcards) rightcards) + ) + ) +) + +(defun make_card (val) + (assign + (rank . suit) (divmod val 4) + (list (+ 2 rank) (+ 1 suit)) + ) +) + +(defun pull_out_cards (selections cards) + (if (not cards) + 0 + (if (logand selections 1) + (c (f cards) (pull_out_cards (lsh -1 selections) (r cards))) + (pull_out_cards (lsh -1 selections) (r cards)) + ) + ) +) + +; Bob challenging +; state is (Bob's picks (alice_cards bob_cards) alice_commit) +; move is alice_salted_picks +; evidence is Bob's card selections +(defun calpokere (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (bob_picks (alice_cards bob_cards) alice_commit) me mover_puzzle solution bob_card_selections) + (assign + alice_salted_picks (substr move 0 16) + alice_card_selections (substr move 16 17) + (alice_final_cards bob_final_cards) (extract_cards bob_picks bob_cards &rest (extract_cards alice_picks alice_cards 0 0)) + result (hand_compare (onehandcalc (pull_out_cards alice_card_selections alice_final_cards)) + (onehandcalc (pull_out_cards bob_card_selections bob_final_cards))) + (assert + (not + (all + (not new_validation_hash) + (= (strlen move) 18) + (= (sha256 alice_salted_picks alice_commit)) + (= (onecount alice_picks) 4) + (<= alice_share + (if (not result) + (/ total 2) + (if (= result 1) + 0 + total + ) + ) + ) + ) + ) + 0 + ) + ) +) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/calpoker_include.clsp b/resources/tests/game-referee-in-cl23/calpoker_include.clsp new file mode 100644 index 000000000..8e821a7af --- /dev/null +++ b/resources/tests/game-referee-in-cl23/calpoker_include.clsp @@ -0,0 +1 @@ +(mod () (include *standard-cl-23*) (include calpoker_generate.clinc) ()) diff --git a/resources/tests/game-referee-in-cl23/condition_codes.clinc b/resources/tests/game-referee-in-cl23/condition_codes.clinc new file mode 100644 index 000000000..45f3265da --- /dev/null +++ b/resources/tests/game-referee-in-cl23/condition_codes.clinc @@ -0,0 +1,41 @@ +; See chia/types/condition_opcodes.py + +( + (defconstant AGG_SIG_UNSAFE 49) + (defconstant AGG_SIG_ME 50) + + ; the conditions below reserve coin amounts and have to be accounted for in output totals + + (defconstant CREATE_COIN 51) + (defconstant RESERVE_FEE 52) + + ; the conditions below deal with announcements, for inter-coin communication + + ; coin announcements + (defconstant CREATE_COIN_ANNOUNCEMENT 60) + (defconstant ASSERT_COIN_ANNOUNCEMENT 61) + + ; puzzle announcements + (defconstant CREATE_PUZZLE_ANNOUNCEMENT 62) + (defconstant ASSERT_PUZZLE_ANNOUNCEMENT 63) + + ; the conditions below let coins inquire about themselves + + (defconstant ASSERT_MY_COIN_ID 70) + (defconstant ASSERT_MY_PARENT_ID 71) + (defconstant ASSERT_MY_PUZZLEHASH 72) + (defconstant ASSERT_MY_AMOUNT 73) + + ; the conditions below ensure that we're "far enough" in the future + + ; wall-clock time + (defconstant ASSERT_SECONDS_RELATIVE 80) + (defconstant ASSERT_SECONDS_ABSOLUTE 81) + + ; block index + (defconstant ASSERT_HEIGHT_RELATIVE 82) + (defconstant ASSERT_HEIGHT_ABSOLUTE 83) + + ; A condition that is always true and always ignore all arguments + (defconstant REMARK 1) +) diff --git a/resources/tests/game-referee-in-cl23/curry-and-treehash.clinc b/resources/tests/game-referee-in-cl23/curry-and-treehash.clinc new file mode 100644 index 000000000..6a63e9364 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/curry-and-treehash.clinc @@ -0,0 +1,92 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant ONE 1) + (defconstant TWO 2) + (defconstant A_KW #a) + (defconstant Q_KW #q) + (defconstant C_KW #c) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 TWO (sha256 ONE C_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) parameter-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash`, updating `environment-hash` + ;; along the way. + + (defun build-curry-list (reversed-curry-parameter-hashes environment-hash) + (if reversed-curry-parameter-hashes + (build-curry-list (r reversed-curry-parameter-hashes) + (update-hash-for-parameter-hash (f reversed-curry-parameter-hashes) environment-hash)) + environment-hash + ) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `function-hash` of a function tree F + ;; return the tree hash of the tree corresponding to + ;; `(a (q . F) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . F) E)` = `(a . ((q . F) . (E . 0)))` + + (defun-inline tree-hash-of-apply (function-hash environment-hash) + (sha256 TWO (sha256 ONE A_KW) + (sha256 TWO (sha256 TWO (sha256 ONE Q_KW) function-hash) + (sha256 TWO environment-hash (sha256 ONE 0)))) + ) + + ;; function-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; reversed-curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; Note that this must be applied in REVERSED order. This may seem strange, but it greatly simplifies + ;; the underlying code, since we calculate the tree hash from the bottom nodes up, and the last + ;; parameters curried must have their hashes calculated first. + ;; + ;; we return the hash of the curried expression + ;; (a (q . function-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the actual curried program. + + (defun puzzle-hash-of-curried-function (function-hash . reversed-curry-parameter-hashes) + (tree-hash-of-apply function-hash + (build-curry-list reversed-curry-parameter-hashes (sha256 ONE ONE))) + ) + + (defconstant b32 32) + + (defun-inline size_b32 (var) + (= (strlen var) b32) + ) + + (defun calculate_coin_id (parent puzzlehash amount) + (if (all (size_b32 parent) (size_b32 puzzlehash) (> amount -1)) + (sha256 parent puzzlehash amount) + (x) + ) + ) + + ; takes a lisp tree and returns the hash of it + (defun shatree (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE))) + +) diff --git a/resources/tests/game-referee-in-cl23/curry.clinc b/resources/tests/game-referee-in-cl23/curry.clinc new file mode 100644 index 000000000..81a1ec3a6 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/curry.clinc @@ -0,0 +1,104 @@ +( + ;; The code below is used to calculate of the tree hash of a curried function + ;; without actually doing the curry, and using other optimization tricks + ;; like unrolling `shatree`. + + (defconstant TWO 2) + (defconstant constant-tree ( + (0x4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a . ; = `(sha256 1)` + 0x9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2) . ; = `(sha256 1 1)` = `(sha256 1 #q)` + (0x02a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222 . ; = `(concat 2 (sha256 1 #a))` + 0x02a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5) ; = `(concat 2 (sha256 1 #c))` + ) + ) + + ; I looked into calculating the values of `constant-tree` because it's pretty easy to code-golf + ; out an implementation that produces the values cheaper than just inlining them. The problem is, + ; when do we calculate them? If there were a way to calculate it "before main" and include it in + ; the globally-accessible constant table, we could do that. But we can't which means to be optimal, + ; client code should call the "build table" code once, then pass it around to anyone that wants to + ; call `curry` or `curry2`. This is pretty intrusive, so for now we'll just use the existing + ; global constant infrastructure, and include it as a fixed table so the tree of four values will + ; appear in all code that includes this file, and it will compress better in generators. + + (defun-inline sha256_one _noargs (f (f constant-tree))) + (defun-inline sha256_one_one _noargs (r (f constant-tree))) + (defun-inline two_sha256_one_a_kw _noargs (f (r constant-tree))) + (defun-inline two_sha256_one_c_kw _noargs (r (r constant-tree))) + + ;; this returns the sha256 tree hash of expression F = `((q . a1) a2)` + (defun hash-expression-F (a1 a2) + (sha256 TWO (sha256 TWO (sha256_one_one) a1) + (sha256 TWO a2 (sha256_one))) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `parameter-hash` of a constant parameter P + ;; return the tree hash of the tree corresponding to + ;; `(c (q . P) E)` + ;; This is the new environment tree with the addition parameter P curried in. + ;; + ;; Note that `(c (q . P) E)` = `(c . ((q . P) . (E . 0)))` + + (defun-inline update-hash-for-parameter-hash (parameter-hash environment-hash) + (sha256 (two_sha256_one_c_kw) (hash-expression-F parameter-hash environment-hash)) + ) + + ;; Given the tree hash `environment-hash` of an environment tree E + ;; and the tree hash `mod-hash` of a mod M + ;; return the tree hash of the tree corresponding to + ;; `(a (q . M) E)` + ;; This is the hash of a new function that adopts the new environment E. + ;; This is used to build of the tree hash of a curried function. + ;; + ;; Note that `(a (q . M) E)` = `(a . ((q . M) . (E . 0)))` + + (defun-inline tree-hash-of-apply (mod-hash environment-hash) + (sha256 (two_sha256_one_a_kw) (hash-expression-F mod-hash environment-hash)) + ) + + ;; This function recursively calls `update-hash-for-parameter-hash` + + (defun calculate-hash-of-curried-parameters (curry-parameter-hashes) + (if curry-parameter-hashes + (update-hash-for-parameter-hash (f curry-parameter-hashes) (calculate-hash-of-curried-parameters (r curry-parameter-hashes))) + (sha256_one_one) + ) + ) + + ;; mod-hash: + ;; the hash of a puzzle function, ie. a `mod` + ;; + ;; curry-parameter-hashes: + ;; a list of pre-hashed trees representing parameters to be curried into the puzzle. + ;; + ;; we return the hash of the curried expression + ;; (a (q . mod-hash) (c (cp1 (c cp2 (c ... 1)...)))) + ;; + ;; Note that from a user's perspective the hashes passed in here aren't simply + ;; the hashes of the desired parameters, but their treehash representation since + ;; that's the form we're assuming they take in the acutal curried program. + + ;; inline functions that take varargs don't seem to work, so we can't inline `curry` + + (defun curry_hashes (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + + ;; this is included for future compilers that handle it properly. If you get weird + ;; errors using this, it may be your tooling. Use `curry` above instead, or inline manually. + + (defun-inline curry_hashes_inline (mod-hash . curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) + + ;; `curry_mod_hashes_inline` takes exactly two parameters rather than varags, and it can be inlined + + (defun-inline curry_mod_hashes_inline (mod-hash curry-parameter-hashes) + (tree-hash-of-apply mod-hash + (calculate-hash-of-curried-parameters curry-parameter-hashes)) + ) +) diff --git a/resources/tests/game-referee-in-cl23/deep_compare.clinc b/resources/tests/game-referee-in-cl23/deep_compare.clinc new file mode 100644 index 000000000..0a863ae33 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/deep_compare.clinc @@ -0,0 +1,41 @@ + +( + (defun deep_compare (a b) + (if (l a) + (if (l b) + (assign-lambda inner_result (deep_compare (f a) (f b)) + (if inner_result + inner_result + (deep_compare (r a) (r b)) + ) + ) + 1 + ) + (if (l b) + -1 + (if (> a b) + 1 + (- 0 (> b a)) + ) + ) + ) + ) + (defun deep< (a b) + (= (deep_compare a b) -1) + ) + (defun deep> (a b) + (= (deep_compare a b) 1) + ) + (defun deep= (a b) + (= (deep_compare a b) 0) + ) + (defun deep<= (a b) + (not (deep> a b)) + ) + (defun deep>= (a b) + (not (deep< a b)) + ) + (defun deep!= (a b) + (not (deep= a b)) + ) +) diff --git a/resources/tests/game-referee-in-cl23/deep_compare_t2.clsp b/resources/tests/game-referee-in-cl23/deep_compare_t2.clsp new file mode 100644 index 000000000..6df52dd65 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/deep_compare_t2.clsp @@ -0,0 +1,6 @@ +(mod (A B) + (include *standard-cl-23*) + (include deep_compare.clinc) + + (deep_compare A B) + ) diff --git a/resources/tests/game-referee-in-cl23/detectwrap.clinc b/resources/tests/game-referee-in-cl23/detectwrap.clinc new file mode 100644 index 000000000..c6364bb36 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/detectwrap.clinc @@ -0,0 +1,17 @@ +( + (defun get-straight-hand (my_straight_high last cards) + (if (print "gsh cards" cards) + (let ((next (get-straight-hand my_straight_high (r cards)))) + (if (logior + (logand (= my_straight_high 5) (= (f (f cards)) 14)) + (logand + (>= my_straight_high (f (f cards))) + (<= (- my_straight_high 4) (f (f cards))))) + (c (f cards) next) + next + ) + ) + () + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/filtermap.clinc b/resources/tests/game-referee-in-cl23/filtermap.clinc new file mode 100644 index 000000000..f37cb862d --- /dev/null +++ b/resources/tests/game-referee-in-cl23/filtermap.clinc @@ -0,0 +1,21 @@ + +( + (defun filtermap_fun (process remaining init) + (if remaining + (assign next (a process (list (f remaining))) + (if next + (c next (filtermap process (r remaining) init)) + (filtermap process (r remaining) init) + ) + ) + init + ) + ) + + (defmac filtermap (process remaining . maybe_init) + (if maybe_init + (qq (filtermap_fun (unquote process) (unquote remaining) (unquote (f maybe_init)))) + (qq (filtermap_fun (unquote process) (unquote remaining) ())) + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/flatten.clinc b/resources/tests/game-referee-in-cl23/flatten.clinc new file mode 100644 index 000000000..ab3815abd --- /dev/null +++ b/resources/tests/game-referee-in-cl23/flatten.clinc @@ -0,0 +1,12 @@ +( + (defun flatten_list (everything) + (if + (not everything) 0 + (prepend (f everything) (flatten_list (r everything))) + ) + ) + (defun flatten everything + (flatten_list everything) + ) + +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/handbitmap.clinc b/resources/tests/game-referee-in-cl23/handbitmap.clinc new file mode 100644 index 000000000..7becb0f95 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/handbitmap.clinc @@ -0,0 +1,66 @@ +( + (defun mem (choice lst) + (if lst + (if (deep= choice (f lst)) + lst + (mem choice (r lst)) + ) + () + ) + ) + + (defun bitmap_from_members (chosen cards) + (if cards + (logior (not (not (mem (f cards) chosen))) (lsh (bitmap_from_members chosen (r cards)) 1)) + 0 + ) + ) + + (defun find_hand_indices_x (hand cards) + (bitmap_from_members (ranks_from_hand hand cards) cards) + ) + + (defun find_hand_indices (hand cards) + (find_hand_indices_x hand cards) + ) + + (defun member_of_hand (rank hand) + (if hand + (if (= (f (f hand)) rank) + 1 + (member_of_hand rank (r hand)) + ) + 0 + ) + ) + + (defun remove_rank_from_hand (rank (@ hand (f_hand . r_hand))) + (if hand + (if (= (f f_hand) rank) + (if (> (r f_hand) 1) + (c (c (f f_hand) (- (r f_hand) 1)) r_hand) + r_hand + ) + (c (f hand) (remove_rank_from_hand rank r_hand)) + ) + () + ) + ) + + (defun ranks_from_hand_real (hand (@ cards ((@ first_card (first_rank . first_suit)) . remaining_cards))) + (if cards + (if (member_of_hand first_rank hand) + (assign + new_hand (remove_rank_from_hand first_rank hand) + (c first_card (ranks_from_hand new_hand remaining_cards)) + ) + (ranks_from_hand hand remaining_cards) + ) + () + ) + ) + + (defun ranks_from_hand (hand cards) + (ranks_from_hand_real (map (lambda (count . rank) (c rank count)) cards)) + ) +) diff --git a/resources/tests/game-referee-in-cl23/handcalc.clinc b/resources/tests/game-referee-in-cl23/handcalc.clinc new file mode 100644 index 000000000..d85154890 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/handcalc.clinc @@ -0,0 +1,232 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defun find_flush (suits) + (assign + ((count1 . suit1)) (group_by_count_clean (atomsort suits)) + (* suit1 (>= count1 5)) + ) + ) + + (defun straight_high_inner (ranks last count) + (if (not ranks) + (if (logand (= last 2) (= count 4)) + ; maybe ace to five + 5 + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high_extended (ranks) + (assign + high (straight_high_inner ranks 0 0) + (if (= high 5) + (* (= (f ranks) 14) 5) + high + ) + ) + ) + + (defun group_by_count_clean (items) + (map + unflatten_card + (atomsort (group_by_count_inner items (f items) 0)) + ) + ) + + (defun find_straight_flush_indices (flush_suit straight_flush_high (@ cards ((first_rank . first_suit) . remaining))) + (if (not cards) + 0 + (assign + straight_to_ace_match + (logand + (= straight_flush_high 5) + (= first_rank 14) + ) + + rank_in_range + (logand + (<= first_rank straight_flush_high) + (> first_rank (- straight_flush_high 5)) + ) + + hit + (logand + (= first_suit flush_suit) + (logior straight_to_ace_match rank_in_range) + ) + + (logior (lsh (find_straight_flush_indices flush_suit straight_flush_high remaining) 1) hit) + ) + ) + ) + + (defun flush_cards_with_index (flush_suit index (@ cards ((first_rank . first_suit)))) + (if (not cards) + 0 + (if (= flush_suit first_suit) + (c (flatten_card (c first_rank index)) (flush_cards_with_index flush_suit (+ index 1) (r cards))) + (flush_cards_with_index flush_suit (+ index 1) (r cards)) + ) + ) + ) + + (defun find_flush_indices (flush_suit cards) + (assign + myfiltered (truncate 5 (atomsort (flush_cards_with_index flush_suit 0 cards))) + (to_bitfield 0 (reverse (atomsort (map (lambda (x) (logand x 15)) myfiltered)))) + ) + ) + + ; includes should be in ascending order + (defun to_bitfield (index includes) + (if (not includes) + 0 + (if (= index (f includes)) + (logior 1 (lsh (to_bitfield (+ index 1) (r includes)) 1)) + (lsh (to_bitfield (+ index 1) includes) 1) + ) + ) + ) + + (defun find_straight_includes (ranks with_index) + (if (all ranks with_index) + (if (= (f ranks) (lsh (f with_index) -4)) + (c (logand 15 (f with_index)) (find_straight_includes (r ranks) (r with_index))) + (find_straight_includes ranks (r with_index)) + ) + 0 + ) + ) + + (defun find_straight_indices (my_straight_high cards) + (assign + with_index (atomsort (ranks_with_indices 0 cards)) + my_ranks + (if (= my_straight_high 5) + (list 14 5 4 3 2) + (list + my_straight_high + (- my_straight_high 1) + (- my_straight_high 2) + (- my_straight_high 3) + (- my_straight_high 4) + ) + ) + + includes (reverse (atomsort (find_straight_includes my_ranks with_index))) + (to_bitfield 0 includes) + ) + ) + + (defun ranks_with_indices (index cards) + (if (not cards) + 0 + (c (flatten_card (c (f (f cards)) index)) (ranks_with_indices (+ index 1) (r cards))) + ) + ) + + (defun find_hand_indices ((@ numbered-cards ((number . card) . rest))) + (if numbered-cards + (logior (lsh 1 number) (find_hand_indices rest)) + 0 + ) + ) + + (defun number_cards (num cards) + (if cards + (c (c num (f cards)) (number_cards (+ num 1) (r cards))) + () + ) + ) + + ;; Sorts the cards by group size according to hand. + ;; Hand has pairs of count and rank. We pull out cards based on their rank + ;; until each bucket is empty in hand and then give the remaining cards. + (defun bucket_cards_by_frequency_groups (hand cards) + (if hand + (assign + (hand_freq . want_rank) (f hand) + + (cards_with_rank . cards_without_rank) (partition (lambda ((& want_rank) (num . (rank . suit))) (= rank want_rank)) cards) + + ;; We have the cards with this rank... go to the next wanted rank. + (append cards_with_rank (bucket_cards_by_frequency_groups (r hand) cards_without_rank)) + ) + cards + ) + ) + + (defun normal_full_house (firstcount secondcount hand cards) + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + ) + + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + sorted_ranks (atomsort (map first cards)) + hand (group_by_count_clean sorted_ranks) + ((firstcount . firstrank) (secondcount . secondrank)) hand + flush_suit (find_flush (map rest cards)) + (if ;; Full house + (logand (= firstcount 3) (= secondcount 2)) + (normal_full_house firstcount secondcount hand cards) + + ;; Flush + flush_suit + (assign-lambda + flush_cards (filtermap (lambda ((& flush_suit) (@ thecard (rank . suit))) (if (= suit flush_suit) rank 0)) cards) + straight_flush_high (straight_high_extended (atomsort flush_cards)) + (if straight_flush_high + (find_straight_flush_indices flush_suit straight_flush_high cards) + (if (logior (< firstcount 3) (logand (= firstcount 3) (= secondcount 1))) + (find_flush_indices flush_suit cards) + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + ) + ) + ) + + ;; Else + (assign + my_straight_high (straight_high_extended sorted_ranks) + (if (all + my_straight_high + (logior + (< firstcount 3) + (logand (= firstcount 3) (= secondcount 1)) + ) + ) + + (find_straight_indices my_straight_high cards) + + (find_hand_indices (truncate 5 (bucket_cards_by_frequency_groups hand (number_cards 0 cards)))) + ) + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/handcalc2.clinc b/resources/tests/game-referee-in-cl23/handcalc2.clinc new file mode 100644 index 000000000..c9e2bef17 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/handcalc2.clinc @@ -0,0 +1,233 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; doesn't work for ten or more cards if there are multiple flushes +; all sorting is done highest to lowest +( + (defconstant STRAIGHT_FLUSH 9) + (defconstant FOUR_OF_A_KIND 8) + (defconstant FULL_HOUSE 7) + (defconstant FLUSH 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun hand< (a b) + (if a + (if (= (f a) (f b)) + (hand< (r a) (r b)) + (< (f a) (f b)) + ) + 0 + ) + ) + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (hand< (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + (defun handsort_inner (@ mylist (first second third) length) + (if (> length 3) + (merge (handsort_inner mylist (/ length 2)) + (handsort_inner (sliceright mylist (/ length 2)) (- length (/ length 2)))) + (if (= length 3) + (if (hand< first second) + (if (hand< second third) + (list first second third) + (if (hand< first third) + (list first third second) + (list third first second) + ) + ) + (if (hand< first third) + (list second first third) + (if (hand< second third) + (list second third first) + (list third second first) + ) + ) + ) + (if (hand< first second) + (list first second) + (list second first) + ) + ) + ) + ) + (defun handsort (@ mylist (first) length) + (if length + (if (= length 1) + (list first) + (handsort_inner mylist length) + ) + 0 + ) + ) + (defund count_suits (@ cards ((firstrank . firstsuit) . remaining)) + (if (not cards) + (list 0 0 0 0) + ; this should use capture + (assign (clubs diamonds hearts spades) (count_suits (r cards)) + (if (= firstsuit 1) + (list (+ clubs 1) diamonds hearts spades) + (if (= firstsuit 2) + (list clubs (+ diamonds 1) hearts spades) + (if (= firstsuit 3) + (list clubs diamonds (+ hearts 1) spades) + (list clubs diamonds hearts (+ spades 1)) + ) + ) + ) + ) + ) + ) + (defun find_flush_2 (cards) + (assign (clubs diamonds hearts spades) (count_suits cards) + (if (> 4 clubs) + 1 + (if (> 4 diamonds) + 2 + (if (> 4 hearts) + 3 + (if (> 4 spades) + 4 + 0 + ) + ) + ) + ) + ) + ) + (defun find_flush_inner (suits last count) + (if (not suits) + 0 + (if (= (f suits) last) + (if (= count 4) + last + (find_flush_inner (r suits) last (+ count 1)) + ) + (find_flush_inner (r suits) (f suits) 1) + ) + ) + ) + ; returns the flush suit or 0 if there isn't any + ; suits must be clustered/sorted + (defun find_flush (suits) + (find_flush_inner (sort (lambda (x y) (deep> x y)) suits) 0 0) + ) + (defun straight_high_inner (ranks started_ace last count) + (if (not ranks) + ; at the end of the list + (if (logand (= last 2) (= count 4) started_ace) + ; ace to five + 5 + ; no straight + 0 + ) + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) started_ace last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) started_ace (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) started_ace (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner ranks (= (f ranks) 14) 0 0) + ) + (defun group_by_count_inner (items last count) + (if (not items) + (list (c count last)) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (c (c count last) val) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + (defun handcalc (cards) + (assign-lambda + first (lambda (x) (f x)) + rest (lambda (x) (r x)) + fsuit (find_flush2 (map rest cards)) + max_flush (if (not fsuit) + 0 + (assign-lambda + fnosuits + (sort + (lambda (x y) (deep> x y)) + (filtermap + (lambda ((& fsuit) (card_rank . card_suit)) + (if (= fsuit card_suit) + card_rank + 0 + ) + ) + cards + 0 + ) + ) + + fsh (straight_high fnosuits) + (if fsh + (list STRAIGHT_FLUSH fsh) + (c FLUSH (slice fnosuits 5)) + ) + ) + ) + nosuits (sort (lambda (x y) (deep> x y)) (map first cards)) + sh (straight_high nosuits) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort (lambda (x y) (deep> x y)) (group_by_count nosuits)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (c FOUR_OF_A_KIND (slice topcards 2)) + ) + ) + ) + (max (lambda (x y) (deep< x y)) (list max_flush max_straight max_group)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/krunk_generate.clinc b/resources/tests/game-referee-in-cl23/krunk_generate.clinc new file mode 100644 index 000000000..9214804d0 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/krunk_generate.clinc @@ -0,0 +1,404 @@ +( +; Alternates moving and validating +; Moving takes (readable_move amount) and returns (0 readable_state move new_validator new_validation_hash split) +; or (1 error_info) +; The validator and hash will be nil if the game is done + +; Validating takes (move new_validation_hash split amount) and returns either (0 readable_state mover) +; or (1 state validation_program evidence aggsig) if there's cheating +; mover is nil if it's the end of the game + +; Checking takes complete args and either assert fails if there's no sign of cheating or returns +; a list of extra conditions, usually empty + +(include assert.clinc) +(include shatree.clinc) +(include curry.clinc) + +(defun make_mover_a (dictionary dictionary_key) + (assign (next next_hash) (make_validator_b dictionary dictionary_key amount) + (curry mover_a (list next next_hash dictionary dictionary_key amount)) + ) +) + +(defun make_validator_a (dictionary dictionary_key) + (assign (next next_hash) (make_mover_b dictionary dictionary_key amount) + (curry mover_a (list next next_hash dictionary dictionary_key amount)) + ) +) + +; Alice challenging +; curried a next program hash and a dictionary key +; state is an Alice commitment +; move is a Bob guess +; evidence may be range of exclusion if Alice is showing Bob's guess is invalid +(defun make_mover_b (dictionary dictionary_key) + (curry krunk_b (list (make_c dictionary_key) (curry krunk_adjudicate dictionary_key))) +) + +(defun make_validator_b (dictionary dictionary_key) +) + +; Bob challenging +; curried a next program hash and a dictionary key +; state is an Alice commitment and a Bob guess +; move is an Alice clue or word reveal if hit +; evidence may be range of exclusion if Bob is showing Alice's word is invalid +(defun make_mover_c (dictionary dictionary_key) + (curry krunk_c (list (make_d dictionary_key) (curry krunk_adjudicate dictionary_key))) +) + +(defun make_validator_c (dictionary dictionary_key) +) + +; Alice challenging +; curried a list of possible next program hashes and a dictionary key +; state is a Alice commitment, Bob guess and Alice clue +; move is a Bob guess and number of remaining guesses +; evidence may be range of exclusion if Alice is showing Bob's word is invalid +(defun make_mover_d (dictionary dictionary_key) + (curry krunk_d (list (list + (make_e dictionary_key 100 0) + (make_e dictionary_key 20 1) + (make_e dictionary_key 5 2) + (make_e dictionary_key 1 3) + ) + (curry krunk_adjudicate dictionary_key)) + ) +) + +(defun make_validator_d (dictionary dictionary_key) +) + +; Bob challenging +; curried a next program hash, dictionary key, and bet amount +; state is an Alice commitment and series of Bob guesses and Alice clues with the +; latest being a guess +; move is an Alice clue or word reveal if hit +; evidence can be index where clue is wrong or be range of exclusion if +; Bob is showing Alice's word is invalid +(defun make_mover_e (turns_left dictionary dictionary_key bet_amount) + (if (not turns_left) + (make_g dictionary_key bet_amount) + (curry krunk_e (list (make_f dictionary_key bet_amount turns_left) + (curry krunk_adjudicate dictionary_key) bet_amount) + ) + ) +) + +(defun make_validator_e (turns_left dictionary dictionary_key bet_amount) +) + +; Alice challenging +; curried a next program hash, dictionary key, and bet amount +; state is an Alice commitment and series of Bob guesses and Alice clues with the +; latest being a clue +; move is a Bob guess +; evidence may be a range of exclusion if Alice is showing that Bob's guess is invalid +(defun make_mover_f (turns_left dictionary dictionary_key bet_amount) + (curry krunk_f (list (make_e dictionary_key bet_amount (- turns_left 1)) + (curry krunk_adjudicate dictionary_key) bet_amount) + ) +) + +(defun make_validator_f (turns_left dictionary dictionary_key bet_amount) +) + +; Bob challenging +; curried a dictionary key and a bet amount +; move is Alice word reveal +; evidence can be index where clue is wrong or range of exclusion if Alice's word is +; not in the dictionary +(defun make_mover_g (dictionary dictionary_key bet_amount) + (curry krunk_g (list (curry krunk_adjudicate dictionary_key) bet_amount)) +) + +(defun make_validator_g (dictionary dictionary_key bet_amount) +) + +(defconst GHASH (shatree krunk_g)) +(defconst FHASH (shatree krunk_f)) +(defconst EHASH (shatree krunk_e)) +(defconst EHASH1 (shatree (curry_hashes EHASH (shatree (curry_hashes FHASH (shatree GHASH)))))) +(defconst EHASH2 (shatree (curry_hashes EHASH (shatree (curry_hashes FHASH (shatree EHASH1)))))) +(defconst EHASH3 (shatree (curry_hashes EHASH (shatree (curry_hashes FHASH (shatree EHASH2)))))) +(defconst DHASH (shatree krunk_d)) +(defconst CHASH (shatree krunk_c)) +(defconst BHASH (shatree krunk_b)) +(defconst AHASH (shatree krunk_a)) + + +; Bob challenging +; state is the dictionary key +; move is an Alice commit to a salted word +; evidence is empty +(defun krunk_a ((move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + dictionary_key me mover_puzzle solution evidence) + + (assert + (not + (all + (= (strlen move) 32) + (= next_validation_hash (sha256 BHASH (shatree (list move dictionary_key)))) + ) + ) + 0 + ) +) + +; Alice challenging +; state is (alice_commit dictionary_key) +; move is a Bob guess +; evidence may be range of exclusion if Alice is showing Bob's guess is invalid +(defun krunk_b ((move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (@ state (alice_commit dictionary_key)) me mover_puzzle solution evidence) + + (if + (all + (= (strlen move) 5) + (= next_validation_hash (sha256 CHASH (shatree (c move state)))) + ) + (assert + (>= move (substr evidence 0 5)) + (<= move (substr evidence 5 10)) + (list (list AGG_SIG_UNSAFE evidence dictionary_key)) + ) + 0 + ) +) + +; Bob challenging +; state is (bob_guess alice_commit dictionary_key) +; move is an Alice clue or commit preimage if hit +; evidence is empty +(defun krunk_c ((move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (@ state (bob_guess alice_commit dictionary_key)) me mover_puzzle solution evidence) + + (assert + (if (= (strlen move) 1) + (any + (>= move 114) + (!= next_validation_hash (sha256 DHASH (shatree (c move state)))) + ) + (any + (!= (strlen move) 37) + (!= (sha256 move) alice_commit) + (!= (substr move 0 5) bob_guess) + ) + ) + 0 + ) +) + +(defun index (myliist num) + (if (not num) + (f mylist) + (index (r mylist) (- num 1)) + ) +) + +; Alice challenging +; state is a (alice_clue bob_guess alice_commit dictionary_key) +; move is a Bob guess and number of remaining guesses +; evidence may be range of exclusion if Alice is showing Bob's word is invalid +(defun krunk_d ((move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (@ state (alice_clue bob_guess @ constants (alice_commit dictionary_key))) me mover_puzzle solution evidence) + + (assign + new_bob_guess (substr move 0 5) + turns_left (substr move 5 6) + (next_hash bet_amount) + (if (not turns_left) (list GHASH 100) + (= turns_left 1) (list EHASH1 20) + (= turns_left 2) (list EHASH2 5) + (list EHASH3 1) + ) + (if + (all + (= (strlen move) 6) + (= next_validation_hash + (sha256 next_hash + (shatree (list (list new_bob_guess alice_clue bob_guess) + bet_amount &rest constants)) + ) + ) + ) + (assert + (>= new_bob_guess (substr evidence 0 5)) + (<= new_bob_guess (substr evidence 5 10)) + (list (list AGG_SIG_UNSAFE evidence dictionary_key)) + ) + 0 + ) + ) +) + +(defun myindex (mylist num) + (if (not num) + mylist + (myindex (r (r mylist)) (- num 1)) + ) +) + +; Bob challenging +; state is ((bob_guess alice_clue bob_guess alice_clue ...) bet_amount alice_commit dictionary_key) +; move is an Alice clue or word reveal if hit +; evidence can be index where clue is wrong +(defun krunk_e (NEXT_HASH (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (move_list @ constants (bet_amount alice_commit dictionary_key)) me mover_puzzle solution evidence) + + (if (= (strlen move) 37) + (assert + (any + (!= (substr move 0 5) (f move_list)) + (!= (sha256 move) alice_commit) + (!= mover_share (* (div amount 200) (+ 100 bet_amount))) + (assign + (myclue guess) (myindex move_list evidence) + (!= myclue (make_clue (substr move 0 5) guess)) + ) + ) + 0 + ) + (assert + (any + (!= (len move) 1) + (>= move 114) + (!= next_validation_hash (sha256 NEXT_HASH (shatree (c (c move move_list) constants)))) + ) + 0 + ) + ) +) + +(defun move_f ((NEXT_VALIDATOR NEXT_HASH DICTIONARY_KEY BET_SIZE) (@STATE ((alice_commit . move_list))) move amount) + (list + (curry NEXT_VALIDATOR (c alice_commit ())) + ) +) + +(defun validate_f ((NEXT_VALIDATOR HASH DICTIONARY_KEY BET_SIZE) STATE move new_validation_hash split amount) + booga booga +) + +; Alice challenging +; state is ((alice_clue bob_guess alice_clue bob_guess ...) bet_amount alice_commit dictionary_key) +; move is a Bob guess +; evidence may be a range of exclusion if Alice is showing that Bob's guess is invalid +(defun krunk_f (NEXT_HASH (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (move_list @ constants (bet_amount alice_commit dictionary_key)) me mover_puzzle solution evidence) + + (if + (all + (= (strlen move) 5) + (= next_validation_hash (sha256 NEXT_HASH + (shatree (c (c move move_list) constants)))) + ) + (assert + (>= move (substr evidence 0 5)) + (<= move (substr evidence 5 10)) + (list (list AGG_SIG_UNSAFE evidence dictionary_key)) + ) + 0 + ) +) + +; Moving takes (readable_move amount) and returns (0 readable_state move new_validator new_validation_hash split) +; or (1 error_info) +; The validator and hash will be nil if the game is done +(defun move_g (BET_SIZE (ALICE_PREIMAGE STATE) move amount) + (assign bob_wins (= (substr ALICE_PREIMAGE 0 5) (f (r STATE))) + (list 0 (+ bob_wins 1) ALICE_PREIMAGE 0 0 + (if bob_wins + (* (/ amount 100) (+ 100 BET_SIZE)) + (* (/ amount 100) (- 100 BET_SIZE)) + ) + ) + ) +) + +; Validating takes (move new_validation_hash split amount) and returns either (0 readable_state mover) +; or (1 state validation_program evidence aggsig) if there's cheating +; mover is nil if it's the end of the game +(defun validate_g ((DICTIONARY DICTIONARY_KEY BET_SIZE) (@STATE ((alice_commit . move_list))) + move new_validation_hash split amount) + (assign + validation_program (curry krunk_g (list DICTIONARY BET_SIZE)) + run_validation_program (lambda ((& move validation_program split STATE) evidence) + (validation_program (list (list move 0 split 0 0 0 amount) + STATE 0 0 0 evidence)) evidence) + proof (find_failure validation_program (list 0 1 2 3 4)) + (if proof + (list 1 STATE validation_program (r proof)) + (assign (@proof2 (begin_range end_range signature)) + (find_exclusion_proof (substr move 0 5) DICTIONARY) + (if proof + (list 1 STATE validation_program + (list (concat begin_range end_range)) signature) + 0 + ) + ) + ) + ) +) + +; Bob challenging +; move is Alice word reveal +; state is ((bob_guess alice_clue bob_guess ...) bet_amount alice_commit dictionary_key) +; evidence can be index where clue is wrong or range of exclusion if Alice's word is +; not in the dictionary +(defun krunk_g ((move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (move_list bet_amount alice_commit dictionary_key) me mover_puzzle solution evidence) + + (if + (all + (= (strlen move) 37) + (= (sha256 move) alice_commit) + (= mover_share + (* (div amount 200) + (if (= (substr move 0 5) (f move_list)) + (+ 100 bet_amount) + (- 100 bet_amount) + ) + ) + ) + ) + (if (= (len evidence) 10) + (assign + word (substr 0 5 move) + (assert + (>= word (substr evidence 0 5)) + (<= word (substr evidence 5 10)) + (list (list AGG_SIG_UNSAFE evidence dictionary_key)) + ) + ) + (assert + (assign + (clue guess) (myindex (r move_list) evidence) + (!= clue (make_clue (substr move 0 5) guess)) + ) + 0 + ) + ) + 0 + ) +) + +; format of dictionary is (lower_dictionary word high_dictionary) or (low high signature) +(defun find_exclusion_proof (word @dictionary (first second third)) + (if (not (l first)) + (if (logand (>= word first) (<= word second)) + dictionary + 0 + ) + (find_exclusion_proof word (if (< word second) first third)) + ) +) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/krunk_include.clsp b/resources/tests/game-referee-in-cl23/krunk_include.clsp new file mode 100644 index 000000000..6b392d08a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/krunk_include.clsp @@ -0,0 +1 @@ +(mod () (include *standard-cl-23*) (include krunk_generate.clinc) ()) diff --git a/resources/tests/game-referee-in-cl23/krunk_make_clue.clinc b/resources/tests/game-referee-in-cl23/krunk_make_clue.clinc new file mode 100644 index 000000000..dea720af6 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/krunk_make_clue.clinc @@ -0,0 +1,58 @@ +( +(defun make_clue (word guess) + (assign + (not_green_word not_green_guess green) (make_green (expand_word word) (expand_word guess)) + yellow (make_yellow not_green_word not_green_guess) + (- (merge_colors green yellow 0) 128) + ) +) +(defun expand_word word + (list (substr word 0 1) (substr word 1 2) (substr word 2 3) (substr word 3 4) (substr word 4 5)) +) +(defun make_green (word guess) + (if (not word) + (list 0 0 0) + (assign (inner_not_green_word inner_not_green_guess inner_green) (make_green (r word) (r guess)) + (if (= (f word) (f guess)) + (list inner_not_green_word inner_not_green_guess (c 1 inner_green)) + (list (c (f word) inner_not_green_word) (c (f guess) inner_not_green_guess) (c 0 inner_green)) + ) + ) + ) +) +(defun make_yellow (word guess) + (if (not guess) + 0 + (if (is_yellow word (f guess)) + (c 1 (make_yellow (elide_one word (f guess)) (r guess))) + (c 0 (make_yellow word (r guess))) + ) + ) +) +(defun elide_one (word letter) + (if (= (f word) letter) + (r word) + (c (f word) (elide_one (r word) letter)) + ) +) +(defun is_yellow (word letter) + (if (not word) + 0 + (if (= (f word) letter) + 1 + (is_yellow (r word) letter) + ) + ) +) +(defun merge_colors (green yellow val) + (if (not green) + val + (merge_colors (r green) &rest + (if (f green) + (list yellow (+ 2 (* 3 val))) + (list (r yellow) (+ (f yellow) (* 3 val))) + ) + ) + ) +) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/last.clinc b/resources/tests/game-referee-in-cl23/last.clinc new file mode 100644 index 000000000..aaa9afd24 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/last.clinc @@ -0,0 +1,44 @@ +( + (defun prefix (L P) + (if L + (c (f L) (prefix (r L) P)) + P + ) + ) + + (defun last_inner ((next . remainder)) + (if remainder + (last_inner remainder) + next + ) + ) + + (defun snoc (L agg) + (if L + (if (r L) + (snoc (r L) (c (f L) agg)) + (c (f L) agg) + ) + (c () ()) + ) + ) + + (defun echo myargs + myargs + ) + + (defmac last ARGS + + (if ARGS + (if (r ARGS) + (assign + (final . rest) (snoc ARGS ()) + reversed (prefix rest (echo final)) + (qq (last_inner (unquote (c (q . echo) reversed)))) + ) + (qq (last_inner (unquote (f ARGS)))) + ) + (x "Last takes at least one argument") + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/len.clinc b/resources/tests/game-referee-in-cl23/len.clinc new file mode 100644 index 000000000..407c36694 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/len.clinc @@ -0,0 +1,3 @@ +( + (defun len (L) (if L (+ 1 (len (r L))) 0)) +) diff --git a/resources/tests/game-referee-in-cl23/main.sym b/resources/tests/game-referee-in-cl23/main.sym new file mode 100644 index 000000000..d93f53a44 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/main.sym @@ -0,0 +1 @@ +{"ac9e61d54eb6967e212c06aab15408292f8558c48f06f9d705150063c68753b0":"prepend.clinc(4):19","ba4484b961b7a2369d948d06c55b64bdbfaffb326bc13b490ab1215dd33d8d46":"*macros*(9):10","35601454cdc8b6b253c2c153d20d41bd234d5af785bada2fec9b806f3d3e1149":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","97f1aa5bc047fef07113607e3c373e96d8d5a1351cc37e2fa022c474c673b421":"prepend.clinc(4):14","a9549b4fbc9e2c4a761843a20b38d0f0409b2959e8c453269df95a2d4340a291":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","959cbf257461e53cfdbbd650fa507fdd8efbe5cf821d4829a44a5f32c317ed06":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","3a8056af8c4a0231c2291077461a84e838e8c12e743d034fbf886a129494d474":"*macros*(9):13","78d79d19cf0b65226f2e85c6320a095520dd28b892e92552eb75680681d89206_arguments":"(a b)","53cadf71ab3e0f40486e0062a0285d0abd49d62268e1c086de49332f345f59c2":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","39517e6ea5ef07f65002b4f33e61d7dc402c1f66a4520b8abfcec4f8452753d0":"prepend.clinc(4):23-prepend.clinc(4):30","f59aaec4e89071300c56f15471775eb151259e1abf02ce04f7bc95945d4db6db":"prepend.clinc(4):14","c7b89cfb9abf2c4cb212a4840b37d762f4c880b8517b0dadb0c310ded24dd86d":"prepend.clinc(4):34","source_file":"test_prepend.clsp","35d2775f75f241d5134e28770c0b9113d64f7fad6e1178899cf93227c4e83ba4":"prepend.clinc(4):14","c4cef5b63c61fb11df3b67cb36408234ec7b97c9002cb15653b9d7b004b2c4bd":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","ed770564041c855cba149d1e6060c78d9a9b8b72755bf18c75e3de33ea4a78c7":"*macros*(9):13","89f9d68742a70b0b54cd17626d61f123782f14a2fc2ef074b0c6721e94fbb59d":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","80b185f76724c1ae194e5a11e268c917f3d9e51c147a65aebcc7c2e9ceff6c40":"test_prepend.clsp(4):12","d390be8fc0e62169431c8225ee915ea00662c05be9ff782c049ac86d3d0a7440":"*macros*(9):13","c77b3c3b64cd919e5791ba14c922e1b5fc7c402fcd7f7298d5a6c30060a1f6b9":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","a12871fee210fb8619291eaea194581cbd2531e4b23759d225f6806923f63222":"prepend.clinc(4):23-prepend.clinc(4):30","b5e944526a144d4f467d0c0df6f9a450e38e67bec4959626a11baf63d2b4d5d2":"prepend.clinc(4):23-prepend.clinc(4):30","52db9ef97986e7382ef78b8eae2dacdbb2ce823ed1396a0fb2f7f120a2b40a63":"test_prepend.clsp(4):14","d14fb9ffc28a82755bf3c63fa2ecf4b45c0506a815ed2726d059e5af470e102e":"*macros*(8):35-*macros*(8):38","__chia__main_arguments":"(X Y)","bbfaf1ff8b0f26ab8988e690d72d73a7a15f0db4bd810f2483aeac706dc845f6":"test_prepend.clsp(4):14","78d79d19cf0b65226f2e85c6320a095520dd28b892e92552eb75680681d89206_left_env":"1","f720203ee97677a8739d12745eec7cb012253c670c0240eb4d5728c0f646e357":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","74add896f7c7e53d1559c4249ea5d71cd04e0f84746df925434ed31963c9420d":"prepend.clinc(4):32","4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785459a":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","a8d5dd63fba471ebcb1f3e8f7c1e1879b7152a6e7298a91ce119a63400ade7c5":"prepend.clinc(4):37","bc5959f43bc6e47175374b6716e53c9a7d72c59424c821336995bad760d9aeb3":"prepend.clinc(3):13","9dcf97a184f32623d11a73124ceb99a5709b083721e878a16d78f596718ba7b2":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","18ad586ec1a16affa3f70278f5dca1dd99f07dabdc196ecff6373967f29ad4fa":"test_prepend.clsp(4):12","c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99":"*prims*(1):1","11904fe16d39a709fcb3cadbbb203b87cde315410d7dc29ed72f472b7427cc8b":"prepend.clinc(4):23-prepend.clinc(4):30","1e69ab8b04b2824c3fa1c4d7cb9eb9cb464fe3507ed3c153feda00fca2afb749":"*macros*(9):64-*macros*(9):67","03151c9662f0f9fc98270d58284a54e917789a677682f9619fa63c77e22f597d":"*macros*(9):13","8536aaab5cf1232394189671ea87e8570a435e77c48af7ee4888c5298ab21a10":"prepend.clinc(4):23-prepend.clinc(4):30","1babe98d1cee6b6a14b5f5d3236940f113fe8263b2bcbfaf5f3992e13f48fcc8":"prepend.clinc(4):23-prepend.clinc(4):30","2f2b9e2945827ae21eb961df0070926b5460ee4df944788649710d7e7db4eb31":"*macros*(9):10","92fc98892c58f1f36cf7b969422d98d1e96cac746a3113926a1e4a1d192c425b":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","57bfd1cb0adda3d94315053fda723f2028320faa8338225d99f629e3d46d43a9":"prepend.clinc(5):13","78d79d19cf0b65226f2e85c6320a095520dd28b892e92552eb75680681d89206":"prepend","0234e285385f27e9d196c0a62860a3b2f933710ece95fc5325649cc1ced72c93":"test_prepend.clsp(4):14","9d09d3b4894f200226c2784e1d5235deed47acebee097cde63322d439eb81237":"test_prepend.clsp(4):12","7fc37b51fc53952d7983363e1fcb535cf6f7c325f4570259d9653aa5c163676c":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","bfa3f9fa222b97f337eb69c35e17da4117f9d875d2c8b0a104d418326d71ca2a":"prepend.clinc(4):32","90d3695440786cce137dc24c6ddc72e899c4347b4f8efa26edefb001653f1439":"prepend.clinc(4):23-prepend.clinc(4):30","6a117e7a12837ecad43e5494eec3526f99489dbc040bc5b3434af888d997ee3a":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","fba696389b83bed654427856423376a2c982ad649e04f982b7b7e05e8eb89070":"test_prepend.clsp(4):4-test_prepend.clsp(4):11","6e753b4ae3f1054677ac81c874e57f9a7ad961c6999e75705171094e2e1f1129":"test_prepend.clsp(4):4-test_prepend.clsp(4):11"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/map.clinc b/resources/tests/game-referee-in-cl23/map.clinc new file mode 100644 index 000000000..40a08a200 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/map.clinc @@ -0,0 +1,17 @@ +( + (defun map-with-rest (F L R) + (if L + (c (a F (list (f L))) (map-with-rest F (r L) R)) + R + ) + ) + + (defun list-len (X) (if X (+ 1 (list-len (r X))) 0)) + + (defmac map ARGS + (if (= (list-len ARGS) 3) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) (unquote (f (r (r ARGS)))))) + (qq (map-with-rest (unquote (f ARGS)) (unquote (f (r ARGS))) ())) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/match.clinc b/resources/tests/game-referee-in-cl23/match.clinc new file mode 100644 index 000000000..d66593c55 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/match.clinc @@ -0,0 +1,12 @@ + +( + (defun match (process remaining) + (if remaining + (if (a process (list (f remaining))) + (f remaining) + (match process (r remaining)) + ) + 0 + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/max.clinc b/resources/tests/game-referee-in-cl23/max.clinc new file mode 100644 index 000000000..5ec6d54f6 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/max.clinc @@ -0,0 +1,13 @@ +( + (defun max_inner (myless best_so_far mylist) + (if (not mylist) best_so_far + (if (a myless (list best_so_far (f mylist))) + (max_inner myless (f mylist) (r mylist)) + (max_inner myless best_so_far (r mylist)) + ) + ) + ) + (defun max (myless mylist) + (max_inner myless (f mylist) (r mylist)) + ) +) diff --git a/resources/tests/game-referee-in-cl23/noncegame.clsp b/resources/tests/game-referee-in-cl23/noncegame.clsp new file mode 100644 index 000000000..54e751e2a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/noncegame.clsp @@ -0,0 +1,17 @@ +(mod (NONCE MODHASH mover_move new_validation mover_share (proof . conditions)) + +(include *standard-cl-23*) +(include assert.clinc) +(include curry-and-treehash.clinc) + +(defun check_new_validation (new_validation MODHASH NONCE) + (= new_validation (puzzle-hash-of-curried-function MODHASH (sha256 1 MODHASH) (shatree (+ NONCE 1)))) +) + +(assert + (check_new_validation new_validation MODHASH NONCE) + (= mover_move (* NONCE 2)) + (= mover_share 1) + (= proof (* NONCE 4)) + conditions) +) diff --git a/resources/tests/game-referee-in-cl23/onehandcalc.clinc b/resources/tests/game-referee-in-cl23/onehandcalc.clinc new file mode 100644 index 000000000..c939214d3 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/onehandcalc.clinc @@ -0,0 +1,147 @@ + +; ranks are 2-14 with 2 being two, 13 being king, and 14 being ace +; suits are 1-4 with no particular labelling +; takes a list of five cards (rank . suit) and returns the value of the best poker +; hand which can be made with them +; Hands are represented: +; straight flush (5 high_card) +; 4 of a kind (4 1 quad_rank kicker) +; full house (3 2 set_rank pair_rank) +; flush (3 1 3 high_card first_kicker second_kicker third_kicker fourth_kicker) +; straight (3 1 2 high_card) +; set (3 1 1 set_rank first_kicker second_kicker) +; two pair (2 2 1 high_pair_rank low_pair_rank kicker) +; pair (2 1 1 1 pair_rank first_kicker second_kicker third_kicker) +; high card (1 1 1 1 1 high_card first_kicker second_kicker third_kicker fourth_kicker) +( + (defun hand_compare (a b) + (if (= (f a) (f b)) + (if (r a) + (hand_compare (r a) (r b)) + 0 + ) + (- (* 2 (> (f a) (f b))) 1) + ) + ) + + (defun hand< (a b) + (= (hand_compare a b) -1) + ) + + (defun merge (a b) + (if (not a) + b + (if (not b) + a + (if (> (f a) (f b)) + (c (f a) (merge (r a) b)) + (c (f b) (merge a (r b))) + ) + ) + ) + ) + + ; Sorts atoms into descending order + ; This is optimized for sorting short lists + ; A more general function would return a list of lists of ascending sizes + ; to be merged + (defun atomsort ((@ firstpos (first @ secondpos (second @ thirdpos (third . remaining))))) + (if firstpos + (if secondpos + (if thirdpos + (assign-lambda + mylist + (if (> first second) + (if (> second third) + (list first second third) + (if (> first third) + (list first third second) + (list third first second) + ) + ) + (if (> first third) + (list second first third) + (if (> second third) + (list second third first) + (list third second first) + ) + ) + ) + (merge mylist (atomsort remaining)) + ) + (if (> first second) + firstpos + (list second first) + ) + ) + firstpos + ) + 0 + ) + ) + + (defun check_flush (@ cards ((rank1 . suit1) (rank2 . suit2) (rank3 . suit3) (rank4 . suit4) (rank5 . suit5))) + (logand (= suit1 suit2) (= suit1 suit3) (= suit1 suit4) (= suit1 suit5)) + ) + + ; returns the high card of a straight or 0 if there isn't any + (defun straight_high (@ all-args (count1 count2 count3 count4 count5 rank1 rank2 rank3 rank4 rank5)) + (if (not (= count1 1)) + 0 + (= rank5 (- rank1 4)) + rank1 + (= rank1 14) + (* (= rank2 5) 5) + 0 + ) + ) + + (defun flatten_card ((rank . suit)) + (logior (lsh rank 4) suit) + ) + + (defun unflatten_card (my_card) + (c (lsh my_card -4) (logand my_card 15)) + ) + + (defun group_by_count_inner (items last count) + (if (not items) + (list (flatten_card (c count last))) + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (c (flatten_card (c count last)) (group_by_count_inner (r items) (f items) 1)) + ) + ) + ) + + (defun group_by_count (items) + (group_by_count_inner items (f items) 0) + ) + + (defun ranks_of_hand (count1 count2 count3 count4 count5 . ranks) + ranks + ) + + (defun onehandcalc ((@ cards ((card1rank . card1suit) (card2rank . card2suit) (card3rank . card3suit) + (card4rank . card4suit) (card5rank . card5suit)))) + (assign-lambda + ranks (atomsort (list card1rank card2rank card3rank card4rank card5rank)) + raw_groups (atomsort (group_by_count ranks)) + hand (map (lambda (x) (lsh x -4)) raw_groups (map (lambda (x) (logand x 15)) raw_groups)) + shigh (straight_high &rest hand) + (if shigh + (if (check_flush &rest cards) + (list 5 shigh) + (if (logior (= (f hand) 4) (logand (= (f hand) 3) (= (f (r hand)) 2))) + hand + (list 3 1 2 shigh) + ) + ) + (if (logand (check_flush &rest cards) (logior (< (f hand) 3) (logand (= (f hand) 3) (< (f (r hand)) 2)))) + (list 3 1 3 (ranks_of_hand &rest hand)) + hand + ) + ) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/partition.clinc b/resources/tests/game-referee-in-cl23/partition.clinc new file mode 100644 index 000000000..8c8c268f6 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/partition.clinc @@ -0,0 +1,15 @@ +( + (defun partition_inner (matched not-matched F L) + (if L + (if (a F (list (f L))) + (partition_inner (c (f L) matched) not-matched F (r L)) + (partition_inner matched (c (f L) not-matched) F (r L)) + ) + (c matched not-matched) + ) + ) + + (defun partition (F L) + (partition_inner () () F L) + ) +) diff --git a/resources/tests/game-referee-in-cl23/permutations.clinc b/resources/tests/game-referee-in-cl23/permutations.clinc new file mode 100644 index 000000000..9664c6aff --- /dev/null +++ b/resources/tests/game-referee-in-cl23/permutations.clinc @@ -0,0 +1,21 @@ +( + (defun permutations_inner (pre post agg) + (if (not post) + agg + (assign + myatom (f post) + newrest (r post) + (map (lambda ((& myatom) x) (c myatom x)) + (permutations (prepend pre newrest)) + (permutations_inner (c myatom pre) newrest agg) + ) + ) + ) + ) + (defun permutations (vals) + (if vals + (permutations_inner 0 vals 0) + (q ()) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/prefix.clinc b/resources/tests/game-referee-in-cl23/prefix.clinc new file mode 100644 index 000000000..0f7ee746a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/prefix.clinc @@ -0,0 +1,15 @@ +( + (defun compile-list (args) + (if args + (if (r args) + ;; We have at least 2 things left... recurse once. + (qq (c (unquote (f args)) (unquote (compile-list (r args))))) + ;; This is the last item, so we return it whole (improper list form). + (qq (unquote (f args))) + ) + 0 + ) + ) + + (defmac prefix ARGS (compile-list ARGS)) +) diff --git a/resources/tests/game-referee-in-cl23/prepend.clinc b/resources/tests/game-referee-in-cl23/prepend.clinc new file mode 100644 index 000000000..2ea293409 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/prepend.clinc @@ -0,0 +1,8 @@ +( + (defun prepend (a b) + (if a + (c (f a) (prepend (r a) b)) + b + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/print.clinc b/resources/tests/game-referee-in-cl23/print.clinc new file mode 100644 index 000000000..95d459b36 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/print.clinc @@ -0,0 +1,3 @@ +( + (defun print (R P) (if (all "$print$" R P) P P)) +) diff --git a/resources/tests/game-referee-in-cl23/range.clinc b/resources/tests/game-referee-in-cl23/range.clinc new file mode 100644 index 000000000..dc1e61ca3 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/range.clinc @@ -0,0 +1,11 @@ +( + (defun range_inner (next final) + (if (= next final) + 0 + (c next (range_inner (+ next 1) final)) + ) + ) + (defun range (i) + (range_inner 0 i) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/reduce.clinc b/resources/tests/game-referee-in-cl23/reduce.clinc new file mode 100644 index 000000000..3251c79a7 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/reduce.clinc @@ -0,0 +1,10 @@ + +( + ; From here to the meat should be in a standard library + (defun reduce (fun lst init) + (if lst + (reduce fun (r lst) (a fun (list (f lst) init))) + init + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/referee.clsp b/resources/tests/game-referee-in-cl23/referee.clsp new file mode 100644 index 000000000..df7545e3b --- /dev/null +++ b/resources/tests/game-referee-in-cl23/referee.clsp @@ -0,0 +1,83 @@ + +; Adjudicates a two player turn based game +; MOVE, VALIDATION_HASH and MOVER_SHARE were all accepted optimistically from the last move +; Both VALIDATION_HASH values are a sha256 of a validation program hash and the shatree of a state +; The next validation program hash may be nil which means no futher moves are allowed +; MOVER_SHARE is how much the mover will get if they fold/accept +; MOD_HASH should be the shatree of referee itself +; NONCE is for anti-replay prevention +; If action is timeout args is nil +; If action is accuse args is (state validation_program mover_puzzle solution evidence) +; If action is move args is (new_move new_validation_info_hash new_mover_share mover_puzzle solution) +; validation programs get passed this: +; ((last_move next_validation_hash my_share me_hash my_puzzle_hash opponent_puzzle_hash +; amount timeout max_move_size referee_hash) +; state me mover_puzzle solution evidence) +(mod (@ all_args ((MOVE VALIDATION_INFO_HASH MOVER_SHARE PREVIOUS_VALIDATION_INFO_HASH + MOVER_PUZZLE_HASH WAITER_PUZZLE_HASH + @ constants (AMOUNT TIMEOUT MAX_MOVE_SIZE MOD_HASH NONCE)) . args)) + (include *standard-cl-23*) + ; This should be a bulk import from a standard library + (include assert.clinc) + (include curry.clinc) + (include match.clinc) + (include shatree.clinc) + (include prefix.clinc) + (include condition_codes.clinc) + + (defun <= (A B) (not (> A B))) + (defun >= (A B) (not (> B A))) + (defun concat (A B) + (if A + (c (f A) (concat (r A) B)) + B + ) + ) + + (if (not args) + ; timeout + (list + (list ASSERT_SECONDS_RELATIVE TIMEOUT) + (i MOVER_SHARE (list CREATE_COIN MOVER_PUZZLE_HASH MOVER_SHARE) (list 1)) + (i (- amount MOVER_SHARE) (list CREATE_COIN WAITER_PUZZLE_HASH (- amount MOVER_SHARE)) (list 1)) + ) + (l (f (r args))) + ; accuse + (assign + (previous_state previous_validation_program mover_puzzle solution) args + previous_validation_program_hash (shatree previous_validation_program) + (assert + (= MOVER_PUZZLE_HASH (shatree mover_puzzle)) + (= PREVIOUS_VALIDATION_INFO_HASH (sha256 previous_validation_program_hash (shatree + previous_state))) + ; usually returns the conditions verbatim + (concat (a previous_validation_program (c previous_validation_program_hash all_args)) + (a mover_puzzle solution)) + ) + ) + ; move + (assign + (new_move new_validation_info_hash new_mover_share mover_puzzle solution) args + new_puzzle_hash (curry_hashes MOD_HASH (shatree (list + new_move new_validation_info_hash new_mover_share + VALIDATION_INFO_HASH WAITER_PUZZLE_HASH MOVER_PUZZLE_HASH &rest constants))) + conditions (a mover_puzzle solution) + (assert + PREVIOUS_VALIDATION_INFO_HASH + (<= (strlen new_move) MAX_MOVE_SIZE) + (<= new_mover_share AMOUNT) + (>= new_mover_share 0) + (logior (not new_validation_info_hash) (= 32 (strlen new_validation_info_hash))) + (= MOVER_PUZZLE_HASH (shatree mover_puzzle)) + ; Check that the child output is made + (match + (lambda ((& new_puzzle_hash AMOUNT) (condname arg1 arg2)) + (logand (= condname CREATE_COIN) (= arg1 new_puzzle_hash) (= arg2 AMOUNT)) + ) + conditions + ) + conditions + ) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/relops.clinc b/resources/tests/game-referee-in-cl23/relops.clinc new file mode 100644 index 000000000..ea5d52184 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/relops.clinc @@ -0,0 +1,5 @@ +( + (defun-inline >= (A B) (not (> B A))) + (defun-inline <= (A B) (not (> A B))) + (defun-inline < (A B) (>= B A)) +) diff --git a/resources/tests/game-referee-in-cl23/reverse.clinc b/resources/tests/game-referee-in-cl23/reverse.clinc new file mode 100644 index 000000000..389963ee9 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/reverse.clinc @@ -0,0 +1,11 @@ +( + (defun reverse_inner (reversed rest) + (if rest + (reverse_inner (c (f rest) reversed) (r rest)) + reversed + ) + ) + (defun reverse (vals) + (reverse_inner 0 vals) + ) +) diff --git a/resources/tests/game-referee-in-cl23/rockpaperscissorsa.clsp b/resources/tests/game-referee-in-cl23/rockpaperscissorsa.clsp new file mode 100644 index 000000000..a7d5113a9 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/rockpaperscissorsa.clsp @@ -0,0 +1,18 @@ +(mod (((alice_image new_validation_hash)) conditions) + (include *standard-cl-22*) + (include assert.clinc) + (include curry.clinc) + (include shatree.clinc) + (compile-file rockpaperscissorsb rockpaperscissorsb.clsp) + (defconst bhash (shatree rockpaperscissorsb)) + + (assert + (not + (all + (= new_validation_hash (sha256 bhash (shatree alice_image))) + (= (len alice_image) 32) + ) + ) + conditions + ) +) diff --git a/resources/tests/game-referee-in-cl23/rockpaperscissorsb.clsp b/resources/tests/game-referee-in-cl23/rockpaperscissorsb.clsp new file mode 100644 index 000000000..8c673c89c --- /dev/null +++ b/resources/tests/game-referee-in-cl23/rockpaperscissorsb.clsp @@ -0,0 +1,20 @@ + +(mod (((bob_move new_validation_hash) (ALICE_IMAGE)) conditions) + + (include *standard-cl-22*) + (include assert.clinc) + (include curry.clinc) + (include shatree.clinc) + (compile-file rockpaperscissorsc "rockpaperscissorsc.clsp") + (defconst chash (shatree rockpaperscissorsc)) + + (assert + (not + (all + (= new_validation (sha256 chash (shatree (list ALICE_IMAGE bob_move)))) + (= (len bob_move) 1) + ) + ) + conditions + ) +) diff --git a/resources/tests/game-referee-in-cl23/rockpaperscissorsc.clsp b/resources/tests/game-referee-in-cl23/rockpaperscissorsc.clsp new file mode 100644 index 000000000..91876cf67 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/rockpaperscissorsc.clsp @@ -0,0 +1,27 @@ +(mod (((alice_preimage new_validation_hash alice_share junk1 junk2 total) (ALICE_IMAGE BOB_MOVE)) conditions) + (include *standard-cl-22*) + (include assert.clinc) + (include curry.clinc) + + (assert + (not + (all + (not new_validation_hash) + (= ALICE_IMAGE (sha256 alice_preimage)) + (= alice_share + (assign + (junk3 result) (divmod (- alice_preimage BOB_MOVE) 3) + (if (not result) + (/ total 2) + (if (= result 2) + 0 + total + ) + ) + ) + ) + ) + ) + conditions + ) +) diff --git a/resources/tests/game-referee-in-cl23/shatree.clinc b/resources/tests/game-referee-in-cl23/shatree.clinc new file mode 100644 index 000000000..05bdb2699 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/shatree.clinc @@ -0,0 +1,11 @@ +( + ;; hash a tree + ;; This is used to calculate a puzzle hash given a puzzle program. + (defun shatree + (TREE) + (if (l TREE) + (sha256 2 (shatree (f TREE)) (shatree (r TREE))) + (sha256 1 TREE) + ) + ) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/slice.clinc b/resources/tests/game-referee-in-cl23/slice.clinc new file mode 100644 index 000000000..2c98a09c5 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/slice.clinc @@ -0,0 +1,10 @@ + +( + ; returns the first count elements of mylist + (defun slice (mylist count) + (if (print (list "slice inputs" nylist count) (not count)) + 0 + (c (f mylist) (slice (r mylist) (- count 1))) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/slice_runner.clsp b/resources/tests/game-referee-in-cl23/slice_runner.clsp new file mode 100644 index 000000000..3bbfebf7d --- /dev/null +++ b/resources/tests/game-referee-in-cl23/slice_runner.clsp @@ -0,0 +1,6 @@ +(mod (list n) + (include *standard-cl-23*) + (include slice.clinc) + + (slice list n) + ) diff --git a/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clsp b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clsp new file mode 100644 index 000000000..1ce6dfd12 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clsp @@ -0,0 +1,28 @@ +(mod () + (include *standard-cl-23*) + (include print.clinc) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include deep_compare.clinc) + + (map + (lambda ((want_cmp_val cmp_a cmp_b)) + (= (deep_compare cmp_a cmp_b) want_cmp_val) + ) + (q + (0 0 0) + (-1 () (1 14 5 4 3 2)) + (1 (1 14 5 4 3 2) ()) + (-1 "X" (1 2)) + (1 (1 2) "X") + (0 (3 2) (3 2)) + (-1 (3 1) (3 3)) + (1 (3 3) (3 1)) + (-1 (1 1) (2 1)) + (1 (3 1) (2 2)) + (-1 (2 2) (3 1)) + ) + ) + ) diff --git a/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clvm.hex b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clvm.hex new file mode 100644 index 000000000..cb3eb0bf7 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff0e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ffff01ffff80ff80ff8080ffff81ffff80ffff01ff0eff05ff04ff03ff028080ffff01ffff01ff0eff05ff04ff03ff0280ff8080ffff81ffff58ffff01ff028080ffff01ffff01ff0280ff5880ffff80ffff03ff0280ffff03ff028080ffff81ffffff03ff0180ffff03ff038080ffff01ffff03ff0380ffff03ff018080ffff81ffffff01ff0180ffff02ff018080ffff01ffff03ff0180ffff02ff028080ffff81ffffff02ff0280ffff03ff01808080ffff04ffff0180ff808080808080ffff04ffff01ffffff02ffff03ff0bffff01ff02ffff01ff04ffff02ff05ffff04ffff05ff0b80ffff01808080ffff02ff08ffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ff80808080808080ff0180ffff01ff02ffff0117ff018080ff0180ff02ffff03ffff07ff0580ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff02ff0affff04ff02ffff04ffff06ff0180ffff04ffff02ff0cffff04ff02ffff04ffff05ff0580ffff04ffff05ff0b80ff8080808080ff8080808080ff0180ffff01ff02ffff01ff0101ff018080ff0180ff0180ffff01ff02ffff01ff02ffff03ffff07ff0b80ffff01ff02ffff01ff0181ffff0180ffff01ff02ffff01ff02ffff03ffff15ff05ff0b80ffff01ff02ffff01ff0101ff0180ffff01ff02ffff01ff11ffff0180ffff15ff0bff058080ff018080ff0180ff018080ff0180ff018080ff0180ffff02ffff03ff0bffff01ff02ffff010bff0180ffff01ff02ffff01ff02ff0cffff04ff02ffff04ffff06ff0980ffff04ffff06ff1580ff8080808080ff018080ff0180ff09ffff02ff0cffff04ff02ffff04ff2bffff04ff5bff8080808080ff1380ff018080 diff --git a/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.sym b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.sym new file mode 100644 index 000000000..51cab0f08 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_deep_compare.sym @@ -0,0 +1 @@ +{"026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_left_env": "1", "__chia__main_arguments": "()", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_arguments": "(a b)", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_left_env": "1", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_left_env": "1", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743_arguments": "((a_$_354 b_$_355) inner_result_$_356)", "source_file": "smoke_test_deep_compare.clsp", "d9f6d93919b2fb79bc296ac80d73b5c48bf044e457f0f678b210f990efeea743": "letbinding_$_373", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160": "lambda_$_372", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b_arguments": "(F L R)", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687_left_env": "1", "026e28eecfeb07594300bd6c3bce34bd4fe340a189ddd5312c7361e242b52160_arguments": "(() (want_cmp_val_$_369 cmp_a_$_370 cmp_b_$_371))", "4fd7e0dfbd7ac5775e6d61670f548dc35ff62a1a4b14f2f3efe09d8b39e6988b": "map-with-rest", "a08c534dd3a89e22a8fadaa027c6b9a8dd4f9a00b72c315821703d8ee1c8f687": "deep_compare"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/smoke_test_permutations.clsp b/resources/tests/game-referee-in-cl23/smoke_test_permutations.clsp new file mode 100644 index 000000000..cced719e1 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_permutations.clsp @@ -0,0 +1,9 @@ +(mod (X) + (include *standard-cl-23*) + (include map.clinc) + (include prepend.clinc) + (include print.clinc) + (include permutations.clinc) + + (permutations X) + ) diff --git a/resources/tests/game-referee-in-cl23/smoke_test_permutations.clvm.hex b/resources/tests/game-referee-in-cl23/smoke_test_permutations.clvm.hex new file mode 100644 index 000000000..2f159ecbb --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff1effff04ff02ffff04ff05ff80808080ffff04ffff01ffffff02ffff03ff0bffff01ff04ffff02ff05ffff04ff13ff808080ffff02ff08ffff04ff02ffff04ff05ffff04ff1bffff04ff17ff80808080808080ffff011780ff0180ff02ffff03ff05ffff01ff04ff09ffff02ff0cffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff02ff08ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff1680ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff13ff808080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff1effff04ff02ffff04ffff02ff0cffff04ff02ffff04ff05ffff04ff1bff8080808080ff80808080ffff04ffff02ff0affff04ff02ffff04ffff04ff13ff0580ffff04ff1bffff04ff17ff808080808080ff808080808080ffff011780ff0180ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ff0affff04ff02ffff04ff80ffff04ff05ffff04ff80ff808080808080ffff01ff01ff808080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl23/smoke_test_permutations.sym b/resources/tests/game-referee-in-cl23/smoke_test_permutations.sym new file mode 100644 index 000000000..f734f8249 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_permutations.sym @@ -0,0 +1 @@ +{"0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_247", "b97201305d0509980d3aa464611b7611b318739af0f2c4c459655f4e73510908_left_env": "1", "__chia__main_arguments": "(X)", "cad9d5be9f4271aab321579b5a3e8962ff95116798a47815da87f7e9ee9120c5": "map-with-rest", "28eb6a7a256c7907517678a492a10229cdcd605e4f14a9ef64a47291f879362e_left_env": "1", "source_file": "smoke_test_permutations.clsp", "cad9d5be9f4271aab321579b5a3e8962ff95116798a47815da87f7e9ee9120c5_arguments": "(F L R)", "817255a0bcf54eea9edf591ee53057239faf249b4ff7a970f0017eee3b89ed59_arguments": "(pre post agg)", "28eb6a7a256c7907517678a492a10229cdcd605e4f14a9ef64a47291f879362e_arguments": "(vals)", "b97201305d0509980d3aa464611b7611b318739af0f2c4c459655f4e73510908": "prepend", "cad9d5be9f4271aab321579b5a3e8962ff95116798a47815da87f7e9ee9120c5_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_242) x_$_244)", "817255a0bcf54eea9edf591ee53057239faf249b4ff7a970f0017eee3b89ed59": "permutations_inner", "b97201305d0509980d3aa464611b7611b318739af0f2c4c459655f4e73510908_arguments": "(a b)", "28eb6a7a256c7907517678a492a10229cdcd605e4f14a9ef64a47291f879362e": "permutations", "817255a0bcf54eea9edf591ee53057239faf249b4ff7a970f0017eee3b89ed59_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/smoke_test_sort.clsp b/resources/tests/game-referee-in-cl23/smoke_test_sort.clsp new file mode 100644 index 000000000..ad5899da0 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_sort.clsp @@ -0,0 +1,11 @@ +(mod (X) + (include *standard-cl-23*) + (include prepend.clinc) + (include sort.clinc) + (include assert.clinc) + (include map.clinc) + (include reverse.clinc) + (include print.clinc) + + (sort (lambda (a b) (> b a)) X) + ) diff --git a/resources/tests/game-referee-in-cl23/smoke_test_sort.clvm.hex b/resources/tests/game-referee-in-cl23/smoke_test_sort.clvm.hex new file mode 100644 index 000000000..476b5f74e --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff12ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff3e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff018080ffff04ffff0101ffff0180808080ffff0180808080ffff04ff05ff8080808080ffff04ffff01ffffffff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff10ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff02ffff03ff05ffff01ff02ffff01ff02ff18ffff04ff02ffff04ffff06ff0580ffff04ff17ffff04ffff04ffff05ff0580ff0b80ff808080808080ff0180ffff01ff02ffff01ff06ff0380ff018080ff0180ffff02ff18ffff04ff02ffff04ff05ffff01ff80ff8080808080ffff02ffff03ffff20ff0b80ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff17ff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff20ff1780ffff01ff02ffff01ff02ff10ffff04ff02ffff04ffff02ff2effff04ff02ffff04ff2fff80808080ffff04ff0bff8080808080ff0180ffff01ff02ffff01ff02ffff03ffff02ff05ffff04ffff05ff0b80ffff04ffff05ff1780ffff0180808080ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ffff06ff0b80ffff04ff17ffff04ffff04ffff05ff0b80ff2f80ff80808080808080ff0180ffff01ff02ffff01ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ffff06ff1780ffff04ffff04ffff05ff1780ff2f80ff80808080808080ff018080ff0180ff018080ff0180ff018080ff0180ff02ff2cffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff01ff80808080808080ffffff02ffff03ff0bffff01ff02ffff01ff02ffff03ffff06ff0b80ffff01ff02ffff01ff02ff2affff04ff02ffff04ffff06ff0180ffff04ffff02ff14ffff04ff02ffff04ff0bff80808080ff8080808080ff0180ffff01ff02ffff010bff018080ff0180ff0180ffff01ff02ffff01ff0180ff018080ff0180ffff02ff3affff04ff02ffff04ff03ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff12ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff3cffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ffff03ff0bffff01ff02ffff01ff02ff16ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ffff02ff16ffff04ff02ffff04ff80ffff04ff05ff8080808080ff15ff17ff0b80ff018080 diff --git a/resources/tests/game-referee-in-cl23/smoke_test_sort.sym b/resources/tests/game-referee-in-cl23/smoke_test_sort.sym new file mode 100644 index 000000000..a4c6667e3 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/smoke_test_sort.sym @@ -0,0 +1 @@ +{"b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_arguments": "(myless a b)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140": "reverse", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa": "merge", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b": "lambda_$_528", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_left_env": "1", "source_file": "smoke_test_sort.clsp", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_arguments": "(mylist)", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_left_env": "1", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1_arguments": "(myless A B agg)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_arguments": "((myless_$_506 mylist_$_507) (a_$_508 b_$_509))", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_arguments": "(((myless_$_506 mylist_$_507) (a_$_508 b_$_509)) sa_$_510 sb_$_511)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4_left_env": "1", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3_arguments": "(@ everything (rest aggl aggr))", "fa9304ef33f250463c38ac3368ad79c5416173e5a666c6571e9b4c5d8b983da1": "merge_inner", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8": "prepend", "95e75b36710d3038b1cfe847cc61158c78d91e4d6db6757217c8b32ac4ae13b3": "split_inner", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_left_env": "1", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53": "split", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47_left_env": "1", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3": "sort", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_arguments": "(vals)", "b8edc250e5666a96397652bb34bdc9979fcd8df7f5aec90e481b7ae4234525aa_left_env": "1", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_left_env": "1", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_left_env": "1", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_left_env": "1", "6336806e19a49e9e91a62932f741d94eeca9a3656f35ecf39bc22e15d9940d53_left_env": "1", "__chia__main_arguments": "(X)", "f51796fc523809b04629ca42cffbb3514471eade8cd7d6908f3015f535a97de4": "letbinding_$_529", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299": "reverse_inner", "9d8df0b4587c62404485833b9a811fe717b4f9eb3ff4a11a7806e7fd07a1c5f8_arguments": "(a b)", "1b7d3888612a5d795887e5e192e68b15536e0e4c08e19324569a576ff06c6299_arguments": "(reversed rest)", "a3ddf8cdd53afc8bcdd3082f709b5f66156f31f8a56e603da27b4e382a68b9f3_arguments": "(myless mylist)", "107eecc0e2d1b059c660f3c81d6e61dd2fc7f71d4f446067132a09d395202140_left_env": "1", "842642e018168c91bd70ba0be54c311ce3947fe0ce5e418f6a1c88289e11c84b_arguments": "(() a_$_526 b_$_527)", "aa2a43f5d1d2ed44bd135ee807b27cb33eea736d2e50b2787c5fd4100f128f47": "letbinding_$_530"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/sort.clinc b/resources/tests/game-referee-in-cl23/sort.clinc new file mode 100644 index 000000000..a9afed46a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/sort.clinc @@ -0,0 +1,44 @@ + +( + (defun split_inner (@ everything (rest aggl aggr)) + (if rest + (split_inner (r rest) aggr (c (f rest) aggl)) + (r everything) + ) + ) + (defun split (mylist) + (split_inner mylist 0 0) + ) + (defun merge_inner (myless A B agg) + ; this should use continued if + (if (not A) + (prepend (reverse agg) B) + (if (not B) + (prepend (reverse agg) A) + (if (a myless (list (f A) (f B))) + (merge_inner myless (r A) B (c (f A) agg)) + (merge_inner myless A (r B) (c (f B) agg)) + ) + ) + ) + ) + (defun merge (myless a b) + (merge_inner myless a b 0) + ) + (defun sort-split (myless (a b)) + (merge myless (sort myless a) (sort myless b)) + ) + (defun sort (myless mylist) + (if mylist + (if (r mylist) + (assign (a b) (split mylist) + sa (sort myless a) + sb (sort myless b) + (merge myless sa sb) + ) + mylist + ) + () + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/space_poker.clinc b/resources/tests/game-referee-in-cl23/space_poker.clinc new file mode 100644 index 000000000..ee4d7647b --- /dev/null +++ b/resources/tests/game-referee-in-cl23/space_poker.clinc @@ -0,0 +1,214 @@ +( +(include spacehandcalc.clinc) +(include assert.clinc) + +(defconst END_HASH (shatree space_poker_end)) +(defconst CONTINUE_RIVER (curry space_poker_continue_street END_HASH)) +(defconst CONTINUE_RIVER_HASH (shatree CONTINUE_RIVER)) +(defconst START_RIVER (curry space_poker_start_street CONTINUE_RIVER_HASH)) +(defconst START_RIVER_HASH (shatree START_RIVER)) +(defconst CONTINUE_TURN (curry space_poker_continue_street START_RIVER_HASH)) +(defconst CONTINUE_TURN_HASH (shatree CONTINUE_TURN)) +(defconst START_TURN (curry space_poker_start_street CONTINUE_TURN_HASH)) +(defconst START_TURN_HASH (shatree START_TURN)) +(defconst CONTINUE_FLOP (curry space_poker_continue_street START_TURN_HASH)) +(defconst CONTINUE_FLOP_HASH (shatree CONTINUE_FLOP)) +(defconst START_FLOP (curry space_poker_start_street CONTINUE_FLOP_HASH)) +(defconst START_FLOP_HASH (shatree START_FLOP)) +(defconst CONTINUE_PREFLOP (curry space_poker_continue_street START_FLOP_HASH)) +(defconst CONTINUE_PREFLOP_HASH (shatree CONTINUE_PREFLOP)) +(defconst START_PREFLOP (curry space_poker_start_street CONTINUE_PREFLOP_HASH)) +(defconst START_PREFLOP_HASH (shatree START_PREFLOP)) +(defconst BHASH (shatree space_poker_b)) +(defconst AHASH (shatree space_poker_a)) + + +; Bob challenging +; state is minraise +; move is Alice image5 +; evidence is nil +; split should be Alice keeps an ante +(defun space_poker_a (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + state me mover_puzzle solution evidence) + (assert + (not + (all + (= (strlen move) 32) + (= next_validation_hash (sha256 BHASH (shatree (list state move)))) + (= mover_share (- (/ amount 2) state)) + ) + ) + 0 + ) +) + +; Alice challenging +; state is minraise and Alice image5 +; move is Bob image4 +; evidence is nil +; split should be Bob keeps an ante +(defun space_poker_b (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (minraise alice_image5) me mover_puzzle solution evidence) + (assert + (not + (all + (= (strlen move) 32) + (= next_validation_hash (sha256 START_FLOP_HASH (shatree (list minraise (+ minraise minraise) + (- (/ amount 2) minraise) alice_image5 move)))) + (= mover_share (- (/ amount 2) state)) + ) + ) + 0 + ) +) + +; Elsa challlenging +; state is minraise, amount in pot, Anna's stack size, Anna's imageN, and Elsa's imageN-1 +; move is Anna's imageN-1 and raise amount (0 for check) +; split should be Anna keeps new amount in pot +(defun space_poker_start_street (NEXT_PROGRAM mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (minraise pot_size anna_stack anna_imagen elsa_imagen-1) me mover_puzzle solution evidence) + (assign + anna_imagen-1 (substr move 0 32) + raise_amount (substr move 32 (strlen move)) + (assert + (not + (all + (= (sha256 anna_imagen-1) anna_imagen) + (>= raise_amount minraise) + (<= raise_amount anna_stack) + (= next_validation_hash (sha256 NEXT_PROGRAM (shatree (list minraise (+ pot_size raise_amount) + (- (- amount anna_stack) pot_size) elsa_imagen-1 anna_imagen-1)))) + (= mover_share (+ raise_amount (- amount anna_stack))) + ) + ) + 0 + ) + ) +) + +; Elsa challenging +; state is minraise, amount in pot, raise amount, Anna's stack size, Anna's imageN, and Elsa's imageN +; move is raise or Anna's imageN-1 +; split should be Anna keeps new amount in pot +(defun space_poker_continue_street (NEXT_PROGRAM mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (minraise pot_size raise_amount anna_stack_size anna_imagen elsa_imagen) me mover_puzzle solution evidence) + (if (= (strlen move) 32) + (assert + (not + (all + (= (sha256 move) anna_imagen) + (= next_validation_hash (sha256 NEXT_PROGRAM (shatree (list minraise (+ pot_size raise_amount) + (- (- amount anna_stack_size) pot_size) elsa_imagen move)))) + (= mover_share (+ raise_amount (- amount anna_stack_size))) + ) + ) + 0 + ) + (assert + (not + (all + (<= minraise move) + (>= anna_stack_size move) + (= next_validation_hash (sha256 mod_hash (shatree (list minraise (+ pot_size raise_amount move) + (- (- amount anna_stack_size) pot_size) elsa_imagen anna_imagen)))) + ) + ) + 0 + ) + ) +) + +(defun extract_one_card (vala valb) + (+ 2 (% (sha256 (logxor vala valb)) 13)) +) + +(defun extract_hole_cards (vala valb pre) + (assign + v1 (% (sha256 (logxor vala valb) (* 13 13))) + (card1 . card2) (divmod v1 13) + (list (+ card1 2) (+ card2 2) &rest pre) + ) +) + +(defun extract_three_cards (vala valb) + (assign + v1 (% (sha256 (logxor vala valb) (* 13 13 13))) + (card1 . v2) (divmod v1 (* 13 13)) + (card2 . card3) (divmod v2 13) + (list (+ card1 2) (+ card2 2) (+ card3 2)) + ) +) + +(defun select_cards (card_list selections) + (assign + (pos1 . pos2) (divmod selections 7) + (assert + (> pos2 pos1) + (>= 0 pos1) + (select_cards_inner 0 (list pos1 pos2 100) card_list) + ) + ) +) + +(defun select_cards_inner (mypos poslist cards) + (if (not cards) + 0 + (if (= mypos (f poslist)) + (select_cards_inner (+ 1 mypos) (r poslist) (r cards)) + (c (f cards) (select_cards_inner (+ 1 mypos) poslist (r cards))) + ) + ) +) + +(defun amount_due (pot_size result) + (if (not result) + (/ pot_size 2) + (= result 1) + pot_size + 0 + ) +) + +; Elsa challenging +; state is minraise, amount in pot, Anna's stack size, Anna's image1 and Elsa's preimage +; move is Anna's preimage and card selection +; evidence is Elsa's card selection +; split should send pot to winner of the hand or even split if chop +(defun space_poker_end (mod_hash (move next_validation_hash mover_share previous_validation_hash + mover_puzzle_hash waiter_puzzle_hash amount timeout max_move_size referee_hash) + (minraise pot_size anna_stack_size anna_image1 elsa_preimage) me mover_puzzle solution evidence) + (assign + anna_preimage (substr move 0 32) + anna_card_selection (substr move 32 33) + elsa_image1 (sha256 elsa_preimage) + elsa_image2 (sha256 elsa_image1) + elsa_image3 (sha256 elsa_image2) + elsa_image4 (sha256 elsa_image3) + anna_image2 (sha256 anna_image1) + anna_image3 (sha256 anna_image2) + anna_image4 (sha256 anna_image3) + table_cards (list (extract_one_card anna_image2 elsa_image2) (extract_one_card anna_image1 elsa_image1) &rest + (extract_three_cards anna_image3 elsa_image3)) + anna_all_cards (extract_hole_cards anna_preimage elsa_image4 table_cards) + anna_hand (spacehandcalc (select_cards anna_all_cards anna_card_selection)) + elsa_all_cards (extract_hole_cards elsa_preimage anna_image4 table_cards) + elsa_hand (spacehandcalc (select_cards elsa_all_cards evidence)) + (assert + (not + (all + (= (sha256 anna_preimage anna_image1)) + (= next_validation_hash 0) + (>= mover_share (+ (- (- amount anna_stack_size) pot_size) + (amount_due pot_size (hand_compare elsa_hand anna_hand)))) + ) + ) + 0 + ) + ) +) +) diff --git a/resources/tests/game-referee-in-cl23/spacehandcalc.clinc b/resources/tests/game-referee-in-cl23/spacehandcalc.clinc new file mode 100644 index 000000000..9db553972 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/spacehandcalc.clinc @@ -0,0 +1,107 @@ + +; ranks are 1-13 with 1 being two, 12 being king, and 13 being ace +; there are no suits, flushes, or ace-to-four straights +; takes a list of card ranks and returns the value of the best poker +; hand which can be made with them +; returned list is hand type followed by cards in descending order +; all sorting is done highest to lowest +( + (include sort.clinc) + (include deep_compare.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include max.clinc) + (defconstant FIVE_OF_A_KIND 8) + (defconstant FOUR_OF_A_KIND 7) + (defconstant FULL_HOUSE 6) + (defconstant STRAIGHT 5) + (defconstant THREE_OF_A_KIND 4) + (defconstant TWO_PAIR 3) + (defconstant PAIR 2) + (defconstant HIGH_CARD 1) + (defun straight_high_inner (ranks last count) + (if (not ranks) + ; at the end of the list + 0 + (if (= last (f ranks)) + ; skip identical cards + (straight_high_inner (r ranks) last count) + ; if the partial straight continues + (if (= (f ranks) (- last 1)) + (if (= count 4) + ; found a straight, add 3 to last because next and last are included + (+ last 3) + ; keep looking for a straight with the count going up by one + (straight_high_inner (r ranks) (f ranks) (+ count 1)) + ) + ; reset the count + (straight_high_inner (r ranks) (f ranks) 1) + ) + ) + ) + ) + ; returns the high card of a straight or 0 if there isn't any + ; ranks must be sorted in descending order + (defun straight_high (ranks) + (straight_high_inner (ranks (= (f ranks) 13) 0 0)) + ) + (defun group_by_count_inner (items last count) + (if (not items) + 0 + (if (= (f items) last) + (group_by_count_inner (r items) last (+ count 1)) + (assign val (group_by_count_inner (r items) (f items) 1) + (if last + (c (c count last) val) + val + ) + ) + ) + ) + ) + (defun group_by_count (items) + (group_by_count_inner items 0 0) + ) + (defun space_hand_calc_inner (cards) + (assign + rest (lambda (x) (r x)) + greater (lambda (x y) (> x y)) + ranks (sort greater cards) + sh (straight_high ranks) + max_straight (if sh + (list STRAIGHT sh) + 0 + ) + groups (sort deep> (group_by_count ranks)) + (top_count . top_card) (f groups) + (second_count . second_card) (f (r groups)) + topcards (map rest groups) + max_group (if (= top_count 1) + (c HIGH_CARD (slice topcards 5)) + (if (= top_count 2) + (if (= second_count 1) + (c PAIR (slice topcards 4)) + (c TWO_PAIR (slice topcards 3)) + ) + (if (= top_count 3) + (if (= second_count 1) + (c THREE_OF_A_KIND (slice topcards 3)) + (c FULL_HOUSE (slice topcards 2)) + ) + (if (= top_count 4) + (c FOUR_OF_A_KIND (slice topcards 2)) + (c FIVE_OF_A_KIND (slice topcards 1)) + ) + ) + ) + ) + (max deep< (list max_straight max_group)) + ) + ) + (defun space_hand_calc (cards boosted) + (assign + result (space_hand_calc_inner cards) + (list (f result) boosted (r result)) + ) + ) +) diff --git a/resources/tests/game-referee-in-cl23/spacepoker_include.clsp b/resources/tests/game-referee-in-cl23/spacepoker_include.clsp new file mode 100644 index 000000000..c0b5d9aa8 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/spacepoker_include.clsp @@ -0,0 +1 @@ +(mod () (include *standard-cl-23*) (include space_poker.clinc) ()) diff --git a/resources/tests/game-referee-in-cl23/steprun.py b/resources/tests/game-referee-in-cl23/steprun.py new file mode 100644 index 000000000..531205ac4 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/steprun.py @@ -0,0 +1,55 @@ +import os +from pathlib import Path +import binascii +import json +from clvm_tools.binutils import assemble, disassemble +from clvm_tools_rs import start_clvm_program, compose_run_function, compile_clvm +from chia.types.blockchain_format.program import Program + +def compile_module_with_symbols(include_paths,source): + path_obj = Path(source) + file_path = path_obj.parent + file_stem = path_obj.stem + target_file = file_path / (file_stem + ".clvm.hex") + sym_file = file_path / (file_stem + ".sym") + compile_result = compile_clvm(source, str(target_file.absolute()), include_paths, True) + symbols = compile_result['symbols'] + if len(symbols) != 0: + with open(str(sym_file.absolute()),'w') as symfile: + symfile.write(json.dumps(symbols)) + +def run_until_end(p): + last = None + location = None + + while not p.is_ended(): + step_result = p.step() + if step_result is not None: + last = step_result + if 'Print' in last: + to_print = last['Print'] + if 'Print-Location' in last: + print(f"{last['Print-Location']}: print {to_print}") + else: + print(f"print {to_print}") + + return last + +def diag_run_clvm(program, args, symbols): + hex_form_of_program = binascii.hexlify(bytes(program)).decode('utf8') + hex_form_of_args = binascii.hexlify(bytes(args)).decode('utf8') + symbols = json.loads(open(symbols).read()) + p = start_clvm_program(hex_form_of_program, hex_form_of_args, symbols, None, {"terse":True}) + report = run_until_end(p) + if 'Failure' in report: + raise Exception(report) + else: + return assemble(report['Final']) + +if __name__ == '__main__': + # smoke test + import sys + program = Program.fromhex(open(sys.argv[1]).read()) + args = Program.fromhex(open(sys.argv[2]).read()) + diag_run_clvm(program, args) + diff --git a/resources/tests/game-referee-in-cl23/test_detectwrap.clsp b/resources/tests/game-referee-in-cl23/test_detectwrap.clsp new file mode 100644 index 000000000..f58a57fea --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_detectwrap.clsp @@ -0,0 +1,8 @@ +(mod (rank cards) + (include *standard-cl-23*) + (include relops.clinc) + (include print.clinc) + (include detectwrap.clinc) + + (get-straight-hand rank cards) +) diff --git a/resources/tests/game-referee-in-cl23/test_handbitmap.clsp b/resources/tests/game-referee-in-cl23/test_handbitmap.clsp new file mode 100644 index 000000000..f2603b31d --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_handbitmap.clsp @@ -0,0 +1,13 @@ +(mod () + + (include *standard-cl-23*) + (include print.clinc) + (include map.clinc) + (include deep_compare.clinc) + (include handbitmap.clinc) + + (ranks_from_hand + (list ((1 . 14) (1 . 13) (1 . 12) (1 . 11) (1 . 10) (1 . 8))) + (list (12 . 1) (11 . 1) (14 . 1) (13 . 1) (10 . 1) (8 . 1)) + ) + ) diff --git a/resources/tests/game-referee-in-cl23/test_handcalc.clsp b/resources/tests/game-referee-in-cl23/test_handcalc.clsp new file mode 100644 index 000000000..92f306907 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_handcalc.clsp @@ -0,0 +1,444 @@ + +(mod () + (include *standard-cl-23*) + (include relops.clinc) + (include deep_compare.clinc) + (include assert.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include truncate.clinc) + (include map.clinc) + (include filtermap.clinc) + (include slice.clinc) + (include print.clinc) + (include partition.clinc) + (include append.clinc) + (include onehandcalc.clinc) + (include handcalc.clinc) + + (defun cards-by-bitmask (mask cards) + (if cards + (let ((next-cards (cards-by-bitmask (lsh mask -1) (r cards)))) + (if (logand 1 mask) + (c (f cards) next-cards) + next-cards + ) + ) + () + ) + ) + + (defun count-bits (mask) + (if mask + (let ((next (count-bits (lsh mask -1)))) + (if (logand mask 1) + (+ 1 next) + next + ) + ) + 0 + ) + ) + + (defun must-have-bits (N M) + (if (= (count-bits M) N) + M + (x "Mask" M "should have" N "bits") + ) + ) + + (defun must-be-len (N L) + (if (= (list-len L) N) + L + (x "List" L "should have" N "elements") + ) + ) + + (defun generate_handcalc_and_reverse_response (cards) + (assign + reversed-cards (reverse cards) + + handcalc-result (print (list "handcalc fwd result for cards" cards) (handcalc cards)) + + reverse-handcalc-result (print (list "handcalc rev result for cards" reversed-cards) (handcalc reversed-cards)) + + chosen-cards (cards-by-bitmask (must-have-bits 5 handcalc-result) cards) + + reverse-chosen-cards (cards-by-bitmask (must-have-bits 5 reverse-handcalc-result) reversed-cards) + + (c (must-be-len 5 chosen-cards) (must-be-len 5 reverse-chosen-cards)) + ) + ) + + (defun runtests_inner ((myfunc firstarg secondarg . remaining)) + (assign-lambda + (first-chosen-cards . first-rev-cards) (generate_handcalc_and_reverse_response firstarg) + + (second-chosen-cards . second-rev-cards) (generate_handcalc_and_reverse_response secondarg) + + first-ohc (print (list "first onehandcalc from " first-chosen-cards) (onehandcalc (must-be-len 5 first-chosen-cards))) + second-ohc (print (list "second onehandcalc from " second-chosen-cards) (onehandcalc (must-be-len 5 second-chosen-cards))) + + first-rev-ohc (print (list "first rev onehandcalc from " first-rev-cards) (onehandcalc (must-be-len 5 first-rev-cards))) + second-rev-ohc (print (list "second rev onehandcalc from " second-rev-cards) (onehandcalc (must-be-len 5 second-rev-cards))) + + (assert + (print (list "======== compare hands ========" first-ohc second-ohc) (a myfunc (list first-ohc second-ohc))) + (print (list "======== first equal ==========" first-ohc first-rev-ohc) (deep= first-ohc first-rev-ohc)) + (print (list "======== second equal =========" second-ohc second-rev-ohc) (deep= second-ohc second-rev-ohc)) + (if remaining + (runtests_inner remaining) + 0 + ) + ) + ) + ) + + (defun runtests tests (if tests (runtests_inner tests) ())) + + ;; Join these up when large application bug is fixed. + (runtests + ; all beats both emerge over and measure higher + ; straight flush with higher kicker ties + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 81 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 8 1)) + ; straight flushes of different suits tie + ; A1 K1 Q1 J1 T1 = A2 K2 Q2 J2 T2 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 14 2) (c 13 2) (c 12 2) (c 11 2) (c 10 2)) + ; higher straight flush beats lower straight flush + ; A1 K1 Q1 J1 T1 > 61 51 41 31 21 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 10 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; A1 K1 Q1 J1 T1 91 = A1 K1 Q1 J1 T1 + deep= + (list (c 12 1) (c 11 1) (c 14 1) (c 13 1) (c 10 1) (c 9 1)) + (list (c 14 2) (c 11 2) (c 10 2) (c 13 2) (c 12 2)) + ; lower (2-6) straight flush beats ace to four straight flush + ; 61 51 41 31 21 > A2 52 42 32 22 + deep> + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; A1 61 51 41 31 21 = 61 51 41 31 21 + deep= + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 6 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; ace to four straight flush with higher kicker ties + ; A2 52 42 32 22 61 = A1 51 41 31 21 71 + deep= + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2) (c 6 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1) (c 7 1)) + ; ace to four straight flushes of different suits tie + ; A1 51 41 31 21 = A2 52 42 32 22 + deep= + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 2) (c 5 2) (c 4 2) (c 3 2) (c 2 2)) + ; ace to four straight flush beats four of a kind + ; A1 51 41 31 21 > K1 K2 K3 K4 J1 + deep> + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; A1 A2 A3 A4 51 41 31 21 = A1 51 41 31 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + (list (c 14 1) (c 5 1) (c 4 1) (c 3 1) (c 2 1)) + ; four of a kind with higher kicker wins + ; K1 K2 K3 K4 Q1 > K1 K2 K3 K4 J1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 11 1)) + ; K1 K2 K3 K4 T1 91 = K1 K2 K3 K4 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1) (c 9 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 10 1)) + ; four of a kind with higher second kicker ties + ; K1 K2 K3 K4 Q1 J1 = K1 K2 K3 K4 Q1 T1 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 11 1)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 12 1) (c 10 1)) + ; higher four of a kind beats lower four of a kind + ; K1 K2 K3 K4 21 > 31 32 33 34 A1 + deep> + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 2 1)) + (list (c 3 1) (c 3 2) (c 3 3) (c 3 4) (c 14 1)) + ; K1 K2 K3 K4 31 32 33 34 = K1 K2 K3 K4 32 + deep= + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 1) (c 3 2) (c 3 3) (c 3 4)) + (list (c 13 1) (c 13 2) (c 13 3) (c 13 4) (c 3 2)) + ; four of a kind beats full house + ; 21 22 23 24 31 > A1 A2 A3 K1 K2 + deep> + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 3 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; four of a kind equality: 21 22 23 24 A1 A2 A3 = 21 22 23 24 A2 + deep= + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 1) (c 14 2) (c 14 3)) + (list (c 2 1) (c 2 2) (c 2 3) (c 2 4) (c 14 2)) + ; full house with higher set wins + ; 51 52 53 21 22 > 31 32 33 71 72 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 2 1) (c 2 2)) + (list (c 3 1) (c 3 2) (c 3 3) (c 7 1) (c 7 2)) + ; A1 A2 A3 K1 K2 K3 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 13 3)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house with same set and higher pair wins + ; 51 52 53 41 42 > 51 52 53 31 32 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 5 1) (c 5 2) (c 5 3) (c 3 1) (c 3 2)) + ; A1 A2 A3 K1 K2 51 52 = A1 A2 A3 K1 K2 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2) (c 5 1) (c 5 2)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 13 2)) + ; full house ties with two sets + ; 51 52 53 41 42 A1 = 51 52 53 41 42 43 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 4 3)) + ; full house beats flush + ; 51 52 53 41 42 > A1 Q1 T1 81 71 + deep> + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + (list (c 14 1) (c 12 1) (c 10 1) (c 8 1) (c 7 1)) + ; 51 52 53 41 42 A1 K1 Q1 = 51 52 53 41 42 + deep= + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2) (c 14 1) (c 13 1) (c 12 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 4 1) (c 4 2)) + ; higher flush beats lower flush + ; A1 61 51 41 31 > K1 Q1 J1 T1 81 + deep> + (list (c 14 1) (c 6 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 13 1) (c 12 2) (c 11 1) (c 10 1) (c 8 1)) + ; A1 K1 Q1 J1 81 71 = A1 K1 Q1 J1 81 + deep= + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 11 1) (c 8 1)) + ; flush with higher second card wins + ; A1 K1 51 41 31 > A1 Q1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 5 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 12 2) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher third card wins + ; A1 K1 Q1 41 31 > A1 K1 J1 T1 91 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 4 1) (c 3 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 9 1)) + ; flush with higher fourth card wins + ; A1 K1 Q1 T1 21 > A1 K1 Q1 91 81 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 2 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 9 1) (c 8 1)) + ; flush with higher fifth card wins + ; A1 K1 Q1 T1 81 > A1 K1 Q1 T1 71 + deep> + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 8 1)) + (list (c 14 1) (c 13 1) (c 12 1) (c 10 1) (c 7 1)) + ; flushes of different suits tie + ; A1 K1 J1 T1 81 = A2 K2 J2 T2 82 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1)) + (list (c 14 2) (c 13 2) (c 11 2) (c 10 2) (c 8 2)) + ; same flush with higher sixth card ties + ; A1 K1 J1 T1 81 71 = A1 K1 J1 T1 81 61 + deep= + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 7 1)) + (list (c 14 1) (c 13 1) (c 11 1) (c 10 1) (c 8 1) (c 6 1)) + ; flush beats straight + ; 71 61 51 41 21 > A1 K2 Q3 J4 T1 + deep> + (list (c 7 1) (c 6 1) (c 5 1) (c 4 1) (c 2 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + ; A1 K2 Q3 J4 T1 81 71 61 = A1 T1 81 71 61 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + (list (c 14 1) (c 10 1) (c 8 1) (c 7 1) (c 6 1)) + ; straight with higher kicker ties + ; A1 K2 Q3 J4 T1 92 = A1 K2 Q3 J4 T1 22 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 2 2)) + ; straights of different suits tie + ; A1 K2 Q3 J4 T1 = A2 K3 Q4 J1 T2 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; higher straight beats lower straight + ; A1 K2 Q3 J4 T1 > 61 52 43 34 21 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1)) + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 K2 Q3 J4 T1 92 83 = A1 K2 Q3 J4 T1 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 10 1) (c 9 2) (c 8 3)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 10 2)) + ; lower (2-6) straight beats ace to four straight + ; 61 52 43 34 21 > A1 52 43 34 21 + deep> + (list (c 6 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + ; A1 62 53 44 31 22 = 62 53 44 31 22 + deep= + (list (c 14 1) (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + (list (c 6 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight with higher kicker ties + ; A1 52 43 34 21 K2 = A1 52 43 34 21 72 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 13 2)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1) (c 7 2)) + ; ace to fours of different suits tie + ; A1 52 43 34 21 = A2 53 44 31 22 + deep= + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 2) (c 5 3) (c 4 4) (c 3 1) (c 2 2)) + ; ace to four straight beats set + ; A1 52 43 34 21 > A1 A2 A3 K1 Q2 + deep> + (list (c 14 1) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 14 3) (c 13 1) (c 12 2)) + ; A1 A2 A3 52 43 34 21 = A1 52 43 34 21 + deep= + (list (c 14 1) (c 14 2) (c 14 3) (c 5 2) (c 4 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 5 2) (c 4 3) (c 3 2) (c 2 1)) + ; higher set wins + ; 71 72 73 34 21 > 51 52 53 A4 K1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 5 1) (c 5 2) (c 5 3) (c 14 4) (c 13 1)) + ; set with higher first kicker wins + ; 71 72 73 A1 22 > 71 72 73 K1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 2 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 13 1) (c 12 2)) + ; 71 72 73 A1 K2 J3 54 43 = 71 72 73 A1 K2 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3) (c 5 4) (c 4 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + ; set with higher second kicker wins + ; 71 72 73 A1 K2 > 71 72 73 A1 Q2 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 12 2)) + ; set with higher third kicker ties + ; 71 72 73 A1 K2 Q3 = 71 72 73 A1 K2 J3 + deep= + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 12 3)) + (list (c 7 1) (c 7 2) (c 7 3) (c 14 1) (c 13 2) (c 11 3)) + ; set beats two pair + ; 71 72 73 34 21 > A1 A2 K3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 7 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 13 4) (c 12 1)) + ; two pair with higher high pair wins + ; K1 K2 33 34 21 > Q1 Q2 J3 J4 A1 + deep> + (list (c 13 1) (c 13 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 12 1) (c 12 2) (c 11 3) (c 11 4) (c 14 1)) + ; A1 A2 K1 K2 J1 J2 = A1 A2 K1 K2 J3 + deep= + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 1) (c 11 2)) + (list (c 14 1) (c 14 2) (c 13 1) (c 13 2) (c 11 3)) + ; two pair with tied higher pair and higher lower pair wins + ; K1 K2 71 72 23 > K1 K2 63 64 A1 + deep> + (list (c 13 1) (c 13 2) (c 7 1) (c 7 2) (c 2 3)) + (list (c 13 1) (c 13 2) (c 6 3) (c 6 4) (c 14 1)) + ; two pair with higher kicker wins + ; K1 K2 Q3 Q4 J1 > K1 K2 Q3 Q4 T1 + deep> + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 10 1)) + ; K1 K2 Q3 Q4 A1 T1 92 63 = K1 K2 Q3 Q4 A1 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1) (c 10 1) (c 9 2) (c 6 3)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 14 1)) + ; two pair with higher second kicker ties + ; K1 K2 Q3 Q4 J1 T2 = K1 K2 Q3 Q4 J1 92 + deep= + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 10 2)) + (list (c 13 1) (c 13 2) (c 12 3) (c 12 4) (c 11 1) (c 9 2)) + ; two pair beats pair + ; 41 42 33 34 21 > A1 A2 K3 Q4 J1 + deep> + (list (c 4 1) (c 4 2) (c 3 3) (c 3 4) (c 2 1)) + (list (c 14 1) (c 14 2) (c 13 3) (c 12 4) (c 11 1)) + ; higher pair wins + ; 71 72 53 44 31 > 61 62 A3 K4 Q1 + deep> + (list (c 7 1) (c 7 2) (c 5 3) (c 4 4) (c 3 1)) + (list (c 6 1) (c 6 2) (c 14 3) (c 13 4) (c 12 1)) + ; tied pair with higher first kicker wins + ; 91 92 A3 34 21 > 91 92 K3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 3 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 13 3) (c 12 4) (c 11 1)) + ; 21 22 A1 Q2 J3 94 81 = 21 22 A1 Q2 J3 + deep= + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3) (c 9 4) (c 8 1)) + (list (c 2 1) (c 2 2) (c 14 1) (c 12 2) (c 11 3)) + ; tied pair with higher second kicker wins + ; 91 92 A3 K4 21 > 91 92 A3 Q4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 2 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 12 4) (c 11 1)) + ; tied pair with higher third kicker wins + ; 91 92 A3 K4 Q1 > 91 92 A3 K4 J1 + deep> + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 11 1)) + ; tied pair with higher fourth kicker ties + ; 91 92 A3 K4 Q1 J2 = 91 92 A3 K4 Q1 T2 + deep= + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 11 2)) + (list (c 9 1) (c 9 2) (c 14 3) (c 13 4) (c 12 1) (c 10 2)) + ; pair beats high card + ; 21 22 33 44 51 > A1 Q2 J3 T4 91 + deep> + (list (c 2 1) (c 2 2) (c 3 3) (c 4 4) (c 5 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher high card wins + ; A1 22 33 44 61 > K1 Q2 J3 T4 81 + deep> + (list (c 14 1) (c 2 2) (c 3 3) (c 4 4) (c 6 1)) + (list (c 13 1) (c 12 2) (c 11 3) (c 10 4) (c 8 1)) + ; A1 K2 J3 T4 81 72 53 = A1 K2 J3 T4 81 + deep= + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1) (c 7 2) (c 5 3)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 8 1)) + ; higher second card wins + ; A1 K2 23 34 41 > A1 Q2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 2 3) (c 3 4) (c 4 1)) + (list (c 14 1) (c 12 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher third card wins + ; A1 K2 Q3 24 41 > A1 K2 J3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 2 4) (c 4 1)) + (list (c 14 1) (c 13 2) (c 11 3) (c 10 4) (c 9 1)) + ; higher fourth card wins + ; A1 K2 Q3 J4 31 > A1 K2 Q3 T4 91 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 3 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 10 4) (c 9 1)) + ; higher fifth card wins + ; A1 K2 Q3 J4 91 > A1 K2 Q3 J4 81 + deep> + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 8 1)) + ; higher sixth card ties + ; A1 K2 Q3 J4 91 22 = A1 K2 Q3 J4 91 82 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 2 2)) + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1) (c 8 2)) + ; high cards of different suits ties + ; A1 K2 Q3 J4 91 = A2 K3 Q4 J1 92 + deep= + (list (c 14 1) (c 13 2) (c 12 3) (c 11 4) (c 9 1)) + (list (c 14 2) (c 13 3) (c 12 4) (c 11 1) (c 9 2)) + ) +) diff --git a/resources/tests/game-referee-in-cl23/test_library_basics.py b/resources/tests/game-referee-in-cl23/test_library_basics.py new file mode 100644 index 000000000..3d42a3644 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_library_basics.py @@ -0,0 +1,130 @@ +import pytest +import random +from itertools import permutations +from hsms.streamables.program import Program +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'], 'smoke_test_deep_compare.clsp') +compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'smoke_test_sort.clsp') +sort_program = Program.from_bytes(bytes.fromhex(open('smoke_test_sort.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_sort.clsp') +test_sort_program = Program.from_bytes(bytes.fromhex(open('test_sort.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_permutations.clsp') +test_permutations_program = Program.from_bytes(bytes.fromhex(open('test_permutations.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_reverse.clsp') +test_reverse_program = Program.from_bytes(bytes.fromhex(open('test_reverse.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_prepend.clsp') +test_prepend_program = Program.from_bytes(bytes.fromhex(open('test_prepend.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_range.clsp') +test_range_program = Program.from_bytes(bytes.fromhex(open('test_range.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'smoke_test_permutations.clsp') +smoke_test_permutations_program = Program.from_bytes(bytes.fromhex(open('smoke_test_permutations.clvm.hex').read())) + +compile_module_with_symbols(['.'], 'test_handcalc.clsp') +test_handcalc_program = Program.from_bytes(bytes.fromhex(open('test_handcalc.clvm.hex').read())) + +def test_smoke_compare(): + compare_program.run(Program.to([])) + +def test_handcalc(): + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + +def proper_list_inner(result,cl): + if hasattr(cl, 'pair') and cl.pair is not None: + result.append(cl.pair[0]) + return proper_list_inner(result,cl.pair[1]) + else: + return result + +def proper_list(cl): + result = [] + return proper_list_inner(result,cl) + +def int_list(cl): + return [Program.to(x).as_int() for x in Program.to(cl).as_atom_list()] + +def de_none_list(l): + return [x if x is not None else [] for x in l] + +def with_random_lists(n,f): + for length in range(n): # 0-10 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + f(orig_list) + +def test_prepend(): + for length1 in range(5): + list_1 = list(range(length1)) + for length2 in range(length1): + prepend_result = test_prepend_program.run([Program.to(list_1[:length2]),Program.to(list_1[length2:])]) + assert list_1 == int_list(prepend_result) + +def test_reverse(): + def test_reverse_list(l): + rev_args = Program.to([l]) + reversed_result = Program.to(list(reversed(l))) + reversed_by_prog = test_reverse_program.run(rev_args) + assert reversed_result == reversed_by_prog + + with_random_lists(10,test_reverse_list) + +def test_range(): + for length in range(10): + want_list = list(range(length)) + result = test_range_program.run(Program.to([length])) + assert want_list == result + +def do_test_permutations_of_size_n(n): + try_list = [random.randint(0,100) for x in range(n)] + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = smoke_test_permutations_program.run(Program.to([try_list])) + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_permutations_0(): + do_test_permutations_of_size_n(0) + +def test_permutations_1(): + do_test_permutations_of_size_n(1) + +def test_permutations_2(): + n = 2 + all_a_string = 0x616161616161 + all_b_string = 0x626262626262 + for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: + want_set = list([list(v) for v in sorted(permutations(try_list))]) + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + pl = proper_list(listed_result) + perms_result = sorted([int_list(x) for x in de_none_list(pl)]) + assert want_set == perms_result + +def test_chialisp_sort_program(): + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + +def test_permutations_n(): + for i in range(3,6): + do_test_permutations_of_size_n(i) + +def test_chialisp_permutations_program(): + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + +def test_smoke_sort(): + for length in range(7): # 0-7 length + for i in range(1 + (3 * length)): # A few orders each + orig_list = [random.randint(0,100) for x in range(length)] + sort_args = Program.to([orig_list]) + sorted_list = Program.to(sorted(orig_list)) + sort_res = sort_program.run(sort_args) + assert sort_res == sorted_list + +if __name__ == '__main__': + test_smoke_sort() diff --git a/resources/tests/game-referee-in-cl23/test_onehandcalc.clsp b/resources/tests/game-referee-in-cl23/test_onehandcalc.clsp new file mode 100644 index 000000000..983360bb5 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_onehandcalc.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-23*) + (include print.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include onehandcalc.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print 'result' (atomsort (print 'about to sort' newlist))) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list (reverse mylist) newlist)) + (permutations mylist) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (reverse (range 15)) (range 15)) + (try_list (reverse (range 15)) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (range i))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-in-cl23/test_permutations.clsp b/resources/tests/game-referee-in-cl23/test_permutations.clsp new file mode 100644 index 000000000..59dd075ec --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_permutations.clsp @@ -0,0 +1,63 @@ +(mod (M N) + (include *standard-cl-23*) + (include prepend.clinc) + (include reverse.clinc) + (include map.clinc) + (include len.clinc) + (include range.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + (include all-in-list.clinc) + (include print.clinc) + + (defun ! (x) + (if x + (* x (! (- x 1))) + 1 + ) + ) + (defun no_repeats_inner ((first . remainder)) + (if remainder + (if (deep= first (f remainder)) + 0 + (no_repeats_inner remainder) + ) + 1 + ) + ) + (defun no_repeats (mylist) + (if mylist + (no_repeats_inner (sort (lambda (a b) (= (deep_compare a b) -1)) mylist)) + 1 + ) + ) + (assert + ;; Is permutations expected to collapse equal alternatives when two of + ;; the items to shuffle are equal? + (= (* (! M) 4) (len (permutations (c 0 (range M))))) + (busy + (lambda (listlen) + (assign + mylist (range listlen) + permed (permutations mylist) + (assert + (= (len permed) (! listlen)) + ;; ensure we didn't produce any permutations that have + ;; repeated elements in them, which would indicate that + ;; the permutation function misbehaved + (all-in-list (map (lambda (L) (no_repeats L)) permed)) + (no_repeats permed) + ) + ) + ) + (reverse (range N)) + 1 + ) + (deep= (permutations 0) (q ())) + 0 + ) +) diff --git a/resources/tests/game-referee-in-cl23/test_permutations.clvm.hex b/resources/tests/game-referee-in-cl23/test_permutations.clvm.hex new file mode 100644 index 000000000..4f0911964 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_permutations.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ffff03ffff09ffff12ffff02ff66ffff04ff02ffff04ff05ff80808080ffff010480ffff02ff48ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff04ff80ffff02ff58ffff04ff02ffff04ff05ff8080808080ff80808080ff8080808080ffff01ff02ffff03ffff02ff8200baffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200fe80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ff8080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff50ffff04ff02ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff80808080ffff04ffff0101ff808080808080ffff01ff02ffff03ffff02ff62ffff04ff02ffff04ffff02ff4affff04ff02ffff04ff80ff80808080ffff04ffff01ff8080ff8080808080ffff01ff0180ffff01ff088080ff0180ffff01ff088080ff0180ffff01ff088080ff0180ffff04ffff01ffffffffffff02ffff03ff05ffff01ff04ff09ffff02ff40ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ff02ffff03ff0bffff01ff02ff60ffff04ff02ffff04ffff04ff13ff0580ffff04ff1bff8080808080ffff010580ff0180ffff02ff60ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff04ffff02ff05ffff04ff13ff808080ffff02ff70ffff04ff02ffff04ff05ffff04ff1bffff04ff17ff80808080808080ffff011780ff0180ffffff02ffff03ff05ffff01ff10ffff0101ffff02ff48ffff04ff02ffff04ff0dff8080808080ffff01ff018080ff0180ff02ffff03ffff09ff05ff0b80ffff01ff0180ffff01ff04ff05ffff02ff68ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff80808080808080ff0180ffff02ff68ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff02ff78ffff04ff02ffff04ff0dffff04ff17ffff04ffff04ff09ff0b80ff808080808080ffff010780ff0180ffffffff02ff78ffff04ff02ffff04ff05ffff04ff80ffff04ff80ff808080808080ff02ff54ffff04ff02ffff04ff03ffff04ffff02ff50ffff04ff02ffff04ff2fff80808080ff8080808080ffff02ffff03ff15ffff01ff02ffff03ff2dffff01ff02ffff03ffff02ff09ffff04ff25ffff04ff4dff80808080ffff01ff02ff64ffff04ff02ffff04ff09ffff04ff35ffff04ff2dffff04ffff04ff25ff5d80ff80808080808080ffff01ff02ff64ffff04ff02ffff04ff09ffff04ff15ffff04ff6dffff04ffff04ff4dff5d80ff8080808080808080ff0180ffff01ff02ff40ffff04ff02ffff04ff0bffff04ff15ff808080808080ff0180ffff01ff02ff40ffff04ff02ffff04ff0bffff04ff2dff808080808080ff0180ff02ff64ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff80ff80808080808080ffffff02ffff03ff0bffff01ff02ffff03ff1bffff01ff02ff6cffff04ff02ffff04ff03ffff04ffff02ff44ffff04ff02ffff04ff0bff80808080ff8080808080ffff010b80ff0180ffff01ff018080ff0180ff02ff5cffff04ff02ffff04ff03ffff04ffff02ff4cffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff4cffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ffff02ff74ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ff8200fcffff04ff02ffff04ff03ffff04ffff07ff0b80ff8080808080ff02ffff03ffff07ff0980ffff01ff02ffff03ff0bffff01ff02ff42ffff04ff02ffff04ff03ffff04ffff02ff8200bcffff04ff02ffff04ff11ffff04ff25ff8080808080ff8080808080ffff01ff010180ff0180ffff01ff02ffff03ff0bffff01ff0181ffffff01ff02ffff03ffff15ff09ff1580ffff01ff0101ffff01ff11ff80ffff15ff15ff09808080ff018080ff018080ff0180ffffffffff02ffff03ff0bffff010bffff01ff02ff8200bcffff04ff02ffff04ff31ffff04ff69ff808080808080ff0180ff09ffff02ff8200bcffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ffff02ffff03ff0bffff01ff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7280ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff13ff808080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff02ff40ffff04ff02ffff04ff05ffff04ff1bff8080808080ff80808080ffff04ffff02ff52ffff04ff02ffff04ffff04ff13ff0580ffff04ff1bffff04ff17ff808080808080ff808080808080ffff011780ff0180ff04ff09ff0b80ffffff02ffff03ff05ffff01ff02ff52ffff04ff02ffff04ff80ffff04ff05ffff04ff80ff808080808080ffff01ff01ff808080ff0180ff02ffff03ff0dffff01ff02ff6affff04ff02ffff04ff0dff80808080ffff010980ff0180ff03ffff02ffff03ff0bffff01ff02ff6affff04ff02ffff04ffff02ff5affff04ff02ffff04ffff02ff05ffff04ff13ff808080ffff04ffff02ff8200baffff04ff02ffff04ff05ffff04ff1bffff04ff17ff808080808080ff8080808080ff80808080ffff011780ff0180ff02ffff03ff05ffff01ff04ffff04ffff0101ff0980ffff02ff8200faffff04ff02ffff04ff0dff8080808080ffff01ff018080ff0180ffffffff02ffff04ffff0122ffff02ff8200faffff04ff02ffff04ff05ff8080808080ff8080ff02ffff03ff05ffff01ff12ff05ffff02ff66ffff04ff02ffff04ffff11ff05ffff010180ff8080808080ffff01ff010180ff0180ffff02ffff03ff0dffff01ff02ffff03ffff02ff62ffff04ff02ffff04ff09ffff04ff15ff8080808080ffff01ff0180ffff01ff02ff56ffff04ff02ffff04ff0dff8080808080ff0180ffff01ff010180ff0180ff02ffff03ff05ffff01ff02ff56ffff04ff02ffff04ffff02ff4cffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ff8080ffff04ffff0101ff80808080ff80808080ffff04ff05ff8080808080ff80808080ffff01ff010180ff0180ffffff09ffff02ff8200bcffff04ff02ffff04ff0bffff04ff17ff8080808080ffff0181ff80ff02ff5effff04ff02ffff04ff03ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ffff02ffff03ffff09ffff02ff48ffff04ff02ffff04ff0bff80808080ffff02ff66ffff04ff02ffff04ff29ff8080808080ffff01ff02ffff03ffff02ff46ffff04ff02ffff04ffff02ff70ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff8200be80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ff8080ffff04ffff0101ff80808080ff80808080ffff04ff0bffff04ff80ff808080808080ff80808080ffff01ff02ff76ffff04ff02ffff04ff0bff80808080ffff01ff088080ff0180ffff01ff088080ff0180ffff02ff76ffff04ff02ffff04ff0bff80808080ff02ff6effff04ff02ffff04ffff04ff80ffff04ff0bff808080ffff04ffff02ff58ffff04ff02ffff04ff0bff80808080ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl23/test_permutations.sym b/resources/tests/game-referee-in-cl23/test_permutations.sym new file mode 100644 index 000000000..8f716298b --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_permutations.sym @@ -0,0 +1 @@ +{"977f394242d63d635c3262f77623308d3dbb75be33fb0579ce068ef9aa61b95f": "lambda_$_1250", "179091fe2a0662e64286145e0bc8d8edbeec24a21caf28941d843233d7a07c18_arguments": "(((() listlen_$_1235) mylist_$_1236) permed_$_1237)", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_left_env": "1", "2f8924a67ce29174ab591e1eea042ab8a92b179aefc79724031aa32c1adca2ec_arguments": "(myless a b)", "179091fe2a0662e64286145e0bc8d8edbeec24a21caf28941d843233d7a07c18": "letbinding_$_1251", "d6959a1fe31bf33707ba5c402e83c70c28523ce1ec1fdfb7f6d1615b8b19ac6f": "permutations", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68_arguments": "(() L_$_1238)", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_left_env": "1", "7b49cb4430f8db99c728f68f250ce64b8d924edf982d256b9f1aa54bcd247bd3": "reverse_inner", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_arguments": "((() listlen_$_1235) mylist_$_1236)", "bac4134726e8744a62cfc2fb8062f615dcbe07e3368df66c28e4ff3f1530b9d5_arguments": "((myless_$_1179 mylist_$_1180) (a_$_1181 b_$_1182))", "d6959a1fe31bf33707ba5c402e83c70c28523ce1ec1fdfb7f6d1615b8b19ac6f_arguments": "(vals)", "8e1010766ed1255e57bcb63d1b8e999065d2295e17e12e8da3a3200dcfe72d85_left_env": "1", "8e1010766ed1255e57bcb63d1b8e999065d2295e17e12e8da3a3200dcfe72d85_arguments": "(L)", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99_left_env": "1", "__chia__main_arguments": "(M N)", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99_arguments": "myargs", "00472c7e852d86221bd799ec98883737a50be0769918af368f85ef82b587c6a5": "no_repeats_inner", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe": "range", "bac4134726e8744a62cfc2fb8062f615dcbe07e3368df66c28e4ff3f1530b9d5": "letbinding_$_1244", "8aaa8445e30d0613c3bc4e69dc922682ab0ddb0037b2b6f962c93b8d39fac6cb_left_env": "1", "f998ceba24fd5237d4759441cb8180302942d3ff3b0df1b16c6ec8a42f9e8feb": "len", "6a6dee0c702d9c433c1574c7f9aec2f9cb96a7058a6ce3c060096f36966dcaf3_left_env": "1", "00472c7e852d86221bd799ec98883737a50be0769918af368f85ef82b587c6a5_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977": "reverse", "5a2304733a44ef0eb65b98013f01b8159c093d28f78f60a6e4e9cbf88d24712a": "map-with-rest", "d2c4cc3b76e22dc7dbace4355f717ea1562ed7e230d9eb109ccebcce5a286762_arguments": "((myless_$_1169 A_$_1170 B_$_1171 agg_$_1172) cse_$_1239)", "bac4134726e8744a62cfc2fb8062f615dcbe07e3368df66c28e4ff3f1530b9d5_left_env": "1", "25fa0c2e23b21e6ed2046ea41e3e0a8b23aaeabab533811fa67e9bc88c13f8b3_left_env": "1", "8aaa8445e30d0613c3bc4e69dc922682ab0ddb0037b2b6f962c93b8d39fac6cb_arguments": "(a b)", "a0f33bb8f86cde256b4b17ff57166f666ac72d124a31b71e4cb9465ac6187cb8_arguments": "(((a_$_1188 b_$_1189) cse_$_1240) inner_result_$_1190)", "9d555f8fa61351176d9cc7653ec69c08e3cf8d7f77b9e62a55672837e11ef8dc": "all-in-list", "075c87dd46d215233cc305592019c4e38d1f9ee8136270fa8ec63bf3b21a7555_left_env": "1", "3c3345d295fe1bf6e242b2447ac80d7a5df6672ce1d81199c6716cb1a11d91e2_arguments": "(x)", "3c3345d295fe1bf6e242b2447ac80d7a5df6672ce1d81199c6716cb1a11d91e2": "!", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706": "lambda_$_1241", "2f8924a67ce29174ab591e1eea042ab8a92b179aefc79724031aa32c1adca2ec_left_env": "1", "42cc7c1c4d655f713c4c3a973f05cf00a2309aa1f881c43b39c18388ad566f6f_arguments": "((next . remainder))", "64da80039b055b3985693281fa3dce6ed49038f5b8bfa0a401890ed4cc06f5b7_arguments": "(a b)", "56fcbb61222cecf3d0508c8f7de453b57ed273192d17b9babbcf949ade228fe3_left_env": "1", "f0d9971063cb915d1a1574f69cf10876e1eadf56199d5a5f646eaa74418e15cb_arguments": "(next final)", "25fa0c2e23b21e6ed2046ea41e3e0a8b23aaeabab533811fa67e9bc88c13f8b3": "permutations_inner", "14f1b1d1c5f29961feaba6098b44d2d5aae15c65d14c98eace0e2bad57a3f16e": "prepend", "7b49cb4430f8db99c728f68f250ce64b8d924edf982d256b9f1aa54bcd247bd3_arguments": "(reversed rest)", "a0f33bb8f86cde256b4b17ff57166f666ac72d124a31b71e4cb9465ac6187cb8_left_env": "1", "2aa95e83d492fad7448cace5ef16276a5120b7d686eaf19dd8ce5528debd16ec_arguments": "(@ everything (rest aggl aggr))", "8e1010766ed1255e57bcb63d1b8e999065d2295e17e12e8da3a3200dcfe72d85": "enquote-rest", "486a24fa9d6684522f2acd9a163da3dc2b927502310181a7a01a62a38511b4f5": "no_repeats", "179091fe2a0662e64286145e0bc8d8edbeec24a21caf28941d843233d7a07c18_left_env": "1", "486a24fa9d6684522f2acd9a163da3dc2b927502310181a7a01a62a38511b4f5_left_env": "1", "42cc7c1c4d655f713c4c3a973f05cf00a2309aa1f881c43b39c18388ad566f6f": "last_inner", "075c87dd46d215233cc305592019c4e38d1f9ee8136270fa8ec63bf3b21a7555_arguments": "((a_$_1188 b_$_1189) cse_$_1240)", "8aaa8445e30d0613c3bc4e69dc922682ab0ddb0037b2b6f962c93b8d39fac6cb": "deep_compare", "56fcbb61222cecf3d0508c8f7de453b57ed273192d17b9babbcf949ade228fe3_arguments": "(((myless_$_1179 mylist_$_1180) (a_$_1181 b_$_1182)) sa_$_1183 sb_$_1184)", "c227759e0110fa53a26da3ce95683321df862de7f55472e9b85abe37bda150e9": "sort", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "d2c4cc3b76e22dc7dbace4355f717ea1562ed7e230d9eb109ccebcce5a286762_left_env": "1", "5a2304733a44ef0eb65b98013f01b8159c093d28f78f60a6e4e9cbf88d24712a_left_env": "1", "14f1b1d1c5f29961feaba6098b44d2d5aae15c65d14c98eace0e2bad57a3f16e_arguments": "(a b)", "2aa95e83d492fad7448cace5ef16276a5120b7d686eaf19dd8ce5528debd16ec": "split_inner", "c227759e0110fa53a26da3ce95683321df862de7f55472e9b85abe37bda150e9_arguments": "(myless mylist)", "7b49cb4430f8db99c728f68f250ce64b8d924edf982d256b9f1aa54bcd247bd3_left_env": "1", "2f8924a67ce29174ab591e1eea042ab8a92b179aefc79724031aa32c1adca2ec": "merge", "9d555f8fa61351176d9cc7653ec69c08e3cf8d7f77b9e62a55672837e11ef8dc_left_env": "1", "2c82355dea6595dde07e0d5e05aa96b89052c8b97d0e0c868356df4914f2fe68": "lambda_$_1252", "64da80039b055b3985693281fa3dce6ed49038f5b8bfa0a401890ed4cc06f5b7_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_left_env": "1", "9242b5b6b2f9c8d952001db1fbcffc4b477638bf957f6a5dd3a2cc742919c977_arguments": "(vals)", "14f1b1d1c5f29961feaba6098b44d2d5aae15c65d14c98eace0e2bad57a3f16e_left_env": "1", "42cc7c1c4d655f713c4c3a973f05cf00a2309aa1f881c43b39c18388ad566f6f_left_env": "1", "977f394242d63d635c3262f77623308d3dbb75be33fb0579ce068ef9aa61b95f_arguments": "(() a_$_1233 b_$_1234)", "3c3345d295fe1bf6e242b2447ac80d7a5df6672ce1d81199c6716cb1a11d91e2_left_env": "1", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238": "letbinding_$_1242", "483fcccf52dd01c7be19ebb1f6ec50a0c235873236a8ab545236771af634b706_arguments": "(() listlen_$_1235)", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99": "echo", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_left_env": "1", "5fe09c9286896c58fb9645e68670c83c492cc65becc9ff451e4de65b1c3f7c98": "split", "c227759e0110fa53a26da3ce95683321df862de7f55472e9b85abe37bda150e9_left_env": "1", "22656977815b97840394f07b4339f2a131a5786afba08ff9ba669f7fc3eb2aa3": "merge_inner", "f0d9971063cb915d1a1574f69cf10876e1eadf56199d5a5f646eaa74418e15cb": "range_inner", "5fe09c9286896c58fb9645e68670c83c492cc65becc9ff451e4de65b1c3f7c98_left_env": "1", "977f394242d63d635c3262f77623308d3dbb75be33fb0579ce068ef9aa61b95f_left_env": "1", "source_file": "test_permutations.clsp", "2aa95e83d492fad7448cace5ef16276a5120b7d686eaf19dd8ce5528debd16ec_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_1249", "f998ceba24fd5237d4759441cb8180302942d3ff3b0df1b16c6ec8a42f9e8feb_arguments": "(L)", "f8de27975a5aa0f0169626c8874de2ee78c9879c44424bfc1153bc150c6282fe_arguments": "(i)", "5fe09c9286896c58fb9645e68670c83c492cc65becc9ff451e4de65b1c3f7c98_arguments": "(mylist)", "6a6dee0c702d9c433c1574c7f9aec2f9cb96a7058a6ce3c060096f36966dcaf3_arguments": "(myfunc mylist returnval)", "e23db45dac9015daa0e667d0d846c354b2b9d9aaa3faedb560854d8662f2e238_left_env": "1", "f998ceba24fd5237d4759441cb8180302942d3ff3b0df1b16c6ec8a42f9e8feb_left_env": "1", "f0d9971063cb915d1a1574f69cf10876e1eadf56199d5a5f646eaa74418e15cb_left_env": "1", "a0f33bb8f86cde256b4b17ff57166f666ac72d124a31b71e4cb9465ac6187cb8": "letbinding_$_1247", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_1206) x_$_1208)", "6a6dee0c702d9c433c1574c7f9aec2f9cb96a7058a6ce3c060096f36966dcaf3": "busy", "d2c4cc3b76e22dc7dbace4355f717ea1562ed7e230d9eb109ccebcce5a286762": "letbinding_$_1243", "56fcbb61222cecf3d0508c8f7de453b57ed273192d17b9babbcf949ade228fe3": "letbinding_$_1245", "9d555f8fa61351176d9cc7653ec69c08e3cf8d7f77b9e62a55672837e11ef8dc_arguments": "(L)", "00472c7e852d86221bd799ec98883737a50be0769918af368f85ef82b587c6a5_arguments": "((first . remainder))", "075c87dd46d215233cc305592019c4e38d1f9ee8136270fa8ec63bf3b21a7555": "letbinding_$_1246", "64da80039b055b3985693281fa3dce6ed49038f5b8bfa0a401890ed4cc06f5b7": "deep=", "5a2304733a44ef0eb65b98013f01b8159c093d28f78f60a6e4e9cbf88d24712a_arguments": "(F L R)", "25fa0c2e23b21e6ed2046ea41e3e0a8b23aaeabab533811fa67e9bc88c13f8b3_arguments": "(pre post agg)", "486a24fa9d6684522f2acd9a163da3dc2b927502310181a7a01a62a38511b4f5_arguments": "(mylist)", "22656977815b97840394f07b4339f2a131a5786afba08ff9ba669f7fc3eb2aa3_left_env": "1", "d6959a1fe31bf33707ba5c402e83c70c28523ce1ec1fdfb7f6d1615b8b19ac6f_left_env": "1", "22656977815b97840394f07b4339f2a131a5786afba08ff9ba669f7fc3eb2aa3_arguments": "(myless A B agg)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/test_prepend.clsp b/resources/tests/game-referee-in-cl23/test_prepend.clsp new file mode 100644 index 000000000..41b7015dc --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_prepend.clsp @@ -0,0 +1,5 @@ +(mod (X Y) + (include *standard-cl-23*) + (include prepend.clinc) + (prepend X Y) + ) diff --git a/resources/tests/game-referee-in-cl23/test_prepend.clvm.hex b/resources/tests/game-referee-in-cl23/test_prepend.clvm.hex new file mode 100644 index 000000000..47dd7f1f1 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_prepend.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff02ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff04ffff01ff02ffff03ff05ffff01ff02ffff01ff04ffff05ff0580ffff02ff02ffff04ff02ffff04ffff06ff0580ffff04ff0bff808080808080ff0180ffff01ff02ffff010bff018080ff0180ff018080 diff --git a/resources/tests/game-referee-in-cl23/test_prepend.sym b/resources/tests/game-referee-in-cl23/test_prepend.sym new file mode 100644 index 000000000..83feb47c9 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_prepend.sym @@ -0,0 +1 @@ +{"dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_left_env": "1", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987": "prepend", "dfe61be8d5db02605605573b4d298395c7a871cc5390a79d535d07bbd2338987_arguments": "(a b)", "source_file": "test_prepend.clsp", "__chia__main_arguments": "(X Y)"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/test_range.clsp b/resources/tests/game-referee-in-cl23/test_range.clsp new file mode 100644 index 000000000..b299e3859 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_range.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-23*) + (include range.clinc) + + (range X) + ) diff --git a/resources/tests/game-referee-in-cl23/test_range.clvm.hex b/resources/tests/game-referee-in-cl23/test_range.clvm.hex new file mode 100644 index 000000000..628a68fe6 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_range.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ffff09ff05ff0b80ffff01ff02ffff01ff0180ff0180ffff01ff02ffff01ff04ff05ffff02ff04ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff808080808080ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl23/test_range.sym b/resources/tests/game-referee-in-cl23/test_range.sym new file mode 100644 index 000000000..ade866ede --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_range.sym @@ -0,0 +1 @@ +{"6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_arguments": "(next final)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556_left_env": "1", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(i)", "__chia__main_arguments": "(X)", "6ba774998680757c6e60d6d6e8a94176f76b74e5f8c6f2cf5d99fb134e916556": "range_inner", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "range", "source_file": "test_range.clsp"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/test_reverse.clsp b/resources/tests/game-referee-in-cl23/test_reverse.clsp new file mode 100644 index 000000000..a7d1d937e --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_reverse.clsp @@ -0,0 +1,6 @@ +(mod (X) + (include *standard-cl-23*) + (include reverse.clinc) + + (reverse X) + ) diff --git a/resources/tests/game-referee-in-cl23/test_reverse.clvm.hex b/resources/tests/game-referee-in-cl23/test_reverse.clvm.hex new file mode 100644 index 000000000..492966787 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_reverse.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff06ffff04ff02ffff04ff05ff80808080ffff04ffff01ffff02ffff03ff0bffff01ff02ffff01ff02ff04ffff04ff02ffff04ffff04ffff05ff0b80ff0580ffff04ffff06ff0b80ff8080808080ff0180ffff01ff02ffff0105ff018080ff0180ff02ff04ffff04ff02ffff04ff80ffff04ff05ff8080808080ff018080 diff --git a/resources/tests/game-referee-in-cl23/test_reverse.sym b/resources/tests/game-referee-in-cl23/test_reverse.sym new file mode 100644 index 000000000..6a95fc6f8 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_reverse.sym @@ -0,0 +1 @@ +{"source_file": "test_reverse.clsp", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_arguments": "(vals)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a_left_env": "1", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_left_env": "1", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01_arguments": "(reversed rest)", "0f035685b03df70de81cbdbd4e600f5d2f148f6c02b0e0a73ef96a26e7121f2a": "reverse", "__chia__main_arguments": "(X)", "893ed9a33d9ef594068ddc5aa4e669dce55ad0e7588062968c1d76ba4c830c01": "reverse_inner"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/test_slice.clsp b/resources/tests/game-referee-in-cl23/test_slice.clsp new file mode 100644 index 000000000..8ae7f9955 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_slice.clsp @@ -0,0 +1,14 @@ +(mod () + (include *standard-cl-23*) + (include print.clinc) + (include range.clinc) + (include deep_compare.clinc) + (include slice.clinc) + (include assert.clinc) + + (assert + (deep= (range 3) (slice (range 5) 3)) + (deep= (range 5) (slice (range 5) 5)) + 0 + ) + ) diff --git a/resources/tests/game-referee-in-cl23/test_sort.clsp b/resources/tests/game-referee-in-cl23/test_sort.clsp new file mode 100644 index 000000000..1d5a2b56b --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_sort.clsp @@ -0,0 +1,37 @@ + +(mod () + (include *standard-cl-23*) + (include print.clinc) + (include sort.clinc) + (include assert.clinc) + (include deep_compare.clinc) + (include reverse.clinc) + (include prepend.clinc) + (include map.clinc) + (include range.clinc) + (include permutations.clinc) + (include last.clinc) + (include busy.clinc) + + (defun try_list (mylist newlist) + (assert (deep= (print "sorted" (sort (lambda (A B) (deep< A B)) newlist)) mylist) 0) + ) + + (defun try_permuted_list (mylist) + (busy (lambda ((& mylist) newlist) (try_list mylist newlist)) + (print "sort all these" (permutations (print "mylist" mylist))) + 0 + ) + ) + (last + (try_list 0 0) + (try_list (range 15) (range 15)) + (try_list (range 15) (reverse (range 15))) + (try_permuted_list (list -1 -1 0 0 2)) + (busy (lambda (i) (try_permuted_list (print "sortme" (range i)))) + (range 4) + 0 + ) + 1 + ) +) diff --git a/resources/tests/game-referee-in-cl23/test_sort.clvm.hex b/resources/tests/game-referee-in-cl23/test_sort.clvm.hex new file mode 100644 index 000000000..c6e978298 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_sort.clvm.hex @@ -0,0 +1 @@ +ff02ffff01ff02ff46ffff04ff02ffff04ffff02ff66ffff04ff02ffff04ffff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff7e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ff8080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff4affff04ff02ffff04ffff0104ff80808080ffff04ff80ff808080808080ffff04ffff02ff6effff04ff02ffff04ffff04ffff0181ffffff04ffff0181ffffff04ff80ffff04ff80ffff04ffff0102ff808080808080ff80808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff42ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ffff04ffff02ff4affff04ff02ffff04ffff010fff80808080ff8080808080ffff04ffff02ff76ffff04ff02ffff04ff80ffff04ff80ff8080808080ffff04ffff0101ff808080808080808080ff80808080ffff04ffff01ffffffffff02ffff03ffff22ffff0187247072696e7424ff05ff0b80ffff010bffff010b80ff0180ffff02ffff03ff05ffff01ff02ff50ffff04ff02ffff04ff0dffff04ff17ffff04ffff04ff09ff0b80ff808080808080ffff010780ff0180ff02ff50ffff04ff02ffff04ff05ffff04ff80ffff04ff80ff808080808080ffffff02ff68ffff04ff02ffff04ff03ffff04ffff02ff42ffff04ff02ffff04ff2fff80808080ff8080808080ff02ffff03ff15ffff01ff02ffff03ff2dffff01ff02ffff03ffff02ff09ffff04ff25ffff04ff4dff80808080ffff01ff02ff48ffff04ff02ffff04ff09ffff04ff35ffff04ff2dffff04ffff04ff25ff5d80ff80808080808080ffff01ff02ff48ffff04ff02ffff04ff09ffff04ff15ffff04ff6dffff04ffff04ff4dff5d80ff8080808080808080ff0180ffff01ff02ff62ffff04ff02ffff04ff0bffff04ff15ff808080808080ff0180ffff01ff02ff62ffff04ff02ffff04ff0bffff04ff2dff808080808080ff0180ffff02ff48ffff04ff02ffff04ff05ffff04ff0bffff04ff17ffff04ff80ff80808080808080ff02ffff03ff0bffff01ff02ffff03ff1bffff01ff02ff44ffff04ff02ffff04ff03ffff04ffff02ff70ffff04ff02ffff04ff0bff80808080ff8080808080ffff010b80ff0180ffff01ff018080ff0180ffffffff02ff64ffff04ff02ffff04ff03ffff04ffff02ff78ffff04ff02ffff04ff09ffff04ff13ff8080808080ffff04ffff02ff78ffff04ff02ffff04ff09ffff04ff2bff8080808080ff808080808080ff02ff58ffff04ff02ffff04ff11ffff04ff0bffff04ff17ff808080808080ffff02ff74ffff04ff02ffff04ff03ffff04ffff07ff0b80ff8080808080ff02ffff03ffff07ff0980ffff01ff02ffff03ff0bffff01ff02ff4cffff04ff02ffff04ff03ffff04ffff02ff54ffff04ff02ffff04ff11ffff04ff25ff8080808080ff8080808080ffff01ff010180ff0180ffff01ff02ffff03ff0bffff01ff0181ffffff01ff02ffff03ffff15ff09ff1580ffff01ff0101ffff01ff11ff80ffff15ff15ff09808080ff018080ff018080ff0180ffffff02ffff03ff0bffff010bffff01ff02ff54ffff04ff02ffff04ff31ffff04ff69ff808080808080ff0180ff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ffff0181ff80ffff09ffff02ff54ffff04ff02ffff04ff05ffff04ff0bff8080808080ff8080ff02ffff03ff0bffff01ff02ff7cffff04ff02ffff04ffff04ff13ff0580ffff04ff1bff8080808080ffff010580ff0180ffffffffff02ff7cffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff05ffff01ff04ff09ffff02ff62ffff04ff02ffff04ff0dffff04ff0bff808080808080ffff010b80ff0180ffff02ffff03ff0bffff01ff04ffff02ff05ffff04ff13ff808080ffff02ff52ffff04ff02ffff04ff05ffff04ff1bffff04ff17ff80808080808080ffff011780ff0180ff02ffff03ffff09ff05ff0b80ffff01ff0180ffff01ff04ff05ffff02ff72ffff04ff02ffff04ffff10ff05ffff010180ffff04ff0bff80808080808080ff0180ffffff02ff72ffff04ff02ffff04ff80ffff04ff05ff8080808080ff02ffff03ff0bffff01ff02ff52ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5a80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff13ff808080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff7affff04ff02ffff04ffff02ff62ffff04ff02ffff04ff05ffff04ff1bff8080808080ff80808080ffff04ffff02ff6affff04ff02ffff04ffff04ff13ff0580ffff04ff1bffff04ff17ff808080808080ff808080808080ffff011780ff0180ffff04ff09ff0b80ff02ffff03ff05ffff01ff02ff6affff04ff02ffff04ff80ffff04ff05ffff04ff80ff808080808080ffff01ff01ff808080ff0180ffffffff02ffff03ff0dffff01ff02ff46ffff04ff02ffff04ff0dff80808080ffff010980ff018003ffff02ffff03ff0bffff01ff02ff46ffff04ff02ffff04ffff02ff66ffff04ff02ffff04ffff02ff05ffff04ff13ff808080ffff04ffff02ff56ffff04ff02ffff04ff05ffff04ff1bffff04ff17ff808080808080ff8080808080ff80808080ffff011780ff0180ff02ffff03ffff02ff5cffff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746564ffff04ffff02ff78ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff4e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ff8080ffff04ffff0101ff80808080ff80808080ffff04ff0bff8080808080ff8080808080ffff04ff05ff8080808080ffff01ff0180ffff01ff088080ff0180ffffff02ff6cffff04ff02ffff04ff0bffff04ff17ff8080808080ff02ff56ffff04ff02ffff04ffff04ffff0102ffff04ffff04ffff0101ffff04ffff0102ffff04ffff04ffff0101ff5e80ffff04ffff04ffff0104ffff04ffff04ffff0101ff0280ffff04ffff0101ff80808080ff8080808080ffff04ffff04ffff0104ffff04ffff04ffff0101ffff04ff05ff808080ffff04ffff0101ff80808080ff80808080ffff04ffff02ff20ffff04ff02ffff04ffff018e736f727420616c6c207468657365ffff04ffff02ff7affff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff01866d796c697374ffff04ff05ff8080808080ff80808080ff8080808080ffff04ff80ff808080808080ffff02ff76ffff04ff02ffff04ff09ffff04ff0bff8080808080ff02ff6effff04ff02ffff04ffff02ff20ffff04ff02ffff04ffff0186736f72746d65ffff04ffff02ff4affff04ff02ffff04ff0bff80808080ff8080808080ff80808080ff018080 diff --git a/resources/tests/game-referee-in-cl23/test_sort.sym b/resources/tests/game-referee-in-cl23/test_sort.sym new file mode 100644 index 000000000..b52d7115d --- /dev/null +++ b/resources/tests/game-referee-in-cl23/test_sort.sym @@ -0,0 +1 @@ +{"652f68e12a6e59641993f596a5644dcf31df81ef40f2c29b254eea5d8c2d4bff": "letbinding_$_1213", "35c2901e470b807d5438698d60919740a425372207406f8e8d1028a848066afb_arguments": "(a b)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_left_env": "1", "dd43ffb7ff900c9b5de80a6caac0388e157acab4c76bdea782158c5e3faebe41_arguments": "(((myless_$_1139 mylist_$_1140) (a_$_1141 b_$_1142)) sa_$_1143 sb_$_1144)", "caf316830203f2531b0730970f0a1ff842cfaa3737b26f671863ba72d4dbcb23_arguments": "(myless A B agg)", "de8e4d6b56fcbccff581079e2fa7840526dd1060d28465da2df907d5479f5fc1": "reverse", "99bd5cd8b43a9260701043b5036b40e8eb88bb2fa9a8a1fc7a1615e956289bf3_arguments": "(F L R)", "3abbdef2c09f5ef57e45e9fea76bc483517f5d61f41b5d446ca2cd52194ab8ad": "permutations_inner", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_left_env": "1", "d43c5858f7535807c689e442e4dd9eb4e168e42bf5d5ec32f385816127ea7cb7_left_env": "1", "source_file": "test_sort.clsp", "f274125ba4dc62cee2127718e542397ddb82bedc2dbc7f7e6ab7e99520f1369c_arguments": "(vals)", "646c25660b2e23796637423fb0cc798fc0cceee4c2c1ab694b40b29829de1918_left_env": "1", "652f68e12a6e59641993f596a5644dcf31df81ef40f2c29b254eea5d8c2d4bff_arguments": "(((a_$_1148 b_$_1149) cse_$_1207) inner_result_$_1150)", "8764fc26d5f82f12e520c8c83a44fcccd198c69ecef8ade84d878558b28312b6": "busy", "8764fc26d5f82f12e520c8c83a44fcccd198c69ecef8ade84d878558b28312b6_left_env": "1", "35c2901e470b807d5438698d60919740a425372207406f8e8d1028a848066afb": "prepend", "d43c5858f7535807c689e442e4dd9eb4e168e42bf5d5ec32f385816127ea7cb7": "sort", "de8e4d6b56fcbccff581079e2fa7840526dd1060d28465da2df907d5479f5fc1_arguments": "(vals)", "99bd5cd8b43a9260701043b5036b40e8eb88bb2fa9a8a1fc7a1615e956289bf3": "map-with-rest", "ec1a55e5177b6c05f4ca7658e0af6ec0949696fc2f5fd4b761885c2f1c486fc4": "last_inner", "0a7b5127d99d3480228e93a4e31e810ca331d7d28f388077f7d45eb823a18136_left_env": "1", "df831d1086e338ee8a71c0b7588c3939989ec70e5695ada095735c81cfac99ac_left_env": "1", "caf316830203f2531b0730970f0a1ff842cfaa3737b26f671863ba72d4dbcb23_left_env": "1", "3e817bd05c10040769ecf76668026b4091c623b991a02e9155fe9e68334733e2": "split", "0a7b5127d99d3480228e93a4e31e810ca331d7d28f388077f7d45eb823a18136_arguments": "(@ everything (rest aggl aggr))", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b": "range", "d43c5858f7535807c689e442e4dd9eb4e168e42bf5d5ec32f385816127ea7cb7_arguments": "(myless mylist)", "f274125ba4dc62cee2127718e542397ddb82bedc2dbc7f7e6ab7e99520f1369c": "permutations", "baab8a8560e19f7a28f84d94e788a555f3b46610a47b17aa8ead22b041adcac6_left_env": "1", "eb5a821dfc5b93a6ae858750615a61afb12efe943c2f2350b05f80a49ef8994d_arguments": "(mylist)", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7": "lambda_$_1208", "ec1a55e5177b6c05f4ca7658e0af6ec0949696fc2f5fd4b761885c2f1c486fc4_arguments": "((next . remainder))", "86359b12df84412bbc1390766400eb618a779245f5dd827c50cbbccc2465734a_left_env": "1", "919ca3a7eebc8bdea24332f40426a170497c22b208c40c57ad229034da3052a6": "letbinding_$_1209", "df831d1086e338ee8a71c0b7588c3939989ec70e5695ada095735c81cfac99ac": "range_inner", "a837d2a0d80ec387d14894d2418203e4f44bed2668f3aba64c0d68e394d9611c": "reverse_inner", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99": "echo", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_left_env": "1", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d": "deep<", "df831d1086e338ee8a71c0b7588c3939989ec70e5695ada095735c81cfac99ac_arguments": "(next final)", "86359b12df84412bbc1390766400eb618a779245f5dd827c50cbbccc2465734a": "try_list", "0a7b5127d99d3480228e93a4e31e810ca331d7d28f388077f7d45eb823a18136": "split_inner", "919ca3a7eebc8bdea24332f40426a170497c22b208c40c57ad229034da3052a6_left_env": "1", "ecb54631c39aa0e71f97b09a6d7e983c1f6f47771562912c33be097f5f187676": "letbinding_$_1212", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_left_env": "1", "dd43ffb7ff900c9b5de80a6caac0388e157acab4c76bdea782158c5e3faebe41": "letbinding_$_1211", "caf316830203f2531b0730970f0a1ff842cfaa3737b26f671863ba72d4dbcb23": "merge_inner", "199ffa2cf4049218a5f783a13b6f6539ea4b18fa43ab34f75b72336de7605f9b_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708": "lambda_$_1215", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99_left_env": "1", "8e2bde2bc32ee2c6313247a0e3b49389312ad884f40296f73dd6c0f7336f2c6d_arguments": "(R P)", "199ffa2cf4049218a5f783a13b6f6539ea4b18fa43ab34f75b72336de7605f9b": "deep_compare", "8e2bde2bc32ee2c6313247a0e3b49389312ad884f40296f73dd6c0f7336f2c6d": "print", "919ca3a7eebc8bdea24332f40426a170497c22b208c40c57ad229034da3052a6_arguments": "((myless_$_1129 A_$_1130 B_$_1131 agg_$_1132) cse_$_1206)", "8ce1ca2d9aa6fd583306772cd9e122af4be26dc842a6679a1bfa22d328b1f379_left_env": "1", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7": "deep=", "ecb54631c39aa0e71f97b09a6d7e983c1f6f47771562912c33be097f5f187676_arguments": "((a_$_1148 b_$_1149) cse_$_1207)", "a837d2a0d80ec387d14894d2418203e4f44bed2668f3aba64c0d68e394d9611c_arguments": "(reversed rest)", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_arguments": "(i)", "3abbdef2c09f5ef57e45e9fea76bc483517f5d61f41b5d446ca2cd52194ab8ad_left_env": "1", "8764fc26d5f82f12e520c8c83a44fcccd198c69ecef8ade84d878558b28312b6_arguments": "(myfunc mylist returnval)", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_arguments": "((mylist_$_1203) newlist_$_1204)", "b8b601fdb8fab0e12e98d10b1e8169d4209f502a901b4084e2f2c099065460e7_arguments": "(a b)", "c79b932e1e1da3c0e098e5ad2c422937eb904a76cf61d83975a74a68fbb04b99_arguments": "myargs", "99bd5cd8b43a9260701043b5036b40e8eb88bb2fa9a8a1fc7a1615e956289bf3_left_env": "1", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560": "lambda_$_1217", "c5bd34dcdeed87a6c78ea6b36052df8f96895a13a69b4179c15faf9f83ba4560_left_env": "1", "__chia__main_arguments": "()", "f274125ba4dc62cee2127718e542397ddb82bedc2dbc7f7e6ab7e99520f1369c_left_env": "1", "962986191da6874f39aeb123a2daa2d87bd1d8a68f612e83d33070a0315fa3d7_arguments": "(() i_$_1205)", "646c25660b2e23796637423fb0cc798fc0cceee4c2c1ab694b40b29829de1918_arguments": "((myless_$_1139 mylist_$_1140) (a_$_1141 b_$_1142))", "6a477b54f8811bb3d5111ee9d39d29db7e3cca8f2521efd80f46dcfd9bc0573b_left_env": "1", "8ce1ca2d9aa6fd583306772cd9e122af4be26dc842a6679a1bfa22d328b1f379_arguments": "(myless a b)", "646c25660b2e23796637423fb0cc798fc0cceee4c2c1ab694b40b29829de1918": "letbinding_$_1210", "baab8a8560e19f7a28f84d94e788a555f3b46610a47b17aa8ead22b041adcac6_arguments": "(() A_$_1201 B_$_1202)", "eb5a821dfc5b93a6ae858750615a61afb12efe943c2f2350b05f80a49ef8994d_left_env": "1", "0912f05321a428d040bc76941cf4f8f7c74f28662f48098303e30cf1a6a43708_arguments": "((myatom_$_1180) x_$_1182)", "199ffa2cf4049218a5f783a13b6f6539ea4b18fa43ab34f75b72336de7605f9b_arguments": "(a b)", "3e817bd05c10040769ecf76668026b4091c623b991a02e9155fe9e68334733e2_arguments": "(mylist)", "ec1a55e5177b6c05f4ca7658e0af6ec0949696fc2f5fd4b761885c2f1c486fc4_left_env": "1", "3e817bd05c10040769ecf76668026b4091c623b991a02e9155fe9e68334733e2_left_env": "1", "35c2901e470b807d5438698d60919740a425372207406f8e8d1028a848066afb_left_env": "1", "8ce1ca2d9aa6fd583306772cd9e122af4be26dc842a6679a1bfa22d328b1f379": "merge", "652f68e12a6e59641993f596a5644dcf31df81ef40f2c29b254eea5d8c2d4bff_left_env": "1", "8e2bde2bc32ee2c6313247a0e3b49389312ad884f40296f73dd6c0f7336f2c6d_left_env": "1", "baab8a8560e19f7a28f84d94e788a555f3b46610a47b17aa8ead22b041adcac6": "lambda_$_1216", "dd43ffb7ff900c9b5de80a6caac0388e157acab4c76bdea782158c5e3faebe41_left_env": "1", "86359b12df84412bbc1390766400eb618a779245f5dd827c50cbbccc2465734a_arguments": "(mylist newlist)", "ecb54631c39aa0e71f97b09a6d7e983c1f6f47771562912c33be097f5f187676_left_env": "1", "de8e4d6b56fcbccff581079e2fa7840526dd1060d28465da2df907d5479f5fc1_left_env": "1", "3abbdef2c09f5ef57e45e9fea76bc483517f5d61f41b5d446ca2cd52194ab8ad_arguments": "(pre post agg)", "6b79b32d680005d302468e9d2c1592335cee3e4e0a454c9ede7653eb17b9c26d_arguments": "(a b)", "eb5a821dfc5b93a6ae858750615a61afb12efe943c2f2350b05f80a49ef8994d": "try_permuted_list", "a837d2a0d80ec387d14894d2418203e4f44bed2668f3aba64c0d68e394d9611c_left_env": "1"} \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/testnoncegame.py b/resources/tests/game-referee-in-cl23/testnoncegame.py new file mode 100644 index 000000000..3b4cd2c2a --- /dev/null +++ b/resources/tests/game-referee-in-cl23/testnoncegame.py @@ -0,0 +1,33 @@ +import hashlib + +from hsms.streamables.program import Program + +from clvm.EvalError import EvalError + +noncegame = Program.from_bytes(bytes.fromhex(open("noncegame.clvm.hex").read())) +noncehash = noncegame.tree_hash() + +def drun(prog: Program, args: Program): + try: + return prog.run(args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(args)}") + raise + +def testnonce(startnonce, maxnonce): + for i in range(startnonce, maxnonce): + mygame = noncegame.curry(i, noncehash) + good_parameters = [i*2, noncegame.curry(i+1, noncehash).tree_hash(), 1, (i*4, b'g')] + bad_parameters = [i*3, noncegame.curry(i+2, noncehash).tree_hash(), 2, (i*5, b'g')] + assert drun(mygame, good_parameters) == b'g' + for j in range(len(good_parameters)): + try: + p = list(good_parameters) + p[j] = bad_parameters[j] + mygame.run(p) + assert False + except EvalError as ee: + pass + +if __name__ == '__main__': + testnonce(3, 7) diff --git a/resources/tests/game-referee-in-cl23/testreferee.py b/resources/tests/game-referee-in-cl23/testreferee.py new file mode 100644 index 000000000..01eb53643 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/testreferee.py @@ -0,0 +1,479 @@ +import pytest +from hashlib import sha256 +from contextlib import asynccontextmanager +from chia.clvm.spend_sim import SimClient, SpendSim +from pathlib import Path +from clvm.casts import int_to_bytes, int_from_bytes + +from hsms.streamables.program import Program +from clvm_tools_rs import compile_clvm +from clvm_tools.binutils import disassemble + +from clvm.EvalError import EvalError +from chia.types.mempool_inclusion_status import MempoolInclusionStatus +from chia.util.errors import Err +from dataclasses import dataclass +from typing import Any +from chia_rs import Coin +from chia.types.spend_bundle import SpendBundle +from chia.types.coin_spend import CoinSpend +from blspy import G2Element + +from steprun import diag_run_clvm, compile_module_with_symbols + +compile_module_with_symbols(['.'],'referee.clsp') +referee = Program.from_bytes(bytes.fromhex(open("referee.clvm.hex").read())) +refhash = referee.tree_hash() +compile_module_with_symbols(['.'],'referee_accuse.clsp') +referee_accuse = Program.from_bytes(bytes.fromhex(open("referee_accuse.clvm.hex").read())) +refaccusehash = referee.tree_hash() +compile_clvm('rockpaperscissorsa.clsp', 'rockpaperscissorsa.clvm.hex', ['.']) +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +compile_clvm('rockpaperscissorsb.clsp', 'rockpaperscissorsb.clvm.hex', ['.']) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +compile_clvm('rockpaperscissorsc.clsp', 'rockpaperscissorsc.clvm.hex', ['.']) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +compile_clvm('rockpaperscissorsd.clsp', 'rockpaperscissorsd.clvm.hex', ['.']) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + +move = 0 +accuse = 1 +timeout = 2 + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha(blob:bytes) -> bytes: + return sha256(blob).digest() + +@pytest.fixture(scope="function") +@asynccontextmanager +async def setup_sim() : + sim = await SpendSim.create(db_path=Path("file:db_test?mode=memory&cache=shared")) + sim_client = SimClient(sim) + await sim.farm_block() + + try: + yield sim, sim_client + finally: + await sim.close() + +def bootstrap_referee(parent_coin_id, initial_validation_program_hash, initial_split, + amount, timeout, max_move_size, mover_puzzle, waiter_puzzle): + """ + returns referee_wrap + """ + puzzle_hash = referee.curry( + [initial_validation_program_hash, 0, initial_split, amount, timeout, max_move_size, mover_puzzle.tree_hash(), + waiter_puzzle.tree_hash(), referee.tree_hash()]).tree_hash() + coin = Coin(parent_coin_id, puzzle_hash, amount) + return RefereeWrap(coin, bytes(32), bytes(32), bytes(32), + initial_validation_program_hash, 0, initial_split, timeout, max_move_size, + mover_puzzle, waiter_puzzle) + +@dataclass +class RefereeWrap: + coin: Any + grandparent_id: Any + parent_validation_program_hash: Any + parent_everything_else_hash: Any + validation_program_hash: Any + move: Any + split: Any + timeout: Any + max_move_size: Any + mover_puzzle: Any + waiter_puzzle: Any + + def curried_parameters_for_our_puzzle(self, purpose, for_self, move_to_make, split, validation_program_hash): + result = Program.to([ + validation_program_hash, + move_to_make, + split, + self.coin.amount, + self.timeout, + self.max_move_size, + self.mover_puzzle.tree_hash() if for_self else self.waiter_puzzle.tree_hash(), + self.waiter_puzzle.tree_hash() if for_self else self.mover_puzzle.tree_hash(), + refhash + ]) + print(f'for {purpose} curried_parameters_for_our_puzzle is {result}') + return result + + def get_puzzle(self): + return referee.curry(self.curried_parameters_for_our_puzzle( + "GET_PUZZLE", + True, + self.move, + self.split, + self.validation_program_hash + )) + + def SpendMove(self, password, move_to_make, split, validation_program_hash): + """ + returns (solution, new RefereeWrap) + """ + print(f"MOVE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"MOVE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + curried_parameters = self.curried_parameters_for_our_puzzle( + "SPEND_MOVE", + False, + move_to_make, + split, + validation_program_hash + ) + print(f"MOVE referee curried parameters {curried_parameters}") + new_puzzle_hash = referee.curry(curried_parameters).tree_hash() + print(f"MOVE new puzzle hash {Program.to(new_puzzle_hash)}") + solution = Program.to([move, move_to_make, split, validation_program_hash, self.mover_puzzle, + [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + everything_else_hash = Program.to([self.move, self.split, self.coin.amount, self.timeout, + self.max_move_size, self.mover_puzzle.tree_hash(), self.waiter_puzzle.tree_hash(), + referee.tree_hash()]).tree_hash() + return (solution, RefereeWrap(coin, self.coin.parent_coin_info, self.validation_program_hash, everything_else_hash, + validation_program_hash, move_to_make, split, self.timeout, self.max_move_size, + self.waiter_puzzle, self.mover_puzzle)) + + def SpendAccuse(self, password): + """ + returns (solution, RefereeAccuse) + """ + print(f"ACCUSE starting with puzzle hash {Program.to(self.get_puzzle().tree_hash())}") + print(f"ACCUSE parent_id {Program.to(self.coin.parent_coin_info)}") + print(f"ACCUSE referee mover_puzzle {self.mover_puzzle.tree_hash()}") + print(f"ACCUSE referee waiter_puzzle {self.waiter_puzzle.tree_hash()}") + new_puzzle_hash = referee_accuse.curry([ + self.parent_validation_program_hash, + self.validation_program_hash, + self.move, + self.split, + self.coin.amount, + self.timeout, + self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash() + ]).tree_hash() + solution = Program.to([accuse, self.grandparent_id, self.parent_validation_program_hash, + self.parent_everything_else_hash, self.mover_puzzle, [password, [51, new_puzzle_hash, self.coin.amount]]]) + coin = Coin(self.coin.name(), new_puzzle_hash, self.coin.amount) + return (solution, RefereeAccuseWrap(coin, self.parent_validation_program_hash, self.validation_program_hash, + self.move, self.split, self.timeout, self.waiter_puzzle.tree_hash(), + self.mover_puzzle.tree_hash())) + + def SpendTimeout(self): + """ + returns (solution, movercoinid, waitercoinid) + """ + movercoinid = Coin(self.coin.name(), self.mover_puzzle.tree_hash(), self.split).name() + waitercoinid = Coin(self.coin.name(), self.waiter_puzzle.tree_hash(), + self.coin.amount - self.split).name() + return (Program.to((timeout, 0)), movercoinid, waitercoinid) + +@dataclass +class RefereeAccuseWrap: + coin: Any + old_validation_puzzle_hash: Any + new_validation_puzzle_hash: Any + move: Any + split: Any + timeout: Any + accused_puzzle_hash: Any + accuser_puzzle_hash: Any + + def get_puzzle(self): + return referee_accuse.curry([self.old_validation_puzzle_hash, self.new_validation_puzzle_hash, + self.move, self.split, self.coin.amount, self.timeout, self.accused_puzzle_hash, + self.accuser_puzzle_hash]) + + def SpendTimeout(self): + """ + returns (solution, coinid) + """ + coin = Coin(self.coin.name(), self.accuser_puzzle_hash, self.coin.amount) + return (Program.to(0), coin.name()) + + def SpendDefend(self, validation_program_reveal, validation_program_solution): + """ + returns (solution, coinid) + """ + solution = Program.to([validation_program_reveal, validation_program_solution]) + coin = Coin(self.coin.name(), self.accused_puzzle_hash, self.coin.amount) + return (solution, coin.name()) + +@pytest.mark.asyncio +@pytest.mark.parametrize('amove', [0, 1, 2]) +@pytest.mark.parametrize('bmove', [0, 1, 2]) +async def test_rps(amove, bmove, setup_sim): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = int_to_bytes(60 + amove) + alice_image = sha(alice_preimage) + bob_preimage = int_to_bytes(60 + bmove) + bob_image = sha(bob_preimage) + alice_move = int_to_bytes(amove) + nil = Program.to(0) + + # (mod (password . conditions) (if (= password 'alice') conditions (x))) + alice_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0185616c69636580ffff0103ffff01ff088080ff0180')) + alice_puzzle_hash = alice_puzzle.tree_hash() + # (mod (password . conditions) (if (= password 'bob') conditions (x))) + bob_puzzle = Program.from_bytes(bytes.fromhex('ff02ffff03ffff09ff02ffff0183626f6280ffff0103ffff01ff088080ff0180')) + bob_puzzle_hash = bob_puzzle.tree_hash() + + async with setup_sim as (sym, client): + acs = Program.to(1) + acs_hash = acs.tree_hash() + await sym.farm_block(acs_hash) + mycoin = (await client.get_coin_records_by_puzzle_hashes([acs_hash], include_spent_coins = False))[0].coin + # make a coin for a game + referee = bootstrap_referee(mycoin.name(), MOD_A.tree_hash(), 2, total, 1000, 50, alice_puzzle, bob_puzzle) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(mycoin, acs, Program.to([[51, referee.coin.puzzle_hash, + referee.coin.amount]]))], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse Bob of cheating (negative test, should fail) + solution, accuse = referee.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_MY_PARENT_ID_FAILED + # timeout too early fail + solution, alice_reward_id, bob_reward_id = referee.SpendTimeout() + spend = SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # timeout succeeds + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == 2 + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == total - 2 + await sym.rewind(savepoint) + # Alice makes an illegally large move, fails + solution, ref2 = referee.SpendMove('alice', bytes(100), 0, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with negative split, fails + solution, ref2 = referee.SpendMove('alice', 'abc', -1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice makes move with split greater than amount, fails + solution, ref2 = referee.SpendMove('alice', 'abc', referee.coin.amount + 1, bytes(32)) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Alice move 1 commit to image + bpuz = MOD_B.curry(alice_image) + solution, ref2 = referee.SpendMove('alice', alice_image, 0, bpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(referee.coin, referee.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuse Alice of cheating + solution, accuse = ref2.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint2 = sym.block_height + # Alice accusation defend, gets everything + solution, reward_id = accuse.SpendDefend(MOD_A, nil) + print(solution) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == alice_puzzle_hash + await sym.rewind(savepoint2) + # accusation timeout too early fail + solution, reward_id = accuse.SpendTimeout() + spend = SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.ASSERT_SECONDS_RELATIVE_FAILED + # accusation timeout succeed, Bob gets everything + sym.pass_time(2000) + await sym.farm_block() + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + reward_coin_wrapper = await client.get_coin_records_by_names([reward_id], include_spent_coins = + False) + reward_coin = reward_coin_wrapper[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Bob move 2 commit to image + cpuz = MOD_C.curry([alice_image, bob_image]) + solution, ref3 = ref2.SpendMove('bob', bob_image, 0, cpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref2.coin, ref2.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice accuse + solution, accuse = ref3.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(bpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + reward_coin = (await client.get_coin_records_by_names([reward_id], include_spent_coins = + False))[0].coin + assert reward_coin.amount == referee.coin.amount + assert reward_coin.puzzle_hash == bob_puzzle_hash + await sym.rewind(savepoint) + # Alice reveals wrong preimage + alice_bad_preimage = int_to_bytes(61 + amove) + dpuz = MOD_D.curry([(amove + 1) % 3, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends, fails + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Alice move 3 reveal preimage + dpuz = MOD_D.curry([alice_move, bob_image]) + solution, ref4 = ref3.SpendMove('alice', alice_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref3.coin, ref3.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Bob accuses + solution, accuse = ref4.SpendAccuse('bob') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice defends + solution, reward_id = accuse.SpendDefend(cpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.rewind(savepoint) + # Bob move 4 reveal wrong preimage + bob_bad_preimage = int_to_bytes(121 + amove) + solution, ref5 = ref4.SpendMove('bob', bob_bad_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # Bob attempts defense with wrong validation program, fails + solution, reward_id = accuse.SpendDefend(acs, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + if amove == bmove: + # Bob move 4 gives wrong split + solution, ref5 = ref4.SpendMove('bob', bob_preimage, 0, dpuz.tree_hash()) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob attempts defense, fails + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + await sym.rewind(savepoint) + # Bob move 4 reveal preimage + solution, ref5 = ref4.SpendMove('bob', bob_preimage, alice_final, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref4.coin, ref4.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + savepoint = sym.block_height + # Alice attempts move, fails + solution, ref6 = ref5.SpendMove('alice', nil, 0, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.FAILED + assert err == Err.GENERATOR_RUNTIME_ERROR + # timeout, split correct + sym.pass_time(2000) + await sym.farm_block() + solution, alice_reward_id, bob_reward_id = ref5.SpendTimeout() + spend = SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), solution)], G2Element()) + (status, err) = await client.push_tx(spend) + assert status == MempoolInclusionStatus.SUCCESS + assert err is None + await sym.farm_block() + if alice_final != 0: + assert (await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False))[0].coin.amount == alice_final + else: + assert len(await client.get_coin_records_by_names([alice_reward_id], include_spent_coins = False)) == 0 + if alice_final != ref5.coin.amount: + assert (await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False))[0].coin.amount == ref5.coin.amount - alice_final + else: + assert len(await client.get_coin_records_by_names([bob_reward_id], include_spent_coins = False)) == 0 + await sym.rewind(savepoint) + # Alice accuses + solution, accuse = ref5.SpendAccuse('alice') + (status, err) = await client.push_tx(SpendBundle([CoinSpend(ref5.coin, ref5.get_puzzle(), + solution)], G2Element())) + assert status == MempoolInclusionStatus.SUCCESS + await sym.farm_block() + # Bob defends + solution, reward_id = accuse.SpendDefend(dpuz, nil) + (status, err) = await client.push_tx(SpendBundle([CoinSpend(accuse.coin, accuse.get_puzzle(), + solution)], G2Element())) + assert (status, err) == (MempoolInclusionStatus.SUCCESS, None) diff --git a/resources/tests/game-referee-in-cl23/testrockpaperscissors.py b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py new file mode 100644 index 000000000..ed45dbccc --- /dev/null +++ b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py @@ -0,0 +1,48 @@ +import hashlib + +from hsms.streamables.program import Program +from hsms.puzzles.load_clvm import load_clvm + +from clvm.EvalError import EvalError + + +MOD_A = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsa.clvm.hex").read())) +MOD_B = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsb.clvm.hex").read())) +MOD_C = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsc.clvm.hex").read())) +MOD_D = Program.from_bytes(bytes.fromhex(open("rockpaperscissorsd.clvm.hex").read())) + + +def drun(prog: Program, *args: Program): + try: + return prog.run(*args) + except EvalError as ee: + print(f"brun -x -y main.sym {prog} {Program.to(list(args))}") + raise + +def sha256(blob:bytes) -> bytes: + return hashlib.sha256(blob).digest() + +def testrps(amove, bmove): + total = 100 + alice_final = (total//2 if amove == bmove else (0 if bmove == (amove + 1) % 3 else total)) + alice_preimage = Program.to(60 + amove) + bob_preimage = Program.to(60 + bmove) + alice_image = sha256(alice_preimage.atom) + bob_image = sha256(bob_preimage.atom) + alice_move = Program.to(amove) + + cd = MOD_D.curry(alice_move, bob_image) + assert cd.run([total, bob_preimage, b'', alice_final, b'j']).atom == b'j' + cc = MOD_C.curry(alice_image, bob_image) + assert cc.run([total, alice_preimage, cd.tree_hash(), 0, b'j']).atom == b'j' + cb = MOD_B.curry(alice_image) + assert cb.run([total, bob_image, cc.tree_hash(), 0, b'j']).atom == b'j' + assert MOD_A.run([total, alice_image, cb.tree_hash(), 0, b'j']).atom == b'j' + +def testall(): + for i in range(3): + for j in range(3): + testrps(i, j) + +if __name__ == '__main__': + testall() diff --git a/resources/tests/game-referee-in-cl23/truncate.clinc b/resources/tests/game-referee-in-cl23/truncate.clinc new file mode 100644 index 000000000..e4557f31c --- /dev/null +++ b/resources/tests/game-referee-in-cl23/truncate.clinc @@ -0,0 +1,8 @@ +( +(defun truncate (N (@ L (LF . LR))) + (if (all N L) + (c LF (truncate (- N 1) LR)) + () + ) +) +) \ No newline at end of file diff --git a/resources/tests/game-referee-in-cl23/utils.clinc b/resources/tests/game-referee-in-cl23/utils.clinc new file mode 100644 index 000000000..72873dd66 --- /dev/null +++ b/resources/tests/game-referee-in-cl23/utils.clinc @@ -0,0 +1,2 @@ +( +) From e53cc58d4d95f128ba13fdc0c5a94af36cc08aca Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 16:38:53 -0700 Subject: [PATCH 31/48] Add hsms dependency because it appears in cl23 tests --- support/test-game-referee.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/support/test-game-referee.sh b/support/test-game-referee.sh index 31e28a93a..fdf384312 100755 --- a/support/test-game-referee.sh +++ b/support/test-game-referee.sh @@ -10,6 +10,7 @@ REF_SUBDIR="$1" python -m pip install --upgrade pip python -m pip install chia_rs==0.2.5 python -m pip install clvm_tools +python -m pip install hsms python -m pip install pytest export PYTHONPATH=$PWD/resources/tests:.:$PYTHONPATH From 6dbf7bd72349adf6636e83c7815b98a82997bfe3 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 16:56:05 -0700 Subject: [PATCH 32/48] Remove hsms dependency since it interferes with other tests --- resources/tests/game-referee-in-cl23/test_library_basics.py | 2 +- resources/tests/game-referee-in-cl23/testnoncegame.py | 2 +- resources/tests/game-referee-in-cl23/testreferee.py | 2 +- resources/tests/game-referee-in-cl23/testrockpaperscissors.py | 3 +-- support/test-game-referee.sh | 1 - 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/resources/tests/game-referee-in-cl23/test_library_basics.py b/resources/tests/game-referee-in-cl23/test_library_basics.py index 3d42a3644..321ea5aa5 100644 --- a/resources/tests/game-referee-in-cl23/test_library_basics.py +++ b/resources/tests/game-referee-in-cl23/test_library_basics.py @@ -1,7 +1,7 @@ import pytest import random from itertools import permutations -from hsms.streamables.program import Program +from chia.types.blockchain_format.program import Program from steprun import diag_run_clvm, compile_module_with_symbols compile_module_with_symbols(['.'], 'smoke_test_deep_compare.clsp') diff --git a/resources/tests/game-referee-in-cl23/testnoncegame.py b/resources/tests/game-referee-in-cl23/testnoncegame.py index 3b4cd2c2a..7f710cab4 100644 --- a/resources/tests/game-referee-in-cl23/testnoncegame.py +++ b/resources/tests/game-referee-in-cl23/testnoncegame.py @@ -1,6 +1,6 @@ import hashlib -from hsms.streamables.program import Program +from chia.types.blockchain_format.program import Program from clvm.EvalError import EvalError diff --git a/resources/tests/game-referee-in-cl23/testreferee.py b/resources/tests/game-referee-in-cl23/testreferee.py index 01eb53643..11ecc88dd 100644 --- a/resources/tests/game-referee-in-cl23/testreferee.py +++ b/resources/tests/game-referee-in-cl23/testreferee.py @@ -5,7 +5,7 @@ from pathlib import Path from clvm.casts import int_to_bytes, int_from_bytes -from hsms.streamables.program import Program +from chia.types.blockchain_format.program import Program from clvm_tools_rs import compile_clvm from clvm_tools.binutils import disassemble diff --git a/resources/tests/game-referee-in-cl23/testrockpaperscissors.py b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py index ed45dbccc..1ee1534ea 100644 --- a/resources/tests/game-referee-in-cl23/testrockpaperscissors.py +++ b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py @@ -1,7 +1,6 @@ import hashlib -from hsms.streamables.program import Program -from hsms.puzzles.load_clvm import load_clvm +from chia.types.blockchain_format.program import Program from clvm.EvalError import EvalError diff --git a/support/test-game-referee.sh b/support/test-game-referee.sh index fdf384312..31e28a93a 100755 --- a/support/test-game-referee.sh +++ b/support/test-game-referee.sh @@ -10,7 +10,6 @@ REF_SUBDIR="$1" python -m pip install --upgrade pip python -m pip install chia_rs==0.2.5 python -m pip install clvm_tools -python -m pip install hsms python -m pip install pytest export PYTHONPATH=$PWD/resources/tests:.:$PYTHONPATH From 983db0d8ec64cf7bd038c651d510d7a254710011 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 18:28:47 -0700 Subject: [PATCH 33/48] Do the new test first so we can see failures earlier, take the strategy from earlier tests (thanks adam) toward Program --- .github/workflows/extensive-tests.yml | 2 +- resources/tests/game-referee-in-cl23/steprun.py | 2 +- resources/tests/game-referee-in-cl23/test_library_basics.py | 2 +- resources/tests/game-referee-in-cl23/testnoncegame.py | 2 +- resources/tests/game-referee-in-cl23/testreferee.py | 2 +- resources/tests/game-referee-in-cl23/testrockpaperscissors.py | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/extensive-tests.yml b/.github/workflows/extensive-tests.yml index d9ea44687..4d34d8770 100644 --- a/.github/workflows/extensive-tests.yml +++ b/.github/workflows/extensive-tests.yml @@ -117,6 +117,6 @@ jobs: run: | . ./activate cp support/test-game-referee.sh . + sh test-game-referee.sh resources/tests/game-referee-in-cl23 sh test-game-referee.sh resources/tests/game-referee-in-cl21 sh test-game-referee.sh resources/tests/game-referee-after-cl21 - sh test-game-referee.sh resources/tests/game-referee-in-cl23 diff --git a/resources/tests/game-referee-in-cl23/steprun.py b/resources/tests/game-referee-in-cl23/steprun.py index 531205ac4..3ae6d1ce8 100644 --- a/resources/tests/game-referee-in-cl23/steprun.py +++ b/resources/tests/game-referee-in-cl23/steprun.py @@ -4,7 +4,7 @@ import json from clvm_tools.binutils import assemble, disassemble from clvm_tools_rs import start_clvm_program, compose_run_function, compile_clvm -from chia.types.blockchain_format.program import Program +from clvm_rs import Program def compile_module_with_symbols(include_paths,source): path_obj = Path(source) diff --git a/resources/tests/game-referee-in-cl23/test_library_basics.py b/resources/tests/game-referee-in-cl23/test_library_basics.py index 321ea5aa5..58d18bdfb 100644 --- a/resources/tests/game-referee-in-cl23/test_library_basics.py +++ b/resources/tests/game-referee-in-cl23/test_library_basics.py @@ -1,7 +1,7 @@ import pytest import random from itertools import permutations -from chia.types.blockchain_format.program import Program +from clvm_rs import Program from steprun import diag_run_clvm, compile_module_with_symbols compile_module_with_symbols(['.'], 'smoke_test_deep_compare.clsp') diff --git a/resources/tests/game-referee-in-cl23/testnoncegame.py b/resources/tests/game-referee-in-cl23/testnoncegame.py index 7f710cab4..523f01fab 100644 --- a/resources/tests/game-referee-in-cl23/testnoncegame.py +++ b/resources/tests/game-referee-in-cl23/testnoncegame.py @@ -1,6 +1,6 @@ import hashlib -from chia.types.blockchain_format.program import Program +from clvm_rs import Program from clvm.EvalError import EvalError diff --git a/resources/tests/game-referee-in-cl23/testreferee.py b/resources/tests/game-referee-in-cl23/testreferee.py index 11ecc88dd..a63769b35 100644 --- a/resources/tests/game-referee-in-cl23/testreferee.py +++ b/resources/tests/game-referee-in-cl23/testreferee.py @@ -5,7 +5,7 @@ from pathlib import Path from clvm.casts import int_to_bytes, int_from_bytes -from chia.types.blockchain_format.program import Program +from clvm_rs import Program from clvm_tools_rs import compile_clvm from clvm_tools.binutils import disassemble diff --git a/resources/tests/game-referee-in-cl23/testrockpaperscissors.py b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py index 1ee1534ea..f435a006e 100644 --- a/resources/tests/game-referee-in-cl23/testrockpaperscissors.py +++ b/resources/tests/game-referee-in-cl23/testrockpaperscissors.py @@ -1,6 +1,6 @@ import hashlib -from chia.types.blockchain_format.program import Program +from clvm_rs import Program from clvm.EvalError import EvalError From 28bb37c041fc8e212593ead24d2b99f083b37266 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 18:51:46 -0700 Subject: [PATCH 34/48] Set unsafe run cost --- resources/tests/game-referee-in-cl23/test_library_basics.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/resources/tests/game-referee-in-cl23/test_library_basics.py b/resources/tests/game-referee-in-cl23/test_library_basics.py index 58d18bdfb..d1f7a68ef 100644 --- a/resources/tests/game-referee-in-cl23/test_library_basics.py +++ b/resources/tests/game-referee-in-cl23/test_library_basics.py @@ -4,6 +4,8 @@ from clvm_rs import Program from steprun import diag_run_clvm, compile_module_with_symbols +Program.set_run_unsafe_max_cost(11000000000) + compile_module_with_symbols(['.'], 'smoke_test_deep_compare.clsp') compare_program = Program.from_bytes(bytes.fromhex(open('smoke_test_deep_compare.clvm.hex').read())) From 9cfc9f12324eef494d5a799361ecab24e4e39de6 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 19:11:37 -0700 Subject: [PATCH 35/48] remove terse, as it doesn't yet exist in this reality --- resources/tests/game-referee-in-cl23/steprun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/tests/game-referee-in-cl23/steprun.py b/resources/tests/game-referee-in-cl23/steprun.py index 3ae6d1ce8..64a8d84cb 100644 --- a/resources/tests/game-referee-in-cl23/steprun.py +++ b/resources/tests/game-referee-in-cl23/steprun.py @@ -39,7 +39,7 @@ def diag_run_clvm(program, args, symbols): hex_form_of_program = binascii.hexlify(bytes(program)).decode('utf8') hex_form_of_args = binascii.hexlify(bytes(args)).decode('utf8') symbols = json.loads(open(symbols).read()) - p = start_clvm_program(hex_form_of_program, hex_form_of_args, symbols, None, {"terse":True}) + p = start_clvm_program(hex_form_of_program, hex_form_of_args, symbols, None) report = run_until_end(p) if 'Failure' in report: raise Exception(report) From 37aa20ccc12d4fdac7b2b0d0ed363a0aec499972 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 20:12:02 -0700 Subject: [PATCH 36/48] Use methods present in clvm_rs' Program, which are slightly different --- resources/tests/game-referee-in-cl23/test_library_basics.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/tests/game-referee-in-cl23/test_library_basics.py b/resources/tests/game-referee-in-cl23/test_library_basics.py index d1f7a68ef..10327d01f 100644 --- a/resources/tests/game-referee-in-cl23/test_library_basics.py +++ b/resources/tests/game-referee-in-cl23/test_library_basics.py @@ -51,7 +51,7 @@ def proper_list(cl): return proper_list_inner(result,cl) def int_list(cl): - return [Program.to(x).as_int() for x in Program.to(cl).as_atom_list()] + return [int(x) for x in Program.to(cl).as_iter()] def de_none_list(l): return [x if x is not None else [] for x in l] From 984ef9559f16e44251e07cf8e6d88d7b83b56ef1 Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 22:20:10 -0700 Subject: [PATCH 37/48] Removing diff --- .github/workflows/build-arm64-wheels.yml | 7 +------ .github/workflows/build-m1-wheel.yml | 11 +++-------- .github/workflows/build-test.yml | 24 +++--------------------- src/compiler/cldb.rs | 5 ----- 4 files changed, 7 insertions(+), 40 deletions(-) diff --git a/.github/workflows/build-arm64-wheels.yml b/.github/workflows/build-arm64-wheels.yml index 97ccdd435..6d8a5f72c 100644 --- a/.github/workflows/build-arm64-wheels.yml +++ b/.github/workflows/build-arm64-wheels.yml @@ -37,18 +37,13 @@ jobs: rustup target add aarch64-unknown-linux-musl rm -rf venv export PATH="${PATH}:/opt/python/cp39-cp39/bin/:/opt/python/cp38-cp38/bin/:/opt/python/cp37-cp37m/bin/" - - name: Build Python wheels run: | /opt/python/cp38-cp38/bin/python -m venv venv if [ ! -f "activate" ]; then ln -s venv/bin/activate; fi . ./activate pip install maturin==1.1.0 - pip install tomlkit - USE_FEATURES=$(./support/feature-fishing.py) - echo "USE_FEATURES=${USE_FEATURES}" >> "$GITHUB_ENV" - export - CC=gcc maturin build --release --strip --manylinux 2014 "--features=extension-module,${USE_FEATURES}" + CC=gcc maturin build --release --strip --manylinux 2014 - name: Upload artifacts uses: actions/upload-artifact@v3 with: diff --git a/.github/workflows/build-m1-wheel.yml b/.github/workflows/build-m1-wheel.yml index 725bfcad3..a7a3c0a4e 100644 --- a/.github/workflows/build-m1-wheel.yml +++ b/.github/workflows/build-m1-wheel.yml @@ -52,13 +52,9 @@ jobs: python3 -m venv venv . ./venv/bin/activate export PATH=~/.cargo/bin:$PATH - arch -arm64 pip install tomlkit - USE_FEATURES=$(arch -arm64 ./support/feature-fishing.py) - echo "USE_FEATURES=${USE_FEATURES}" >> "$GITHUB_ENV" - arch -arm64 pip install maturin==1.1.0 - arch -arm64 maturin build -i python --release --strip "--features=extension-module,${USE_FEATURES}" - echo "cargo test using features: ${USE_FEATURES}" - arch -arm64 cargo test --features="${USE_FEATURES}" + pip install maturin==1.1.0 + maturin build -i python --release --strip + cargo test - name: Install clvm_tools_rs wheel run: | @@ -106,7 +102,6 @@ jobs: - name: Run tests from clvm_tools run: | . ./venv/bin/activate - arch -arm64 cargo test --features="${USE_FEATURES}" cd clvm_tools pytest diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index a6ee8a771..b3f9b9f7a 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -49,13 +49,6 @@ jobs: run: | python -m pip install maturin==1.1.0 - - name: Set up feature flags to use - shell: bash - run: | - python -m pip install tomlkit - USE_FEATURES=$(./support/feature-fishing.py) - echo "USE_FEATURES=${USE_FEATURES}" >> "$GITHUB_ENV" - - name: Build MacOs with maturin on Python ${{ matrix.python }} if: startsWith(matrix.os, 'macos') env: @@ -98,10 +91,9 @@ jobs: - name: Build Windows with maturin on Python ${{ matrix.python }} if: startsWith(matrix.os, 'windows') - shell: bash run: | python -m venv venv - cp venv/Scripts/activate . + echo ". .\venv\Scripts\Activate.ps1" > activate.ps1 . ./activate maturin build -i python --release --strip # Find and install the newly built wheel @@ -148,16 +140,6 @@ jobs: python -c 'import clvm_tools_rs; print(clvm_tools_rs.__file__)' echo "CLVM_TOOLS_RS_VERSION=$(python -c 'import clvm_tools_rs; print(clvm_tools_rs.get_version())')" >> "$GITHUB_ENV" - # Test cldb output both run from python and via its command line tool. - # Thanks: https://stackoverflow.com/questions/9948517/how-to-stop-a-powershell-script-on-the-first-error - - name: "Run step run tests" - shell: bash - run: | - . ./activate - cargo build --no-default-features --features="${USE_FEATURES}" - cd resources/tests && \ - python test_clvm_step.py && \ - python mandelbrot-cldb.py - name: Verify recompilation of old sources match with new compiler if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') @@ -165,7 +147,7 @@ jobs: set -x . ./activate # Build cmd line tools - PYO3_PYTHON=`which python` cargo build --no-default-features --features="${USE_FEATURES}" --release + PYO3_PYTHON=`which python` cargo build --no-default-features --release # Grab chia-blockchain rm -rf chia-blockchain @@ -228,7 +210,7 @@ jobs: - name: Run tests if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') - run: cargo test --features="${USE_FEATURES}" + run: cargo test --no-default-features - name: Exhaustive assign tests if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') diff --git a/src/compiler/cldb.rs b/src/compiler/cldb.rs index 464c943ac..b85a27481 100644 --- a/src/compiler/cldb.rs +++ b/src/compiler/cldb.rs @@ -21,11 +21,9 @@ use crate::compiler::clvm::{convert_from_clvm_rs, run_step, RunStep}; use crate::compiler::runtypes::RunFailure; use crate::compiler::sexp::SExp; use crate::compiler::srcloc::Srcloc; -#[cfg(feature = "debug-print")] use crate::util::u8_from_number; use crate::util::Number; -#[cfg(feature = "debug-print")] fn print_atom() -> SExp { SExp::Atom(Srcloc::start("*print*"), b"$print$".to_vec()) } @@ -114,7 +112,6 @@ pub struct CldbRun { outputs_to_step: HashMap, } -#[cfg(feature = "debug-print")] fn humanize(a: Rc) -> Rc { match a.borrow() { SExp::Integer(l, i) => { @@ -135,7 +132,6 @@ fn humanize(a: Rc) -> Rc { } } -#[cfg(feature = "debug-print")] fn is_print_request(a: &SExp) -> Option<(Srcloc, Rc)> { if let SExp::Cons(l, f, r) = a { if &print_atom() == f.borrow() { @@ -241,7 +237,6 @@ impl CldbRun { let args = format_arg_inputs(&arg_associations); self.to_print.insert("Argument-Refs".to_string(), args); } else if v == 34_u32.to_bigint().unwrap() { - #[cfg(feature = "debug-print")] // Handle diagnostic output. if let Some((loc, outputs)) = is_print_request(a) { self.to_print From 2707446def038a2e8ef7a082542d23191d31bfff Mon Sep 17 00:00:00 2001 From: arty Date: Wed, 1 Nov 2023 22:22:47 -0700 Subject: [PATCH 38/48] Remove some alternate future artifacts --- support/feature-fishing.py | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100755 support/feature-fishing.py diff --git a/support/feature-fishing.py b/support/feature-fishing.py deleted file mode 100755 index d63850b7c..000000000 --- a/support/feature-fishing.py +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env python - -from tomlkit import parse -import sys - -cargo_toml = parse(open('Cargo.toml').read()) -results=",".join(list(filter(lambda x: x != 'extension-module', cargo_toml['features']['default']))) -if len(sys.argv) > 1: - print(f"{sys.argv[1]}{results}") -else: - print(results) From dc616467e72c9ed02c1add4fa43a90bc8ca08096 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:12:31 -0800 Subject: [PATCH 39/48] Make extra param optional for other users --- resources/tests/lib/steprun.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/resources/tests/lib/steprun.py b/resources/tests/lib/steprun.py index a6cd37257..fe3332660 100644 --- a/resources/tests/lib/steprun.py +++ b/resources/tests/lib/steprun.py @@ -37,7 +37,9 @@ def run_until_end(p): return last -def diag_run_clvm(program, args, symbols, options): +def diag_run_clvm(program, args, symbols, options=None): + if options is None: + options = {} hex_form_of_program = binascii.hexlify(bytes(program)).decode('utf8') hex_form_of_args = binascii.hexlify(bytes(args)).decode('utf8') symbols = json.loads(open(symbols).read()) From 5ce518fd7c975433435d9b86dd30974ab8214531 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:13:45 -0800 Subject: [PATCH 40/48] Ensure we set the frugal version of the diag runner --- .../tests/game-referee-after-cl21/test_library_basics.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/resources/tests/game-referee-after-cl21/test_library_basics.py b/resources/tests/game-referee-after-cl21/test_library_basics.py index 926ddde7a..c8cce6664 100644 --- a/resources/tests/game-referee-after-cl21/test_library_basics.py +++ b/resources/tests/game-referee-after-cl21/test_library_basics.py @@ -70,7 +70,7 @@ def test_smoke_compare(): compare_program.run(Program.to([])) def test_handcalc(): - diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym') + diag_run_clvm(test_handcalc_program, Program.to([]), 'test_handcalc.sym', {'print': True}) def proper_list_inner(result,cl): if hasattr(cl, 'pair') and cl.pair is not None: @@ -137,20 +137,20 @@ def test_permutations_2(): all_b_string = 0x626262626262 for try_list in [[all_a_string,all_b_string], [all_b_string,all_a_string]]: want_set = list([list(v) for v in sorted(permutations(try_list))]) - listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym') + listed_result = diag_run_clvm(smoke_test_permutations_program, Program.to([try_list]), 'smoke_test_permutations.sym', {'print': True}) pl = proper_list(listed_result) perms_result = sorted([int_list(x) for x in de_none_list(pl)]) assert want_set == perms_result def test_chialisp_sort_program(): - diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym') + diag_run_clvm(test_sort_program, Program.to([]), 'test_sort.sym', {'print': True}) def test_permutations_n(): for i in range(3,6): do_test_permutations_of_size_n(i) def test_chialisp_permutations_program(): - diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym') + diag_run_clvm(test_permutations_program, Program.to([3, 5]), 'test_permutations.sym', {'print': True}) def test_smoke_sort(): for length in range(7): # 0-7 length From d53699e01091b6c4f31d9b709b99af0e911243db Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:20:26 -0800 Subject: [PATCH 41/48] Run on unix-y things --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index d5f1f120c..bb324ed5d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -154,7 +154,7 @@ jobs: python mandelbrot-cldb.py - name: "Test step run with mandelbrot, setting print only" - shell: bash + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | . ./activate python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > /tmp/mand_output.txt From 6e728eb9baf0aff7e9299abb4275b63d2849a595 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:36:05 -0800 Subject: [PATCH 42/48] Remove extras --- .github/workflows/build-test.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index bb324ed5d..c29a1120c 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -142,7 +142,6 @@ jobs: # Test cldb output both run from python and via its command line tool. - name: "Run step run tests" - shell: bash run: | . ./activate cargo build @@ -154,7 +153,6 @@ jobs: python mandelbrot-cldb.py - name: "Test step run with mandelbrot, setting print only" - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.python, '3.8') run: | . ./activate python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > /tmp/mand_output.txt From d54d39083c8ea4ad335baf07283475a5c15d1d2c Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:43:07 -0800 Subject: [PATCH 43/48] Remove '\' which isn't recognized in this shell --- .github/workflows/build-test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index c29a1120c..9f8bb5937 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -148,9 +148,7 @@ jobs: pip install . pip install clvm_rs pip install clvm_tools - cd resources/tests && \ - python test_clvm_step.py && \ - python mandelbrot-cldb.py + cd resources/tests && python test_clvm_step.py && python mandelbrot-cldb.py - name: "Test step run with mandelbrot, setting print only" run: | From 0025a99fbbb76548a659f125c2ae0bcbd426a0a1 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 11:51:23 -0800 Subject: [PATCH 44/48] Don't refer to /tmp --- .github/workflows/build-test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 9f8bb5937..aab35cd7e 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -153,9 +153,10 @@ jobs: - name: "Test step run with mandelbrot, setting print only" run: | . ./activate - python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > /tmp/mand_output.txt + python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > mand_output.txt # Fail if the output differs. - diff -s -q /tmp/mand_output.txt ./resources/tests/mandelbrot/mand_test.txt + diff -s -q mand_output.txt ./resources/tests/mandelbrot/mand_test.txt + rm -f mand_output.txt - name: Verify recompilation of old sources match with new compiler From b27295449c71b334c6e3bc48ba9e449cbc855c9f Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 12:02:37 -0800 Subject: [PATCH 45/48] Use git diff as it should be present --- .github/workflows/build-test.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index aab35cd7e..4ea8671bb 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -154,8 +154,7 @@ jobs: run: | . ./activate python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > mand_output.txt - # Fail if the output differs. - diff -s -q mand_output.txt ./resources/tests/mandelbrot/mand_test.txt + git diff --no-index -s --quiet -- mand_output.txt ./resources/tests/mandelbrot/mand_test.txt rm -f mand_output.txt From e7bab472f041fa456e091cfe132329a501606213 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 12:04:13 -0800 Subject: [PATCH 46/48] Add comment --- .github/workflows/build-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 4ea8671bb..becc49145 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -154,6 +154,7 @@ jobs: run: | . ./activate python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > mand_output.txt + # git diff invoked this way returns 0 (as /bin/true) if there is no difference or 1 if there is. git diff --no-index -s --quiet -- mand_output.txt ./resources/tests/mandelbrot/mand_test.txt rm -f mand_output.txt From e87aa3ae782447d5024fe026e211e636056c00a6 Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 12:10:33 -0800 Subject: [PATCH 47/48] use long name since we're in a wierd shell --- .github/workflows/build-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index becc49145..c4028515d 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -156,7 +156,7 @@ jobs: python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > mand_output.txt # git diff invoked this way returns 0 (as /bin/true) if there is no difference or 1 if there is. git diff --no-index -s --quiet -- mand_output.txt ./resources/tests/mandelbrot/mand_test.txt - rm -f mand_output.txt + rm --force mand_output.txt - name: Verify recompilation of old sources match with new compiler From 8c34084366a6703a0bccb0a1c9f58c5f26903c6d Mon Sep 17 00:00:00 2001 From: arty Date: Fri, 17 Nov 2023 13:03:33 -0800 Subject: [PATCH 48/48] ci --- .github/workflows/build-test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index c4028515d..c5a5ef7d7 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -156,7 +156,9 @@ jobs: python ./resources/tests/lib/steprun.py ./resources/tests/mandelbrot/mandelbrot.clvm.hex resources/tests/mandelbrot/mand_args.txt ./resources/tests/mandelbrot/mandelbrot.sym > mand_output.txt # git diff invoked this way returns 0 (as /bin/true) if there is no difference or 1 if there is. git diff --no-index -s --quiet -- mand_output.txt ./resources/tests/mandelbrot/mand_test.txt - rm --force mand_output.txt + # Remove file in a compatible way using git as a general tool + git add mand_output.txt + git rm --force mand_output.txt - name: Verify recompilation of old sources match with new compiler