Use the code from the book (and from my notes) to implement a Stack ADT using a linked list.( https://github.com/IvoIvanov77/-Algorithms/blob/403289d0c471f157049d3279bbfe5917de69b4df/src/fundamentals/Evaluate.java ) Use this Stack to implement Dijkstra’s Two-Stack Algorithm for expression evaluation. This code is also given in the book and in my notes. You will need to change this code so that the algorithm is in a separate method for the evaluation. That is, read the input into a String variable that you pass to your method for evaluation.
To this code, add Junit test to test the Stack methods and to test the evaluate method.
META-INF/MANIFEST.MF
Manifest-Version: 1.0
Created-By: 1.8.0_191 (Oracle Corporation)
BinaryIn.java
BinaryIn.java
/******************************************************************************
* Compilation: javac BinaryIn.java
* Execution: java BinaryIn input output
* Dependencies: none
*
* This library is for reading binary data from an input stream.
*
* % java BinaryIn https://introcs.cs.princeton.edu/java/cover output
*
******************************************************************************/
import
java
.
io
.
BufferedInputStream
;
import
java
.
io
.
File
;
import
java
.
io
.
FileInputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
InputStream
;
import
java
.
net
.
Socket
;
import
java
.
net
.
URL
;
import
java
.
net
.
URLConnection
;
import
java
.
util
.
NoSuchElementException
;
/**
* Binary input. This class provides methods for reading
* in bits from a binary input stream, either
* one bit at a time (as a {
@code
boolean}),
* 8 bits at a time (as a {
@code
byte} or {
@code
char}),
* 16 bits at a time (as a {
@code
short}),
* 32 bits at a time (as an {
@code
int} or {
@code
float}), or
* 64 bits at a time (as a {
@code
double} or {
@code
long}).
*
* The binary input stream can be from standard input, a filename,
* a URL name, a Socket, or an InputStream.
*
* All primitive types are assumed to be represented using their
* standard Java representations, in big-endian (most significant
* byte first) order.
*
* The client should not intermix calls to {
@code
BinaryIn} with calls
* to {
@code
In}; otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryIn
{
private
static
final
int
EOF
=
–
1
;
// end of file
private
BufferedInputStream
in
;
// the input stream
private
int
buffer
;
// one character buffer
private
int
n
;
// number of bits left in buffer
/**
* Initializes a binary input stream from standard input.
*/
public
BinaryIn
()
{
in
=
new
BufferedInputStream
(
System
.
in
);
fillBuffer
();
}
/**
* Initializes a binary input stream from an {
@code
InputStream}.
*
*
@param
is the {
@code
InputStream} object
*/
public
BinaryIn
(
InputStream
is
)
{
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
/**
* Initializes a binary input stream from a socket.
*
*
@param
socket the socket
*/
public
BinaryIn
(
Socket
socket
)
{
try
{
InputStream
is
=
socket
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
“Could not open ”
+
socket
);
}
}
/**
* Initializes a binary input stream from a URL.
*
*
@param
url the URL
*/
public
BinaryIn
(
URL url
)
{
try
{
URLConnection
site
=
url
.
openConnection
();
InputStream
is
=
site
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
“Could not open ”
+
url
);
}
}
/**
* Initializes a binary input stream from a filename or URL name.
*
*
@param
name the name of the file or URL
*/
public
BinaryIn
(
String
name
)
{
try
{
// first try to read file from local file system
File
file
=
new
File
(
name
);
if
(
file
.
exists
())
{
FileInputStream
fis
=
new
FileInputStream
(
file
);
in
=
new
BufferedInputStream
(
fis
);
fillBuffer
();
return
;
}
// next try for files included in jar
URL url
=
getClass
().
getResource
(
name
);
// or URL from web
if
(
url
==
null
)
{
url
=
new
URL
(
name
);
}
URLConnection
site
=
url
.
openConnection
();
InputStream
is
=
site
.
getInputStream
();
in
=
new
BufferedInputStream
(
is
);
fillBuffer
();
}
catch
(
IOException
ioe
)
{
System
.
err
.
println
(
“Could not open ”
+
name
);
}
}
private
void
fillBuffer
()
{
try
{
buffer
=
in
.
read
();
n
=
8
;
}
catch
(
IOException
e
)
{
System
.
err
.
println
(
“EOF”
);
buffer
=
EOF
;
n
=
–
1
;
}
}
/**
* Returns true if this binary input stream exists.
*
*
@return
{
@code
true} if this binary input stream exists;
* {
@code
false} otherwise
*/
public
boolean
exists
()
{
return
in
!=
null
;
}
/**
* Returns true if this binary input stream is empty.
*
*
@return
{
@code
true} if this binary input stream is empty;
* {
@code
false} otherwise
*/
public
boolean
isEmpty
()
{
return
buffer
==
EOF
;
}
/**
* Reads the next bit of data from this binary input stream and return as a boolean.
*
*
@return
the next bit of data from this binary input stream as a {
@code
boolean}
*
@throws
NoSuchElementException if this binary input stream is empty
*/
public
boolean
readBoolean
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
“Reading from empty input stream”
);
n
—
;
boolean
bit
=
((
buffer
>>
n
)
&
1
)
==
1
;
if
(
n
==
0
)
fillBuffer
();
return
bit
;
}
/**
* Reads the next 8 bits from this binary input stream and return as an 8-bit char.
*
*
@return
the next 8 bits of data from this binary input stream as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than 8 bits available
*/
public
char
readChar
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
“Reading from empty input stream”
);
// special case when aligned byte
if
(
n
==
8
)
{
int
x
=
buffer
;
fillBuffer
();
return
(
char
)
(
x
&
0xff
);
}
// combine last N bits of current buffer with first 8-N bits of new buffer
int
x
=
buffer
;
x
<<=
(
8
-
n
);
int
oldN
=
n
;
fillBuffer
();
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
=
oldN
;
x
|=
(
buffer
>>>
n
);
return
(
char
)
(
x
&
0xff
);
// the above code doesn’t quite work for the last character if N = 8
// because buffer will be -1
}
/**
* Reads the next r bits from this binary input stream and return as an r-bit character.
*
*
@param
r number of bits to read
*
@return
the next {
@code
r} bits of data from this binary input streamt as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 16}
*/
public
char
readChar
(
int
r
)
{
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
“Illegal value of r = ”
+
r
);
// optimize r = 8 case
if
(
r
==
8
)
return
readChar
();
char
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the remaining bytes of data from this binary input stream and return as a string.
*
*
@return
the remaining bytes of data from this binary input stream as a {
@code
String}
*
@throws
NoSuchElementException if this binary input stream is empty or if the number of bits
* available is not a multiple of 8 (byte-aligned)
*/
public
String
readString
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
StringBuilder
sb
=
new
StringBuilder
();
while
(
!
isEmpty
())
{
char
c
=
readChar
();
sb
.
append
(
c
);
}
return
sb
.
toString
();
}
/**
* Reads the next 16 bits from this binary input stream and return as a 16-bit short.
*
*
@return
the next 16 bits of data from this binary input stream as a {
@code
short}
*
@throws
NoSuchElementException if there are fewer than 16 bits available
*/
public
short
readShort
()
{
short
x
=
0
;
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 32 bits from this binary input stream and return as a 32-bit int.
*
*
@return
the next 32 bits of data from this binary input stream as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than 32 bits available
*/
public
int
readInt
()
{
int
x
=
0
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next r bits from this binary input stream return as an r-bit int.
*
*
@param
r number of bits to read
*
@return
the next {
@code
r} bits of data from this binary input stream as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than r bits available
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 32}
*/
public
int
readInt
(
int
r
)
{
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
“Illegal value of r = ”
+
r
);
// optimize r = 32 case
if
(
r
==
32
)
return
readInt
();
int
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the next 64 bits from this binary input stream and return as a 64-bit long.
*
*
@return
the next 64 bits of data from this binary input stream as a {
@code
long}
*
@throws
NoSuchElementException if there are fewer than 64 bits available
*/
public
long
readLong
()
{
long
x
=
0
;
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 64 bits from this binary input stream and return as a 64-bit double.
*
*
@return
the next 64 bits of data from this binary input stream as a {
@code
double}
*
@throws
NoSuchElementException if there are fewer than 64 bits available
*/
public
double
readDouble
()
{
return
Double
.
longBitsToDouble
(
readLong
());
}
/**
* Reads the next 32 bits from this binary input stream and return as a 32-bit float.
*
*
@return
the next 32 bits of data from this binary input stream as a {
@code
float}
*
@throws
NoSuchElementException if there are fewer than 32 bits available
*/
public
float
readFloat
()
{
return
Float
.
intBitsToFloat
(
readInt
());
}
/**
* Reads the next 8 bits from this binary input stream and return as an 8-bit byte.
*
*
@return
the next 8 bits of data from this binary input stream as a {
@code
byte}
*
@throws
NoSuchElementException if there are fewer than 8 bits available
*/
public
byte
readByte
()
{
char
c
=
readChar
();
return
(
byte
)
(
c
&
0xff
);
}
/**
* Unit tests the {
@code
BinaryIn} data type.
* Reads the name of a file or URL (first command-line argument)
* and writes it to a file (second command-line argument).
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
BinaryIn
in
=
new
BinaryIn
(
args
[
0
]);
BinaryOut
out
=
new
BinaryOut
(
args
[
1
]);
// read one 8-bit char at a time
while
(
!
in
.
isEmpty
())
{
char
c
=
in
.
readChar
();
out
.
write
(
c
);
}
out
.
flush
();
}
}
BinaryOut.java
BinaryOut.java
/******************************************************************************
* Compilation: javac BinaryOut.java
* Execution: java BinaryOut
* Dependencies: none
*
* Write binary data to an output stream, either one 1-bit boolean,
* one 8-bit char, one 32-bit int, one 64-bit double, one 32-bit float,
* or one 64-bit long at a time. The output stream can be standard
* output, a file, an OutputStream or a Socket.
*
* The bytes written are not aligned.
*
******************************************************************************/
import
java
.
io
.
BufferedOutputStream
;
import
java
.
io
.
FileOutputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
OutputStream
;
import
java
.
net
.
Socket
;
/**
* Binary output. This class provides methods for converting
* primtive type variables ({
@code
boolean}, {
@code
byte}, {
@code
char},
* {
@code
int}, {
@code
long}, {
@code
float}, and {
@code
double})
* to sequences of bits and writing them to an output stream.
* The output stream can be standard output, a file, an OutputStream or a Socket.
* Uses big-endian (most-significant byte first).
*
* The client must {
@code
flush()} the output stream when finished writing bits.
*
* The client should not intermix calls to {
@code
BinaryOut} with calls
* to {
@code
Out}; otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryOut
{
private
BufferedOutputStream
out
;
// the output stream
private
int
buffer
;
// 8-bit buffer of bits to write out
private
int
n
;
// number of bits remaining in buffer
/**
* Initializes a binary output stream from standard output.
*/
public
BinaryOut
()
{
out
=
new
BufferedOutputStream
(
System
.
out
);
}
/**
* Initializes a binary output stream from an {
@code
OutputStream}.
*
@param
os the {
@code
OutputStream}
*/
public
BinaryOut
(
OutputStream
os
)
{
out
=
new
BufferedOutputStream
(
os
);
}
/**
* Initializes a binary output stream from a file.
*
@param
filename the name of the file
*/
public
BinaryOut
(
String
filename
)
{
try
{
OutputStream
os
=
new
FileOutputStream
(
filename
);
out
=
new
BufferedOutputStream
(
os
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Initializes a binary output stream from a socket.
*
@param
socket the socket
*/
public
BinaryOut
(
Socket
socket
)
{
try
{
OutputStream
os
=
socket
.
getOutputStream
();
out
=
new
BufferedOutputStream
(
os
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to the binary output stream.
*
@param
x the bit
*/
private
void
writeBit
(
boolean
x
)
{
// add bit to buffer
buffer
<<=
1
;
if
(
x
)
buffer
|=
1
;
// if buffer is full (8 bits), write out as a single byte
n
++
;
if
(
n
==
8
)
clearBuffer
();
}
/**
* Writes the 8-bit byte to the binary output stream.
*
@param
x the byte
*/
private
void
writeByte
(
int
x
)
{
assert
x
>=
0
&&
x
<
256
;
// optimized if byte-aligned
if
(
n
==
0
)
{
try
{
out
.
write
(
x
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
return
;
}
// otherwise write one bit at a time
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
8
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
// write out any remaining bits in buffer to the binary output stream, padding with 0s
private
void
clearBuffer
()
{
if
(
n
==
0
)
return
;
if
(
n
>
0
)
buffer
<<=
(
8
-
n
);
try
{
out
.
write
(
buffer
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
n
=
0
;
buffer
=
0
;
}
/**
* Flushes the binary output stream, padding 0s if number of bits written so far
* is not a multiple of 8.
*/
public
void
flush
()
{
clearBuffer
();
try
{
out
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Flushes and closes the binary output stream.
* Once it is closed, bits can no longer be written.
*/
public
void
close
()
{
flush
();
try
{
out
.
close
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to the binary output stream.
*
@param
x the {
@code
boolean} to write
*/
public
void
write
(
boolean
x
)
{
writeBit
(
x
);
}
/**
* Writes the 8-bit byte to the binary output stream.
*
@param
x the {
@code
byte} to write.
*/
public
void
write
(
byte
x
)
{
writeByte
(
x
&
0xff
);
}
/**
* Writes the 32-bit int to the binary output stream.
*
@param
x the {
@code
int} to write
*/
public
void
write
(
int
x
)
{
writeByte
((
x
>>>
24
)
&
0xff
);
writeByte
((
x
>>>
16
)
&
0xff
);
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the r-bit int to the binary output stream.
*
*
@param
x the {
@code
int} to write
*
@param
r the number of relevant bits in the char
*
@throws
IllegalArgumentException unless {
@code
r} is between 1 and 32
*
@throws
IllegalArgumentException unless {
@code
x} is between 0 and 2r – 1
*/
public
void
write
(
int
x
,
int
r
)
{
if
(
r
==
32
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
“Illegal value for r = ”
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the 64-bit double to the binary output stream.
*
@param
x the {
@code
double} to write
*/
public
void
write
(
double
x
)
{
write
(
Double
.
doubleToRawLongBits
(
x
));
}
/**
* Writes the 64-bit long to the binary output stream.
*
@param
x the {
@code
long} to write
*/
public
void
write
(
long
x
)
{
writeByte
((
int
)
((
x
>>>
56
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
48
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
40
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
32
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
24
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
16
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
8
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
0
)
&
0xff
));
}
/**
* Writes the 32-bit float to the binary output stream.
*
@param
x the {
@code
float} to write
*/
public
void
write
(
float
x
)
{
write
(
Float
.
floatToRawIntBits
(
x
));
}
/**
* Write the 16-bit int to the binary output stream.
*
@param
x the {
@code
short} to write.
*/
public
void
write
(
short
x
)
{
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the 8-bit char to the binary output stream.
*
*
@param
x the {
@code
char} to write
*
@throws
IllegalArgumentException unless {
@code
x} is betwen 0 and 255
*/
public
void
write
(
char
x
)
{
if
(
x
<
0
||
x
>=
256
)
throw
new
IllegalArgumentException
(
“Illegal 8-bit char = ”
+
x
);
writeByte
(
x
);
}
/**
* Writes the r-bit char to the binary output stream.
*
*
@param
x the {
@code
char} to write
*
@param
r the number of relevant bits in the char
*
@throws
IllegalArgumentException unless {
@code
r} is between 1 and 16
*
@throws
IllegalArgumentException unless {
@code
x} is between 0 and 2r – 1
*/
public
void
write
(
char
x
,
int
r
)
{
if
(
r
==
8
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
“Illegal value for r = ”
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the string of 8-bit characters to the binary output stream.
*
*
@param
s the {
@code
String} to write
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 255
*/
public
void
write
(
String
s
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
));
}
/**
* Writes the string of r-bit characters to the binary output stream.
*
@param
s the {
@code
String} to write
*
@param
r the number of relevants bits in each character
*
@throws
IllegalArgumentException unless r is between 1 and 16
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 2r – 1
*/
public
void
write
(
String
s
,
int
r
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
),
r
);
}
/**
* Test client. Read bits from standard input and write to the file
* specified on command line.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// create binary output stream to write to file
String
filename
=
args
[
0
];
BinaryOut
out
=
new
BinaryOut
(
filename
);
BinaryIn
in
=
new
BinaryIn
();
// read from standard input and write to file
while
(
!
in
.
isEmpty
())
{
char
c
=
in
.
readChar
();
out
.
write
(
c
);
}
out
.
flush
();
}
}
BinaryStdIn.java
BinaryStdIn.java
/******************************************************************************
* Compilation: javac BinaryStdIn.java
* Execution: java BinaryStdIn < input > output
* Dependencies: none
*
* Supports reading binary data from standard input.
*
* % java BinaryStdIn < input > output
* % diff input output
*
******************************************************************************/
import
java
.
io
.
BufferedInputStream
;
import
java
.
io
.
IOException
;
import
java
.
util
.
NoSuchElementException
;
/**
* Binary standard input. This class provides methods for reading
* in bits from standard input, either one bit at a time (as a {
@code
boolean}),
* 8 bits at a time (as a {
@code
byte} or {
@code
char}),
* 16 bits at a time (as a {
@code
short}), 32 bits at a time
* (as an {
@code
int} or {
@code
float}), or 64 bits at a time (as a
* {
@code
double} or {
@code
long}).
*
* All primitive types are assumed to be represented using their
* standard Java representations, in big-endian (most significant
* byte first) order.
*
* The client should not intermix calls to {
@code
BinaryStdIn} with calls
* to {
@code
StdIn} or {
@code
System.in};
* otherwise unexpected behavior will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryStdIn
{
private
static
final
int
EOF
=
–
1
;
// end of file
private
static
BufferedInputStream
in
;
// input stream
private
static
int
buffer
;
// one character buffer
private
static
int
n
;
// number of bits left in buffer
private
static
boolean
isInitialized
;
// has BinaryStdIn been called for first time?
// don’t instantiate
private
BinaryStdIn
()
{
}
// fill buffer
private
static
void
initialize
()
{
in
=
new
BufferedInputStream
(
System
.
in
);
buffer
=
0
;
n
=
0
;
fillBuffer
();
isInitialized
=
true
;
}
private
static
void
fillBuffer
()
{
try
{
buffer
=
in
.
read
();
n
=
8
;
}
catch
(
IOException
e
)
{
System
.
out
.
println
(
“EOF”
);
buffer
=
EOF
;
n
=
–
1
;
}
}
/**
* Close this input stream and release any associated system resources.
*/
public
static
void
close
()
{
if
(
!
isInitialized
)
initialize
();
try
{
in
.
close
();
isInitialized
=
false
;
}
catch
(
IOException
ioe
)
{
throw
new
IllegalStateException
(
“Could not close BinaryStdIn”
,
ioe
);
}
}
/**
* Returns true if standard input is empty.
*
@return
true if and only if standard input is empty
*/
public
static
boolean
isEmpty
()
{
if
(
!
isInitialized
)
initialize
();
return
buffer
==
EOF
;
}
/**
* Reads the next bit of data from standard input and return as a boolean.
*
*
@return
the next bit of data from standard input as a {
@code
boolean}
*
@throws
NoSuchElementException if standard input is empty
*/
public
static
boolean
readBoolean
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
“Reading from empty input stream”
);
n
—
;
boolean
bit
=
((
buffer
>>
n
)
&
1
)
==
1
;
if
(
n
==
0
)
fillBuffer
();
return
bit
;
}
/**
* Reads the next 8 bits from standard input and return as an 8-bit char.
* Note that {
@code
char} is a 16-bit type;
* to read the next 16 bits as a char, use {
@code
readChar(16)}.
*
*
@return
the next 8 bits of data from standard input as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than 8 bits available on standard input
*/
public
static
char
readChar
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
“Reading from empty input stream”
);
// special case when aligned byte
if
(
n
==
8
)
{
int
x
=
buffer
;
fillBuffer
();
return
(
char
)
(
x
&
0xff
);
}
// combine last n bits of current buffer with first 8-n bits of new buffer
int
x
=
buffer
;
x
<<=
(
8
-
n
);
int
oldN
=
n
;
fillBuffer
();
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
n
=
oldN
;
x
|=
(
buffer
>>>
n
);
return
(
char
)
(
x
&
0xff
);
// the above code doesn’t quite work for the last character if n = 8
// because buffer will be -1, so there is a special case for aligned byte
}
/**
* Reads the next r bits from standard input and return as an r-bit character.
*
*
@param
r number of bits to read.
*
@return
the next r bits of data from standard input as a {
@code
char}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available on standard input
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 16}
*/
public
static
char
readChar
(
int
r
)
{
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
“Illegal value of r = ”
+
r
);
// optimize r = 8 case
if
(
r
==
8
)
return
readChar
();
char
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the remaining bytes of data from standard input and return as a string.
*
*
@return
the remaining bytes of data from standard input as a {
@code
String}
*
@throws
NoSuchElementException if standard input is empty or if the number of bits
* available on standard input is not a multiple of 8 (byte-aligned)
*/
public
static
String
readString
()
{
if
(
isEmpty
())
throw
new
NoSuchElementException
(
"Reading from empty input stream"
);
StringBuilder
sb
=
new
StringBuilder
();
while
(
!
isEmpty
())
{
char
c
=
readChar
();
sb
.
append
(
c
);
}
return
sb
.
toString
();
}
/**
* Reads the next 16 bits from standard input and return as a 16-bit short.
*
*
@return
the next 16 bits of data from standard input as a {
@code
short}
*
@throws
NoSuchElementException if there are fewer than 16 bits available on standard input
*/
public
static
short
readShort
()
{
short
x
=
0
;
for
(
int
i
=
0
;
i
<
2
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 32 bits from standard input and return as a 32-bit int.
*
*
@return
the next 32 bits of data from standard input as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than 32 bits available on standard input
*/
public
static
int
readInt
()
{
int
x
=
0
;
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next r bits from standard input and return as an r-bit int.
*
*
@param
r number of bits to read.
*
@return
the next r bits of data from standard input as a {
@code
int}
*
@throws
NoSuchElementException if there are fewer than {
@code
r} bits available on standard input
*
@throws
IllegalArgumentException unless {
@code
1 <= r <= 32}
*/
public
static
int
readInt
(
int
r
)
{
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
“Illegal value of r = ”
+
r
);
// optimize r = 32 case
if
(
r
==
32
)
return
readInt
();
int
x
=
0
;
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
x
<<=
1
;
boolean
bit
=
readBoolean
();
if
(
bit
)
x
|=
1
;
}
return
x
;
}
/**
* Reads the next 64 bits from standard input and return as a 64-bit long.
*
*
@return
the next 64 bits of data from standard input as a {
@code
long}
*
@throws
NoSuchElementException if there are fewer than 64 bits available on standard input
*/
public
static
long
readLong
()
{
long
x
=
0
;
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
char
c
=
readChar
();
x
<<=
8
;
x
|=
c
;
}
return
x
;
}
/**
* Reads the next 64 bits from standard input and return as a 64-bit double.
*
*
@return
the next 64 bits of data from standard input as a {
@code
double}
*
@throws
NoSuchElementException if there are fewer than 64 bits available on standard input
*/
public
static
double
readDouble
()
{
return
Double
.
longBitsToDouble
(
readLong
());
}
/**
* Reads the next 32 bits from standard input and return as a 32-bit float.
*
*
@return
the next 32 bits of data from standard input as a {
@code
float}
*
@throws
NoSuchElementException if there are fewer than 32 bits available on standard input
*/
public
static
float
readFloat
()
{
return
Float
.
intBitsToFloat
(
readInt
());
}
/**
* Reads the next 8 bits from standard input and return as an 8-bit byte.
*
*
@return
the next 8 bits of data from standard input as a {
@code
byte}
*
@throws
NoSuchElementException if there are fewer than 8 bits available on standard input
*/
public
static
byte
readByte
()
{
char
c
=
readChar
();
return
(
byte
)
(
c
&
0xff
);
}
/**
* Test client. Reads in a binary input file from standard input and writes
* it to standard output.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// read one 8-bit char at a time
while
(
!
BinaryStdIn
.
isEmpty
())
{
char
c
=
BinaryStdIn
.
readChar
();
BinaryStdOut
.
write
(
c
);
}
BinaryStdOut
.
flush
();
}
}
BinaryStdOut.java
BinaryStdOut.java
/******************************************************************************
* Compilation: javac BinaryStdOut.java
* Execution: java BinaryStdOut
* Dependencies: none
*
* Write binary data to standard output, either one 1-bit boolean,
* one 8-bit char, one 32-bit int, one 64-bit double, one 32-bit float,
* or one 64-bit long at a time.
*
* The bytes written are not aligned.
*
******************************************************************************/
import
java
.
io
.
BufferedOutputStream
;
import
java
.
io
.
IOException
;
/**
* Binary standard output. This class provides methods for converting
* primtive type variables ({
@code
boolean}, {
@code
byte}, {
@code
char},
* {
@code
int}, {
@code
long}, {
@code
float}, and {
@code
double})
* to sequences of bits and writing them to standard output.
* Uses big-endian (most-significant byte first).
*
* The client must {
@code
flush()} the output stream when finished writing bits.
*
* The client should not intermix calls to {
@code
BinaryStdOut} with calls
* to {
@code
StdOut} or {
@code
System.out}; otherwise unexpected behavior
* will result.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
BinaryStdOut
{
private
static
BufferedOutputStream
out
;
// output stream (standard output)
private
static
int
buffer
;
// 8-bit buffer of bits to write
private
static
int
n
;
// number of bits remaining in buffer
private
static
boolean
isInitialized
;
// has BinaryStdOut been called for first time?
// don’t instantiate
private
BinaryStdOut
()
{
}
// initialize BinaryStdOut
private
static
void
initialize
()
{
out
=
new
BufferedOutputStream
(
System
.
out
);
buffer
=
0
;
n
=
0
;
isInitialized
=
true
;
}
/**
* Writes the specified bit to standard output.
*/
private
static
void
writeBit
(
boolean
bit
)
{
if
(
!
isInitialized
)
initialize
();
// add bit to buffer
buffer
<<=
1
;
if
(
bit
)
buffer
|=
1
;
// if buffer is full (8 bits), write out as a single byte
n
++
;
if
(
n
==
8
)
clearBuffer
();
}
/**
* Writes the 8-bit byte to standard output.
*/
private
static
void
writeByte
(
int
x
)
{
if
(
!
isInitialized
)
initialize
();
assert
x
>=
0
&&
x
<
256
;
// optimized if byte-aligned
if
(
n
==
0
)
{
try
{
out
.
write
(
x
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
return
;
}
// otherwise write one bit at a time
for
(
int
i
=
0
;
i
<
8
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
8
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
// write out any remaining bits in buffer to standard output, padding with 0s
private
static
void
clearBuffer
()
{
if
(
!
isInitialized
)
initialize
();
if
(
n
==
0
)
return
;
if
(
n
>
0
)
buffer
<<=
(
8
-
n
);
try
{
out
.
write
(
buffer
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
n
=
0
;
buffer
=
0
;
}
/**
* Flushes standard output, padding 0s if number of bits written so far
* is not a multiple of 8.
*/
public
static
void
flush
()
{
clearBuffer
();
try
{
out
.
flush
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Flushes and closes standard output. Once standard output is closed, you can no
* longer write bits to it.
*/
public
static
void
close
()
{
flush
();
try
{
out
.
close
();
isInitialized
=
false
;
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Writes the specified bit to standard output.
*
@param
x the {
@code
boolean} to write.
*/
public
static
void
write
(
boolean
x
)
{
writeBit
(
x
);
}
/**
* Writes the 8-bit byte to standard output.
*
@param
x the {
@code
byte} to write.
*/
public
static
void
write
(
byte
x
)
{
writeByte
(
x
&
0xff
);
}
/**
* Writes the 32-bit int to standard output.
*
@param
x the {
@code
int} to write.
*/
public
static
void
write
(
int
x
)
{
writeByte
((
x
>>>
24
)
&
0xff
);
writeByte
((
x
>>>
16
)
&
0xff
);
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the r-bit int to standard output.
*
@param
x the {
@code
int} to write.
*
@param
r the number of relevant bits in the char.
*
@throws
IllegalArgumentException if {
@code
r} is not between 1 and 32.
*
@throws
IllegalArgumentException if {
@code
x} is not between 0 and 2r – 1.
*/
public
static
void
write
(
int
x
,
int
r
)
{
if
(
r
==
32
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
32
)
throw
new
IllegalArgumentException
(
“Illegal value for r = ”
+
r
);
if
(
x
<
0
||
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the 64-bit double to standard output.
*
@param
x the {
@code
double} to write.
*/
public
static
void
write
(
double
x
)
{
write
(
Double
.
doubleToRawLongBits
(
x
));
}
/**
* Writes the 64-bit long to standard output.
*
@param
x the {
@code
long} to write.
*/
public
static
void
write
(
long
x
)
{
writeByte
((
int
)
((
x
>>>
56
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
48
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
40
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
32
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
24
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
16
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
8
)
&
0xff
));
writeByte
((
int
)
((
x
>>>
0
)
&
0xff
));
}
/**
* Writes the 32-bit float to standard output.
*
@param
x the {
@code
float} to write.
*/
public
static
void
write
(
float
x
)
{
write
(
Float
.
floatToRawIntBits
(
x
));
}
/**
* Writes the 16-bit int to standard output.
*
@param
x the {
@code
short} to write.
*/
public
static
void
write
(
short
x
)
{
writeByte
((
x
>>>
8
)
&
0xff
);
writeByte
((
x
>>>
0
)
&
0xff
);
}
/**
* Writes the 8-bit char to standard output.
*
@param
x the {
@code
char} to write.
*
@throws
IllegalArgumentException if {
@code
x} is not betwen 0 and 255.
*/
public
static
void
write
(
char
x
)
{
if
(
x
<
0
||
x
>=
256
)
throw
new
IllegalArgumentException
(
“Illegal 8-bit char = ”
+
x
);
writeByte
(
x
);
}
/**
* Writes the r-bit char to standard output.
*
@param
x the {
@code
char} to write.
*
@param
r the number of relevant bits in the char.
*
@throws
IllegalArgumentException if {
@code
r} is not between 1 and 16.
*
@throws
IllegalArgumentException if {
@code
x} is not between 0 and 2r – 1.
*/
public
static
void
write
(
char
x
,
int
r
)
{
if
(
r
==
8
)
{
write
(
x
);
return
;
}
if
(
r
<
1
||
r
>
16
)
throw
new
IllegalArgumentException
(
“Illegal value for r = ”
+
r
);
if
(
x
>=
(
1
<<
r
))
throw
new
IllegalArgumentException
(
"Illegal "
+
r
+
"-bit char = "
+
x
);
for
(
int
i
=
0
;
i
<
r
;
i
++
)
{
boolean
bit
=
((
x
>>>
(
r
–
i
–
1
))
&
1
)
==
1
;
writeBit
(
bit
);
}
}
/**
* Writes the string of 8-bit characters to standard output.
*
@param
s the {
@code
String} to write.
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 255.
*/
public
static
void
write
(
String
s
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
));
}
/**
* Writes the string of r-bit characters to standard output.
*
@param
s the {
@code
String} to write.
*
@param
r the number of relevants bits in each character.
*
@throws
IllegalArgumentException if r is not between 1 and 16.
*
@throws
IllegalArgumentException if any character in the string is not
* between 0 and 2r – 1.
*/
public
static
void
write
(
String
s
,
int
r
)
{
for
(
int
i
=
0
;
i
<
s
.
length
();
i
++
)
write
(
s
.
charAt
(
i
),
r
);
}
/**
* Tests the methods in this class.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
int
m
=
Integer
.
parseInt
(
args
[
0
]);
// write n integers to binary standard output
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
BinaryStdOut
.
write
(
i
);
}
BinaryStdOut
.
flush
();
}
}
Draw.java
Draw.java
/******************************************************************************
* Compilation: javac Draw.java
* Execution: java Draw
* Dependencies: none
*
* Drawing library. This class provides a basic capability for creating
* drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, and curves
* in a window on your computer and to save the drawings to a file.
* This is the object-oriented version of standard draw; it supports
* multiple indepedent drawing windows.
*
* Todo
* ----
* - Add support for gradient fill, etc.
*
* Remarks
* -------
* - don't use AffineTransform for rescaling since it inverts
* images and strings
* - careful using setFont in inner loop within an animation -
* it can cause flicker
*
******************************************************************************/
import
java
.
awt
.
BasicStroke
;
import
java
.
awt
.
Color
;
import
java
.
awt
.
Component
;
import
java
.
awt
.
FileDialog
;
import
java
.
awt
.
Font
;
import
java
.
awt
.
FontMetrics
;
import
java
.
awt
.
Graphics
;
import
java
.
awt
.
Graphics2D
;
import
java
.
awt
.
Image
;
import
java
.
awt
.
MediaTracker
;
import
java
.
awt
.
RenderingHints
;
import
java
.
awt
.
Toolkit
;
import
java
.
awt
.
event
.
ActionEvent
;
import
java
.
awt
.
event
.
ActionListener
;
import
java
.
awt
.
event
.
MouseEvent
;
import
java
.
awt
.
event
.
MouseListener
;
import
java
.
awt
.
event
.
MouseMotionListener
;
import
java
.
awt
.
event
.
KeyEvent
;
import
java
.
awt
.
event
.
KeyListener
;
import
java
.
awt
.
geom
.
Arc2D
;
import
java
.
awt
.
geom
.
Ellipse2D
;
import
java
.
awt
.
geom
.
GeneralPath
;
import
java
.
awt
.
geom
.
Line2D
;
import
java
.
awt
.
geom
.
Rectangle2D
;
import
java
.
awt
.
image
.
BufferedImage
;
import
java
.
awt
.
image
.
DirectColorModel
;
import
java
.
awt
.
image
.
WritableRaster
;
import
java
.
io
.
File
;
import
java
.
io
.
IOException
;
import
java
.
net
.
MalformedURLException
;
import
java
.
net
.
URL
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
LinkedList
;
import
java
.
util
.
TreeSet
;
import
javax
.
imageio
.
ImageIO
;
import
javax
.
swing
.
ImageIcon
;
import
javax
.
swing
.
JFrame
;
import
javax
.
swing
.
JLabel
;
import
javax
.
swing
.
JMenu
;
import
javax
.
swing
.
JMenuBar
;
import
javax
.
swing
.
JMenuItem
;
import
javax
.
swing
.
KeyStroke
;
/**
* Draw. This class provides a basic capability for
* creating drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, and curves
* in a window on your computer and to save the drawings to a file.
* This is the object-oriented version of standard draw; it supports
* multiple indepedent drawing windows.
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
Draw
implements
ActionListener
,
MouseListener
,
MouseMotionListener
,
KeyListener
{
/**
* The color black.
*/
public
static
final
Color
BLACK
=
Color
.
BLACK
;
/**
* The color blue.
*/
public
static
final
Color
BLUE
=
Color
.
BLUE
;
/**
* The color cyan.
*/
public
static
final
Color
CYAN
=
Color
.
CYAN
;
/**
* The color dark gray.
*/
public
static
final
Color
DARK_GRAY
=
Color
.
DARK_GRAY
;
/**
* The color gray.
*/
public
static
final
Color
GRAY
=
Color
.
GRAY
;
/**
* The color green.
*/
public
static
final
Color
GREEN
=
Color
.
GREEN
;
/**
* The color light gray.
*/
public
static
final
Color
LIGHT_GRAY
=
Color
.
LIGHT_GRAY
;
/**
* The color magenta.
*/
public
static
final
Color
MAGENTA
=
Color
.
MAGENTA
;
/**
* The color orange.
*/
public
static
final
Color
ORANGE
=
Color
.
ORANGE
;
/**
* The color pink.
*/
public
static
final
Color
PINK
=
Color
.
PINK
;
/**
* The color red.
*/
public
static
final
Color
RED
=
Color
.
RED
;
/**
* The color white.
*/
public
static
final
Color
WHITE
=
Color
.
WHITE
;
/**
* The color yellow.
*/
public
static
final
Color
YELLOW
=
Color
.
YELLOW
;
/**
* Shade of blue used in Introduction to Programming in Java.
* It is Pantone 300U. The RGB values are approximately (9, 90, 166).
*/
public
static
final
Color
BOOK_BLUE
=
new
Color
(
9
,
90
,
166
);
/**
* Shade of light blue used in Introduction to Programming in Java.
* The RGB values are approximately (103, 198, 243).
*/
public
static
final
Color
BOOK_LIGHT_BLUE
=
new
Color
(
103
,
198
,
243
);
/**
* Shade of red used in Algorithms, 4th edition.
* It is Pantone 1805U. The RGB values are approximately (150, 35, 31).
*/
public
static
final
Color
BOOK_RED
=
new
Color
(
150
,
35
,
31
);
/**
* Shade of orange used in Princeton’s identity.
* It is PMS 158. The RGB values are approximately (245, 128, 37).
*/
public
static
final
Color
PRINCETON_ORANGE
=
new
Color
(
245
,
128
,
37
);
// default colors
private
static
final
Color
DEFAULT_PEN_COLOR
=
BLACK
;
private
static
final
Color
DEFAULT_CLEAR_COLOR
=
WHITE
;
// boundary of drawing canvas, 0% border
private
static
final
double
BORDER
=
0.0
;
private
static
final
double
DEFAULT_XMIN
=
0.0
;
private
static
final
double
DEFAULT_XMAX
=
1.0
;
private
static
final
double
DEFAULT_YMIN
=
0.0
;
private
static
final
double
DEFAULT_YMAX
=
1.0
;
// default canvas size is SIZE-by-SIZE
private
static
final
int
DEFAULT_SIZE
=
512
;
// default pen radius
private
static
final
double
DEFAULT_PEN_RADIUS
=
0.002
;
// default font
private
static
final
Font
DEFAULT_FONT
=
new
Font
(
“SansSerif”
,
Font
.
PLAIN
,
16
);
// current pen color
private
Color
penColor
;
// canvas size
private
int
width
=
DEFAULT_SIZE
;
private
int
height
=
DEFAULT_SIZE
;
// current pen radius
private
double
penRadius
;
// show we draw immediately or wait until next show?
private
boolean
defer
=
false
;
private
double
xmin
,
ymin
,
xmax
,
ymax
;
// name of window
private
String
name
=
“Draw”
;
// for synchronization
private
final
Object
mouseLock
=
new
Object
();
private
final
Object
keyLock
=
new
Object
();
// current font
private
Font
font
;
// the JLabel for drawing
private
JLabel
draw
;
// double buffered graphics
private
BufferedImage
offscreenImage
,
onscreenImage
;
private
Graphics2D
offscreen
,
onscreen
;
// the frame for drawing to the screen
private
JFrame
frame
=
new
JFrame
();
// mouse state
private
boolean
isMousePressed
=
false
;
private
double
mouseX
=
0
;
private
double
mouseY
=
0
;
// keyboard state
private
final
LinkedList
<
Character
>
keysTyped
=
new
LinkedList
<
Character
>
();
private
final
TreeSet
<
Integer
>
keysDown
=
new
TreeSet
<
Integer
>
();
// event-based listeners
private
final
ArrayList
<
DrawListener
>
listeners
=
new
ArrayList
<
DrawListener
>
();
/**
* Initializes an empty drawing object with the given name.
*
*
@param
name the title of the drawing window.
*/
public
Draw
(
String
name
)
{
this
.
name
=
name
;
init
();
}
/**
* Initializes an empty drawing object.
*/
public
Draw
()
{
init
();
}
private
void
init
()
{
if
(
frame
!=
null
)
frame
.
setVisible
(
false
);
frame
=
new
JFrame
();
offscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
onscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
offscreen
=
offscreenImage
.
createGraphics
();
onscreen
=
onscreenImage
.
createGraphics
();
offscreen
.
scale
(
2.0
,
2.0
);
// since we made it 2x as big
setXscale
();
setYscale
();
offscreen
.
setColor
(
DEFAULT_CLEAR_COLOR
);
offscreen
.
fillRect
(
0
,
0
,
width
,
height
);
setPenColor
();
setPenRadius
();
setFont
();
clear
();
// add antialiasing
RenderingHints
hints
=
new
RenderingHints
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
hints
.
put
(
RenderingHints
.
KEY_RENDERING
,
RenderingHints
.
VALUE_RENDER_QUALITY
);
offscreen
.
addRenderingHints
(
hints
);
// frame stuff
RetinaImageIcon
icon
=
new
RetinaImageIcon
(
onscreenImage
);
draw
=
new
JLabel
(
icon
);
draw
.
addMouseListener
(
this
);
draw
.
addMouseMotionListener
(
this
);
frame
.
setContentPane
(
draw
);
frame
.
addKeyListener
(
this
);
// JLabel cannot get keyboard focus
frame
.
setResizable
(
false
);
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // closes all windows
frame
.
setDefaultCloseOperation
(
JFrame
.
DISPOSE_ON_CLOSE
);
// closes only current window
frame
.
setFocusTraversalKeysEnabled
(
false
);
// to recognize VK_TAB with isKeyPressed()
frame
.
setTitle
(
name
);
frame
.
setJMenuBar
(
createMenuBar
());
frame
.
pack
();
frame
.
requestFocusInWindow
();
frame
.
setVisible
(
true
);
}
/**
* Sets the upper-left hand corner of the drawing window to be (x, y), where (0, 0) is upper left.
*
*
@param
x the number of pixels from the left
*
@param
y the number of pixels from the top
*
@throws
IllegalArgumentException if the width or height is 0 or negative
*/
public
void
setLocationOnScreen
(
int
x
,
int
y
)
{
if
(
x
<=
0
||
y
<=
0
)
throw
new
IllegalArgumentException
();
frame
.
setLocation
(
x
,
y
);
}
/**
* Sets the default close operation.
*
*
@param
value the value, typically {
@code
JFrame.EXIT_ON_CLOSE}
* (close all windows) or {
@code
JFrame.DISPOSE_ON_CLOSE}
* (close current window)
*/
public
void
setDefaultCloseOperation
(
int
value
)
{
frame
.
setDefaultCloseOperation
(
value
);
}
/**
* Sets the canvas (drawing area) to be width-by-height pixels.
* This also erases the current drawing and resets the coordinate system, pen radius,
* pen color, and font back to their default values.
* Ordinarly, this method is called once, at the very beginning of a program.
*
*
@param
canvasWidth the width as a number of pixels
*
@param
canvasHeight the height as a number of pixels
*
@throws
IllegalArgumentException unless both {
@code
canvasWidth}
* and {
@code
canvasHeight} are positive
*/
public
void
setCanvasSize
(
int
canvasWidth
,
int
canvasHeight
)
{
if
(
canvasWidth
<
1
||
canvasHeight
<
1
)
{
throw
new
IllegalArgumentException
(
"width and height must be positive"
);
}
width
=
canvasWidth
;
height
=
canvasHeight
;
init
();
}
// create the menu bar (changed to private)
private
JMenuBar
createMenuBar
()
{
JMenuBar
menuBar
=
new
JMenuBar
();
JMenu
menu
=
new
JMenu
(
"File"
);
menuBar
.
add
(
menu
);
JMenuItem
menuItem1
=
new
JMenuItem
(
" Save... "
);
menuItem1
.
addActionListener
(
this
);
// Java 10+: replace getMenuShortcutKeyMask() with getMenuShortcutKeyMaskEx()
menuItem1
.
setAccelerator
(
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_S
,
Toolkit
.
getDefaultToolkit
().
getMenuShortcutKeyMask
()));
menu
.
add
(
menuItem1
);
return
menuBar
;
}
/***************************************************************************
* User and screen coordinate systems.
***************************************************************************/
// throw an IllegalArgumentException if x is NaN or infinite
private
static
void
validate
(
double
x
,
String
name
)
{
if
(
Double
.
isNaN
(
x
))
throw
new
IllegalArgumentException
(
name
+
" is NaN"
);
if
(
Double
.
isInfinite
(
x
))
throw
new
IllegalArgumentException
(
name
+
" is infinite"
);
}
// throw an IllegalArgumentException if s is null
private
static
void
validateNonnegative
(
double
x
,
String
name
)
{
if
(
x
<
0
)
throw
new
IllegalArgumentException
(
name
+
" negative"
);
}
// throw an IllegalArgumentException if s is null
private
static
void
validateNotNull
(
Object
x
,
String
name
)
{
if
(
x
==
null
)
throw
new
IllegalArgumentException
(
name
+
" is null"
);
}
/**
* Sets the x-scale to be the default (between 0.0 and 1.0).
*/
public
void
setXscale
()
{
setXscale
(
DEFAULT_XMIN
,
DEFAULT_XMAX
);
}
/**
* Sets the y-scale to be the default (between 0.0 and 1.0).
*/
public
void
setYscale
()
{
setYscale
(
DEFAULT_YMIN
,
DEFAULT_YMAX
);
}
/**
* Sets the x-scale.
*
*
@param
min the minimum value of the x-scale
*
@param
max the maximum value of the x-scale
*
@throws
IllegalArgumentException if {
@code
(max == min)}
*
@throws
IllegalArgumentException if either {
@code
min} or {
@code
max} is either NaN or infinite
*/
public
void
setXscale
(
double
min
,
double
max
)
{
validate
(
min
,
"min"
);
validate
(
max
,
"max"
);
double
size
=
max
-
min
;
if
(
size
==
0.0
)
throw
new
IllegalArgumentException
(
"the min and max are the same"
);
xmin
=
min
-
BORDER
*
size
;
xmax
=
max
+
BORDER
*
size
;
}
/**
* Sets the y-scale.
*
*
@param
min the minimum value of the y-scale
*
@param
max the maximum value of the y-scale
*
@throws
IllegalArgumentException if {
@code
(max == min)}
*
@throws
IllegalArgumentException if either {
@code
min} or {
@code
max} is either NaN or infinite
*/
public
void
setYscale
(
double
min
,
double
max
)
{
validate
(
min
,
"min"
);
validate
(
max
,
"max"
);
double
size
=
max
-
min
;
if
(
size
==
0.0
)
throw
new
IllegalArgumentException
(
"the min and max are the same"
);
ymin
=
min
-
BORDER
*
size
;
ymax
=
max
+
BORDER
*
size
;
}
// helper functions that scale from user coordinates to screen coordinates and back
private
double
scaleX
(
double
x
)
{
return
width
*
(
x
-
xmin
)
/
(
xmax
-
xmin
);
}
private
double
scaleY
(
double
y
)
{
return
height
*
(
ymax
-
y
)
/
(
ymax
-
ymin
);
}
private
double
factorX
(
double
w
)
{
return
w
*
width
/
Math
.
abs
(
xmax
-
xmin
);
}
private
double
factorY
(
double
h
)
{
return
h
*
height
/
Math
.
abs
(
ymax
-
ymin
);
}
private
double
userX
(
double
x
)
{
return
xmin
+
x
*
(
xmax
-
xmin
)
/
width
;
}
private
double
userY
(
double
y
)
{
return
ymax
-
y
*
(
ymax
-
ymin
)
/
height
;
}
/**
* Clears the screen to the default color (white).
*/
public
void
clear
()
{
clear
(
DEFAULT_CLEAR_COLOR
);
}
/**
* Clears the screen to the given color.
*
*
@param
color the color to make the background
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
void
clear
(
Color
color
)
{
validateNotNull
(
color
,
"color"
);
offscreen
.
setColor
(
color
);
offscreen
.
fillRect
(
0
,
0
,
width
,
height
);
offscreen
.
setColor
(
penColor
);
draw
();
}
/**
* Gets the current pen radius.
*
*
@return
the current pen radius
*/
public
double
getPenRadius
()
{
return
penRadius
;
}
/**
* Sets the pen size to the default (.002).
*/
public
void
setPenRadius
()
{
setPenRadius
(
DEFAULT_PEN_RADIUS
);
}
/**
* Sets the radius of the pen to the given size.
*
*
@param
radius the radius of the pen
*
@throws
IllegalArgumentException if {
@code
radius} is negative, NaN, or infinite
*/
public
void
setPenRadius
(
double
radius
)
{
validate
(
radius
,
"pen radius"
);
validateNonnegative
(
radius
,
"pen radius"
);
penRadius
=
radius
*
DEFAULT_SIZE
;
BasicStroke
stroke
=
new
BasicStroke
((
float
)
penRadius
,
BasicStroke
.
CAP_ROUND
,
BasicStroke
.
JOIN_ROUND
);
// BasicStroke stroke = new BasicStroke((float) penRadius);
offscreen
.
setStroke
(
stroke
);
}
/**
* Gets the current pen color.
*
*
@return
the current pen color
*/
public
Color
getPenColor
()
{
return
penColor
;
}
/**
* Sets the pen color to the default color (black).
*/
public
void
setPenColor
()
{
setPenColor
(
DEFAULT_PEN_COLOR
);
}
/**
* Sets the pen color to the given color.
*
*
@param
color the color to make the pen
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
void
setPenColor
(
Color
color
)
{
validateNotNull
(
color
,
"color"
);
penColor
=
color
;
offscreen
.
setColor
(
penColor
);
}
/**
* Sets the pen color to the given RGB color.
*
*
@param
red the amount of red (between 0 and 255)
*
@param
green the amount of green (between 0 and 255)
*
@param
blue the amount of blue (between 0 and 255)
*
@throws
IllegalArgumentException if {
@code
red}, {
@code
green},
* or {
@code
blue} is outside its prescribed range
*/
public
void
setPenColor
(
int
red
,
int
green
,
int
blue
)
{
if
(
red
<
0
||
red
>=
256
)
throw
new
IllegalArgumentException
(
“red must be between 0 and 255”
);
if
(
green
<
0
||
green
>=
256
)
throw
new
IllegalArgumentException
(
“green must be between 0 and 255”
);
if
(
blue
<
0
||
blue
>=
256
)
throw
new
IllegalArgumentException
(
“blue must be between 0 and 255”
);
setPenColor
(
new
Color
(
red
,
green
,
blue
));
}
/**
* Turns on xor mode.
*/
public
void
xorOn
()
{
offscreen
.
setXORMode
(
DEFAULT_CLEAR_COLOR
);
}
/**
* Turns off xor mode.
*/
public
void
xorOff
()
{
offscreen
.
setPaintMode
();
}
/**
* Gets the current {
@code
JLabel} for use in some other GUI.
*
*
@return
the current {
@code
JLabel}
*/
public
JLabel
getJLabel
()
{
return
draw
;
}
/**
* Gets the current font.
*
*
@return
the current font
*/
public
Font
getFont
()
{
return
font
;
}
/**
* Sets the font to the default font (sans serif, 16 point).
*/
public
void
setFont
()
{
setFont
(
DEFAULT_FONT
);
}
/**
* Sets the font to the given value.
*
*
@param
font the font
*
@throws
IllegalArgumentException if {
@code
font} is {
@code
null}
*/
public
void
setFont
(
Font
font
)
{
validateNotNull
(
font
,
“font”
);
this
.
font
=
font
;
}
/***************************************************************************
* Drawing geometric shapes.
***************************************************************************/
/**
* Draws a line from (x0, y0) to (x1, y1).
*
*
@param
x0 the x-coordinate of the starting point
*
@param
y0 the y-coordinate of the starting point
*
@param
x1 the x-coordinate of the destination point
*
@param
y1 the y-coordinate of the destination point
*
@throws
IllegalArgumentException if any coordinate is either NaN or infinite
*/
public
void
line
(
double
x0
,
double
y0
,
double
x1
,
double
y1
)
{
validate
(
x0
,
“x0”
);
validate
(
y0
,
“y0”
);
validate
(
x1
,
“x1”
);
validate
(
y1
,
“y1”
);
offscreen
.
draw
(
new
Line2D
.
Double
(
scaleX
(
x0
),
scaleY
(
y0
),
scaleX
(
x1
),
scaleY
(
y1
)));
draw
();
}
/**
* Draws one pixel at (x, y).
*
*
@param
x the x-coordinate of the pixel
*
@param
y the y-coordinate of the pixel
*
@throws
IllegalArgumentException if {
@code
x} or {
@code
y} is either NaN or infinite
*/
private
void
pixel
(
double
x
,
double
y
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
offscreen
.
fillRect
((
int
)
Math
.
round
(
scaleX
(
x
)),
(
int
)
Math
.
round
(
scaleY
(
y
)),
1
,
1
);
}
/**
* Draws a point at (x, y).
*
*
@param
x the x-coordinate of the point
*
@param
y the y-coordinate of the point
*
@throws
IllegalArgumentException if either {
@code
x} or {
@code
y} is either NaN or infinite
*/
public
void
point
(
double
x
,
double
y
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
r
=
penRadius
;
// double ws = factorX(2*r);
// double hs = factorY(2*r);
// if (ws <= 1 && hs <= 1) pixel(x, y);
if
(
r
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
r
/
2
,
ys
-
r
/
2
,
r
,
r
));
draw
();
}
/**
* Draws a circle of the specified radius, centered at (x, y).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
void
circle
(
double
x
,
double
y
,
double
radius
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“radius”
);
validateNonnegative
(
radius
,
“radius”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
radius
);
double
hs
=
factorY
(
2
*
radius
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
draw
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a filled circle of the specified radius, centered at (x, y).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
void
filledCircle
(
double
x
,
double
y
,
double
radius
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“radius”
);
validateNonnegative
(
radius
,
“radius”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
radius
);
double
hs
=
factorY
(
2
*
radius
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws an ellipse with the specified semimajor and semiminor axes,
* centered at (x, y).
*
*
@param
x the x-coordinate of the center of the ellipse
*
@param
y the y-coordinate of the center of the ellipse
*
@param
semiMajorAxis is the semimajor axis of the ellipse
*
@param
semiMinorAxis is the semiminor axis of the ellipse
*
@throws
IllegalArgumentException if either {
@code
semiMajorAxis}
* or {
@code
semiMinorAxis} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
void
ellipse
(
double
x
,
double
y
,
double
semiMajorAxis
,
double
semiMinorAxis
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
semiMajorAxis
,
“semimajor axis”
);
validate
(
semiMinorAxis
,
“semiminor axis”
);
validateNonnegative
(
semiMajorAxis
,
“semimajor axis”
);
validateNonnegative
(
semiMinorAxis
,
“semiminor axis”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
semiMajorAxis
);
double
hs
=
factorY
(
2
*
semiMinorAxis
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
draw
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a filled ellipse with the specified semimajor and semiminor axes,
* centered at (x, y).
*
*
@param
x the x-coordinate of the center of the ellipse
*
@param
y the y-coordinate of the center of the ellipse
*
@param
semiMajorAxis is the semimajor axis of the ellipse
*
@param
semiMinorAxis is the semiminor axis of the ellipse
*
@throws
IllegalArgumentException if either {
@code
semiMajorAxis}
* or {
@code
semiMinorAxis} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
void
filledEllipse
(
double
x
,
double
y
,
double
semiMajorAxis
,
double
semiMinorAxis
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
semiMajorAxis
,
“semimajor axis”
);
validate
(
semiMinorAxis
,
“semiminor axis”
);
validateNonnegative
(
semiMajorAxis
,
“semimajor axis”
);
validateNonnegative
(
semiMinorAxis
,
“semiminor axis”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
semiMajorAxis
);
double
hs
=
factorY
(
2
*
semiMinorAxis
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a circular arc of the specified radius,
* centered at (x, y), from angle1 to angle2 (in degrees).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@param
angle1 the starting angle. 0 would mean an arc beginning at 3 o’clock.
*
@param
angle2 the angle at the end of the arc. For example, if
* you want a 90 degree arc, then angle2 should be angle1 + 90.
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
void
arc
(
double
x
,
double
y
,
double
radius
,
double
angle1
,
double
angle2
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“arc radius”
);
validate
(
angle1
,
“angle1”
);
validate
(
angle2
,
“angle2”
);
validateNonnegative
(
radius
,
“arc radius”
);
while
(
angle2
<
angle1
)
angle2
+=
360
;
double
xs
=
scaleX
(
x
);
double ys = scaleY(y);
double ws = factorX(2*radius);
double hs = factorY(2*radius);
if (ws <= 1 && hs <= 1) pixel(x, y);
else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN));
draw();
}
/** * Draws a square of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the square * @param y the y-coordinate of the center of the square * @param halfLength one half the length of any side of the square * @throws IllegalArgumentException if {@code halfLength} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public void square(double x, double y, double halfLength) {
validate(x, “x”);
validate(y, “y”);
validate(halfLength, “halfLength”);
validateNonnegative(halfLength, “half length”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfLength);
double hs = factorY(2*halfLength);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a square of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the square * @param y the y-coordinate of the center of the square * @param halfLength one half the length of any side of the square * @throws IllegalArgumentException if {@code halfLength} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public void filledSquare(double x, double y, double halfLength) {
validate(x, “x”);
validate(y, “y”);
validate(halfLength, “halfLength”);
validateNonnegative(halfLength, “half length”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfLength);
double hs = factorY(2*halfLength);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a rectangle of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the rectangle * @param y the y-coordinate of the center of the rectangle * @param halfWidth one half the width of the rectangle * @param halfHeight one half the height of the rectangle * @throws IllegalArgumentException if either {@code halfWidth} or {@code halfHeight} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public void rectangle(double x, double y, double halfWidth, double halfHeight) {
validate(x, “x”);
validate(y, “y”);
validate(halfWidth, “halfWidth”);
validate(halfHeight, “halfHeight”);
validateNonnegative(halfWidth, “half width”);
validateNonnegative(halfHeight, “half height”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfWidth);
double hs = factorY(2*halfHeight);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a filled rectangle of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the rectangle * @param y the y-coordinate of the center of the rectangle * @param halfWidth one half the width of the rectangle * @param halfHeight one half the height of the rectangle * @throws IllegalArgumentException if either {@code halfWidth} or {@code halfHeight} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public void filledRectangle(double x, double y, double halfWidth, double halfHeight) {
validate(x, “x”);
validate(y, “y”);
validate(halfWidth, “halfWidth”);
validate(halfHeight, “halfHeight”);
validateNonnegative(halfWidth, “half width”);
validateNonnegative(halfHeight, “half height”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfWidth);
double hs = factorY(2*halfHeight);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a polygon with the vertices * (x0, y0), * (x1, y1), …, * (xn–1, yn–1). * * @param x an array of all the x-coordinates of the polygon * @param y an array of all the y-coordinates of the polygon * @throws IllegalArgumentException unless {@code x[]} and {@code y[]} * are of the same length * @throws IllegalArgumentException if any coordinate is either NaN or infinite * @throws IllegalArgumentException if either {@code x[]} or {@code y[]} is {@code null} */
public void polygon(double[] x, double[] y) {
validateNotNull(x, “x-coordinate array”);
validateNotNull(y, “y-coordinate array”);
for (int i = 0; i < x.length; i++) validate(x[i], "x[" + i + "]"); for (int i = 0; i < y.length; i++) validate(y[i], "y[" + i + "]"); int n1 = x.length; int n2 = y.length; if (n1 != n2) throw new IllegalArgumentException("arrays must be of the same length"); int n = n1; if (n == 0) return; GeneralPath path = new GeneralPath(); path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); for (int i = 0; i < n; i++) path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); path.closePath(); offscreen.draw(path); draw(); } /** * Draws a filled polygon with the vertices * (x0, y0), * (x1, y1), …, * (xn–1, yn–1). * * @param x an array of all the x-coordinates of the polygon * @param y an array of all the y-coordinates of the polygon * @throws IllegalArgumentException unless {@code x[]} and {@code y[]} * are of the same length * @throws IllegalArgumentException if any coordinate is either NaN or infinite * @throws IllegalArgumentException if either {@code x[]} or {@code y[]} is {@code null} */
public void filledPolygon(double[] x, double[] y) {
validateNotNull(x, “x-coordinate array”);
validateNotNull(y, “y-coordinate array”);
for (int i = 0; i < x.length; i++) validate(x[i], "x[" + i + "]"); for (int i = 0; i < y.length; i++) validate(y[i], "y[" + i + "]"); int n1 = x.length; int n2 = y.length; if (n1 != n2) throw new IllegalArgumentException("arrays must be of the same length"); int n = n1; if (n == 0) return; GeneralPath path = new GeneralPath(); path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); for (int i = 0; i < n; i++) path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); path.closePath(); offscreen.fill(path); draw(); } /*************************************************************************** * Drawing images. ***************************************************************************/ // get an image from the given filename private static Image getImage(String filename) { if (filename == null) throw new IllegalArgumentException(); // to read from file ImageIcon icon = new ImageIcon(filename); // try to read from URL if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { try { URL url = new URL(filename); icon = new ImageIcon(url); } catch (MalformedURLException e) { /* not a url */ } } // in case file is inside a .jar (classpath relative to StdDraw) if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { URL url = StdDraw.class.getResource(filename); if (url != null) icon = new ImageIcon(url); } // in case file is inside a .jar (classpath relative to root of jar) if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { URL url = Draw.class.getResource("/" + filename); if (url == null) throw new IllegalArgumentException("image " + filename + " not found"); icon = new ImageIcon(url); } return icon.getImage(); } /** * Draws the specified image centered at (x, y). * The supported image formats are JPEG, PNG, and GIF. * As an optimization, the picture is cached, so there is no performance * penalty for redrawing the same image multiple times (e.g., in an animation). * However, if you change the picture file after drawing it, subsequent * calls will draw the original picture. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if either {@code x} or {@code y} is either NaN or infinite */
public void picture(double x, double y, String filename) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(filename, “filename”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
int ws = image.getWidth(null);
int hs = image.getHeight(null);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); draw(); } /** * Draws the specified image centered at (x, y), * rotated given number of degrees. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if {@code x}, {@code y}, {@code degrees} is NaN or infinite * @throws IllegalArgumentException if {@code filename} is {@code null} */
public void picture(double x, double y, String filename, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(degrees, “degrees”);
validateNotNull(filename, “filename”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
int ws = image.getWidth(null);
int hs = image.getHeight(null);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); offscreen.rotate(Math.toRadians(-degrees), xs, ys); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); offscreen.rotate(Math.toRadians(+degrees), xs, ys); draw(); } /** * Draws the specified image centered at (x, y), * rescaled to the specified bounding box. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param scaledWidth the width of the scaled image (in screen coordinates) * @param scaledHeight the height of the scaled image (in screen coordinates) * @throws IllegalArgumentException if either {@code scaledWidth} * or {@code scaledHeight} is negative * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite * @throws IllegalArgumentException if {@code filename} is {@code null} */
public void picture(double x, double y, String filename, double scaledWidth, double scaledHeight) {
validate(x, “x”);
validate(y, “y”);
validate(scaledWidth, “scaled width”);
validate(scaledHeight, “scaled height”);
validateNotNull(filename, “filename”);
validateNonnegative(scaledWidth, “scaled width”);
validateNonnegative(scaledHeight, “scaled height”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(scaledWidth);
double hs = factorY(scaledHeight);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); if (ws <= 1 && hs <= 1) pixel(x, y); else { offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), (int) Math.round(ws), (int) Math.round(hs), null); } draw(); } /** * Draws the specified image centered at (x, y), rotated * given number of degrees, and rescaled to the specified bounding box. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param scaledWidth the width of the scaled image (in screen coordinates) * @param scaledHeight the height of the scaled image (in screen coordinates) * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if either {@code scaledWidth} * or {@code scaledHeight} is negative * @throws IllegalArgumentException if the image filename is invalid */
public void picture(double x, double y, String filename, double scaledWidth, double scaledHeight, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(scaledWidth, “scaled width”);
validate(scaledHeight, “scaled height”);
validate(degrees, “degrees”);
validateNotNull(filename, “filename”);
validateNonnegative(scaledWidth, “scaled width”);
validateNonnegative(scaledHeight, “scaled height”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(scaledWidth);
double hs = factorY(scaledHeight);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); if (ws <= 1 && hs <= 1) pixel(x, y); offscreen.rotate(Math.toRadians(-degrees), xs, ys); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), (int) Math.round(ws), (int) Math.round(hs), null); offscreen.rotate(Math.toRadians(+degrees), xs, ys); draw(); } /*************************************************************************** * Drawing text. ***************************************************************************/ /** * Writes the given text string in the current font, centered at (x, y). * * @param x the center x-coordinate of the text * @param y the center y-coordinate of the text * @param text the text to write * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public void text(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
int ws = metrics.stringWidth(text);
int hs = metrics.getDescent();
offscreen.drawString(text, (float) (xs – ws/2.0), (float) (ys + hs));
draw();
}
/** * Writes the given text string in the current font, centered at (x, y) and * rotated by the specified number of degrees. * @param x the center x-coordinate of the text * @param y the center y-coordinate of the text * @param text the text to write * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x}, {@code y}, or {@code degrees} is either NaN or infinite */
public void text(double x, double y, String text, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(degrees, “degrees”);
validateNotNull(text, “text”);
double xs = scaleX(x);
double ys = scaleY(y);
offscreen.rotate(Math.toRadians(-degrees), xs, ys);
text(x, y, text);
offscreen.rotate(Math.toRadians(+degrees), xs, ys);
}
/** * Writes the given text string in the current font, left-aligned at (x, y). * @param x the x-coordinate of the text * @param y the y-coordinate of the text * @param text the text * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public void textLeft(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
// int ws = metrics.stringWidth(text); int hs = metrics.getDescent();
offscreen.drawString(text, (float) xs, (float) (ys + hs));
draw();
}
/** * Writes the given text string in the current font, right-aligned at (x, y). * * @param x the x-coordinate of the text * @param y the y-coordinate of the text * @param text the text to write * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public void textRight(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
int ws = metrics.stringWidth(text);
int hs = metrics.getDescent();
offscreen.drawString(text, (float) (xs – ws), (float) (ys + hs));
draw();
}
/** * Copies the offscreen buffer to the onscreen buffer, pauses for t milliseconds * and enables double buffering. * @param t number of milliseconds * @deprecated replaced by {@link #enableDoubleBuffering()}, {@link #show()}, and {@link #pause(int t)} */
@Deprecated
public void show(int t) {
show();
pause(t);
enableDoubleBuffering();
}
/** * Pause for t milliseconds. This method is intended to support computer animations. * @param t number of milliseconds */
public void pause(int t) {
try {
Thread.sleep(t);
}
catch (InterruptedException e) {
System.out.println(“Error sleeping”);
}
}
/** * Copies offscreen buffer to onscreen buffer. There is no reason to call * this method unless double buffering is enabled. */
public void show() {
onscreen.drawImage(offscreenImage, 0, 0, null);
frame.repaint();
}
// draw onscreen if defer is false private void draw() {
if (!defer) show();
}
/** * Enable double buffering. All subsequent calls to * drawing methods such as {@code line()}, {@code circle()}, * and {@code square()} will be deferred until the next call * to show(). Useful for animations. */
public void enableDoubleBuffering() {
defer = true;
}
/** * Disable double buffering. All subsequent calls to * drawing methods such as {@code line()}, {@code circle()}, * and {@code square()} will be displayed on screen when called. * This is the default. */
public void disableDoubleBuffering() {
defer = false;
}
/** * Saves the drawing to using the specified filename. * The supported image formats are JPEG and PNG; * the filename suffix must be {@code } or {@code }. * * @param filename the name of the file with one of the required suffixes * @throws IllegalArgumentException if {@code filename} is {@code null} */
public void save(String filename) {
validateNotNull(filename, “filename”);
File file = new File(filename);
String suffix = filename.substring(filename.lastIndexOf(‘.’) + 1);
// png files if (“png”.equalsIgnoreCase(suffix)) {
try {
ImageIO.write(offscreenImage, suffix, file);
}
catch (IOException e) {
e.printStackTrace();
}
}
// need to change from ARGB to RGB for jpeg // reference: http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727 else if (“jpg”.equalsIgnoreCase(suffix)) {
WritableRaster raster = offscreenImage.getRaster();
WritableRaster newRaster;
newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});
DirectColorModel cm = (DirectColorModel) offscreenImage.getColorModel();
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
cm.getRedMask(),
cm.getGreenMask(),
cm.getBlueMask());
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
try {
ImageIO.write(rgbBuffer, suffix, file);
}
catch (IOException e) {
e.printStackTrace();
}
}
else {
System.out.println(“Invalid image file type: ” + suffix);
}
}
/** * This method cannot be called directly. */
@Override
public void actionPerformed(ActionEvent e) {
FileDialog chooser = new FileDialog(frame, “Use a or extension”, FileDialog.SAVE);
chooser.setVisible(true);
String filename = chooser.getFile();
if (filename != null) {
save(chooser.getDirectory() + File.separator + chooser.getFile());
}
}
/*************************************************************************** * Event-based interactions. ***************************************************************************/
/** * Adds a {@link DrawListener} to listen to keyboard and mouse events. * * @param listener the {\tt DrawListener} argument */
public void addListener(DrawListener listener) {
// ensure there is a window for listenting to events show();
listeners.add(listener);
frame.addKeyListener(this);
frame.addMouseListener(this);
frame.addMouseMotionListener(this);
frame.setFocusable(true); }
/*************************************************************************** * Mouse interactions. ***************************************************************************/
/** * Returns true if the mouse is being pressed. * * @return {@code true} if the mouse is being pressed; * {@code false} otherwise */
public boolean isMousePressed() {
synchronized (mouseLock) {
return isMousePressed;
}
}
/** * Returns true if the mouse is being pressed. * * @return {@code true} if the mouse is being pressed; * {@code false} otherwise * @deprecated replaced by {@link #isMousePressed()} */
@Deprecated
public boolean mousePressed() {
synchronized (mouseLock) {
return isMousePressed;
}
}
/** * Returns the x-coordinate of the mouse. * @return the x-coordinate of the mouse */
public double mouseX() {
synchronized (mouseLock) {
return mouseX;
}
}
/** * Returns the y-coordinate of the mouse. * * @return the y-coordinate of the mouse */
public double mouseY() {
synchronized (mouseLock) {
return mouseY;
}
}
/** * This method cannot be called directly. */
@Override
public void mouseEntered(MouseEvent e) {
// this body is intentionally left empty }
/** * This method cannot be called directly. */
@Override
public void mouseExited(MouseEvent e) {
// this body is intentionally left empty }
/** * This method cannot be called directly. */
@Override
public void mousePressed(MouseEvent e) {
synchronized (mouseLock) {
mouseX = userX(e.getX());
mouseY = userY(e.getY());
isMousePressed = true;
}
if (e.getButton() == MouseEvent.BUTTON1) {
for (DrawListener listener : listeners)
listener.mousePressed(userX(e.getX()), userY(e.getY()));
}
}
/** * This method cannot be called directly. */
@Override
public void mouseReleased(MouseEvent e) {
synchronized (mouseLock) {
isMousePressed = false;
}
if (e.getButton() == MouseEvent.BUTTON1) {
for (DrawListener listener : listeners)
listener.mouseReleased(userX(e.getX()), userY(e.getY()));
}
}
/** * This method cannot be called directly. */
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
for (DrawListener listener : listeners)
listener.mouseClicked(userX(e.getX()), userY(e.getY()));
}
}
/** * This method cannot be called directly. */
@Override
public void mouseDragged(MouseEvent e) {
synchronized (mouseLock) {
mouseX = userX(e.getX());
mouseY = userY(e.getY());
}
// doesn’t seem to work if a button is specified for (DrawListener listener : listeners)
listener.mouseDragged(userX(e.getX()), userY(e.getY()));
}
/** * This method cannot be called directly. */
@Override
public void mouseMoved(MouseEvent e) {
synchronized (mouseLock) {
mouseX = userX(e.getX());
mouseY = userY(e.getY());
}
}
/*************************************************************************** * Keyboard interactions. ***************************************************************************/
/** * Returns true if the user has typed a key. * * @return {@code true} if the user has typed a key; {@code false} otherwise */
public boolean hasNextKeyTyped() {
synchronized (keyLock) {
return !keysTyped.isEmpty();
}
}
/** * The next key typed by the user. * * @return the next key typed by the user */
public char nextKeyTyped() {
synchronized (keyLock) {
return keysTyped.removeLast();
}
}
/** * Returns true if the keycode is being pressed. *
* This method takes as an argument the keycode (corresponding to a physical key). * It can handle action keys (such as F1 and arrow keys) and modifier keys * (such as shift and control). * See {@link KeyEvent} for a description of key codes. * * @param keycode the keycode to check * @return {@code true} if {@code keycode} is currently being pressed; * {@code false} otherwise */
public boolean isKeyPressed(int keycode) {
synchronized (keyLock) {
return keysDown.contains(keycode);
}
}
/** * This method cannot be called directly. */
@Override
public void keyTyped(KeyEvent e) {
synchronized (keyLock) {
keysTyped.addFirst(e.getKeyChar());
}
// notify all listeners for (DrawListener listener : listeners)
listener.keyTyped(e.getKeyChar());
}
/** * This method cannot be called directly. */
@Override
public void keyPressed(KeyEvent e) {
synchronized (keyLock) {
keysDown.add(e.getKeyCode());
}
// notify all listeners for (DrawListener listener : listeners)
listener.keyPressed(e.getKeyCode());
}
/** * This method cannot be called directly. */
@Override
public void keyReleased(KeyEvent e) {
synchronized (keyLock) {
keysDown.remove(e.getKeyCode());
}
// notify all listeners for (DrawListener listener : listeners)
listener.keyPressed(e.getKeyCode());
}
/*************************************************************************** * For improved resolution on Mac Retina displays. ***************************************************************************/
private static class RetinaImageIcon extends ImageIcon {
public RetinaImageIcon(Image image) {
super(image);
}
public int getIconWidth() {
return super.getIconWidth() / 2;
}
/** * Gets the height of the icon. * * @return the height in pixels of this icon */
public int getIconHeight() {
return super.getIconHeight() / 2;
}
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.scale(0.5, 0.5);
super.paintIcon(c, g2, x * 2, y * 2);
g2.dispose();
}
}
/** * Test client. * * @param args the command-line arguments */
public static void main(String[] args) {
// create one drawing window Draw draw1 = new Draw(“Test client 1”);
draw1.square(0.2, 0.8, 0.1);
draw1.filledSquare(0.8, 0.8, 0.2);
draw1.circle(0.8, 0.2, 0.2);
draw1.setPenColor(Draw.MAGENTA);
draw1.setPenRadius(0.02);
draw1.arc(0.8, 0.2, 0.1, 200, 45);
// create another one Draw draw2 = new Draw(“Test client 2”);
draw2.setCanvasSize(900, 200);
// draw a blue diamond draw2.setPenRadius();
draw2.setPenColor(Draw.BLUE);
double[] x = { 0.1, 0.2, 0.3, 0.2 };
double[] y = { 0.2, 0.3, 0.2, 0.1 };
draw2.filledPolygon(x, y);
// text draw2.setPenColor(Draw.BLACK);
draw2.text(0.2, 0.5, “bdfdfdfdlack text”);
draw2.setPenColor(Draw.WHITE);
draw2.text(0.8, 0.8, “white text”);
}
}
DrawListener.java
DrawListener.java
/******************************************************************************
* Compilation: javac DrawListener.java
* Execution: none
* Dependencies: none
*
* Interface that accompanies Draw.java.
******************************************************************************/
/**
* DrawListener. This interface provides a basic capability for
* responding to keyboard in mouse events from {
@link
Draw} via callbacks.
* You can see some examples in
* Section 3.6.
*
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
interface
DrawListener
{
/**
* Invoked when the mouse has been pressed.
*
*
@param
x the x-coordinate of the mouse
*
@param
y the y-coordinate of the mouse
*/
void
mousePressed
(
double
x
,
double
y
);
/**
* Invoked when the mouse has been dragged.
*
*
@param
x the x-coordinate of the mouse
*
@param
y the y-coordinate of the mouse
*/
void
mouseDragged
(
double
x
,
double
y
);
/**
* Invoked when the mouse has been released.
*
*
@param
x the x-coordinate of the mouse
*
@param
y the y-coordinate of the mouse
*/
void
mouseReleased
(
double
x
,
double
y
);
/**
* Invoked when the mouse has been clicked (pressed and released).
*
*
@param
x the x-coordinate of the mouse
*
@param
y the y-coordinate of the mouse
*/
void
mouseClicked
(
double
x
,
double
y
);
/**
* Invoked when a key has been typed.
*
*
@param
c the character typed
*/
void
keyTyped
(
char
c
);
/**
* Invoked when a key has been pressed.
*
*
@param
keycode the key combination pressed
*/
void
keyPressed
(
int
keycode
);
/**
* Invoked when a key has been released.
*
*
@param
keycode the key combination released
*/
void
keyReleased
(
int
keycode
);
}
GrayscalePicture.java
GrayscalePicture.java
/******************************************************************************
* Compilation: javac GrayscalePicture.java
* Execution: java GrayscalePicture imagename
* Dependencies: none
*
* Data type for manipulating individual pixels of a grayscale image. The
* original image can be read from a file in JPEG, GIF, or PNG format, or the
* user can create a blank image of a given dimension. Includes methods for
* displaying the image in a window on the screen or saving to a file.
*
* % java GrayscalePicture mandrill
*
* Remarks
* ——-
* – pixel (x, y) is column x and row y, where (0, 0) is upper left
*
* – uses BufferedImage.TYPE_INT_RGB because BufferedImage.TYPE_BYTE_GRAY
* seems to do some undesirable olor correction when calling getRGB() and
* setRGB()
*
******************************************************************************/
import
java
.
awt
.
Color
;
import
java
.
awt
.
FileDialog
;
import
java
.
awt
.
Toolkit
;
import
java
.
awt
.
event
.
ActionEvent
;
import
java
.
awt
.
event
.
ActionListener
;
import
java
.
awt
.
event
.
KeyEvent
;
import
java
.
awt
.
image
.
BufferedImage
;
import
java
.
io
.
File
;
import
java
.
io
.
IOException
;
import
java
.
net
.
URL
;
import
javax
.
imageio
.
ImageIO
;
import
javax
.
swing
.
ImageIcon
;
import
javax
.
swing
.
JFrame
;
import
javax
.
swing
.
JLabel
;
import
javax
.
swing
.
JMenu
;
import
javax
.
swing
.
JMenuBar
;
import
javax
.
swing
.
JMenuItem
;
import
javax
.
swing
.
JPanel
;
import
javax
.
swing
.
KeyStroke
;
/**
* This class provides methods for manipulating individual pixels of
* a grayscale image.
* The original image can be read from a {
@code
PNG}, {
@code
GIF},
* or {
@code
JPEG} file or the user can create a blank image of a given dimension.
* This class includes methods for displaying the image in a window on
* the screen or saving it to a file.
*
* Pixel (col, row) is column col and row row.
* By default, the origin (0, 0) is the pixel in the top-left corner,
* which is a common convention in image processing.
* The method {
@link
#setOriginLowerLeft()} change the origin to the lower left.
*
* The {
@code
get()} and {
@code
set()} methods use {
@link
Color} objects to get
* or set the color of the specified pixel. The {
@link
Color} objects are converted
* to grayscale if they have different values for the R, G, and B channels.
* The {
@code
getGrayscale()} and {
@code
setGrayscale()} methods use an
* 8-bit {
@code
int} to encode the grayscale value, thereby avoiding the need to
* create temporary {
@code
Color} objects.
*
* A W-by-H picture uses ~ 4 W H bytes of memory,
* since the color of each pixel is encoded as a 32-bit int
* (even though, in principle, only ~ W H bytes are needed).
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
* See {
@link
Picture} for a version that supports 32-bit RGB color images.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
GrayscalePicture
implements
ActionListener
{
private
BufferedImage
image
;
// the rasterized image
private
JFrame
frame
;
// on-screen view
private
String
filename
;
// name of file
private
boolean
isOriginUpperLeft
=
true
;
// location of origin
private
final
int
width
,
height
;
// width and height
/**
* Creates a {
@code
width}-by-{
@code
height} picture, with {
@code
width} columns
* and {
@code
height} rows, where each pixel is black.
*
*
@param
width the width of the picture
*
@param
height the height of the picture
*
@throws
IllegalArgumentException if {
@code
width} is negative
*
@throws
IllegalArgumentException if {
@code
height} is negative
*/
public
GrayscalePicture
(
int
width
,
int
height
)
{
if
(
width
<
0
)
throw
new
IllegalArgumentException
(
"width must be non-negative"
);
if
(
height
<
0
)
throw
new
IllegalArgumentException
(
"height must be non-negative"
);
this
.
width
=
width
;
this
.
height
=
height
;
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
}
/**
* Creates a new grayscale picture that is a deep copy of the argument picture.
*
*
@param
picture the picture to copy
*
@throws
IllegalArgumentException if {
@code
picture} is {
@code
null}
*/
public
GrayscalePicture
(
GrayscalePicture
picture
)
{
if
(
picture
==
null
)
throw
new
IllegalArgumentException
(
"constructor argument is null"
);
width
=
picture
.
width
();
height
=
picture
.
height
();
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
filename
=
picture
.
filename
;
isOriginUpperLeft
=
picture
.
isOriginUpperLeft
;
for
(
int
col
=
0
;
col
<
width
();
col
++
)
for
(
int
row
=
0
;
row
<
height
();
row
++
)
image
.
setRGB
(
col
,
row
,
picture
.
image
.
getRGB
(
col
,
row
));
}
/**
* Creates a grayscale picture by reading an image from a file or URL.
*
*
@param
name the name of the file ( , .gif, or ) or URL.
*
@throws
IllegalArgumentException if cannot read image
*
@throws
IllegalArgumentException if {
@code
name} is {
@code
null}
*/
public
GrayscalePicture
(
String
name
)
{
if
(
name
==
null
)
throw
new
IllegalArgumentException
(
"constructor argument is null"
);
this
.
filename
=
name
;
try
{
// try to read from file in working directory
File
file
=
new
File
(
name
);
if
(
file
.
isFile
())
{
image
=
ImageIO
.
read
(
file
);
}
else
{
// resource relative to .class file
URL url
=
getClass
().
getResource
(
name
);
// resource relative to classloader root
if
(
url
==
null
)
{
url
=
getClass
().
getClassLoader
().
getResource
(
name
);
}
// or URL from web
if
(
url
==
null
)
{
url
=
new
URL
(
name
);
}
image
=
ImageIO
.
read
(
url
);
}
if
(
image
==
null
)
{
throw
new
IllegalArgumentException
(
"could not read image: "
+
name
);
}
width
=
image
.
getWidth
(
null
);
height
=
image
.
getHeight
(
null
);
// convert to grayscale inplace
for
(
int
col
=
0
;
col
<
width
;
col
++
)
{
for
(
int
row
=
0
;
row
<
height
;
row
++
)
{
Color
color
=
new
Color
(
image
.
getRGB
(
col
,
row
));
Color
gray
=
toGray
(
color
);
image
.
setRGB
(
col
,
row
,
gray
.
getRGB
());
}
}
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
"could not open image: "
+
name
,
ioe
);
}
}
// Returns a grayscale version of the given color as a Color object.
private
static
Color
toGray
(
Color
color
)
{
int
r
=
color
.
getRed
();
int
g
=
color
.
getGreen
();
int
b
=
color
.
getBlue
();
int
y
=
(
int
)
(
Math
.
round
(
0.299
*
r
+
0.587
*
g
+
0.114
*
b
));
return
new
Color
(
y
,
y
,
y
);
}
/**
* Returns a {
@link
JLabel} containing this picture, for embedding in a {
@link
JPanel},
* {
@link
JFrame} or other GUI widget.
*
*
@return
the {
@code
JLabel}
*/
public
JLabel
getJLabel
()
{
if
(
image
==
null
)
return
null
;
// no image available
ImageIcon
icon
=
new
ImageIcon
(
image
);
return
new
JLabel
(
icon
);
}
/**
* Sets the origin to be the upper left pixel. This is the default.
*/
public
void
setOriginUpperLeft
()
{
isOriginUpperLeft
=
true
;
}
/**
* Sets the origin to be the lower left pixel.
*/
public
void
setOriginLowerLeft
()
{
isOriginUpperLeft
=
false
;
}
/**
* Displays the picture in a window on the screen.
*/
public
void
show
()
{
// create the GUI for viewing the image if needed
if
(
frame
==
null
)
{
frame
=
new
JFrame
();
JMenuBar
menuBar
=
new
JMenuBar
();
JMenu
menu
=
new
JMenu
(
"File"
);
menuBar
.
add
(
menu
);
JMenuItem
menuItem1
=
new
JMenuItem
(
" Save... "
);
menuItem1
.
addActionListener
(
this
);
// use getMenuShortcutKeyMaskEx() in Java 10 (getMenuShortcutKeyMask() deprecated)
menuItem1
.
setAccelerator
(
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_S
,
Toolkit
.
getDefaultToolkit
().
getMenuShortcutKeyMask
()));
menu
.
add
(
menuItem1
);
frame
.
setJMenuBar
(
menuBar
);
frame
.
setContentPane
(
getJLabel
());
// f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame
.
setDefaultCloseOperation
(
JFrame
.
DISPOSE_ON_CLOSE
);
if
(
filename
==
null
)
frame
.
setTitle
(
width
+
"-by-"
+
height
);
else
frame
.
setTitle
(
filename
);
frame
.
setResizable
(
false
);
frame
.
pack
();
frame
.
setVisible
(
true
);
}
// draw
frame
.
repaint
();
}
/**
* Returns the height of the picture.
*
*
@return
the height of the picture (in pixels)
*/
public
int
height
()
{
return
height
;
}
/**
* Returns the width of the picture.
*
*
@return
the width of the picture (in pixels)
*/
public
int
width
()
{
return
width
;
}
private
void
validateRowIndex
(
int
row
)
{
if
(
row
<
0
||
row
>=
height
())
throw
new
IllegalArgumentException
(
“row index must be between 0 and ”
+
(
height
()
–
1
)
+
“: ”
+
row
);
}
private
void
validateColumnIndex
(
int
col
)
{
if
(
col
<
0
||
col
>=
width
())
throw
new
IllegalArgumentException
(
“column index must be between 0 and ”
+
(
width
()
–
1
)
+
“: ”
+
col
);
}
private
void
validateGrayscaleValue
(
int
gray
)
{
if
(
gray
<
0
||
gray
>=
256
)
throw
new
IllegalArgumentException
(
“grayscale value must be between 0 and 255”
);
}
/**
* Returns the grayscale value of pixel ({
@code
col}, {
@code
row}) as a {
@link
java.awt.Color}.
*
*
@param
col the column index
*
@param
row the row index
*
@return
the grayscale value of pixel ({
@code
col}, {
@code
row})
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
Color
get
(
int
col
,
int
row
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
Color
color
=
new
Color
(
image
.
getRGB
(
col
,
row
));
return
toGray
(
color
);
}
/**
* Returns the grayscale value of pixel ({
@code
col}, {
@code
row}) as an {
@code
int}
* between 0 and 255.
* Using this method can be more efficient than {
@link
#get(int, int)} because
* it does not create a {
@code
Color} object.
*
*
@param
col the column index
*
@param
row the row index
*
@return
the 8-bit integer representation of the grayscale value of pixel ({
@code
col}, {
@code
row})
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
int
getGrayscale
(
int
col
,
int
row
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
if
(
isOriginUpperLeft
)
return
image
.
getRGB
(
col
,
row
)
&
0xFF
;
else
return
image
.
getRGB
(
col
,
height
-
row
-
1
)
&
0xFF
;
}
/**
* Sets the color of pixel ({
@code
col}, {
@code
row}) to the given grayscale value.
*
*
@param
col the column index
*
@param
row the row index
*
@param
color the color (converts to grayscale if color is not a shade of gray)
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
void
set
(
int
col
,
int
row
,
Color
color
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
if
(
color
==
null
)
throw
new
IllegalArgumentException
(
"color argument is null"
);
Color
gray
=
toGray
(
color
);
image
.
setRGB
(
col
,
row
,
gray
.
getRGB
());
}
/**
* Sets the color of pixel ({
@code
col}, {
@code
row}) to the given grayscale value
* between 0 and 255.
*
*
@param
col the column index
*
@param
row the row index
*
@param
gray the 8-bit integer representation of the grayscale value
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
void
setGrayscale
(
int
col
,
int
row
,
int
gray
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
validateGrayscaleValue
(
gray
);
int
rgb
=
gray
|
(
gray
<<
8
)
|
(
gray
<<
16
);
if
(
isOriginUpperLeft
)
image
.
setRGB
(
col
,
row
,
rgb
);
else
image
.
setRGB
(
col
,
height
-
row
-
1
,
rgb
);
}
/**
* Returns true if this picture is equal to the argument picture.
*
*
@param
other the other picture
*
@return
{
@code
true} if this picture is the same dimension as {
@code
other}
* and if all pixels have the same color; {
@code
false} otherwise
*/
public
boolean
equals
(
Object
other
)
{
if
(
other
==
this
)
return
true
;
if
(
other
==
null
)
return
false
;
if
(
other
.
getClass
()
!=
this
.
getClass
())
return
false
;
GrayscalePicture
that
=
(
GrayscalePicture
)
other
;
if
(
this
.
width
()
!=
that
.
width
())
return
false
;
if
(
this
.
height
()
!=
that
.
height
())
return
false
;
for
(
int
col
=
0
;
col
<
width
();
col
++
)
for
(
int
row
=
0
;
row
<
height
();
row
++
)
if
(
this
.
getGrayscale
(
col
,
row
)
!=
that
.
getGrayscale
(
col
,
row
))
return
false
;
return
true
;
}
/**
* Returns a string representation of this picture.
* The result is a width
-by-height
matrix of pixels,
* where the grayscale value of a pixel is an integer between 0 and 255.
*
*
@return
a string representation of this picture
*/
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
width
+
“-by-”
+
height
+
” grayscale picture (grayscale values given in hex)\n”
);
for
(
int
row
=
0
;
row
<
height
;
row
++
)
{
for
(
int
col
=
0
;
col
<
width
;
col
++
)
{
int
gray
=
0
;
if
(
isOriginUpperLeft
)
gray
=
0xFF
&
image
.
getRGB
(
col
,
row
);
else
gray
=
0xFF
&
image
.
getRGB
(
col
,
height
-
row
-
1
);
sb
.
append
(
String
.
format
(
"%3d "
,
gray
));
}
sb
.
append
(
"\n"
);
}
return
sb
.
toString
().
trim
();
}
/**
* This operation is not supported because pictures are mutable.
*
*
@return
does not return a value
*
@throws
UnsupportedOperationException if called
*/
public
int
hashCode
()
{
throw
new
UnsupportedOperationException
(
"hashCode() is not supported because pictures are mutable"
);
}
/**
* Saves the picture to a file in either PNG or JPEG format.
* The filetype extension must be either or .
*
*
@param
name the name of the file
*
@throws
IllegalArgumentException if {
@code
name} is {
@code
null}
*/
public
void
save
(
String
name
)
{
if
(
name
==
null
)
throw
new
IllegalArgumentException
(
"argument to save() is null"
);
save
(
new
File
(
name
));
filename
=
name
;
}
/**
* Saves the picture to a file in a PNG or JPEG image format.
*
*
@param
file the file
*
@throws
IllegalArgumentException if {
@code
file} is {
@code
null}
*/
public
void
save
(
File
file
)
{
if
(
file
==
null
)
throw
new
IllegalArgumentException
(
"argument to save() is null"
);
filename
=
file
.
getName
();
if
(
frame
!=
null
)
frame
.
setTitle
(
filename
);
String
suffix
=
filename
.
substring
(
filename
.
lastIndexOf
(
'.'
)
+
1
);
if
(
"jpg"
.
equalsIgnoreCase
(
suffix
)
||
"png"
.
equalsIgnoreCase
(
suffix
))
{
try
{
ImageIO
.
write
(
image
,
suffix
,
file
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
else
{
System
.
out
.
println
(
"Error: filename must end in or "
);
}
}
/**
* Opens a save dialog box when the user selects "Save As" from the menu.
*/
@
Override
public
void
actionPerformed
(
ActionEvent
e
)
{
FileDialog
chooser
=
new
FileDialog
(
frame
,
"Use a or extension"
,
FileDialog
.
SAVE
);
chooser
.
setVisible
(
true
);
if
(
chooser
.
getFile
()
!=
null
)
{
save
(
chooser
.
getDirectory
()
+
File
.
separator
+
chooser
.
getFile
());
}
}
/**
* Unit tests this {
@code
Picture} data type.
* Reads a picture specified by the command-line argument,
* and shows it in a window on the screen.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
GrayscalePicture
picture
=
new
GrayscalePicture
(
args
[
0
]);
StdOut
.
printf
(
"%d-by-%d\n"
,
picture
.
width
(),
picture
.
height
());
GrayscalePicture
copy
=
new
GrayscalePicture
(
picture
);
picture
.
show
();
copy
.
show
();
while
(
!
StdIn
.
isEmpty
())
{
int
row
=
StdIn
.
readInt
();
int
col
=
StdIn
.
readInt
();
int
gray
=
StdIn
.
readInt
();
picture
.
setGrayscale
(
row
,
col
,
gray
);
StdOut
.
println
(
picture
.
get
(
row
,
col
));
StdOut
.
println
(
picture
.
getGrayscale
(
row
,
col
));
}
}
}
In.java
In.java
/******************************************************************************
* Compilation: javac In.java
* Execution: java In (basic test --- see source for required files)
* Dependencies: none
*
* Reads in data of various types from standard input, files, and URLs.
*
******************************************************************************/
import
java
.
io
.
BufferedInputStream
;
import
java
.
io
.
File
;
import
java
.
io
.
FileInputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
InputStream
;
import
java
.
net
.
URL
;
import
java
.
net
.
Socket
;
// import java.net.HttpURLConnection;
import
java
.
net
.
URLConnection
;
import
java
.
util
.
ArrayList
;
import
java
.
util
.
InputMismatchException
;
import
java
.
util
.
Locale
;
import
java
.
util
.
NoSuchElementException
;
import
java
.
util
.
Scanner
;
import
java
.
util
.
regex
.
Pattern
;
/**
* Input. This class provides methods for reading strings
* and numbers from standard input, file input, URLs, and sockets.
*
* The Locale used is: language = English, country = US. This is consistent
* with the formatting conventions with Java floating-point literals,
* command-line arguments (via {
@link
Double#parseDouble(String)})
* and standard output.
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
* Like {
@link
Scanner}, reading a token also consumes preceding Java
* whitespace, reading a full line consumes
* the following end-of-line delimeter, while reading a character consumes
* nothing extra.
*
* Whitespace is defined in {
@link
Character#isWhitespace(char)}. Newlines
* consist of \n, \r, \r\n, and Unicode hex code points 0x2028, 0x2029, 0x0085;
* Scanner.java (NB: Java 6u23 and earlier uses only \r, \r, \r\n).
*
*
@author
David Pritchard
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
In
{
///// begin: section (1 of 2) of code duplicated from In to StdIn.
// assume Unicode UTF-8 encoding
private
static
final
String
CHARSET_NAME
=
“UTF-8”
;
// assume language = English, country = US for consistency with System.out.
private
static
final
Locale
LOCALE
=
Locale
.
US
;
// the default token separator; we maintain the invariant that this value
// is held by the scanner’s delimiter between calls
private
static
final
Pattern
WHITESPACE_PATTERN
=
Pattern
.
compile
(
“\\p{javaWhitespace}+”
);
// makes whitespace characters significant
private
static
final
Pattern
EMPTY_PATTERN
=
Pattern
.
compile
(
“”
);
// used to read the entire input. source:
// http://weblogs.java.net/blog/pat/archive/2004/10/stupid_scanner_1.html
private
static
final
Pattern
EVERYTHING_PATTERN
=
Pattern
.
compile
(
“\\A”
);
//// end: section (1 of 2) of code duplicated from In to StdIn.
private
Scanner
scanner
;
/**
* Initializes an input stream from standard input.
*/
public
In
()
{
scanner
=
new
Scanner
(
new
BufferedInputStream
(
System
.
in
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
}
/**
* Initializes an input stream from a socket.
*
*
@param
socket the socket
*
@throws
IllegalArgumentException if cannot open {
@code
socket}
*
@throws
IllegalArgumentException if {
@code
socket} is {
@code
null}
*/
public
In
(
Socket
socket
)
{
if
(
socket
==
null
)
throw
new
IllegalArgumentException
(
“socket argument is null”
);
try
{
InputStream
is
=
socket
.
getInputStream
();
scanner
=
new
Scanner
(
new
BufferedInputStream
(
is
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
“Could not open ”
+
socket
,
ioe
);
}
}
/**
* Initializes an input stream from a URL.
*
*
@param
url the URL
*
@throws
IllegalArgumentException if cannot open {
@code
url}
*
@throws
IllegalArgumentException if {
@code
url} is {
@code
null}
*/
public
In
(
URL url
)
{
if
(
url
==
null
)
throw
new
IllegalArgumentException
(
“url argument is null”
);
try
{
URLConnection
site
=
url
.
openConnection
();
InputStream
is
=
site
.
getInputStream
();
scanner
=
new
Scanner
(
new
BufferedInputStream
(
is
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
“Could not open ”
+
url
,
ioe
);
}
}
/**
* Initializes an input stream from a file.
*
*
@param
file the file
*
@throws
IllegalArgumentException if cannot open {
@code
file}
*
@throws
IllegalArgumentException if {
@code
file} is {
@code
null}
*/
public
In
(
File
file
)
{
if
(
file
==
null
)
throw
new
IllegalArgumentException
(
“file argument is null”
);
try
{
// for consistency with StdIn, wrap with BufferedInputStream instead of use
// file as argument to Scanner
FileInputStream
fis
=
new
FileInputStream
(
file
);
scanner
=
new
Scanner
(
new
BufferedInputStream
(
fis
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
“Could not open ”
+
file
,
ioe
);
}
}
/**
* Initializes an input stream from a filename or web page name.
*
*
@param
name the filename or web page name
*
@throws
IllegalArgumentException if cannot open {
@code
name} as
* a file or URL
*
@throws
IllegalArgumentException if {
@code
name} is {
@code
null}
*/
public
In
(
String
name
)
{
if
(
name
==
null
)
throw
new
IllegalArgumentException
(
“argument is null”
);
try
{
// first try to read file from local file system
File
file
=
new
File
(
name
);
if
(
file
.
exists
())
{
// for consistency with StdIn, wrap with BufferedInputStream instead of use
// file as argument to Scanner
FileInputStream
fis
=
new
FileInputStream
(
file
);
scanner
=
new
Scanner
(
new
BufferedInputStream
(
fis
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
return
;
}
// resource relative to .class file
URL url
=
getClass
().
getResource
(
name
);
// resource relative to classloader root
if
(
url
==
null
)
{
url
=
getClass
().
getClassLoader
().
getResource
(
name
);
}
// or URL from web
if
(
url
==
null
)
{
url
=
new
URL
(
name
);
}
URLConnection
site
=
url
.
openConnection
();
// in order to set User-Agent, replace above line with these two
// HttpURLConnection site = (HttpURLConnection) url.openConnection();
// site.addRequestProperty(“User-Agent”, “Mozilla/4.76”);
InputStream
is
=
site
.
getInputStream
();
scanner
=
new
Scanner
(
new
BufferedInputStream
(
is
),
CHARSET_NAME
);
scanner
.
useLocale
(
LOCALE
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
“Could not open ”
+
name
,
ioe
);
}
}
/**
* Initializes an input stream from a given {
@link
Scanner} source; use with
* {
@code
new Scanner(String)} to read from a string.
*
* Note that this does not create a defensive copy, so the
* scanner will be mutated as you read on.
*
*
@param
scanner the scanner
*
@throws
IllegalArgumentException if {
@code
scanner} is {
@code
null}
*/
public
In
(
Scanner
scanner
)
{
if
(
scanner
==
null
)
throw
new
IllegalArgumentException
(
“scanner argument is null”
);
this
.
scanner
=
scanner
;
}
/**
* Returns true if this input stream exists.
*
*
@return
{
@code
true} if this input stream exists; {
@code
false} otherwise
*/
public
boolean
exists
()
{
return
scanner
!=
null
;
}
//// begin: section (2 of 2) of code duplicated from In to StdIn,
//// with all methods changed from “public” to “public static”.
/**
* Returns true if input stream is empty (except possibly whitespace).
* Use this to know whether the next call to {
@link
#readString()},
* {
@link
#readDouble()}, etc will succeed.
*
*
@return
{
@code
true} if this input stream is empty (except possibly whitespace);
* {
@code
false} otherwise
*/
public
boolean
isEmpty
()
{
return
!
scanner
.
hasNext
();
}
/**
* Returns true if this input stream has a next line.
* Use this method to know whether the
* next call to {
@link
#readLine()} will succeed.
* This method is functionally equivalent to {
@link
#hasNextChar()}.
*
*
@return
{
@code
true} if this input stream has more input (including whitespace);
* {
@code
false} otherwise
*/
public
boolean
hasNextLine
()
{
return
scanner
.
hasNextLine
();
}
/**
* Returns true if this input stream has more input (including whitespace).
* Use this method to know whether the next call to {
@link
#readChar()} will succeed.
* This method is functionally equivalent to {
@link
#hasNextLine()}.
*
*
@return
{
@code
true} if this input stream has more input (including whitespace);
* {
@code
false} otherwise
*/
public
boolean
hasNextChar
()
{
scanner
.
useDelimiter
(
EMPTY_PATTERN
);
boolean
result
=
scanner
.
hasNext
();
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
return
result
;
}
/**
* Reads and returns the next line in this input stream.
*
*
@return
the next line in this input stream; {
@code
null} if no such line
*/
public
String
readLine
()
{
String
line
;
try
{
line
=
scanner
.
nextLine
();
}
catch
(
NoSuchElementException
e
)
{
line
=
null
;
}
return
line
;
}
/**
* Reads and returns the next character in this input stream.
*
*
@return
the next {
@code
char} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*/
public
char
readChar
()
{
scanner
.
useDelimiter
(
EMPTY_PATTERN
);
try
{
String
ch
=
scanner
.
next
();
assert
ch
.
length
()
==
1
:
“Internal (Std)In.readChar() error!”
+
” Please contact the authors.”
;
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
return
ch
.
charAt
(
0
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘char’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads and returns the remainder of this input stream, as a string.
*
*
@return
the remainder of this input stream, as a string
*/
public
String
readAll
()
{
if
(
!
scanner
.
hasNextLine
())
return
“”
;
String
result
=
scanner
.
useDelimiter
(
EVERYTHING_PATTERN
).
next
();
// not that important to reset delimeter, since now scanner is empty
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
// but let’s do it anyway
return
result
;
}
/**
* Reads the next token from this input stream and returns it as a {
@code
String}.
*
*
@return
the next {
@code
String} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*/
public
String
readString
()
{
try
{
return
scanner
.
next
();
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘String’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
int},
* and returns the {
@code
int}.
*
*
@return
the next {
@code
int} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as an {
@code
int}
*/
public
int
readInt
()
{
try
{
return
scanner
.
nextInt
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read an ‘int’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read an ‘int’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
double},
* and returns the {
@code
double}.
*
*
@return
the next {
@code
double} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
double}
*/
public
double
readDouble
()
{
try
{
return
scanner
.
nextDouble
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘double’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read a ‘double’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
float},
* and returns the {
@code
float}.
*
*
@return
the next {
@code
float} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
float}
*/
public
float
readFloat
()
{
try
{
return
scanner
.
nextFloat
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘float’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read a ‘float’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
long},
* and returns the {
@code
long}.
*
*
@return
the next {
@code
long} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
long}
*/
public
long
readLong
()
{
try
{
return
scanner
.
nextLong
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘long’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read a ‘long’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
short},
* and returns the {
@code
short}.
*
*
@return
the next {
@code
short} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
short}
*/
public
short
readShort
()
{
try
{
return
scanner
.
nextShort
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘short’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read a ‘short’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
byte},
* and returns the {
@code
byte}.
*
* To read binary data, use {
@link
BinaryIn}.
*
*
@return
the next {
@code
byte} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
byte}
*/
public
byte
readByte
()
{
try
{
return
scanner
.
nextByte
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘byte’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read a ‘byte’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from this input stream, parses it as a {
@code
boolean}
* (interpreting either {
@code
“true”} or {
@code
“1”} as {
@code
true},
* and either {
@code
“false”} or {
@code
“0”} as {
@code
false}).
*
*
@return
the next {
@code
boolean} in this input stream
*
@throws
NoSuchElementException if the input stream is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
boolean}
*/
public
boolean
readBoolean
()
{
try
{
String
token
=
readString
();
if
(
“true”
.
equalsIgnoreCase
(
token
))
return
true
;
if
(
“false”
.
equalsIgnoreCase
(
token
))
return
false
;
if
(
“1”
.
equals
(
token
))
return
true
;
if
(
“0”
.
equals
(
token
))
return
false
;
throw
new
InputMismatchException
(
“attempts to read a ‘boolean’ value from the input stream, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘boolean’ value from the input stream, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads all remaining tokens from this input stream and returns them as
* an array of strings.
*
*
@return
all remaining tokens in this input stream, as an array of strings
*/
public
String
[]
readAllStrings
()
{
// we could use readAll.trim().split(), but that’s not consistent
// since trim() uses characters 0x00..0x20 as whitespace
String
[]
tokens
=
WHITESPACE_PATTERN
.
split
(
readAll
());
if
(
tokens
.
length
==
0
||
tokens
[
0
].
length
()
>
0
)
return
tokens
;
String
[]
decapitokens
=
new
String
[
tokens
.
length
–
1
];
for
(
int
i
=
0
;
i
<
tokens
.
length
-
1
;
i
++
)
decapitokens
[
i
]
=
tokens
[
i
+
1
];
return
decapitokens
;
}
/**
* Reads all remaining lines from this input stream and returns them as
* an array of strings.
*
*
@return
all remaining lines in this input stream, as an array of strings
*/
public
String
[]
readAllLines
()
{
ArrayList
<
String
>
lines
=
new
ArrayList
<
String
>
();
while
(
hasNextLine
())
{
lines
.
add
(
readLine
());
}
return
lines
.
toArray
(
new
String
[
lines
.
size
()]);
}
/**
* Reads all remaining tokens from this input stream, parses them as integers,
* and returns them as an array of integers.
*
*
@return
all remaining lines in this input stream, as an array of integers
*/
public
int
[]
readAllInts
()
{
String
[]
fields
=
readAllStrings
();
int
[]
vals
=
new
int
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Integer
.
parseInt
(
fields
[
i
]);
return
vals
;
}
/**
* Reads all remaining tokens from this input stream, parses them as longs,
* and returns them as an array of longs.
*
*
@return
all remaining lines in this input stream, as an array of longs
*/
public
long
[]
readAllLongs
()
{
String
[]
fields
=
readAllStrings
();
long
[]
vals
=
new
long
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Long
.
parseLong
(
fields
[
i
]);
return
vals
;
}
/**
* Reads all remaining tokens from this input stream, parses them as doubles,
* and returns them as an array of doubles.
*
*
@return
all remaining lines in this input stream, as an array of doubles
*/
public
double
[]
readAllDoubles
()
{
String
[]
fields
=
readAllStrings
();
double
[]
vals
=
new
double
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Double
.
parseDouble
(
fields
[
i
]);
return
vals
;
}
///// end: section (2 of 2) of code duplicated from In to StdIn */
/**
* Closes this input stream.
*/
public
void
close
()
{
scanner
.
close
();
}
/**
* Reads all integers from a file and returns them as
* an array of integers.
*
*
@param
filename the name of the file
*
@return
the integers in the file
*
@deprecated
Replaced by {
@code
new In(filename)}.{
@link
#readAllInts()}.
*/
@
Deprecated
public
static
int
[]
readInts
(
String
filename
)
{
return
new
In
(
filename
).
readAllInts
();
}
/**
* Reads all doubles from a file and returns them as
* an array of doubles.
*
*
@param
filename the name of the file
*
@return
the doubles in the file
*
@deprecated
Replaced by {
@code
new In(filename)}.{
@link
#readAllDoubles()}.
*/
@
Deprecated
public
static
double
[]
readDoubles
(
String
filename
)
{
return
new
In
(
filename
).
readAllDoubles
();
}
/**
* Reads all strings from a file and returns them as
* an array of strings.
*
*
@param
filename the name of the file
*
@return
the strings in the file
*
@deprecated
Replaced by {
@code
new In(filename)}.{
@link
#readAllStrings()}.
*/
@
Deprecated
public
static
String
[]
readStrings
(
String
filename
)
{
return
new
In
(
filename
).
readAllStrings
();
}
/**
* Reads all integers from standard input and returns them
* an array of integers.
*
*
@return
the integers on standard input
*
@deprecated
Replaced by {
@link
StdIn#readAllInts()}.
*/
@
Deprecated
public
static
int
[]
readInts
()
{
return
new
In
().
readAllInts
();
}
/**
* Reads all doubles from standard input and returns them as
* an array of doubles.
*
*
@return
the doubles on standard input
*
@deprecated
Replaced by {
@link
StdIn#readAllDoubles()}.
*/
@
Deprecated
public
static
double
[]
readDoubles
()
{
return
new
In
().
readAllDoubles
();
}
/**
* Reads all strings from standard input and returns them as
* an array of strings.
*
*
@return
the strings on standard input
*
@deprecated
Replaced by {
@link
StdIn#readAllStrings()}.
*/
@
Deprecated
public
static
String
[]
readStrings
()
{
return
new
In
().
readAllStrings
();
}
/**
* Unit tests the {
@code
In} data type.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
In
in
;
String
urlName
=
"https://introcs.cs.princeton.edu/java/stdlib/InTest.txt"
;
// read from a URL
System
.
out
.
println
(
"readAll() from URL "
+
urlName
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
urlName
);
System
.
out
.
println
(
in
.
readAll
());
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one line at a time from URL
System
.
out
.
println
(
"readLine() from URL "
+
urlName
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
urlName
);
while
(
!
in
.
isEmpty
())
{
String
s
=
in
.
readLine
();
System
.
out
.
println
(
s
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one string at a time from URL
System
.
out
.
println
(
"readString() from URL "
+
urlName
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
urlName
);
while
(
!
in
.
isEmpty
())
{
String
s
=
in
.
readString
();
System
.
out
.
println
(
s
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one line at a time from file in current directory
System
.
out
.
println
(
"readLine() from current directory"
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
"./InTest.txt"
);
while
(
!
in
.
isEmpty
())
{
String
s
=
in
.
readLine
();
System
.
out
.
println
(
s
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one line at a time from file using relative path
System
.
out
.
println
(
"readLine() from relative path"
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
"../stdlib/InTest.txt"
);
while
(
!
in
.
isEmpty
())
{
String
s
=
in
.
readLine
();
System
.
out
.
println
(
s
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one char at a time
System
.
out
.
println
(
"readChar() from file"
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
"InTest.txt"
);
while
(
!
in
.
isEmpty
())
{
char
c
=
in
.
readChar
();
System
.
out
.
print
(
c
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
System
.
out
.
println
();
// read one line at a time from absolute OS X / Linux path
System
.
out
.
println
(
"readLine() from absolute OS X / Linux path"
);
System
.
out
.
println
(
"---------------------------------------------------------------------------"
);
try
{
in
=
new
In
(
"/n/fs/introcs/www/java/stdlib/InTest.txt"
);
while
(
!
in
.
isEmpty
())
{
String
s
=
in
.
readLine
();
System
.
out
.
println
(
s
);
}
}
catch
(
IllegalArgumentException
e
)
{
System
.
out
.
println
(
e
);
}
System
.
out
.
println
();
// read one line at a time from absolute Windows path System.out.println("readLine() from absolute Windows path");
System.out.println("---------------------------------------------------------------------------");
try {
in = new In("G:\\www\\introcs\\stdlib\\InTest.txt");
while (!in.isEmpty()) {
String s = in.readLine();
System.out.println(s);
}
System.out.println();
}
catch (IllegalArgumentException e) {
System.out.println(e);
}
System.out.println();
}
}
Out.java
Out.java
/******************************************************************************
* Compilation: javac Out.java
* Execution: java Out
* Dependencies: none
*
* Writes data of various types to: stdout, file, or socket.
*
******************************************************************************/
import
java
.
io
.
FileOutputStream
;
import
java
.
io
.
IOException
;
import
java
.
io
.
OutputStream
;
import
java
.
io
.
OutputStreamWriter
;
import
java
.
io
.
PrintWriter
;
import
java
.
net
.
Socket
;
import
java
.
util
.
Locale
;
/**
* This class provides methods for writing strings and numbers to
* various output streams, including standard output, file, and sockets.
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
class
Out
{
// force Unicode UTF-8 encoding; otherwise it’s system dependent
private
static
final
String
CHARSET_NAME
=
“UTF-8”
;
// assume language = English, country = US for consistency with In
private
static
final
Locale
LOCALE
=
Locale
.
US
;
private
PrintWriter
out
;
/**
* Initializes an output stream from a {
@link
OutputStream}.
*
*
@param
os the {
@code
OutputStream}
*/
public
Out
(
OutputStream
os
)
{
try
{
OutputStreamWriter
osw
=
new
OutputStreamWriter
(
os
,
CHARSET_NAME
);
out
=
new
PrintWriter
(
osw
,
true
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Initializes an output stream from standard output.
*/
public
Out
()
{
this
(
System
.
out
);
}
/**
* Initializes an output stream from a socket.
*
*
@param
socket the socket
*/
public
Out
(
Socket
socket
)
{
try
{
OutputStream
os
=
socket
.
getOutputStream
();
OutputStreamWriter
osw
=
new
OutputStreamWriter
(
os
,
CHARSET_NAME
);
out
=
new
PrintWriter
(
osw
,
true
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Initializes an output stream from a file.
*
*
@param
filename the name of the file
*/
public
Out
(
String
filename
)
{
try
{
OutputStream
os
=
new
FileOutputStream
(
filename
);
OutputStreamWriter
osw
=
new
OutputStreamWriter
(
os
,
CHARSET_NAME
);
out
=
new
PrintWriter
(
osw
,
true
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
/**
* Closes the output stream.
*/
public
void
close
()
{
out
.
close
();
}
/**
* Terminates the current line by printing the line-separator string.
*/
public
void
println
()
{
out
.
println
();
}
/**
* Prints an object to this output stream and then terminates the line.
*
*
@param
x the object to print
*/
public
void
println
(
Object
x
)
{
out
.
println
(
x
);
}
/**
* Prints a boolean to this output stream and then terminates the line.
*
*
@param
x the boolean to print
*/
public
void
println
(
boolean
x
)
{
out
.
println
(
x
);
}
/**
* Prints a character to this output stream and then terminates the line.
*
*
@param
x the character to print
*/
public
void
println
(
char
x
)
{
out
.
println
(
x
);
}
/**
* Prints a double to this output stream and then terminates the line.
*
*
@param
x the double to print
*/
public
void
println
(
double
x
)
{
out
.
println
(
x
);
}
/**
* Prints a float to this output stream and then terminates the line.
*
*
@param
x the float to print
*/
public
void
println
(
float
x
)
{
out
.
println
(
x
);
}
/**
* Prints an integer to this output stream and then terminates the line.
*
*
@param
x the integer to print
*/
public
void
println
(
int
x
)
{
out
.
println
(
x
);
}
/**
* Prints a long to this output stream and then terminates the line.
*
*
@param
x the long to print
*/
public
void
println
(
long
x
)
{
out
.
println
(
x
);
}
/**
* Prints a byte to this output stream and then terminates the line.
*
* To write binary data, see {
@link
BinaryOut}.
*
*
@param
x the byte to print
*/
public
void
println
(
byte
x
)
{
out
.
println
(
x
);
}
/**
* Flushes this output stream.
*/
public
void
print
()
{
out
.
flush
();
}
/**
* Prints an object to this output stream and flushes this output stream.
*
*
@param
x the object to print
*/
public
void
print
(
Object
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a boolean to this output stream and flushes this output stream.
*
*
@param
x the boolean to print
*/
public
void
print
(
boolean
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a character to this output stream and flushes this output stream.
*
*
@param
x the character to print
*/
public
void
print
(
char
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a double to this output stream and flushes this output stream.
*
*
@param
x the double to print
*/
public
void
print
(
double
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a float to this output stream and flushes this output stream.
*
*
@param
x the float to print
*/
public
void
print
(
float
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints an integer to this output stream and flushes this output stream.
*
*
@param
x the integer to print
*/
public
void
print
(
int
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a long integer to this output stream and flushes this output stream.
*
*
@param
x the long integer to print
*/
public
void
print
(
long
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a byte to this output stream and flushes this output stream.
*
*
@param
x the byte to print
*/
public
void
print
(
byte
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a formatted string to this output stream, using the specified format
* string and arguments, and then flushes this output stream.
*
*
@param
format the format string
*
@param
args the arguments accompanying the format string
*/
public
void
printf
(
String
format
,
Object
…
args
)
{
out
.
printf
(
LOCALE
,
format
,
args
);
out
.
flush
();
}
/**
* Prints a formatted string to this output stream, using the specified
* locale, format string, and arguments, and then flushes this output stream.
*
*
@param
locale the locale
*
@param
format the format string
*
@param
args the arguments accompanying the format string
*/
public
void
printf
(
Locale
locale
,
String
format
,
Object
…
args
)
{
out
.
printf
(
locale
,
format
,
args
);
out
.
flush
();
}
/**
* A test client.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
Out
out
;
// write to stdout
out
=
new
Out
();
out
.
println
(
“Test 1”
);
out
.
close
();
// write to a file
out
=
new
Out
(
“test.txt”
);
out
.
println
(
“Test 2”
);
out
.
close
();
}
}
Picture.java
Picture.java
/******************************************************************************
* Compilation: javac Picture.java
* Execution: java Picture imagename
* Dependencies: none
*
* Data type for manipulating individual pixels of an image. The original
* image can be read from a file in JPG, GIF, or PNG format, or the
* user can create a blank image of a given dimension. Includes methods for
* displaying the image in a window on the screen or saving to a file.
*
* % java Picture mandrill
*
* Remarks
* ——-
* – pixel (x, y) is column x and row y, where (0, 0) is upper left
*
******************************************************************************/
import
java
.
awt
.
Color
;
import
java
.
awt
.
FileDialog
;
import
java
.
awt
.
Toolkit
;
import
java
.
awt
.
event
.
ActionEvent
;
import
java
.
awt
.
event
.
ActionListener
;
import
java
.
awt
.
event
.
KeyEvent
;
import
java
.
awt
.
image
.
BufferedImage
;
import
java
.
io
.
File
;
import
java
.
io
.
IOException
;
import
java
.
net
.
URL
;
import
javax
.
imageio
.
ImageIO
;
import
javax
.
swing
.
ImageIcon
;
import
javax
.
swing
.
JFrame
;
import
javax
.
swing
.
JLabel
;
import
javax
.
swing
.
JMenu
;
import
javax
.
swing
.
JMenuBar
;
import
javax
.
swing
.
JMenuItem
;
import
javax
.
swing
.
JPanel
;
import
javax
.
swing
.
KeyStroke
;
/**
* This class provides methods for manipulating individual pixels of
* an image using the RGB color format. The alpha component (for transparency)
* is not currently supported.
* The original image can be read from a {
@code
PNG}, {
@code
GIF},
* or {
@code
JPEG} file or the user can create a blank image of a given dimension.
* This class includes methods for displaying the image in a window on
* the screen or saving it to a file.
*
* Pixel (col, row) is column col and row row.
* By default, the origin (0, 0) is the pixel in the top-left corner,
* which is a common convention in image processing.
* The method {
@link
#setOriginLowerLeft()} change the origin to the lower left.
*
* The {
@code
get()} and {
@code
set()} methods use {
@link
Color} objects to get
* or set the color of the specified pixel.
* The {
@code
getRGB()} and {
@code
setRGB()} methods use a 32-bit {
@code
int}
* to encode the color, thereby avoiding the need to create temporary
* {
@code
Color} objects. The red (R), green (G), and blue (B) components
* are encoded using the least significant 24 bits.
* Given a 32-bit {
@code
int} encoding the color, the following code extracts
* the RGB components:
*
* int r = (rgb >> 16) & 0xFF; * int g = (rgb >> 8) & 0xFF; * int b = (rgb >> 0) & 0xFF; *
* Given the RGB components (8-bits each) of a color,
* the following statement packs it into a 32-bit {
@code
int}:
*
* int rgb = (r << 16) + (g << 8) + (b << 0); *
*
* A W-by-H picture uses ~ 4 W H bytes of memory,
* since the color of each pixel is encoded as a 32-bit int
.
*
* For additional documentation, see
* Section 3.1 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
* See {
@link
GrayscalePicture} for a version that supports grayscale images.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
Picture
implements
ActionListener
{
private
BufferedImage
image
;
// the rasterized image
private
JFrame
frame
;
// on-screen view
private
String
filename
;
// name of file
private
boolean
isOriginUpperLeft
=
true
;
// location of origin
private
final
int
width
,
height
;
// width and height
/**
* Creates a {
@code
width}-by-{
@code
height} picture, with {
@code
width} columns
* and {
@code
height} rows, where each pixel is black.
*
*
@param
width the width of the picture
*
@param
height the height of the picture
*
@throws
IllegalArgumentException if {
@code
width} is negative or zero
*
@throws
IllegalArgumentException if {
@code
height} is negative or zero
*/
public
Picture
(
int
width
,
int
height
)
{
if
(
width
<=
0
)
throw
new
IllegalArgumentException
(
"width must be positive"
);
if
(
height
<=
0
)
throw
new
IllegalArgumentException
(
"height must be positive"
);
this
.
width
=
width
;
this
.
height
=
height
;
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
// set to TYPE_INT_ARGB here and in next constructor to support transparency
}
/**
* Creates a new picture that is a deep copy of the argument picture.
*
*
@param
picture the picture to copy
*
@throws
IllegalArgumentException if {
@code
picture} is {
@code
null}
*/
public
Picture
(
Picture
picture
)
{
if
(
picture
==
null
)
throw
new
IllegalArgumentException
(
"constructor argument is null"
);
width
=
picture
.
width
();
height
=
picture
.
height
();
image
=
new
BufferedImage
(
width
,
height
,
BufferedImage
.
TYPE_INT_RGB
);
filename
=
picture
.
filename
;
isOriginUpperLeft
=
picture
.
isOriginUpperLeft
;
for
(
int
col
=
0
;
col
<
width
();
col
++
)
for
(
int
row
=
0
;
row
<
height
();
row
++
)
image
.
setRGB
(
col
,
row
,
picture
.
image
.
getRGB
(
col
,
row
));
}
/**
* Creates a picture by reading an image from a file or URL.
*
*
@param
name the name of the file ( , .gif, or ) or URL.
*
@throws
IllegalArgumentException if cannot read image
*
@throws
IllegalArgumentException if {
@code
name} is {
@code
null}
*/
public
Picture
(
String
name
)
{
if
(
name
==
null
)
throw
new
IllegalArgumentException
(
"constructor argument is null"
);
this
.
filename
=
name
;
try
{
// try to read from file in working directory
File
file
=
new
File
(
name
);
if
(
file
.
isFile
())
{
image
=
ImageIO
.
read
(
file
);
}
else
{
// resource relative to .class file
URL url
=
getClass
().
getResource
(
filename
);
// resource relative to classloader root
if
(
url
==
null
)
{
url
=
getClass
().
getClassLoader
().
getResource
(
name
);
}
// or URL from web
if
(
url
==
null
)
{
url
=
new
URL
(
name
);
}
image
=
ImageIO
.
read
(
url
);
}
if
(
image
==
null
)
{
throw
new
IllegalArgumentException
(
"could not read image: "
+
name
);
}
width
=
image
.
getWidth
(
null
);
height
=
image
.
getHeight
(
null
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
"could not open image: "
+
name
,
ioe
);
}
}
/**
* Creates a picture by reading the image from a PNG, GIF, or JPEG file.
*
*
@param
file the file
*
@throws
IllegalArgumentException if cannot read image
*
@throws
IllegalArgumentException if {
@code
file} is {
@code
null}
*/
public
Picture
(
File
file
)
{
if
(
file
==
null
)
throw
new
IllegalArgumentException
(
"constructor argument is null"
);
try
{
image
=
ImageIO
.
read
(
file
);
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
"could not open file: "
+
file
,
ioe
);
}
if
(
image
==
null
)
{
throw
new
IllegalArgumentException
(
"could not read file: "
+
file
);
}
width
=
image
.
getWidth
(
null
);
height
=
image
.
getHeight
(
null
);
filename
=
file
.
getName
();
}
/**
* Returns a {
@link
JLabel} containing this picture, for embedding in a {
@link
JPanel},
* {
@link
JFrame} or other GUI widget.
*
*
@return
the {
@code
JLabel}
*/
public
JLabel
getJLabel
()
{
if
(
image
==
null
)
return
null
;
// no image available
ImageIcon
icon
=
new
ImageIcon
(
image
);
return
new
JLabel
(
icon
);
}
/**
* Sets the origin to be the upper left pixel. This is the default.
*/
public
void
setOriginUpperLeft
()
{
isOriginUpperLeft
=
true
;
}
/**
* Sets the origin to be the lower left pixel.
*/
public
void
setOriginLowerLeft
()
{
isOriginUpperLeft
=
false
;
}
/**
* Displays the picture in a window on the screen.
*/
public
void
show
()
{
// create the GUI for viewing the image if needed
if
(
frame
==
null
)
{
frame
=
new
JFrame
();
JMenuBar
menuBar
=
new
JMenuBar
();
JMenu
menu
=
new
JMenu
(
"File"
);
menuBar
.
add
(
menu
);
JMenuItem
menuItem1
=
new
JMenuItem
(
" Save... "
);
menuItem1
.
addActionListener
(
this
);
// use getMenuShortcutKeyMaskEx() in Java 10 (getMenuShortcutKeyMask() deprecated)
menuItem1
.
setAccelerator
(
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_S
,
Toolkit
.
getDefaultToolkit
().
getMenuShortcutKeyMask
()));
menu
.
add
(
menuItem1
);
frame
.
setJMenuBar
(
menuBar
);
frame
.
setContentPane
(
getJLabel
());
// f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame
.
setDefaultCloseOperation
(
JFrame
.
DISPOSE_ON_CLOSE
);
if
(
filename
==
null
)
frame
.
setTitle
(
width
+
"-by-"
+
height
);
else
frame
.
setTitle
(
filename
);
frame
.
setResizable
(
false
);
frame
.
pack
();
frame
.
setVisible
(
true
);
}
// draw
frame
.
repaint
();
}
/**
* Returns the height of the picture.
*
*
@return
the height of the picture (in pixels)
*/
public
int
height
()
{
return
height
;
}
/**
* Returns the width of the picture.
*
*
@return
the width of the picture (in pixels)
*/
public
int
width
()
{
return
width
;
}
private
void
validateRowIndex
(
int
row
)
{
if
(
row
<
0
||
row
>=
height
())
throw
new
IllegalArgumentException
(
“row index must be between 0 and ”
+
(
height
()
–
1
)
+
“: ”
+
row
);
}
private
void
validateColumnIndex
(
int
col
)
{
if
(
col
<
0
||
col
>=
width
())
throw
new
IllegalArgumentException
(
“column index must be between 0 and ”
+
(
width
()
–
1
)
+
“: ”
+
col
);
}
/**
* Returns the color of pixel ({
@code
col}, {
@code
row}) as a {
@link
java.awt.Color}.
*
*
@param
col the column index
*
@param
row the row index
*
@return
the color of pixel ({
@code
col}, {
@code
row})
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
Color
get
(
int
col
,
int
row
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
int
rgb
=
getRGB
(
col
,
row
);
return
new
Color
(
rgb
);
}
/**
* Returns the color of pixel ({
@code
col}, {
@code
row}) as an {
@code
int}.
* Using this method can be more efficient than {
@link
#get(int, int)} because
* it does not create a {
@code
Color} object.
*
*
@param
col the column index
*
@param
row the row index
*
@return
the integer representation of the color of pixel ({
@code
col}, {
@code
row})
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
int
getRGB
(
int
col
,
int
row
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
if
(
isOriginUpperLeft
)
return
image
.
getRGB
(
col
,
row
);
else
return
image
.
getRGB
(
col
,
height
-
row
-
1
);
}
/**
* Sets the color of pixel ({
@code
col}, {
@code
row}) to given color.
*
*
@param
col the column index
*
@param
row the row index
*
@param
color the color
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
void
set
(
int
col
,
int
row
,
Color
color
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
if
(
color
==
null
)
throw
new
IllegalArgumentException
(
"color argument is null"
);
int
rgb
=
color
.
getRGB
();
setRGB
(
col
,
row
,
rgb
);
}
/**
* Sets the color of pixel ({
@code
col}, {
@code
row}) to given color.
*
*
@param
col the column index
*
@param
row the row index
*
@param
rgb the integer representation of the color
*
@throws
IllegalArgumentException unless both {
@code
0 <= col < width} and {
@code
0 <= row < height}
*/
public
void
setRGB
(
int
col
,
int
row
,
int
rgb
)
{
validateColumnIndex
(
col
);
validateRowIndex
(
row
);
if
(
isOriginUpperLeft
)
image
.
setRGB
(
col
,
row
,
rgb
);
else
image
.
setRGB
(
col
,
height
-
row
-
1
,
rgb
);
}
/**
* Returns true if this picture is equal to the argument picture.
*
*
@param
other the other picture
*
@return
{
@code
true} if this picture is the same dimension as {
@code
other}
* and if all pixels have the same color; {
@code
false} otherwise
*/
public
boolean
equals
(
Object
other
)
{
if
(
other
==
this
)
return
true
;
if
(
other
==
null
)
return
false
;
if
(
other
.
getClass
()
!=
this
.
getClass
())
return
false
;
Picture
that
=
(
Picture
)
other
;
if
(
this
.
width
()
!=
that
.
width
())
return
false
;
if
(
this
.
height
()
!=
that
.
height
())
return
false
;
for
(
int
col
=
0
;
col
<
width
();
col
++
)
for
(
int
row
=
0
;
row
<
height
();
row
++
)
if
(
this
.
getRGB
(
col
,
row
)
!=
that
.
getRGB
(
col
,
row
))
return
false
;
return
true
;
}
/**
* Returns a string representation of this picture.
* The result is a width
-by-height
matrix of pixels,
* where the color of a pixel is represented using 6 hex digits to encode
* the red, green, and blue components.
*
*
@return
a string representation of this picture
*/
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
();
sb
.
append
(
width
+
“-by-”
+
height
+
” picture (RGB values given in hex)\n”
);
for
(
int
row
=
0
;
row
<
height
;
row
++
)
{
for
(
int
col
=
0
;
col
<
width
;
col
++
)
{
int
rgb
=
0
;
if
(
isOriginUpperLeft
)
rgb
=
image
.
getRGB
(
col
,
row
);
else
rgb
=
image
.
getRGB
(
col
,
height
-
row
-
1
);
sb
.
append
(
String
.
format
(
"#%06X "
,
rgb
&
0xFFFFFF
));
}
sb
.
append
(
"\n"
);
}
return
sb
.
toString
().
trim
();
}
/**
* This operation is not supported because pictures are mutable.
*
*
@return
does not return a value
*
@throws
UnsupportedOperationException if called
*/
public
int
hashCode
()
{
throw
new
UnsupportedOperationException
(
"hashCode() is not supported because pictures are mutable"
);
}
/**
* Saves the picture to a file in either PNG or JPEG format.
* The filetype extension must be either or .
*
*
@param
name the name of the file
*
@throws
IllegalArgumentException if {
@code
name} is {
@code
null}
*/
public
void
save
(
String
name
)
{
if
(
name
==
null
)
throw
new
IllegalArgumentException
(
"argument to save() is null"
);
save
(
new
File
(
name
));
filename
=
name
;
}
/**
* Saves the picture to a file in a PNG or JPEG image format.
*
*
@param
file the file
*
@throws
IllegalArgumentException if {
@code
file} is {
@code
null}
*/
public
void
save
(
File
file
)
{
if
(
file
==
null
)
throw
new
IllegalArgumentException
(
"argument to save() is null"
);
filename
=
file
.
getName
();
if
(
frame
!=
null
)
frame
.
setTitle
(
filename
);
String
suffix
=
filename
.
substring
(
filename
.
lastIndexOf
(
'.'
)
+
1
);
if
(
"jpg"
.
equalsIgnoreCase
(
suffix
)
||
"png"
.
equalsIgnoreCase
(
suffix
))
{
try
{
ImageIO
.
write
(
image
,
suffix
,
file
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
else
{
System
.
out
.
println
(
"Error: filename must end in or "
);
}
}
/**
* Opens a save dialog box when the user selects "Save As" from the menu.
*/
@
Override
public
void
actionPerformed
(
ActionEvent
e
)
{
FileDialog
chooser
=
new
FileDialog
(
frame
,
"Use a or extension"
,
FileDialog
.
SAVE
);
chooser
.
setVisible
(
true
);
if
(
chooser
.
getFile
()
!=
null
)
{
save
(
chooser
.
getDirectory
()
+
File
.
separator
+
chooser
.
getFile
());
}
}
/**
* Unit tests this {
@code
Picture} data type.
* Reads a picture specified by the command-line argument,
* and shows it in a window on the screen.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
Picture
picture
=
new
Picture
(
args
[
0
]);
System
.
out
.
printf
(
"%d-by-%d\n"
,
picture
.
width
(),
picture
.
height
());
picture
.
show
();
}
}
PlayMusic.java
PlayMusic.java
import
java
.
io
.
InputStream
;
import
java
.
io
.
IOException
;
import
java
.
applet
.
*
;
import
java
.
net
.
*
;
import
java
.
io
.
*
;
import
javax
.
sound
.
sampled
.
AudioFormat
;
import
javax
.
sound
.
sampled
.
AudioInputStream
;
import
javax
.
sound
.
sampled
.
AudioSystem
;
import
javax
.
sound
.
sampled
.
DataLine
;
import
javax
.
sound
.
sampled
.
LineUnavailableException
;
import
javax
.
sound
.
sampled
.
SourceDataLine
;
import
javax
.
sound
.
sampled
.
UnsupportedAudioFileException
;
public
class
PlayMusic
{
// play sound file using Applet.newAudioClip();
private
static
void
playApplet
(
String
filename
)
{
URL url
=
null
;
try
{
File
file
=
new
File
(
filename
);
if
(
file
.
canRead
())
url
=
file
.
toURI
().
toURL
();
}
catch
(
MalformedURLException
e
)
{
e
.
printStackTrace
();
}
// URL url = StdAudio.class.getResource(filename);
if
(
url
==
null
)
throw
new
RuntimeException
(
"audio "
+
filename
+
" not found"
);
AudioClip
clip
=
Applet
.
newAudioClip
(
url
);
clip
.
play
();
}
public
static
synchronized
void
play
(
final
String
filename
)
{
// code adapted from: http://stackoverflow.com/questions/26305/how-can-i-play-sound-in-java
try
{
System
.
out
.
println
(
"trying AudioSystem.getClip()"
);
// check if file format is supported
// (if not, will throw an UnsupportedAudioFileException)
InputStream
is
=
PlayMusic
.
class
.
getResourceAsStream
(
filename
);
AudioInputStream
ais
=
AudioSystem
.
getAudioInputStream
(
is
);
new
Thread
(
new
Runnable
()
{
@
Override
public
void
run
()
{
stream
(
filename
);
}
}).
start
();
}
// let's try Applet.newAudioClip() instead
catch
(
UnsupportedAudioFileException
e
)
{
System
.
out
.
println
(
"trying Applet.newAudioClip()"
);
playApplet
(
filename
);
System
.
out
.
println
(
"done 2"
);
return
;
}
// something else went wrong
catch
(
Exception
e
)
{
System
.
out
.
println
(
e
);
System
.
out
.
println
(
"Could not play "
+
filename
);
}
}
// https://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
// play a wav or aif file
// javax.sound.sampled.Clip fails for long clips (on some systems)
private
static
void
stream
(
String
filename
)
{
SourceDataLine
line
=
null
;
// int BUFFER_SIZE = 65526; // 64K buffer
int
BUFFER_SIZE
=
4096
;
// 4K buffer
try
{
InputStream
is
=
PlayMusic
.
class
.
getResourceAsStream
(
filename
);
AudioInputStream
ais
=
AudioSystem
.
getAudioInputStream
(
is
);
AudioFormat
audioFormat
=
ais
.
getFormat
();
DataLine
.
Info
info
=
new
DataLine
.
Info
(
SourceDataLine
.
class
,
audioFormat
);
line
=
(
SourceDataLine
)
AudioSystem
.
getLine
(
info
);
line
.
open
(
audioFormat
);
line
.
start
();
byte
[]
samples
=
new
byte
[
BUFFER_SIZE
];
int
count
=
0
;
while
((
count
=
ais
.
read
(
samples
,
0
,
BUFFER_SIZE
))
!=
-
1
)
{
line
.
write
(
samples
,
0
,
count
);
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
catch
(
UnsupportedAudioFileException
e
)
{
e
.
printStackTrace
();
}
catch
(
LineUnavailableException
e
)
{
e
.
printStackTrace
();
}
finally
{
if
(
line
!=
null
)
{
line
.
drain
();
line
.
close
();
}
}
}
public
static
void
main
(
String
[]
args
)
{
String
filename
=
args
[
0
];
play
(
filename
);
System
.
out
.
println
(
"done"
);
}
}
StdArrayIO.java
StdArrayIO.java
/******************************************************************************
* Compilation: javac StdArrayIO.java
* Execution: java StdArrayIO < input.txt
* Dependencies: StdOut.java
* Data files: https://introcs.cs.princeton.edu/java/22library/tinyDouble1D.txt
* https://introcs.cs.princeton.edu/java/22library/tinyDouble2D.txt
* https://introcs.cs.princeton.edu/java/22library/tinyBoolean2D.txt
*
* A library for reading in 1D and 2D arrays of integers, doubles,
* and booleans from standard input and printing them out to
* standard output.
*
* % more tinyDouble1D.txt
* 4
* .000 .246 .222 -.032
*
* % more tinyDouble2D.txt
* 4 3
* .000 .270 .000
* .246 .224 -.036
* .222 .176 .0893
* -.032 .739 .270
*
* % more tinyBoolean2D.txt
* 4 3
* 1 1 0
* 0 0 0
* 0 1 1
* 1 1 1
*
* % cat tinyDouble1D.txt tinyDouble2D.txt tinyBoolean2D.txt | java StdArrayIO
* 4
* 0.00000 0.24600 0.22200 -0.03200
*
* 4 3
* 0.00000 0.27000 0.00000
* 0.24600 0.22400 -0.03600
* 0.22200 0.17600 0.08930
* 0.03200 0.73900 0.27000
*
* 4 3
* 1 1 0
* 0 0 0
* 0 1 1
* 1 1 1
*
******************************************************************************/
/**
* Standard array IO. This class provides methods for reading
* in 1D and 2D arrays from standard input and printing out to
* standard output.
*
* For additional documentation, see
* Section 2.2 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
class
StdArrayIO
{
// it doesn’t make sense to instantiate this class
private
StdArrayIO
()
{
}
/**
* Reads a 1D array of doubles from standard input and returns it.
*
*
@return
the 1D array of doubles
*/
public
static
double
[]
readDouble1D
()
{
int
n
=
StdIn
.
readInt
();
double
[]
a
=
new
double
[
n
];
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
a
[
i
]
=
StdIn
.
readDouble
();
}
return
a
;
}
/**
* Prints an array of doubles to standard output.
*
*
@param
a the 1D array of doubles
*/
public
static
void
print
(
double
[]
a
)
{
int
n
=
a
.
length
;
StdOut
.
println
(
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
StdOut
.
printf
(
"%9.5f "
,
a
[
i
]);
}
StdOut
.
println
();
}
/**
* Reads a 2D array of doubles from standard input and returns it.
*
*
@return
the 2D array of doubles
*/
public
static
double
[][]
readDouble2D
()
{
int
m
=
StdIn
.
readInt
();
int
n
=
StdIn
.
readInt
();
double
[][]
a
=
new
double
[
m
][
n
];
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
a
[
i
][
j
]
=
StdIn
.
readDouble
();
}
}
return
a
;
}
/**
* Prints the 2D array of doubles to standard output.
*
*
@param
a the 2D array of doubles
*/
public
static
void
print
(
double
[][]
a
)
{
int
m
=
a
.
length
;
int
n
=
a
[
0
].
length
;
StdOut
.
println
(
m
+
" "
+
n
);
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
StdOut
.
printf
(
"%9.5f "
,
a
[
i
][
j
]);
}
StdOut
.
println
();
}
}
/**
* Reads a 1D array of integers from standard input and returns it.
*
*
@return
the 1D array of integers
*/
public
static
int
[]
readInt1D
()
{
int
n
=
StdIn
.
readInt
();
int
[]
a
=
new
int
[
n
];
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
a
[
i
]
=
StdIn
.
readInt
();
}
return
a
;
}
/**
* Prints an array of integers to standard output.
*
*
@param
a the 1D array of integers
*/
public
static
void
print
(
int
[]
a
)
{
int
n
=
a
.
length
;
StdOut
.
println
(
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
StdOut
.
printf
(
"%9d "
,
a
[
i
]);
}
StdOut
.
println
();
}
/**
* Reads a 2D array of integers from standard input and returns it.
*
*
@return
the 2D array of integers
*/
public
static
int
[][]
readInt2D
()
{
int
m
=
StdIn
.
readInt
();
int
n
=
StdIn
.
readInt
();
int
[][]
a
=
new
int
[
m
][
n
];
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
a
[
i
][
j
]
=
StdIn
.
readInt
();
}
}
return
a
;
}
/**
* Print a 2D array of integers to standard output.
*
*
@param
a the 2D array of integers
*/
public
static
void
print
(
int
[][]
a
)
{
int
m
=
a
.
length
;
int
n
=
a
[
0
].
length
;
StdOut
.
println
(
m
+
" "
+
n
);
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
StdOut
.
printf
(
"%9d "
,
a
[
i
][
j
]);
}
StdOut
.
println
();
}
}
/**
* Reads a 1D array of booleans from standard input and returns it.
*
*
@return
the 1D array of booleans
*/
public
static
boolean
[]
readBoolean1D
()
{
int
n
=
StdIn
.
readInt
();
boolean
[]
a
=
new
boolean
[
n
];
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
a
[
i
]
=
StdIn
.
readBoolean
();
}
return
a
;
}
/**
* Prints a 1D array of booleans to standard output.
*
*
@param
a the 1D array of booleans
*/
public
static
void
print
(
boolean
[]
a
)
{
int
n
=
a
.
length
;
StdOut
.
println
(
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
if
(
a
[
i
])
StdOut
.
print
(
"1 "
);
else
StdOut
.
print
(
"0 "
);
}
StdOut
.
println
();
}
/**
* Reads a 2D array of booleans from standard input and returns it.
*
*
@return
the 2D array of booleans
*/
public
static
boolean
[][]
readBoolean2D
()
{
int
m
=
StdIn
.
readInt
();
int
n
=
StdIn
.
readInt
();
boolean
[][]
a
=
new
boolean
[
m
][
n
];
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
a
[
i
][
j
]
=
StdIn
.
readBoolean
();
}
}
return
a
;
}
/**
* Prints a 2D array of booleans to standard output.
*
*
@param
a the 2D array of booleans
*/
public
static
void
print
(
boolean
[][]
a
)
{
int
m
=
a
.
length
;
int
n
=
a
[
0
].
length
;
StdOut
.
println
(
m
+
" "
+
n
);
for
(
int
i
=
0
;
i
<
m
;
i
++
)
{
for
(
int
j
=
0
;
j
<
n
;
j
++
)
{
if
(
a
[
i
][
j
])
StdOut
.
print
(
"1 "
);
else
StdOut
.
print
(
"0 "
);
}
StdOut
.
println
();
}
}
/**
* Unit tests {
@code
StdArrayIO}.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// read and print an array of doubles
double
[]
a
=
StdArrayIO
.
readDouble1D
();
StdArrayIO
.
print
(
a
);
StdOut
.
println
();
// read and print a matrix of doubles
double
[][]
b
=
StdArrayIO
.
readDouble2D
();
StdArrayIO
.
print
(
b
);
StdOut
.
println
();
// read and print a matrix of doubles
boolean
[][]
d
=
StdArrayIO
.
readBoolean2D
();
StdArrayIO
.
print
(
d
);
StdOut
.
println
();
}
}
StdAudio.java
StdAudio.java
/******************************************************************************
* Compilation: javac StdAudio.java
* Execution: java StdAudio
* Dependencies: none
*
* Simple library for reading, writing, and manipulating .wav files.
*
*
* Limitations
* -----------
* - Assumes the audio is monaural, little endian, with sampling rate
* of 44,100
* - check when reading .wav files from a .jar file ?
*
******************************************************************************/
import
javax
.
sound
.
sampled
.
Clip
;
import
java
.
io
.
File
;
import
java
.
io
.
ByteArrayInputStream
;
import
java
.
io
.
InputStream
;
import
java
.
io
.
IOException
;
import
java
.
net
.
URL
;
import
javax
.
sound
.
sampled
.
AudioFileFormat
;
import
javax
.
sound
.
sampled
.
AudioFormat
;
import
javax
.
sound
.
sampled
.
AudioInputStream
;
import
javax
.
sound
.
sampled
.
AudioSystem
;
import
javax
.
sound
.
sampled
.
DataLine
;
import
javax
.
sound
.
sampled
.
LineUnavailableException
;
import
javax
.
sound
.
sampled
.
SourceDataLine
;
import
javax
.
sound
.
sampled
.
UnsupportedAudioFileException
;
import
javax
.
sound
.
sampled
.
LineListener
;
import
javax
.
sound
.
sampled
.
LineEvent
;
/**
* Standard audio. This class provides a basic capability for
* creating, reading, and saving audio.
*
* The audio format uses a sampling rate of 44,100 Hz, 16-bit, monaural.
*
*
* For additional documentation, see Section 1.5 of
* Computer Science: An Interdisciplinary Approach by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
StdAudio
{
/**
* The sample rate: 44,100 Hz for CD quality audio.
*/
public
static
final
int
SAMPLE_RATE
=
44100
;
private
static
final
int
BYTES_PER_SAMPLE
=
2
;
// 16-bit audio
private
static
final
int
BITS_PER_SAMPLE
=
16
;
// 16-bit audio
private
static
final
double
MAX_16_BIT
=
32768
;
private
static
final
int
SAMPLE_BUFFER_SIZE
=
4096
;
private
static
final
int
MONO
=
1
;
private
static
final
int
STEREO
=
2
;
private
static
final
boolean
LITTLE_ENDIAN
=
false
;
private
static
final
boolean
BIG_ENDIAN
=
true
;
private
static
final
boolean
SIGNED
=
true
;
private
static
final
boolean
UNSIGNED
=
false
;
private
static
SourceDataLine
line
;
// to play the sound
private
static
byte
[]
buffer
;
// our internal buffer
private
static
int
bufferSize
=
0
;
// number of samples currently in internal buffer
private
StdAudio
()
{
// can not instantiate
}
// static initializer
static
{
init
();
}
// open up an audio stream
private
static
void
init
()
{
try
{
// 44,100 Hz, 16-bit audio, mono, signed PCM, little endian
AudioFormat
format
=
new
AudioFormat
((
float
)
SAMPLE_RATE
,
BITS_PER_SAMPLE
,
MONO
,
SIGNED
,
LITTLE_ENDIAN
);
DataLine
.
Info
info
=
new
DataLine
.
Info
(
SourceDataLine
.
class
,
format
);
line
=
(
SourceDataLine
)
AudioSystem
.
getLine
(
info
);
line
.
open
(
format
,
SAMPLE_BUFFER_SIZE
*
BYTES_PER_SAMPLE
);
// the internal buffer is a fraction of the actual buffer size, this choice is arbitrary
// it gets divided because we can’t expect the buffered data to line up exactly with when
// the sound card decides to push out its samples.
buffer
=
new
byte
[
SAMPLE_BUFFER_SIZE
*
BYTES_PER_SAMPLE
/
3
];
}
catch
(
LineUnavailableException
e
)
{
System
.
out
.
println
(
e
.
getMessage
());
}
// no sound gets made before this call
line
.
start
();
}
// get an AudioInputStream object from a file
private
static
AudioInputStream
getAudioInputStreamFromFile
(
String
filename
)
{
if
(
filename
==
null
)
{
throw
new
IllegalArgumentException
(
“filename is null”
);
}
try
{
// first try to read file from local file system
File
file
=
new
File
(
filename
);
if
(
file
.
exists
())
{
return
AudioSystem
.
getAudioInputStream
(
file
);
}
// resource relative to .class file
InputStream
is1
=
StdAudio
.
class
.
getResourceAsStream
(
filename
);
if
(
is1
!=
null
)
{
return
AudioSystem
.
getAudioInputStream
(
is1
);
}
// resource relative to classloader root
InputStream
is2
=
StdAudio
.
class
.
getClassLoader
().
getResourceAsStream
(
filename
);
if
(
is2
!=
null
)
{
return
AudioSystem
.
getAudioInputStream
(
is2
);
}
// give up
else
{
throw
new
IllegalArgumentException
(
“could not read ‘”
+
filename
+
“‘”
);
}
}
catch
(
IOException
e
)
{
throw
new
IllegalArgumentException
(
“could not read ‘”
+
filename
+
“‘”
,
e
);
}
catch
(
UnsupportedAudioFileException
e
)
{
throw
new
IllegalArgumentException
(
“file of unsupported audio format: ‘”
+
filename
+
“‘”
,
e
);
}
}
/**
* Closes standard audio.
*/
public
static
void
close
()
{
line
.
drain
();
line
.
stop
();
}
/**
* Writes one sample (between -1.0 and +1.0) to standard audio.
* If the sample is outside the range, it will be clipped.
*
*
@param
sample the sample to play
*
@throws
IllegalArgumentException if the sample is {
@code
Double.NaN}
*/
public
static
void
play
(
double
sample
)
{
if
(
Double
.
isNaN
(
sample
))
throw
new
IllegalArgumentException
(
“sample is NaN”
);
// clip if outside [-1, +1]
if
(
sample
<
-
1.0
)
sample
=
-
1.0
;
if
(
sample
>
+
1.0
)
sample
=
+
1.0
;
// convert to bytes
short
s
=
(
short
)
(
MAX_16_BIT
*
sample
);
if
(
sample
==
1.0
)
s
=
Short
.
MAX_VALUE
;
// special case since 32768 not a short
buffer
[
bufferSize
++
]
=
(
byte
)
s
;
buffer
[
bufferSize
++
]
=
(
byte
)
(
s
>>
8
);
// little endian
// send to sound card if buffer is full
if
(
bufferSize
>=
buffer
.
length
)
{
line
.
write
(
buffer
,
0
,
buffer
.
length
);
bufferSize
=
0
;
}
}
/**
* Writes the array of samples (between -1.0 and +1.0) to standard audio.
* If a sample is outside the range, it will be clipped.
*
*
@param
samples the array of samples to play
*
@throws
IllegalArgumentException if any sample is {
@code
Double.NaN}
*
@throws
IllegalArgumentException if {
@code
samples} is {
@code
null}
*/
public
static
void
play
(
double
[]
samples
)
{
if
(
samples
==
null
)
throw
new
IllegalArgumentException
(
“argument to play() is null”
);
for
(
int
i
=
0
;
i
<
samples
.
length
;
i
++
)
{
play
(
samples
[
i
]);
}
}
/**
* Reads audio samples from a file (in .wav or .au format) and returns
* them as a double array with values between -1.0 and +1.0.
* The audio file must be 16-bit with a sampling rate of 44,100.
* It can be mono or stereo.
*
*
@param
filename the name of the audio file
*
@return
the array of samples
*/
public
static
double
[]
read
(
String
filename
)
{
// make sure that AudioFormat is 16-bit, 44,100 Hz, little endian
final
AudioInputStream
ais
=
getAudioInputStreamFromFile
(
filename
);
AudioFormat
audioFormat
=
ais
.
getFormat
();
// require sampling rate = 44,100 Hz
if
(
audioFormat
.
getSampleRate
()
!=
SAMPLE_RATE
)
{
throw
new
IllegalArgumentException
(
"StdAudio.read() currently supports only a sample rate of "
+
SAMPLE_RATE
+
" Hz\n"
+
"audio format: "
+
audioFormat
);
}
// require 16-bit audio
if
(
audioFormat
.
getSampleSizeInBits
()
!=
BITS_PER_SAMPLE
)
{
throw
new
IllegalArgumentException
(
"StdAudio.read() currently supports only "
+
BITS_PER_SAMPLE
+
"-bit audio\n"
+
"audio format: "
+
audioFormat
);
}
// require little endian
if
(
audioFormat
.
isBigEndian
())
{
throw
new
IllegalArgumentException
(
"StdAudio.read() currently supports only audio stored using little endian\n"
+
"audio format: "
+
audioFormat
);
}
byte
[]
bytes
=
null
;
try
{
int
bytesToRead
=
ais
.
available
();
bytes
=
new
byte
[
bytesToRead
];
int
bytesRead
=
ais
.
read
(
bytes
);
if
(
bytesToRead
!=
bytesRead
)
{
throw
new
IllegalStateException
(
"read only "
+
bytesRead
+
" of "
+
bytesToRead
+
" bytes"
);
}
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
"could not read '"
+
filename
+
"'"
,
ioe
);
}
int
n
=
bytes
.
length
;
// little endian, mono
if
(
audioFormat
.
getChannels
()
==
MONO
)
{
double
[]
data
=
new
double
[
n
/
2
];
for
(
int
i
=
0
;
i
<
n
/
2
;
i
++
)
{
// little endian, mono
data
[
i
]
=
((
short
)
(((
bytes
[
2
*
i
+
1
]
&
0xFF
)
<<
8
)
|
(
bytes
[
2
*
i
]
&
0xFF
)))
/
((
double
)
MAX_16_BIT
);
}
return
data
;
}
// little endian, stereo
else
if
(
audioFormat
.
getChannels
()
==
STEREO
)
{
double
[]
data
=
new
double
[
n
/
4
];
for
(
int
i
=
0
;
i
<
n
/
4
;
i
++
)
{
double
left
=
((
short
)
(((
bytes
[
4
*
i
+
1
]
&
0xFF
)
<<
8
)
|
(
bytes
[
4
*
i
+
0
]
&
0xFF
)))
/
((
double
)
MAX_16_BIT
);
double
right
=
((
short
)
(((
bytes
[
4
*
i
+
3
]
&
0xFF
)
<<
8
)
|
(
bytes
[
4
*
i
+
2
]
&
0xFF
)))
/
((
double
)
MAX_16_BIT
);
data
[
i
]
=
(
left
+
right
)
/
2.0
;
}
return
data
;
}
// TODO: handle big endian (or other formats)
else
throw
new
IllegalStateException
(
"audio format is neither mono or stereo"
);
}
/**
* Saves the double array as an audio file (using .wav or .au format).
*
*
@param
filename the name of the audio file
*
@param
samples the array of samples
*
@throws
IllegalArgumentException if unable to save {
@code
filename}
*
@throws
IllegalArgumentException if {
@code
samples} is {
@code
null}
*
@throws
IllegalArgumentException if {
@code
filename} is {
@code
null}
*
@throws
IllegalArgumentException if {
@code
filename} extension is not {
@code
.wav}
* or {
@code
.au}
*/
public
static
void
save
(
String
filename
,
double
[]
samples
)
{
if
(
filename
==
null
)
{
throw
new
IllegalArgumentException
(
"filenameis null"
);
}
if
(
samples
==
null
)
{
throw
new
IllegalArgumentException
(
"samples[] is null"
);
}
// assumes 16-bit samples with sample rate = 44,100 Hz
// use 16-bit audio, mono, signed PCM, little Endian
AudioFormat
format
=
new
AudioFormat
(
SAMPLE_RATE
,
16
,
MONO
,
SIGNED
,
LITTLE_ENDIAN
);
byte
[]
data
=
new
byte
[
2
*
samples
.
length
];
for
(
int
i
=
0
;
i
<
samples
.
length
;
i
++
)
{
int
temp
=
(
short
)
(
samples
[
i
]
*
MAX_16_BIT
);
if
(
samples
[
i
]
==
1.0
)
temp
=
Short
.
MAX_VALUE
;
// special case since 32768 not a short
data
[
2
*
i
+
0
]
=
(
byte
)
temp
;
data
[
2
*
i
+
1
]
=
(
byte
)
(
temp
>>
8
);
// little endian
}
// now save the file
try
{
ByteArrayInputStream
bais
=
new
ByteArrayInputStream
(
data
);
AudioInputStream
ais
=
new
AudioInputStream
(
bais
,
format
,
samples
.
length
);
if
(
filename
.
endsWith
(
“.wav”
)
||
filename
.
endsWith
(
“.WAV”
))
{
AudioSystem
.
write
(
ais
,
AudioFileFormat
.
Type
.
WAVE
,
new
File
(
filename
));
}
else
if
(
filename
.
endsWith
(
“.au”
)
||
filename
.
endsWith
(
“.AU”
))
{
AudioSystem
.
write
(
ais
,
AudioFileFormat
.
Type
.
AU
,
new
File
(
filename
));
}
else
{
throw
new
IllegalArgumentException
(
“file type for saving must be .wav or .au”
);
}
}
catch
(
IOException
ioe
)
{
throw
new
IllegalArgumentException
(
“unable to save file ‘”
+
filename
+
“‘”
,
ioe
);
}
}
/**
* Plays an audio file (in .wav, .mid, or .au format) in a background thread.
*
*
@param
filename the name of the audio file
*
@throws
IllegalArgumentException if unable to play {
@code
filename}
*
@throws
IllegalArgumentException if {
@code
filename} is {
@code
null}
*/
public
static
synchronized
void
play
(
final
String
filename
)
{
new
Thread
(
new
Runnable
()
{
public
void
run
()
{
AudioInputStream
ais
=
getAudioInputStreamFromFile
(
filename
);
stream
(
ais
);
}
}).
start
();
}
// https://www3.ntu.edu.sg/home/ehchua/programming/java/J8c_PlayingSound.html
// play a wav or aif file
// javax.sound.sampled.Clip fails for long clips (on some systems), perhaps because
// JVM closes (see remedy in loop)
private
static
void
stream
(
AudioInputStream
ais
)
{
SourceDataLine
line
=
null
;
int
BUFFER_SIZE
=
4096
;
// 4K buffer
try
{
AudioFormat
audioFormat
=
ais
.
getFormat
();
DataLine
.
Info
info
=
new
DataLine
.
Info
(
SourceDataLine
.
class
,
audioFormat
);
line
=
(
SourceDataLine
)
AudioSystem
.
getLine
(
info
);
line
.
open
(
audioFormat
);
line
.
start
();
byte
[]
samples
=
new
byte
[
BUFFER_SIZE
];
int
count
=
0
;
while
((
count
=
ais
.
read
(
samples
,
0
,
BUFFER_SIZE
))
!=
–
1
)
{
line
.
write
(
samples
,
0
,
count
);
}
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
catch
(
LineUnavailableException
e
)
{
e
.
printStackTrace
();
}
finally
{
if
(
line
!=
null
)
{
line
.
drain
();
line
.
close
();
}
}
}
/**
* Loops an audio file (in .wav, .mid, or .au format) in a background thread.
*
*
@param
filename the name of the audio file
*
@throws
IllegalArgumentException if {
@code
filename} is {
@code
null}
*/
public
static
synchronized
void
loop
(
String
filename
)
{
if
(
filename
==
null
)
throw
new
IllegalArgumentException
();
final
AudioInputStream
ais
=
getAudioInputStreamFromFile
(
filename
);
try
{
Clip
clip
=
AudioSystem
.
getClip
();
// Clip clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
clip
.
open
(
ais
);
clip
.
loop
(
Clip
.
LOOP_CONTINUOUSLY
);
}
catch
(
LineUnavailableException
e
)
{
e
.
printStackTrace
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
// keep JVM open
new
Thread
(
new
Runnable
()
{
public
void
run
()
{
while
(
true
)
{
try
{
Thread
.
sleep
(
1000
);
}
catch
(
InterruptedException
e
)
{
e
.
printStackTrace
();
}
}
}
}).
start
();
}
/***************************************************************************
* Unit tests {
@code
StdAudio}.
***************************************************************************/
// create a note (sine wave) of the given frequency (Hz), for the given
// duration (seconds) scaled to the given volume (amplitude)
private
static
double
[]
note
(
double
hz
,
double
duration
,
double
amplitude
)
{
int
n
=
(
int
)
(
StdAudio
.
SAMPLE_RATE
*
duration
);
double
[]
a
=
new
double
[
n
+
1
];
for
(
int
i
=
0
;
i
<=
n
;
i
++
)
a
[
i
]
=
amplitude
*
Math
.
sin
(
2
*
Math
.
PI
*
i
*
hz
/
StdAudio
.
SAMPLE_RATE
);
return
a
;
}
/**
* Test client - play an A major scale to standard audio.
*
*
@param
args the command-line arguments
*/
/**
* Test client - play an A major scale to standard audio.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// 440 Hz for 1 sec
double
freq
=
440.0
;
for
(
int
i
=
0
;
i
<=
StdAudio
.
SAMPLE_RATE
;
i
++
)
{
StdAudio
.
play
(
0.5
*
Math
.
sin
(
2
*
Math
.
PI
*
freq
*
i
/
StdAudio
.
SAMPLE_RATE
));
}
// scale increments
int
[]
steps
=
{
0
,
2
,
4
,
5
,
7
,
9
,
11
,
12
};
for
(
int
i
=
0
;
i
<
steps
.
length
;
i
++
)
{
double
hz
=
440.0
*
Math
.
pow
(
2
,
steps
[
i
]
/
12.0
);
StdAudio
.
play
(
note
(
hz
,
1.0
,
0.5
));
}
// need to call this in non-interactive stuff so the program doesn't terminate
// until all the sound leaves the speaker.
StdAudio
.
close
();
}
}
StdDraw.java
StdDraw.java
/******************************************************************************
* Compilation: javac StdDraw.java
* Execution: java StdDraw
* Dependencies: none
*
* Standard drawing library. This class provides a basic capability for
* creating drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, and curves
* in a window on your computer and to save the drawings to a file.
*
* Todo
* ----
* - Add support for gradient fill, etc.
* - Fix setCanvasSize() so that it can only be called once.
* - On some systems, drawing a line (or other shape) that extends way
* beyond canvas (e.g., to infinity) dimensions does not get drawn.
*
* Remarks
* -------
* - don't use AffineTransform for rescaling since it inverts
* images and strings
*
******************************************************************************/
import
java
.
awt
.
BasicStroke
;
import
java
.
awt
.
Color
;
import
java
.
awt
.
Component
;
import
java
.
awt
.
FileDialog
;
import
java
.
awt
.
Font
;
import
java
.
awt
.
FontMetrics
;
import
java
.
awt
.
Graphics
;
import
java
.
awt
.
Graphics2D
;
import
java
.
awt
.
Image
;
import
java
.
awt
.
MediaTracker
;
import
java
.
awt
.
RenderingHints
;
import
java
.
awt
.
Toolkit
;
import
java
.
awt
.
event
.
ActionEvent
;
import
java
.
awt
.
event
.
ActionListener
;
import
java
.
awt
.
event
.
MouseEvent
;
import
java
.
awt
.
event
.
MouseListener
;
import
java
.
awt
.
event
.
MouseMotionListener
;
import
java
.
awt
.
event
.
KeyEvent
;
import
java
.
awt
.
event
.
KeyListener
;
import
java
.
awt
.
geom
.
Arc2D
;
import
java
.
awt
.
geom
.
Ellipse2D
;
import
java
.
awt
.
geom
.
GeneralPath
;
import
java
.
awt
.
geom
.
Line2D
;
import
java
.
awt
.
geom
.
Rectangle2D
;
import
java
.
awt
.
image
.
BufferedImage
;
import
java
.
awt
.
image
.
DirectColorModel
;
import
java
.
awt
.
image
.
WritableRaster
;
import
java
.
io
.
File
;
import
java
.
io
.
IOException
;
import
java
.
net
.
MalformedURLException
;
import
java
.
net
.
URL
;
import
java
.
util
.
LinkedList
;
import
java
.
util
.
TreeSet
;
import
java
.
util
.
NoSuchElementException
;
import
javax
.
imageio
.
ImageIO
;
import
javax
.
swing
.
ImageIcon
;
import
javax
.
swing
.
JFrame
;
import
javax
.
swing
.
JLabel
;
import
javax
.
swing
.
JMenu
;
import
javax
.
swing
.
JMenuBar
;
import
javax
.
swing
.
JMenuItem
;
import
javax
.
swing
.
KeyStroke
;
/**
* The {
@code
StdDraw} class provides a basic capability for
* creating drawings with your programs. It uses a simple graphics model that
* allows you to create drawings consisting of points, lines, squares,
* circles, and other geometric shapes in a window on your computer and
* to save the drawings to a file. Standard drawing also includes
* facilities for text, color, pictures, and animation, along with
* user interaction via the keyboard and mouse.
*
* Getting started.
* To use this class, you must have {
@code
StdDraw.class} in your
* Java classpath. If you used our autoinstaller, you should be all set.
* Otherwise, either download
* and add to your Java classpath or download
* and put a copy in your working directory.
*
* Now, type the following short program into your editor:
*
* public class TestStdDraw { * public static void main(String[] args) { * StdDraw.setPenRadius(0.05); * StdDraw.setPenColor(StdDraw.BLUE); * StdDraw.point(0.5, 0.5); * StdDraw.setPenColor(StdDraw.MAGENTA); * StdDraw.line(0.2, 0.2, 0.8, 0.2); * } * } *
* If you compile and execute the program, you should see a window
* appear with a thick magenta line and a blue point.
* This program illustrates the two main types of methods in standard
* drawing—methods that draw geometric shapes and methods that
* control drawing parameters.
* The methods {
@code
StdDraw.line()} and {
@code
StdDraw.point()}
* draw lines and points; the methods {
@code
StdDraw.setPenRadius()}
* and {
@code
StdDraw.setPenColor()} control the line thickness and color.
*
* Points and lines.
* You can draw points and line segments with the following methods:
*
- {
@link
#point(double x, double y)}*
- {
@link
#line(double x1, double y1, double x2, double y2)}*
*
*
* The x– and y-coordinates must be in the drawing area
* (between 0 and 1 and by default) or the points and lines will not be visible.
*
* Squares, circles, rectangles, and ellipses.
* You can draw squares, circles, rectangles, and ellipses using
* the following methods:
*
- {
@link
#circle(double x, double y, double radius)}*
- {
@link
#ellipse(double x, double y, double semiMajorAxis, double semiMinorAxis)}*
- {
@link
#square(double x, double y, double halfLength)}*
- {
@link
#rectangle(double x, double y, double halfWidth, double halfHeight)}*
*
*
* All of these methods take as arguments the location and size of the shape.
* The location is always specified by the x– and y-coordinates
* of its center.
* The size of a circle is specified by its radius and the size of an ellipse is
* specified by the lengths of its semi-major and semi-minor axes.
* The size of a square or rectangle is specified by its half-width or half-height.
* The convention for drawing squares and rectangles is parallel to those for
* drawing circles and ellipses, but may be unexpected to the uninitiated.
*
* The methods above trace outlines of the given shapes. The following methods
* draw filled versions:
*
- {
@link
#filledCircle(double x, double y, double radius)}*
- {
@link
#filledEllipse(double x, double y, double semiMajorAxis, double semiMinorAxis)}*
- {
@link
#filledSquare(double x, double y, double radius)}*
- {
@link
#filledRectangle(double x, double y, double halfWidth, double halfHeight)}*
*
*
* Circular arcs.
* You can draw circular arcs with the following method:
*
- {
@link
#arc(double x, double y, double radius, double angle1, double angle2)}*
*
*
* The arc is from the circle centered at (x, y) of the specified radius.
* The arc extends from angle1 to angle2. By convention, the angles are
* polar (counterclockwise angle from the x-axis)
* and represented in degrees. For example, {
@code
StdDraw.arc(0.0, 0.0, 1.0, 0, 90)}
* draws the arc of the unit circle from 3 o’clock (0 degrees) to 12 o’clock (90 degrees).
*
* Polygons.
* You can draw polygons with the following methods:
*
- {
@link
#polygon(double[] x, double[] y)}*
- {
@link
#filledPolygon(double[] x, double[] y)}*
*
*
* The points in the polygon are ({
@code
x[i]}, {
@code
y[i]}).
* For example, the following code fragment draws a filled diamond
* with vertices (0.1, 0.2), (0.2, 0.3), (0.3, 0.2), and (0.2, 0.1):
*
* double[] x = { 0.1, 0.2, 0.3, 0.2 }; * double[] y = { 0.2, 0.3, 0.2, 0.1 }; * StdDraw.filledPolygon(x, y); *
*
* Pen size.
* The pen is circular, so that when you set the pen radius to r
* and draw a point, you get a circle of radius r. Also, lines are
* of thickness 2r and have rounded ends. The default pen radius
* is 0.005 and is not affected by coordinate scaling. This default pen
* radius is about 1/200 the width of the default canvas, so that if
* you draw 100 points equally spaced along a horizontal or vertical line,
* you will be able to see individual circles, but if you draw 200 such
* points, the result will look like a line.
*
- {
@link
#setPenRadius(double radius)}*
*
*
* For example, {
@code
StdDraw.setPenRadius(0.025)} makes
* the thickness of the lines and the size of the points to be five times
* the 0.005 default.
* To draw points with the minimum possible radius (one pixel on typical
* displays), set the pen radius to 0.0.
*
* Pen color.
* All geometric shapes (such as points, lines, and circles) are drawn using
* the current pen color. By default, it is black.
* You can change the pen color with the following methods:
*
- {
@link
#setPenColor(int red, int green, int blue)}*
- {
@link
#setPenColor(Color color)}*
*
*
* The first method allows you to specify colors using the RGB color system.
* This color picker
* is a convenient way to find a desired color.
* The second method allows you to specify colors using the
* {
@link
Color} data type that is discussed in Chapter 3. Until then,
* you can use this method with one of these predefined colors in standard drawing:
* {
@link
#BLACK}, {
@link
#BLUE}, {
@link
#CYAN}, {
@link
#DARK_GRAY}, {
@link
#GRAY},
* {
@link
#GREEN}, {
@link
#LIGHT_GRAY}, {
@link
#MAGENTA}, {
@link
#ORANGE},
* {
@link
#PINK}, {
@link
#RED}, {
@link
#WHITE}, {
@link
#YELLOW},
* {
@link
#BOOK_BLUE}, {
@link
#BOOK_LIGHT_BLUE}, {
@link
#BOOK_RED}, and
* {
@link
#PRINCETON_ORANGE}.
* For example, {
@code
StdDraw.setPenColor(StdDraw.MAGENTA)} sets the
* pen color to magenta.
*
* Canvas size.
* By default, all drawing takes places in a 512-by-512 canvas.
* The canvas does not include the window title or window border.
* You can change the size of the canvas with the following method:
*
- {
@link
#setCanvasSize(int width, int height)}*
*
*
* This sets the canvas size to be width-by-height pixels.
* It also erases the current drawing and resets the coordinate system,
* pen radius, pen color, and font back to their default values.
* Ordinarly, this method is called once, at the very beginning of a program.
* For example, {
@code
StdDraw.setCanvasSize(800, 800)}
* sets the canvas size to be 800-by-800 pixels.
*
* Canvas scale and coordinate system.
* By default, all drawing takes places in the unit square, with (0, 0) at
* lower left and (1, 1) at upper right. You can change the default
* coordinate system with the following methods:
*
- {
@link
#setXscale(double xmin, double xmax)}*
- {
@link
#setYscale(double ymin, double ymax)}*
- {
@link
#setScale(double min, double max)}*
*
*
* The arguments are the coordinates of the minimum and maximum
* x– or y-coordinates that will appear in the canvas.
* For example, if you wish to use the default coordinate system but
* leave a small margin, you can call {
@code
StdDraw.setScale(-.05, 1.05)}.
*
* These methods change the coordinate system for subsequent drawing
* commands; they do not affect previous drawings.
* These methods do not change the canvas size; so, if the x–
* and y-scales are different, squares will become rectangles
* and circles will become ellipses.
*
* Text.
* You can use the following methods to annotate your drawings with text:
*
- {
@link
#text(double x, double y, String text)}*
- {
@link
#text(double x, double y, String text, double degrees)}*
- {
@link
#textLeft(double x, double y, String text)}*
- {
@link
#textRight(double x, double y, String text)}*
*
*
* The first two methods write the specified text in the current font,
* centered at (x, y).
* The second method allows you to rotate the text.
* The last two methods either left- or right-align the text at (x, y).
*
* The default font is a Sans Serif font with point size 16.
* You can use the following method to change the font:
*
- {
@link
#setFont(Font font)}*
*
*
* You use the {
@link
Font} data type to specify the font. This allows you to
* choose the face, size, and style of the font. For example, the following
* code fragment sets the font to Arial Bold, 60 point.
*
* Font font = new Font("Arial", Font.BOLD, 60); * StdDraw.setFont(font); * StdDraw.text(0.5, 0.5, "Hello, World"); *
*
* Images.
* You can use the following methods to add images to your drawings:
*
- {
@link
#picture(double x, double y, String filename)}*
- {
@link
#picture(double x, double y, String filename, double degrees)}*
- {
@link
#picture(double x, double y, String filename, double scaledWidth, double scaledHeight)}*
- {
@link
#picture(double x, double y, String filename, double scaledWidth, double scaledHeight, double degrees)}*
*
*
* These methods draw the specified image, centered at (x, y).
* The supported image formats are JPEG, PNG, and GIF.
* The image will display at its native size, independent of the coordinate system.
* Optionally, you can rotate the image a specified number of degrees counterclockwise
* or rescale it to fit snugly inside a width-by-height bounding box.
*
* Saving to a file.
* You save your image to a file using the File → Save menu option.
* You can also save a file programatically using the following method:
*
- {
@link
#save(String filename)}*
*
*
* The supported image formats are JPEG and PNG. The filename must have either the
* extension or .
* We recommend using PNG for drawing that consist solely of geometric shapes and JPEG
* for drawings that contains pictures.
*
* Clearing the canvas.
* To clear the entire drawing canvas, you can use the following methods:
*
- {
@link
#clear()}*
- {
@link
#clear(Color color)}*
*
*
* The first method clears the canvas to white; the second method
* allows you to specify a color of your choice. For example,
* {
@code
StdDraw.clear(StdDraw.LIGHT_GRAY)} clears the canvas to a shade
* of gray.
*
* Computer animations and double buffering.
* Double buffering is one of the most powerful features of standard drawing,
* enabling computer animations.
* The following methods control the way in which objects are drawn:
*
- {
@link
#enableDoubleBuffering()}*
- {
@link
#disableDoubleBuffering()}*
- {
@link
#show()}*
- {
@link
#pause(int t)}*
*
*
* By default, double buffering is disabled, which means that as soon as you
* call a drawing
* method—such as {
@code
point()} or {
@code
line()}—the
* results appear on the screen.
*
* When double buffering is enabled by calling {
@link
#enableDoubleBuffering()},
* all drawing takes place on the offscreen canvas. The offscreen canvas
* is not displayed. Only when you call
* {
@link
#show()} does your drawing get copied from the offscreen canvas to
* the onscreen canvas, where it is displayed in the standard drawing window. You
* can think of double buffering as collecting all of the lines, points, shapes,
* and text that you tell it to draw, and then drawing them all
* simultaneously, upon request.
*
* The most important use of double buffering is to produce computer
* animations, creating the illusion of motion by rapidly
* displaying static drawings. To produce an animation, repeat
* the following four steps:
*
- Clear the offscreen canvas.
*
- Draw objects on the offscreen canvas.
*
- Copy the offscreen canvas to the onscreen canvas.
*
- Wait for a short while.
*
*
*
* The {
@link
#clear()}, {
@link
#show()}, and {
@link
#pause(int t)} methods
* support the first, third, and fourth of these steps, respectively.
*
* For example, this code fragment animates two balls moving in a circle.
*
* StdDraw.setScale(-2, +2); * StdDraw.enableDoubleBuffering(); * * for (double t = 0.0; true; t += 0.02) { * double x = Math.sin(t); * double y = Math.cos(t); * StdDraw.clear(); * StdDraw.filledCircle(x, y, 0.05); * StdDraw.filledCircle(-x, -y, 0.05); * StdDraw.show(); * StdDraw.pause(20); * } *
*
* Keyboard and mouse inputs.
* Standard drawing has very basic support for keyboard and mouse input.
* It is much less powerful than most user interface libraries provide, but also much simpler.
* You can use the following methods to intercept mouse events:
*
- {
@link
#isMousePressed()}*
- {
@link
#mouseX()}*
- {
@link
#mouseY()}*
*
*
* The first method tells you whether a mouse button is currently being pressed.
* The last two methods tells you the x– and y-coordinates of the mouse’s
* current position, using the same coordinate system as the canvas (the unit square, by default).
* You should use these methods in an animation loop that waits a short while before trying
* to poll the mouse for its current state.
* You can use the following methods to intercept keyboard events:
*
- {
@link
#hasNextKeyTyped()}*
- {
@link
#nextKeyTyped()}*
- {
@link
#isKeyPressed(int keycode)}*
*
*
* If the user types lots of keys, they will be saved in a list until you process them.
* The first method tells you whether the user has typed a key (that your program has
* not yet processed).
* The second method returns the next key that the user typed (that your program has
* not yet processed) and removes it from the list of saved keystrokes.
* The third method tells you whether a key is currently being pressed.
*
* Accessing control parameters.
* You can use the following methods to access the current pen color, pen radius,
* and font:
*
- {
@link
#getPenColor()}*
- {
@link
#getPenRadius()}*
- {
@link
#getFont()}*
*
*
* These methods are useful when you want to temporarily change a
* control parameter and reset it back to its original value.
*
* Corner cases.
* Here are some corner cases.
*
- Drawing an object outside (or partly outside) the canvas is permitted.
* However, only the part of the object that appears inside the canvas
* will be visible.
*
- Any method that is passed a {
@code
null} argument will throw an* {
@link
IllegalArgumentException}.*
- Any method that is passed a {
@link
Double#NaN},* {
@link
Double#POSITIVE_INFINITY}, or {
@link
Double#NEGATIVE_INFINITY}* argument will throw an {
@link
IllegalArgumentException}.*
- Due to floating-point issues, an object drawn with an x– or
* y-coordinate that is way outside the canvas (such as the line segment
* from (0.5, –10^308) to (0.5, 10^308) may not be visible even in the
* part of the canvas where it should be.
*
*
*
* Performance tricks.
* Standard drawing is capable of drawing large amounts of data.
* Here are a few tricks and tips:
*
- Use double buffering for static drawing with a large
* number of objects.
* That is, call {
@link
#enableDoubleBuffering()} before* the sequence of drawing commands and call {
@link
#show()} afterwards.* Incrementally displaying a complex drawing while it is being
* created can be intolerably inefficient on many computer systems.
*
- When drawing computer animations, call {
@code
show()}* only once per frame, not after drawing each individual object.
*
- If you call {
@code
picture()} multiple times with the same filename,* Java will cache the image, so you do not incur the cost of reading
* from a file each time.
*
*
*
* Known bugs and issues.
*
- The {
@code
picture()} methods may not draw the portion of the image that is* inside the canvas if the center point (x, y) is outside the
* canvas.
* This bug appears only on some systems.
*
*
*
* Reference.
* For additional documentation,
* see Section 1.5 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
StdDraw
implements
ActionListener
,
MouseListener
,
MouseMotionListener
,
KeyListener
{
/**
* The color black.
*/
public
static
final
Color
BLACK
=
Color
.
BLACK
;
/**
* The color blue.
*/
public
static
final
Color
BLUE
=
Color
.
BLUE
;
/**
* The color cyan.
*/
public
static
final
Color
CYAN
=
Color
.
CYAN
;
/**
* The color dark gray.
*/
public
static
final
Color
DARK_GRAY
=
Color
.
DARK_GRAY
;
/**
* The color gray.
*/
public
static
final
Color
GRAY
=
Color
.
GRAY
;
/**
* The color green.
*/
public
static
final
Color
GREEN
=
Color
.
GREEN
;
/**
* The color light gray.
*/
public
static
final
Color
LIGHT_GRAY
=
Color
.
LIGHT_GRAY
;
/**
* The color magenta.
*/
public
static
final
Color
MAGENTA
=
Color
.
MAGENTA
;
/**
* The color orange.
*/
public
static
final
Color
ORANGE
=
Color
.
ORANGE
;
/**
* The color pink.
*/
public
static
final
Color
PINK
=
Color
.
PINK
;
/**
* The color red.
*/
public
static
final
Color
RED
=
Color
.
RED
;
/**
* The color white.
*/
public
static
final
Color
WHITE
=
Color
.
WHITE
;
/**
* The color yellow.
*/
public
static
final
Color
YELLOW
=
Color
.
YELLOW
;
/**
* Shade of blue used in Introduction to Programming in Java.
* It is Pantone 300U. The RGB values are approximately (9, 90, 166).
*/
public
static
final
Color
BOOK_BLUE
=
new
Color
(
9
,
90
,
166
);
/**
* Shade of light blue used in Introduction to Programming in Java.
* The RGB values are approximately (103, 198, 243).
*/
public
static
final
Color
BOOK_LIGHT_BLUE
=
new
Color
(
103
,
198
,
243
);
/**
* Shade of red used in Algorithms, 4th edition.
* It is Pantone 1805U. The RGB values are approximately (150, 35, 31).
*/
public
static
final
Color
BOOK_RED
=
new
Color
(
150
,
35
,
31
);
/**
* Shade of orange used in Princeton University’s identity.
* It is PMS 158. The RGB values are approximately (245, 128, 37).
*/
public
static
final
Color
PRINCETON_ORANGE
=
new
Color
(
245
,
128
,
37
);
// default colors
private
static
final
Color
DEFAULT_PEN_COLOR
=
BLACK
;
private
static
final
Color
DEFAULT_CLEAR_COLOR
=
WHITE
;
// current pen color
private
static
Color
penColor
;
// default canvas size is DEFAULT_SIZE-by-DEFAULT_SIZE
private
static
final
int
DEFAULT_SIZE
=
512
;
private
static
int
width
=
DEFAULT_SIZE
;
private
static
int
height
=
DEFAULT_SIZE
;
// default pen radius
private
static
final
double
DEFAULT_PEN_RADIUS
=
0.002
;
// current pen radius
private
static
double
penRadius
;
// show we draw immediately or wait until next show?
private
static
boolean
defer
=
false
;
// boundary of drawing canvas, 0% border
// private static final double BORDER = 0.05;
private
static
final
double
BORDER
=
0.00
;
private
static
final
double
DEFAULT_XMIN
=
0.0
;
private
static
final
double
DEFAULT_XMAX
=
1.0
;
private
static
final
double
DEFAULT_YMIN
=
0.0
;
private
static
final
double
DEFAULT_YMAX
=
1.0
;
private
static
double
xmin
,
ymin
,
xmax
,
ymax
;
// for synchronization
private
static
Object
mouseLock
=
new
Object
();
private
static
Object
keyLock
=
new
Object
();
// default font
private
static
final
Font
DEFAULT_FONT
=
new
Font
(
“SansSerif”
,
Font
.
PLAIN
,
16
);
// current font
private
static
Font
font
;
// double buffered graphics
private
static
BufferedImage
offscreenImage
,
onscreenImage
;
private
static
Graphics2D
offscreen
,
onscreen
;
// singleton for callbacks: avoids generation of extra .class files
private
static
StdDraw
std
=
new
StdDraw
();
// the frame for drawing to the screen
private
static
JFrame
frame
;
// mouse state
private
static
boolean
isMousePressed
=
false
;
private
static
double
mouseX
=
0
;
private
static
double
mouseY
=
0
;
// queue of typed key characters
private
static
LinkedList
<
Character
>
keysTyped
=
new
LinkedList
<
Character
>
();
// set of key codes currently pressed down
private
static
TreeSet
<
Integer
>
keysDown
=
new
TreeSet
<
Integer
>
();
// singleton pattern: client can’t instantiate
private
StdDraw
()
{
}
// static initializer
static
{
init
();
}
/**
* Sets the canvas (drawing area) to be 512-by-512 pixels.
* This also erases the current drawing and resets the coordinate system,
* pen radius, pen color, and font back to their default values.
* Ordinarly, this method is called once, at the very beginning
* of a program.
*/
public
static
void
setCanvasSize
()
{
setCanvasSize
(
DEFAULT_SIZE
,
DEFAULT_SIZE
);
}
/**
* Sets the canvas (drawing area) to be width-by-height pixels.
* This also erases the current drawing and resets the coordinate system,
* pen radius, pen color, and font back to their default values.
* Ordinarly, this method is called once, at the very beginning
* of a program.
*
*
@param
canvasWidth the width as a number of pixels
*
@param
canvasHeight the height as a number of pixels
*
@throws
IllegalArgumentException unless both {
@code
canvasWidth} and
* {
@code
canvasHeight} are positive
*/
public
static
void
setCanvasSize
(
int
canvasWidth
,
int
canvasHeight
)
{
if
(
canvasWidth
<=
0
)
throw
new
IllegalArgumentException
(
"width must be positive"
);
if
(
canvasHeight
<=
0
)
throw
new
IllegalArgumentException
(
"height must be positive"
);
width
=
canvasWidth
;
height
=
canvasHeight
;
init
();
}
// init
private
static
void
init
()
{
if
(
frame
!=
null
)
frame
.
setVisible
(
false
);
frame
=
new
JFrame
();
offscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
onscreenImage
=
new
BufferedImage
(
2
*
width
,
2
*
height
,
BufferedImage
.
TYPE_INT_ARGB
);
offscreen
=
offscreenImage
.
createGraphics
();
onscreen
=
onscreenImage
.
createGraphics
();
offscreen
.
scale
(
2.0
,
2.0
);
// since we made it 2x as big
setXscale
();
setYscale
();
offscreen
.
setColor
(
DEFAULT_CLEAR_COLOR
);
offscreen
.
fillRect
(
0
,
0
,
width
,
height
);
setPenColor
();
setPenRadius
();
setFont
();
clear
();
// add antialiasing
RenderingHints
hints
=
new
RenderingHints
(
RenderingHints
.
KEY_ANTIALIASING
,
RenderingHints
.
VALUE_ANTIALIAS_ON
);
hints
.
put
(
RenderingHints
.
KEY_RENDERING
,
RenderingHints
.
VALUE_RENDER_QUALITY
);
offscreen
.
addRenderingHints
(
hints
);
// frame stuff
RetinaImageIcon
icon
=
new
RetinaImageIcon
(
onscreenImage
);
JLabel
draw
=
new
JLabel
(
icon
);
draw
.
addMouseListener
(
std
);
draw
.
addMouseMotionListener
(
std
);
frame
.
setContentPane
(
draw
);
frame
.
addKeyListener
(
std
);
// JLabel cannot get keyboard focus
frame
.
setFocusTraversalKeysEnabled
(
false
);
// allow VK_TAB with isKeyPressed()
frame
.
setResizable
(
false
);
frame
.
setDefaultCloseOperation
(
JFrame
.
EXIT_ON_CLOSE
);
// closes all windows
// frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // closes only current window
frame
.
setTitle
(
"Standard Draw"
);
frame
.
setJMenuBar
(
createMenuBar
());
frame
.
pack
();
frame
.
requestFocusInWindow
();
frame
.
setVisible
(
true
);
}
// create the menu bar (changed to private)
private
static
JMenuBar
createMenuBar
()
{
JMenuBar
menuBar
=
new
JMenuBar
();
JMenu
menu
=
new
JMenu
(
"File"
);
menuBar
.
add
(
menu
);
JMenuItem
menuItem1
=
new
JMenuItem
(
" Save... "
);
menuItem1
.
addActionListener
(
std
);
// Java 10+: replace getMenuShortcutKeyMask() with getMenuShortcutKeyMaskEx()
menuItem1
.
setAccelerator
(
KeyStroke
.
getKeyStroke
(
KeyEvent
.
VK_S
,
Toolkit
.
getDefaultToolkit
().
getMenuShortcutKeyMask
()));
menu
.
add
(
menuItem1
);
return
menuBar
;
}
/***************************************************************************
* User and screen coordinate systems.
***************************************************************************/
// throw an IllegalArgumentException if x is NaN or infinite
private
static
void
validate
(
double
x
,
String
name
)
{
if
(
Double
.
isNaN
(
x
))
throw
new
IllegalArgumentException
(
name
+
" is NaN"
);
if
(
Double
.
isInfinite
(
x
))
throw
new
IllegalArgumentException
(
name
+
" is infinite"
);
}
// throw an IllegalArgumentException if s is null
private
static
void
validateNonnegative
(
double
x
,
String
name
)
{
if
(
x
<
0
)
throw
new
IllegalArgumentException
(
name
+
" negative"
);
}
// throw an IllegalArgumentException if s is null
private
static
void
validateNotNull
(
Object
x
,
String
name
)
{
if
(
x
==
null
)
throw
new
IllegalArgumentException
(
name
+
" is null"
);
}
/**
* Sets the x-scale to be the default (between 0.0 and 1.0).
*/
public
static
void
setXscale
()
{
setXscale
(
DEFAULT_XMIN
,
DEFAULT_XMAX
);
}
/**
* Sets the y-scale to be the default (between 0.0 and 1.0).
*/
public
static
void
setYscale
()
{
setYscale
(
DEFAULT_YMIN
,
DEFAULT_YMAX
);
}
/**
* Sets the x-scale and y-scale to be the default
* (between 0.0 and 1.0).
*/
public
static
void
setScale
()
{
setXscale
();
setYscale
();
}
/**
* Sets the x-scale to the specified range.
*
*
@param
min the minimum value of the x-scale
*
@param
max the maximum value of the x-scale
*
@throws
IllegalArgumentException if {
@code
(max == min)}
*
@throws
IllegalArgumentException if either {
@code
min} or {
@code
max} is either NaN or infinite
*/
public
static
void
setXscale
(
double
min
,
double
max
)
{
validate
(
min
,
“min”
);
validate
(
max
,
“max”
);
double
size
=
max
–
min
;
if
(
size
==
0.0
)
throw
new
IllegalArgumentException
(
“the min and max are the same”
);
synchronized
(
mouseLock
)
{
xmin
=
min
–
BORDER
*
size
;
xmax
=
max
+
BORDER
*
size
;
}
}
/**
* Sets the y-scale to the specified range.
*
*
@param
min the minimum value of the y-scale
*
@param
max the maximum value of the y-scale
*
@throws
IllegalArgumentException if {
@code
(max == min)}
*
@throws
IllegalArgumentException if either {
@code
min} or {
@code
max} is either NaN or infinite
*/
public
static
void
setYscale
(
double
min
,
double
max
)
{
validate
(
min
,
“min”
);
validate
(
max
,
“max”
);
double
size
=
max
–
min
;
if
(
size
==
0.0
)
throw
new
IllegalArgumentException
(
“the min and max are the same”
);
synchronized
(
mouseLock
)
{
ymin
=
min
–
BORDER
*
size
;
ymax
=
max
+
BORDER
*
size
;
}
}
/**
* Sets both the x-scale and y-scale to the (same) specified range.
*
*
@param
min the minimum value of the x– and y-scales
*
@param
max the maximum value of the x– and y-scales
*
@throws
IllegalArgumentException if {
@code
(max == min)}
*
@throws
IllegalArgumentException if either {
@code
min} or {
@code
max} is either NaN or infinite
*/
public
static
void
setScale
(
double
min
,
double
max
)
{
validate
(
min
,
“min”
);
validate
(
max
,
“max”
);
double
size
=
max
–
min
;
if
(
size
==
0.0
)
throw
new
IllegalArgumentException
(
“the min and max are the same”
);
synchronized
(
mouseLock
)
{
xmin
=
min
–
BORDER
*
size
;
xmax
=
max
+
BORDER
*
size
;
ymin
=
min
–
BORDER
*
size
;
ymax
=
max
+
BORDER
*
size
;
}
}
// helper functions that scale from user coordinates to screen coordinates and back
private
static
double
scaleX
(
double
x
)
{
return
width
*
(
x
–
xmin
)
/
(
xmax
–
xmin
);
}
private
static
double
scaleY
(
double
y
)
{
return
height
*
(
ymax
–
y
)
/
(
ymax
–
ymin
);
}
private
static
double
factorX
(
double
w
)
{
return
w
*
width
/
Math
.
abs
(
xmax
–
xmin
);
}
private
static
double
factorY
(
double
h
)
{
return
h
*
height
/
Math
.
abs
(
ymax
–
ymin
);
}
private
static
double
userX
(
double
x
)
{
return
xmin
+
x
*
(
xmax
–
xmin
)
/
width
;
}
private
static
double
userY
(
double
y
)
{
return
ymax
–
y
*
(
ymax
–
ymin
)
/
height
;
}
/**
* Clears the screen to the default color (white).
*/
public
static
void
clear
()
{
clear
(
DEFAULT_CLEAR_COLOR
);
}
/**
* Clears the screen to the specified color.
*
*
@param
color the color to make the background
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
static
void
clear
(
Color
color
)
{
validateNotNull
(
color
,
“color”
);
offscreen
.
setColor
(
color
);
offscreen
.
fillRect
(
0
,
0
,
width
,
height
);
offscreen
.
setColor
(
penColor
);
draw
();
}
/**
* Returns the current pen radius.
*
*
@return
the current value of the pen radius
*/
public
static
double
getPenRadius
()
{
return
penRadius
;
}
/**
* Sets the pen size to the default size (0.002).
* The pen is circular, so that lines have rounded ends, and when you set the
* pen radius and draw a point, you get a circle of the specified radius.
* The pen radius is not affected by coordinate scaling.
*/
public
static
void
setPenRadius
()
{
setPenRadius
(
DEFAULT_PEN_RADIUS
);
}
/**
* Sets the radius of the pen to the specified size.
* The pen is circular, so that lines have rounded ends, and when you set the
* pen radius and draw a point, you get a circle of the specified radius.
* The pen radius is not affected by coordinate scaling.
*
*
@param
radius the radius of the pen
*
@throws
IllegalArgumentException if {
@code
radius} is negative, NaN, or infinite
*/
public
static
void
setPenRadius
(
double
radius
)
{
validate
(
radius
,
“pen radius”
);
validateNonnegative
(
radius
,
“pen radius”
);
penRadius
=
radius
;
float
scaledPenRadius
=
(
float
)
(
radius
*
DEFAULT_SIZE
);
BasicStroke
stroke
=
new
BasicStroke
(
scaledPenRadius
,
BasicStroke
.
CAP_ROUND
,
BasicStroke
.
JOIN_ROUND
);
// BasicStroke stroke = new BasicStroke(scaledPenRadius);
offscreen
.
setStroke
(
stroke
);
}
/**
* Returns the current pen color.
*
*
@return
the current pen color
*/
public
static
Color
getPenColor
()
{
return
penColor
;
}
/**
* Sets the pen color to the default color (black).
*/
public
static
void
setPenColor
()
{
setPenColor
(
DEFAULT_PEN_COLOR
);
}
/**
* Sets the pen color to the specified color.
*
* The predefined pen colors are
* {
@code
StdDraw.BLACK}, {
@code
StdDraw.BLUE}, {
@code
StdDraw.CYAN},
* {
@code
StdDraw.DARK_GRAY}, {
@code
StdDraw.GRAY}, {
@code
StdDraw.GREEN},
* {
@code
StdDraw.LIGHT_GRAY}, {
@code
StdDraw.MAGENTA}, {
@code
StdDraw.ORANGE},
* {
@code
StdDraw.PINK}, {
@code
StdDraw.RED}, {
@code
StdDraw.WHITE}, and
* {
@code
StdDraw.YELLOW}.
*
*
@param
color the color to make the pen
*
@throws
IllegalArgumentException if {
@code
color} is {
@code
null}
*/
public
static
void
setPenColor
(
Color
color
)
{
validateNotNull
(
color
,
“color”
);
penColor
=
color
;
offscreen
.
setColor
(
penColor
);
}
/**
* Sets the pen color to the specified RGB color.
*
*
@param
red the amount of red (between 0 and 255)
*
@param
green the amount of green (between 0 and 255)
*
@param
blue the amount of blue (between 0 and 255)
*
@throws
IllegalArgumentException if {
@code
red}, {
@code
green},
* or {
@code
blue} is outside its prescribed range
*/
public
static
void
setPenColor
(
int
red
,
int
green
,
int
blue
)
{
if
(
red
<
0
||
red
>=
256
)
throw
new
IllegalArgumentException
(
“red must be between 0 and 255”
);
if
(
green
<
0
||
green
>=
256
)
throw
new
IllegalArgumentException
(
“green must be between 0 and 255”
);
if
(
blue
<
0
||
blue
>=
256
)
throw
new
IllegalArgumentException
(
“blue must be between 0 and 255”
);
setPenColor
(
new
Color
(
red
,
green
,
blue
));
}
/**
* Returns the current font.
*
*
@return
the current font
*/
public
static
Font
getFont
()
{
return
font
;
}
/**
* Sets the font to the default font (sans serif, 16 point).
*/
public
static
void
setFont
()
{
setFont
(
DEFAULT_FONT
);
}
/**
* Sets the font to the specified value.
*
*
@param
font the font
*
@throws
IllegalArgumentException if {
@code
font} is {
@code
null}
*/
public
static
void
setFont
(
Font
font
)
{
validateNotNull
(
font
,
“font”
);
StdDraw
.
font
=
font
;
}
/***************************************************************************
* Drawing geometric shapes.
***************************************************************************/
/**
* Draws a line segment between (x0, y0) and
* (x1, y1).
*
*
@param
x0 the x-coordinate of one endpoint
*
@param
y0 the y-coordinate of one endpoint
*
@param
x1 the x-coordinate of the other endpoint
*
@param
y1 the y-coordinate of the other endpoint
*
@throws
IllegalArgumentException if any coordinate is either NaN or infinite
*/
public
static
void
line
(
double
x0
,
double
y0
,
double
x1
,
double
y1
)
{
validate
(
x0
,
“x0”
);
validate
(
y0
,
“y0”
);
validate
(
x1
,
“x1”
);
validate
(
y1
,
“y1”
);
offscreen
.
draw
(
new
Line2D
.
Double
(
scaleX
(
x0
),
scaleY
(
y0
),
scaleX
(
x1
),
scaleY
(
y1
)));
draw
();
}
/**
* Draws one pixel at (x, y).
* This method is private because pixels depend on the display.
* To achieve the same effect, set the pen radius to 0 and call {
@code
point()}.
*
*
@param
x the x-coordinate of the pixel
*
@param
y the y-coordinate of the pixel
*
@throws
IllegalArgumentException if {
@code
x} or {
@code
y} is either NaN or infinite
*/
private
static
void
pixel
(
double
x
,
double
y
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
offscreen
.
fillRect
((
int
)
Math
.
round
(
scaleX
(
x
)),
(
int
)
Math
.
round
(
scaleY
(
y
)),
1
,
1
);
}
/**
* Draws a point centered at (x, y).
* The point is a filled circle whose radius is equal to the pen radius.
* To draw a single-pixel point, first set the pen radius to 0.
*
*
@param
x the x-coordinate of the point
*
@param
y the y-coordinate of the point
*
@throws
IllegalArgumentException if either {
@code
x} or {
@code
y} is either NaN or infinite
*/
public
static
void
point
(
double
x
,
double
y
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
r
=
penRadius
;
float
scaledPenRadius
=
(
float
)
(
r
*
DEFAULT_SIZE
);
// double ws = factorX(2*r);
// double hs = factorY(2*r);
// if (ws <= 1 && hs <= 1) pixel(x, y);
if
(
scaledPenRadius
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
scaledPenRadius
/
2
,
ys
-
scaledPenRadius
/
2
,
scaledPenRadius
,
scaledPenRadius
));
draw
();
}
/**
* Draws a circle of the specified radius, centered at (x, y).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
static
void
circle
(
double
x
,
double
y
,
double
radius
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“radius”
);
validateNonnegative
(
radius
,
“radius”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
radius
);
double
hs
=
factorY
(
2
*
radius
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
draw
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a filled circle of the specified radius, centered at (x, y).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
static
void
filledCircle
(
double
x
,
double
y
,
double
radius
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“radius”
);
validateNonnegative
(
radius
,
“radius”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
radius
);
double
hs
=
factorY
(
2
*
radius
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws an ellipse with the specified semimajor and semiminor axes,
* centered at (x, y).
*
*
@param
x the x-coordinate of the center of the ellipse
*
@param
y the y-coordinate of the center of the ellipse
*
@param
semiMajorAxis is the semimajor axis of the ellipse
*
@param
semiMinorAxis is the semiminor axis of the ellipse
*
@throws
IllegalArgumentException if either {
@code
semiMajorAxis}
* or {
@code
semiMinorAxis} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
static
void
ellipse
(
double
x
,
double
y
,
double
semiMajorAxis
,
double
semiMinorAxis
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
semiMajorAxis
,
“semimajor axis”
);
validate
(
semiMinorAxis
,
“semiminor axis”
);
validateNonnegative
(
semiMajorAxis
,
“semimajor axis”
);
validateNonnegative
(
semiMinorAxis
,
“semiminor axis”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
semiMajorAxis
);
double
hs
=
factorY
(
2
*
semiMinorAxis
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
draw
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a filled ellipse with the specified semimajor and semiminor axes,
* centered at (x, y).
*
*
@param
x the x-coordinate of the center of the ellipse
*
@param
y the y-coordinate of the center of the ellipse
*
@param
semiMajorAxis is the semimajor axis of the ellipse
*
@param
semiMinorAxis is the semiminor axis of the ellipse
*
@throws
IllegalArgumentException if either {
@code
semiMajorAxis}
* or {
@code
semiMinorAxis} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
static
void
filledEllipse
(
double
x
,
double
y
,
double
semiMajorAxis
,
double
semiMinorAxis
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
semiMajorAxis
,
“semimajor axis”
);
validate
(
semiMinorAxis
,
“semiminor axis”
);
validateNonnegative
(
semiMajorAxis
,
“semimajor axis”
);
validateNonnegative
(
semiMinorAxis
,
“semiminor axis”
);
double
xs
=
scaleX
(
x
);
double
ys
=
scaleY
(
y
);
double
ws
=
factorX
(
2
*
semiMajorAxis
);
double
hs
=
factorY
(
2
*
semiMinorAxis
);
if
(
ws
<=
1
&&
hs
<=
1
)
pixel
(
x
,
y
);
else
offscreen
.
fill
(
new
Ellipse2D
.
Double
(
xs
-
ws
/
2
,
ys
-
hs
/
2
,
ws
,
hs
));
draw
();
}
/**
* Draws a circular arc of the specified radius,
* centered at (x, y), from angle1 to angle2 (in degrees).
*
*
@param
x the x-coordinate of the center of the circle
*
@param
y the y-coordinate of the center of the circle
*
@param
radius the radius of the circle
*
@param
angle1 the starting angle. 0 would mean an arc beginning at 3 o’clock.
*
@param
angle2 the angle at the end of the arc. For example, if
* you want a 90 degree arc, then angle2 should be angle1 + 90.
*
@throws
IllegalArgumentException if {
@code
radius} is negative
*
@throws
IllegalArgumentException if any argument is either NaN or infinite
*/
public
static
void
arc
(
double
x
,
double
y
,
double
radius
,
double
angle1
,
double
angle2
)
{
validate
(
x
,
“x”
);
validate
(
y
,
“y”
);
validate
(
radius
,
“arc radius”
);
validate
(
angle1
,
“angle1”
);
validate
(
angle2
,
“angle2”
);
validateNonnegative
(
radius
,
“arc radius”
);
while (angle2 < angle1) angle2 += 360; double xs = scaleX(x); double ys = scaleY(y); double ws = factorX(2*radius); double hs = factorY(2*radius); if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.draw(new Arc2D.Double(xs - ws/2, ys - hs/2, ws, hs, angle1, angle2 - angle1, Arc2D.OPEN)); draw(); } /** * Draws a square of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the square * @param y the y-coordinate of the center of the square * @param halfLength one half the length of any side of the square * @throws IllegalArgumentException if {@code halfLength} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public static void square(double x, double y, double halfLength) {
validate(x, “x”);
validate(y, “y”);
validate(halfLength, “halfLength”);
validateNonnegative(halfLength, “half length”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfLength);
double hs = factorY(2*halfLength);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a filled square of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the square * @param y the y-coordinate of the center of the square * @param halfLength one half the length of any side of the square * @throws IllegalArgumentException if {@code halfLength} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public static void filledSquare(double x, double y, double halfLength) {
validate(x, “x”);
validate(y, “y”);
validate(halfLength, “halfLength”);
validateNonnegative(halfLength, “half length”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfLength);
double hs = factorY(2*halfLength);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a rectangle of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the rectangle * @param y the y-coordinate of the center of the rectangle * @param halfWidth one half the width of the rectangle * @param halfHeight one half the height of the rectangle * @throws IllegalArgumentException if either {@code halfWidth} or {@code halfHeight} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public static void rectangle(double x, double y, double halfWidth, double halfHeight) {
validate(x, “x”);
validate(y, “y”);
validate(halfWidth, “halfWidth”);
validate(halfHeight, “halfHeight”);
validateNonnegative(halfWidth, “half width”);
validateNonnegative(halfHeight, “half height”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfWidth);
double hs = factorY(2*halfHeight);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.draw(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a filled rectangle of the specified size, centered at (x, y). * * @param x the x-coordinate of the center of the rectangle * @param y the y-coordinate of the center of the rectangle * @param halfWidth one half the width of the rectangle * @param halfHeight one half the height of the rectangle * @throws IllegalArgumentException if either {@code halfWidth} or {@code halfHeight} is negative * @throws IllegalArgumentException if any argument is either NaN or infinite */
public static void filledRectangle(double x, double y, double halfWidth, double halfHeight) {
validate(x, “x”);
validate(y, “y”);
validate(halfWidth, “halfWidth”);
validate(halfHeight, “halfHeight”);
validateNonnegative(halfWidth, “half width”);
validateNonnegative(halfHeight, “half height”);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(2*halfWidth);
double hs = factorY(2*halfHeight);
if (ws <= 1 && hs <= 1) pixel(x, y); else offscreen.fill(new Rectangle2D.Double(xs - ws/2, ys - hs/2, ws, hs)); draw(); } /** * Draws a polygon with the vertices * (x0, y0), * (x1, y1), …, * (xn–1, yn–1). * * @param x an array of all the x-coordinates of the polygon * @param y an array of all the y-coordinates of the polygon * @throws IllegalArgumentException unless {@code x[]} and {@code y[]} * are of the same length * @throws IllegalArgumentException if any coordinate is either NaN or infinite * @throws IllegalArgumentException if either {@code x[]} or {@code y[]} is {@code null} */
public static void polygon(double[] x, double[] y) {
validateNotNull(x, “x-coordinate array”);
validateNotNull(y, “y-coordinate array”);
for (int i = 0; i < x.length; i++) validate(x[i], "x[" + i + "]"); for (int i = 0; i < y.length; i++) validate(y[i], "y[" + i + "]"); int n1 = x.length; int n2 = y.length; if (n1 != n2) throw new IllegalArgumentException("arrays must be of the same length"); int n = n1; if (n == 0) return; GeneralPath path = new GeneralPath(); path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); for (int i = 0; i < n; i++) path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); path.closePath(); offscreen.draw(path); draw(); } /** * Draws a filled polygon with the vertices * (x0, y0), * (x1, y1), …, * (xn–1, yn–1). * * @param x an array of all the x-coordinates of the polygon * @param y an array of all the y-coordinates of the polygon * @throws IllegalArgumentException unless {@code x[]} and {@code y[]} * are of the same length * @throws IllegalArgumentException if any coordinate is either NaN or infinite * @throws IllegalArgumentException if either {@code x[]} or {@code y[]} is {@code null} */
public static void filledPolygon(double[] x, double[] y) {
validateNotNull(x, “x-coordinate array”);
validateNotNull(y, “y-coordinate array”);
for (int i = 0; i < x.length; i++) validate(x[i], "x[" + i + "]"); for (int i = 0; i < y.length; i++) validate(y[i], "y[" + i + "]"); int n1 = x.length; int n2 = y.length; if (n1 != n2) throw new IllegalArgumentException("arrays must be of the same length"); int n = n1; if (n == 0) return; GeneralPath path = new GeneralPath(); path.moveTo((float) scaleX(x[0]), (float) scaleY(y[0])); for (int i = 0; i < n; i++) path.lineTo((float) scaleX(x[i]), (float) scaleY(y[i])); path.closePath(); offscreen.fill(path); draw(); } /*************************************************************************** * Drawing images. ***************************************************************************/ // get an image from the given filename private static Image getImage(String filename) { if (filename == null) throw new IllegalArgumentException(); // to read from file ImageIcon icon = new ImageIcon(filename); // try to read from URL if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { try { URL url = new URL(filename); icon = new ImageIcon(url); } catch (MalformedURLException e) { /* not a url */ } } // in case file is inside a .jar (classpath relative to StdDraw) if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { URL url = StdDraw.class.getResource(filename); if (url != null) icon = new ImageIcon(url); } // in case file is inside a .jar (classpath relative to root of jar) if ((icon == null) || (icon.getImageLoadStatus() != MediaTracker.COMPLETE)) { URL url = StdDraw.class.getResource("/" + filename); if (url == null) throw new IllegalArgumentException("image " + filename + " not found"); icon = new ImageIcon(url); } return icon.getImage(); } /*************************************************************************** * [Summer 2016] Should we update to use ImageIO instead of ImageIcon()? * Seems to have some issues loading images on some systems * and slows things down on other systems. * especially if you don't call ImageIO.setUseCache(false) * One advantage is that it returns a BufferedImage. ***************************************************************************/ /* private static BufferedImage getImage(String filename) { if (filename == null) throw new IllegalArgumentException(); // from a file or URL try { URL url = new URL(filename); BufferedImage image = ImageIO.read(url); return image; } catch (IOException e) { // ignore } // in case file is inside a .jar (classpath relative to StdDraw) try { URL url = StdDraw.class.getResource(filename); BufferedImage image = ImageIO.read(url); return image; } catch (IOException e) { // ignore } // in case file is inside a .jar (classpath relative to root of jar) try { URL url = StdDraw.class.getResource("/" + filename); BufferedImage image = ImageIO.read(url); return image; } catch (IOException e) { // ignore } throw new IllegalArgumentException("image " + filename + " not found"); }*/ /** * Draws the specified image centered at (x, y). * The supported image formats are JPEG, PNG, and GIF. * As an optimization, the picture is cached, so there is no performance * penalty for redrawing the same image multiple times (e.g., in an animation). * However, if you change the picture file after drawing it, subsequent * calls will draw the original picture. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if either {@code x} or {@code y} is either NaN or infinite */
public static void picture(double x, double y, String filename) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(filename, “filename”);
// BufferedImage image = getImage(filename); Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
// int ws = image.getWidth(); // can call only if image is a BufferedImage // int hs = image.getHeight(); int ws = image.getWidth(null);
int hs = image.getHeight(null);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); draw(); } /** * Draws the specified image centered at (x, y), * rotated given number of degrees. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if {@code x}, {@code y}, {@code degrees} is NaN or infinite * @throws IllegalArgumentException if {@code filename} is {@code null} */
public static void picture(double x, double y, String filename, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(degrees, “degrees”);
validateNotNull(filename, “filename”);
// BufferedImage image = getImage(filename); Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
// int ws = image.getWidth(); // can call only if image is a BufferedImage // int hs = image.getHeight(); int ws = image.getWidth(null);
int hs = image.getHeight(null);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); offscreen.rotate(Math.toRadians(-degrees), xs, ys); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), null); offscreen.rotate(Math.toRadians(+degrees), xs, ys); draw(); } /** * Draws the specified image centered at (x, y), * rescaled to the specified bounding box. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param scaledWidth the width of the scaled image (in screen coordinates) * @param scaledHeight the height of the scaled image (in screen coordinates) * @throws IllegalArgumentException if either {@code scaledWidth} * or {@code scaledHeight} is negative * @throws IllegalArgumentException if the image filename is invalid * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite * @throws IllegalArgumentException if {@code filename} is {@code null} */
public static void picture(double x, double y, String filename, double scaledWidth, double scaledHeight) {
validate(x, “x”);
validate(y, “y”);
validate(scaledWidth, “scaled width”);
validate(scaledHeight, “scaled height”);
validateNotNull(filename, “filename”);
validateNonnegative(scaledWidth, “scaled width”);
validateNonnegative(scaledHeight, “scaled height”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(scaledWidth);
double hs = factorY(scaledHeight);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); if (ws <= 1 && hs <= 1) pixel(x, y); else { offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), (int) Math.round(ws), (int) Math.round(hs), null); } draw(); } /** * Draws the specified image centered at (x, y), rotated * given number of degrees, and rescaled to the specified bounding box. * The supported image formats are JPEG, PNG, and GIF. * * @param x the center x-coordinate of the image * @param y the center y-coordinate of the image * @param filename the name of the image/picture, e.g., “ball.gif” * @param scaledWidth the width of the scaled image (in screen coordinates) * @param scaledHeight the height of the scaled image (in screen coordinates) * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if either {@code scaledWidth} * or {@code scaledHeight} is negative * @throws IllegalArgumentException if the image filename is invalid */
public static void picture(double x, double y, String filename, double scaledWidth, double scaledHeight, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(scaledWidth, “scaled width”);
validate(scaledHeight, “scaled height”);
validate(degrees, “degrees”);
validateNotNull(filename, “filename”);
validateNonnegative(scaledWidth, “scaled width”);
validateNonnegative(scaledHeight, “scaled height”);
Image image = getImage(filename);
double xs = scaleX(x);
double ys = scaleY(y);
double ws = factorX(scaledWidth);
double hs = factorY(scaledHeight);
if (ws < 0 || hs < 0) throw new IllegalArgumentException("image " + filename + " is corrupt"); if (ws <= 1 && hs <= 1) pixel(x, y); offscreen.rotate(Math.toRadians(-degrees), xs, ys); offscreen.drawImage(image, (int) Math.round(xs - ws/2.0), (int) Math.round(ys - hs/2.0), (int) Math.round(ws), (int) Math.round(hs), null); offscreen.rotate(Math.toRadians(+degrees), xs, ys); draw(); } /*************************************************************************** * Drawing text. ***************************************************************************/ /** * Writes the given text string in the current font, centered at (x, y). * * @param x the center x-coordinate of the text * @param y the center y-coordinate of the text * @param text the text to write * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public static void text(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
int ws = metrics.stringWidth(text);
int hs = metrics.getDescent();
offscreen.drawString(text, (float) (xs – ws/2.0), (float) (ys + hs));
draw();
}
/** * Writes the given text string in the current font, centered at (x, y) and * rotated by the specified number of degrees. * @param x the center x-coordinate of the text * @param y the center y-coordinate of the text * @param text the text to write * @param degrees is the number of degrees to rotate counterclockwise * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x}, {@code y}, or {@code degrees} is either NaN or infinite */
public static void text(double x, double y, String text, double degrees) {
validate(x, “x”);
validate(y, “y”);
validate(degrees, “degrees”);
validateNotNull(text, “text”);
double xs = scaleX(x);
double ys = scaleY(y);
offscreen.rotate(Math.toRadians(-degrees), xs, ys);
text(x, y, text);
offscreen.rotate(Math.toRadians(+degrees), xs, ys);
}
/** * Writes the given text string in the current font, left-aligned at (x, y). * @param x the x-coordinate of the text * @param y the y-coordinate of the text * @param text the text * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public static void textLeft(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
int hs = metrics.getDescent();
offscreen.drawString(text, (float) xs, (float) (ys + hs));
draw();
}
/** * Writes the given text string in the current font, right-aligned at (x, y). * * @param x the x-coordinate of the text * @param y the y-coordinate of the text * @param text the text to write * @throws IllegalArgumentException if {@code text} is {@code null} * @throws IllegalArgumentException if {@code x} or {@code y} is either NaN or infinite */
public static void textRight(double x, double y, String text) {
validate(x, “x”);
validate(y, “y”);
validateNotNull(text, “text”);
offscreen.setFont(font);
FontMetrics metrics = offscreen.getFontMetrics();
double xs = scaleX(x);
double ys = scaleY(y);
int ws = metrics.stringWidth(text);
int hs = metrics.getDescent();
offscreen.drawString(text, (float) (xs – ws), (float) (ys + hs));
draw();
}
/** * Copies the offscreen buffer to the onscreen buffer, pauses for t milliseconds * and enables double buffering. * @param t number of milliseconds * @deprecated replaced by {@link #enableDoubleBuffering()}, {@link #show()}, and {@link #pause(int t)} */
@Deprecated
public static void show(int t) {
validateNonnegative(t, “t”);
show();
pause(t);
enableDoubleBuffering();
}
/** * Pauses for t milliseconds. This method is intended to support computer animations. * @param t number of milliseconds */
public static void pause(int t) {
validateNonnegative(t, “t”);
try {
Thread.sleep(t);
}
catch (InterruptedException e) {
System.out.println(“Error sleeping”);
}
}
/** * Copies offscreen buffer to onscreen buffer. There is no reason to call * this method unless double buffering is enabled. */
public static void show() {
onscreen.drawImage(offscreenImage, 0, 0, null);
frame.repaint();
}
// draw onscreen if defer is false private static void draw() {
if (!defer) show();
}
/** * Enables double buffering. All subsequent calls to * drawing methods such as {@code line()}, {@code circle()}, * and {@code square()} will be deferred until the next call * to show(). Useful for animations. */
public static void enableDoubleBuffering() {
defer = true;
}
/** * Disables double buffering. All subsequent calls to * drawing methods such as {@code line()}, {@code circle()}, * and {@code square()} will be displayed on screen when called. * This is the default. */
public static void disableDoubleBuffering() {
defer = false;
}
/*************************************************************************** * Save drawing to a file. ***************************************************************************/
/** * Saves the drawing to using the specified filename. * The supported image formats are JPEG and PNG; * the filename suffix must be {@code } or {@code }. * * @param filename the name of the file with one of the required suffixes * @throws IllegalArgumentException if {@code filename} is {@code null} */
public static void save(String filename) {
validateNotNull(filename, “filename”);
File file = new File(filename);
String suffix = filename.substring(filename.lastIndexOf(‘.’) + 1);
// png files if (“png”.equalsIgnoreCase(suffix)) {
try {
ImageIO.write(onscreenImage, suffix, file);
}
catch (IOException e) {
e.printStackTrace();
}
}
// need to change from ARGB to RGB for JPEG // reference: http://archives.java.sun.com/cgi-bin/wa?A2=ind0404&L=java2d-interest&D=0&P=2727 else if (“jpg”.equalsIgnoreCase(suffix)) {
WritableRaster raster = onscreenImage.getRaster();
WritableRaster newRaster;
newRaster = raster.createWritableChild(0, 0, width, height, 0, 0, new int[] {0, 1, 2});
DirectColorModel cm = (DirectColorModel) onscreenImage.getColorModel();
DirectColorModel newCM = new DirectColorModel(cm.getPixelSize(),
cm.getRedMask(),
cm.getGreenMask(),
cm.getBlueMask());
BufferedImage rgbBuffer = new BufferedImage(newCM, newRaster, false, null);
try {
ImageIO.write(rgbBuffer, suffix, file);
}
catch (IOException e) {
e.printStackTrace();
}
}
else {
System.out.println(“Invalid image file type: ” + suffix);
}
}
/** * This method cannot be called directly. */
@Override
public void actionPerformed(ActionEvent e) {
FileDialog chooser = new FileDialog(StdDraw.frame, “Use a or extension”, FileDialog.SAVE);
chooser.setVisible(true);
String filename = chooser.getFile();
if (filename != null) {
StdDraw.save(chooser.getDirectory() + File.separator + chooser.getFile());
}
}
/*************************************************************************** * Mouse interactions. ***************************************************************************/
/** * Returns true if the mouse is being pressed. * * @return {@code true} if the mouse is being pressed; {@code false} otherwise */
public static boolean isMousePressed() {
synchronized (mouseLock) {
return isMousePressed;
}
}
/** * Returns true if the mouse is being pressed. * * @return {@code true} if the mouse is being pressed; {@code false} otherwise * @deprecated replaced by {@link #isMousePressed()} */
@Deprecated
public static boolean mousePressed() {
synchronized (mouseLock) {
return isMousePressed;
}
}
/** * Returns the x-coordinate of the mouse. * * @return the x-coordinate of the mouse */
public static double mouseX() {
synchronized (mouseLock) {
return mouseX;
}
}
/** * Returns the y-coordinate of the mouse. * * @return y-coordinate of the mouse */
public static double mouseY() {
synchronized (mouseLock) {
return mouseY;
}
}
/** * This method cannot be called directly. */
@Override
public void mouseClicked(MouseEvent e) {
// this body is intentionally left empty }
/** * This method cannot be called directly. */
@Override
public void mouseEntered(MouseEvent e) {
// this body is intentionally left empty }
/** * This method cannot be called directly. */
@Override
public void mouseExited(MouseEvent e) {
// this body is intentionally left empty }
/** * This method cannot be called directly. */
@Override
public void mousePressed(MouseEvent e) {
synchronized (mouseLock) {
mouseX = StdDraw.userX(e.getX());
mouseY = StdDraw.userY(e.getY());
isMousePressed = true;
}
}
/** * This method cannot be called directly. */
@Override
public void mouseReleased(MouseEvent e) {
synchronized (mouseLock) {
isMousePressed = false;
}
}
/** * This method cannot be called directly. */
@Override
public void mouseDragged(MouseEvent e) {
synchronized (mouseLock) {
mouseX = StdDraw.userX(e.getX());
mouseY = StdDraw.userY(e.getY());
}
}
/** * This method cannot be called directly. */
@Override
public void mouseMoved(MouseEvent e) {
synchronized (mouseLock) {
mouseX = StdDraw.userX(e.getX());
mouseY = StdDraw.userY(e.getY());
}
}
/*************************************************************************** * Keyboard interactions. ***************************************************************************/
/** * Returns true if the user has typed a key (that has not yet been processed). * * @return {@code true} if the user has typed a key (that has not yet been processed * by {@link #nextKeyTyped()}; {@code false} otherwise */
public static boolean hasNextKeyTyped() {
synchronized (keyLock) {
return !keysTyped.isEmpty();
}
}
/** * Returns the next key that was typed by the user (that your program has not already processed). * This method should be preceded by a call to {@link #hasNextKeyTyped()} to ensure * that there is a next key to process. * This method returns a Unicode character corresponding to the key * typed (such as {@code ‘a’} or {@code ‘A’}). * It cannot identify action keys (such as F1 and arrow keys) * or modifier keys (such as control). * * @return the next key typed by the user (that your program has not already processed). * @throws NoSuchElementException if there is no remaining key */
public static char nextKeyTyped() {
synchronized (keyLock) {
if (keysTyped.isEmpty()) {
throw new NoSuchElementException(“your program has already processed all keystrokes”);
}
return keysTyped.remove(keysTyped.size() – 1);
// return keysTyped.removeLast(); }
}
/** * Returns true if the given key is being pressed. *
* This method takes the keycode (corresponding to a physical key) * as an argument. It can handle action keys * (such as F1 and arrow keys) and modifier keys (such as shift and control). * See {@link KeyEvent} for a description of key codes. * * @param keycode the key to check if it is being pressed * @return {@code true} if {@code keycode} is currently being pressed; * {@code false} otherwise */
public static boolean isKeyPressed(int keycode) {
synchronized (keyLock) {
return keysDown.contains(keycode);
}
}
/** * This method cannot be called directly. */
@Override
public void keyTyped(KeyEvent e) {
synchronized (keyLock) {
keysTyped.addFirst(e.getKeyChar());
}
}
/** * This method cannot be called directly. */
@Override
public void keyPressed(KeyEvent e) {
synchronized (keyLock) {
keysDown.add(e.getKeyCode());
}
}
/** * This method cannot be called directly. */
@Override
public void keyReleased(KeyEvent e) {
synchronized (keyLock) {
keysDown.remove(e.getKeyCode());
}
}
/*************************************************************************** * For improved resolution on Mac Retina displays. ***************************************************************************/
private static class RetinaImageIcon extends ImageIcon {
public RetinaImageIcon(Image image) {
super(image);
}
public int getIconWidth() {
return super.getIconWidth() / 2;
}
/** * Gets the height of the icon. * * @return the height in pixels of this icon */
public int getIconHeight() {
return super.getIconHeight() / 2;
}
public synchronized void paintIcon(Component c, Graphics g, int x, int y) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BICUBIC);
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2.scale(0.5, 0.5);
super.paintIcon(c, g2, x * 2, y * 2);
g2.dispose();
}
}
/** * Test client. * * @param args the command-line arguments */
public static void main(String[] args) {
StdDraw.square(0.2, 0.8, 0.1);
StdDraw.filledSquare(0.8, 0.8, 0.2);
StdDraw.circle(0.8, 0.2, 0.2);
StdDraw.setPenColor(StdDraw.BOOK_RED);
StdDraw.setPenRadius(0.02);
StdDraw.arc(0.8, 0.2, 0.1, 200, 45);
// draw a blue diamond StdDraw.setPenRadius();
StdDraw.setPenColor(StdDraw.BOOK_BLUE);
double[] x = { 0.1, 0.2, 0.3, 0.2 };
double[] y = { 0.2, 0.3, 0.2, 0.1 };
StdDraw.filledPolygon(x, y);
// text StdDraw.setPenColor(StdDraw.BLACK);
StdDraw.text(0.2, 0.5, “black text”);
StdDraw.setPenColor(StdDraw.WHITE);
StdDraw.text(0.8, 0.8, “white text”);
}
}
StdIn.java
StdIn.java
/******************************************************************************
* Compilation: javac StdIn.java
* Execution: java StdIn (interactive test of basic functionality)
* Dependencies: none
*
* Reads in data of various types from standard input.
*
******************************************************************************/
import
java
.
util
.
ArrayList
;
import
java
.
util
.
InputMismatchException
;
import
java
.
util
.
Locale
;
import
java
.
util
.
NoSuchElementException
;
import
java
.
util
.
Scanner
;
import
java
.
util
.
regex
.
Pattern
;
/**
* The {
@code
StdIn} class provides static methods for reading strings
* and numbers from standard input.
* These functions fall into one of four categories:
*
- those for reading individual tokens from standard input, one at a time,
* and converting each to a number, string, or boolean
*
- those for reading characters from standard input, one at a time
*
- those for reading lines from standard input, one at a time
*
- those for reading a sequence of values of the same type from standard input,
* and returning the values in an array
*
*
*
* Generally, it is best not to mix functions from the different
* categories in the same program.
*
* Getting started.
* To use this class, you must have {
@code
StdIn.class} in your
* Java classpath. If you used our autoinstaller, you should be all set.
* Otherwise, either download
* and add to your Java classpath or download
* and put a copy in your working directory.
*
* Reading tokens from standard input and converting to numbers and strings.
* You can use the following methods to read numbers, strings, and booleans
* from standard input one at a time:
*
- {
@link
#isEmpty()}*
- {
@link
#readInt()}*
- {
@link
#readDouble()}*
- {
@link
#readString()}*
- {
@link
#readShort()}*
- {
@link
#readLong()}*
- {
@link
#readFloat()}*
- {
@link
#readByte()}*
- {
@link
#readBoolean()}*
*
*
* The first method returns true if standard input has no more tokens.
* Each other method skips over any input that is whitespace. Then, it reads
* the next token and attempts to convert it into a value of the specified
* type. If it succeeds, it returns that value; otherwise, it
* throws an {
@link
InputMismatchException}.
*
* Whitespace includes spaces, tabs, and newlines; the full definition
* is inherited from {
@link
Character#isWhitespace(char)}.
* A token is a maximal sequence of non-whitespace characters.
* The precise rules for describing which tokens can be converted to
* integers and floating-point numbers are inherited from
* Scanner,
* using the locale {
@link
Locale#US}; the rules
* for floating-point numbers are slightly different
* from those in {
@link
Double#valueOf(String)},
* but unlikely to be of concern to most programmers.
*
* As an example, the following code fragment reads integers from standard input,
* one at a time, and prints them one per line.
*
* while (!StdIn.isEmpty()) { * double value = StdIn.readDouble(); * StdOut.println(value); * } *
*
* Reading characters from standard input.
* You can use the following two methods to read characters from standard input one at a time:
*
- {
@link
#hasNextChar()}*
- {
@link
#readChar()}*
*
*
* The first method returns true if standard input has more input (including whitespace).
* The second method reads and returns the next character of input on standard
* input (possibly a whitespace character).
*
* As an example, the following code fragment reads characters from standard input,
* one character at a time, and prints it to standard output.
*
* while (StdIn.hasNextChar()) { * char c = StdIn.readChar(); * StdOut.print(c); * } *
*
* Reading lines from standard input.
* You can use the following two methods to read lines from standard input:
*
- {
@link
#hasNextLine()}*
- {
@link
#readLine()}*
*
*
* The first method returns true if standard input has more input (including whitespace).
* The second method reads and returns the remaining portion of
* the next line of input on standard input (possibly whitespace),
* discarding the trailing line separator.
*
* A line separator is defined to be one of the following strings:
* {
@code
\n} (Linux), {
@code
\r} (old Macintosh),
* {
@code
\r\n} (Windows),
* {
@code
\}{
@code
u2028}, {
@code
\}{
@code
u2029}, or {
@code
\}{
@code
u0085}.
*
* As an example, the following code fragment reads text from standard input,
* one line at a time, and prints it to standard output.
*
* while (StdIn.hasNextLine()) { * String line = StdIn.readLine(); * StdOut.println(line); * } *
*
* Reading a sequence of values of the same type from standard input.
* You can use the following methods to read a sequence numbers, strings,
* or booleans (all of the same type) from standard input:
*
- {
@link
#readAllDoubles()}*
- {
@link
#readAllInts()}*
- {
@link
#readAllLongs()}*
- {
@link
#readAllStrings()}*
- {
@link
#readAllLines()}*
- {
@link
#readAll()}*
*
*
* The first three methods read of all of remaining token on standard input
* and converts the tokens to values of
* the specified type, as in the corresponding
* {
@code
readDouble}, {
@code
readInt}, and {
@code
readString()} methods.
* The {
@code
readAllLines()} method reads all remaining lines on standard
* input and returns them as an array of strings.
* The {
@code
readAll()} method reads all remaining input on standard
* input and returns it as a string.
*
* As an example, the following code fragment reads all of the remaining
* tokens from standard input and returns them as an array of strings.
*
* String[] words = StdIn.readAllStrings(); *
*
* Differences with Scanner.
* {
@code
StdIn} and {
@link
Scanner} are both designed to parse
* tokens and convert them to primitive types and strings.
* The main differences are summarized below:
*
- {
@code
StdIn} is a set of static methods and reads* reads input from only standard input. It is suitable for use before
* a programmer knows about objects.
* See {
@link
In} for an object-oriented version that handles* input from files, URLs,
* and sockets.
*
- {
@code
StdIn} uses whitespace as the delimiter pattern* that separates tokens.
* {
@link
Scanner} supports arbitrary delimiter patterns.*
- {
@code
StdIn} coerces the character-set encoding to UTF-8,* which is the most widely used character encoding for Unicode.
*
- {
@code
StdIn} coerces the locale to {
@link
Locale#US},* for consistency with {
@link
StdOut}, {
@link
Double#parseDouble(String)},* and floating-point literals.
*
- {
@code
StdIn} has convenient methods for reading a single* character; reading in sequences of integers, doubles, or strings;
* and reading in all of the remaining input.
*
*
*
* Historical note: {
@code
StdIn} preceded {
@code
Scanner}; when
* {
@code
Scanner} was introduced, this class was re-implemented to use {
@code
Scanner}.
*
* Using standard input.
* Standard input is a fundamental operating system abstraction on Mac OS X,
* Windows, and Linux.
* The methods in {
@code
StdIn} are blocking, which means that they
* will wait until you enter input on standard input.
* If your program has a loop that repeats until standard input is empty,
* you must signal that the input is finished.
* To do so, depending on your operating system and IDE,
* use either {
@code
@code
* If you are redirecting standard input from a file, you will not need
* to do anything to signal that the input is finished.
*
* Known bugs.
* Java’s UTF-8 encoding does not recognize the optional
* If the input begins with the optional byte-order mask, {
@code
StdIn}
* will have an extra character {
@code
\}{
@code
uFEFF} at the beginning.
*
* Reference.
* For additional documentation,
* see Section 1.5 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*
@author
David Pritchard
*/
public
final
class
StdIn
{
/*** begin: section (1 of 2) of code duplicated from In to StdIn. */
// assume Unicode UTF-8 encoding
private
static
final
String
CHARSET_NAME
=
“UTF-8”
;
// assume language = English, country = US for consistency with System.out.
private
static
final
Locale
LOCALE
=
Locale
.
US
;
// the default token separator; we maintain the invariant that this value
// is held by the scanner’s delimiter between calls
private
static
final
Pattern
WHITESPACE_PATTERN
=
Pattern
.
compile
(
“\\p{javaWhitespace}+”
);
// makes whitespace significant
private
static
final
Pattern
EMPTY_PATTERN
=
Pattern
.
compile
(
“”
);
// used to read the entire input
private
static
final
Pattern
EVERYTHING_PATTERN
=
Pattern
.
compile
(
“\\A”
);
/*** end: section (1 of 2) of code duplicated from In to StdIn. */
private
static
Scanner
scanner
;
// it doesn’t make sense to instantiate this class
private
StdIn
()
{
}
//// begin: section (2 of 2) of code duplicated from In to StdIn,
//// with all methods changed from “public” to “public static”
/**
* Returns true if standard input is empty (except possibly for whitespace).
* Use this method to know whether the next call to {
@link
#readString()},
* {
@link
#readDouble()}, etc will succeed.
*
*
@return
{
@code
true} if standard input is empty (except possibly
* for whitespace); {
@code
false} otherwise
*/
public
static
boolean
isEmpty
()
{
return
!
scanner
.
hasNext
();
}
/**
* Returns true if standard input has a next line.
* Use this method to know whether the
* next call to {
@link
#readLine()} will succeed.
* This method is functionally equivalent to {
@link
#hasNextChar()}.
*
*
@return
{
@code
true} if standard input has more input (including whitespace);
* {
@code
false} otherwise
*/
public
static
boolean
hasNextLine
()
{
return
scanner
.
hasNextLine
();
}
/**
* Returns true if standard input has more input (including whitespace).
* Use this method to know whether the next call to {
@link
#readChar()} will succeed.
* This method is functionally equivalent to {
@link
#hasNextLine()}.
*
*
@return
{
@code
true} if standard input has more input (including whitespace);
* {
@code
false} otherwise
*/
public
static
boolean
hasNextChar
()
{
scanner
.
useDelimiter
(
EMPTY_PATTERN
);
boolean
result
=
scanner
.
hasNext
();
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
return
result
;
}
/**
* Reads and returns the next line, excluding the line separator if present.
*
*
@return
the next line, excluding the line separator if present;
* {
@code
null} if no such line
*/
public
static
String
readLine
()
{
String
line
;
try
{
line
=
scanner
.
nextLine
();
}
catch
(
NoSuchElementException
e
)
{
line
=
null
;
}
return
line
;
}
/**
* Reads and returns the next character.
*
*
@return
the next {
@code
char}
*
@throws
NoSuchElementException if standard input is empty
*/
public
static
char
readChar
()
{
try
{
scanner
.
useDelimiter
(
EMPTY_PATTERN
);
String
ch
=
scanner
.
next
();
assert
ch
.
length
()
==
1
:
“Internal (Std)In.readChar() error!”
+
” Please contact the authors.”
;
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
return
ch
.
charAt
(
0
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘char’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads and returns the remainder of the input, as a string.
*
*
@return
the remainder of the input, as a string
*
@throws
NoSuchElementException if standard input is empty
*/
public
static
String
readAll
()
{
if
(
!
scanner
.
hasNextLine
())
return
“”
;
String
result
=
scanner
.
useDelimiter
(
EVERYTHING_PATTERN
).
next
();
// not that important to reset delimeter, since now scanner is empty
scanner
.
useDelimiter
(
WHITESPACE_PATTERN
);
// but let’s do it anyway
return
result
;
}
/**
* Reads the next token and returns the {
@code
String}.
*
*
@return
the next {
@code
String}
*
@throws
NoSuchElementException if standard input is empty
*/
public
static
String
readString
()
{
try
{
return
scanner
.
next
();
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘String’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as an integer, and returns the integer.
*
*
@return
the next integer on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as an {
@code
int}
*/
public
static
int
readInt
()
{
try
{
return
scanner
.
nextInt
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read an ‘int’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attemps to read an ‘int’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a double, and returns the double.
*
*
@return
the next double on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
double}
*/
public
static
double
readDouble
()
{
try
{
return
scanner
.
nextDouble
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘double’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘double’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a float, and returns the float.
*
*
@return
the next float on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
float}
*/
public
static
float
readFloat
()
{
try
{
return
scanner
.
nextFloat
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘float’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘float’ value from standard input, ”
+
“but there no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a long integer, and returns the long integer.
*
*
@return
the next long integer on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
long}
*/
public
static
long
readLong
()
{
try
{
return
scanner
.
nextLong
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘long’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘long’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a short integer, and returns the short integer.
*
*
@return
the next short integer on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
short}
*/
public
static
short
readShort
()
{
try
{
return
scanner
.
nextShort
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘short’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘short’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a byte, and returns the byte.
*
*
@return
the next byte on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
byte}
*/
public
static
byte
readByte
()
{
try
{
return
scanner
.
nextByte
();
}
catch
(
InputMismatchException
e
)
{
String
token
=
scanner
.
next
();
throw
new
InputMismatchException
(
“attempts to read a ‘byte’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘byte’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads the next token from standard input, parses it as a boolean,
* and returns the boolean.
*
*
@return
the next boolean on standard input
*
@throws
NoSuchElementException if standard input is empty
*
@throws
InputMismatchException if the next token cannot be parsed as a {
@code
boolean}:
* {
@code
true} or {
@code
1} for true, and {
@code
false} or {
@code
0} for false,
* ignoring case
*/
public
static
boolean
readBoolean
()
{
try
{
String
token
=
readString
();
if
(
“true”
.
equalsIgnoreCase
(
token
))
return
true
;
if
(
“false”
.
equalsIgnoreCase
(
token
))
return
false
;
if
(
“1”
.
equals
(
token
))
return
true
;
if
(
“0”
.
equals
(
token
))
return
false
;
throw
new
InputMismatchException
(
“attempts to read a ‘boolean’ value from standard input, ”
+
“but the next token is \””
+
token
+
“\””
);
}
catch
(
NoSuchElementException
e
)
{
throw
new
NoSuchElementException
(
“attempts to read a ‘boolean’ value from standard input, ”
+
“but no more tokens are available”
);
}
}
/**
* Reads all remaining tokens from standard input and returns them as an array of strings.
*
*
@return
all remaining tokens on standard input, as an array of strings
*/
public
static
String
[]
readAllStrings
()
{
// we could use readAll.trim().split(), but that’s not consistent
// because trim() uses characters 0x00..0x20 as whitespace
String
[]
tokens
=
WHITESPACE_PATTERN
.
split
(
readAll
());
if
(
tokens
.
length
==
0
||
tokens
[
0
].
length
()
>
0
)
return
tokens
;
// don’t include first token if it is leading whitespace
String
[]
decapitokens
=
new
String
[
tokens
.
length
–
1
];
for
(
int
i
=
0
;
i
<
tokens
.
length
-
1
;
i
++
)
decapitokens
[
i
]
=
tokens
[
i
+
1
];
return
decapitokens
;
}
/**
* Reads all remaining lines from standard input and returns them as an array of strings.
*
@return
all remaining lines on standard input, as an array of strings
*/
public
static
String
[]
readAllLines
()
{
ArrayList
<
String
>
lines
=
new
ArrayList
<
String
>
();
while
(
hasNextLine
())
{
lines
.
add
(
readLine
());
}
return
lines
.
toArray
(
new
String
[
lines
.
size
()]);
}
/**
* Reads all remaining tokens from standard input, parses them as integers, and returns
* them as an array of integers.
*
@return
all remaining integers on standard input, as an array
*
@throws
InputMismatchException if any token cannot be parsed as an {
@code
int}
*/
public
static
int
[]
readAllInts
()
{
String
[]
fields
=
readAllStrings
();
int
[]
vals
=
new
int
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Integer
.
parseInt
(
fields
[
i
]);
return
vals
;
}
/**
* Reads all remaining tokens from standard input, parses them as longs, and returns
* them as an array of longs.
*
@return
all remaining longs on standard input, as an array
*
@throws
InputMismatchException if any token cannot be parsed as a {
@code
long}
*/
public
static
long
[]
readAllLongs
()
{
String
[]
fields
=
readAllStrings
();
long
[]
vals
=
new
long
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Long
.
parseLong
(
fields
[
i
]);
return
vals
;
}
/**
* Reads all remaining tokens from standard input, parses them as doubles, and returns
* them as an array of doubles.
*
@return
all remaining doubles on standard input, as an array
*
@throws
InputMismatchException if any token cannot be parsed as a {
@code
double}
*/
public
static
double
[]
readAllDoubles
()
{
String
[]
fields
=
readAllStrings
();
double
[]
vals
=
new
double
[
fields
.
length
];
for
(
int
i
=
0
;
i
<
fields
.
length
;
i
++
)
vals
[
i
]
=
Double
.
parseDouble
(
fields
[
i
]);
return
vals
;
}
//// end: section (2 of 2) of code duplicated from In to StdIn
// do this once when StdIn is initialized
static
{
resync
();
}
/**
* If StdIn changes, use this to reinitialize the scanner.
*/
private
static
void
resync
()
{
setScanner
(
new
Scanner
(
new
java
.
io
.
BufferedInputStream
(
System
.
in
),
CHARSET_NAME
));
}
private
static
void
setScanner
(
Scanner
scanner
)
{
StdIn
.
scanner
=
scanner
;
StdIn
.
scanner
.
useLocale
(
LOCALE
);
}
/**
* Reads all remaining tokens, parses them as integers, and returns
* them as an array of integers.
*
@return
all remaining integers, as an array
*
@throws
InputMismatchException if any token cannot be parsed as an {
@code
int}
*
@deprecated
Replaced by {
@link
#readAllInts()}.
*/
@
Deprecated
public
static
int
[]
readInts
()
{
return
readAllInts
();
}
/**
* Reads all remaining tokens, parses them as doubles, and returns
* them as an array of doubles.
*
@return
all remaining doubles, as an array
*
@throws
InputMismatchException if any token cannot be parsed as a {
@code
double}
*
@deprecated
Replaced by {
@link
#readAllDoubles()}.
*/
@
Deprecated
public
static
double
[]
readDoubles
()
{
return
readAllDoubles
();
}
/**
* Reads all remaining tokens and returns them as an array of strings.
*
@return
all remaining tokens, as an array of strings
*
@deprecated
Replaced by {
@link
#readAllStrings()}.
*/
@
Deprecated
public
static
String
[]
readStrings
()
{
return
readAllStrings
();
}
/**
* Interactive test of basic functionality.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
StdOut
.
print
(
"Type a string: "
);
String
s
=
StdIn
.
readString
();
StdOut
.
println
(
"Your string was: "
+
s
);
StdOut
.
println
();
StdOut
.
print
(
"Type an int: "
);
int
a
=
StdIn
.
readInt
();
StdOut
.
println
(
"Your int was: "
+
a
);
StdOut
.
println
();
StdOut
.
print
(
"Type a boolean: "
);
boolean
b
=
StdIn
.
readBoolean
();
StdOut
.
println
(
"Your boolean was: "
+
b
);
StdOut
.
println
();
StdOut
.
print
(
"Type a double: "
);
double
c
=
StdIn
.
readDouble
();
StdOut
.
println
(
"Your double was: "
+
c
);
StdOut
.
println
();
}
}
StdInTest.java
StdInTest.java
/**
* Test client for StdIn and In.
**/
import
java
.
util
.
Scanner
;
import
java
.
lang
.
reflect
.
Array
;
import
java
.
lang
.
reflect
.
Method
;
import
java
.
io
.
ByteArrayInputStream
;
public
class
StdInTest
{
private
static
boolean
testStdIn
;
private
static
Method
resyncMethod
;
private
static
int
testCount
=
0
;
// make a printable/readable version of an object
public
static
Object
escape
(
Object
original
)
{
if
(
original
instanceof
Character
)
{
char
u
=
(
char
)
((
Character
)
original
);
int
idx
=
"\b\t\n\f\r\"\'\\"
.
indexOf
(
u
);
if
(
idx
>=
0
)
return
“\\”
+
“btnfr\”\’\\”
.
charAt
(
idx
);
if
(
u
<
32
)
return
"\\"
+
Integer
.
toOctalString
(
u
);
if
(
u
>
126
)
return
“\\u”
+
String
.
format
(
“%04X”
,
(
int
)
u
);
return
original
;
}
else
if
(
original
instanceof
String
)
{
StringBuilder
result
=
new
StringBuilder
();
for
(
char
c
:
((
String
)
original
).
toCharArray
())
result
.
append
(
escape
(
c
));
return
“\””
+
result
.
toString
()
+
“\””
;
}
else
if
(
original
.
getClass
().
isArray
())
{
StringBuilder
result
=
new
StringBuilder
(
“[”
);
int
len
=
Array
.
getLength
(
original
);
for
(
int
i
=
0
;
i
<
len
;
i
++
)
result
.
append
(
" "
).
append
(
escape
(
Array
.
get
(
original
,
i
)));
return
result
.
append
(
"]"
).
toString
();
}
return
original
;
}
public
static
boolean
canResync
()
{
try
{
resyncMethod
=
StdIn
.
class
.
getMethod
(
"resync"
);
}
catch
(
NoSuchMethodException
e
)
{
return
false
;
}
return
true
;
}
/**
* In the two methods below, each Object[] of "steps" is a length-2
* array: the first is a String holding a method name, the second
* is the expected return value when that method is called in sequence.
*/
public
static
void
test
(
String
input
,
Object
[][]
steps
)
{
test
(
input
,
steps
,
false
);
// create Scanner from String
if
(
testStdIn
)
test
(
input
,
steps
,
true
);
// uses stdIn/System.setIn
testCount
++
;
}
public
static
void
test
(
String
input
,
Object
[][]
steps
,
boolean
useStdIn
)
{
In
in
=
null
;
if
(
useStdIn
)
{
try
{
System
.
setIn
(
new
ByteArrayInputStream
(
input
.
getBytes
(
"UTF-8"
)));
}
catch
(
java
.
io
.
UnsupportedEncodingException
e
)
{
throw
new
RuntimeException
(
e
.
toString
());
}
// in order for this to work, you need to change resync to public
try
{
//call StdIn.resync();
resyncMethod
.
invoke
(
null
);
}
catch
(
IllegalAccessException
e
)
{
throw
new
RuntimeException
(
e
.
toString
());
}
catch
(
java
.
lang
.
reflect
.
InvocationTargetException
e
)
{
throw
new
RuntimeException
(
e
.
toString
());
}
}
else
in
=
new
In
(
new
Scanner
(
input
));
int
count
=
0
;
for
(
Object
[]
step
:
steps
)
{
String
cmd
=
(
String
)
step
[
0
];
Object
expected
=
step
[
1
];
Object
result
;
String
preamble
=
"Failed input %s\nStep %d (%s)\n"
;
try
{
Method
method
;
// nice and easy since these methods take no arguments
if
(
useStdIn
)
method
=
StdIn
.
class
.
getMethod
(
cmd
);
else
method
=
in
.
getClass
().
getMethod
(
cmd
);
result
=
method
.
invoke
(
in
);
// fine to be null for static
}
catch
(
NoSuchMethodException
e
)
{
java
.
io
.
StringWriter
errors
=
new
java
.
io
.
StringWriter
();
e
.
printStackTrace
(
new
java
.
io
.
PrintWriter
(
errors
));
throw
new
RuntimeException
(
String
.
format
(
preamble
,
input
,
count
,
cmd
)
+
errors
.
toString
());
}
catch
(
IllegalAccessException
e
)
{
java
.
io
.
StringWriter
errors
=
new
java
.
io
.
StringWriter
();
e
.
printStackTrace
(
new
java
.
io
.
PrintWriter
(
errors
));
throw
new
RuntimeException
(
String
.
format
(
preamble
,
input
,
count
,
cmd
)
+
errors
.
toString
());
}
catch
(
java
.
lang
.
reflect
.
InvocationTargetException
e
)
{
java
.
io
.
StringWriter
errors
=
new
java
.
io
.
StringWriter
();
e
.
printStackTrace
(
new
java
.
io
.
PrintWriter
(
errors
));
e
.
getCause
().
printStackTrace
(
new
java
.
io
.
PrintWriter
(
errors
));
throw
new
RuntimeException
(
String
.
format
(
preamble
,
input
,
count
,
cmd
)
+
errors
.
toString
());
}
if
(
expected
.
getClass
().
isArray
())
{
if
(
!
(
result
.
getClass
().
isArray
()))
{
StdOut
.
printf
(
preamble
+
"Expected array, got %s\n"
,
input
,
count
,
cmd
,
result
);
continue
;
}
Object
r
=
result
,
e
=
expected
;
// to shorten lines below
int
rl
=
Array
.
getLength
(
r
);
int
el
=
Array
.
getLength
(
e
);
if
(
el
!=
rl
)
StdOut
.
printf
(
preamble
+
"Expected %d, got %d items:\n%s\n"
,
escape
(
input
),
count
,
cmd
,
el
,
rl
,
escape
(
r
));
else
{
for
(
int
i
=
0
;
i
<
rl
;
i
++
)
{
if
(
!
(
Array
.
get
(
r
,
i
).
equals
(
Array
.
get
(
e
,
i
))))
StdOut
.
printf
(
preamble
+
"\nExpected [%d]=%s, got %s\n"
,
escape
(
input
),
count
,
cmd
,
i
,
escape
(
Array
.
get
(
e
,
i
)),
escape
(
Array
.
get
(
r
,
i
)));
}
}
}
else
if
(
!
result
.
equals
(
expected
))
{
StdOut
.
printf
(
preamble
+
"Expected %s, got %s\n"
,
escape
(
input
),
count
,
cmd
,
escape
(
expected
),
escape
(
result
));
}
count
++
;
}
}
public
static
void
main
(
String
[]
args
)
{
testStdIn
=
canResync
();
if
(
testStdIn
)
StdOut
.
println
(
"Note: any errors appear duplicated since tests run 2x."
);
else
StdOut
.
println
(
"Note: StdIn.resync is private, only In will be tested."
);
test
(
"this is a test"
,
new
Object
[][]
{
{
"isEmpty"
,
false
},
{
"hasNextChar"
,
true
},
{
"hasNextLine"
,
true
},
{
"readAllStrings"
,
new
String
[]
{
"this"
,
"is"
,
"a"
,
"test"
}},
{
"isEmpty"
,
true
},
{
"hasNextChar"
,
false
},
{
"hasNextLine"
,
false
}
});
test
(
"\n\n\n"
,
new
Object
[][]
{
{
"isEmpty"
,
true
},
{
"hasNextChar"
,
true
},
{
"hasNextLine"
,
true
},
{
"readAll"
,
"\n\n\n"
}
});
test
(
""
,
new
Object
[][]
{
{
"isEmpty"
,
true
},
{
"hasNextChar"
,
false
},
{
"hasNextLine"
,
false
}
});
test
(
"\t\t \t\t"
,
new
Object
[][]
{
{
"isEmpty"
,
true
},
{
"hasNextChar"
,
true
},
{
"hasNextLine"
,
true
},
{
"readAll"
,
"\t\t \t\t"
}
});
test
(
"readLine consumes newline\nyeah!"
,
new
Object
[][]
{
{
"readLine"
,
"readLine consumes newline"
},
{
"readChar"
,
'y'
}
});
test
(
"readString doesn't consume spaces"
,
new
Object
[][]
{
{
"readString"
,
"readString"
},
{
"readChar"
,
' '
}
});
test
(
"\n\nblank lines test"
,
new
Object
[][]
{
{
"readLine"
,
""
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"readLine"
,
"blank lines test"
},
{
"hasNextLine"
,
false
}
});
test
(
" \n \t \n correct \n\t\n\t .trim replacement \n\t"
,
new
Object
[][]
{
{
"readAllStrings"
,
new
String
[]{
"correct"
,
".trim"
,
"replacement"
}},
{
"hasNextChar"
,
false
}
});
StringBuilder
sb
=
new
StringBuilder
();
Object
[][]
expected
=
new
Object
[
2000
][
2
];
for
(
int
i
=
0
;
i
<
1000
;
i
++
)
{
sb
.
append
((
char
)
i
);
sb
.
append
((
char
)
(
i
+
8000
));
// include weird non-breaking spaces
expected
[
2
*
i
][
0
]
=
"readChar"
;
expected
[
2
*
i
+
1
][
0
]
=
"readChar"
;
expected
[
2
*
i
][
1
]
=
(
char
)
i
;
expected
[
2
*
i
+
1
][
1
]
=
(
char
)(
i
+
8000
);
}
test
(
sb
.
toString
(),
expected
);
test
(
" this \n and \that \n "
,
new
Object
[][]
{
{
"readString"
,
"this"
},
{
"readString"
,
"and"
},
{
"readChar"
,
' '
},
{
"readString"
,
"hat"
},
{
"readChar"
,
' '
},
{
"isEmpty"
,
true
},
{
"hasNextLine"
,
true
},
{
"readLine"
,
""
},
{
"readLine"
,
" "
}
});
test
(
" 1 2 3 \n\t 4 5 "
,
new
Object
[][]
{
{
"readAllInts"
,
new
int
[]
{
1
,
2
,
3
,
4
,
5
}}
});
test
(
" 0 1 False true falsE True "
,
new
Object
[][]
{
{
"readBoolean"
,
false
},
{
"readBoolean"
,
true
},
{
"readBoolean"
,
false
},
{
"readBoolean"
,
true
},
{
"readBoolean"
,
false
},
{
"readBoolean"
,
true
}
});
test
(
" \240\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008"
+
"\u2009\u200A\u205F\u3000"
,
new
Object
[][]
{
{
"readString"
,
"\240"
},
// non-breaking space - not java whitespace
{
"readString"
,
"\u2007"
},
// similarly
{
"hasNextChar"
,
true
},
// there is some stuff left over
{
"isEmpty"
,
true
},
// but it is all whitespace
{
"readChar"
,
'\u2008'
}
// such as this one
});
// line sep, par sep, NEL, unit sep, vtab --- first 3 are newlines
// NB: \205 is treated as a line separator, but not whitespace!
test
(
"a\u2028b\u2029c\37d\13e\205f"
,
new
Object
[][]
{
{
"readAllStrings"
,
new
String
[]{
"a"
,
"b"
,
"c"
,
"d"
,
"e\205f"
}}
});
test
(
"a\u2028b\u2029c\37d\13e\205f"
,
new
Object
[][]
{
{
"readLine"
,
"a"
},
{
"readLine"
,
"b"
},
{
"readLine"
,
"c\37d\13e"
},
{
"readLine"
,
"f"
}
});
test
(
"\u2028\u2029"
,
// line separator, par separator
new
Object
[][]
{
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"hasNextChar"
,
true
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
false
},
{
"hasNextChar"
,
false
}
});
test
(
"\n\n"
,
new
Object
[][]
{
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"hasNextChar"
,
true
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
false
},
{
"hasNextChar"
,
false
}
});
test
(
"\r\n\r\n"
,
new
Object
[][]
{
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"hasNextChar"
,
true
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
false
},
{
"hasNextChar"
,
false
}
});
test
(
"\n\r"
,
new
Object
[][]
{
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"hasNextChar"
,
true
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
false
},
{
"hasNextChar"
,
false
}
});
test
(
"\r\n"
,
new
Object
[][]
{
{
"readLine"
,
""
},
{
"hasNextChar"
,
false
},
{
"hasNextLine"
,
false
}
});
test
(
"3E4 \t -0.5 \n \t +4"
,
new
Object
[][]
{
{
"readAllDoubles"
,
new
double
[]
{
30000
,
-
0.5
,
4
}}
});
test
(
" whitespace "
,
new
Object
[][]
{
{
"readString"
,
"whitespace"
},
{
"readChar"
,
' '
},
{
"hasNextLine"
,
false
}
});
test
(
" whitespace \n"
,
new
Object
[][]
{
{
"readString"
,
"whitespace"
},
{
"readChar"
,
' '
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
false
}
});
test
(
" whitespace \n "
,
new
Object
[][]
{
{
"readString"
,
"whitespace"
},
{
"readChar"
,
' '
},
{
"readLine"
,
""
},
{
"hasNextLine"
,
true
},
{
"readLine"
,
" "
},
{
"hasNextLine"
,
false
}
});
test
(
" 34 -12983 3.25\n\t foo!"
,
new
Object
[][]
{
{
"readByte"
,
(
byte
)
34
},
{
"readShort"
,
(
short
)
-
12983
},
{
"readDouble"
,
3.25
},
{
"readAll"
,
"\n\t foo!"
}
});
test
(
"30000000000 3.5 3e4, foo \t\t ya"
,
new
Object
[][]
{
{
"readLong"
,
30000000000L
},
{
"readFloat"
,
(
float
)
3.5
},
{
"readAllStrings"
,
new
String
[]
{
"3e4,"
,
"foo"
,
"ya"
}}
});
// testing consistency of whitespace and read(All)String(s)
test
(
" \u0001 foo \u0001 foo \u0001 foo"
,
new
Object
[][]
{
{
"readAllStrings"
,
new
String
[]
{
"\u0001"
,
"foo"
,
"\u0001"
,
"foo"
,
"\u0001"
,
"foo"
}}
});
test
(
" \u2005 foo \u2005 foo \u2005 foo"
,
new
Object
[][]
{
{
"readAllStrings"
,
new
String
[]
{
"foo"
,
"foo"
,
"foo"
}}
});
test
(
" \u0001 foo \u0001 foo \u0001 foo"
,
new
Object
[][]
{
{
"readString"
,
"\u0001"
},
{
"readString"
,
"foo"
},
{
"readString"
,
"\u0001"
},
{
"readString"
,
"foo"
},
{
"readString"
,
"\u0001"
},
{
"readString"
,
"foo"
}
});
test
(
" \u2005 foo \u2005 foo \u2005 foo"
,
new
Object
[][]
{
{
"readString"
,
"foo"
},
{
"readString"
,
"foo"
},
{
"readString"
,
"foo"
}
});
StdOut
.
printf
(
"Ran %d tests.\n"
,
testCount
);
}
}
StdOut.java
StdOut.java
/******************************************************************************
* Compilation: javac StdOut.java
* Execution: java StdOut
* Dependencies: none
*
* Writes data of various types to standard output.
*
******************************************************************************/
import
java
.
io
.
OutputStreamWriter
;
import
java
.
io
.
PrintWriter
;
import
java
.
io
.
UnsupportedEncodingException
;
import
java
.
util
.
Locale
;
/**
* This class provides methods for printing strings and numbers to standard output.
*
* Getting started.
* To use this class, you must have {
@code
StdOut.class} in your
* Java classpath. If you used our autoinstaller, you should be all set.
* Otherwise, either download
* and add to your Java classpath or download
* and put a copy in your working directory.
*
* Here is an example program that uses {
@code
StdOut}:
*
* public class TestStdOut { * public static void main(String[] args) { * int a = 17; * int b = 23; * int sum = a + b; * StdOut.println("Hello, World"); * StdOut.printf("%d + %d = %d\n", a, b, sum); * } * } *
*
* Differences with System.out.
* The behavior of {
@code
StdOut} is similar to that of {
@link
System#out},
* but there are a few technical differences:
*
- {
@code
StdOut} coerces the character-set encoding to UTF-8,* which is a standard character encoding for Unicode.
*
- {
@code
StdOut} coerces the locale to {
@link
Locale#US},* for consistency with {
@link
StdIn}, {
@link
Double#parseDouble(String)},* and floating-point literals.
*
- {
@code
StdOut} flushes standard output after each call to* {
@code
print()} so that text will appear immediately in the terminal.*
*
*
* Reference.
* For additional documentation,
* see Section 1.5 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
StdOut
{
// force Unicode UTF-8 encoding; otherwise it’s system dependent
private
static
final
String
CHARSET_NAME
=
“UTF-8”
;
// assume language = English, country = US for consistency with StdIn
private
static
final
Locale
LOCALE
=
Locale
.
US
;
// send output here
private
static
PrintWriter
out
;
// this is called before invoking any methods
static
{
try
{
out
=
new
PrintWriter
(
new
OutputStreamWriter
(
System
.
out
,
CHARSET_NAME
),
true
);
}
catch
(
UnsupportedEncodingException
e
)
{
System
.
out
.
println
(
e
);
}
}
// don’t instantiate
private
StdOut
()
{
}
/**
* Terminates the current line by printing the line-separator string.
*/
public
static
void
println
()
{
out
.
println
();
}
/**
* Prints an object to this output stream and then terminates the line.
*
*
@param
x the object to print
*/
public
static
void
println
(
Object
x
)
{
out
.
println
(
x
);
}
/**
* Prints a boolean to standard output and then terminates the line.
*
*
@param
x the boolean to print
*/
public
static
void
println
(
boolean
x
)
{
out
.
println
(
x
);
}
/**
* Prints a character to standard output and then terminates the line.
*
*
@param
x the character to print
*/
public
static
void
println
(
char
x
)
{
out
.
println
(
x
);
}
/**
* Prints a double to standard output and then terminates the line.
*
*
@param
x the double to print
*/
public
static
void
println
(
double
x
)
{
out
.
println
(
x
);
}
/**
* Prints an integer to standard output and then terminates the line.
*
*
@param
x the integer to print
*/
public
static
void
println
(
float
x
)
{
out
.
println
(
x
);
}
/**
* Prints an integer to standard output and then terminates the line.
*
*
@param
x the integer to print
*/
public
static
void
println
(
int
x
)
{
out
.
println
(
x
);
}
/**
* Prints a long to standard output and then terminates the line.
*
*
@param
x the long to print
*/
public
static
void
println
(
long
x
)
{
out
.
println
(
x
);
}
/**
* Prints a short integer to standard output and then terminates the line.
*
*
@param
x the short to print
*/
public
static
void
println
(
short
x
)
{
out
.
println
(
x
);
}
/**
* Prints a byte to standard output and then terminates the line.
*
* To write binary data, see {
@link
BinaryStdOut}.
*
*
@param
x the byte to print
*/
public
static
void
println
(
byte
x
)
{
out
.
println
(
x
);
}
/**
* Flushes standard output.
*/
public
static
void
print
()
{
out
.
flush
();
}
/**
* Prints an object to standard output and flushes standard output.
*
*
@param
x the object to print
*/
public
static
void
print
(
Object
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a boolean to standard output and flushes standard output.
*
*
@param
x the boolean to print
*/
public
static
void
print
(
boolean
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a character to standard output and flushes standard output.
*
*
@param
x the character to print
*/
public
static
void
print
(
char
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a double to standard output and flushes standard output.
*
*
@param
x the double to print
*/
public
static
void
print
(
double
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a float to standard output and flushes standard output.
*
*
@param
x the float to print
*/
public
static
void
print
(
float
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints an integer to standard output and flushes standard output.
*
*
@param
x the integer to print
*/
public
static
void
print
(
int
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a long integer to standard output and flushes standard output.
*
*
@param
x the long integer to print
*/
public
static
void
print
(
long
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a short integer to standard output and flushes standard output.
*
*
@param
x the short integer to print
*/
public
static
void
print
(
short
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a byte to standard output and flushes standard output.
*
*
@param
x the byte to print
*/
public
static
void
print
(
byte
x
)
{
out
.
print
(
x
);
out
.
flush
();
}
/**
* Prints a formatted string to standard output, using the specified format
* string and arguments, and then flushes standard output.
*
*
*
@param
format the format string
*
@param
args the arguments accompanying the format string
*/
public
static
void
printf
(
String
format
,
Object
…
args
)
{
out
.
printf
(
LOCALE
,
format
,
args
);
out
.
flush
();
}
/**
* Prints a formatted string to standard output, using the locale and
* the specified format string and arguments; then flushes standard output.
*
*
@param
locale the locale
*
@param
format the format string
*
@param
args the arguments accompanying the format string
*/
public
static
void
printf
(
Locale
locale
,
String
format
,
Object
…
args
)
{
out
.
printf
(
locale
,
format
,
args
);
out
.
flush
();
}
/**
* Unit tests some of the methods in {
@code
StdOut}.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
// write to stdout
StdOut
.
println
(
“Test”
);
StdOut
.
println
(
17
);
StdOut
.
println
(
true
);
StdOut
.
printf
(
“%.6f\n”
,
1.0
/
7.0
);
}
}
StdRandom.java
StdRandom.java
/******************************************************************************
* Compilation: javac StdRandom.java
* Execution: java StdRandom
* Dependencies: StdOut.java
*
* A library of static methods to generate pseudo-random numbers from
* different distributions (bernoulli, uniform, gaussian, discrete,
* and exponential). Also includes a method for shuffling an array.
*
*
* % java StdRandom 5
* seed = 1316600602069
* 59 16.81826 true 8.83954 0
* 32 91.32098 true 9.11026 0
* 35 10.11874 true 8.95396 3
* 92 32.88401 true 8.87089 0
* 72 92.55791 true 9.46241 0
*
* % java StdRandom 5
* seed = 1316600616575
* 96 60.17070 true 8.72821 0
* 79 32.01607 true 8.58159 0
* 81 59.49065 true 9.10423 1
* 96 51.65818 true 9.02102 0
* 99 17.55771 true 8.99762 0
*
* % java StdRandom 5 1316600616575
* seed = 1316600616575
* 96 60.17070 true 8.72821 0
* 79 32.01607 true 8.58159 0
* 81 59.49065 true 9.10423 1
* 96 51.65818 true 9.02102 0
* 99 17.55771 true 8.99762 0
*
*
* Remark
* ——
* – Relies on randomness of nextDouble() method in java.util.Random
* to generate pseudo-random numbers in [0, 1).
*
* – This library allows you to set and get the pseudo-random number seed.
*
* – See http://www.honeylocust.com/RngPack/ for an industrial
* strength random number generator in Java.
*
******************************************************************************/
import
java
.
util
.
Random
;
/**
* The {
@code
StdRandom} class provides static methods for generating
* random number from various discrete and continuous distributions,
* including uniform, Bernoulli, geometric, Gaussian, exponential, Pareto,
* Poisson, and Cauchy. It also provides method for shuffling an
* array or subarray and generating random permutations.
*
* By convention, all intervals are half open. For example,
* uniform(-1.0, 1.0)
returns a random number between
* -1.0
(inclusive) and 1.0
(exclusive).
* Similarly, shuffle(a, lo, hi)
shuffles the hi - lo
* elements in the array a[]
, starting at index lo
* (inclusive) and ending at index hi
(exclusive).
*
* For additional documentation,
* see Section 2.2 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
StdRandom
{
private
static
Random
random
;
// pseudo-random number generator
private
static
long
seed
;
// pseudo-random number generator seed
// static initializer
static
{
// this is how the seed was set in Java 1.4
seed
=
System
.
currentTimeMillis
();
random
=
new
Random
(
seed
);
}
// don’t instantiate
private
StdRandom
()
{
}
/**
* Sets the seed of the pseudo-random number generator.
* This method enables you to produce the same sequence of “random”
* number for each execution of the program.
* Ordinarily, you should call this method at most once per program.
*
*
@param
s the seed
*/
public
static
void
setSeed
(
long
s
)
{
seed
=
s
;
random
=
new
Random
(
seed
);
}
/**
* Returns the seed of the pseudo-random number generator.
*
*
@return
the seed
*/
public
static
long
getSeed
()
{
return
seed
;
}
/**
* Returns a random real number uniformly in [0, 1).
*
*
@return
a random real number uniformly in [0, 1)
*/
public
static
double
uniform
()
{
return
random
.
nextDouble
();
}
/**
* Returns a random integer uniformly in [0, n).
*
*
@param
n number of possible integers
*
@return
a random integer uniformly between 0 (inclusive) and {
@code
n} (exclusive)
*
@throws
IllegalArgumentException if {
@code
n <= 0}
*/
public
static
int
uniform
(
int
n
)
{
if
(
n
<=
0
)
throw
new
IllegalArgumentException
(
"argument must be positive: "
+
n
);
return
random
.
nextInt
(
n
);
}
/**
* Returns a random long integer uniformly in [0, n).
*
*
@param
n number of possible {
@code
long} integers
*
@return
a random long integer uniformly between 0 (inclusive) and {
@code
n} (exclusive)
*
@throws
IllegalArgumentException if {
@code
n <= 0}
*/
public
static
long
uniform
(
long
n
)
{
if
(
n
<=
0L
)
throw
new
IllegalArgumentException
(
"argument must be positive: "
+
n
);
// https://docs.oracle.com/javase/8/docs/api/java/util/Random.html#longs-long-long-long-
long
r
=
random
.
nextLong
();
long
m
=
n
-
1
;
// power of two
if
((
n
&
m
)
==
0L
)
{
return
r
&
m
;
}
// reject over-represented candidates
long
u
=
r
>>>
1
;
while
(
u
+
m
–
(
r
=
u
%
n
)
<
0L
)
{
u
=
random
.
nextLong
()
>>>
1
;
}
return
r
;
}
///////////////////////////////////////////////////////////////////////////
// STATIC METHODS BELOW RELY ON JAVA.UTIL.RANDOM ONLY INDIRECTLY VIA
// THE STATIC METHODS ABOVE.
///////////////////////////////////////////////////////////////////////////
/**
* Returns a random real number uniformly in [0, 1).
*
*
@return
a random real number uniformly in [0, 1)
*
@deprecated
Replaced by {
@link
#uniform()}.
*/
@
Deprecated
public
static
double
random
()
{
return
uniform
();
}
/**
* Returns a random integer uniformly in [a, b).
*
*
@param
a the left endpoint
*
@param
b the right endpoint
*
@return
a random integer uniformly in [a, b)
*
@throws
IllegalArgumentException if {
@code
b <= a}
*
@throws
IllegalArgumentException if {
@code
b - a >= Integer.MAX_VALUE}
*/
public
static
int
uniform
(
int
a
,
int
b
)
{
if
((
b
<=
a
)
||
((
long
)
b
-
a
>=
Integer
.
MAX_VALUE
))
{
throw
new
IllegalArgumentException
(
“invalid range: [”
+
a
+
“, ”
+
b
+
“)”
);
}
return
a
+
uniform
(
b
–
a
);
}
/**
* Returns a random real number uniformly in [a, b).
*
*
@param
a the left endpoint
*
@param
b the right endpoint
*
@return
a random real number uniformly in [a, b)
*
@throws
IllegalArgumentException unless {
@code
a < b}
*/
public
static
double
uniform
(
double
a
,
double
b
)
{
if
(
!
(
a
<
b
))
{
throw
new
IllegalArgumentException
(
"invalid range: ["
+
a
+
", "
+
b
+
")"
);
}
return
a
+
uniform
()
*
(
b
-
a
);
}
/**
* Returns a random boolean from a Bernoulli distribution with success
* probability p.
*
*
@param
p the probability of returning {
@code
true}
*
@return
{
@code
true} with probability {
@code
p} and
* {
@code
false} with probability {
@code
1 – p}
*
@throws
IllegalArgumentException unless {
@code
0} ≤ {
@code
p} ≤ {
@code
1.0}
*/
public
static
boolean
bernoulli
(
double
p
)
{
if
(
!
(
p
>=
0.0
&&
p
<=
1.0
))
throw
new
IllegalArgumentException
(
"probability p must be between 0.0 and 1.0: "
+
p
);
return
uniform
()
<
p
;
}
/**
* Returns a random boolean from a Bernoulli distribution with success
* probability 1/2.
*
*
@return
{
@code
true} with probability 1/2 and
* {
@code
false} with probability 1/2
*/
public
static
boolean
bernoulli
()
{
return
bernoulli
(
0.5
);
}
/**
* Returns a random real number from a standard Gaussian distribution.
*
*
@return
a random real number from a standard Gaussian distribution
* (mean 0 and standard deviation 1).
*/
public
static
double
gaussian
()
{
// use the polar form of the Box-Muller transform
double
r
,
x
,
y
;
do
{
x
=
uniform
(
-
1.0
,
1.0
);
y
=
uniform
(
-
1.0
,
1.0
);
r
=
x
*
x
+
y
*
y
;
}
while
(
r
>=
1
||
r
==
0
);
return
x
*
Math
.
sqrt
(
–
2
*
Math
.
log
(
r
)
/
r
);
// Remark: y * Math.sqrt(-2 * Math.log(r) / r)
// is an independent random gaussian
}
/**
* Returns a random real number from a Gaussian distribution with mean μ
* and standard deviation σ.
*
*
@param
mu the mean
*
@param
sigma the standard deviation
*
@return
a real number distributed according to the Gaussian distribution
* with mean {
@code
mu} and standard deviation {
@code
sigma}
*/
public
static
double
gaussian
(
double
mu
,
double
sigma
)
{
return
mu
+
sigma
*
gaussian
();
}
/**
* Returns a random integer from a geometric distribution with success
* probability p.
* The integer represents the number of independent trials
* before the first success.
*
*
@param
p the parameter of the geometric distribution
*
@return
a random integer from a geometric distribution with success
* probability {
@code
p}; or {
@code
Integer.MAX_VALUE} if
* {
@code
p} is (nearly) equal to {
@code
1.0}.
*
@throws
IllegalArgumentException unless {
@code
p >= 0.0} and {
@code
p <= 1.0}
*/
public
static
int
geometric
(
double
p
)
{
if
(
!
(
p
>=
0
))
{
throw
new
IllegalArgumentException
(
“probability p must be greater than 0: ”
+
p
);
}
if
(
!
(
p
<=
1.0
))
{
throw
new
IllegalArgumentException
(
"probability p must not be larger than 1: "
+
p
);
}
// using algorithm given by Knuth
return
(
int
)
Math
.
ceil
(
Math
.
log
(
uniform
())
/
Math
.
log
(
1.0
-
p
));
}
/**
* Returns a random integer from a Poisson distribution with mean λ.
*
*
@param
lambda the mean of the Poisson distribution
*
@return
a random integer from a Poisson distribution with mean {
@code
lambda}
*
@throws
IllegalArgumentException unless {
@code
lambda > 0.0} and not infinite
*/
public
static
int
poisson
(
double
lambda
)
{
if
(
!
(
lambda
>
0.0
))
throw
new
IllegalArgumentException
(
“lambda must be positive: ”
+
lambda
);
if
(
Double
.
isInfinite
(
lambda
))
throw
new
IllegalArgumentException
(
“lambda must not be infinite: ”
+
lambda
);
// using algorithm given by Knuth
// see http://en.wikipedia.org/wiki/Poisson_distribution
int
k
=
0
;
double
p
=
1.0
;
double
expLambda
=
Math
.
exp
(
–
lambda
);
do
{
k
++
;
p
*=
uniform
();
}
while
(
p
>=
expLambda
);
return
k
–
1
;
}
/**
* Returns a random real number from the standard Pareto distribution.
*
*
@return
a random real number from the standard Pareto distribution
*/
public
static
double
pareto
()
{
return
pareto
(
1.0
);
}
/**
* Returns a random real number from a Pareto distribution with
* shape parameter α.
*
*
@param
alpha shape parameter
*
@return
a random real number from a Pareto distribution with shape
* parameter {
@code
alpha}
*
@throws
IllegalArgumentException unless {
@code
alpha > 0.0}
*/
public
static
double
pareto
(
double
alpha
)
{
if
(
!
(
alpha
>
0.0
))
throw
new
IllegalArgumentException
(
“alpha must be positive: ”
+
alpha
);
return
Math
.
pow
(
1
–
uniform
(),
–
1.0
/
alpha
)
–
1.0
;
}
/**
* Returns a random real number from the Cauchy distribution.
*
*
@return
a random real number from the Cauchy distribution.
*/
public
static
double
cauchy
()
{
return
Math
.
tan
(
Math
.
PI
*
(
uniform
()
–
0.5
));
}
/**
* Returns a random integer from the specified discrete distribution.
*
*
@param
probabilities the probability of occurrence of each integer
*
@return
a random integer from a discrete distribution:
* {
@code
i} with probability {
@code
probabilities[i]}
*
@throws
IllegalArgumentException if {
@code
probabilities} is {
@code
null}
*
@throws
IllegalArgumentException if sum of array entries is not (very nearly) equal to {
@code
1.0}
*
@throws
IllegalArgumentException unless {
@code
probabilities[i] >= 0.0} for each index {
@code
i}
*/
public
static
int
discrete
(
double
[]
probabilities
)
{
if
(
probabilities
==
null
)
throw
new
IllegalArgumentException
(
“argument array is null”
);
double
EPSILON
=
1.0E-14
;
double
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
probabilities
.
length
;
i
++
)
{
if
(
!
(
probabilities
[
i
]
>=
0.0
))
throw
new
IllegalArgumentException
(
“array entry ”
+
i
+
” must be nonnegative: ”
+
probabilities
[
i
]);
sum
+=
probabilities
[
i
];
}
if
(
sum
>
1.0
+
EPSILON
||
sum
<
1.0
-
EPSILON
)
throw
new
IllegalArgumentException
(
"sum of array entries does not approximately equal 1.0: "
+
sum
);
// the for loop may not return a value when both r is (nearly) 1.0 and when the
// cumulative sum is less than 1.0 (as a result of floating-point roundoff error)
while
(
true
)
{
double
r
=
uniform
();
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
probabilities
.
length
;
i
++
)
{
sum
=
sum
+
probabilities
[
i
];
if
(
sum
>
r
)
return
i
;
}
}
}
/**
* Returns a random integer from the specified discrete distribution.
*
*
@param
frequencies the frequency of occurrence of each integer
*
@return
a random integer from a discrete distribution:
* {
@code
i} with probability proportional to {
@code
frequencies[i]}
*
@throws
IllegalArgumentException if {
@code
frequencies} is {
@code
null}
*
@throws
IllegalArgumentException if all array entries are {
@code
0}
*
@throws
IllegalArgumentException if {
@code
frequencies[i]} is negative for any index {
@code
i}
*
@throws
IllegalArgumentException if sum of frequencies exceeds {
@code
Integer.MAX_VALUE} (231 – 1)
*/
public
static
int
discrete
(
int
[]
frequencies
)
{
if
(
frequencies
==
null
)
throw
new
IllegalArgumentException
(
“argument array is null”
);
long
sum
=
0
;
for
(
int
i
=
0
;
i
<
frequencies
.
length
;
i
++
)
{
if
(
frequencies
[
i
]
<
0
)
throw
new
IllegalArgumentException
(
"array entry "
+
i
+
" must be nonnegative: "
+
frequencies
[
i
]);
sum
+=
frequencies
[
i
];
}
if
(
sum
==
0
)
throw
new
IllegalArgumentException
(
"at least one array entry must be positive"
);
if
(
sum
>=
Integer
.
MAX_VALUE
)
throw
new
IllegalArgumentException
(
“sum of frequencies overflows an int”
);
// pick index i with probabilitity proportional to frequency
double
r
=
uniform
((
int
)
sum
);
sum
=
0
;
for
(
int
i
=
0
;
i
<
frequencies
.
length
;
i
++
)
{
sum
+=
frequencies
[
i
];
if
(
sum
>
r
)
return
i
;
}
// can’t reach here
assert
false
;
return
–
1
;
}
/**
* Returns a random real number from an exponential distribution
* with rate λ.
*
*
@param
lambda the rate of the exponential distribution
*
@return
a random real number from an exponential distribution with
* rate {
@code
lambda}
*
@throws
IllegalArgumentException unless {
@code
lambda > 0.0}
*/
public
static
double
exp
(
double
lambda
)
{
if
(
!
(
lambda
>
0.0
))
throw
new
IllegalArgumentException
(
“lambda must be positive: ”
+
lambda
);
return
–
Math
.
log
(
1
–
uniform
())
/
lambda
;
}
/**
* Rearranges the elements of the specified array in uniformly random order.
*
*
@param
a the array to shuffle
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*/
public
static
void
shuffle
(
Object
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
int
r
=
i
+
uniform
(
n
-
i
);
// between i and n-1
Object
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified array in uniformly random order.
*
*
@param
a the array to shuffle
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*/
public
static
void
shuffle
(
double
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
int
r
=
i
+
uniform
(
n
-
i
);
// between i and n-1
double
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified array in uniformly random order.
*
*
@param
a the array to shuffle
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*/
public
static
void
shuffle
(
int
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
int
r
=
i
+
uniform
(
n
-
i
);
// between i and n-1
int
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified array in uniformly random order.
*
*
@param
a the array to shuffle
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*/
public
static
void
shuffle
(
char
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
int
r
=
i
+
uniform
(
n
-
i
);
// between i and n-1
char
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified subarray in uniformly random order.
*
*
@param
a the array to shuffle
*
@param
lo the left endpoint (inclusive)
*
@param
hi the right endpoint (exclusive)
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*
*/
public
static
void
shuffle
(
Object
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
int
r
=
i
+
uniform
(
hi
-
i
);
// between i and hi-1
Object
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified subarray in uniformly random order.
*
*
@param
a the array to shuffle
*
@param
lo the left endpoint (inclusive)
*
@param
hi the right endpoint (exclusive)
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
void
shuffle
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
int
r
=
i
+
uniform
(
hi
-
i
);
// between i and hi-1
double
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Rearranges the elements of the specified subarray in uniformly random order.
*
*
@param
a the array to shuffle
*
@param
lo the left endpoint (inclusive)
*
@param
hi the right endpoint (exclusive)
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
void
shuffle
(
int
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
int
r
=
i
+
uniform
(
hi
-
i
);
// between i and hi-1
int
temp
=
a
[
i
];
a
[
i
]
=
a
[
r
];
a
[
r
]
=
temp
;
}
}
/**
* Returns a uniformly random permutation of n elements.
*
*
@param
n number of elements
*
@throws
IllegalArgumentException if {
@code
n} is negative
*
@return
an array of length {
@code
n} that is a uniformly random permutation
* of {
@code
0}, {
@code
1}, …, {
@code
n-1}
*/
public
static
int
[]
permutation
(
int
n
)
{
if
(
n
<
0
)
throw
new
IllegalArgumentException
(
"argument is negative"
);
int
[]
perm
=
new
int
[
n
];
for
(
int
i
=
0
;
i
<
n
;
i
++
)
perm
[
i
]
=
i
;
shuffle
(
perm
);
return
perm
;
}
/**
* Returns a uniformly random permutation of k of n elements.
*
*
@param
n number of elements
*
@param
k number of elements to select
*
@throws
IllegalArgumentException if {
@code
n} is negative
*
@throws
IllegalArgumentException unless {
@code
0 <= k <= n}
*
@return
an array of length {
@code
k} that is a uniformly random permutation
* of {
@code
k} of the elements from {
@code
0}, {
@code
1}, ..., {
@code
n-1}
*/
public
static
int
[]
permutation
(
int
n
,
int
k
)
{
if
(
n
<
0
)
throw
new
IllegalArgumentException
(
"argument is negative"
);
if
(
k
<
0
||
k
>
n
)
throw
new
IllegalArgumentException
(
“k must be between 0 and n”
);
int
[]
perm
=
new
int
[
k
];
for
(
int
i
=
0
;
i
<
k
;
i
++
)
{
int
r
=
uniform
(
i
+
1
);
// between 0 and i
perm
[
i
]
=
perm
[
r
];
perm
[
r
]
=
i
;
}
for
(
int
i
=
k
;
i
<
n
;
i
++
)
{
int
r
=
uniform
(
i
+
1
);
// between 0 and i
if
(
r
<
k
)
perm
[
r
]
=
i
;
}
return
perm
;
}
// throw an IllegalArgumentException if x is null
// (x can be of type Object[], double[], int[], ...)
private
static
void
validateNotNull
(
Object
x
)
{
if
(
x
==
null
)
{
throw
new
IllegalArgumentException
(
"argument is null"
);
}
}
// throw an exception unless 0 <= lo <= hi <= length
private
static
void
validateSubarrayIndices
(
int
lo
,
int
hi
,
int
length
)
{
if
(
lo
<
0
||
hi
>
length
||
lo
>
hi
)
{
throw
new
IllegalArgumentException
(
“subarray indices out of bounds: [”
+
lo
+
“, ”
+
hi
+
“)”
);
}
}
/**
* Unit tests the methods in this class.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
int
n
=
Integer
.
parseInt
(
args
[
0
]);
if
(
args
.
length
==
2
)
StdRandom
.
setSeed
(
Long
.
parseLong
(
args
[
1
]));
double
[]
probabilities
=
{
0.5
,
0.3
,
0.1
,
0.1
};
int
[]
frequencies
=
{
5
,
3
,
1
,
1
};
String
[]
a
=
“A B C D E F G”
.
split
(
” ”
);
StdOut
.
println
(
“seed = ”
+
StdRandom
.
getSeed
());
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
StdOut
.
printf
(
"%2d "
,
uniform
(
100
));
StdOut
.
printf
(
"%8.5f "
,
uniform
(
10.0
,
99.0
));
StdOut
.
printf
(
"%5b "
,
bernoulli
(
0.5
));
StdOut
.
printf
(
"%7.5f "
,
gaussian
(
9.0
,
0.2
));
StdOut
.
printf
(
"%1d "
,
discrete
(
probabilities
));
StdOut
.
printf
(
"%1d "
,
discrete
(
frequencies
));
StdOut
.
printf
(
"%11d "
,
uniform
(
100000000000L
));
StdRandom
.
shuffle
(
a
);
for
(
String
s
:
a
)
StdOut
.
print
(
s
);
StdOut
.
println
();
}
}
}
StdStats.java
StdStats.java
/******************************************************************************
* Compilation: javac StdStats.java
* Execution: java StdStats < input.txt
* Dependencies: StdOut.java
*
* Library of statistical functions.
*
* The test client reads an array of real numbers from standard
* input, and computes the minimum, mean, maximum, and
* standard deviation.
*
* The functions all throw a java.lang.IllegalArgumentException
* if the array passed in as an argument is null.
*
* The floating-point functions all return NaN if any input is NaN.
*
* Unlike Math.min() and Math.max(), the min() and max() functions
* do not differentiate between -0.0 and 0.0.
*
* % more tiny.txt
* 5
* 3.0 1.0 2.0 5.0 4.0
*
* % java StdStats < tiny.txt
* min 1.000
* mean 3.000
* max 5.000
* std dev 1.581
*
* Should these funtions use varargs instead of array arguments?
*
******************************************************************************/
/**
* The {
@code
StdStats} class provides static methods for computing
* statistics such as min, max, mean, sample standard deviation, and
* sample variance.
*
* For additional documentation, see
* Section 2.2 of
* Computer Science: An Interdisciplinary Approach
* by Robert Sedgewick and Kevin Wayne.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
final
class
StdStats
{
private
StdStats
()
{
}
/**
* Returns the maximum value in the specified array.
*
*
@param
a the array
*
@return
the maximum value in the array {
@code
a[]};
* {
@code
Double.NEGATIVE_INFINITY} if no such value
*/
public
static
double
max
(
double
[]
a
)
{
validateNotNull
(
a
);
double
max
=
Double
.
NEGATIVE_INFINITY
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
if
(
Double
.
isNaN
(
a
[
i
]))
return
Double
.
NaN
;
if
(
a
[
i
]
>
max
)
max
=
a
[
i
];
}
return
max
;
}
/**
* Returns the maximum value in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the maximum value in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NEGATIVE_INFINITY} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
max
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
double
max
=
Double
.
NEGATIVE_INFINITY
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
if
(
Double
.
isNaN
(
a
[
i
]))
return
Double
.
NaN
;
if
(
a
[
i
]
>
max
)
max
=
a
[
i
];
}
return
max
;
}
/**
* Returns the maximum value in the specified array.
*
*
@param
a the array
*
@return
the maximum value in the array {
@code
a[]};
* {
@code
Integer.MIN_VALUE} if no such value
*/
public
static
int
max
(
int
[]
a
)
{
validateNotNull
(
a
);
int
max
=
Integer
.
MIN_VALUE
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
if
(
a
[
i
]
>
max
)
max
=
a
[
i
];
}
return
max
;
}
/**
* Returns the minimum value in the specified array.
*
*
@param
a the array
*
@return
the minimum value in the array {
@code
a[]};
* {
@code
Double.POSITIVE_INFINITY} if no such value
*/
public
static
double
min
(
double
[]
a
)
{
validateNotNull
(
a
);
double
min
=
Double
.
POSITIVE_INFINITY
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
if
(
Double
.
isNaN
(
a
[
i
]))
return
Double
.
NaN
;
if
(
a
[
i
]
<
min
)
min
=
a
[
i
];
}
return
min
;
}
/**
* Returns the minimum value in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the maximum value in the subarray {
@code
a[lo..hi)};
* {
@code
Double.POSITIVE_INFINITY} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
min
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
double
min
=
Double
.
POSITIVE_INFINITY
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
if
(
Double
.
isNaN
(
a
[
i
]))
return
Double
.
NaN
;
if
(
a
[
i
]
<
min
)
min
=
a
[
i
];
}
return
min
;
}
/**
* Returns the minimum value in the specified array.
*
*
@param
a the array
*
@return
the minimum value in the array {
@code
a[]};
* {
@code
Integer.MAX_VALUE} if no such value
*/
public
static
int
min
(
int
[]
a
)
{
validateNotNull
(
a
);
int
min
=
Integer
.
MAX_VALUE
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
if
(
a
[
i
]
<
min
)
min
=
a
[
i
];
}
return
min
;
}
/**
* Returns the average value in the specified array.
*
*
@param
a the array
*
@return
the average value in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
mean
(
double
[]
a
)
{
validateNotNull
(
a
);
if
(
a
.
length
==
0
)
return
Double
.
NaN
;
double
sum
=
sum
(
a
);
return
sum
/
a
.
length
;
}
/**
* Returns the average value in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the average value in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NaN} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
mean
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
int
length
=
hi
-
lo
;
if
(
length
==
0
)
return
Double
.
NaN
;
double
sum
=
sum
(
a
,
lo
,
hi
);
return
sum
/
length
;
}
/**
* Returns the average value in the specified array.
*
*
@param
a the array
*
@return
the average value in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
mean
(
int
[]
a
)
{
validateNotNull
(
a
);
if
(
a
.
length
==
0
)
return
Double
.
NaN
;
int
sum
=
sum
(
a
);
return
1.0
*
sum
/
a
.
length
;
}
/**
* Returns the sample variance in the specified array.
*
*
@param
a the array
*
@return
the sample variance in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
var
(
double
[]
a
)
{
validateNotNull
(
a
);
if
(
a
.
length
==
0
)
return
Double
.
NaN
;
double
avg
=
mean
(
a
);
double
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
sum
+=
(
a
[
i
]
-
avg
)
*
(
a
[
i
]
-
avg
);
}
return
sum
/
(
a
.
length
-
1
);
}
/**
* Returns the sample variance in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the sample variance in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NaN} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
var
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
int
length
=
hi
-
lo
;
if
(
length
==
0
)
return
Double
.
NaN
;
double
avg
=
mean
(
a
,
lo
,
hi
);
double
sum
=
0.0
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
sum
+=
(
a
[
i
]
-
avg
)
*
(
a
[
i
]
-
avg
);
}
return
sum
/
(
length
-
1
);
}
/**
* Returns the sample variance in the specified array.
*
*
@param
a the array
*
@return
the sample variance in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
var
(
int
[]
a
)
{
validateNotNull
(
a
);
if
(
a
.
length
==
0
)
return
Double
.
NaN
;
double
avg
=
mean
(
a
);
double
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
sum
+=
(
a
[
i
]
-
avg
)
*
(
a
[
i
]
-
avg
);
}
return
sum
/
(
a
.
length
-
1
);
}
/**
* Returns the population variance in the specified array.
*
*
@param
a the array
*
@return
the population variance in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
varp
(
double
[]
a
)
{
validateNotNull
(
a
);
if
(
a
.
length
==
0
)
return
Double
.
NaN
;
double
avg
=
mean
(
a
);
double
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
sum
+=
(
a
[
i
]
-
avg
)
*
(
a
[
i
]
-
avg
);
}
return
sum
/
a
.
length
;
}
/**
* Returns the population variance in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the population variance in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NaN} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
varp
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
int
length
=
hi
-
lo
;
if
(
length
==
0
)
return
Double
.
NaN
;
double
avg
=
mean
(
a
,
lo
,
hi
);
double
sum
=
0.0
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
sum
+=
(
a
[
i
]
-
avg
)
*
(
a
[
i
]
-
avg
);
}
return
sum
/
length
;
}
/**
* Returns the sample standard deviation in the specified array.
*
*
@param
a the array
*
@return
the sample standard deviation in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
stddev
(
double
[]
a
)
{
validateNotNull
(
a
);
return
Math
.
sqrt
(
var
(
a
));
}
/**
* Returns the sample standard deviation in the specified array.
*
*
@param
a the array
*
@return
the sample standard deviation in the array {
@code
a[]};
* {
@code
Double.NaN} if no such value
*/
public
static
double
stddev
(
int
[]
a
)
{
validateNotNull
(
a
);
return
Math
.
sqrt
(
var
(
a
));
}
/**
* Returns the sample standard deviation in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the sample standard deviation in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NaN} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
stddev
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
return
Math
.
sqrt
(
var
(
a
,
lo
,
hi
));
}
/**
* Returns the population standard deviation in the specified array.
*
*
@param
a the array
*
@return
the population standard deviation in the array;
* {
@code
Double.NaN} if no such value
*/
public
static
double
stddevp
(
double
[]
a
)
{
validateNotNull
(
a
);
return
Math
.
sqrt
(
varp
(
a
));
}
/**
* Returns the population standard deviation in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the population standard deviation in the subarray {
@code
a[lo..hi)};
* {
@code
Double.NaN} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
public
static
double
stddevp
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
return
Math
.
sqrt
(
varp
(
a
,
lo
,
hi
));
}
/**
* Returns the sum of all values in the specified array.
*
*
@param
a the array
*
@return
the sum of all values in the array {
@code
a[]};
* {
@code
0.0} if no such value
*/
private
static
double
sum
(
double
[]
a
)
{
validateNotNull
(
a
);
double
sum
=
0.0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
sum
+=
a
[
i
];
}
return
sum
;
}
/**
* Returns the sum of all values in the specified subarray.
*
*
@param
a the array
*
@param
lo the left endpoint of the subarray (inclusive)
*
@param
hi the right endpoint of the subarray (exclusive)
*
@return
the sum of all values in the subarray {
@code
a[lo..hi)};
* {
@code
0.0} if no such value
*
@throws
IllegalArgumentException if {
@code
a} is {
@code
null}
*
@throws
IllegalArgumentException unless {
@code
(0 <= lo) && (lo < hi) && (hi <= a.length)}
*/
private
static
double
sum
(
double
[]
a
,
int
lo
,
int
hi
)
{
validateNotNull
(
a
);
validateSubarrayIndices
(
lo
,
hi
,
a
.
length
);
double
sum
=
0.0
;
for
(
int
i
=
lo
;
i
<
hi
;
i
++
)
{
sum
+=
a
[
i
];
}
return
sum
;
}
/**
* Returns the sum of all values in the specified array.
*
*
@param
a the array
*
@return
the sum of all values in the array {
@code
a[]};
* {
@code
0.0} if no such value
*/
private
static
int
sum
(
int
[]
a
)
{
validateNotNull
(
a
);
int
sum
=
0
;
for
(
int
i
=
0
;
i
<
a
.
length
;
i
++
)
{
sum
+=
a
[
i
];
}
return
sum
;
}
/**
* Plots the points (0, a0), (1, a1), …,
* (n-1, an-1) to standard draw.
*
*
@param
a the array of values
*/
public
static
void
plotPoints
(
double
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
StdDraw
.
setXscale
(
–
1
,
n
);
StdDraw
.
setPenRadius
(
1.0
/
(
3.0
*
n
));
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
StdDraw
.
point
(
i
,
a
[
i
]);
}
}
/**
* Plots the line segments connecting
* (i, ai) to
* (i+1, ai+1) for
* each i to standard draw.
*
*
@param
a the array of values
*/
public
static
void
plotLines
(
double
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
StdDraw
.
setXscale
(
–
1
,
n
);
StdDraw
.
setPenRadius
();
for
(
int
i
=
1
;
i
<
n
;
i
++
)
{
StdDraw
.
line
(
i
-
1
,
a
[
i
-
1
],
i
,
a
[
i
]);
}
}
/**
* Plots bars from (0, ai) to
* (ai) for each i
* to standard draw.
*
*
@param
a the array of values
*/
public
static
void
plotBars
(
double
[]
a
)
{
validateNotNull
(
a
);
int
n
=
a
.
length
;
StdDraw
.
setXscale
(
–
1
,
n
);
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
StdDraw
.
filledRectangle
(
i
,
a
[
i
]
/
2
,
0.25
,
a
[
i
]
/
2
);
}
}
// throw an IllegalArgumentException if x is null
// (x is either of type double[] or int[])
private
static
void
validateNotNull
(
Object
x
)
{
if
(
x
==
null
)
throw
new
IllegalArgumentException
(
"argument is null"
);
}
// throw an exception unless 0 <= lo <= hi <= length
private
static
void
validateSubarrayIndices
(
int
lo
,
int
hi
,
int
length
)
{
if
(
lo
<
0
||
hi
>
length
||
lo
>
hi
)
throw
new
IllegalArgumentException
(
“subarray indices out of bounds: [”
+
lo
+
“, ”
+
hi
+
“)”
);
}
/**
* Unit tests {
@code
StdStats}.
* Convert command-line arguments to array of doubles and call various methods.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
double
[]
a
=
StdArrayIO
.
readDouble1D
();
StdOut
.
printf
(
” min %10.3f\n”
,
min
(
a
));
StdOut
.
printf
(
” mean %10.3f\n”
,
mean
(
a
));
StdOut
.
printf
(
” max %10.3f\n”
,
max
(
a
));
StdOut
.
printf
(
” stddev %10.3f\n”
,
stddev
(
a
));
StdOut
.
printf
(
” var %10.3f\n”
,
var
(
a
));
StdOut
.
printf
(
” stddevp %10.3f\n”
,
stddevp
(
a
));
StdOut
.
printf
(
” varp %10.3f\n”
,
varp
(
a
));
}
}
StopwatchCPU.java
StopwatchCPU.java
/******************************************************************************
* Compilation: javac StopwatchCPU.java
* Execution: none
* Dependencies: none
*
* A version of Stopwatch.java that measures CPU time on a single
* core or processor (instead of wall clock time).
*
******************************************************************************/
import
java
.
lang
.
management
.
ThreadMXBean
;
import
java
.
lang
.
management
.
ManagementFactory
;
/**
* The {
@code
StopwatchCPU} data type is for measuring
* the CPU time used during a programming task.
*
* See {
@link
Stopwatch} for a version that measures wall-clock time
* (the real time that elapses).
*
*
@author
Josh Hug
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
class
StopwatchCPU
{
private
static
final
double
NANOSECONDS_PER_SECOND
=
1000000000
;
private
final
ThreadMXBean
threadTimer
;
private
final
long
start
;
/**
* Initializes a new stopwatch.
*/
public
StopwatchCPU
()
{
threadTimer
=
ManagementFactory
.
getThreadMXBean
();
start
=
threadTimer
.
getCurrentThreadCpuTime
();
}
/**
* Returns the elapsed CPU time (in seconds) since the stopwatch was created.
*
*
@return
elapsed CPU time (in seconds) since the stopwatch was created
*/
public
double
elapsedTime
()
{
long
now
=
threadTimer
.
getCurrentThreadCpuTime
();
return
(
now
–
start
)
/
NANOSECONDS_PER_SECOND
;
}
}
Stopwatch.java
Stopwatch.java
/******************************************************************************
* Compilation: javac Stopwatch.java
* Execution: java Stopwatch n
* Dependencies: none
*
* A utility class to measure the running time (wall clock) of a program.
*
* % java8 Stopwatch 100000000
* 6.666667e+11 0.5820 seconds
* 6.666667e+11 8.4530 seconds
*
******************************************************************************/
/**
* The {
@code
Stopwatch} data type is for measuring
* the time that elapses between the start and end of a
* programming task (wall-clock time).
*
* See {
@link
StopwatchCPU} for a version that measures CPU time.
*
*
@author
Robert Sedgewick
*
@author
Kevin Wayne
*/
public
class
Stopwatch
{
private
final
long
start
;
/**
* Initializes a new stopwatch.
*/
public
Stopwatch
()
{
start
=
System
.
currentTimeMillis
();
}
/**
* Returns the elapsed CPU time (in seconds) since the stopwatch was created.
*
*
@return
elapsed CPU time (in seconds) since the stopwatch was created
*/
public
double
elapsedTime
()
{
long
now
=
System
.
currentTimeMillis
();
return
(
now
–
start
)
/
1000.0
;
}
/**
* Unit tests the {
@code
Stopwatch} data type.
* Takes a command-line argument {
@code
n} and computes the
* sum of the square roots of the first {
@code
n} positive integers,
* first using {
@code
Math.sqrt()}, then using {
@code
Math.pow()}.
* It prints to standard output the sum and the amount of time to
* compute the sum. Note that the discrete sum can be approximated by
* an integral – the sum should be approximately 2/3 * (n^(3/2) – 1).
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
int
n
=
Integer
.
parseInt
(
args
[
0
]);
// sum of square roots of integers from 1 to n using Math.sqrt(x).
Stopwatch
timer1
=
new
Stopwatch
();
double
sum1
=
0.0
;
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
sum1
+=
Math
.
sqrt
(
i
);
}
double
time1
=
timer1
.
elapsedTime
();
StdOut
.
printf
(
"%e (%.2f seconds)\n"
,
sum1
,
time1
);
// sum of square roots of integers from 1 to n using Math.pow(x, 0.5).
Stopwatch
timer2
=
new
Stopwatch
();
double
sum2
=
0.0
;
for
(
int
i
=
1
;
i
<=
n
;
i
++
)
{
sum2
+=
Math
.
pow
(
i
,
0.5
);
}
double
time2
=
timer2
.
elapsedTime
();
StdOut
.
printf
(
"%e (%.2f seconds)\n"
,
sum2
,
time2
);
}
}
TestIntroCS.java
TestIntroCS.java
/******************************************************************************
* Compilation: javac-introcs TestIntroCS.java
* Execution: java-introcs TestIntroCS n
*
* Play chaos game to produce Barnsley's fern.
* This program is intended to test that stdlib.jar is properly installed.
*
* % java-introcs TestIntroCS 10000
*
******************************************************************************/
public
class
TestIntroCS
{
public
static
void
main
(
String
[]
args
)
{
int
n
=
10000
;
// number of points to draw (default 10000)
if
(
args
.
length
==
1
)
{
n
=
Integer
.
parseInt
(
args
[
0
]);
}
StdDraw
.
setScale
(
-
0.1
,
1.1
);
// leave a 10% border
StdDraw
.
clear
(
StdDraw
.
BOOK_LIGHT_BLUE
);
// background color
StdDraw
.
setPenColor
(
0
,
114
,
0
);
// a shade of green
// starting point
double
x
=
0.5
;
double
y
=
0.0
;
// repeated choose one of four update rules at random
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
double
tempx
,
tempy
;
double
r
=
StdRandom
.
uniform
(
0.0
,
1.0
);
// stem
if
(
r
<=
0.01
)
{
tempx
=
0.50
;
tempy
=
0.16
*
y
;
}
// largest left-hand leaflet
else
if
(
r
<=
0.08
)
{
tempx
=
0.20
*
x
-
0.26
*
y
+
0.400
;
tempy
=
0.23
*
x
+
0.22
*
y
-
0.045
;
}
// largest right-hand leaflet
else
if
(
r
<=
0.15
)
{
tempx
=
-
0.15
*
x
+
0.28
*
y
+
0.575
;
tempy
=
0.26
*
x
+
0.24
*
y
-
0.086
;
}
// successively smaller leaflets
else
{
tempx
=
0.85
*
x
+
0.04
*
y
+
0.075
;
tempy
=
-
0.04
*
x
+
0.85
*
y
+
0.180
;
}
// update (x, y) and draw point
x
=
tempx
;
y
=
tempy
;
StdDraw
.
point
(
x
,
y
);
}
}
}
UnicodeTest.java
UnicodeTest.java
/******************************************************************************
* Compilation: javac-introcs UnicodeTest.java
* Execution: java-introcs UnicodeTest
* Dependencies: StdOut.java
*
* This programs prints out all of the Unicode characters in the basic
* multilingual plane (U+0000 to U+FFFF) in a table. It skips the
* following types of characters:
* -
* - control characters
* - modifier symbols
* - non-spacing marks
* - Unicode formatting commands
* - reserved for surrogate pairs
* - reserved for private use
*
*
* % java-introcs UnicodeTest
* U+0020 ! " # $ % & ' ( ) * + , - . /
* U+0030 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
* U+0040 @ A B C D E F G H I J K L M N O
* U+0050 P Q R S T U V W X Y Z [ \ ] _
* U+0060 a b c d e f g h i j k l m n o
* U+0070 p q r s t u v w x y z { | } ~
* U+00A0 ¡ ¢ £ ¤ ¥ ¦ § © ª « ¬ ®
* U+00B0 ° ± ² ³ µ ¶ · ¹ º » ¼ ½ ¾ ¿
* U+00C0 À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï
* U+00D0 Ð Ñ Ò Ó Ô Õ Ö × Ø Ù Ú Û Ü Ý Þ ß
* U+00E0 à á â ã ä å æ ç è é ê ë ì í î ï
* U+00F0 ð ñ ò ó ô õ ö ÷ ø ù ú û ü ý þ ÿ
* U+0100 Ā ā Ă ă Ą ą Ć ć Ĉ ĉ Ċ ċ Č č Ď ď
* …
*
* Depending on your system setup and font, not all of the Unicode
* characters may display properly.
*
* Quirks: when printing certain Hebrew or Arabic characters, the
* table may print right-to-left instead of left-to-right.
*
* For a description of Unicode terminology, see:
* http://docs.oracle.com/javase/tutorial/i18n/text/terminology.html
*
* For the Character API, see:
* http://docs.oracle.com/javase/7/docs/api/java/lang/Character.html
*
* To see what each Unicode character should look like, see:
* http://www.fileformat.info/info/unicode/index.htm
* http://www.fileformat.info/info/unicode/char/05D0/index.htm
*
*
******************************************************************************/
public
class
UnicodeTest
{
// number of Unicode characters to display per line
private
static
final
int
CHARS_PER_LINE
=
16
;
// number of Unicode characters to display (basic multilingual plane)
private
static
final
int
MAX_CHAR
=
65536
;
// do not instantiate
private
UnicodeTest
()
{
}
// Returns a string representation of the given codePoint, or a single
// space if the codePoint should not be suppressed when printing.
private
static
String
toString
(
int
codePoint
)
{
if
(
!
Character
.
isDefined
(
codePoint
))
return
” ”
;
if
(
Character
.
isISOControl
(
codePoint
))
return
” ”
;
if
(
Character
.
isWhitespace
(
codePoint
))
return
” ”
;
// if (Character.isSurrogate(codePoint) return ” “; // Java 1.7+ only
if
(
Character
.
isLowSurrogate
((
char
)
codePoint
))
return
” ”
;
// Java 1.5+
if
(
Character
.
isHighSurrogate
((
char
)
codePoint
))
return
” ”
;
// Java 1.5+
switch
(
Character
.
getType
(
codePoint
))
{
case
Character
.
MODIFIER_SYMBOL
:
return
” ”
;
case
Character
.
CONTROL
:
return
” ”
;
case
Character
.
MODIFIER_LETTER
:
return
” ”
;
case
Character
.
NON_SPACING_MARK
:
return
” ”
;
case
Character
.
FORMAT
:
return
” ”
;
case
Character
.
PRIVATE_USE
:
return
” ”
;
default
:
return
new
String
(
Character
.
toChars
(
codePoint
));
}
}
/**
* Prints Unicode characters to standard output.
*
*
@param
args the command-line arguments
*/
public
static
void
main
(
String
[]
args
)
{
for
(
int
line
=
0
;
line
<
2
*
Character
.
MAX_VALUE
/
CHARS_PER_LINE
;
line
++
)
{
StringBuilder
buffer
=
new
StringBuilder
();
for
(
int
i
=
0
;
i
<
CHARS_PER_LINE
;
i
++
)
{
int
codePoint
=
CHARS_PER_LINE
*
line
+
i
;
buffer
.
append
(
toString
(
codePoint
)
+
" "
);
}
String
output
=
buffer
.
toString
();
if
(
!
output
.
trim
().
equals
(
""
))
{
// U+202D is the Unicode override to force left-to-right direction
// but doesn't seem to work with Unix more
StdOut
.
printf
(
"U+%04X %s\n"
,
16
*
line
,
output
);
}
}
}
}
BinaryIn.class
public final synchronized class BinaryIn {
private static final int EOF = -1;
private java.io.BufferedInputStream in;
private int buffer;
private int n;
public void BinaryIn();
public void BinaryIn(java.io.InputStream);
public void BinaryIn(java.net.Socket);
public void BinaryIn(java.net.URL);
public void BinaryIn(String);
private void fillBuffer();
public boolean exists();
public boolean isEmpty();
public boolean readBoolean();
public char readChar();
public char readChar(int);
public String readString();
public short readShort();
public int readInt();
public int readInt(int);
public long readLong();
public double readDouble();
public float readFloat();
public byte readByte();
public static void main(String[]);
}
BinaryOut.class
public final synchronized class BinaryOut {
private java.io.BufferedOutputStream out;
private int buffer;
private int n;
public void BinaryOut();
public void BinaryOut(java.io.OutputStream);
public void BinaryOut(String);
public void BinaryOut(java.net.Socket);
private void writeBit(boolean);
private void writeByte(int);
private void clearBuffer();
public void flush();
public void close();
public void write(boolean);
public void write(byte);
public void write(int);
public void write(int, int);
public void write(double);
public void write(long);
public void write(float);
public void write(short);
public void write(char);
public void write(char, int);
public void write(String);
public void write(String, int);
public static void main(String[]);
static void
}
BinaryStdIn.class
public final synchronized class BinaryStdIn {
private static final int EOF = -1;
private static java.io.BufferedInputStream in;
private static int buffer;
private static int n;
private static boolean isInitialized;
private void BinaryStdIn();
private static void initialize();
private static void fillBuffer();
public static void close();
public static boolean isEmpty();
public static boolean readBoolean();
public static char readChar();
public static char readChar(int);
public static String readString();
public static short readShort();
public static int readInt();
public static int readInt(int);
public static long readLong();
public static double readDouble();
public static float readFloat();
public static byte readByte();
public static void main(String[]);
}
BinaryStdOut.class
public final synchronized class BinaryStdOut {
private static java.io.BufferedOutputStream out;
private static int buffer;
private static int n;
private static boolean isInitialized;
private void BinaryStdOut();
private static void initialize();
private static void writeBit(boolean);
private static void writeByte(int);
private static void clearBuffer();
public static void flush();
public static void close();
public static void write(boolean);
public static void write(byte);
public static void write(int);
public static void write(int, int);
public static void write(double);
public static void write(long);
public static void write(float);
public static void write(short);
public static void write(char);
public static void write(char, int);
public static void write(String);
public static void write(String, int);
public static void main(String[]);
static void
}
Draw.class
public final synchronized class Draw implements java.awt.event.ActionListener, java.awt.event.MouseListener, java.awt.event.MouseMotionListener, java.awt.event.KeyListener {
public static final java.awt.Color BLACK;
public static final java.awt.Color BLUE;
public static final java.awt.Color CYAN;
public static final java.awt.Color DARK_GRAY;
public static final java.awt.Color GRAY;
public static final java.awt.Color GREEN;
public static final java.awt.Color LIGHT_GRAY;
public static final java.awt.Color MAGENTA;
public static final java.awt.Color ORANGE;
public static final java.awt.Color PINK;
public static final java.awt.Color RED;
public static final java.awt.Color WHITE;
public static final java.awt.Color YELLOW;
public static final java.awt.Color BOOK_BLUE;
public static final java.awt.Color BOOK_LIGHT_BLUE;
public static final java.awt.Color BOOK_RED;
public static final java.awt.Color PRINCETON_ORANGE;
private static final java.awt.Color DEFAULT_PEN_COLOR;
private static final java.awt.Color DEFAULT_CLEAR_COLOR;
private static final double BORDER = 0.0;
private static final double DEFAULT_XMIN = 0.0;
private static final double DEFAULT_XMAX = 1.0;
private static final double DEFAULT_YMIN = 0.0;
private static final double DEFAULT_YMAX = 1.0;
private static final int DEFAULT_SIZE = 512;
private static final double DEFAULT_PEN_RADIUS = 0.002;
private static final java.awt.Font DEFAULT_FONT;
private java.awt.Color penColor;
private int width;
private int height;
private double penRadius;
private boolean defer;
private double xmin;
private double ymin;
private double xmax;
private double ymax;
private String name;
private final Object mouseLock;
private final Object keyLock;
private java.awt.Font font;
private javax.swing.JLabel draw;
private java.awt.image.BufferedImage offscreenImage;
private java.awt.image.BufferedImage onscreenImage;
private java.awt.Graphics2D offscreen;
private java.awt.Graphics2D onscreen;
private javax.swing.JFrame frame;
private boolean isMousePressed;
private double mouseX;
private double mouseY;
private final java.util.LinkedList keysTyped;
private final java.util.TreeSet keysDown;
private final java.util.ArrayList listeners;
public void Draw(String);
public void Draw();
private void init();
public void setLocationOnScreen(int, int);
public void setDefaultCloseOperation(int);
public void setCanvasSize(int, int);
private javax.swing.JMenuBar createMenuBar();
private static void validate(double, String);
private static void validateNonnegative(double, String);
private static void validateNotNull(Object, String);
public void setXscale();
public void setYscale();
public void setXscale(double, double);
public void setYscale(double, double);
private double scaleX(double);
private double scaleY(double);
private double factorX(double);
private double factorY(double);
private double userX(double);
private double userY(double);
public void clear();
public void clear(java.awt.Color);
public double getPenRadius();
public void setPenRadius();
public void setPenRadius(double);
public java.awt.Color getPenColor();
public void setPenColor();
public void setPenColor(java.awt.Color);
public void setPenColor(int, int, int);
public void xorOn();
public void xorOff();
public javax.swing.JLabel getJLabel();
public java.awt.Font getFont();
public void setFont();
public void setFont(java.awt.Font);
public void line(double, double, double, double);
private void pixel(double, double);
public void point(double, double);
public void circle(double, double, double);
public void filledCircle(double, double, double);
public void ellipse(double, double, double, double);
public void filledEllipse(double, double, double, double);
public void arc(double, double, double, double, double);
public void square(double, double, double);
public void filledSquare(double, double, double);
public void rectangle(double, double, double, double);
public void filledRectangle(double, double, double, double);
public void polygon(double[], double[]);
public void filledPolygon(double[], double[]);
private static java.awt.Image getImage(String);
public void picture(double, double, String);
public void picture(double, double, String, double);
public void picture(double, double, String, double, double);
public void picture(double, double, String, double, double, double);
public void text(double, double, String);
public void text(double, double, String, double);
public void textLeft(double, double, String);
public void textRight(double, double, String);
public void show(int);
public void pause(int);
public void show();
private void draw();
public void enableDoubleBuffering();
public void disableDoubleBuffering();
public void save(String);
public void actionPerformed(java.awt.event.ActionEvent);
public void addListener(DrawListener);
public boolean isMousePressed();
public boolean mousePressed();
public double mouseX();
public double mouseY();
public void mouseEntered(java.awt.event.MouseEvent);
public void mouseExited(java.awt.event.MouseEvent);
public void mousePressed(java.awt.event.MouseEvent);
public void mouseReleased(java.awt.event.MouseEvent);
public void mouseClicked(java.awt.event.MouseEvent);
public void mouseDragged(java.awt.event.MouseEvent);
public void mouseMoved(java.awt.event.MouseEvent);
public boolean hasNextKeyTyped();
public char nextKeyTyped();
public boolean isKeyPressed(int);
public void keyTyped(java.awt.event.KeyEvent);
public void keyPressed(java.awt.event.KeyEvent);
public void keyReleased(java.awt.event.KeyEvent);
public static void main(String[]);
static void
}
DrawListener.class
public abstract interface DrawListener {
public abstract void mousePressed(double, double);
public abstract void mouseDragged(double, double);
public abstract void mouseReleased(double, double);
public abstract void mouseClicked(double, double);
public abstract void keyTyped(char);
public abstract void keyPressed(int);
public abstract void keyReleased(int);
}
Draw$RetinaImageIcon.class
synchronized class Draw$RetinaImageIcon extends javax.swing.ImageIcon {
public void Draw$RetinaImageIcon(java.awt.Image);
public int getIconWidth();
public int getIconHeight();
public synchronized void paintIcon(java.awt.Component, java.awt.Graphics, int, int);
}
GrayscalePicture.class
public final synchronized class GrayscalePicture implements java.awt.event.ActionListener {
private java.awt.image.BufferedImage image;
private javax.swing.JFrame frame;
private String filename;
private boolean isOriginUpperLeft;
private final int width;
private final int height;
public void GrayscalePicture(int, int);
public void GrayscalePicture(GrayscalePicture);
public void GrayscalePicture(String);
private static java.awt.Color toGray(java.awt.Color);
public javax.swing.JLabel getJLabel();
public void setOriginUpperLeft();
public void setOriginLowerLeft();
public void show();
public int height();
public int width();
private void validateRowIndex(int);
private void validateColumnIndex(int);
private void validateGrayscaleValue(int);
public java.awt.Color get(int, int);
public int getGrayscale(int, int);
public void set(int, int, java.awt.Color);
public void setGrayscale(int, int, int);
public boolean equals(Object);
public String toString();
public int hashCode();
public void save(String);
public void save(java.io.File);
public void actionPerformed(java.awt.event.ActionEvent);
public static void main(String[]);
}
In.class
public final synchronized class In {
private static final String CHARSET_NAME = UTF-8;
private static final java.util.Locale LOCALE;
private static final java.util.regex.Pattern WHITESPACE_PATTERN;
private static final java.util.regex.Pattern EMPTY_PATTERN;
private static final java.util.regex.Pattern EVERYTHING_PATTERN;
private java.util.Scanner scanner;
public void In();
public void In(java.net.Socket);
public void In(java.net.URL);
public void In(java.io.File);
public void In(String);
public void In(java.util.Scanner);
public boolean exists();
public boolean isEmpty();
public boolean hasNextLine();
public boolean hasNextChar();
public String readLine();
public char readChar();
public String readAll();
public String readString();
public int readInt();
public double readDouble();
public float readFloat();
public long readLong();
public short readShort();
public byte readByte();
public boolean readBoolean();
public String[] readAllStrings();
public String[] readAllLines();
public int[] readAllInts();
public long[] readAllLongs();
public double[] readAllDoubles();
public void close();
public static int[] readInts(String);
public static double[] readDoubles(String);
public static String[] readStrings(String);
public static int[] readInts();
public static double[] readDoubles();
public static String[] readStrings();
public static void main(String[]);
static void
}
Out.class
public synchronized class Out {
private static final String CHARSET_NAME = UTF-8;
private static final java.util.Locale LOCALE;
private java.io.PrintWriter out;
public void Out(java.io.OutputStream);
public void Out();
public void Out(java.net.Socket);
public void Out(String);
public void close();
public void println();
public void println(Object);
public void println(boolean);
public void println(char);
public void println(double);
public void println(float);
public void println(int);
public void println(long);
public void println(byte);
public void print();
public void print(Object);
public void print(boolean);
public void print(char);
public void print(double);
public void print(float);
public void print(int);
public void print(long);
public void print(byte);
public transient void printf(String, Object[]);
public transient void printf(java.util.Locale, String, Object[]);
public static void main(String[]);
static void
}
Picture.class
public final synchronized class Picture implements java.awt.event.ActionListener {
private java.awt.image.BufferedImage image;
private javax.swing.JFrame frame;
private String filename;
private boolean isOriginUpperLeft;
private final int width;
private final int height;
public void Picture(int, int);
public void Picture(Picture);
public void Picture(String);
public void Picture(java.io.File);
public javax.swing.JLabel getJLabel();
public void setOriginUpperLeft();
public void setOriginLowerLeft();
public void show();
public int height();
public int width();
private void validateRowIndex(int);
private void validateColumnIndex(int);
public java.awt.Color get(int, int);
public int getRGB(int, int);
public void set(int, int, java.awt.Color);
public void setRGB(int, int, int);
public boolean equals(Object);
public String toString();
public int hashCode();
public void save(String);
public void save(java.io.File);
public void actionPerformed(java.awt.event.ActionEvent);
public static void main(String[]);
}
PlayMusic$1.class
final synchronized class PlayMusic$1 implements Runnable {
void PlayMusic$1(String);
public void run();
}
PlayMusic.class
public synchronized class PlayMusic {
public void PlayMusic();
private static void playApplet(String);
public static synchronized void play(String);
private static void stream(String);
public static void main(String[]);
}
StdArrayIO.class
public synchronized class StdArrayIO {
private void StdArrayIO();
public static double[] readDouble1D();
public static void print(double[]);
public static double[][] readDouble2D();
public static void print(double[][]);
public static int[] readInt1D();
public static void print(int[]);
public static int[][] readInt2D();
public static void print(int[][]);
public static boolean[] readBoolean1D();
public static void print(boolean[]);
public static boolean[][] readBoolean2D();
public static void print(boolean[][]);
public static void main(String[]);
}
StdAudio$1.class
final synchronized class StdAudio$1 implements Runnable {
void StdAudio$1(String);
public void run();
}
StdAudio$2.class
final synchronized class StdAudio$2 implements Runnable {
void StdAudio$2();
public void run();
}
StdAudio.class
public final synchronized class StdAudio {
public static final int SAMPLE_RATE = 44100;
private static final int BYTES_PER_SAMPLE = 2;
private static final int BITS_PER_SAMPLE = 16;
private static final double MAX_16_BIT = 32768.0;
private static final int SAMPLE_BUFFER_SIZE = 4096;
private static final int MONO = 1;
private static final int STEREO = 2;
private static final boolean LITTLE_ENDIAN = 0;
private static final boolean BIG_ENDIAN = 1;
private static final boolean SIGNED = 1;
private static final boolean UNSIGNED = 0;
private static javax.sound.sampled.SourceDataLine line;
private static byte[] buffer;
private static int bufferSize;
private void StdAudio();
private static void init();
private static javax.sound.sampled.AudioInputStream getAudioInputStreamFromFile(String);
public static void close();
public static void play(double);
public static void play(double[]);
public static double[] read(String);
public static void save(String, double[]);
public static synchronized void play(String);
private static void stream(javax.sound.sampled.AudioInputStream);
public static synchronized void loop(String);
private static double[] note(double, double, double);
public static void main(String[]);
static void
}
StdDraw.class
public final synchronized class StdDraw implements java.awt.event.ActionListener, java.awt.event.MouseListener, java.awt.event.MouseMotionListener, java.awt.event.KeyListener {
public static final java.awt.Color BLACK;
public static final java.awt.Color BLUE;
public static final java.awt.Color CYAN;
public static final java.awt.Color DARK_GRAY;
public static final java.awt.Color GRAY;
public static final java.awt.Color GREEN;
public static final java.awt.Color LIGHT_GRAY;
public static final java.awt.Color MAGENTA;
public static final java.awt.Color ORANGE;
public static final java.awt.Color PINK;
public static final java.awt.Color RED;
public static final java.awt.Color WHITE;
public static final java.awt.Color YELLOW;
public static final java.awt.Color BOOK_BLUE;
public static final java.awt.Color BOOK_LIGHT_BLUE;
public static final java.awt.Color BOOK_RED;
public static final java.awt.Color PRINCETON_ORANGE;
private static final java.awt.Color DEFAULT_PEN_COLOR;
private static final java.awt.Color DEFAULT_CLEAR_COLOR;
private static java.awt.Color penColor;
private static final int DEFAULT_SIZE = 512;
private static int width;
private static int height;
private static final double DEFAULT_PEN_RADIUS = 0.002;
private static double penRadius;
private static boolean defer;
private static final double BORDER = 0.0;
private static final double DEFAULT_XMIN = 0.0;
private static final double DEFAULT_XMAX = 1.0;
private static final double DEFAULT_YMIN = 0.0;
private static final double DEFAULT_YMAX = 1.0;
private static double xmin;
private static double ymin;
private static double xmax;
private static double ymax;
private static Object mouseLock;
private static Object keyLock;
private static final java.awt.Font DEFAULT_FONT;
private static java.awt.Font font;
private static java.awt.image.BufferedImage offscreenImage;
private static java.awt.image.BufferedImage onscreenImage;
private static java.awt.Graphics2D offscreen;
private static java.awt.Graphics2D onscreen;
private static StdDraw std;
private static javax.swing.JFrame frame;
private static boolean isMousePressed;
private static double mouseX;
private static double mouseY;
private static java.util.LinkedList keysTyped;
private static java.util.TreeSet keysDown;
private void StdDraw();
public static void setCanvasSize();
public static void setCanvasSize(int, int);
private static void init();
private static javax.swing.JMenuBar createMenuBar();
private static void validate(double, String);
private static void validateNonnegative(double, String);
private static void validateNotNull(Object, String);
public static void setXscale();
public static void setYscale();
public static void setScale();
public static void setXscale(double, double);
public static void setYscale(double, double);
public static void setScale(double, double);
private static double scaleX(double);
private static double scaleY(double);
private static double factorX(double);
private static double factorY(double);
private static double userX(double);
private static double userY(double);
public static void clear();
public static void clear(java.awt.Color);
public static double getPenRadius();
public static void setPenRadius();
public static void setPenRadius(double);
public static java.awt.Color getPenColor();
public static void setPenColor();
public static void setPenColor(java.awt.Color);
public static void setPenColor(int, int, int);
public static java.awt.Font getFont();
public static void setFont();
public static void setFont(java.awt.Font);
public static void line(double, double, double, double);
private static void pixel(double, double);
public static void point(double, double);
public static void circle(double, double, double);
public static void filledCircle(double, double, double);
public static void ellipse(double, double, double, double);
public static void filledEllipse(double, double, double, double);
public static void arc(double, double, double, double, double);
public static void square(double, double, double);
public static void filledSquare(double, double, double);
public static void rectangle(double, double, double, double);
public static void filledRectangle(double, double, double, double);
public static void polygon(double[], double[]);
public static void filledPolygon(double[], double[]);
private static java.awt.Image getImage(String);
public static void picture(double, double, String);
public static void picture(double, double, String, double);
public static void picture(double, double, String, double, double);
public static void picture(double, double, String, double, double, double);
public static void text(double, double, String);
public static void text(double, double, String, double);
public static void textLeft(double, double, String);
public static void textRight(double, double, String);
public static void show(int);
public static void pause(int);
public static void show();
private static void draw();
public static void enableDoubleBuffering();
public static void disableDoubleBuffering();
public static void save(String);
public void actionPerformed(java.awt.event.ActionEvent);
public static boolean isMousePressed();
public static boolean mousePressed();
public static double mouseX();
public static double mouseY();
public void mouseClicked(java.awt.event.MouseEvent);
public void mouseEntered(java.awt.event.MouseEvent);
public void mouseExited(java.awt.event.MouseEvent);
public void mousePressed(java.awt.event.MouseEvent);
public void mouseReleased(java.awt.event.MouseEvent);
public void mouseDragged(java.awt.event.MouseEvent);
public void mouseMoved(java.awt.event.MouseEvent);
public static boolean hasNextKeyTyped();
public static char nextKeyTyped();
public static boolean isKeyPressed(int);
public void keyTyped(java.awt.event.KeyEvent);
public void keyPressed(java.awt.event.KeyEvent);
public void keyReleased(java.awt.event.KeyEvent);
public static void main(String[]);
static void
}
StdDraw$RetinaImageIcon.class
synchronized class StdDraw$RetinaImageIcon extends javax.swing.ImageIcon {
public void StdDraw$RetinaImageIcon(java.awt.Image);
public int getIconWidth();
public int getIconHeight();
public synchronized void paintIcon(java.awt.Component, java.awt.Graphics, int, int);
}
StdIn.class
public final synchronized class StdIn {
private static final String CHARSET_NAME = UTF-8;
private static final java.util.Locale LOCALE;
private static final java.util.regex.Pattern WHITESPACE_PATTERN;
private static final java.util.regex.Pattern EMPTY_PATTERN;
private static final java.util.regex.Pattern EVERYTHING_PATTERN;
private static java.util.Scanner scanner;
private void StdIn();
public static boolean isEmpty();
public static boolean hasNextLine();
public static boolean hasNextChar();
public static String readLine();
public static char readChar();
public static String readAll();
public static String readString();
public static int readInt();
public static double readDouble();
public static float readFloat();
public static long readLong();
public static short readShort();
public static byte readByte();
public static boolean readBoolean();
public static String[] readAllStrings();
public static String[] readAllLines();
public static int[] readAllInts();
public static long[] readAllLongs();
public static double[] readAllDoubles();
private static void resync();
private static void setScanner(java.util.Scanner);
public static int[] readInts();
public static double[] readDoubles();
public static String[] readStrings();
public static void main(String[]);
static void
}
StdInTest.class
public synchronized class StdInTest {
private static boolean testStdIn;
private static reflect.Method resyncMethod;
private static int testCount;
public void StdInTest();
public static Object escape(Object);
public static boolean canResync();
public static void test(String, Object[][]);
public static void test(String, Object[][], boolean);
public static void main(String[]);
static void
}
StdOut.class
public final synchronized class StdOut {
private static final String CHARSET_NAME = UTF-8;
private static final java.util.Locale LOCALE;
private static java.io.PrintWriter out;
private void StdOut();
public static void println();
public static void println(Object);
public static void println(boolean);
public static void println(char);
public static void println(double);
public static void println(float);
public static void println(int);
public static void println(long);
public static void println(short);
public static void println(byte);
public static void print();
public static void print(Object);
public static void print(boolean);
public static void print(char);
public static void print(double);
public static void print(float);
public static void print(int);
public static void print(long);
public static void print(short);
public static void print(byte);
public static transient void printf(String, Object[]);
public static transient void printf(java.util.Locale, String, Object[]);
public static void main(String[]);
static void
}
StdRandom.class
public final synchronized class StdRandom {
private static java.util.Random random;
private static long seed;
private void StdRandom();
public static void setSeed(long);
public static long getSeed();
public static double uniform();
public static int uniform(int);
public static long uniform(long);
public static double random();
public static int uniform(int, int);
public static double uniform(double, double);
public static boolean bernoulli(double);
public static boolean bernoulli();
public static double gaussian();
public static double gaussian(double, double);
public static int geometric(double);
public static int poisson(double);
public static double pareto();
public static double pareto(double);
public static double cauchy();
public static int discrete(double[]);
public static int discrete(int[]);
public static double exp(double);
public static void shuffle(Object[]);
public static void shuffle(double[]);
public static void shuffle(int[]);
public static void shuffle(char[]);
public static void shuffle(Object[], int, int);
public static void shuffle(double[], int, int);
public static void shuffle(int[], int, int);
public static int[] permutation(int);
public static int[] permutation(int, int);
private static void validateNotNull(Object);
private static void validateSubarrayIndices(int, int, int);
public static void main(String[]);
static void
}
StdStats.class
public final synchronized class StdStats {
private void StdStats();
public static double max(double[]);
public static double max(double[], int, int);
public static int max(int[]);
public static double min(double[]);
public static double min(double[], int, int);
public static int min(int[]);
public static double mean(double[]);
public static double mean(double[], int, int);
public static double mean(int[]);
public static double var(double[]);
public static double var(double[], int, int);
public static double var(int[]);
public static double varp(double[]);
public static double varp(double[], int, int);
public static double stddev(double[]);
public static double stddev(int[]);
public static double stddev(double[], int, int);
public static double stddevp(double[]);
public static double stddevp(double[], int, int);
private static double sum(double[]);
private static double sum(double[], int, int);
private static int sum(int[]);
public static void plotPoints(double[]);
public static void plotLines(double[]);
public static void plotBars(double[]);
private static void validateNotNull(Object);
private static void validateSubarrayIndices(int, int, int);
public static void main(String[]);
}
Stopwatch.class
public synchronized class Stopwatch {
private final long start;
public void Stopwatch();
public double elapsedTime();
public static void main(String[]);
}
StopwatchCPU.class
public synchronized class StopwatchCPU {
private static final double NANOSECONDS_PER_SECOND = 1.0E9;
private final management.ThreadMXBean threadTimer;
private final long start;
public void StopwatchCPU();
public double elapsedTime();
}
TestIntroCS.class
public synchronized class TestIntroCS {
public void TestIntroCS();
public static void main(String[]);
}
UnicodeTest.class
public synchronized class UnicodeTest {
private static final int CHARS_PER_LINE = 16;
private static final int MAX_CHAR = 65536;
private void UnicodeTest();
private static String toString(int);
public static void main(String[]);
}
InTest.txt
This is a test file.
Here is line 2.
mandrill