Initial checkin from local CVS repo
This commit is contained in:
commit
df06084365
|
@ -0,0 +1,3 @@
|
|||
bin
|
||||
release
|
||||
.DS_Store
|
|
@ -0,0 +1,280 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
|
@ -0,0 +1,68 @@
|
|||
Automata Explorer
|
||||
=================
|
||||
|
||||
Autaomata Explorer was a weekend project of mine after a brief but
|
||||
passionate interest in cellular automata back in 2003. This project
|
||||
should therefore _not_ be looked at as an example of my most recent
|
||||
(or best) work. Nevertheless, I am preserving it here on Github for
|
||||
historical interest and pure vanity!
|
||||
|
||||
These days, if you're interested in a much, much better Cellular
|
||||
Automata explorer, I would recommend Golly (http://golly.sourceforge.net/)
|
||||
|
||||
Building Automata
|
||||
-----------------
|
||||
|
||||
Automata uses the Ant Java build system. To build a JAR file, just type:
|
||||
|
||||
% ant
|
||||
|
||||
|
||||
To build a full release, including a versioned ZIP file, type:
|
||||
|
||||
% ant release
|
||||
|
||||
Building on OS X
|
||||
----------------
|
||||
|
||||
On OS X, this project uses the JarBundler ant task (another weekend
|
||||
project of mine) to create an executable Java bundle. Type:
|
||||
|
||||
% ant release-macosx
|
||||
|
||||
|
||||
Running Automata Explorer
|
||||
-------------------------
|
||||
|
||||
Automata requires the Java Runtime version 1.3 or later.
|
||||
|
||||
To run by hand from the command line, just type
|
||||
|
||||
UNIX or OS X:
|
||||
% java -jar bin/automata.jar
|
||||
|
||||
WINDOWS
|
||||
> java -jar BIN\automata.jar
|
||||
|
||||
|
||||
Mac OS X releases will produce a double-clickable bundle, as well.
|
||||
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
Copyright (c) 2012, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
@ -0,0 +1,104 @@
|
|||
<project name="Automata" default="build-all" basedir=".">
|
||||
<property name="id" value="$Id: build.xml,v 1.16 2003/10/13 04:05:41 sethm Exp $"/>
|
||||
<property name="version" value="1.2.4"/>
|
||||
<property name="appname" value="automata"/>
|
||||
<property name="dir.classes" value="${basedir}/classes" />
|
||||
<property name="dir.release" value="${basedir}/release" />
|
||||
<property name="dir.resources" value="${basedir}/resources" />
|
||||
<property name="dir.bin" value="${basedir}/bin" />
|
||||
<property name="dir.src" value="${basedir}/src" />
|
||||
<property name="dir.doc" value="${basedir}/javadoc" />
|
||||
<property name="dir.lib" value="${basedir}/lib" />
|
||||
<property name="main.class" value="com.loomcom.automata.Launcher" />
|
||||
|
||||
<property name="lib.jarbundler" value="${dir.lib}/jarbundler-2.2.0.jar" />
|
||||
|
||||
<property name="jar" value="${appname}.jar" />
|
||||
<property name="zip" value="${appname}-${version}.zip" />
|
||||
<property name="tar" value="${appname}-${version}.tar" />
|
||||
|
||||
<taskdef name="jarbundler"
|
||||
classpath="${lib.jarbundler}"
|
||||
classname="net.sourceforge.jarbundler.JarBundler"/>
|
||||
|
||||
<target name="jar" depends="compile">
|
||||
<jar jarfile="${dir.bin}/${jar}"
|
||||
basedir="${dir.classes}">
|
||||
<manifest>
|
||||
<attribute name="Main-Class" value="${main.class}" />
|
||||
</manifest>
|
||||
</jar>
|
||||
</target>
|
||||
|
||||
<target name="compile">
|
||||
<mkdir dir="${dir.classes}"/>
|
||||
<mkdir dir="${dir.bin}"/>
|
||||
<javac srcdir="${dir.src}"
|
||||
destdir="${dir.classes}"/>
|
||||
</target>
|
||||
|
||||
<target name="javadoc">
|
||||
<javadoc destdir="${dir.doc}"
|
||||
author="true"
|
||||
version="true"
|
||||
use="true"
|
||||
windowtitle="Automata">
|
||||
<packageset dir="${dir.src}" defaultexcludes="yes">
|
||||
<include name="com/loomcom/automata/**" />
|
||||
<exclude name="CVS" />
|
||||
</packageset>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
|
||||
<target name="release" depends="build-all">
|
||||
<mkdir dir="${dir.release}"/>
|
||||
<zip destfile="${dir.release}/${zip}">
|
||||
<zipfileset dir="${basedir}"
|
||||
prefix="${appname}-${version}/"
|
||||
includes="LICENSE.TXT,README.TXT,build.xml,src/**,javadoc/**,bin/**,lib/**"/>
|
||||
</zip>
|
||||
<tar destfile="${dir.release}/${tar}">
|
||||
<tarfileset dir="${basedir}"
|
||||
prefix="${appname}-${version}/"
|
||||
includes="LICENSE.TXT,README.TXT,build.xml,src/**,javadoc/**,bin/**,lib/**"/>
|
||||
</tar>
|
||||
<!-- Compress the tar -->
|
||||
<gzip src="${dir.release}/${tar}" zipfile="${dir.release}/${tar}.gz"/>
|
||||
<!-- Remove the old tar, leave the gzip file -->
|
||||
<delete file="${dir.release}/${tar}" quiet="true" />
|
||||
</target>
|
||||
|
||||
<!-- Create a Mac OS X application bundle. This will not work on
|
||||
a non-MacOS X platform. -->
|
||||
<target name="release-macosx" depends="release">
|
||||
<jarbundler dir="${dir.release}"
|
||||
name="Automata ${version}"
|
||||
jars="${dir.bin}/${jar}"
|
||||
mainclass="com.loomcom.automata.Launcher"
|
||||
icon="${dir.resources}/automata.icns"
|
||||
version="${version}"
|
||||
infostring="Automata ${version}"
|
||||
jvmversion="1.4+"
|
||||
smalltabs="true"
|
||||
antialiasedgraphics="false"
|
||||
antialiasedtext="false"
|
||||
liveresize="false"
|
||||
growboxintrudes="false"
|
||||
screenmenu="true" />
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete includeEmptyDirs="true" quiet="true">
|
||||
<fileset dir="${basedir}" includes="**/.DS_Store"/>
|
||||
<fileset dir="${dir.doc}" includes="**" />
|
||||
<fileset dir="${dir.release}" includes="**" />
|
||||
<fileset dir="${dir.classes}" includes="**" />
|
||||
<fileset dir="${dir.bin}" includes="*.jar" />
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<target name="build-all" depends="jar,javadoc">
|
||||
</target>
|
||||
|
||||
</project>
|
Binary file not shown.
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* Information about the application. A standard "About" box, to stroke ego.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: AboutDialog.java,v 1.11 2003/10/04 00:37:59 sethm Exp $
|
||||
*/
|
||||
public class AboutDialog extends JFrame {
|
||||
|
||||
private static String dateString = "October 3, 2003";
|
||||
private static String versionString = "1.2.4";
|
||||
|
||||
/**
|
||||
* Construct an About Box frame.
|
||||
*/
|
||||
public AboutDialog() {
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
JPanel infoPanel = new JPanel();
|
||||
infoPanel.setBorder(BorderFactory.createEmptyBorder(18,18,18,18));
|
||||
infoPanel.setLayout(new BoxLayout(infoPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
Font largeFont = new Font("SansSerif", Font.BOLD, 18);
|
||||
Font midFont = new Font("SansSerif", Font.BOLD, 14);
|
||||
Font textFont = new Font("SansSerif", Font.PLAIN, 14);
|
||||
Font smallFont = new Font("SansSerif", Font.PLAIN, 10);
|
||||
|
||||
JLabel nameLabel = new JLabel("Cellular Automata Explorer");
|
||||
nameLabel.setFont(largeFont);
|
||||
nameLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JLabel authorLabel = new JLabel("Seth Morabito");
|
||||
authorLabel.setFont(midFont);
|
||||
authorLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JLabel companyLabel = new JLabel("Loom Communications");
|
||||
companyLabel.setFont(textFont);
|
||||
companyLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JLabel urlLabel = new JLabel("http://www.loomcom.com/");
|
||||
urlLabel.setFont(textFont);
|
||||
urlLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JLabel versionLabel = new JLabel("Version " + versionString);
|
||||
versionLabel.setFont(smallFont);
|
||||
versionLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JLabel dateLabel = new JLabel(dateString);
|
||||
dateLabel.setFont(smallFont);
|
||||
dateLabel.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
JTextArea license =
|
||||
new JTextArea("Distributed under the terms of the GNU\n" +
|
||||
"Public License. For details, see the file\n" +
|
||||
"LICENSE.TXT, or http://www.gnu.org/licenses/gpl.html");
|
||||
license.setFont(smallFont);
|
||||
license.setEditable(false);
|
||||
license.setBackground(getBackground());
|
||||
license.setAlignmentX(Component.LEFT_ALIGNMENT);
|
||||
|
||||
|
||||
infoPanel.add(nameLabel);
|
||||
infoPanel.add(Box.createRigidArea(new Dimension(0,10)));
|
||||
infoPanel.add(authorLabel);
|
||||
infoPanel.add(companyLabel);
|
||||
infoPanel.add(urlLabel);
|
||||
infoPanel.add(versionLabel);
|
||||
infoPanel.add(dateLabel);
|
||||
infoPanel.add(Box.createRigidArea(new Dimension(0,10)));
|
||||
infoPanel.add(license);
|
||||
|
||||
JButton okButton = new JButton("OK");
|
||||
okButton.setSelected(true);
|
||||
|
||||
okButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
JPanel buttonBar = new JPanel();
|
||||
buttonBar.setLayout(new FlowLayout(FlowLayout.CENTER));
|
||||
|
||||
buttonBar.add(okButton);
|
||||
|
||||
getContentPane().add(infoPanel, BorderLayout.CENTER);
|
||||
getContentPane().add(buttonBar, BorderLayout.SOUTH);
|
||||
|
||||
setResizable(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,788 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* The main Cellular Automata application window.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: AutomataFrame.java,v 1.14 2003/10/13 04:00:23 sethm Exp $
|
||||
*/
|
||||
public class AutomataFrame extends JFrame implements Observer {
|
||||
|
||||
// Constants
|
||||
private static final String FRAME_TITLE = "Automata";
|
||||
|
||||
// Pseudo-Constants defined during initialization
|
||||
private String DEFAULT_SPEED;
|
||||
private JRadioButtonMenuItem DEFAULT_RULESET;
|
||||
private JRadioButtonMenuItem DEFAULT_SHAPE;
|
||||
|
||||
// The size of our cells, in pixels
|
||||
int mCellSize;
|
||||
|
||||
// Thread which will update the Cell Panel
|
||||
private UpdateThread mUpdateThread;
|
||||
|
||||
// The shape we want to draw, or null for no shape.
|
||||
private boolean[][] mDrawGlider;
|
||||
|
||||
// Cell panel mouse and mousemotion listener
|
||||
private CellSelectListener mCellSelectListener;
|
||||
|
||||
// The cell data model
|
||||
private CellModel mCellModel;
|
||||
|
||||
// Components
|
||||
private CellPanel mCellPanel;
|
||||
private ColorChooserDialog mColorChooser;
|
||||
private AboutDialog mAboutDialog;
|
||||
private JLabel mGenerationCountLabel;
|
||||
private JButton mStepButton;
|
||||
private JToggleButton mStartStopButton;
|
||||
private JComboBox mSpeedSelector;
|
||||
|
||||
// The menu bar and associated menu items
|
||||
private JMenuBar mMenuBar;
|
||||
|
||||
private JMenu mFileMenu;
|
||||
private JMenuItem mAboutMenuItem;
|
||||
private JMenuItem mNewAutomataMenuItem;
|
||||
private JMenuItem mQuitMenuItem;
|
||||
|
||||
private JMenu mDrawMenu;
|
||||
private JCheckBoxMenuItem mShowOutlinesMenuItem;
|
||||
private JMenuItem mEditColorsMenuItem;
|
||||
private JCheckBoxMenuItem mShowAgingMenuItem;
|
||||
private JMenuItem mResetMenuItem;
|
||||
private JMenu mGliderSubMenu;
|
||||
private ButtonGroup mGliderButtonGroup;
|
||||
|
||||
private JMenu mRulesMenu;
|
||||
private ButtonGroup mRulesButtonGroup;
|
||||
|
||||
// Containers associated with the menu items
|
||||
private TreeMap mGliderMap;
|
||||
private TreeMap mRulesMap;
|
||||
|
||||
// UI layout containers
|
||||
private JPanel mCellPanelContainer;
|
||||
private JPanel mButtonContainer;
|
||||
private JPanel mUIButtons;
|
||||
private JPanel mStatusContainer;
|
||||
|
||||
/**
|
||||
* Construct a new frame to hold our automata simulation.
|
||||
* Just a pass-through to setupUI() at the moment.
|
||||
*/
|
||||
public AutomataFrame() {
|
||||
setupUI();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new cell panel to the main app window.
|
||||
*/
|
||||
public void addCells(int cols, int rows, int cellSize) {
|
||||
mCellSize = cellSize;
|
||||
|
||||
mCellModel = new CellModel(cols, rows);
|
||||
mCellModel.addObserver(this);
|
||||
|
||||
// Remove any existing cell panel
|
||||
if (mCellPanel != null) {
|
||||
mCellPanelContainer.remove(mCellPanel);
|
||||
}
|
||||
|
||||
mCellPanel = new CellPanel(mCellModel, cellSize);
|
||||
|
||||
mCellSelectListener = new CellSelectListener();
|
||||
|
||||
mCellPanel.addMouseListener(mCellSelectListener);
|
||||
mCellPanel.addMouseMotionListener(mCellSelectListener);
|
||||
|
||||
mCellPanelContainer.add(mCellPanel);
|
||||
|
||||
mUpdateThread = new UpdateThread(mCellModel);
|
||||
|
||||
// set initial conditions
|
||||
setDefaults();
|
||||
|
||||
// Register with the color chooser
|
||||
if (mColorChooser != null) {
|
||||
mColorChooser.setCellPanel(mCellPanel);
|
||||
}
|
||||
|
||||
// Start the thread which updates the cell model.
|
||||
mUpdateThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the current cell panel from the main app window.
|
||||
*/
|
||||
public void removeCells() {
|
||||
mCellSize = 0;
|
||||
|
||||
if (mUpdateThread != null) {
|
||||
mUpdateThread.doStop();
|
||||
}
|
||||
|
||||
if (mCellPanelContainer != null) {
|
||||
mCellPanelContainer.remove(mCellPanel);
|
||||
}
|
||||
|
||||
if (mCellPanel != null) {
|
||||
mCellPanel.removeMouseListener(mCellSelectListener);
|
||||
mCellPanel.removeMouseMotionListener(mCellSelectListener);
|
||||
}
|
||||
|
||||
mCellModel = null;
|
||||
mCellSelectListener = null;
|
||||
mCellPanel = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each time a new cell panel is added, reset the UI
|
||||
* widgets to default values.
|
||||
*/
|
||||
private void setDefaults() {
|
||||
// Make sure the Start/Stop button is reset
|
||||
stopCellUpdates();
|
||||
|
||||
if (mCellSize > 3) {
|
||||
mShowOutlinesMenuItem.setSelected(true);
|
||||
mCellPanel.showCellOutlines(true);
|
||||
} else {
|
||||
mShowOutlinesMenuItem.setSelected(false);
|
||||
mShowOutlinesMenuItem.setEnabled(false);
|
||||
mCellPanel.showCellOutlines(false);
|
||||
}
|
||||
|
||||
mSpeedSelector.setSelectedItem(DEFAULT_SPEED);
|
||||
|
||||
// Programatically select the default ruleset
|
||||
DEFAULT_RULESET.setSelected(true);
|
||||
DEFAULT_RULESET.doClick();
|
||||
|
||||
// Programatically select the default ruleset
|
||||
DEFAULT_SHAPE.setSelected(true);
|
||||
DEFAULT_SHAPE.doClick();
|
||||
|
||||
mGenerationCountLabel.setText("0");
|
||||
|
||||
mShowAgingMenuItem.setSelected(true);
|
||||
mCellPanel.setCellAging(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of the Observer interface.
|
||||
*/
|
||||
public void update(Observable t, Object o) {
|
||||
mGenerationCountLabel.setText(
|
||||
Integer.toString(mCellModel.getGeneration()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to cleanly shut down the application in a polite way.
|
||||
*/
|
||||
private void shutdown() {
|
||||
if (mUpdateThread != null) {
|
||||
try {
|
||||
// Offer a short window to politely join with
|
||||
// the thread before shutting down, good manners
|
||||
mUpdateThread.doStop();
|
||||
mUpdateThread.join(500);
|
||||
} catch (InterruptedException ex) {
|
||||
;
|
||||
}
|
||||
}
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lay out the UI.
|
||||
*/
|
||||
private void setupUI() {
|
||||
setTitle(FRAME_TITLE);
|
||||
|
||||
// Components
|
||||
JComboBox speedComboBox;
|
||||
JCheckBox cellOutlineSelector;
|
||||
JLabel cellTypeLabel;
|
||||
JLabel speedLabel;
|
||||
|
||||
// The main menu bar.
|
||||
mMenuBar = new JMenuBar();
|
||||
|
||||
int menuKeyMask =
|
||||
java.awt.Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
|
||||
/*
|
||||
* The "File" Menu
|
||||
*/
|
||||
mFileMenu = new JMenu("File");
|
||||
mFileMenu.setMnemonic(KeyEvent.VK_F);
|
||||
|
||||
mAboutMenuItem = new JMenuItem("About");
|
||||
mAboutMenuItem.setMnemonic(KeyEvent.VK_A);
|
||||
mAboutMenuItem.addActionListener(new AboutListener());
|
||||
|
||||
mNewAutomataMenuItem = new JMenuItem("New Automata...");
|
||||
mNewAutomataMenuItem.setMnemonic(KeyEvent.VK_N);
|
||||
mNewAutomataMenuItem.addActionListener(new NewAutomataListener());
|
||||
|
||||
mQuitMenuItem = new JMenuItem("Quit", KeyEvent.VK_Q);
|
||||
mQuitMenuItem.setAccelerator(KeyStroke.getKeyStroke(
|
||||
KeyEvent.VK_Q, menuKeyMask));
|
||||
|
||||
mQuitMenuItem.addActionListener(new QuitListener());
|
||||
|
||||
// Assemble the menu
|
||||
mFileMenu.add(mAboutMenuItem);
|
||||
mFileMenu.add(mNewAutomataMenuItem);
|
||||
mFileMenu.add(mQuitMenuItem);
|
||||
|
||||
/*
|
||||
* The "Draw" Menu
|
||||
*/
|
||||
mDrawMenu = new JMenu("Draw");
|
||||
mDrawMenu.setMnemonic(KeyEvent.VK_D);
|
||||
|
||||
// Show or hide cell outlines
|
||||
mShowOutlinesMenuItem = new JCheckBoxMenuItem("Show Cell Outlines");
|
||||
mShowOutlinesMenuItem.setMnemonic(KeyEvent.VK_O);
|
||||
mShowOutlinesMenuItem.addItemListener(new ShowOutlinesListener());
|
||||
|
||||
// Enable or disable the showing of cell "age"
|
||||
mShowAgingMenuItem = new JCheckBoxMenuItem("Show Cell Aging");
|
||||
mShowAgingMenuItem.setMnemonic(KeyEvent.VK_A);
|
||||
mShowAgingMenuItem.addItemListener(new ShowAgingListener());
|
||||
|
||||
// Set custom colors...
|
||||
mEditColorsMenuItem = new JMenuItem("Edit Colors...");
|
||||
mEditColorsMenuItem.setMnemonic(KeyEvent.VK_C);
|
||||
mEditColorsMenuItem.addActionListener(new EditColorsListener());
|
||||
|
||||
// Clear the panel and reset...
|
||||
mResetMenuItem = new JMenuItem("Clear Display");
|
||||
mResetMenuItem.setMnemonic(KeyEvent.VK_L);
|
||||
mResetMenuItem.addActionListener(new ResetPanelListener());
|
||||
|
||||
mGliderSubMenu = new JMenu("Draw Glider");
|
||||
|
||||
// A set of shapes we know how to draw...
|
||||
mGliderButtonGroup = new ButtonGroup();
|
||||
|
||||
mGliderMap = setupGliders();
|
||||
|
||||
final String noGlider = "None";
|
||||
|
||||
ShapeMenuListener shapeMenuListener = new ShapeMenuListener(noGlider);
|
||||
|
||||
JRadioButtonMenuItem noGliderItem = new JRadioButtonMenuItem(noGlider);
|
||||
|
||||
DEFAULT_SHAPE = noGliderItem;
|
||||
|
||||
noGliderItem.addActionListener(shapeMenuListener);
|
||||
mGliderButtonGroup.add(noGliderItem);
|
||||
mGliderSubMenu.add(noGliderItem);
|
||||
|
||||
for (Iterator i = mGliderMap.keySet().iterator(); i.hasNext(); ) {
|
||||
String s = (String) i.next();
|
||||
|
||||
JRadioButtonMenuItem item = new JRadioButtonMenuItem(s);
|
||||
item.addActionListener(shapeMenuListener);
|
||||
mGliderButtonGroup.add(item);
|
||||
mGliderSubMenu.add(item);
|
||||
}
|
||||
|
||||
// Populate the "Draw" menu
|
||||
mDrawMenu.add(mShowOutlinesMenuItem);
|
||||
mDrawMenu.add(mShowAgingMenuItem);
|
||||
mDrawMenu.addSeparator();
|
||||
mDrawMenu.add(mEditColorsMenuItem);
|
||||
mDrawMenu.addSeparator();
|
||||
mDrawMenu.add(mResetMenuItem);
|
||||
mDrawMenu.addSeparator();
|
||||
mDrawMenu.add(mGliderSubMenu);
|
||||
|
||||
/*
|
||||
* The "Rules" Menu
|
||||
*/
|
||||
mRulesMap = setupRuleSets();
|
||||
|
||||
mRulesMenu = new JMenu("Rules");
|
||||
mRulesButtonGroup = new ButtonGroup();
|
||||
|
||||
// Handle menu events from the Rules menu
|
||||
RulesMenuListener rulesMenuListener = new RulesMenuListener();
|
||||
|
||||
// Populate the "Rules" menu
|
||||
boolean first = true;
|
||||
for (Iterator i = mRulesMap.keySet().iterator(); i.hasNext();) {
|
||||
String s = (String) i.next();
|
||||
|
||||
JRadioButtonMenuItem item = new JRadioButtonMenuItem(s);
|
||||
item.addActionListener(rulesMenuListener);
|
||||
|
||||
// We should automatically choose a rule set to start with.
|
||||
// It should be either the first rule set on the menu, or "Life",
|
||||
// if it is found.
|
||||
if (first || "Life".equals(((RuleSet)mRulesMap.get(s)).getShortName())) {
|
||||
DEFAULT_RULESET = item;
|
||||
first = false;
|
||||
}
|
||||
|
||||
mRulesButtonGroup.add(item);
|
||||
mRulesMenu.add(item);
|
||||
}
|
||||
|
||||
// Assembling the menu bar
|
||||
mMenuBar.add(mFileMenu);
|
||||
mMenuBar.add(mDrawMenu);
|
||||
mMenuBar.add(mRulesMenu);
|
||||
|
||||
this.setJMenuBar(mMenuBar);
|
||||
|
||||
// The "Start/Pause" button
|
||||
mStartStopButton = new JToggleButton("Start", false);
|
||||
mStartStopButton.addItemListener(new StartButtonListener());
|
||||
|
||||
// Combo Box that determines the generation update speed
|
||||
mSpeedSelector = new JComboBox();
|
||||
mSpeedSelector.addItem("1");
|
||||
mSpeedSelector.addItem("2");
|
||||
mSpeedSelector.addItem("5");
|
||||
mSpeedSelector.addItem("10");
|
||||
mSpeedSelector.addItem("20");
|
||||
|
||||
// Set the default speed to be selected when creating a new
|
||||
// automata cell panel.
|
||||
DEFAULT_SPEED = "5";
|
||||
|
||||
mSpeedSelector.addActionListener(new SpeedSelectorListener());
|
||||
|
||||
// "Step" button
|
||||
mStepButton = new JButton("Step");
|
||||
mStepButton.addActionListener(new StepButtonListener());
|
||||
|
||||
// Container for the Cell Panel
|
||||
mCellPanelContainer = new JPanel();
|
||||
mCellPanelContainer.setLayout(new FlowLayout(FlowLayout.CENTER));
|
||||
// mCellPanelContainer.add(mCellPanel);
|
||||
|
||||
// Container for UI buttons and status labels
|
||||
mButtonContainer = new JPanel();
|
||||
|
||||
mUIButtons = new JPanel();
|
||||
|
||||
GridBagLayout gridBag = new GridBagLayout();
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
mUIButtons.setLayout(gridBag);
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
|
||||
speedLabel = new JLabel("Generations per second");
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
gridBag.setConstraints(speedLabel, c);
|
||||
mUIButtons.add(speedLabel);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 1;
|
||||
gridBag.setConstraints(mSpeedSelector, c);
|
||||
mUIButtons.add(mSpeedSelector);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 1;
|
||||
gridBag.setConstraints(mStartStopButton, c);
|
||||
mUIButtons.add(mStartStopButton);
|
||||
|
||||
c.gridx = 2;
|
||||
c.gridy = 1;
|
||||
gridBag.setConstraints(mStepButton, c);
|
||||
mUIButtons.add(mStepButton);
|
||||
|
||||
// Status label
|
||||
mStatusContainer = new JPanel();
|
||||
|
||||
mGenerationCountLabel = new JLabel("0", JLabel.CENTER);
|
||||
mGenerationCountLabel.setForeground(Color.red);
|
||||
|
||||
mStatusContainer.setLayout(new BorderLayout());
|
||||
mStatusContainer.add(new JLabel("Generations"), BorderLayout.NORTH);
|
||||
mStatusContainer.add(mGenerationCountLabel, BorderLayout.SOUTH);
|
||||
|
||||
mButtonContainer.add(mUIButtons, BorderLayout.WEST);
|
||||
mButtonContainer.add(mStatusContainer, BorderLayout.EAST);
|
||||
|
||||
getContentPane().add(mCellPanelContainer, BorderLayout.CENTER);
|
||||
getContentPane().add(mButtonContainer, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause refreshing the cell generations.
|
||||
*/
|
||||
private void stopCellUpdates() {
|
||||
if (mUpdateThread != null) {
|
||||
mStepButton.setEnabled(true);
|
||||
mStepButton.doClick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update one cell generation, then stop.
|
||||
*/
|
||||
private void stepCellUpdates() {
|
||||
if (mCellPanel != null && mUpdateThread.isPaused()) {
|
||||
mCellModel.transform();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A list of built-in shapes we can draw. Most of these are
|
||||
* gliders in the Life rule set, as well as some others.
|
||||
*
|
||||
* @return A map of pattern names and arrays
|
||||
*/
|
||||
private TreeMap setupGliders() {
|
||||
|
||||
TreeMap gliderMap = new TreeMap();
|
||||
|
||||
// "The Glider"
|
||||
gliderMap.put("The Glider", new boolean[][] {
|
||||
{true, false, false}, // Row 1
|
||||
{true, false, true}, // Row 2
|
||||
{true, true, false} // Row 3
|
||||
});
|
||||
|
||||
// A "Fountain" glider
|
||||
gliderMap.put("Fountain", new boolean[][] {
|
||||
{true, true, true, false, false, false},
|
||||
{true, false, false, false, true, true},
|
||||
{false, true, true, true, true, true},
|
||||
{false, false, false, false, false, false},
|
||||
{false, true, true, true, true, true},
|
||||
{true, false, false, false, true, true},
|
||||
{true, true, true, false, false, false}
|
||||
});
|
||||
|
||||
// "The Coe Ship" glider
|
||||
gliderMap.put("The Coe Ship", new boolean[][] {
|
||||
{false, true, true, false, false, false, false, false, false, false},
|
||||
{true, true, false, true, true, false, false, false, false, false},
|
||||
{false, true, true, true, true, false, false, false, false, false},
|
||||
{false, false, true, true, false, false, false, false, false, false},
|
||||
{false, false, false, true, false, false, false, false, false, false},
|
||||
{false, true, false, false, false, true, false, false, false, false},
|
||||
{true, false, false, false, false, false, true, false, true, true},
|
||||
{true, false, false, false, false, false, true, true, false, false},
|
||||
{true, true, true, true, true, true, false, false, false, false},
|
||||
});
|
||||
|
||||
// "Lightweight Spaceship" glider
|
||||
gliderMap.put("Lightweight Spaceship", new boolean[][] {
|
||||
{false, true, true, true},
|
||||
{true, false, false, true},
|
||||
{false, false, false, true},
|
||||
{false, false, false, true},
|
||||
{true, false, true, false}
|
||||
});
|
||||
|
||||
// More, as time permits...
|
||||
return gliderMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the list of rule sets.
|
||||
*
|
||||
* NOTE: To add new rule sets to the application, list 'em here!
|
||||
* Future versions will allow creation of new rule sets on the fly at
|
||||
* through a nifty dialog.
|
||||
*/
|
||||
private TreeMap setupRuleSets() {
|
||||
|
||||
LinkedList rules = new LinkedList();
|
||||
TreeMap rulesMap = new TreeMap();
|
||||
|
||||
// Start with the classic.
|
||||
rules.add(new RuleSet("Life", new int[]{3}, new int[]{2,3}));
|
||||
|
||||
rules.add(new RuleSet("Amoeba", new int[]{3,5,7}, new int[]{1,3,5,8}));
|
||||
rules.add(new RuleSet("Assimilation", new int[]{3,4,5},
|
||||
new int[]{4,5,6,7}));
|
||||
rules.add(new RuleSet("Bacteria", new int[]{3,4}, new int[]{4,5,6}));
|
||||
rules.add(new RuleSet("Blinkers", new int[]{3,4,5}, new int[]{2}));
|
||||
rules.add(new RuleSet("Blossom", new int[]{2,3}, new int[]{2,3}));
|
||||
rules.add(new RuleSet("Bugs", new int[]{3,5,6,7},
|
||||
new int[]{1,5,6,7,8}));
|
||||
rules.add(new RuleSet("Coagulations", new int[]{3,7,8},
|
||||
new int[]{2,3,5,6,7,8}));
|
||||
rules.add(new RuleSet("Coral", new int[]{3},
|
||||
new int[]{4,5,6,7,8}));
|
||||
rules.add(new RuleSet("Day & Night", new int[]{3,6,7,8},
|
||||
new int[]{3,4,6,7,8}));
|
||||
rules.add(new RuleSet("Diamoeba", new int[]{3,5,6,7,8},
|
||||
new int[]{5,6,7,8}));
|
||||
rules.add(new RuleSet("Gnarl", new int[]{1}, new int[]{1}));
|
||||
rules.add(new RuleSet("H-trees", new int[]{1},
|
||||
new int[]{0,1,2,3,4,5,6,7,8}));
|
||||
rules.add(new RuleSet("HighLife", new int[]{3,6}, new int[]{2,3}));
|
||||
rules.add(new RuleSet("Holstein", new int[]{3,5,6,7,8},
|
||||
new int[]{4,6,7,8}));
|
||||
rules.add(new RuleSet("Iceballs", new int[]{2,5,6,7,8},
|
||||
new int[]{5,6,7,8}));
|
||||
rules.add(new RuleSet("Land Rush", new int[]{3,6},
|
||||
new int[]{2,3,4,5,7,8}));
|
||||
rules.add(new RuleSet("Life Without Death", new int[]{3},
|
||||
new int[]{0,1,2,3,4,5,6,7,8}));
|
||||
rules.add(new RuleSet("LongLife", new int[]{3,4,5}, new int[]{5}));
|
||||
rules.add(new RuleSet("Majority", new int[]{4,5,6,7,8},
|
||||
new int[]{5,6,7,8}));
|
||||
rules.add(new RuleSet("Maze", new int[]{3}, new int[]{1,2,3,4,5}));
|
||||
rules.add(new RuleSet("Move", new int[]{3,6,8}, new int[]{2,4,5}));
|
||||
rules.add(new RuleSet("Pseudo Life", new int[]{3,5,7},
|
||||
new int[]{2,3,8}));
|
||||
rules.add(new RuleSet("Replicator", new int[]{1,3,5,7},
|
||||
new int[]{1,3,5,7}));
|
||||
rules.add(new RuleSet("Seeds", new int[]{2},
|
||||
new int[]{}));
|
||||
rules.add(new RuleSet("Serviettes", new int[]{2,3,4},
|
||||
new int[]{}));
|
||||
|
||||
// Rulesets without nicknames
|
||||
rules.add(new RuleSet(new int[]{2,4,8}, new int[]{2,4,8}));
|
||||
rules.add(new RuleSet(new int[]{3,4,5}, new int[]{2,4,5}));
|
||||
rules.add(new RuleSet(new int[]{3,4}, new int[]{2,5}));
|
||||
rules.add(new RuleSet(new int[]{3,5}, new int[]{2,4}));
|
||||
|
||||
// "Probabilistic" rulesets
|
||||
rules.add(new ChanceRuleSet("Randomized Life", new int[]{3},
|
||||
new int[]{2,3},
|
||||
99.0, 99.0));
|
||||
|
||||
for (Iterator i = rules.iterator(); i.hasNext(); ) {
|
||||
RuleSet r = (RuleSet) i.next();
|
||||
rulesMap.put(r.getName(), r);
|
||||
}
|
||||
|
||||
return rulesMap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Event Listener Implementations
|
||||
*/
|
||||
private final class StartButtonListener implements ItemListener {
|
||||
public void itemStateChanged(ItemEvent evt) {
|
||||
JToggleButton b = (JToggleButton) evt.getSource();
|
||||
if (mUpdateThread != null) {
|
||||
if (evt.getStateChange() == ItemEvent.SELECTED) {
|
||||
mStartStopButton.setText("Pause");
|
||||
mStepButton.setEnabled(false);
|
||||
mUpdateThread.go();
|
||||
} else {
|
||||
mStartStopButton.setText("Start");
|
||||
mStepButton.setEnabled(true);
|
||||
mUpdateThread.pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class StepButtonListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
stepCellUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
private final class SpeedSelectorListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
JComboBox source = (JComboBox) evt.getSource();
|
||||
String s = (String) source.getSelectedItem();
|
||||
int gps = Integer.valueOf(s).intValue();
|
||||
if (gps > 0 && gps < 1000) {
|
||||
mUpdateThread.setSleepInterval(1000 / gps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class RulesMenuListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
String s = evt.getActionCommand();
|
||||
RuleSet rs = (RuleSet) mRulesMap.get(s);
|
||||
mCellModel.setRuleSet(rs);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ShapeMenuListener implements ActionListener {
|
||||
private final String noGlider;
|
||||
private ShapeMenuListener(String noGlider) {
|
||||
super();
|
||||
this.noGlider = noGlider;
|
||||
}
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
String s = evt.getActionCommand();
|
||||
// Our special case is a single cell. If we're just
|
||||
// drawing single cells, there's no need to set any
|
||||
// glider shape.
|
||||
if (noGlider.equals(s)) {
|
||||
mDrawGlider = null;
|
||||
return;
|
||||
}
|
||||
|
||||
mDrawGlider = (boolean[][]) mGliderMap.get(s);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ResetPanelListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
stopCellUpdates();
|
||||
mCellModel.reset();
|
||||
}
|
||||
}
|
||||
|
||||
private final class EditColorsListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (mColorChooser == null) {
|
||||
mColorChooser = new ColorChooserDialog(mCellPanel);
|
||||
Utilities.centerWindow(mColorChooser);
|
||||
}
|
||||
mColorChooser.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ShowAgingListener implements ItemListener {
|
||||
public void itemStateChanged(ItemEvent evt) {
|
||||
if (evt.getStateChange() == ItemEvent.SELECTED) {
|
||||
mCellPanel.setCellAging(true);
|
||||
} else {
|
||||
mCellPanel.setCellAging(false);
|
||||
}
|
||||
mCellPanel.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private final class ShowOutlinesListener implements ItemListener {
|
||||
public void itemStateChanged(ItemEvent evt) {
|
||||
if (evt.getStateChange() == ItemEvent.SELECTED) {
|
||||
mCellPanel.showCellOutlines(true);
|
||||
} else {
|
||||
mCellPanel.showCellOutlines(false);
|
||||
}
|
||||
mCellPanel.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
private final class QuitListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private final class NewAutomataListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
// Hide ourselves...
|
||||
setVisible(false);
|
||||
|
||||
// Remove our cells.
|
||||
removeCells();
|
||||
|
||||
// Show the launcher.
|
||||
Launcher launcher = Launcher.getLauncher();
|
||||
launcher.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
private final class AboutListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (mAboutDialog == null) {
|
||||
mAboutDialog = new AboutDialog();
|
||||
mAboutDialog.pack();
|
||||
}
|
||||
Utilities.centerWindow(mAboutDialog);
|
||||
mAboutDialog.setVisible(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen for mouse events in the Cell Panel.
|
||||
*/
|
||||
private final class CellSelectListener
|
||||
implements MouseListener, MouseMotionListener {
|
||||
int mLastCellX = 0;
|
||||
int mLastCellY = 0;
|
||||
|
||||
// MouseListener implementations
|
||||
|
||||
/*
|
||||
*Toggle the clicked-on cell
|
||||
*/
|
||||
public void mouseClicked(MouseEvent evt) {
|
||||
CellPanel source = (CellPanel)evt.getSource();
|
||||
int x = evt.getX();
|
||||
int y = evt.getY();
|
||||
int cellX = x / mCellSize;
|
||||
int cellY = y / mCellSize;
|
||||
|
||||
if (mDrawGlider != null) {
|
||||
mCellModel.drawShape(cellX, cellY, mDrawGlider);
|
||||
} else {
|
||||
mCellModel.flipCell(cellX, cellY);
|
||||
}
|
||||
}
|
||||
public void mouseEntered(MouseEvent evt) {
|
||||
}
|
||||
public void mouseExited(MouseEvent evt) {
|
||||
}
|
||||
public void mousePressed(MouseEvent evt) {
|
||||
}
|
||||
public void mouseReleased(MouseEvent evt) {
|
||||
}
|
||||
|
||||
// MouseMotionListener implementations
|
||||
|
||||
/*
|
||||
* Allow primitive pattern drawing while dragging the mouse.
|
||||
*/
|
||||
public void mouseDragged(MouseEvent evt) {
|
||||
int x = evt.getX();
|
||||
int y = evt.getY();
|
||||
int cellX = x / mCellSize;
|
||||
int cellY = y / mCellSize;
|
||||
boolean drawOrErase =
|
||||
!((evt.getModifiers()
|
||||
& (InputEvent.SHIFT_DOWN_MASK | InputEvent.SHIFT_MASK))
|
||||
!= 0);
|
||||
if (cellX != mLastCellX || cellY != mLastCellY) {
|
||||
mCellModel.setCell(cellX, cellY, drawOrErase);
|
||||
|
||||
mLastCellX = cellX;
|
||||
mLastCellY = cellY;
|
||||
}
|
||||
}
|
||||
public void mouseMoved(MouseEvent evt) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
/**
|
||||
* The data model representing the cells. This model represents the
|
||||
* current state of all the "cells" (boolean bits) in the two-dimensional
|
||||
* world.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: CellModel.java,v 1.6 2003/07/09 23:32:49 sethm Exp $
|
||||
*/
|
||||
public class CellModel extends java.util.Observable {
|
||||
private boolean[][] mCells; // The actual data.
|
||||
private boolean[][] mTempCells; // Temp array used when transforming
|
||||
|
||||
private int[][] mCellAges; // Array of cell ages.
|
||||
|
||||
private int mCols; // Width of the cell array
|
||||
private int mRows; // Height of the cell array
|
||||
private RuleSet mRuleSet; // Rule set to use when transforming
|
||||
|
||||
private int mGeneration; // Current "generation"
|
||||
|
||||
/**
|
||||
* Create a new two dimensional cell array with width <tt>x</tt>
|
||||
* and height <tt>y</tt>.
|
||||
*
|
||||
* @param x The number of cell columns
|
||||
* @param y The number of cell rows
|
||||
*/
|
||||
public CellModel(int x, int y) {
|
||||
this(x, y, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new two dimensional cell array with width <tt>x</tt>
|
||||
* and height <tt>y</tt>, and set the initial rule set.
|
||||
*
|
||||
* @param x The number of cell columns
|
||||
* @param y The number of cell rows
|
||||
* @param rs The RuleSet to use at creation time
|
||||
*/
|
||||
public CellModel(int x, int y, RuleSet rs) {
|
||||
mCells = new boolean[x][y];
|
||||
mTempCells = new boolean[x][y];
|
||||
mCellAges = new int[x][y];
|
||||
mCols = x;
|
||||
mRows = y;
|
||||
mRuleSet = rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean value of the cell at <tt>(x,y)</tt>
|
||||
*
|
||||
* @param x The cell <tt>x</tt> coordinate
|
||||
* @param y The cell <tt>y</tt> coordinate
|
||||
* @return True if the cell is alive, false if not
|
||||
*/
|
||||
public boolean getCell(int x, int y) {
|
||||
if (x < 0 || y < 0 || x > (mCols - 1) || y > (mRows - 1))
|
||||
return false;
|
||||
|
||||
return mCells[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the age, in generations, of the cell at <tt>(x,y)</tt>
|
||||
*/
|
||||
public int getCellAge(int x, int y) {
|
||||
if (x < 0 || y < 0 || x > (mCols - 1) || y > (mRows - 1))
|
||||
return 0;
|
||||
|
||||
return mCellAges[x][y];
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the cell at <tt>(x,y)</tt>.
|
||||
*
|
||||
* @param x The cell <tt>x</tt> coordinate.
|
||||
* @param y The cell <tt>y</tt> coordinate.
|
||||
*/
|
||||
public void flipCell(int x, int y) {
|
||||
if (x < 0 || y < 0 || x > (mCols - 1) || y > (mRows - 1))
|
||||
return;
|
||||
|
||||
mCells[x][y] = !mCells[x][y];
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cell at <tt>(x,y)</tt> with the supplied boolean value.
|
||||
*
|
||||
* @param x The cell <tt>x</tt> coordinate.
|
||||
* @param y The cell <tt>y</tt> coordinate.
|
||||
* @param b The value to set.
|
||||
*/
|
||||
public void setCell(int x, int y, boolean b) {
|
||||
if (x < 0 || y < 0 || x > (mCols - 1) || y > (mRows - 1))
|
||||
return;
|
||||
|
||||
mCells[x][y] = b;
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of columns in this cell field.
|
||||
*
|
||||
* @return The number of columns.
|
||||
*/
|
||||
public int getCols() {
|
||||
return mCols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of rows in this cell field.
|
||||
*
|
||||
* @return The number of rows.
|
||||
*/
|
||||
public int getRows() {
|
||||
return mRows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the field, clearing the data and setting the generation
|
||||
* count back to 0.
|
||||
*/
|
||||
public void reset() {
|
||||
for (int i = 0; i < mCols; i++) {
|
||||
for (int j = 0; j < mRows; j++) {
|
||||
mCells[i][j] = false;
|
||||
mCellAges[i][j] = 0;
|
||||
}
|
||||
}
|
||||
mGeneration = 0;
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current cell generation.
|
||||
*
|
||||
* @return Cell generation.
|
||||
*/
|
||||
public int getGeneration() {
|
||||
return mGeneration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform to the next generation of cells.
|
||||
*/
|
||||
public void transform() {
|
||||
if (mRuleSet == null) { return; }
|
||||
mRuleSet.transform(mCells, mTempCells);
|
||||
|
||||
for (int i = 0; i < mCols; i++) {
|
||||
for (int j = 0; j < mRows; j++) {
|
||||
if (mCells[i][j] & mTempCells[i][j])
|
||||
mCellAges[i][j]++;
|
||||
else
|
||||
mCellAges[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the arrays, speedily
|
||||
boolean[][] b = mCells;
|
||||
mCells = mTempCells;
|
||||
mTempCells = b;
|
||||
b = null;
|
||||
mGeneration++;
|
||||
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the RuleSet which will be used when transforming from one
|
||||
* generation to the next.
|
||||
*
|
||||
* @param rs The RuleSet to use when transforming
|
||||
*/
|
||||
public void setRuleSet(RuleSet rs) {
|
||||
mRuleSet = rs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current rule set used for transforms.
|
||||
*
|
||||
* @return The current rule set.
|
||||
*/
|
||||
public RuleSet getRuleSet() {
|
||||
return mRuleSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Place a shape into the cell field, centered on point <tt>(x,y)</tt>
|
||||
*
|
||||
* @param pattern A 2D array of booleans representing the pattern bits.
|
||||
*/
|
||||
public void drawShape(int x, int y, boolean[][] pattern) {
|
||||
int width = Utilities.getWidth(pattern);
|
||||
int height = Utilities.getHeight(pattern);
|
||||
|
||||
|
||||
// On the cell panel, the shape will begin at origin
|
||||
// ((x - width / 2), (y - height / 2))
|
||||
int originX = (x - width / 2);
|
||||
int originY = (y - height / 2);
|
||||
|
||||
// Set the appropriate bits in the mCells array
|
||||
int patternX = 0;
|
||||
outer:
|
||||
for (int i = originX; i < (originX + width) ; i++, patternX++) {
|
||||
int patternY = 0;
|
||||
for (int j = originY; j < (originY + height); j++, patternY++) {
|
||||
if (i < 0 || i > mCols - 1)
|
||||
continue;
|
||||
if (j < 0 || j > mRows - 1)
|
||||
continue outer;
|
||||
if (pattern[patternX][patternY])
|
||||
mCells[i][j] = true;
|
||||
}
|
||||
}
|
||||
setChanged();
|
||||
notifyObservers();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.geom.*;
|
||||
import java.util.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* The visual representation of a two dimensional field of cells. Cells which
|
||||
* are alive are represented by a colored rectangle on a background field.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: CellPanel.java,v 1.10 2003/10/03 23:41:03 sethm Exp $
|
||||
*/
|
||||
public class CellPanel extends JComponent implements Observer {
|
||||
private int mCols;
|
||||
private int mRows;
|
||||
private int mCellSize;
|
||||
|
||||
private Color mOutlineColor; // Outline color
|
||||
|
||||
private CellModel mCellModel;
|
||||
|
||||
private boolean mShowCellOutlines = true; // Show outlines by default
|
||||
private boolean mShowAging;
|
||||
|
||||
/**
|
||||
* Construct a new CellPanel.
|
||||
*
|
||||
* @param model The cell model for this panel.
|
||||
* @param cellSize The size of the cells, in pixels.
|
||||
*/
|
||||
public CellPanel(CellModel model, int cellSize) {
|
||||
setDoubleBuffered(true);
|
||||
mCellModel = model;
|
||||
model.addObserver(this);
|
||||
mCols = model.getCols();
|
||||
mRows = model.getRows();
|
||||
mCellSize = cellSize;
|
||||
|
||||
// Default colors
|
||||
setForeground(Color.black);
|
||||
setBackground(Color.white);
|
||||
setOutline(Color.lightGray);
|
||||
|
||||
setSize(mCellSize * mCols, mCellSize * mRows);
|
||||
setPreferredSize(new Dimension(mCellSize * mCols, mCellSize * mRows));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cell outline color.
|
||||
*
|
||||
* @param c The color to use when drawing the cell outlines.
|
||||
*/
|
||||
public void setOutline(Color c) {
|
||||
mOutlineColor = c;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the panel whether to draw cell outlines or not.
|
||||
*
|
||||
* @param b True to show outlines, false otherwise.
|
||||
*/
|
||||
public void showCellOutlines(boolean b) {
|
||||
this.mShowCellOutlines = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to remove the default update() behavior,
|
||||
* which clears the component on each paint call.
|
||||
*/
|
||||
public void update(Graphics g) {
|
||||
return; // do nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of the Observer interface.
|
||||
*/
|
||||
public void update(Observable t, Object o) {
|
||||
repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a lighter version of this color. Not to be confused
|
||||
* with the Color.brighen() method! This method will return a
|
||||
* color with a higher alpha value based on the percent parameter.
|
||||
*/
|
||||
private Color lightenColor(Color c, int age) {
|
||||
int red = c.getRed();
|
||||
int green = c.getGreen();
|
||||
int blue = c.getBlue();
|
||||
int alpha = c.getAlpha();
|
||||
|
||||
double p = 1.0 - (0.05 * age);
|
||||
|
||||
if (p > 0.20) {
|
||||
alpha = (int)(p * alpha);
|
||||
} else {
|
||||
alpha = (int)(0.20 * alpha);
|
||||
}
|
||||
|
||||
return new Color(red, green, blue, alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the cell field.
|
||||
*/
|
||||
public void paint(Graphics g) {
|
||||
Graphics2D g2d = (Graphics2D) g;
|
||||
|
||||
int width = getSize().width;
|
||||
int height = getSize().height;
|
||||
|
||||
// Clear the panel.
|
||||
g2d.setPaint(getBackground());
|
||||
g2d.fill(new Rectangle(0, 0, width, height));
|
||||
|
||||
g2d.setPaint(getForeground());
|
||||
for (int i = 0; i < mCols; i++) {
|
||||
for (int j = 0; j < mRows; j++) {
|
||||
if (mCellModel.getCell(i, j)) {
|
||||
// If cell aging is enabled, draw aged cells
|
||||
int age = 0;
|
||||
if (mShowAging) {
|
||||
age = mCellModel.getCellAge(i, j);
|
||||
g2d.setPaint(lightenColor(getForeground(), age));
|
||||
}
|
||||
g2d.fillRect(i * mCellSize,
|
||||
j * mCellSize,
|
||||
mCellSize,
|
||||
mCellSize);
|
||||
if (mShowAging) {
|
||||
g2d.setPaint(getForeground());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show outlines if desired
|
||||
if (mShowCellOutlines) {
|
||||
drawCellOutlines(g2d);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the color used to draw the cell outlines.
|
||||
*
|
||||
* @return The color used to draw the cell outlines.
|
||||
*/
|
||||
public Color getOutline() {
|
||||
return mOutlineColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the display of cell "aging"
|
||||
*/
|
||||
public void setCellAging(boolean b) {
|
||||
mShowAging = b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a grid showing the outlines of the cells.
|
||||
*/
|
||||
private void drawCellOutlines(Graphics2D g2d) {
|
||||
g2d.setPaint(mOutlineColor);
|
||||
g2d.setStroke(new BasicStroke(1.0f));
|
||||
|
||||
int width = getSize().width;
|
||||
int height = getSize().height;
|
||||
|
||||
// Draw rectangle outlining the entire component
|
||||
g2d.draw(new Rectangle(0, 0, width - 1, height - 1));
|
||||
|
||||
// Draw the vertical lines
|
||||
for (int i = 0; i < mCols; i++) {
|
||||
g2d.drawLine(i * mCellSize, 0, i * mCellSize, height);
|
||||
}
|
||||
|
||||
// Draw the horizontal lines
|
||||
for (int j = 0; j < mRows; j++) {
|
||||
g2d.drawLine(0, j * mCellSize, width, j * mCellSize);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
/**
|
||||
* A subclass of RuleSet which adds probability to the rules.
|
||||
*
|
||||
* Why? Because.
|
||||
*
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: ChanceRuleSet.java,v 1.5 2003/07/09 23:32:49 sethm Exp $
|
||||
*/
|
||||
public class ChanceRuleSet extends RuleSet {
|
||||
|
||||
private double mBp; // "Birth" probability
|
||||
private double mSp; // "Survival" probability
|
||||
|
||||
/**
|
||||
*
|
||||
* @param name The displayable name of this rule
|
||||
* @param born Array of neighbors required for an empty cell to
|
||||
* come to life.
|
||||
* @param survive Array neighbors required for a living cell to
|
||||
* survive.
|
||||
* @param bp The probability, between 0.0 and 100.0, that new cell
|
||||
* birth will succeed.
|
||||
* @param sp The probability, between 0.0 and 100.0, that cell
|
||||
* survival will succeed.
|
||||
*/
|
||||
public ChanceRuleSet(String name, int[] born, int[] survive,
|
||||
double bp, double sp)
|
||||
{
|
||||
super(name, born, survive);
|
||||
mBp = bp;
|
||||
mSp = sp;
|
||||
}
|
||||
|
||||
|
||||
public ChanceRuleSet(int[] born, int[] survive,
|
||||
double bp, double sp)
|
||||
{
|
||||
super(null, born, survive);
|
||||
mBp = bp;
|
||||
mSp = sp;
|
||||
}
|
||||
|
||||
public void transform(boolean[][] from, boolean[][] to) {
|
||||
if (from == null || to == null) { return; }
|
||||
|
||||
int cols = Utilities.getWidth(to);
|
||||
int rows = Utilities.getHeight(to);
|
||||
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
|
||||
// Compute a value between 0.0 and 100.0
|
||||
double chance = Math.random() * 100.0;
|
||||
|
||||
int count = Utilities.getNeighborCount(from, i, j);
|
||||
boolean val = false;
|
||||
|
||||
if (!from[i][j]) {
|
||||
// "Born" rules
|
||||
for (int k = 0; k < mBornOn.length; k++) {
|
||||
val |= (count == mBornOn[k] && chance <= mBp);
|
||||
}
|
||||
} else {
|
||||
// "Survive" rules
|
||||
for (int k = 0; k < mSurviveOn.length; k++) {
|
||||
val |= (count == mSurviveOn[k] && chance <= mSp);
|
||||
}
|
||||
}
|
||||
|
||||
to[i][j] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,201 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.*;
|
||||
|
||||
/**
|
||||
* Color chooser dialog. This dialog allows the user to set colors for the
|
||||
* cells, background, and outlines.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: ColorChooserDialog.java,v 1.6 2003/08/23 21:09:15 sethm Exp $
|
||||
*/
|
||||
public class ColorChooserDialog extends JDialog {
|
||||
private CellPanel mCellPanel;
|
||||
private JColorChooser mColorChooser;
|
||||
private JComboBox mElementBox;
|
||||
|
||||
// The cell panel we actually update.
|
||||
private CellPanel mPreviewCells;
|
||||
|
||||
private Color mCellColor;
|
||||
private Color mBackgroundColor;
|
||||
private Color mOutlineColor;
|
||||
|
||||
boolean mSetCellColor;
|
||||
boolean mSetBackgroundColor;
|
||||
boolean mSetOutlineColor;
|
||||
|
||||
private static final String CELLS_STRING = "Cells";
|
||||
private static final String BG_STRING = "Background";
|
||||
private static final String OUTLINE_STRING = "Outline";
|
||||
|
||||
/**
|
||||
* Construct a color chooser dialog.
|
||||
*
|
||||
* @param p The cell panel to set colors for.
|
||||
*/
|
||||
public ColorChooserDialog(CellPanel p) {
|
||||
mCellPanel = p;
|
||||
|
||||
JPanel bannerPanel = new JPanel();
|
||||
bannerPanel.setLayout(new FlowLayout());
|
||||
bannerPanel.setBorder(BorderFactory.
|
||||
createTitledBorder("Set color for"));
|
||||
|
||||
mElementBox = new JComboBox();
|
||||
mElementBox.addItem(CELLS_STRING);
|
||||
mElementBox.addItem(BG_STRING);
|
||||
mElementBox.addItem(OUTLINE_STRING);
|
||||
|
||||
mElementBox.addItemListener(new SelectElementListener());
|
||||
|
||||
bannerPanel.add(mElementBox);
|
||||
|
||||
mColorChooser = new JColorChooser();
|
||||
|
||||
// Set the preview panel.
|
||||
// Cheat! Since we already have this component handy, make a
|
||||
// small 3x3 one with 20px cells as our preview panel.
|
||||
JPanel previewPanel = new JPanel();
|
||||
|
||||
previewPanel.setLayout(new FlowLayout());
|
||||
|
||||
CellModel model = new CellModel(3,3);
|
||||
mPreviewCells = new CellPanel(model, 20);
|
||||
model.flipCell(1, 1);
|
||||
|
||||
previewPanel.add(mPreviewCells);
|
||||
|
||||
// Some VMs seem to require an explicit size setting here in
|
||||
// order for the preview panel component to be displayed
|
||||
// properly.
|
||||
previewPanel.setSize(mPreviewCells.getSize());
|
||||
previewPanel.setBorder(BorderFactory.createEmptyBorder(0,0,1,0));
|
||||
|
||||
mColorChooser.setPreviewPanel(previewPanel);
|
||||
|
||||
mColorChooser.getSelectionModel().addChangeListener(
|
||||
new PreviewListener());
|
||||
|
||||
// Dialog OK/Cancel buttons
|
||||
JPanel buttonBar = new JPanel();
|
||||
buttonBar.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
|
||||
JButton okButton = new JButton("OK");
|
||||
JButton cancelButton = new JButton("Cancel");
|
||||
|
||||
okButton.addActionListener(new SetColorListener());
|
||||
|
||||
cancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
|
||||
buttonBar.add(okButton);
|
||||
buttonBar.add(cancelButton);
|
||||
|
||||
getContentPane().add(bannerPanel, BorderLayout.NORTH);
|
||||
getContentPane().add(mColorChooser, BorderLayout.CENTER);
|
||||
getContentPane().add(buttonBar, BorderLayout.SOUTH);
|
||||
|
||||
pack();
|
||||
setResizable(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Target a new cell panel.
|
||||
*/
|
||||
public void setCellPanel(CellPanel p) {
|
||||
mCellPanel = p;
|
||||
p.setForeground(mCellColor);
|
||||
p.setBackground(mBackgroundColor);
|
||||
p.setOutline(mOutlineColor);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the new colors to the CellPanel we're updating, then hide.
|
||||
*/
|
||||
final private class SetColorListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (mSetCellColor) {
|
||||
mCellPanel.setForeground(mCellColor);
|
||||
}
|
||||
if (mSetBackgroundColor) {
|
||||
mCellPanel.setBackground(mBackgroundColor);
|
||||
}
|
||||
if (mSetOutlineColor) {
|
||||
mCellPanel.setOutline(mOutlineColor);
|
||||
}
|
||||
mCellPanel.repaint();
|
||||
// Hide, but stick around.
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user selects a new element to change the color for,
|
||||
* update the color chooser's model to reflect the color that's
|
||||
* already there.
|
||||
*/
|
||||
final private class SelectElementListener implements ItemListener {
|
||||
public void itemStateChanged(ItemEvent evt) {
|
||||
if (mElementBox.getSelectedItem().equals(CELLS_STRING)) {
|
||||
mColorChooser.setColor(mPreviewCells.getForeground());
|
||||
} else if (mElementBox.getSelectedItem().equals(BG_STRING)) {
|
||||
mColorChooser.setColor(mPreviewCells.getBackground());
|
||||
} else if (mElementBox.getSelectedItem().equals(OUTLINE_STRING)) {
|
||||
mColorChooser.setColor(mPreviewCells.getOutline());
|
||||
}
|
||||
|
||||
mPreviewCells.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user selects a new color, update the preview panel
|
||||
* and instance colors appropriately.
|
||||
*/
|
||||
final private class PreviewListener implements ChangeListener {
|
||||
public void stateChanged(ChangeEvent evt) {
|
||||
if (mElementBox.getSelectedItem().equals(CELLS_STRING)) {
|
||||
mCellColor = mColorChooser.getColor();
|
||||
mSetCellColor = true;
|
||||
mPreviewCells.setForeground(mCellColor);
|
||||
} else if (mElementBox.getSelectedItem().equals(BG_STRING)) {
|
||||
mBackgroundColor = mColorChooser.getColor();
|
||||
mSetBackgroundColor = true;
|
||||
mPreviewCells.setBackground(mBackgroundColor);
|
||||
} else if (mElementBox.getSelectedItem().equals(OUTLINE_STRING)) {
|
||||
mOutlineColor = mColorChooser.getColor();
|
||||
mSetOutlineColor = true;
|
||||
mPreviewCells.setOutline(mOutlineColor);
|
||||
}
|
||||
|
||||
mPreviewCells.repaint();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* Application setup and launch dialog.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: Launcher.java,v 1.7 2003/10/13 04:00:24 sethm Exp $
|
||||
*/
|
||||
public class Launcher extends JFrame {
|
||||
|
||||
// Cell panel size, and default values
|
||||
private int mCellSize = 10; // Size of cells in pixels
|
||||
private int mRows = 64; // Rows
|
||||
private int mCols = 64; // Columns
|
||||
|
||||
private AutomataFrame mAutomataFrame; // Main window.
|
||||
|
||||
private Dimension mScreenSize;
|
||||
|
||||
// Containers
|
||||
private JPanel mIntroPanel;
|
||||
private JPanel mInputPanel;
|
||||
private JPanel mButtonPanel;
|
||||
|
||||
// Input
|
||||
private JTextField mColsField;
|
||||
private JTextField mRowsField;
|
||||
private JTextField mCellSizeField;
|
||||
|
||||
// Labels
|
||||
private JLabel mIntroLabel;
|
||||
private JLabel mColsLabel;
|
||||
private JLabel mRowsLabel;
|
||||
private JLabel mCellSizeLabel;
|
||||
private JLabel mPixelLabel;
|
||||
|
||||
// Buttons
|
||||
private JButton mOKButton;
|
||||
private JButton mCancelButton;
|
||||
|
||||
// Static reference to ourself
|
||||
private static Launcher mLauncher;
|
||||
|
||||
private static final String FRAME_TITLE = "Setup";
|
||||
|
||||
/**
|
||||
* Construct a default application launcher.
|
||||
*/
|
||||
public Launcher() {
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setupUI();
|
||||
pack();
|
||||
setResizable(false);
|
||||
Utilities.centerWindow(this);
|
||||
}
|
||||
|
||||
public static Launcher getLauncher() {
|
||||
if (mLauncher == null) {
|
||||
mLauncher = new Launcher();
|
||||
}
|
||||
|
||||
return mLauncher;
|
||||
}
|
||||
/**
|
||||
* Lay out the visual look.
|
||||
*/
|
||||
private void setupUI() {
|
||||
setTitle(FRAME_TITLE);
|
||||
|
||||
// Set the system look and feel
|
||||
try {
|
||||
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
|
||||
} catch (Exception e) {
|
||||
; // Swallow this exception, because there's really no other
|
||||
// useful action to take here.
|
||||
}
|
||||
|
||||
mScreenSize = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
|
||||
mIntroPanel = new JPanel();
|
||||
mInputPanel = new JPanel();
|
||||
mButtonPanel = new JPanel();
|
||||
|
||||
mButtonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
|
||||
|
||||
Font largeFont = new Font("SansSerif", Font.BOLD, 16);
|
||||
Font smallFont = new Font("SansSerif", Font.PLAIN, 10);
|
||||
|
||||
mIntroLabel = new JLabel("Create a New Cellular Automata");
|
||||
mIntroLabel.setFont(largeFont);
|
||||
|
||||
mIntroPanel.add(mIntroLabel);
|
||||
|
||||
mCellSizeLabel = new JLabel("Cell size");
|
||||
mPixelLabel = new JLabel("(in pixels)");
|
||||
mPixelLabel.setFont(smallFont);
|
||||
|
||||
mColsLabel = new JLabel("Columns");
|
||||
mRowsLabel = new JLabel("Rows");
|
||||
|
||||
mColsField = new JTextField(Integer.toString(mCols));
|
||||
mRowsField = new JTextField(Integer.toString(mRows));
|
||||
mCellSizeField = new JTextField(Integer.toString(mCellSize));
|
||||
|
||||
mOKButton = new JButton("OK");
|
||||
mOKButton.addActionListener(new CreateCellPanelListener());
|
||||
|
||||
mCancelButton = new JButton("Cancel");
|
||||
mCancelButton.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
mColsField.setColumns(4);
|
||||
mRowsField.setColumns(4);
|
||||
mCellSizeField.setColumns(2);
|
||||
|
||||
GridBagLayout gb = new GridBagLayout();
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
|
||||
c.insets = new Insets(5,5,5,5);
|
||||
|
||||
mInputPanel.setLayout(gb);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 0;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 1;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
gb.setConstraints(mColsLabel, c);
|
||||
mInputPanel.add(mColsLabel);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 0;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 2;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
gb.setConstraints(mColsField, c);
|
||||
mInputPanel.add(mColsField);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 1;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 1;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
gb.setConstraints(mRowsLabel, c);
|
||||
mInputPanel.add(mRowsLabel);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 1;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 2;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
gb.setConstraints(mRowsField, c);
|
||||
mInputPanel.add(mRowsField);
|
||||
|
||||
c.gridx = 0;
|
||||
c.gridy = 2;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 1;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.EAST;
|
||||
gb.setConstraints(mCellSizeLabel, c);
|
||||
mInputPanel.add(mCellSizeLabel);
|
||||
|
||||
c.gridx = 1;
|
||||
c.gridy = 2;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 1;
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
gb.setConstraints(mCellSizeField, c);
|
||||
mInputPanel.add(mCellSizeField);
|
||||
|
||||
c.gridx = 2;
|
||||
c.gridy = 2;
|
||||
c.weightx = 0.0;
|
||||
c.gridwidth = 1;
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.anchor = GridBagConstraints.WEST;
|
||||
gb.setConstraints(mPixelLabel, c);
|
||||
mInputPanel.add(mPixelLabel);
|
||||
|
||||
mButtonPanel.add(mOKButton);
|
||||
mButtonPanel.add(mCancelButton);
|
||||
|
||||
getContentPane().add(mIntroPanel, BorderLayout.NORTH);
|
||||
getContentPane().add(mInputPanel, BorderLayout.CENTER);
|
||||
getContentPane().add(mButtonPanel, BorderLayout.SOUTH);
|
||||
}
|
||||
|
||||
private int getCols() {
|
||||
try {
|
||||
return Integer.parseInt(mColsField.getText());
|
||||
} catch (NumberFormatException ex) {
|
||||
return mCols;
|
||||
}
|
||||
}
|
||||
|
||||
private int getRows() {
|
||||
try {
|
||||
return Integer.parseInt(mRowsField.getText());
|
||||
} catch (NumberFormatException ex) {
|
||||
return mRows;
|
||||
}
|
||||
}
|
||||
|
||||
private int getCellSize() {
|
||||
try {
|
||||
return Integer.parseInt(mCellSizeField.getText());
|
||||
} catch (NumberFormatException ex) {
|
||||
return mCellSize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main application entry point.
|
||||
*
|
||||
* @param args Application arguments (not used).
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
Launcher launcher = Launcher.getLauncher();
|
||||
launcher.setVisible(true);
|
||||
}
|
||||
|
||||
private final class CreateCellPanelListener implements ActionListener {
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
int cols = getCols();
|
||||
int rows = getRows();
|
||||
int cellSize = getCellSize();
|
||||
|
||||
if (cellSize < 0 || cols < 0 || rows < 0) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"Please use positive numbers.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (cellSize * cols > mScreenSize.width ||
|
||||
cellSize * rows > mScreenSize.height) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
"The values you've chosen would create\n" +
|
||||
"a window too large to fit on the screen.\n" +
|
||||
"Please choose smaller values.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (mAutomataFrame == null) {
|
||||
mAutomataFrame = new AutomataFrame();
|
||||
}
|
||||
|
||||
mAutomataFrame.addCells(cols, rows, cellSize);
|
||||
|
||||
mAutomataFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
mAutomataFrame.pack();
|
||||
mAutomataFrame.setResizable(false);
|
||||
Utilities.centerWindow(mAutomataFrame);
|
||||
mAutomataFrame.setVisible(true);
|
||||
|
||||
// hide ourselves
|
||||
setVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
/**
|
||||
* Define a set of rules which transform one 2D array into
|
||||
* another.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: RuleSet.java,v 1.8 2003/10/13 04:00:24 sethm Exp $
|
||||
*/
|
||||
public class RuleSet {
|
||||
final int[] mBornOn;
|
||||
final int[] mSurviveOn;
|
||||
String mName;
|
||||
String mShortName;
|
||||
|
||||
/**
|
||||
* Create a new ruleset with a nickname.
|
||||
*
|
||||
* @param name The displayable name of this rule, i.e. "Life"
|
||||
* @param born Array of neighbors required for an empty cell to
|
||||
* come to life.
|
||||
* @param survive Array of neighbors required for a living cell to
|
||||
* survive.
|
||||
*/
|
||||
public RuleSet(String name, int[] born, int[] survive) {
|
||||
mBornOn = born;
|
||||
mSurviveOn = survive;
|
||||
mShortName = name;
|
||||
|
||||
makeDisplayableName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new un-named ruleset.
|
||||
*
|
||||
* @param born Array of neighbors required for an empty cell to
|
||||
* come to life.
|
||||
* @param survive Array of neighbors required for a living cell to
|
||||
* survive.
|
||||
*/
|
||||
public RuleSet(int[] born, int[] survive) {
|
||||
this(null, born, survive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform from one generation of cells to the next.
|
||||
*/
|
||||
public void transform(boolean[][] from, boolean[][] to) {
|
||||
if (from == null || to == null) { return; }
|
||||
|
||||
int cols = Utilities.getWidth(to);
|
||||
int rows = Utilities.getHeight(to);
|
||||
|
||||
for (int i = 0; i < cols; i++) {
|
||||
for (int j = 0; j < rows; j++) {
|
||||
|
||||
int count = Utilities.getNeighborCount(from, i, j);
|
||||
boolean val = false;
|
||||
|
||||
if (!from[i][j]) {
|
||||
// "Born" rules
|
||||
for (int k = 0; k < mBornOn.length; k++) {
|
||||
val |= (count == mBornOn[k]);
|
||||
}
|
||||
} else {
|
||||
// "Survive" rules
|
||||
for (int k = 0; k < mSurviveOn.length; k++) {
|
||||
val |= (count == mSurviveOn[k]);
|
||||
}
|
||||
}
|
||||
|
||||
to[i][j] = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the name of this ruleset.
|
||||
*
|
||||
* @return The displayable name of this ruleset.
|
||||
*/
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the short name of this ruleset.
|
||||
*
|
||||
* @return The displayable name of this ruleset.
|
||||
*/
|
||||
public String getShortName() {
|
||||
return mShortName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Munge the parameter string into a fancy displayable name.
|
||||
*/
|
||||
void makeDisplayableName(String s) {
|
||||
StringBuffer buf = new StringBuffer();
|
||||
|
||||
if (s != null) {
|
||||
buf.append(s);
|
||||
buf.append(" (");
|
||||
}
|
||||
|
||||
buf.append("B");
|
||||
for (int i = 0; i < mBornOn.length; i++) {
|
||||
buf.append(Integer.toString(mBornOn[i]));
|
||||
}
|
||||
buf.append("/S");
|
||||
for (int i = 0; i < mSurviveOn.length; i++) {
|
||||
buf.append(Integer.toString(mSurviveOn[i]));
|
||||
}
|
||||
if (s != null) {
|
||||
buf.append(")");
|
||||
}
|
||||
|
||||
mName = buf.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
/**
|
||||
* Thread which updates the cell model.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: UpdateThread.java,v 1.5 2003/10/04 01:23:14 sethm Exp $
|
||||
*/
|
||||
public class UpdateThread extends Thread {
|
||||
CellModel mCellModel;
|
||||
int mSleepInterval;
|
||||
boolean mStop = false;
|
||||
boolean mPause = true;
|
||||
|
||||
public UpdateThread(CellModel m) {
|
||||
mCellModel = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the delay between each cell data update.
|
||||
*
|
||||
* @param i The delay, in milliseconds.
|
||||
*/
|
||||
public void setSleepInterval(int i) {
|
||||
mSleepInterval = i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the cell model, then wait for a specified time and loop.
|
||||
*/
|
||||
public void run() {
|
||||
while (!mStop) {
|
||||
while (mPause) {
|
||||
try {
|
||||
synchronized(this) {
|
||||
wait();
|
||||
mPause = false;
|
||||
}
|
||||
} catch (InterruptedException ex) {
|
||||
System.out.println(ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Update the cell generation one step.
|
||||
mCellModel.transform();
|
||||
|
||||
try {
|
||||
Thread.sleep(mSleepInterval);
|
||||
} catch (InterruptedException ex) {
|
||||
System.out.println(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start updating the cell data if the thread is currently paused.
|
||||
*/
|
||||
public synchronized void go() {
|
||||
this.notifyAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* Pause the thread. The thread can be started again using
|
||||
* the <tt>go()</tt> method.
|
||||
*
|
||||
*/
|
||||
public void pause() {
|
||||
mPause = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the thread. The thread cannot be started again once
|
||||
* it has been stopped.
|
||||
*/
|
||||
public void doStop() {
|
||||
mStop = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true of the thread is paused (not updating the model).
|
||||
*
|
||||
* @return true if the thread is not currently updating
|
||||
* the cell data (i.e., in a wait state)
|
||||
*/
|
||||
public boolean isPaused() {
|
||||
return mPause;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Automata, a Cellular Automata explorer.
|
||||
*
|
||||
* Copyright (c) 2003, Seth J. Morabito <sethm@loomcom.com> All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
* Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
package com.loomcom.automata;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
/**
|
||||
* A few useful static utilities.
|
||||
*
|
||||
* @author Seth Morabito
|
||||
* @version $Id: Utilities.java,v 1.4 2003/07/09 23:20:11 sethm Exp $
|
||||
*/
|
||||
public class Utilities {
|
||||
|
||||
/**
|
||||
* Center a window on screen.
|
||||
*
|
||||
* @param w The window to center.
|
||||
*/
|
||||
public static void centerWindow(Window w) {
|
||||
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
|
||||
int width = w.getWidth();
|
||||
int height = w.getHeight();
|
||||
|
||||
w.setLocation(d.width/2 - width/2, d.height/2 - height/2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the number of living neighbor cells for a point in a 2D
|
||||
* array.
|
||||
*
|
||||
* This version unrolls the loop and implements "wrap-around",
|
||||
* eliminating edge effects. The code is longer and messier, but because
|
||||
* of unrolling the loop, we actually see about a 2x execution time
|
||||
* reduction.
|
||||
*
|
||||
* @param cells The array to look in.
|
||||
* @param x The cell's x coordinate.
|
||||
* @param y The cell's y coordinate.
|
||||
*/
|
||||
public static int getNeighborCount(boolean[][] cells, int x, int y) {
|
||||
int neighborCount = 0;
|
||||
|
||||
int cols = cells.length;
|
||||
int rows = cells[0].length;
|
||||
|
||||
int x_right = x < cols-1 ? x+1 : 0;
|
||||
int x_left = x > 0 ? x-1 : cols-1;
|
||||
int y_top = y > 0 ? y-1 : rows-1;
|
||||
int y_bottom = y < rows-1 ? y+1 : 0;
|
||||
|
||||
if (cells[x_left][y_top]) neighborCount++;
|
||||
if (cells[x_left][y]) neighborCount++;
|
||||
if (cells[x_left][y_bottom]) neighborCount++;
|
||||
if (cells[x][y_top]) neighborCount++;
|
||||
if (cells[x][y_bottom]) neighborCount++;
|
||||
if (cells[x_right][y_top]) neighborCount++;
|
||||
if (cells[x_right][y]) neighborCount++;
|
||||
if (cells[x_right][y_bottom]) neighborCount++;
|
||||
return neighborCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely return the "width" of a 2D array.
|
||||
*/
|
||||
public static int getWidth(boolean[][] array) {
|
||||
return array.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely return the "height" of a 2D array.
|
||||
*/
|
||||
public static int getHeight(boolean[][] array) {
|
||||
if (array.length > 0) {
|
||||
return array[0].length;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue