📄 abacus.java
字号:
/*
* 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.1 1995/09/25 20:15:07 elf Exp elf $ */
/* $Log: Abacus.java,v $
* Revision 1.1 1995/09/25 20:15:07 elf
* Initial revision
*/
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.
<pre>
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
=============
</pre>
@author Luis Fernandes
*/
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
/**
Initialize the Abacus by initializing the internal column
array. If a "VALUE" resource is specified, set the column array
according to it, instead.
*/
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<MAXCOLS; i++) column[i]=499;
/* check for user-specified value resource*/
valattr=getParameter("value");
/* System.out.println("==>"+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; i<len; i++)
{
int val=Integer.valueOf(valattr.substring(i,i+1)).intValue();
// set value in the upper-deck
if(val>4)
{
/* 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<MAXCOLS; col++)
{
int r;
int val=0;
/* find the empty row, and determine what the value is*/
/* top-deck*/
for(r=2; r>=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 (draw the frame, draw the rods & draw the
beads). Display the value in the frame. */
public
void paint(Graphics g)
{
if (bead == null) {
return;
}
drawFrame(g);
for(int i=0; i<MAXCOLS; i++)
{
drawColumn(g, i);
}
displayValue(g);
}/* init()*/
public void update(Graphics g)
{
paint(g);
g.setColor(Color.black);
g.fillRect(0,0,INITWIDTH, FRAMEWIDTH);
displayValue(g);
}
/**
Handle a mouse-click.
Convert the x/y position of the click to a row/column equivalent
and move the corresponding bead.
@param evt is the internal AWT event varaible
@param x is the x-position of the click, in pixels
@param y is the y-position of the click, in pixels
@return ux as a global (used for clipping calculations)
@return uy as a global (used for clipping calculations)
*/
public
boolean mouseUp(java.awt.Event evt, int x, int y) {
/* row,col returned in cx,cy*/
boolean i=translateXY2RowCol(x, y);
if(i) /*valid row,col...*/
{
if(RowOccupied(cy,column[cx]))
{
animateBead(cy,cx);
ux=FRAMEWIDTH+(cx*(COLGAP+BEADWIDTH));
uy=FRAMEWIDTH+(cy*(ROWGAP+BEADHEIGHT));
repaint();
}
}
return true;
} /*mouseUp()*/
private
void drawColumn(Graphics g, int col)
{
for(int beadnum=0; beadnum<9; beadnum++)
{
if(RowOccupied(beadnum,column[col]))
{
drawBead(g, beadnum, col);
}
else
{
undrawBead(g, beadnum, col);
}
}
} /*drawColumn()*/
private
void drawBead(Graphics g, int row, int col)
{
if(row<3) /* beads in the top-deck */
{
g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
else /* account for the middle-rail */
{
g.drawImage(bead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
(2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
} /*drawBead()*/
private
void undrawBead(Graphics g, int row, int col)
{
if(row<3) /* beads in the top-deck */
{
g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
FRAMEWIDTH+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
else /* account for the middle-rail */
{
g.drawImage(nobead, FRAMEWIDTH+COLGAP+(col*(BEADWIDTH+COLGAP)),
(2*FRAMEWIDTH)+(row*(BEADHEIGHT+ROWGAP))+2, this);
}
} /*undrawBead()*/
private
void drawFrame(Graphics g)
{
g.setColor(Color.blue);
/* the rails*/
for(int i=0; i<NCOLS; i++)
g.drawLine(FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)), 0,
FRAMEWIDTH+COLGAP+(BEADWIDTH/2)+(i*(BEADWIDTH+COLGAP)),
INITHEIGHT);
g.setColor(Color.black);
g.fillRect(0,0,INITWIDTH, FRAMEWIDTH); /*top bar*/
g.fillRect(0,INITHEIGHT-FRAMEWIDTH, INITWIDTH, FRAMEWIDTH); /*bot bar*/
g.fillRect(INITWIDTH-FRAMEWIDTH, 0, INITWIDTH, INITHEIGHT); /*right bar*/
g.fillRect(0,0, FRAMEWIDTH, INITHEIGHT-FRAMEWIDTH); /*left bar*/
/* middle bar*/
g.fillRect(0, MIDFRAME, INITWIDTH, FRAMEWIDTH);
}/*drawFrame()*/
/**
* Moves the bead specified by r & c in the appropriate direction
*
* @param r is the row number for the bead
* @param c is the column number for the bead
*/
public
void animateBead(int r, int c)
{
if(r<3) /* selection in upper deck*/
{
int i;
/* find empty row in upperdeck; pos 0,1,2*/
for(i=0; i<3; i++) if(!RowOccupied(i,column[c])) break;
if(i<r) /* if empty row is above cur bead...*/
moveBeadUp(r,c);
else
moveBeadDn(r,c);
}
else /* selection in lower deck*/
{
int i;
/* find empty row in lowerdeck; pos 3-8 */
for(i=3; i<9; i++) if(!RowOccupied(i,column[c])) break;
if(i<r) /* if empty row is above cur bead...*/
moveBeadUp(r,c);
else
moveBeadDn(r,c);
}
}/*animateBead()*/
private
void moveBeadUp(int r, int c)
{
/* keep looking for an empty position directly above*/
if(RowOccupied(r-1,column[c])) moveBeadUp(r-1,c);
column[c]=column[c]-(1<<r); /* row 'r' is now empty */
column[c]=column[c]+(1<<((r-1))); /* row 'r-1' now is occupied*/
// check whether we have to carry to next column
if(!RowOccupied(0,column[c]))
{
System.out.println("Carry to col"+(c-1));
carry=true;
}
else if(c==0 && r==1)
{
overflow=false;
}
} /*moveBeadUp()*/
private
void moveBeadDn(int r, int c)
{
/* keep looking for an empty position directly below*/
if(RowOccupied(r+1,column[c])) moveBeadDn(r+1,c);
column[c]=column[c]-(1<<r); /* row 'r' is now empty */
column[c]=column[c]+(1<<((r+1))); /* row 'r+1' now is occupied*/
// check whether we have to carry to next column if in the top frame
if(!RowOccupied(0,column[c]) && r<3)
{
if(c==0)
{
System.out.println("***OVERFLOW***");
overflow=true;
return;
}
System.out.println("Carry to col"+(c-1));
carry=true;
}
}/* moveBeadDown()*/
/** translateXY2RowCol, converts x,y coord a row,col coord. The top
* deck has 3 rows (1 is empty), the bottom deck has 6 rows (1 is
* empty). Row # 3 is invalid because the middle-frame occupies this
* position. Coordinates for the bottom deck are adjusted for this
* anomaly, i.e. row #4 on the screen, is actually index #3 into the
* Column array.
*
* @param absolute x,y coordinates representing the click-location
* @return as globals cx: the row (0-9) & cy: the col (0-NCOLS) index
* @return True if click was on a bead or empty position
* @return False if click was at mid-frame location
*/
private
boolean translateXY2RowCol(int x, int y)
{
cx=(x-FRAMEWIDTH)/(COLGAP+BEADWIDTH);
if(cy<MIDFRAME)
{
cy=(y-FRAMEWIDTH)/(ROWGAP+BEADHEIGHT);
}
else /* account for the middle-frame (+1 bead size().height) (+4 is fudge)*/
{
cy=(y-((2*FRAMEWIDTH)-BEADHEIGHT))/(ROWGAP+BEADHEIGHT);
}
/* technically, the mid-frame occupies position 3 & click is invalid*/
if(cy==3) return(false);
else if(cy>2) /* 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()*/
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -