Δευτέρα 6 Φεβρουαρίου 2023

NewtonRaphson Find TimeOfCollision for 2Balls with Deceleration

 Download and run(with java) the .jar

https://drive.google.com/file/d/1gQGtCntPb3NsV14_5K9qgR3ewU--5DzK/view?usp=sharing










NewtonRaphson method for solution x^4









or compile and run....

/*

 * To change this license header, choose License Headers in Project Properties.

 * To change this template file, choose Tools | Templates

 * and open the template in the editor.

 */

package time2ballscollisionwithdeceleration;


import java.awt.BasicStroke;

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.Point;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import java.awt.event.MouseMotionListener;

import java.awt.event.MouseWheelEvent;

import java.awt.event.MouseWheelListener;

import javax.swing.JButton;

import javax.swing.JCheckBox;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JSpinner;

import javax.swing.SpinnerNumberModel;



/**

 *

 * @author dimitrak

 */

public class Time2BallsCollisionWithDeceleration extends JFrame implements MouseListener,MouseMotionListener,MouseWheelListener{

    public static void main(String[] args) {

        new Time2BallsCollisionWithDeceleration();

        Balla a=new Balla();

        System.out.println("epibradynsi: "+a.a);

        a.resetAtSpeed(8);

        System.out.println("speed Arxiko "+a.sp);

        System.out.println("distToStop "+a.Ddist(a.timeToStop));

        System.out.println("timeNow : "+a.timeNow);

        System.out.println("Now speed : "+a.spn);

    }

    

    

    Balla a=new Balla();

    Balla b=new Balla();


    Thread thrSim=new Thread(){

        public void run(){

            while(true){

                runSimStep();

            }

        }

    };

    

    

    JLabel jlDt=new JLabel("DT-sim millis");

    JSpinner jspDt=new JSpinner(new SpinnerNumberModel(100,10,1000,10));

    JPanel jpDt=new JPanel(new BorderLayout());

    

    JCheckBox jchPlayReturn=new JCheckBox("return trip",true);

    

    JPanel jpn=new JPanel(new FlowLayout());

    

    

    public Time2BallsCollisionWithDeceleration(){

        super("Find TIME of Collision between 2 balls with (radius,speed,angle , AND DECELARATION from friction)");

    

        a.col=Color.blue;

        b.col=Color.magenta;

        

        

        jpDt.add(BorderLayout.WEST,jlDt);

        jpDt.add(BorderLayout.CENTER,jspDt);

        

        

        jpn.add(jchPlayReturn);

        jpn.add(jbPlay);

        jpn.add(jbTimeZero);

        jpn.add(jpDt);

        

        getContentPane().add(BorderLayout.CENTER,jp);

        getContentPane().add(BorderLayout.NORTH,jpn);

        

        

        setBounds(0,0,777,666);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setVisible(true);

        

        jp.addMouseListener(this);

        jp.addMouseMotionListener(this);

        jp.addMouseWheelListener(this);

        

        thrSim.start();

        

        

        jbPlay.addActionListener(e->jbPlay());

        jbTimeZero.addActionListener(e->jbTimeZero());

        

        a.resetAtPos(350,140);

        a.resetAtAngle(Math.toRadians(45));

        a.resetAtSpeed(35);

    

        b.resetAtPos(a.r,400);

        b.resetAtAngle(-Math.toRadians(30));

        b.resetAtSpeed(46);

    

        recomputeCollisionTime();

    }

    

    Graphics2D g=null;

    JPanel jp=new JPanel(){

        public void paintComponent(Graphics gr){

            super.paintComponent(gr);

            g=(Graphics2D)gr;

            paintingBalls();

        }

    };

    Font font=new Font("Dialog",0,16);

    void paintingBalls(){

        

        

        

        

        g.setColor(Color.black);

        g.setFont(font);

        int x=10;

        int y=font.getSize();

        g.drawString("Press IN some ball and dragg mouse to change ball location", x,y);

        y+=font.getSize();

        g.drawString("Mouse Roll a)to change ball Speed ,b)+SHIFT to change ball Angle, c)+SHIFT+CNTRL to change ball DE-CELARATION(friction*g)", x,y);

        y+=font.getSize();

        g.drawString(" "+ex+a.timeCollision, x,y);

        y+=font.getSize();

        g.drawString("Solution/Collision Time : "+a.timeCollision, x,y);

        

        if(a.timeCollision>a.timeToStop && a.timeCollision>b.timeToStop){

            g.setColor(Color.red);

            y+=font.getSize();

            g.drawString("Solution/Collision is on RETURN TRIP...not valid on billiards", x,y);

            

        }

        

        y+=font.getSize();g.setColor(Color.black);

        g.drawString("simTime:"+simTimeSecNow, x,y);

        

        y+=font.getSize();g.setColor(a.col);

        g.drawString("a timeToStop: "+a.timeToStop, x,y);

        y+=font.getSize();g.setColor(b.col);

        g.drawString("b timeToStop: "+b.timeToStop, x,y);

        y+=font.getSize();g.setColor(a.col);

        g.drawString("a dist till collision: "+a.distcol, x,y);

        y+=font.getSize();g.setColor(b.col);

        g.drawString("b dist till collision: "+b.distcol, x,y);

        y+=font.getSize();g.setColor(a.col);

        g.drawString("a acc: "+-a.a, x,y);

        y+=font.getSize();g.setColor(b.col);

        g.drawString("b acc: "+-b.a, x,y);

        

        a.paint(g);

        b.paint(g);

    }

    

    

    

    

    


    @Override

    public void mouseClicked(MouseEvent e) {

    }


    boolean pressedLeft,pressedRight;

    Balla ballNowPressed=a;

    @Override

    public void mousePressed(MouseEvent e) {

        pressedLeft=e.getButton()==MouseEvent.BUTTON1;

        pressedRight=e.getButton()==MouseEvent.BUTTON3;

        ballNowPressed=null;

        double dist1=a.dist(e.getX(),e.getY());

        double dist2=b.dist(e.getX(),e.getY());

        System.out.println(""+dist1+" , "+dist2);

        if(dist1<=a.r && dist1<=dist2){

            ballNowPressed=a;

        }

        if(dist2<=b.r && dist2<=dist1){

            ballNowPressed=b;

        }

        

    

    }


    @Override

    public void mouseReleased(MouseEvent e) {

    }


    @Override

    public void mouseEntered(MouseEvent e) {

    }


    @Override

    public void mouseExited(MouseEvent e) {

    }


    @Override

    public void mouseDragged(MouseEvent e) {

        if(ballNowPressed!=null){

            ballNowPressed.resetAtPos(e.getX(),e.getY());

            recomputeCollisionTime();

        }

    }


    @Override

    public void mouseMoved(MouseEvent e) {

    }


    @Override

    public void mouseWheelMoved(MouseWheelEvent e) {

        

        if(ballNowPressed!=null){

            double mul=1;

            if(e.isAltDown()){

                mul*=10;

            }

            if(!e.isShiftDown()){

                ballNowPressed.resetAtSpeedDif(-mul*e.getWheelRotation());

            }

            else{

                if(!e.isControlDown()){

                    ballNowPressed.resetAtAngleDif(Math.toRadians(-5*e.getWheelRotation()));

                }

                else{

                    ballNowPressed.resetAtAccDif(-mul*0.1*e.getWheelRotation());

                }

            }

            recomputeCollisionTime();

        }

    }

    

    Pol ex=new Pol(4);

    

    public double solNewtonRaphson(double Ax,double Ay,double Asp,double Aacc,double Aang,double Aradius,

                           double Bx,double By,double Bsp,double Bacc,double Bang,double Bradius){

        double dx=Bx-Ax;

        double dy=By-Ay;

        double R=Aradius+Bradius;//dy^2 + dx^2 =R^2

        double d=Aacc/2;

        double c=Bacc/2;

        double h=Asp;

        double e=Bsp;

        double m=Math.cos(Aang);

        double k=Math.cos(Bang);

        double f=Math.sin(Aang);

        double l=Math.sin(Bang);

        double ckdm=c*k-d*m;//coses

        double ekhm=e*k-h*m;//coses

        double cldf=c*l-d*f;//sins

        double elhf=e*l-h*f;//sins

        ex.p[0]=dx*dx + dy*dy - R*R;

        ex.p[1]=2*dx*ekhm + 2*dy*elhf;

        ex.p[2]=ekhm*ekhm + 2*dx*ckdm + elhf*elhf + 2*dy*cldf;

        ex.p[3]=2*ekhm*ckdm + 2*elhf*cldf;

        ex.p[4]=ckdm*ckdm + cldf*cldf;

        

        ex.showAllDerivatives();

        System.out.println("Possible: "+ex.findSomeQuickNewtonRoot());

        return ex.NewtonRaphson(ex.findSomeQuickNewtonRoot(), 100, 0.0000001);

    }

    void recomputeCollisionTime(){

        maxTimeSec=Math.max(a.timeToStop, b.timeToStop);

        if(jchPlayReturn.isSelected()){

            maxTimeSec*=2;

        }

        double t=solNewtonRaphson(

                a.xf,a.yf,a.sp,-a.a,a.an,a.r

                ,b.xf,b.yf,b.sp,-b.a,b.an,b.r

        );

        System.out.println("Collision AT Time: "+t);

        a.resetAtTimeCollision(t);

        b.resetAtTimeCollision(t);


        jp.repaint();

    }

    /**

     * Searching t (collision time)

     * AendX=AstartX+(t*Aspeed)cos(Aangle)

     * AendY=AstartY+(t*Aspeed)sin(Aangle)

     * BendX=BstartX+(t*Bspeed)cos(Bangle)

     * BendY=BstartY+(t*Bspeed)sin(Bangle)

     * 

     * (BendY-AendY)^2 +(BendX-AendX)^2 = (ARadius+BRadius)^2

     *//*

    void recomputeCollisionTime0(){

    

        //System.out.println("recomputing collision time");

        double tLess=-1;

        double aco=a.sp*Math.cos(a.an);

        double asi=a.sp*Math.sin(a.an);

        double bco=b.sp*Math.cos(b.an);

        double bsi=b.sp*Math.sin(b.an);

        double dsi=bsi-asi;

        double dco=bco-aco;

        double dy=b.yf-a.yf;

        double dx=b.xf-a.xf;

        

        double A=dsi*dsi+dco*dco;

        double B=2*((dsi)*(dy)+(dco)*(dx));

        double C=dy*dy+dx*dx-Math.pow(a.r+b.r,2);

        double D=B*B-4*A*C;//System.out.println("D = "+D);

        if(D<0){System.out.println("No solutions");}

        else{

            double t1=(-B-Math.sqrt(D))/(2*A);

            double t2=(-B+Math.sqrt(D))/(2*A);//System.out.println("t1 : "+t1+"   ,   t2: "+t2);

            tLess=t1;

            if(t2<t1){tLess=t2;}

        }

        //a.resetAtTimeCollision(tLess*1000);

        //b.resetAtTimeCollision(tLess*1000);

        

        

        jp.repaint();

    }*/

    

    JButton jbPlay=new JButton("Play");

    JButton jbTimeZero=new JButton("TimeZero");

    

    boolean simPaused=true;

    long pauseMillis=60000;

    long stepMillis=(int)jspDt.getValue();

    double stepSec=((double)stepMillis)/1000d;

    double simTimeMillisNow=0;

    double simTimeSecNow=0;

    double maxTimeSec=10;

    void runSimStep(){

        long sl=pauseMillis;

        if(!simPaused){

            boolean simend=false;

            sl=stepMillis;

            if(jchPlayReturn.isSelected()){

                a.resetAtTimeNow(simTimeSecNow);

                b.resetAtTimeNow(simTimeSecNow);

            }

            else{

                if(a.timeToStop>=simTimeSecNow){

                    a.resetAtTimeNow(simTimeSecNow);

                }

                if(b.timeToStop>=simTimeSecNow){

                    b.resetAtTimeNow(simTimeSecNow);

                }

            }

            

            jp.repaint();

            

            simTimeMillisNow+=stepMillis;

            simTimeSecNow+=stepSec;

            

            if(simTimeSecNow>maxTimeSec){

                simend=true;

                simPause();

                jbTimeZero();

            }

        }

        try{thrSim.sleep(sl);}catch(InterruptedException inter){}

    }

    void jbPlay(){

        if(simPaused){

            simUnPause();

        }

        else{

            simPause();

        }

    }

    void simPause(){

        jbPlay.setText("Play");

        simPaused=true;

        

    }

    

    void simUnPause(){

        jbPlay.setText("Simulating");

        simPaused=false;

        thrSim.interrupt();

    }

    void jbTimeZero(){

        simTimeMillisNow=0;

        simTimeSecNow=0;

    }

    

    

    

    

}


class Balla{

    double coefFriction=0.2;

    double mass=0.2;

    double g=10;

    double a=coefFriction*g;

    

    

    Color col=Color.BLUE;

    double r=50;

    double d=2*r;

    double xf=2*r+Math.random()*300,yf=2*r+Math.random()*300;

    double an=Math.toRadians(Math.random()*360);

    double sp=10+Math.random()*10;

    double xl,yl;


    double timeToStop=sp/a;

    double xe,ye;

    

    double timeNow=timeToStop/2;

    double spn=sp-a*timeNow;

    double xn,yn;

    

    double timeCollision=-1;

    double spcol=sp-a*timeCollision;

    double distcol=(Ddist(timeCollision));

    double xc,yc;

    

    public Balla(){

        resetAtPos();

    }

    void resetAtPos(){

        resetAtPos(xf, yf);

    }

    void resetAtPosold(double x,double y){

        xf=x;

        yf=y;

        xl=xf+r*Math.cos(an);

        yl=yf+r*Math.sin(an);

        //1000 millis sp

        //timeEnd  x?

        double distMaxTime=(sp*timeToStop)/1000;

        xe=xf+distMaxTime*Math.cos(an);

        ye=yf+distMaxTime*Math.sin(an);

        

        double distNowTime=(sp*timeNow)/1000;

        xn=xf+distNowTime*Math.cos(an);

        yn=yf+distNowTime*Math.sin(an);

        

        if(timeCollision>0){

            xc=xf+distcol*Math.cos(an);

            yc=yf+distcol*Math.sin(an);

            

        }

    }

    

    public double Ddist(double t){

        double out=sp*t-((a*t*t)/2);

        return out;

    }

    void resetAtPos(double x,double y){

        xf=x;

        yf=y;

        xl=xf+r*Math.cos(an);

        yl=yf+r*Math.sin(an);

        //1000 millis sp

        //timeEnd  x?

        double distMaxTime=(Ddist(timeToStop));

        //System.out.println("distMaxTime: " +distMaxTime+" for timeToStop="+timeToStop);

        xe=xf+distMaxTime*Math.cos(an);

        ye=yf+distMaxTime*Math.sin(an);

        

        double distNowTime=(Ddist(timeNow));

        xn=xf+distNowTime*Math.cos(an);

        yn=yf+distNowTime*Math.sin(an);

        

        if(timeCollision>0){

            double distAtCollision=(Ddist(timeCollision));

            xc=xf+distAtCollision*Math.cos(an);

            yc=yf+distAtCollision*Math.sin(an);

            

        }

    }

    void resetAtAngle(double newAngle){

        an=newAngle;

        resetAtPos();

    }

    void resetAtAngleDif(double difAngle){

        resetAtAngle(difAngle+an);

    }

    void resetAtSpeed(double newSpeed){

        sp=newSpeed;

        timeToStop=sp/a;

        spn=sp-a*timeNow;

        System.out.println(sp+" m/ss -> TimeToStop = "+timeToStop);

        resetAtPos();

    }

    void resetAtSpeedDif(double difSpeed){

        resetAtSpeed(difSpeed+sp);

    }

    void resetAtTimeNow(double newNowTime){

        timeNow=newNowTime;

        spn=sp-a*timeNow;

        resetAtPos();

    }

    void resetAtTimeCollision(double newCollisionTime){

        timeCollision=newCollisionTime;

        spcol=sp-a*timeCollision;

        distcol=(sp*timeCollision)/1000;

        resetAtPos();

    }

    void resetAtAcc(double accNew){

        accNew=Math.abs(accNew);

        a=accNew;

        timeToStop=sp/a;

        spn=sp-a*timeNow;

        resetAtPos();

    }

    void resetAtAccDif(double accDif){

        resetAtAcc(a+accDif);

        System.out.println(""+a);

    }

    

    public double dist(double x,double y){

        return Point.distance(xf, yf, x, y);

    }


    static BasicStroke strokeNormal=new BasicStroke(1);

    static BasicStroke strokeMoving=new BasicStroke(1,0,0,10,new float[]{10,10},0);

    public void paint(Graphics2D g){

        g.setStroke(strokeNormal);

        g.setColor(col);

        g.drawOval((int)(xf-r),(int)(yf-r), (int)(d),(int)( d));

        g.drawLine((int)(xf),(int)(yf),(int)(xl),(int)(yl));

        g.drawOval((int)(xe-r),(int)(ye-r), (int)(d),(int)( d));

        g.drawLine((int)(xf),(int)(yf),(int)(xe),(int)(ye));

        

        g.drawString("V0="+(nice(sp))+" m/s", (int)(xf),(int)(yf));

        

        

        g.setStroke(strokeMoving);

        g.drawOval((int)(xn-r),(int)(yn-r), (int)(d),(int)( d));

        g.drawString("V="+(nice(spn))+" m/s", (int)(xn),(int)(yn));

        

        if(timeCollision>0){

            g.setColor(Color.RED);

            g.setStroke(strokeNormal);

            int ucx=(int)(xc-r);

            int ucy=(int)(yc-r);

            g.drawOval(ucx,ucy, (int)(d),(int)( d));

            //g.drawLine(ucx,ucy,(int)(ucx+d),(int)(ucy+d));

        }

    }

    

    static double nice(double d){

        d*=1000;

        d=(long)d;

        d/=1000;

        return d;

    }

}

class JNewtonRaphson {

    public static void main(String[] args) {


    }

    static void test(){

        Pol p=new Pol(3,-7,1,2,-19);

        System.out.println(""+p);

        System.out.println(""+p.strf(-1));

        System.out.println(""+p.strf(0));

        System.out.println(""+p.strf(1));

        System.out.println(""+p.hasSolutionAt(-100, 100, 1));

        System.out.println(""+p.findSomeQuickNewtonRoot());

        p.showAllDerivatives();

        System.out.println("--------------");

        p.NewtonRaphson(0, 100, 0.0000001);

        

        

    }

    

    

}


class Pol{

    double[]p;

    

    public Pol(int maxPower){

        p=new double[maxPower+1];

    }

    public Pol(double []ps){

        this(ps,false);

    }

    public Pol(double []ps,boolean assign){

        if(assign){

            p=ps;

        }

        else{

            p=new double[ps.length];

            System.arraycopy(ps, 0, p, 0, ps.length);

        }

    }

    

    public Pol(double p2,double p1,double c){

        this(2);

        p[0]=c;

        p[1]=p1;

        p[2]=p2;

    }

    public Pol(double p3,double p2,double p1,double c){

        this(3);

        p[0]=c;

        p[1]=p1;

        p[2]=p2;

        p[3]=p3;

    }

    public Pol(double p4,double p3,double p2,double p1,double c){

        this(4);

        p[0]=c;

        p[1]=p1;

        p[2]=p2;

        p[3]=p3;

        p[4]=p4;

    }

    

    public double NewtonRaphson(double xPossible,int maxsteps,double epsilon){

        

        Pol ft=getfDerivative();

        double x=xPossible;

        double h = fHorner(x) / ft.fHorner(x);

        int i=0;

        while (i<maxsteps && Math.abs(h) >= epsilon){

            x -=h;

            h = fHorner(x) / ft.fHorner(x);

            //System.out.println(i+" : "+x);

            ++i;

        }

        //System.out.println("sol: "+x);

        System.out.println(""+strf(x));

        return x;

    }


    public void showAllDerivatives(){

        Pol a=this;

        int ton=0;

        while(a.p.length>1){

            System.out.println("f["+(ton)+"](x)="+a);

            a=a.getfDerivative();

            ++ton;

        }

        System.out.println("f["+(ton)+"](x)="+a);

    }

    public Pol getfDerivative(){

        int l=p.length;

        if(p.length<2){

            return new Pol(0);//y=0;

        }

        l-=1;

        double ps[]=new double[l];

        int pos=l-1;

        while(l>0){

            ps[pos]=p[l]*l;

            --pos;

            --l;

        }

        return new Pol(ps,true);

    }

    public double findSomeQuickNewtonRoot(){

        double out=hasSolutionAt(-10, 10,0.1);//200 max

        if(Double.isNaN(out)){

            out=hasSolutionAt(-100, 100,1);//200 max

            if(Double.isNaN(out)){

                out=hasSolutionAt(-1000, 1000,10);//200 max

                if(Double.isNaN(out)){

                    out=hasSolutionAt(-10000, 10000,100);//200 max

                }

            }

        }

        return out;

    }

    public double hasSolutionAt(double x1,double x2,double xstep){

        if(x2<x1){

            double temp=x2;

            x2=x1;

            x1=temp;

        }

        else if(x1<x2){

            

        }

        else{

            

        }

        if(xstep<0){

            xstep=-xstep;

        }

        else if(xstep>0){}

        else{

            xstep=x2-x1;

            xstep/=100;

        }

        

        double x=x1;

        double y=fHorner(x);

        boolean startNeg=false;

        if(y<0){

            startNeg=true;

        }

        else if(y>0){

            

        }

        else{

            return x;

        }

        x+=xstep;

        x2+=xstep;

        while(x<x2){

            y=fHorner(x);

            if(y<0){

                if(!startNeg){

                    return x-xstep/2;

                }

            }

            else if(y>0){

                if(startNeg){

                    return x-xstep/2;

                }

            }

            else{

                return x;

            }

            x+=xstep;

        }

        

        

        return Double.NaN;

    }

    

    public double fHorner(double x){

        int i=p.length-1;

        double out=p[i];

        --i;

        while(i>=0){

            out*=x;

            out+=p[i];

            --i;

        }

        return out;

    }

    

    public double fOld(double x){

        int i=0;

        double v=p[i];

        double out=v;

        double xs=1;

        ++i;

        while(i<p.length){

            xs*=x;

            out+=xs*p[i];

            ++i;

        }

        return out;

    }

    public double f(double x){

        return fHorner(x);

    }

    public String strf(double x){

        return "f("+x+") = "+f(x);

    }


    

    public String toString(){

        String out="";

        int i=p.length-1;

        double v;

        while(i>0){

            v=p[i];

            if(v>0){

                out+="+"+v+"(x^"+i+") ";

            }

            else if(v<0){

                out+=""+v+"(x^"+i+") ";

            }

            --i;

        }

        v=p[i];

        if(v>0){

            out+="+"+v;

        }

        else if(v<0){

            out+=""+v;

        }

        else{

            if(p.length==1){

                out+="+0";

            }

        }

        

        return out;

    }

}


Κυριακή 5 Φεβρουαρίου 2023

Collision Time For Two Balls

download and run this

https://drive.google.com/file/d/1_IPdpTKzLNTJYxBxxbtJyAkH3dnFwSZD/view?usp=sharing


//or....stand alone / ready to compile and run simple code










/*

 * To change this license header, choose License Headers in Project Properties.

 * To change this template file, choose Tools | Templates

 * and open the template in the editor.

 */

package j2ballscollisionfounder;


import java.awt.BasicStroke;

import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.FlowLayout;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.Point;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import java.awt.event.MouseMotionListener;

import java.awt.event.MouseWheelEvent;

import java.awt.event.MouseWheelListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JPanel;

import javax.swing.JSpinner;

import javax.swing.SpinnerNumberModel;


/**

 *

 * @author dimitrak

 */

public class J2BallsCollisionFounder extends JFrame implements MouseListener,MouseMotionListener,MouseWheelListener{

    public static void main(String[] args) {

        new J2BallsCollisionFounder();

    }

    

    

    Balla a=new Balla();

    Balla b=new Balla();


    Thread thrSim=new Thread(){

        public void run(){

            while(true){

                runSimStep();

            }

        }

    };

    

    

    JLabel jlDt=new JLabel("DT-sim millis");

    JSpinner jspDt=new JSpinner(new SpinnerNumberModel(100,10,1000,10));

    JPanel jpDt=new JPanel(new BorderLayout());

    

    JPanel jpn=new JPanel(new FlowLayout());

    

    

    public J2BallsCollisionFounder(){

        super("Found TIME of Collision between 2 balls with (radius,speed,angle)");

    

        b.col=Color.black;

        

        

        jpDt.add(BorderLayout.WEST,jlDt);

        jpDt.add(BorderLayout.CENTER,jspDt);

        

        

        jpn.add(jbPlay);

        jpn.add(jbTimeZero);

        jpn.add(jpDt);

        

        getContentPane().add(BorderLayout.CENTER,jp);

        getContentPane().add(BorderLayout.NORTH,jpn);

        

        

        setBounds(0,0,777,666);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setVisible(true);

        

        jp.addMouseListener(this);

        jp.addMouseMotionListener(this);

        jp.addMouseWheelListener(this);

        

        thrSim.start();

        

        

        jbPlay.addActionListener(e->jbPlay());

        jbTimeZero.addActionListener(e->jbTimeZero());

        

        a.resetAtPos(300,100);

        a.resetAtAngle(Math.PI/2);

        a.resetAtSpeed(60);

    

        b.resetAtPos(100,300);

        b.resetAtAngle(-Math.PI/8);

        b.resetAtSpeed(60);

    

        recomputeCollisionTime();

    }

    

    Graphics2D g=null;

    JPanel jp=new JPanel(){

        public void paintComponent(Graphics gr){

            super.paintComponent(gr);

            g=(Graphics2D)gr;

            paintingBalls();

        }

    };

    Font font=new Font("Dialog",0,16);

    void paintingBalls(){

        

        

        

        

        g.setColor(Color.black);

        g.setFont(font);

        int x=10;

        int y=font.getSize();

        g.drawString("Press IN some ball and dragg mouse to change ball location", x,y);

        y+=font.getSize();

        g.drawString("Mouse Roll to change ball Speed", x,y);

        y+=font.getSize();

        g.drawString("Mouse Roll +SHIFT to change ball Angle", x,y);

        

        a.paint(g);

        b.paint(g);

    }

    

    

    

    

    


    @Override

    public void mouseClicked(MouseEvent e) {

    }


    boolean pressedLeft,pressedRight;

    Balla ballNowPressed=a;

    @Override

    public void mousePressed(MouseEvent e) {

        pressedLeft=e.getButton()==MouseEvent.BUTTON1;

        pressedRight=e.getButton()==MouseEvent.BUTTON3;

        ballNowPressed=null;

        double dist1=a.dist(e.getX(),e.getY());

        double dist2=b.dist(e.getX(),e.getY());

        System.out.println(""+dist1+" , "+dist2);

        if(dist1<=a.r && dist1<=dist2){

            ballNowPressed=a;

        }

        if(dist2<=b.r && dist2<=dist1){

            ballNowPressed=b;

        }

        

    

    }


    @Override

    public void mouseReleased(MouseEvent e) {

    }


    @Override

    public void mouseEntered(MouseEvent e) {

    }


    @Override

    public void mouseExited(MouseEvent e) {

    }


    @Override

    public void mouseDragged(MouseEvent e) {

        if(ballNowPressed!=null){

            ballNowPressed.resetAtPos(e.getX(),e.getY());

            recomputeCollisionTime();

        }

    }


    @Override

    public void mouseMoved(MouseEvent e) {

    }


    @Override

    public void mouseWheelMoved(MouseWheelEvent e) {

        

        if(ballNowPressed!=null){

            if(!e.isShiftDown()){

                ballNowPressed.resetAtSpeedDif(-5*e.getWheelRotation());

            }

            else{

                ballNowPressed.resetAtAngleDif(Math.toRadians(-5*e.getWheelRotation()));

            }

            recomputeCollisionTime();

        }

    }

    

    /**

     * Searching t (collision time)

     * AendX=AstartX+(t*Aspeed)cos(Aangle)

     * AendY=AstartY+(t*Aspeed)sin(Aangle)

     * BendX=BstartX+(t*Bspeed)cos(Bangle)

     * BendY=BstartY+(t*Bspeed)sin(Bangle)

     * 

     * (BendY-AendY)^2 +(BendX-AendX)^2 = (ARadius+BRadius)^2

     */

    void recomputeCollisionTime(){

        //System.out.println("recomputing collision time");

        double tLess=-1;

        double aco=a.sp*Math.cos(a.an);

        double asi=a.sp*Math.sin(a.an);

        double bco=b.sp*Math.cos(b.an);

        double bsi=b.sp*Math.sin(b.an);

        double dsi=bsi-asi;

        double dco=bco-aco;

        double dy=b.yf-a.yf;

        double dx=b.xf-a.xf;

        

        double A=dsi*dsi+dco*dco;

        double B=2*((dsi)*(dy)+(dco)*(dx));

        double C=dy*dy+dx*dx-Math.pow(a.r+b.r,2);

        double D=B*B-4*A*C;//System.out.println("D = "+D);

        if(D<0){System.out.println("No solutions");}

        else{

            double t1=(-B-Math.sqrt(D))/(2*A);

            double t2=(-B+Math.sqrt(D))/(2*A);//System.out.println("t1 : "+t1+"   ,   t2: "+t2);

            tLess=t1;

            if(t2<t1){tLess=t2;}

        }

        a.resetAtTimeCollision(tLess*1000);

        b.resetAtTimeCollision(tLess*1000);

        

        

        jp.repaint();

    }

    

    JButton jbPlay=new JButton("Play");

    JButton jbTimeZero=new JButton("TimeZero");

    

    boolean simPaused=true;

    long stepMillis=100;

    long pauseMillis=60000;

    double simTime=0;

    double simDtime(){return (int)jspDt.getValue();}

    double simMaxtime=5000;

    void runSimStep(){

        long sl=pauseMillis;

        if(!simPaused){

            boolean simend=false;

            sl=stepMillis;

            simTime+=simDtime();

            if(simTime>simMaxtime){

                simTime=simMaxtime;

                simend=true;

            }

            a.resetAtTimeNow(simTime);

            b.resetAtTimeNow(simTime);

            jp.repaint();

            

            if(simend){

                simPause();

                simTime=0;

            }

        }

        try{thrSim.sleep(sl);}catch(InterruptedException inter){}

    }

    void jbPlay(){

        if(simPaused){

            simUnPause();

        }

        else{

            simPause();

        }

    }

    void simPause(){

        jbPlay.setText("Play");

        simPaused=true;

        

    }

    

    void simUnPause(){

        jbPlay.setText("Simulating");

        simPaused=false;

        thrSim.interrupt();

    }

    void jbTimeZero(){

        simTime=0;

    }

    

    

    

    

}


class Balla{

    Color col=Color.BLUE;

    double r=50;

    double d=2*r;

    double xf=2*r+Math.random()*300,yf=2*r+Math.random()*300;

    double an=Math.toRadians(Math.random()*360);

    double sp=10+Math.random()*100;

    double xl,yl;

    

    double timeEnd=5000;

    double xe,ye;

    

    double timeNow=timeEnd/2;

    double xn,yn;

    

    double timeCollision=-1;

    double xc,yc;

    

    public Balla(){

        resetAtPos();

    }

    void resetAtPos(){

        resetAtPos(xf, yf);

    }

    void resetAtPos(double x,double y){

        xf=x;

        yf=y;

        xl=xf+r*Math.cos(an);

        yl=yf+r*Math.sin(an);

        //1000 millis sp

        //timeEnd  x?

        double distMaxTime=(sp*timeEnd)/1000;

        xe=xf+distMaxTime*Math.cos(an);

        ye=yf+distMaxTime*Math.sin(an);

        

        double distNowTime=(sp*timeNow)/1000;

        xn=xf+distNowTime*Math.cos(an);

        yn=yf+distNowTime*Math.sin(an);

        

        if(timeCollision>0){

            double distAtCollision=(sp*timeCollision)/1000;

            xc=xf+distAtCollision*Math.cos(an);

            yc=yf+distAtCollision*Math.sin(an);

            

        }

    }

    void resetAtAngle(double newAngle){

        an=newAngle;

        resetAtPos();

    }

    void resetAtAngleDif(double difAngle){

        resetAtAngle(difAngle+an);

    }

    void resetAtSpeed(double newSpeed){

        sp=newSpeed;

        resetAtPos();

    }

    void resetAtSpeedDif(double difSpeed){

        resetAtSpeed(difSpeed+sp);

    }

    void resetAtTimeNow(double newNowTime){

        timeNow=newNowTime;

        resetAtPos();

    }

    void resetAtTimeCollision(double newCollisionTime){

        timeCollision=newCollisionTime;

        resetAtPos();

    }

    

    public double dist(double x,double y){

        return Point.distance(xf, yf, x, y);

    }


    static BasicStroke strokeNormal=new BasicStroke(1);

    static BasicStroke strokeMoving=new BasicStroke(1,0,0,10,new float[]{10,10},0);

    public void paint(Graphics2D g){

        g.setStroke(strokeNormal);

        g.setColor(col);

        g.drawOval((int)(xf-r),(int)(yf-r), (int)(d),(int)( d));

        g.drawLine((int)(xf),(int)(yf),(int)(xl),(int)(yl));

        g.drawOval((int)(xe-r),(int)(ye-r), (int)(d),(int)( d));

        

        double spn=sp*1000;

        spn=(long)spn;

        spn/=1000;

        g.drawString("V="+(spn)+" px/s", (int)(xf),(int)(yf));

        

        

        g.setStroke(strokeMoving);

        g.drawOval((int)(xn-r),(int)(yn-r), (int)(d),(int)( d));

        

        if(timeCollision>0){

            g.setColor(Color.RED);

            g.setStroke(strokeNormal);

            int ucx=(int)(xc-r);

            int ucy=(int)(yc-r);

            g.drawOval(ucx,ucy, (int)(d),(int)( d));

            //g.drawLine(ucx,ucy,(int)(ucx+d),(int)(ucy+d));

        }

    }

}

Κυριακή 15 Ιανουαρίου 2023

Why Horner is BEST for computing Polyonym(some) in big powers

 So ..from below image we see that

cost less CPU to compute with Horner than old fashion!!!

Especially if we have a Polyonim like

F(x)=x^10-2x^9+5x^8...etc...

So..with Horner we need N multiplications and N adds.

Old fashion we need N+ N-1 +N-2+....1 =N+N*(N/2) mulyiplications!!!

Nice!!!! I just hadnt realise it!!!

William George Horner



Σάββατο 12 Νοεμβρίου 2022

English Vocabulary Enrichment from Jwiki_0

 ...













https://en.wikipedia.org/wiki/Web_scraping

https://en.wikipedia.org/wiki/Document_Object_Model

/**

 *

 * @author jimak

 * @date Nov 13, 2022

 */

public class Dom extends Node{

    public static void main(String[] args) {

        JHTMLParserBuilder.main(args);

    }


    public Dom() {

        super();

        getBuffer().append("DOM");

    }

    

    

    public void parse(StringBuffer inputBuf){

        int inputLen=inputBuf.length();

        int inputI=0;

        char ch;

        Node workingNode=this;

        StringBuffer workingBuf=workingNode.getBuffer();

        while(inputI<inputLen){

            ch=inputBuf.charAt(inputI);

            if(ch!='<'){

                workingBuf.append(ch);

            }

            else{

                StringBuffer holeTag=new StringBuffer(" ");

                holeTag.append(ch);

                ++inputI;

                boolean closedok=false;

                String tagName="";

                boolean spaceNotFound=true;

                while(inputI<inputLen){

                    ch=inputBuf.charAt(inputI);

                    ++inputI;

                    holeTag.append(ch);

                    if(ch=='>'){

                        closedok=true;

                        break;

                    }

                    else if(spaceNotFound){

                        if(ch==' '){spaceNotFound=false;}

                        else{tagName+=ch;}

                    }

                }

                //System.out.println(inputI+" , "+tagName+" : "+holeTag);

                if(closedok){

                    boolean isClosingTag=tagName.charAt(0)=='/';

                    //System.out.println("Closing:"+isClosingTag);

                    if(isClosingTag){

                        String realTag=tagName.substring(1);

                        Node firstOpenedParent=workingNode.getFirstParentTag(realTag);

                        if(firstOpenedParent!=null){

                            Node neoNode=new Node();

                            workingNode=(Node)firstOpenedParent.getParent();

                            workingNode.add(neoNode);

                            workingNode=neoNode;

                            workingBuf=workingNode.getBuffer();

                        }

                        else{

                            System.out.println(inputI+" , "+tagName+" : "+holeTag);

                            System.out.println("Didnt find any opening Tag for this ...continueing");

                        }

                    }

                    else{

                        Tag neoTag=new Tag(holeTag,tagName);

                        workingNode.add(neoTag);

                        workingNode=neoTag;

                        workingBuf=workingNode.getBuffer();

                        

                        Node neoNode=new Node();

                        workingNode.add(neoNode);

                        workingNode=neoNode;

                        workingBuf=workingNode.getBuffer();

                    }

                }

                else{

                    workingBuf.append(holeTag);

                }

                

                --inputI;

                

            }

            ++inputI;

            

        }

        

        System.out.println("end main parsing.Now must remove empty nodes");

        

        Vector<Node> toBeRemoved=new Vect<Node>();

        Enumeration en=preorderEnumeration();

        en.nextElement();

        while(en.hasMoreElements()){

            Node n=(Node)en.nextElement();

            StringBuffer nb=n.getBuffer();

            String s=nb.toString().trim();

            //System.out.println(s.length()+">"+s);

            int nbls=s.length();

            if(nbls>0){


            }

            else{

                toBeRemoved.add(n);

            }

        }

        int i=0,l=toBeRemoved.size();

        System.out.println("must remove "+toBeRemoved.size());

        while(i<l){

            Node n=toBeRemoved.get(i);

            //n.getBuffer().append("To Be Removed");

            Node np=(Node)n.getParent();

            int nIndex=np.getIndex(n);

            np.remove(nIndex);

            int chs=n.getChildCount();

            --chs;

            while(chs>-1){

                Node nch=(Node)n.getChildAt(chs);

                np.insert(nch, nIndex);

                --chs;

            }

            ++i;

        }

    }

    


}


Πέμπτη 10 Νοεμβρίου 2022

a vocabulary text day trick ?

     static String days[]={"SUNDAY","MONDAY","TUESDAY","WEDNESDAY","THUSDAY","FRIDAY","SATURDAY"};

    

    static Hashtable<String,Integer>hash=new Hashtable<>();

    static{

        int i=0;

        while(i<days.length){

            hash.put(days[i].substring(0,2),i);

            ++i;

        }

    }

    public static void main(String[] args) {

        

        int i=0;

        int l=10000000;

        int r,o;

        

        long ts=System.currentTimeMillis();

        while(i<l){

            r=Rand.sti.nextInt(7);

            o=getIndexOfDay0(days[r]);

            ++i;

        }

        long te=System.currentTimeMillis();

        te-=ts;

        System.out.println("time:"+te);

    }

    static final int[]trick0={

        4,6,5,0,0

       ,3,0,0,0,0

       ,0,0,0,1,0

       ,0,0,0,0,0

       ,2

    } ;

    

    public static int getIndexOfDay1(String someday){

        String key=Character.toUpperCase(someday.charAt(0))+""+Character.toUpperCase(someday.charAt(1));

        return hash.get(key);

    }

    public static int getIndexOfDay0(String someday){

        char ch0=Character.toUpperCase(someday.charAt(0));

        int ch1=Character.toUpperCase(someday.charAt(1));

        ch1&=ch0;

        ch1-=64;

        return trick0[ch1];

    }


Δευτέρα 7 Νοεμβρίου 2022

Java Simple Snake Game


Jar with src (if jdk installed)

https://drive.google.com/file/d/1yNAFEdnr-p5pDZjh0kctfWyVPR0nkLNX/view?usp=sharing



 









(or compile and run ~ 700 lines)


/*

 * To change this license header, choose License Headers in Project Properties.

 * To change this template file, choose Tools | Templates

 * and open the template in the editor.

 */

package jsnake;


import java.awt.BorderLayout;

import java.awt.Color;

import java.awt.Dimension;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.Graphics2D;

import java.awt.GridLayout;

import java.awt.Toolkit;

import java.awt.event.ComponentEvent;

import java.awt.event.ComponentListener;

import java.awt.event.ItemEvent;

import java.awt.event.KeyEvent;

import java.awt.event.KeyListener;

import java.awt.event.MouseEvent;

import java.awt.event.MouseListener;

import java.util.Random;

import java.util.Vector;

import javax.swing.JButton;

import javax.swing.JCheckBox;

import javax.swing.JComboBox;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JSpinner;

import javax.swing.SpinnerNumberModel;

import javax.swing.event.ChangeEvent;


/**

 *

 * @author jimak

 */

public class JSnake extends JPanel  implements MouseListener,KeyListener,ComponentListener{


    public static String getHelpString(){

        return ""

                + "Simple Java Snake Options"

                + "\nPress"

                + "\nArrows or W-up S-down A-left D-Right to turn snake's head."

                + "\n\nY/U to decrease/increase snake's speed."

                + "\nG/H to decrease/increase Rows and Cols."

                + ""

                + "\n\nT to change paint type"

                + "\nR to change snake's color."

                + "\nL to just ignore that you just lost.(just not show the red line)"

                + ""

                + "\n\nP to Restart by having almost half being filled."

                + "\n\nEnter to Restart ."

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + ""

                + "\n\n\n(you can still play if you loose and have some move to go)";

    }

    static Toolkit tk=Toolkit.getDefaultToolkit();

    static Dimension scr=tk.getScreenSize();

    static Random rand=new Random();

    public static Color randColor(){

        return new Color(rand.nextInt(255),rand.nextInt(255),rand.nextInt(255));

    }

    /**

     * @param args the command line arguments

     */

    public static void main(String[] args) {

        // TODO code application logic here

    

        try{

            JFrame jfr=new JFrame("Simple Java Snake Game");

            jfr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            int insw=scr.width/10;

            int insh=scr.height/10;

            jfr.setBounds(insw,insh,scr.width-2*insw,scr.height-2*insh);

            JSnake jsn=new JSnake();

            jfr.getContentPane().add(jsn);

            jfr.setVisible(true);

            JOptionPane.showMessageDialog(null,getHelpString());

            //throw new IllegalAccessError();

        }catch(Throwable thr){

            try{System.err.println(""+thr);}catch(Throwable thr2){}

            try{JOptionPane.showMessageDialog(null, thr,"will exit app",JOptionPane.ERROR_MESSAGE);}catch(Throwable thr2){}

            try{thr.printStackTrace();}catch(Throwable thr2){}

            System.exit(-1);

        }

        

    }

    

    static int dirs[][]=new int[4][2];

    public static final int dirRight=0;

    public static final int dirDown=1;

    public static final int dirLeft=2;

    public static final int dirUp=3;

    static{

        dirs[dirRight][0]=1;

        dirs[dirRight][1]=0;

        

        dirs[dirDown][0]=0;

        dirs[dirDown][1]=1;

        

        dirs[dirLeft][0]=-1;

        dirs[dirLeft][1]=0;

        

        

        dirs[dirUp][0]=0;

        dirs[dirUp][1]=-1;

    }

    public static int oppositeDir(int some){

        if(some==dirRight){return dirLeft;}

        if(some==dirLeft){return dirRight;}

        if(some==dirDown){return dirUp;}

        return dirDown;

    }

    

    JButton jbFillHalf=new JButton("Restart-Half");

    JButton jbRestart=new JButton("Restart");

    JSpinner jspRowsCols=new JSpinner(new SpinnerNumberModel(12,5,100,1));

    JPanel jpRowsCols=new JPanel(new BorderLayout());

    JSpinner jspMovesPerSecond=new JSpinner(new SpinnerNumberModel(3,1,10,1));

    JPanel jpMovesPerSecond=new JPanel(new BorderLayout());

    JPanel jpOthers=new JPanel(new GridLayout(1,2));

    

    JPanel jpRestartButs=new JPanel(new GridLayout(1,2));

    

    int rows,cols;

    int sqs;

    int headDir=0;

    byte snakex[];

    byte snakey[];

    int snakeLen=0;

    

    Graphics2D g;

    class SnakePainter{

        void paintSnakeSquare(int x,int y){

            g.fillRect(x+1, y+1, sqs-2,sqs-2);

        }

        public String toString(){return "fill Rect";}

    };

    SnakePainter currSnakePainter=new SnakePainter();

    SnakePainter snakePainter[]={

        currSnakePainter

        ,new SnakePainter(){

            void paintSnakeSquare(int x,int y){g.fillOval(x, y, sqs,sqs);}

            public String toString(){return "fill Oval";}

        }

        ,new SnakePainter(){

            void paintSnakeSquare(int x,int y){g.drawRect(x, y, sqs,sqs);}

            public String toString(){return "Quicker";}

        }

        ,new SnakePainter(){

            void paintSnakeSquare(int x,int y){g.drawOval(x, y, sqs,sqs);}

            public String toString(){return "draw Oval";}

        }

        ,new SnakePainter(){

            void paintSnakeSquare(int x,int y){g.drawOval(x, y, sqs,sqs);g.drawRect(x, y, sqs,sqs);}

            public String toString(){return "draws";}

        }

    };

    JComboBox<SnakePainter> jcombPaintType=new JComboBox<>(snakePainter);

    

    JPanel jpPaint=new JPanel(){

        public void paintComponent(Graphics gr){

            super.paintComponent(gr);

            g=(Graphics2D)gr;

            paintSnake();

        }

    };

    Thread thrRepainter=new Thread(){

        @Override

        public void run() { 

            while(true){

                jpPaint.repaint();

                try{sleep(20);}catch(InterruptedException inter){}

            

            }

        }

    };

    long thrMoverSleep=1000/(int)jspMovesPerSecond.getValue();

    boolean thrMoverPaused=false;

    Thread thrMover=new Thread(){

        @Override

        public void run() {

            while(true){

                if(thrMoverPaused){

                    try{sleep(600000);}catch(InterruptedException inter){}

                }

                else{

                    moveSnake();

                    try{sleep(thrMoverSleep);}catch(InterruptedException inter){}

                }

            }

        }

    };

    void thrMoverPause(){

        thrMoverPaused=true;

        thrMover.interrupt();

    }

    void thrMoverUnpause(){

        thrMoverPaused=false;

        thrMover.interrupt();

    }

    Font bigFont=new Font("Dialog",1,24);

    public JSnake(){

        super(new BorderLayout());

        jpPaint.setFont(bigFont);

        

        

        

        jpRestartButs.add(jbRestart);

        jpRestartButs.add(jbFillHalf);

        

        jpRowsCols.add(BorderLayout.WEST,new JLabel("Rows&Cols"));

        jpRowsCols.add(BorderLayout.CENTER,jspRowsCols);

        jpRowsCols.add(BorderLayout.EAST,jpRestartButs);

        

        jpMovesPerSecond.add(BorderLayout.WEST,new JLabel("moves/sec"));

        jpMovesPerSecond.add(BorderLayout.CENTER,jspMovesPerSecond);

        jpMovesPerSecond.add(BorderLayout.EAST,jcombPaintType);

        

        jpOthers.add(jpRowsCols);

        jpOthers.add(jpMovesPerSecond);

        

        add(BorderLayout.CENTER,jpPaint);

        add(BorderLayout.SOUTH,jpOthers);


        

        jspRowsCols(null);

        jbRestart();

        componentResized(null);

        

        

        

        jpPaint.addMouseListener(this);

        jpPaint.addKeyListener(this);

        

        addComponentListener(this);

        jspRowsCols.addChangeListener(e->jspRowsCols(e));

        jspMovesPerSecond.addChangeListener(e->jspMovesPerSecond());

        jbFillHalf.addActionListener(e->jbRestartHalf());

        jbRestart.addActionListener(e->jbRestart());

        jcombPaintType.addItemListener(e->jcombPaintType(e));

        

        

        Thread focuser=new Thread(){

            public void run(){

                try{sleep(1111);}catch(InterruptedException inter){}

                jpPaint.requestFocusInWindow();

                try{sleep(1111);}catch(InterruptedException inter){}

                jpPaint.requestFocusInWindow();

            }

        };

        focuser.setDaemon(true);

        thrMover.setDaemon(true);

        thrRepainter.setDaemon(true);

        

        

        

        thrRepainter.start();

        thrMover.start();

        focuser.start(); 

    }

    void jcombPaintType(ItemEvent e){

        if(e.getStateChange()==ItemEvent.SELECTED){

            currSnakePainter=(SnakePainter)jcombPaintType.getSelectedItem();

            jpPaint.requestFocusInWindow();

        }

    }

    void nextSnakePaintType(){

        int si=jcombPaintType.getSelectedIndex();

        ++si;

        if(si>=snakePainter.length){

            si=0;

        }

        jcombPaintType.setSelectedIndex(si);

    }

    void increaseSpeed(){

        int next=(int)jspMovesPerSecond.getValue();

        next+=1;

        if(next<=(int)((SpinnerNumberModel)jspMovesPerSecond.getModel()).getMaximum()){

            jspMovesPerSecond.setValue(next);

        }

        else{ tk.beep();}

    }

    void decreaseSpeed(){

        int next=(int)jspMovesPerSecond.getValue();

        next-=1;

        if(next>=(int)((SpinnerNumberModel)jspMovesPerSecond.getModel()).getMinimum()){

            jspMovesPerSecond.setValue(next);

        }

        else{tk.beep();}

    }

    void increaseRowsCols(){

        int next=(int)jspRowsCols.getValue();

        next+=1;

        if(next<=(int)((SpinnerNumberModel)jspRowsCols.getModel()).getMaximum()){

            jspRowsCols.setValue(next);

        }

        else{tk.beep();}

    }

    void decreaseRowsCols(){

        int next=(int)jspRowsCols.getValue();

        next-=1;

        if(next>=(int)((SpinnerNumberModel)jspRowsCols.getModel()).getMinimum()){

            jspRowsCols.setValue(next);

        }

        else{tk.beep();}

    }

    void jspMovesPerSecond(){

        long sec=1000;

        sec/=(int)jspMovesPerSecond.getValue();

        thrMoverSleep=sec;

    }

    void jspRowsCols(ChangeEvent e){

        int rc=(int)jspRowsCols.getValue();

        int rcs=rc*rc;

        byte neox[]=new byte[rcs];

        byte neoy[]=new byte[rcs];

        rows=rc;

        cols=rc;

        snakex=neox;

        snakey=neoy;

        jbRestart();

        componentResized(null);

        

    }

    void jbRestartHalf(){

        if(jbFillHalf.isEnabled()){

            thrMoverPause();

            int l=snakex.length;

            int half=l/2;

            int x=2;

            int y=3;

            if(rows<10){

                y=1;

            }

           

            headDir=dirRight;

            snakeLen=1;

            int i=0;

            snakex[i]=(byte)x;

            snakey[i]=(byte)y;

            ++y;

            ++i;

            boolean ystartOdd=y%2==1;

            while(y<rows){

                if(ystartOdd==(y%2==1)){

                    x=2;

                    while(x<cols){

                        snakex[i]=(byte)x;

                        snakey[i]=(byte)y;

                        ++i;++snakeLen;

                        ++x;

                    }

                }

                else{

                    x=cols-1;

                    while(x>1){

                        snakex[i]=(byte)x;

                        snakey[i]=(byte)y;

                        ++i;++snakeLen;

                        --x;

                    }

                    

                }

                ++y;

            }

            lost=false;won=false;

            createNewRandomApple();

            jpPaint.requestFocusInWindow();

            thrMoverUnpause();

            //jbFillHalf.setEnabled(false);

        }else{tk.beep();}

    }

    void jbRestart(){

        setAllEmpty(2,2,0);

    }

    void setAllEmpty(int snakeI,int snakeJ,int dir){

        thrMoverPause();

        jbFillHalf.setEnabled(true);

        

        lost=false;won=false;

        snakeLen=1;

        snakex[0]=(byte)snakeI;

        snakey[0]=(byte)snakeJ;

        headDir=dir;

        createNewRandomApple();

        jpPaint.requestFocusInWindow();

        thrMoverUnpause();

     }

    

    int applei=-1,applej=-1;

    int availables=0;

    void createNewRandomApple(){

        Vector<Integer> avXs=new Vector<>();

        Vector<Integer> avYs=new Vector<>();

        int i=0;

        while(i<rows){

            int j=0;

            while(j<cols){

                int s=0;

                boolean snakeHasThisSquare=false;

                while(s<snakeLen){

                    if(snakex[s]==j && snakey[s]==i){

                        snakeHasThisSquare=true;

                        s=snakeLen;

                    }

                    ++s;

                }

                if(!snakeHasThisSquare){

                    avXs.add(j);

                    avYs.add(i);

                }

                ++j;

            }

            ++i;

        }

        int size=avXs.size();

        availables=size-1;

        won=availables<rows;

        if(size>0){

            int appleIndex=rand.nextInt(size);

            applei=avXs.get(appleIndex);

            applej=avYs.get(appleIndex);

        }

        else{

            System.out.println("You won !!!! ");

            won=true;

        }

        //System.out.println("Availables: "+availables);

        

    }

    boolean snakeContains(int r,int c){

        int i=0;

        while(i<snakeLen){

            if(snakex[i]==r && snakey[i]==c){

                return true;

            }

            i++;

        }

        

        return false;

    }

    void moveSnake(){

        //System.out.println("moviung");

        int i=0;

        int headi=snakex[0];

        int headj=snakey[0];

        

        int nextheadi=headi+dirs[headDir][0];

        int nextheadj=headj+dirs[headDir][1];

        if(nextheadi<0 ||nextheadi>=cols || nextheadj<0 || nextheadj>=rows){

            lost=true;

        }

        else{

            if(snakeContains(nextheadi, nextheadj)){

                lost=true;

            }

            else{

                

                if(nextheadi==applei && nextheadj==applej){

                    //System.out.println("eating increase snake len");

                    int last=snakeLen;

                    while(last>0){

                        snakex[last]=snakex[last-1];

                        snakey[last]=snakey[last-1];

                        --last;

                    }

                    snakeLen++;

                    snakex[0]=(byte)nextheadi;

                    snakey[0]=(byte)nextheadj;

                    createNewRandomApple();

                    jpPaint.repaint();

                }

                else{

                    int last=snakeLen-1;

                    while(last>0){

                        snakex[last]=snakex[last-1];

                        snakey[last]=snakey[last-1];

                        --last;

                    }

                    snakex[0]=(byte)nextheadi;

                    snakey[0]=(byte)nextheadj;

                }

            }

        }

        

    }

    int headDir(){

        int out=-1;

        if(snakeLen>1){

            if(snakex[0]>snakex[1]){

                return dirRight;

            }

            else if(snakex[0]<snakex[1]){

                return dirLeft;

            }

            else if(snakey[0]>snakey[1]){

                return dirDown;

            }

            else{

                return dirUp;

            }

        }

        return out;

    }

    void setDir(int newDir){

        int dirCurr=headDir();

        if(dirCurr>-1){

            if(newDir!=oppositeDir(dirCurr)){

                headDir=newDir;

            }

            else{

                System.out.println("avoid set opposite direction");

            }

        }

        else{

            headDir=newDir;

        }

    }

    Color colSnake=Color.blue;

    Color colSq=Color.white;

    Color colWall=new Color(10,55,88,88);

    boolean lost=false;

    boolean won=false;

    int wall=10;

    int wall2=wall*2;

    void paintSnake(){

        g.setColor(colWall);

        int x=0;

        int y=0;

        g.fillRect(0, 0, wall2+(cols)*sqs,wall);//up wall

        g.fillRect(0, wall+((rows)*sqs),wall2+(cols)*sqs, wall);//down wall

        g.fillRect(x,wall2, wall, (rows)*sqs-wall2);//left wall

        g.fillRect(wall+cols*sqs,wall2, wall, (rows)*sqs-wall2);//right wall

        

        g.setColor(colSq);

        int i=0,j;

        x=wall;

        y=wall;

        while(i<rows){

            j=i%2;

            x=wall+j*sqs;

            while(j<cols){

                g.fillRect(x,y, sqs,sqs);

                j+=2;

                x+=sqs*2;

            }

            y+=sqs;

            ++i;

        }

        

        g.setColor(colSnake);

        i=0;

        

        while(i<snakeLen){

            x=snakex[i];

            y=snakey[i];

            x*=sqs;

            y*=sqs;

            x+=wall;

            y+=wall;

            currSnakePainter.paintSnakeSquare(x, y);

            //g.fillOval(x,y, sqs,sqs);

            //g.fillRect(x,y, sqs,sqs);

            //g.drawRect(x,y, sqs,sqs);

            //g.drawOval(x,y, sqs,sqs);

            ++i;

        }

        

        g.setColor(Color.red);

        g.fillRect(wall+applei*sqs, wall+applej*sqs, sqs,sqs);

        

        i=0;

        x=snakex[i];

        y=snakey[i];

        x*=sqs;

        y*=sqs;

        x+=sqs/2;

        y+=sqs/2;

        x+=wall;

        y+=wall;

        int xn=x+dirs[headDir][0]*sqs;

        int yn=y+dirs[headDir][1]*sqs;

        g.drawLine(x,y,xn,yn);

        

        

        if(lost){

            g.setColor(Color.RED);

            g.drawLine(0,0,1000,1000);

        }

        g.setColor(Color.green);

        g.drawString("Remains = "+availables,1,bigFont.getSize());

        if(won){

            g.setColor(Color.MAGENTA);

            g.translate((cols/2)*sqs, (rows/2)*sqs);

            g.rotate(theta);theta+=Math.toRadians(10);

            g.drawString("You won ",0,0);

        }

    }

    double theta=0;


    @Override

    public void mouseClicked(MouseEvent e) {

    }


    @Override

    public void mousePressed(MouseEvent e) {

        jpPaint.requestFocusInWindow();

    }


    @Override

    public void mouseReleased(MouseEvent e) {

    }


    @Override

    public void mouseEntered(MouseEvent e) {

    }


    @Override

    public void mouseExited(MouseEvent e) {

    }


    @Override

    public void keyTyped(KeyEvent e) {

    }


    @Override

    public void keyPressed(KeyEvent e) {

        int kc=e.getKeyCode();

        if((kc==KeyEvent.VK_UP||kc==KeyEvent.VK_W) && headDir!=dirDown){

            //System.out.println("up");

            setDir(dirUp);            

        }

        else if((kc==KeyEvent.VK_DOWN||kc==KeyEvent.VK_S) && headDir!=dirUp){

            //System.out.println("down");

            setDir(dirDown);

            

        }

        else if((kc==KeyEvent.VK_LEFT||kc==KeyEvent.VK_A) && headDir!=dirRight){

            //System.out.println("left");

            setDir(dirLeft);

            

        }

        else if((kc==KeyEvent.VK_RIGHT||kc==KeyEvent.VK_D) && headDir!=dirLeft){

            //System.out.println("right");

            setDir(dirRight);

            

        }

        else if(kc==KeyEvent.VK_ENTER){

            jbRestart();

        }

        else if(kc==KeyEvent.VK_P){

            jbRestartHalf();

        }

        else if(kc==KeyEvent.VK_Y){

            decreaseSpeed();

        }

        else if(kc==KeyEvent.VK_U){

            increaseSpeed();

        }

        else if(kc==KeyEvent.VK_G){

            decreaseRowsCols();

        }

        else if(kc==KeyEvent.VK_H){

            increaseRowsCols();

        }

        else if(kc==KeyEvent.VK_L){

            lost=false;

        }

        else if(kc==KeyEvent.VK_R){

            colSnake=randColor();

        }

        else if(kc==KeyEvent.VK_T){

            nextSnakePaintType();

        }

    }


    @Override

    public void keyReleased(KeyEvent e) {

    }


    @Override

    public void componentResized(ComponentEvent e) {

        int fitsrows=(jpPaint.getHeight()-wall*2)/(rows);

        int fitscols=(jpPaint.getWidth()-wall*2)/(cols);

        sqs=Math.min(fitscols, fitsrows);

        jpPaint.repaint();

    }


    @Override

    public void componentMoved(ComponentEvent e) {

    }


    @Override

    public void componentShown(ComponentEvent e) {

    }


    @Override

    public void componentHidden(ComponentEvent e) {

    }

    

    

    

    


}