package org.ais_sanmarino.ludoj.robotoj; import java.awt.*; import java.awt.event.KeyListener; import java.awt.event.WindowListener; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowEvent; import java.awt.event.ActionEvent; import java.applet.Applet; /** *
* Tiu cxi klaso realigas malnovan ekran-ludon, * kiu ekzistis jam en fruaj UNIX-generacioj. * Gxi tie nomigxis robots kaj estis ludebla sur * negrafikaj ekranoj. * Ekzistas ankaux grafika versio nomata xrobots. *
** La ludanto povas movi ludpecon (la "fugxanton") en la * ok ekran-direktoj, cxiam al najbara kampo. * Li povas ankaux "transporti" gxin al hazarde elektita kampo. * La celo de la ludo estas eviti malicajn robotojn, * kiuj volas kapti kaj mortigi la fugxanton. * Ili movigxas cxiam direkte al la fugxanto, * kaj kiam ili kolizias kun gxi aux kun alia roboto, * ili eksplodas. *
** La sxanco de la ludanto estas direkti robotojn al aliaj robotoj, * ankaux al jam eksplodintaj. * Se li sukcesas detrui cxiujn robotoj, li gajnas, * sed ankoraux ne havas poentojn. * Por akiri tiajn li devas kuragxi "atenti", * t. e. iumomente rezigni je sia eblo movi la fugxanton * kaj simple lasi la robotoj kuri (espereble al sindetruo). * Por cxiu roboto ekzistanta en tiu momento de la decido atendi * li ricevas unu poenton. * Poentoj akumuligxas, sed cxe morto oni (kompreneble) perdas * cxiujn poentojn. *
*
* Pro sia UNIX-deveno la ludo uzas la manovrajn klavojn de
* vi.
* Por movi la fugxanton en la ok direktojn eblas uzi jenajn klavojn:
*
* y k u * h . l * b j n **
* La punkto (.) kauxzas unuciklan atendon.
* Majuskloj ripetigas movon tiom longe, kiom eblas (sen kolizii kun io aux io).
* Por uzantoj de Germanaj klavaroj la klavo z efikas egale
* al y
* (kiu en Usonaj klavaroj situas tie,
* kie en Germanaj situas la z).
*
* Krome eblas jenaj komandoj: *
* Havu plezuron ludante! *
* * @author Reinhard Fössmeier * @version 1.0 (2001-11-25) */ public class Robotoj extends Applet implements WindowListener { /** * interfaco por klasoj, kiuj ricevas komandojn. */ interface Komandato { /** plenumu donitan komandon. */ void plenumu( int komando ); } /** * interfaco por klasoj, kiuj povas raporti al la uzanto detalojn * pri la ludo. */ interface Mesagxisto { /** montru donitan mesagxon. */ void mesagxu( String t ); /** montru akiritajn poentojn. */ void montruPoentojn( int po ); /** montru la maksimumon de (iam) akiritaj poentoj. */ void montruMaksimumajnPoentojn( int mpo ); } /** rezervenda alteco por la butonaro */ private final int butonAlteco = 35; /** * La ludkampo. * Temas -- pro historiaj kauxzoj -- pri kampo de 80 oble 24 kampetoj * inter kiuj movigxas la lud-pecoj. */ protected Kampo kampo = new Kampo(); /** * La programo ekrulas en memstara fenestro. */ public static void main( String par[] ) { Frame kadro = new Frame(); Robotoj rob = new Robotoj(); Butonaro bu = rob.new Butonaro( rob.kampo, true ); kadro.setSize( 500, 300 ); kadro.setLayout( new BorderLayout() ); kadro.add( rob.kampo, BorderLayout.CENTER ); kadro.add( bu, BorderLayout.NORTH ); kadro.addWindowListener( rob ); bu.addKeyListener( rob.kampo ); rob.kampo. metuMesagxiston( bu ); kadro.setVisible( true ); /* 1.0: show(); */ rob.kampo.requestFocus(); } /** * La programeto (apleto) ekrulas. * Videbligu la fenestron kaj ekludigu! */ public void init() { Butonaro bu = new Butonaro( kampo, false ); setLayout( new BorderLayout() ); add( kampo, BorderLayout.CENTER ); add( bu, BorderLayout.NORTH ); bu.addKeyListener( kampo ); kampo. metuMesagxiston( bu ); setVisible( true ); /* 1.0: show(); */ Dimension gr = getSize(); gr.height -= butonAlteco; kampo.setSize( gr ); } /** * Pentru la lud-kampon (kradon). */ public void paint( Graphics g ) { kampo.paint( g ); kampo.requestFocus(); } public void windowOpened( WindowEvent e ) { } public void windowClosing( WindowEvent e ) { e.getWindow().setVisible( false ); System.exit( 0 ); } /** * Fermigxas la fenestro, finu la programon. */ public void windowClosed( WindowEvent e ) { System.exit( 0 ); } public void windowIconified( WindowEvent e ) { } public void windowDeiconified( WindowEvent e ) { } public void windowActivated( WindowEvent e ) { } public void windowDeactivated( WindowEvent e ) { } /** * tiu cxi klaso provizas la ludkampon, * sur kiu movigxas la lud-pecoj. */ class Kampo extends Canvas implements KeyListener, Komandato { /** * ripet-faktoro, kiu simbolu "nefinion"; * sur nia kampo por tio suficxas eta nombro. */ private final int NEFINIE_DA_FOJOJ = 1025; /** la grandeco de la kampo en bilderoj */ Dimension c; /** la longeco de la kampo en kamperoj */ final int nx = 80; /** la largxeco de la kampo en kamperoj */ final int ny = 24; /** konstanto, kiu simbolas la senmovan atendadon de la fugxanto */ final int ATENDU = KeyEvent.VK_W; /** multobligilo por komandoj */ int oblo = 0; /** cxu la ludanto gajnis? */ private boolean gajnis = false; /** cxu la ludanto malgajnis? */ private boolean malgajnis = false; /** la nombro de la malicaj robotoj */ private final int nrob = 15; /** la robotoj */ protected Roboto rob[] = new Roboto[ nrob ]; /** la ludanto */ protected Fugxanto fugx = null; /** la (akumulitaj) poentoj en la aktuala ludo */ protected int poentoj = 0; /** la gxis nun maksimumaj poentoj */ protected int maksimumajPoentoj = 0; /** la nombro de la robotoj ekzistantaj cxe decido "atendi" */ protected int atendatajRobotoj = 0; /** por vidigi mesagxon */ protected Mesagxisto mesagxisto = null; Kampo() { addKeyListener( this ); valorizu(); } /** * Registru mesagxiston por raporti al la ludanto. * antauxe registritaj mesagixstoj estas forgesitaj. * param m la nova mesagxisto */ void metuMesagxiston( Mesagxisto m ) { mesagxisto = m; } /** * Donu komencajn valorojn al la variabloj. * Hazarde loku la fugxanton * kaj aron da robotoj. * Tamen zorgu, ke la fugxanto ne tuj mortu. */ private void valorizu() { gajnis = false; malgajnis = false; oblo = 0; atendatajRobotoj = 0; for( int nr = 0; nr < nrob; nr++ ) { int x = (int) ( java.lang.Math.random() * nx ); int y = (int) ( java.lang.Math.random() * ny ); rob[ nr ] = new Roboto( x, y ); } fugx = null; while( fugx == null ) { int x = (int) ( java.lang.Math.random() * nx ); int y = (int) ( java.lang.Math.random() * ny ); fugx = new Fugxanto( x, y ); for( int nr = 0; nr < nrob; nr++ ) { if( rob[ nr ].ricevuPozicion().x == x && rob[ nr ].ricevuPozicion().y == y ) { fugx = null; } } } System.gc(); if( mesagxisto != null ) { mesagxisto.mesagxu( "" ); mesagxisto.montruPoentojn( poentoj ); mesagxisto.montruMaksimumajnPoentojn( maksimumajPoentoj ); } requestFocus(); } /** * Pentru la lud-kampon (kradon). */ public void paint( Graphics g ) { if( c == null ) { c = getSize(); } g.setColor( gajnis ? Color.green : malgajnis ? Color.red : Color.black ); for( int ix= 0; ix <= nx; ix++ ) { int x = ix * c.width / nx; g.drawLine( x, 0, x, c.height-1 ); } for( int iy= 0; iy <= ny; iy++ ) { int y = iy * c.height / ny; g.drawLine( 0, y, c.width-1, y ); } for( int nr = 0; nr < rob.length; nr++ ) { rob[nr].pentru( g ); } fugx.pentru( g ); // requestFocus(); } /** * kontrolu, cxu eblas movi la fugxanton al donita kampo */ boolean cxuEblasMovoAl( Point p ) { if( p.x < 0 || p.x >= nx || p.y < 0 || p.y >= ny ) { return false; } for( int nr = 0; nr < rob.length; nr++ ) { if( p.equals( rob[ nr ].ricevuPozicion() ) ) { return false; } } return true; } /** * movu cxiujn pecojn * @param signo la signo, kiu donas la direkton de la movo * @returns cxu eblis la dezirata movo */ boolean faruMovon( int signo ) { if( gajnis || malgajnis ) { return false; } boolean sukceso = true; if( signo != ATENDU && ! (sukceso = fugx.movigxuJe( signo )) ) { return sukceso; // == false } Point pf = fugx.ricevuPozicion(); // movu la robotojn cele al la fugxanto: for( int nr = 0; nr < rob.length; nr++ ) { if( ! rob[ nr ].detruita() ) { rob[nr].movigxuCeleAl( pf ); } } // kontrolu, cxu roboto koliziis kontraux io: for( int nr = 0; nr < rob.length; nr++ ) { for( int nr2 = nr+1; nr2 < rob.length; nr2++ ) { if( rob[ nr ].ricevuPozicion().equals( rob[ nr2 ].ricevuPozicion() ) ) { rob[ nr ] .detruu(); rob[ nr2 ] .detruu(); } } } for( int nr = 0; nr < rob.length; nr++ ) { if( rob[ nr ].ricevuPozicion().equals( fugx.ricevuPozicion())) { malgajnis = true; poentoj = 0; fugx.mortu(); rob[ nr ] .detruu(); System.out.println( "vi malgajnis." ); if( mesagxisto != null ) { mesagxisto.mesagxu( "vi malgajnis." ); mesagxisto.montruPoentojn( poentoj ); } } } int nRestantajRobotoj = nombruRobotojn(); if( nRestantajRobotoj == 0 ) { gajnis = true; System.out.println( "vi gajnis!" ); poentoj += atendatajRobotoj; if( poentoj > maksimumajPoentoj ) { maksimumajPoentoj = poentoj; } if( mesagxisto != null ) { mesagxisto.mesagxu( "vi gajnis!" ); mesagxisto.montruPoentojn( poentoj ); mesagxisto.montruMaksimumajnPoentojn( maksimumajPoentoj ); } } return true; } /** * @returns cxu poziciop estas dangxera,
* do cxu estas roboto najbare.
* @param p la ekzamenenda pozicio
*/
protected boolean dangxera( Point p ) {
for( int nr = 0; nr < rob.length; nr++ ) {
final Point pr = rob[ nr ].ricevuPozicion();
// ekzamenu, cxu tiu roboto estas najbara:
if( ! rob[ nr ].detruita() &&
Math.abs( pr.x - p.x ) <= 1 &&
Math.abs( pr.y - p.y ) <= 1 ) {
return true;
}
}
return false;
}
public void keyTyped( KeyEvent e ) {
}
/**
* La uzanto premis klavon.
* Lauxe movu la fuxganton
*/
public void keyPressed( KeyEvent e ) {
int komando = e.getKeyCode();
final int d = komando > KeyEvent.VK_9 ? -1 :
komando - KeyEvent.VK_0;
if( e.getKeyChar() == '.' && komando != KeyEvent.VK_PERIOD ) {
// MS IE liveras la kodon 190 por la punkto-klavo
System.err.println("KODO: " + komando + " --> " + KeyEvent.VK_PERIOD );
komando = KeyEvent.VK_PERIOD;
}
switch( komando ) {
case KeyEvent.VK_Q: // finu
case KeyEvent.VK_R: // rekomencu
plenumu( komando );
break;
case KeyEvent.VK_W: // atendu
atendatajRobotoj = nombruRobotojn();
while( ! gajnis && ! malgajnis ) {
faruMovon( ATENDU );
Graphics g = getGraphics();
update( g );
g.dispose();
System.gc();
try {
Thread.sleep( 120 );
} catch( InterruptedException esc ) {
}
}
break;
case KeyEvent.VK_T: // transportigxu
oblo = 0;
faruMovon( komando );
repaint();
break;
default:
if( d >= 0 ) {
oblo = 10*oblo + (komando - '0');
}
else {
final char c = e.getKeyChar();
if( c == 'H' ||
c == 'J' ||
c == 'K' ||
c == 'L' ||
c == 'Z' ||
c == 'Y' ||
c == 'U' ||
c == 'B' ||
c == 'N' ) {
// majuskloj irigas tiom, kiom eblas:
oblo = NEFINIE_DA_FOJOJ;
}
for( int o = 0; o == 0 || o < oblo; o++ ) {
final boolean sukceso = faruMovon( komando );
if( sukceso ) {
Graphics g = getGraphics();
update( g );
g.dispose();
try {
Thread.sleep( 120 );
} catch( InterruptedException esc ) {
}
}
else {
oblo = 0; // finu la ciklon
}
}
oblo = 0;
}
break;
}
if( d < 0 ) {
oblo = 0;
}
}
public void keyReleased( KeyEvent e ) {
}
/**
* Plenumu donitan komandon.
* Gxi povas veni de la klavaro aux de butonpremo.
* @param komando la komando
*/
public void plenumu( int komando ) {
switch( komando ) {
case KeyEvent.VK_Q:
try {
System.exit( 0 );
}
catch( Exception esc ) {
// AppletSecurityException aux io simila
}
break;
case KeyEvent.VK_R: // rekomencu
valorizu();
repaint();
break;
default:
throw( new IllegalArgumentException( "komando " + komando ) );
}
}
/**
* @return la nombron de la ekzistantaj (ne detruitaj) robotoj
*/
protected int nombruRobotojn() {
int nRestantajRobotoj = 0;
for( int nr = 0; nr < rob.length; nr++ ) {
if( ! rob[ nr ].detruita() ) {
nRestantajRobotoj++;
}
}
return nRestantajRobotoj;
}
}
/**
* Tiu cxi klaso reprezentas ludpecon.
* De gxi derivigxas
* Fugxanto
* kaj
* Roboto.
*/
abstract class Ulo {
/** la pozicio de la ludpeco */
Point poz;
/**
* Metu novan ludpecon al la donita pozicio
* @param x la horizontala koordinato
* @param y la vertikala koordinato
*/
Ulo( int x, int y ) {
poz = new Point( x, y );
}
/** @returns la pozicion de la ludpeco */
Point ricevuPozicion() {
return poz;
}
/** pentru la ludpecon */
abstract void pentru( Graphics g );
}
/**
* Tiu cxi klaso reprezentas la robotojn.
* Ili povas movigxi ne libere,
* sed nur cele al la fugxanto.
*/
class Roboto extends Ulo {
/** cxu la roboto jam estis detruita? */
protected boolean detruita = false;
/** Metu novan roboton sur la kampon */
Roboto( int x, int y ) {
super( x, y );
}
/**
* Pentru la roboton.
* Depende de la detruiteco gxi estas flava aux rugxa.
*/
void pentru( Graphics g ) {
int x = poz.x * kampo.c.width / kampo.nx;
int y = poz.y * kampo.c.height / kampo.ny;
g.setColor( detruita ? Color.yellow : Color.red );
g.fillOval( x, y, kampo.c.width / kampo.nx,
kampo.c.height / kampo.ny );
}
/**
* Movu la roboton direkte al donita punkto.
* @param celo la cel-punkto
*/
void movigxuCeleAl( Point celo ) {
if( ! detruita ) {
int dx = celo.x - poz.x;
int dy = celo.y - poz.y;
dx = dx > 0 ? 1 : dx < 0 ? -1 : 0;
dy = dy > 0 ? 1 : dy < 0 ? -1 : 0;
poz.x += dx;
poz.y += dy;
}
}
/**
* Diru al la roboto, ke gxi jxus estis detruita.
* Riparo ne eblas.
*/
void detruu() {
detruita = true;
}
/**
* @returns cxu la roboto estas detruita
*/
boolean detruita() {
return detruita;
}
}
/**
* La klaso por la fugxanto.
* Gxi havas komunan superklason kun siaj malamikoj, la robotoj.
*/
class Fugxanto extends Ulo {
/** cxu la fugxanto mortis? */
protected boolean mortinta = false;
/** Metu novan fugxanton sur la kampon. */
Fugxanto( int x, int y ) {
super( x, y );
}
/** pentru la ulon kiel ovalon */
void pentru( Graphics g ) {
int x = poz.x * kampo.c.width / kampo.nx;
int y = poz.y * kampo.c.height / kampo.ny;
g.setColor( mortinta ? Color.orange : Color.blue );
g.fillOval( x, y, kampo.c.width / kampo.nx,
kampo.c.height / kampo.ny );
}
/** necesas morti... */
void mortu() {
mortinta = true;
}
/** movu la donitan punkton laux la donita direkto.
Direkto povas esti: