80 |
80 |
Thread drawThread;
|
81 |
81 |
SelectionIndicator indicator;
|
82 |
82 |
PacketMonitor packetMonitor;
|
|
83 |
ColonetServerInterface csi;
|
83 |
84 |
|
84 |
85 |
|
85 |
86 |
public void init () {
|
... | ... | |
277 |
278 |
indicator.setRadius(RADIUS+3, 15); //a tad more than the bot radius
|
278 |
279 |
packetMonitor = new PacketMonitor();
|
279 |
280 |
datalistener = new DataListener();
|
|
281 |
|
|
282 |
csi = new ColonetServerInterface(log);
|
280 |
283 |
|
281 |
284 |
}
|
282 |
285 |
|
283 |
|
public synchronized void paint (Graphics g)
|
284 |
|
{
|
|
286 |
public synchronized void paint (Graphics g) {
|
285 |
287 |
/* First, redraw the graphical components in the applet.
|
286 |
288 |
This paint method overrides the built-in paint of the
|
287 |
289 |
JApplet, and we don't want to deal with redrawing the
|
... | ... | |
293 |
295 |
|
294 |
296 |
}
|
295 |
297 |
|
296 |
|
public synchronized void update (Graphics g)
|
297 |
|
{
|
|
298 |
public synchronized void update (Graphics g) {
|
298 |
299 |
paint(g);
|
299 |
300 |
}
|
300 |
301 |
|
301 |
|
public void actionPerformed (ActionEvent e)
|
302 |
|
{
|
|
302 |
public void actionPerformed (ActionEvent e) {
|
303 |
303 |
Object source = e.getSource();
|
304 |
304 |
if (source == btnGraph) {
|
305 |
305 |
btnGraph.setEnabled(false);
|
... | ... | |
320 |
320 |
}
|
321 |
321 |
}
|
322 |
322 |
|
323 |
|
private void randomize ()
|
324 |
|
{
|
|
323 |
private void randomize () {
|
325 |
324 |
Random r = new Random();
|
326 |
325 |
StringBuilder s = new StringBuilder();
|
327 |
326 |
|
328 |
327 |
int count = r.nextInt(8) + 1;
|
329 |
|
for (int i = 0; i < count; i++)
|
330 |
|
{
|
331 |
|
for (int j = 0; j < count; j++)
|
332 |
|
{
|
|
328 |
for (int i = 0; i < count; i++) {
|
|
329 |
for (int j = 0; j < count; j++) {
|
333 |
330 |
if (r.nextBoolean())
|
334 |
331 |
s.append("" + (r.nextInt(16) + 1));
|
335 |
332 |
else
|
... | ... | |
343 |
340 |
txtInput.setText(s.toString());
|
344 |
341 |
}
|
345 |
342 |
|
346 |
|
private void doSocket ()
|
347 |
|
{
|
348 |
|
//make sure hostname and port are valid
|
349 |
|
if (txtHost.getText().equals("") || txtPort.getText().equals("")) {
|
350 |
|
err("Please enter a hostname and port.");
|
351 |
|
return;
|
352 |
|
}
|
353 |
|
int port = 0;
|
354 |
|
try {
|
355 |
|
port = Integer.parseInt(txtPort.getText());
|
356 |
|
} catch (Exception e) {
|
357 |
|
err("Invalid port");
|
358 |
|
return;
|
359 |
|
}
|
360 |
|
|
361 |
|
//make sure we aren't already connected. if so, disconnect first.
|
362 |
|
if (socket != null && socket.isConnected()) {
|
363 |
|
try {
|
364 |
|
out.close();
|
365 |
|
socket.close();
|
366 |
|
} catch (IOException e) {}
|
367 |
|
}
|
368 |
|
|
369 |
|
try {
|
370 |
|
socket = new Socket(txtHost.getText(), port);
|
371 |
|
} catch (UnknownHostException e) {
|
372 |
|
err("Unknown Host Exception");
|
373 |
|
return;
|
374 |
|
} catch (IOException e) {
|
375 |
|
err("IO Exception\n\n" + e);
|
376 |
|
return;
|
377 |
|
} catch (java.security.AccessControlException e) {
|
378 |
|
err("Permission denied by java.security.AccessControlException."
|
379 |
|
+"\n\nYou may only connect to the server from which this applet was loaded.");
|
380 |
|
return;
|
381 |
|
}
|
382 |
|
if (socket == null || !socket.isConnected()) {
|
383 |
|
err("Connection failed. Try connecting again.");
|
384 |
|
return;
|
385 |
|
}
|
386 |
|
msg("Connected to " + txtHost.getText() + " on port " + port + "\n");
|
387 |
|
lblConnectionStatus.setText("Online");
|
388 |
|
try {
|
389 |
|
out = new OutputStreamWriter(socket.getOutputStream());
|
390 |
|
} catch (IOException e) {
|
391 |
|
warn("Could not get OutputStream from socket connection.");
|
392 |
|
}
|
393 |
|
|
|
343 |
private void doSocket () {
|
|
344 |
csi.connect(txtHost.getText(), txtPort.getText());
|
394 |
345 |
}
|
395 |
346 |
|
396 |
|
public void drawRobot (int id, int x, int y)
|
397 |
|
{
|
|
347 |
public void drawRobot (int id, int x, int y) {
|
398 |
348 |
//save the bot in memory, so we can tell if we click on it later
|
399 |
349 |
botRect[id] = new Rectangle(x-RADIUS, y-RADIUS, 2*RADIUS, 2*RADIUS);
|
400 |
350 |
|
... | ... | |
407 |
357 |
canvas.drawString("" + id, x-10, y+10);
|
408 |
358 |
}
|
409 |
359 |
|
410 |
|
public void drawConnection (int start, int end, int radius, Color color)
|
411 |
|
{
|
|
360 |
public void drawConnection (int start, int end, int radius, Color color) {
|
412 |
361 |
final int ARROW_LENGTH = 18;
|
413 |
362 |
|
414 |
363 |
double angle = 2.0 * Math.PI / numBots;
|
... | ... | |
444 |
393 |
int dx_half = (int)(ARROW_LENGTH/2 * Math.sin(theta));
|
445 |
394 |
int rx = (big_dx > 0) ? endx - dx_arrow : endx + dx_arrow;
|
446 |
395 |
int ry = (big_dy > 0) ? endy + dy_arrow : endy - dy_arrow;
|
447 |
|
//System.out.println("" + start + "->" + end + " : dx=" + big_dx + ",dy=" + big_dy + ",dy_arrow=" + dy_arrow + ",dx_arrow=" + dx_arrow + ",theta=" + theta + ",endx=" + endx + ",endy=" + endy + ",rx=" + rx + ",ry=" + ry);
|
448 |
396 |
poly.addPoint(endx, endy);
|
449 |
397 |
poly.addPoint(rx - dx_half, ry - dy_half);
|
450 |
398 |
poly.addPoint(rx + dx_half, ry + dy_half);
|
451 |
399 |
canvas.fillPolygon(poly);
|
452 |
400 |
}
|
453 |
401 |
|
454 |
|
public void run ()
|
455 |
|
{
|
456 |
|
while (true)
|
457 |
|
{
|
|
402 |
public void run () {
|
|
403 |
while (true) {
|
458 |
404 |
step();
|
459 |
405 |
repaint();
|
460 |
|
try { Thread.sleep(90); }
|
461 |
|
catch (InterruptedException e) { return; }
|
|
406 |
try {
|
|
407 |
Thread.sleep(90);
|
|
408 |
} catch (InterruptedException e) {
|
|
409 |
return;
|
|
410 |
}
|
462 |
411 |
}
|
463 |
412 |
}
|
464 |
413 |
|
465 |
|
public void step ()
|
466 |
|
{
|
|
414 |
public void step () {
|
467 |
415 |
final int DIAMETER = image.getWidth() - 2*BUFFER;
|
468 |
416 |
final int BIGRADIUS = DIAMETER / 2;
|
469 |
417 |
final int TOKENRADIUS = 40;
|
... | ... | |
478 |
426 |
numBots = rows.length;
|
479 |
427 |
String [][] entries = new String[numBots][numBots];
|
480 |
428 |
valid = true;
|
481 |
|
for (int i = 0; i < numBots; i++)
|
482 |
|
{
|
|
429 |
for (int i = 0; i < numBots; i++) {
|
483 |
430 |
entries[i] = rows[i].split(" ");
|
484 |
431 |
if (entries[i].length != rows.length) valid = false;
|
485 |
432 |
}
|
486 |
433 |
|
487 |
|
if (valid)
|
488 |
|
{
|
|
434 |
if (valid) {
|
489 |
435 |
this.showStatus("Matrix OK");
|
490 |
436 |
|
491 |
437 |
// draw robots and find which one is seleced
|
... | ... | |
494 |
440 |
botRect = new Rectangle[numBots];
|
495 |
441 |
int x, y;
|
496 |
442 |
if (selectedBot >= numBots) selectedBot = 0;
|
497 |
|
for (int i = 0; i < numBots; i++)
|
498 |
|
{
|
|
443 |
for (int i = 0; i < numBots; i++) {
|
499 |
444 |
x = cx - (int)(BIGRADIUS * Math.cos(i * angle));
|
500 |
445 |
y = cy - (int)(BIGRADIUS * Math.sin(i * angle));
|
501 |
446 |
drawRobot(i, x, y);
|
... | ... | |
513 |
458 |
// create an inner circle along which the connections are made.
|
514 |
459 |
// let the diameter of this circle be 2*RADIUS less than the outerDiameter.
|
515 |
460 |
// see what connections exist
|
516 |
|
for (int row = 0; row < numBots; row++)
|
517 |
|
{
|
518 |
|
for(int col = 0; col < numBots; col++)
|
519 |
|
{
|
520 |
|
if (! entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) //one-way
|
521 |
|
{
|
522 |
|
//drawConnection(row, col, BIGRADIUS-RADIUS, Color.GRAY);
|
|
461 |
for (int row = 0; row < numBots; row++) {
|
|
462 |
for(int col = 0; col < numBots; col++) {
|
|
463 |
if (!entries[row][col].equals("-") && entries[col][row].equals("-") && row != col) {
|
|
464 |
//TODO: Make a standard gray
|
523 |
465 |
drawConnection(row, col, BIGRADIUS-RADIUS, new Color(200,200,200));
|
524 |
466 |
}
|
525 |
|
else if (! entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) //two-way
|
526 |
|
{
|
|
467 |
else if (!entries[row][col].equals("-") && ! entries[col][row].equals("-") && row != col) {
|
527 |
468 |
drawConnection(row, col, BIGRADIUS-RADIUS, Color.BLACK);
|
528 |
469 |
}
|
529 |
470 |
}
|
... | ... | |
533 |
474 |
indicator.draw();
|
534 |
475 |
txtInfo.setText("Packet statistics: ???");
|
535 |
476 |
|
536 |
|
}
|
537 |
|
else // if matrix is not valid
|
538 |
|
{
|
|
477 |
} else {// if matrix is not valid
|
539 |
478 |
this.showStatus("Error: Invalid matrix");
|
540 |
479 |
}
|
541 |
480 |
|
... | ... | |
546 |
485 |
* token passing or deleted if the information can be retrieved
|
547 |
486 |
* directly from the Colonet server instead.
|
548 |
487 |
*/
|
549 |
|
public void moveToken ()
|
550 |
|
{
|
551 |
|
try { tokenLoc = (tokenLoc+1)%numBots; }
|
552 |
|
catch (ArithmeticException e) { } // in case numRobots is zero
|
|
488 |
public void moveToken () {
|
|
489 |
try {
|
|
490 |
tokenLoc = (tokenLoc+1)%numBots;
|
|
491 |
} catch (ArithmeticException e) { // in case numRobots is zero
|
|
492 |
}
|
553 |
493 |
|
554 |
494 |
packetMonitor.addTokenPass();
|
555 |
495 |
}
|
... | ... | |
561 |
501 |
public void mouseEntered(MouseEvent e) {}
|
562 |
502 |
public void mouseReleased(MouseEvent e) {}
|
563 |
503 |
public void mouseClicked(MouseEvent e) {}
|
564 |
|
public void mousePressed(MouseEvent e)
|
565 |
|
{
|
|
504 |
public void mousePressed(MouseEvent e) {
|
566 |
505 |
try {
|
567 |
|
for (int i = 0; i < numBots; i++)
|
568 |
|
{
|
|
506 |
for (int i = 0; i < numBots; i++) {
|
569 |
507 |
if (botRect[i].contains(e.getPoint()))
|
570 |
508 |
selectedBot = i;
|
571 |
509 |
}
|
... | ... | |
575 |
513 |
|
576 |
514 |
}
|
577 |
515 |
|
578 |
|
private void msg (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.INFORMATION_MESSAGE);}
|
579 |
|
private void warn (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.WARNING_MESSAGE);}
|
580 |
|
private void err (String text) {JOptionPane.showMessageDialog(null, text, "Colonet", JOptionPane.ERROR_MESSAGE);}
|
581 |
|
|
582 |
|
|
583 |
516 |
/*
|
584 |
517 |
* SelectionIndicator thread.
|
585 |
518 |
* Graphical representation of the selection marker
|
... | ... | |
589 |
522 |
* externally and should only run if all calculations in step() have
|
590 |
523 |
* been completed.
|
591 |
524 |
*/
|
592 |
|
private class SelectionIndicator extends Thread
|
593 |
|
{
|
|
525 |
private class SelectionIndicator extends Thread {
|
594 |
526 |
|
595 |
527 |
final int INDICATOR_DELAY = 100;
|
596 |
528 |
final double DTHETA = 0.3; //larger values make the marker rotate faster
|
... | ... | |
614 |
546 |
|
615 |
547 |
int steps;
|
616 |
548 |
|
617 |
|
public SelectionIndicator (Graphics2D g)
|
618 |
|
{
|
|
549 |
public SelectionIndicator (Graphics2D g) {
|
619 |
550 |
super("SelectionIndicator");
|
620 |
551 |
this.g = g;
|
621 |
552 |
running = false;
|
... | ... | |
632 |
563 |
px4 = 0; py4 = 0;
|
633 |
564 |
}
|
634 |
565 |
|
635 |
|
public synchronized void setCenter (int sx, int sy)
|
636 |
|
{
|
|
566 |
public synchronized void setCenter (int sx, int sy) {
|
637 |
567 |
if (sx == this.sx && sy == this.sy) return;
|
638 |
568 |
this.sx = sx;
|
639 |
569 |
this.sy = sy;
|
640 |
570 |
steps = 0;
|
641 |
571 |
}
|
642 |
572 |
|
643 |
|
public synchronized void setRadius (int r, int dr)
|
644 |
|
{
|
|
573 |
public synchronized void setRadius (int r, int dr) {
|
645 |
574 |
this.r = r;
|
646 |
575 |
this.dr = dr;
|
647 |
576 |
steps = 0;
|
648 |
577 |
}
|
649 |
578 |
|
650 |
|
public void run ()
|
651 |
|
{
|
|
579 |
public void run () {
|
652 |
580 |
running = true;
|
653 |
|
while (running)
|
654 |
|
{
|
|
581 |
while (running) {
|
655 |
582 |
step();
|
656 |
|
try { Thread.sleep(INDICATOR_DELAY); }
|
657 |
|
catch (InterruptedException e) { running = false; return; }
|
|
583 |
try {
|
|
584 |
Thread.sleep(INDICATOR_DELAY);
|
|
585 |
} catch (InterruptedException e) {
|
|
586 |
running = false;
|
|
587 |
return;
|
|
588 |
}
|
658 |
589 |
}
|
659 |
590 |
}
|
660 |
591 |
|
661 |
|
private synchronized void step ()
|
662 |
|
{
|
|
592 |
private synchronized void step () {
|
663 |
593 |
Polygon poly1_new = new Polygon();
|
664 |
594 |
Polygon poly2_new = new Polygon();
|
665 |
595 |
Polygon poly3_new = new Polygon();
|
... | ... | |
687 |
617 |
int dx_poly = (int)(dr/2 * Math.sin(theta));
|
688 |
618 |
|
689 |
619 |
//determine critical points
|
|
620 |
//kansas city shuffle!
|
690 |
621 |
px1 = sx + dx_inner;
|
691 |
622 |
py1 = sy - dy_inner;
|
692 |
623 |
rx1 = sx + dx_outer;
|
... | ... | |
727 |
658 |
if (steps < 300) steps++;
|
728 |
659 |
}
|
729 |
660 |
|
730 |
|
public synchronized void draw ()
|
731 |
|
{
|
|
661 |
public synchronized void draw () {
|
732 |
662 |
if (!running) return;
|
733 |
663 |
g.setColor(Color.GRAY);
|
734 |
664 |
//draw polygons
|
... | ... | |
744 |
674 |
* Simulator thread.
|
745 |
675 |
*
|
746 |
676 |
*/
|
747 |
|
private class Simulator extends Thread
|
748 |
|
{
|
|
677 |
private class Simulator extends Thread {
|
749 |
678 |
final int SIMULATOR_DELAY = 300;
|
750 |
|
|
751 |
679 |
boolean running;
|
752 |
680 |
|
753 |
|
public Simulator ()
|
754 |
|
{
|
|
681 |
public Simulator () {
|
755 |
682 |
super("Simulator");
|
756 |
683 |
running = false;
|
757 |
684 |
}
|
758 |
685 |
|
759 |
|
public void run ()
|
760 |
|
{
|
|
686 |
public void run () {
|
761 |
687 |
running = true;
|
762 |
|
while (running)
|
763 |
|
{
|
|
688 |
while (running) {
|
764 |
689 |
step();
|
765 |
|
try { Thread.sleep(SIMULATOR_DELAY); }
|
766 |
|
catch (InterruptedException e) { running = false; return; }
|
|
690 |
try {
|
|
691 |
Thread.sleep(SIMULATOR_DELAY);
|
|
692 |
} catch (InterruptedException e) {
|
|
693 |
running = false;
|
|
694 |
return;
|
|
695 |
}
|
767 |
696 |
}
|
768 |
697 |
}
|
769 |
698 |
|
770 |
|
private void step ()
|
771 |
|
{
|
|
699 |
private void step () {
|
772 |
700 |
// simulate passing the token
|
773 |
701 |
moveToken();
|
774 |
|
|
775 |
702 |
}
|
776 |
703 |
|
777 |
704 |
}
|
... | ... | |
782 |
709 |
* Currently, this counts the rate of token passes but will eventually
|
783 |
710 |
* be modified to keep more important statistics.
|
784 |
711 |
*/
|
785 |
|
private class PacketMonitor extends Thread
|
786 |
|
{
|
|
712 |
private class PacketMonitor extends Thread {
|
787 |
713 |
final int PACKETMONITOR_DELAY = 1000;
|
788 |
714 |
|
789 |
715 |
boolean running;
|
790 |
716 |
int tokenPasses;
|
791 |
717 |
|
792 |
|
public PacketMonitor ()
|
793 |
|
{
|
|
718 |
public PacketMonitor () {
|
794 |
719 |
super("PacketMonitor");
|
795 |
720 |
running = false;
|
796 |
721 |
tokenPasses = 0;
|
797 |
722 |
}
|
798 |
723 |
|
799 |
|
public void run ()
|
800 |
|
{
|
|
724 |
public void run () {
|
801 |
725 |
running = true;
|
802 |
|
while (running)
|
803 |
|
{
|
|
726 |
while (running) {
|
804 |
727 |
displayTokenPasses();
|
805 |
|
try { Thread.sleep(PACKETMONITOR_DELAY); }
|
806 |
|
catch (InterruptedException e) { running = false; return; }
|
|
728 |
try {
|
|
729 |
Thread.sleep(PACKETMONITOR_DELAY);
|
|
730 |
} catch (InterruptedException e) {
|
|
731 |
running = false;
|
|
732 |
return;
|
|
733 |
}
|
807 |
734 |
}
|
808 |
735 |
}
|
809 |
736 |
|
810 |
|
public synchronized void addTokenPass ()
|
811 |
|
{
|
|
737 |
public synchronized void addTokenPass () {
|
812 |
738 |
tokenPasses++;
|
813 |
739 |
}
|
814 |
740 |
|
815 |
|
public synchronized void displayTokenPasses ()
|
816 |
|
{
|
|
741 |
public synchronized void displayTokenPasses () {
|
817 |
742 |
lblTokenPasses.setText("" + tokenPasses);
|
818 |
743 |
tokenPasses = 0;
|
819 |
744 |
}
|
... | ... | |
824 |
749 |
* DataListener thread.
|
825 |
750 |
*
|
826 |
751 |
*/
|
827 |
|
class DataListener extends Thread
|
828 |
|
{
|
|
752 |
class DataListener extends Thread {
|
829 |
753 |
final int DATALISTENER_DELAY = 1000;
|
830 |
754 |
BufferedReader reader;
|
831 |
755 |
|
832 |
|
public DataListener ()
|
833 |
|
{
|
|
756 |
public DataListener () {
|
834 |
757 |
super("Colonet DataListener");
|
835 |
758 |
}
|
836 |
759 |
|
837 |
|
public void run ()
|
838 |
|
{
|
|
760 |
public void run () {
|
839 |
761 |
String line;
|
840 |
|
try {
|
841 |
|
reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
842 |
|
} catch (IOException e) {
|
843 |
|
warn("Could not open input stream from socket.\nTry relooding the applet.");
|
844 |
|
}
|
845 |
|
while (true)
|
846 |
|
{
|
|
762 |
reader = csi.getBufferedReader();
|
|
763 |
while (true) {
|
847 |
764 |
try {
|
848 |
|
if (reader.ready())
|
849 |
|
{
|
|
765 |
if (csi.isReady()) {
|
850 |
766 |
line = reader.readLine();
|
851 |
|
if (line != null)
|
852 |
|
{
|
853 |
|
msg("Incoming data: [" + line + "]");
|
|
767 |
if (line != null) {
|
|
768 |
csi.msg("Incoming data: [" + line + "]");
|
|
769 |
//TODO: parse incoming data here
|
854 |
770 |
}
|
855 |
771 |
}
|
856 |
772 |
Thread.sleep(DATALISTENER_DELAY);
|
857 |
773 |
} catch (InterruptedException e) {
|
858 |
774 |
return;
|
859 |
775 |
} catch (IOException e) {
|
860 |
|
warn("IOException while reading incoming data.");
|
|
776 |
csi.warn("IOException while reading incoming data.");
|
861 |
777 |
}
|
862 |
778 |
}
|
863 |
779 |
}
|
864 |
780 |
|
865 |
781 |
}
|
866 |
782 |
|
867 |
|
|
868 |
|
|
869 |
|
|
870 |
783 |
}
|