Notice: Welcome to TinyChan, an account has automatically been created and assigned to you, you don't have to register or log in to use the board, but don't clear your cookies unless you have set a memorable name and password. Alternatively, you can restore your ID. The use of this site requires cookies to be enabled; please cease browsing this site if you don't consent.

TinyChan

New reply in topic: Bytebeat/Floatbeat/Funcbeat

You are not recognized as the original poster of this topic.

:

You are required to fill in a captcha for your first 5 posts. Sorry, but this is required to stop people from posting while drunk. Please be responsible and don't drink and post!
If you receive this often, consider not clearing your cookies.

Please familiarise yourself with the rules and markup syntax before posting.


Replying to stack-oriented math expression…

let mod=(n,m)=>(n%m+m)%m,
    oper={
  "+":(a,b)=>a+b,"-":(a,b)=>a-b,
  "*":(a,b)=>a*b,"/":(a,b)=>a/b,
  "%":mod,"**":(a,b)=>a**b
},fun={ //.length for N of arguments
  sin:Math.sin,rand:Math.random,
  abs:Math.abs,floor:Math.floor
},chooseRand=a=>a[Math.floor(Math.random()*a.length)];
/*
Examples of Reverse Polish Notation (RPN):
  t 220 * 1 % → (t*220)%1
  rand 1 t 1 % - 5 ** * → rand()*((1-(t%1))**5)
  .5 1 10 t * 2 % - abs - → .5-abs(1-((10*t)%2))
*/
function genExpr(){
  const ops=Object.keys(oper),
        unaries=Object.keys(fun).filter(k=>fun[k].length===1),
        terminals=["t",...Object.keys(fun).filter(k=>fun[k].length===0)];
  let stack=[],esd=0,maxLen=10; //eval stack depth
  while(esd<1||Math.random()>.2||stack.length<3){
    let options=["terminal"];
    if(esd>=1)options.push("unary");
    if(esd>=2)options.push("binary");
    const choice=chooseRand(options);
    switch(choice){
      case"terminal":
        if(Math.random()<.2){
          stack.push(chooseRand(terminals));
        }else{
          stack.push(floor(random()*21)*.5-5);
        }
        esd++;
      break;
      case"unary":
        stack.push(chooseRand(unaries));
      break;
      case"binary":
        stack.push(chooseRand(ops));
        esd--;
      break;
    }
    if(stack.length>=maxLen)break;
  }
  //ensure minimum size and balance
  while(esd!==1||stack.length<3){
    if(esd<1){
      stack.push(chooseRand([.5,1])); //push dummy operand
      esd++;
    }else if(esd>1){
      stack.push("+"); //try to reduce stack
      esd--;
    }else{break;}
  }
  return stack;
}
function evalExpr(stack){
  return function(tVal){
    let s=[];
    for(let token of stack){
      try{
        if(typeof token==="number"){
          s.push(token);
        }else if(token==="t"){
          s.push(tVal);
        }else if(oper.hasOwnProperty(token)){
          if(s.length<2)return 0; //not enough
          const b=s.pop(),a=s.pop(),
                result=oper[token](a,b);
          s.push(isFinite(result)?result:0);
        }else if(fun.hasOwnProperty(token)){
          if(fun[token].length===0){s.push(fun[token]());continue;} //e.g. rand
          if(!s.length)return 0; //no args to push
          const result=fun[token](s.pop()); //TODO: multiple args
          s.push(isFinite(result)?result:0);
        }else{return 0;}
      }catch(e){
        console.error("Eval error:",e,"at",token);
        return 0;
      }
    }
    const result=s.pop()||0;
    return isNaN(result)||!isFinite(result)?0:result;
  };
}
/*let timer={
  t:0,l:.1
},expr=genExpr(),eFun=evalExpr(expr);
return(t,SR)=>{
  timer.t+=1/SR;
  if(timer.t>=timer.l){
    timer.t%=timer.l;
    expr=genExpr();eFun=evalExpr(expr);
  }
  return eFun(t);
};*/
let split=str=>str.split(" ").map(e=>{let n=parseFloat(e);return isNaN(n)?e:n;}),
    eFun=[
  evalExpr(split(".5 1 440 t * 2 % - abs -")),
  evalExpr(split("rand .5 - 1 t 1 % - 5 ** *")),
  ...(new Array(5).fill(0).map(()=>evalExpr(genExpr())))
];
return t=>{
  return eFun[floor(t/2)%eFun.length](t);
};

Interesting to think about in theory, but boring when it's put into practice.