import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.geom.*; import java.net.*; import java.io.*; import java.applet.*; class Node { //********************************************* //* * //* This class is needed for the class list. * //* A Node looks like an element of the list. * //* * //********************************************* private int value; //Value of the Node private Node next; //The next Node in the list private Node previous; //The previous Node in the list public Node(){ value=0; } public Node(int _value){ value=_value; } public void setValue(int _value){ value=_value; } public void setPrevious(Node _previous){ previous=_previous; } public void setNext(Node _next){ next=_next; } public int getValue(){ return value; } public Node getPrevious(){ return previous; } public Node getNext(){ return next; } } class List { //****************************************** //* * //* This class decribe a bichained list. * //* I don't use the linkedList of java * //* because it need use of complex Object. * //* * //****************************************** private Node first; //The first Node of the list private Node last; //The last Node of the list public Node current; //A Node we play the game of an iterator public int length; //The length of the list public List(){ length=0; } public Node getFirst(){ return first; } public Node getLast(){ return last; } public void initCurrent(){ current=first; } public void setCurrent(Node _current){ current=_current; } public Node getCurrent(){ return current; } public boolean isEnd(){ return current==last; } public void shift(){ // --------------------------------------- //| Change the current node with the next | // --------------------------------------- current=current.getNext(); } public void addFirst(int value){ // ---------------------------------------------------- //| Add a Node of value 'value' at the end of the list | // ---------------------------------------------------- Node node=new Node(value); if(length==0){ first=node; last=node; } else{ first.setPrevious(node); node.setNext(first); first=node; } length++; } public void addLast(int value){ // ---------------------------------------------------- //| Add a Node of value 'value' at the end of the list | // ---------------------------------------------------- Node node=new Node(value); if(length==0){ first=node; last=node; } else{ last.setNext(node); node.setPrevious(last); last=node; } length++; } public Node addBefore(int value){ // ----------------------------------------------------------------- //| Add a Node of value 'value' before the current Node of the list | //| and return the new Node | // ----------------------------------------------------------------- Node node=new Node(value); if(current==first){ first=node; node.setNext(current); current.setPrevious(node); } else { Node temp=current.getPrevious(); temp.setNext(node); node.setPrevious(temp); current.setPrevious(node); node.setNext(current); } length++; return node; } public Node addAfter(int value){ // ---------------------------------------------------------------- //| Add a Node of value 'value' after the current Node of the list | //| and return the new Node | // ---------------------------------------------------------------- Node node=new Node(value); if(current==last){ last=node; node.setPrevious(current); current.setNext(node); } else{ Node temp=current.getNext(); temp.setPrevious(node); node.setNext(temp); current.setNext(node); node.setPrevious(current); } length++; return node; } public void remove(Node node){ // ---------------------------------- //| Remove the Node node of the list | // ---------------------------------- if(length!=0){ if(length==1){ length=0; } else{ if(node==first){ first=node.getNext(); node=first; } else if(node==last){ last=node.getPrevious(); current=last; } else{ (node.getPrevious()).setNext(node.getNext()); (node.getNext()).setPrevious(node.getPrevious()); } length--; } } } public int value(){ return current.getValue(); } public int length(){ return length; } } public class HandleReduction extends JApplet implements ActionListener{ //******************************************************* //* * //* This class represent the window of the application. * //* * //******************************************************* public static final long serialVersionUID = 0; private Panel panel; //Will draw graphics on the panel private JTextField textFieldDraw; private JTextField textFieldReduce; private JTextField textFieldCompare1; private JTextField textFieldCompare2; private JButton draw; private JButton reduce; private JButton compare; private JButton option; private JButton startDraw; private JButton startReduce; private JButton startCompare; private JButton applyOption; private JButton cancelDraw; private JButton cancelReduce; private JButton cancelCompare; private JButton cancelOption; private JFrame drawFrame; private JFrame reduceFrame; private JFrame compareFrame; private JFrame optionFrame; private JScrollBar delay; private JLabel speed; private JRadioButton continuous; private JRadioButton stepbystep; public JLabel currentWord; public int speedValue=100; public boolean continuousAnimation=true; public int speedValue2; public boolean continuousAnimation2; public void init(){ panel=new Panel(); panel.setBackground(Color.darkGray); panel.setBounds(0,20,480,600); add(panel); currentWord=new JLabel("No braid word"); currentWord.setBounds(0,0,480,20); add(currentWord); draw=new JButton("Draw"); draw.addActionListener(this); draw.setBounds(0,620,120,20); add(draw); reduce=new JButton("Reduce"); reduce.addActionListener(this); reduce.setBounds(120,620,120,20); add(reduce); compare=new JButton("Compare"); compare.addActionListener(this); compare.setBounds(240,620,120,20); add(compare); option=new JButton("Controls"); option.addActionListener(this); option.setBounds(360,620,120,20); add(option); add(new JLabel("")); } public void start(){ update(getGraphics()); validate(); } public void lock(){ draw.setEnabled(false); reduce.setEnabled(false); compare.setEnabled(false); option.setEnabled(false); } public void unlock(){ draw.setEnabled(true); reduce.setEnabled(true); compare.setEnabled(true); option.setEnabled(true); } public void actionPerformed(ActionEvent event){ // ---------------------------------------------------------- //| Specify what the action on the element of the windows do | // ---------------------------------------------------------- //===> Draw If(event.getSource()==draw){ drawFrame=new JFrame("Draw"); drawFrame.setSize(300,105); drawFrame.setLocationRelativeTo(null); drawFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); drawFrame.setResizable(false); lock(); JLabel message=new JLabel("Enter a braid word : "); message.setBounds(5,5,290,20); textFieldDraw=new JTextField(10); textFieldDraw.setBounds(5,25,290,20); textFieldDraw.addActionListener(this); startDraw=new JButton("Draw"); startDraw.addActionListener(this); startDraw.setBounds(20,55,120,20); cancelDraw=new JButton("Cancel"); cancelDraw.addActionListener(this); cancelDraw.setBounds(160,55,120,20); drawFrame.add(message); drawFrame.add(textFieldDraw); drawFrame.add(startDraw); drawFrame.add(cancelDraw); drawFrame.add(new JLabel("")); drawFrame.setVisible(true); } else if(event.getSource()==startDraw){ panel.init(this,speedValue,continuousAnimation); panel.writeBraidWord(textFieldDraw.getText()); unlock(); drawFrame.dispose(); } else if(event.getSource()==cancelDraw){ unlock(); drawFrame.dispose(); } //===> Reduce else if(event.getSource()==reduce){ reduceFrame=new JFrame("Reduce"); reduceFrame.setSize(300,105); reduceFrame.setLocationRelativeTo(null); reduceFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); reduceFrame.setResizable(false); lock(); JLabel message=new JLabel("Enter a braid word : "); message.setBounds(5,5,290,20); textFieldReduce=new JTextField(10); textFieldReduce.setBounds(5,25,290,20); textFieldReduce.addActionListener(this); startReduce=new JButton("Reduce"); startReduce.addActionListener(this); startReduce.setBounds(20,55,120,20); cancelReduce=new JButton("Cancel"); cancelReduce.addActionListener(this); cancelReduce.setBounds(160,55,120,20); reduceFrame.add(message); reduceFrame.add(textFieldReduce); reduceFrame.add(startReduce); reduceFrame.add(cancelReduce); reduceFrame.add(new JLabel("")); reduceFrame.setVisible(true); } else if(event.getSource()==startReduce){ textFieldReduce.setEnabled(false); if(!panel.working){ panel.init(this,speedValue,continuousAnimation); panel.writeBraidWord(textFieldReduce.getText()); panel.working=true; startReduce.setText("Continue"); startReduce.updateUI(); } startReduce.setEnabled(false); boolean red=panel.reduce(); String message; int ind=panel.indice(); if(red){ if(ind==0){ message="The final word is empty, so your initial braid word \n"+textFieldReduce.getText()+" is trivial."; } else{ message="There is no more handle and the final word is nonempty, so your initial braid word\n "+textFieldReduce.getText()+" is not trivial."; } JOptionPane.showMessageDialog(null,message); unlock(); panel.working=false; reduceFrame.dispose(); } else{ startReduce.setEnabled(true); } } else if(event.getSource()==cancelReduce){ reduceFrame.dispose(); unlock(); panel.working=false; } //===> Compare else if(event.getSource()==compare){ compareFrame=new JFrame("Compare"); compareFrame.setSize(300,145); compareFrame.setLocationRelativeTo(null); compareFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); compareFrame.setResizable(false); lock(); JLabel message1=new JLabel("Enter a first braid word : "); message1.setBounds(5,5,290,20); textFieldCompare1=new JTextField(10); textFieldCompare1.setBounds(5,25,290,20); JLabel message2=new JLabel("Enter a second braid word : "); message2.setBounds(5,45,290,20); textFieldCompare2=new JTextField(10); textFieldCompare2.setBounds(5,65,290,20); startCompare=new JButton("Compare"); startCompare.addActionListener(this); startCompare.setBounds(20,95,120,20); cancelCompare=new JButton("Cancel"); cancelCompare.addActionListener(this); cancelCompare.setBounds(160,95,120,20); compareFrame.add(message1); compareFrame.add(textFieldCompare1); compareFrame.add(message2); compareFrame.add(textFieldCompare2); compareFrame.add(startCompare); compareFrame.add(cancelCompare); compareFrame.add(new JLabel("")); compareFrame.setVisible(true); } else if(event.getSource()==startCompare){ if(!panel.working){ String word1,word2; word1=textFieldCompare1.getText(); word2=textFieldCompare2.getText(); textFieldCompare1.setEnabled(false); textFieldCompare2.setEnabled(false); panel.init(this,speedValue,continuousAnimation); panel.compare(word1,word2); startCompare.setText("Continue"); startCompare.updateUI(); } boolean red; startCompare.setEnabled(false); red=panel.reduce(); if(red){ String message; int ind=panel.indice(); if(ind==0){ message="The final word is empty,\nso your initial braid words "+textFieldCompare1.getText()+" and "+textFieldCompare2.getText()+" are equivalent."; } else if(ind>0){ //smaller message="There is no more handle and the final word is nonempty,\nso your initial braid words "+textFieldCompare1.getText()+" and "+textFieldCompare2.getText()+" are not equivalent."; } else{ //larger message="There is no more handle and the final word is nonempty,\nso your initial braid words "+textFieldCompare1.getText()+" and "+textFieldCompare2.getText()+" are not equivalent."; } JOptionPane.showMessageDialog(null,message); compareFrame.dispose(); panel.working=false; unlock(); } else{ startCompare.setEnabled(true); } } else if(event.getSource()==cancelCompare){ compareFrame.dispose(); unlock(); panel.working=false; } //===> Option else if(event.getSource()==option){ optionFrame=new JFrame("Controls"); optionFrame.setSize(300,110); optionFrame.setLocationRelativeTo(null); optionFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); optionFrame.setResizable(false); lock(); continuous=new JRadioButton(); stepbystep=new JRadioButton(); ButtonGroup group = new ButtonGroup(); continuous.setText("Continuous"); stepbystep.setText("Step-by-step"); continuous.addActionListener(this); stepbystep.addActionListener(this); continuousAnimation2=continuousAnimation; speedValue2=speedValue; if(continuousAnimation){ continuous.setSelected(true); } else{ stepbystep.setSelected(true); } group.add(continuous); group.add(stepbystep); JLabel label1=new JLabel("Mode :"); delay=new JScrollBar(JScrollBar.HORIZONTAL,speedValue,0,0,100); delay.addAdjustmentListener(new java.awt.event.AdjustmentListener(){ public void adjustmentValueChanged(AdjustmentEvent event){ scrollBarValueChanged(event); } }); speed=new JLabel("Speed : "+speedValue); label1.setBounds(5,5,60,20); continuous.setBounds(65,5,100,20); stepbystep.setBounds(165,5,120,20); speed.setBounds(5,30,80,20); delay.setBounds(85,30,200,20); applyOption=new JButton("Apply"); applyOption.addActionListener(this); applyOption.setBounds(20,60,120,20); cancelOption=new JButton("Cancel"); cancelOption.addActionListener(this); cancelOption.setBounds(160,60,120,20); optionFrame.add(label1); optionFrame.add(continuous); optionFrame.add(stepbystep); optionFrame.add(speed); optionFrame.add(delay); optionFrame.add(applyOption); optionFrame.add(cancelOption); optionFrame.add(new JLabel("")); optionFrame.setVisible(true); } else if(event.getSource()==continuous){ if(continuous.isSelected()){ continuousAnimation2=true; } } else if(event.getSource()==stepbystep){ if(stepbystep.isSelected()){ continuousAnimation2=false; } } else if(event.getSource()==applyOption){ continuousAnimation=continuousAnimation2; speedValue=speedValue2; unlock(); optionFrame.dispose(); } else if(event.getSource()==cancelOption){ optionFrame.dispose(); unlock(); } } public void scrollBarValueChanged(AdjustmentEvent event){ if(event.getSource()==delay){ speedValue2=delay.getValue(); speed.setText("Speed : "+speedValue2); } } public String getAppletInfo() { return "Handle reduction algorithm."; } } class Pause extends Thread{ //********************************* //* * //* This class pause the program. * //* * //********************************* public void pause(int delayValue){ try { sleep(delayValue); } catch (InterruptedException ex) {} } } class Panel extends JPanel{ //************************************************ //* * //* This class is the key class of this program. * //* It contains algoritms and drawing tools. * //* * //************************************************ public static final long serialVersionUID = 0; //Word variable private HandleReduction myWindow; private JLabel currentBraidWord; //=====> Braid variable private String braidWord; //The initial braid word private boolean braidWordSet=false; private List braid; //The braid word as a list public String currentWord=""; public boolean working=false; private String compareWord1; private String compareWord2; //=====> Strand variable private int strandNumber=5; //The number of strand private float strandStep; //The distance between two strand private float strandWidth; //The width of a strand private float strandLeft; //The x position of the leftmost strand private float[] xPos; //The x postion of strands private float[] xPosNext; //The next x position of strands private float yUp; //The y position of the first element of the braid //=====> Handle variable private Node handleBegin; //The first node of the handle private Node handleEnd; //The last node of the handle private int handleStrand; //The current strand of the handle private int handleType; //The type of the handle, is 1 if the handle start with a positive element private boolean handleNormalDraw; //This variable is true if we draw the handle with the classic metod private boolean onHandle; //This variable is true if we are in between the handleBegin Node and the handleEnd node private float handleBeginYPos; //The y position of the begin of the handle private float handleEndYPos; //The y position of the end of the handle //======> Trivial variable private int trivialNumber; //The number of trivial element without the extremity private float trivialHeight; //The height of a trivial element //======> Animation variable private int animationStep; //The current animation step private float parameterAnimationStep2; // \ private float parameterAnimationStep4; // | Parameters for the animation private float parameterAnimationStep5; // / private boolean continuousAnimation; private int delayValue; private Pause pause=new Pause(); //For make pause during animation //======> Color variable private Color[] strandColor; //The color of different strand private Color handleColor=Color.black; //The color of the handle private Color originalHandleStrandColor; //The original color of the handle strand //======> Way variable private GeneralPath[] continuousWay; //The currant continuous way of strands //======> Double Buffering variable private Image offScreenBuffer; //A buffer in wich we draw and after drawing we will show this buffer private boolean isDraw; //For not repeat drawing // ================= //I I //I Braid functions I //I I // ================= private void initBraid(){ // ----------------------------------------------------- //| Iniliasition of braid as a list and of strandNumber | // ----------------------------------------------------- int length; int value; char letter; strandNumber=2; value=0; braid=new List(); length=braidWord.length(); //get the length of the braid word braid.addLast(0); //add a trivial at the begin for(int i=0;i='a' && letter<='z'){ //if we have a lower case letter value=(int)(letter-'a')+1; //value is 1 for 'a', 2 for 'b', ... if(value+1>strandNumber){ //update the strand number strandNumber=value+1; } } else if(letter>='A' && letter<='Z'){ //if we have an upper case letter value=-(int)(letter-'A')-1; //value is -1 for 'A', -2 for 'B', ... if(-value+1>strandNumber){ //update the strand number strandNumber=-value+1; } } else{ value=0; } braid.addLast(value); //add the value at the list of the braid } braid.addLast(0); //add a trivial at th end } public void init(HandleReduction _myWindow,int _delayValue,boolean _continuousAnimation){ myWindow=_myWindow; delayValue=100-_delayValue; continuousAnimation=_continuousAnimation; } public void writeBraidWord(String buffer){ // ----------------------------------------------------- //| Initialise the braid word and some other parameters | //------------------------------------------------------ braidWord=buffer; initBraid(); //initialise the braid list animationStep=0; //initialise the animation step trivialNumber=0; // \ trivialHeight=0; // Initilise the trivial parameters handleNormalDraw=true; //we draw the handle with the classic method for the moment updateCurrentBraidWord(); braidWordSet=true; isDraw=false; //we draw a new image update(super.getGraphics()); //update draw } public void compare(String word1, String word2){ int length; int value; char letter; compareWord1=word1; compareWord2=word2; strandNumber=2; value=0; braid=new List(); length=word2.length(); //get the length of the braid word for(int i=0;i='a' && letter<='z'){ //if we have a lower case letter value=(int)(letter-'a')+1; //value is 1 for 'a', 2 for 'b', ... if(value+1>strandNumber){ //update the strand number strandNumber=value+1; } } else if(letter>='A' && letter<='Z'){ //if we have an upper case letter value=-(int)(letter-'A')-1; //value is -1 for 'A', -2 for 'B', ... if(-value+1>strandNumber){ //update the strand number strandNumber=-value+1; } } else{ value=24; } braid.addLast(value); //add the value at the list of the braid } braid.addLast(0); length=word1.length(); for(int i=0;i='a' && letter<='z'){ value=-(int)(letter-'a')-1; if(-value+1>strandNumber){ strandNumber=-value+1; } } else if(letter>='A' && letter<='Z'){ value=(int)(letter-'A')+1; if(value+1>strandNumber){ strandNumber=value+1; } } else{ value=24; } braid.addFirst(value); } braid.addFirst(0); animationStep=0; trivialNumber=0; trivialHeight=0; handleNormalDraw=true; updateCurrentBraidWord(); braidWordSet=true; isDraw=false; //we draw a new image working=true; update(super.getGraphics()); //update draw } public void updateCurrentBraidWord(){ boolean stop; int value; String res=""; braid.initCurrent(); stop=false; while(!stop){ value=braid.value(); if(value>0){ res+=(char)((value-1)+'a'); } else if(value<0){ res+=(char)((-value-1)+'A'); } if(braid.isEnd()){ stop=true; } if(!stop){ braid.shift(); } } if(res==""){ res="1"; } currentWord=res; (myWindow.currentWord).setText("Current braid word: "+res); myWindow.update(myWindow.getGraphics()); myWindow.validate(); } // =============================== //I I //I Handle reduction algorithms I //I I // =============================== public void findHandle(){ // ----------------------------------- //| Search a handle in the braid word | //| with no intricated handle | // ----------------------------------- Node handles[]=new Node[strandNumber]; //We stock information of potential handle int signs[]=new int[strandNumber]; //We stock the sign of the last n generato in signs[n]; int sign,value; boolean stop; //A flag for stop the main while for(int i=0;iMath.abs(indice)){ indice=value; } if(braid.isEnd()){ stop=true; } else{ braid.shift(); } } return indice; } // ================= //I I //I Color functions I //I I // ================= public void initStrandColor(){ // --------------------------- //| Init the color of strands | // --------------------------- strandColor=new Color[strandNumber]; //Make the table of strand color for(int strand=1;strandb){ return a; } else{ return b; } } public double square(double a){ return a*a; } // =================== //I I //I Position function I //I I // =================== public void calcXPosNext(){ // ---------------------------------------- //| Compute the nex x position of strands. | //| It's a key function for animation. | // ---------------------------------------- for(int strand=0;strand=1){ trivialHeight=1; parameterAnimationStep2=1; animationStep=2; pause.pause(delayValue); return reduce(); } else{ trivialHeight+=0.1; update(getGraphics()); pause.pause(delayValue); return reduce(); } } else if(animationStep==2){ if(handleStrand==0){ return true; } else if(parameterAnimationStep2<(float)(1.25)*((float)strandWidth/strandStep)){ handleNormalDraw=false; animationStep=3; pause.pause(delayValue); return reduce(); } else{ parameterAnimationStep2-=(float)0.05; update(getGraphics()); pause.pause(delayValue); return reduce(); } } else if(animationStep==3){ parameterAnimationStep4=0; animationStep=4; update(getGraphics()); pause.pause(delayValue); return reduce(); } else if(animationStep==4){ if(parameterAnimationStep4>=1){ removeHandle(); handleNormalDraw=true; parameterAnimationStep5=1-(float)(1.25)*((float)strandWidth/strandStep); animationStep=5; pause.pause(delayValue); return reduce(); } else{ parameterAnimationStep4+=(float)0.05; update(getGraphics()); pause.pause(delayValue); return reduce(); } } else if(animationStep==5){ if(parameterAnimationStep5<=(float)0.05){ parameterAnimationStep5=0; animationStep=6; pause.pause(delayValue); return reduce(); } else{ parameterAnimationStep5-=(float)0.05; update(getGraphics()); pause.pause(delayValue); return reduce(); } } else if(animationStep==6){ if(trivialHeight<=0){ trivialHeight=0; animationStep=7; pause.pause(delayValue); update(getGraphics()); return reduce(); } else{ trivialHeight-=0.1; update(getGraphics()); pause.pause(delayValue); return reduce(); } } else if(animationStep==7){ removeTrivials(); handleStrand=0; update(getGraphics()); animationStep=0; updateCurrentBraidWord(); update(getGraphics()); pause.pause(delayValue); if(continuousAnimation){ return reduce(); } else{ return false; } } return false; } }