/* * Copyright (c) 1995 Luis Fernandes * * Permission to use, copy, hack, and distribute this software and its * documentation for NON-COMMERCIAL purposes and without fee is hereby * granted provided that this copyright notice appears in all copies. * */ /* $Id: Abacus.java,v 1.3f 1995/06/01 22:59:31 elf Exp elf $ */ /* $Log: Abacus.java,v $ # Revision 1.3f 1995/06/01 22:59:31 elf # Value of each column is now displayed in the top frame. # # Redraw (via update) is clipped to a region that surrounds the # appropriate column that needs updating. # # Revision 1.2f 1995/04/17 16:40:13 elf # Implemented user-defined resource "VALUE" which may to used to set # the initial condition (bead-configuration) of the abacus. # # Eliminated *some* re-draw flicker by moving the repaint() call to # animateBead() rather than keeping it in moveBead() where it caused # the applet to redraw everytime a bead moved (this was especially bad # when several beads moved at once). # */ import java.awt.*; /* This is a java-applet simulation of a Chinese abacus. Each column is stored internally in an integer array called 'column' that is initialized to represent the resting positions of the beads: 2 bead on top deck row-pos 0 & 1, pos 2 empty; 5 beads lower deck pos 4-8, pos 3 empty. The initial value is 499d=111110011 where a '1' represents a position that is occupied by a bead and a '0' represents an empty position. As the beads are moved, the 1's are shifted (using << and >>) accordingly to represent their new locations. */ /* The illustration below represents 1 column of the abacus. * O represents the bead; * | represents an empty position (the rod) * = represents the frame * * ============= Row Position (index 'r' ) * O 0 * O 1 Upper Deck * | 2 * ============= * | 3 * O 4 * O 5 Lower Deck * O 6 * O 7 * O 8 * ============= * */ public class Abacus extends java.applet.Applet { /* initial attributes of the abacus*/ static final int MAXCOLS=10; /* number of columns the abacus will have */ static final int BEADHEIGHT=17; static final int BEADWIDTH=17; static final int FRAMEWIDTH=10; /* thickness of the frame*/ static final int COLGAP=2; /* gap between 2 cols*/ static final int ROWGAP=2; /* gap between 2 rows*/ static final int NTOPROWS=3; /*(2 beads, 1 gap on top-deck)*/ static final int NBOTROWS=6; /*(5 beads, 1 gap on top-deck)*/ static final int NCOLS=MAXCOLS; /* number of columns*/ static final int NROWS=(NTOPROWS+NBOTROWS); /* number of rows*/ static final int MIDFRAME=(FRAMEWIDTH+(NTOPROWS*BEADHEIGHT)+((NTOPROWS+1)*ROWGAP)); //size().width & size().height of window depends on attributes of the abacus static final int INITWIDTH=((2*FRAMEWIDTH)+(NCOLS*BEADWIDTH)+((NCOLS+1)*COLGAP)); static final int INITHEIGHT=((3*FRAMEWIDTH)+(NROWS*BEADHEIGHT)+((NROWS+1)*ROWGAP)); private int column[]=new int[MAXCOLS]; private int cx, cy; // for xlating x,y to row,col private int ux, uy; // for clipping region private boolean overflow; // when the abacus overflows this is true private boolean carry; // when a calc causes a carry to the next col Image bead, nobead; // holds picture of a bead and an empty loc Font valueFont; // to paint the value public void init() { String valattr; /* Init the internal configuration of the beads: 499d=111110011 * (2 bead on top deck pos 0 & 1; 5 beads lower deck pos 4-8, * pos 2 & 3 are empty initially) */ for(int i=0; i"+valattr); */ if((valattr==null) || (valattr.length()>MAXCOLS) ) { /* if no attribute is specified, or the value is too big, * use default*/ System.out.println(valattr+"(VALUE resource) is either too big or unspecified; ignoring.\n"); } else /* set each column according to the user-specified value*/ { int len=valattr.length(); for(int i=0; i4) { /* System.out.println("Col "+i+"%5="+val%5); */ animateBead(1, i); } // set value in the lower-deck int remainder=val%5; if(remainder>0) { animateBead(3+remainder, i); } } } bead=getImage(getCodeBase(), "images/diamond.gif"); nobead=getImage(getCodeBase(), "images/nodiamond.gif"); valueFont=new java.awt.Font("Courier", Font.BOLD, 10); resize(INITWIDTH, INITHEIGHT); /* initial size */ } private void displayValue(Graphics g) { char valchars[]= new char [MAXCOLS*3]; String value= new String (valchars); if(overflow) value+="*"; /* look at each column*/ for(int col=0; col=0; r--) { if(!RowOccupied(r, column[col])) break; } val+=((2-r)*5); /* bottom-deck*/ for(r=3; r<9; r++) { if(!RowOccupied(r, column[col])) break; } val+=(r-3); /* System.out.println("\tColumn"+col+"value="+val);*/ value=value+" "+Integer.toString(val); } if(overflow) g.setColor(Color.red); else g.setColor(Color.yellow); g.drawString(value, 5, 10); } /* draw the abacus */ public void paint(Graphics g) { if (bead == null) { return; } drawFrame(g); for(int i=0; i2) /* if pos (row) is greater than 3 ...*/ { cy--; /* ...adjust by 1 row*/ return(true); } else { return(true); } }/*translateXY2RowCol()*/ final private boolean RowOccupied(int r, int c) { if((c & 1<<(r))==0) { return false; } else { return true; } }/*RowOccupied()*/ }