Advertisement
Advertisement
| 04.27.2008 at 08:28PM PDT, ID: 23357736 |
|
[x]
Attachment Details
|
||
|
[x]
The Solution Rating System
|
||
|
With so many solutions, how can you tell which solutions are most likely to help you and which ones are not? To provide you with a tool to use, we rate our solutions based on various elements that most accurately determine if a solution is a quality solution. To explain what factors affect the solution rating, here are the elements we take into consideration when formulating our solution rating.
Your Input Matters If you have any suggestions that you would like to make for our rating system, please ask a question in the Suggestions Zone of Community Support. Thank you! |
||
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 506: 507: 508: 509: 510: 511: 512: 513: 514: 515: 516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531: 532: 533: 534: 535: 536: 537: 538: 539: 540: 541: 542: 543: 544: 545: 546: 547: 548: 549: 550: 551: 552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562: 563: 564: 565: 566: 567: 568: 569: 570: 571: 572: 573: 574: 575: 576: 577: 578: 579: 580: 581: 582: 583: 584: 585: 586: 587: 588: 589: 590: 591: 592: 593: 594: 595: 596: 597: 598: 599: 600: 601: 602: 603: 604: 605: 606: 607: 608: 609: 610: 611: 612: 613: 614: 615: 616: 617: 618: 619: 620: 621: 622: 623: 624: 625: 626: 627: 628: 629: 630: 631: 632: 633: 634: 635: 636: 637: 638: 639: 640: 641: 642: 643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654: 655: 656: 657: 658: 659: 660: 661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685: 686: 687: 688: 689: 690: 691: 692: 693: 694: 695: 696: 697: 698: 699: 700: 701: 702: 703: 704: 705: 706: 707: 708: 709: 710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726: 727: 728: 729: 730: 731: 732: 733: 734: 735: 736: 737: 738: 739: 740: 741: 742: 743: 744: 745: 746: 747: 748: 749: 750: 751: 752: 753: 754: 755: 756: 757: 758: 759: 760: 761: 762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773: 774: 775: 776: 777: 778: 779: 780: 781: 782: 783: 784: 785: 786: 787: 788: 789: 790: 791: 792: 793: 794: 795: 796: 797: 798: 799: 800: 801: 802: 803: 804: 805: 806: 807: 808: 809: 810: 811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825: 826: 827: 828: 829: 830: 831: 832: 833: 834: 835: 836: 837: 838: 839: 840: 841: 842: 843: 844: 845: 846: 847: 848: 849: 850: 851: 852: 853: 854: 855: 856: 857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880: 881: 882: 883: 884: 885: 886: 887: 888: 889: 890: 891: 892: 893: 894: 895: 896: 897: 898: 899: 900: 901: 902: 903: 904: 905: 906: 907: 908: 909: 910: |
class ClientHandler extends ConnectionBase
{
String name = "Dave" + this.hashCode();
LODServer server;
int x = 0;
int y = 0;
int lantern = 0;
int sword = 0;
int armour = 0;
int treasure = 0;
int hp = 3;
boolean dead = false;
boolean isMyTurn = false;
int ap = 0;
synchronized void startTurn () throws InterruptedException {
try {
server.playerTurn.acquire();
} catch (InterruptedException e) {
throw(e);
}
ap = 6 - (lantern + sword + armour);
isMyTurn = true;
serverStartTurn();
return;
}
void clientHello(String newName) {
name = newName;
return;
}
void clientLook() {
if ((server.gameStarted == false) || (dead == true)) {
return;
} else {
serverLookReplyBegin();
int distance = 2 + lantern;
for (int i = -distance; i <= distance; ++i) {
String line = "";
for (int j = -distance; j <= distance; ++j) {
char content = '?';
int targetX = x + j;
int targetY = y + i;
if (Math.abs(i) + Math.abs(j) > distance + 1) {
content = 'X';
} else if ((targetX < 0) || (targetX >= server.mapWidth) ||
(targetY < 0) || (targetY >= server.mapHeight)) {
content = '#';
} else {
switch (server.map[targetY][targetX]) {
case LODServer.EMPTY : content = '.'; break;
case LODServer.HEALTH : content = 'H'; break;
case LODServer.LANTERN : content = 'L'; break;
case LODServer.SWORD : content = 'S'; break;
case LODServer.ARMOUR : content = 'A'; break;
case LODServer.EXIT : content = 'E'; break;
case LODServer.WALL : content = '#'; break;
default :
if (server.map[targetY][targetX] > 0) {
content = 'G';
} else {
System.err.println("Invalid map location : [" + targetY + "][" + targetX + "] = " + server.map[targetY][targetX]);
System.exit(1);
}
}
for (ClientHandler c : server.clients) {
if (c != this) {
if ((c.x == targetX) && (c.y == targetY)) {
content = 'P';
}
}
}
}
line += content;
}
serverLookReply(line);
}
}
}
void clientShout(String message) {
if (server.gameStarted == false) {
return;
} else {
for (ClientHandler c : server.clients) {
if (c != this) {
c.serverMessage(name + " : " + message);
}
}
return;
}
}
void clientPickup() {
String failMessage = "";
if ((isMyTurn) && (ap > 0)) {
switch (server.map[y][x]) {
case LODServer.EXIT :
case LODServer.EMPTY :
failMessage = "Nothing to pick up";
break;
case LODServer.HEALTH :
ap = 0;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
++hp;
serverHitMod(1);
sendChangeNotifications();
return;
//break; // Commented out as never reached
case LODServer.LANTERN :
if (lantern == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
lantern = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a lantern";
}
break;
case LODServer.SWORD :
if (sword == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
sword = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a sword";
}
break;
case LODServer.ARMOUR :
if (armour == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
armour = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a armour";
}
break;
default :
if (server.map[y][x] > 0) {
--ap;
int treasurePickedUp = server.map[y][x];
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
treasure += treasurePickedUp;
serverTreasureMod(treasurePickedUp);
sendChangeNotifications();
return;
} else {
System.err.println("Pickup at strange map location : [" + y + "][" + x + "] = " + server.map[y][x]);
System.exit(1);
}
}
} else {
if (!isMyTurn) {
failMessage = "Faulty client : PICKUP outside of turn";
} else {
failMessage = "No action points left";
}
}
serverFail(failMessage);
return;
}
void clientMove(char direction) {
String failMessage;
if ((isMyTurn) && (ap > 0)) {
int targetX = x;
int targetY = y;
switch (direction) {
case 'N' : --targetY; break;
case 'S' : ++targetY; break;
case 'E' : ++targetX; break;
case 'W' : --targetX; break;
default : // Shouldn't happen
System.err.println("Internal error in connection base.");
System.err.println("'" + direction + "' is not a direction.");
System.exit(1);
}
if ((targetX >= 0) && (targetX < server.mapWidth) &&
(targetY >= 0) && (targetY < server.mapHeight)) {
if (server.map[targetY][targetX] != LODServer.WALL) {
boolean targetEmpty = true;
for (ClientHandler c : server.clients) {
if ((c != this) && (c.x == targetX) && (c.y == targetY)) {
targetEmpty = false;
}
}
if (targetEmpty) {
--ap;
x = targetX;
y = targetY;
serverSucceed();
sendChangeNotifications();
return;
} else {
failMessage = "Can not move into another player";
}
} else {
failMessage = "Can not move into a wall";
}
} else {
// Needs to be the same as above or
// otherwise lets people know where
// the edges of the labyrinth are.
failMessage = "Can not move into a wall";
}
} else {
if (!isMyTurn) {
// Only happens with faulty clients
failMessage = "Faulty client : MOVE outside of turn";
} else {
failMessage = "No action points left";
}
}
// Fail unless there is an explict reason why we succeed
serverFail(failMessage);
return;
}
// Handles the client message ATTACK
void clientAttack(char direction) {
String failMessage;
// Can only attack if it is this player's turn
// and they have action points left
if ((isMyTurn) && (ap > 0)) {
// Work out which square we're targeting
int targetX = x;
int targetY = y;
switch (direction) {
case 'N' : --targetY; break;
case 'S' : ++targetY; break;
case 'E' : ++targetX; break;
case 'W' : --targetX; break;
default : // Shouldn't happen
System.err.println("Internal error in connection base.");
System.err.println("'" + direction + "' is not a direction.");
System.exit(1);
}
// Work out which player that is
ClientHandler target = null;
for (ClientHandler c : server.clients) {
if ((c.x == targetX) && (c.y == targetY)) {
target = c;
break;
}
}
// If there is another player in the target square
if (target != null) {
// There is a 75% chance of hitting
if (Math.random() < 0.75) {
// Reduce the target's hitpoints
int damage = 1 + sword - target.armour;
target.hp -= damage;
// Notify them of the change
target.serverMessage("You where hit by " + name +
" for " + damage + " points of damage");
target.serverHitMod(-damage);
// Notify the attacker of a successful attack
serverSucceed();
// If the target has been killed
if (target.hp <= 0) {
target.serverMessage(name + " has killed you");
target.die();
}
return;
} else {
// This message is not required by the spec
// but adds to the playability of the game
target.serverMessage("You dodged " + name + "'s attack");
failMessage = "They dodged your attack";
}
} else {
failMessage = "No one there to attack";
}
} else {
if (!isMyTurn) {
// Only happens with faulty clients
failMessage = "Faulty client : ATTACK outside of turn";
} else {
failMessage = "No action points left";
}
}
// Fail unless there is an explict reason why we succeed
serverFail(failMessage);
return;
}
// Handles the client message ENDTURN
void clientEndTurn() {
// Check to see if this player has won
if ((treasure >= server.goal) && (server.map[y][x] == LODServer.EXIT)) {
server.gameFinished = true;
}
// Mark that it is no longer this player's turn
isMyTurn = false;
// Release the semaphore
// (thus the LODServer can acquire it, and
// make it the next player's go).
server.playerTurn.release();
return;
}
// Not a message; what to do if the client disconnects
void clientDisconnected() {
die();
// Disconnecting may occur during the player's turn,
// unlike the other causes of death.
if (isMyTurn) {
// Act as if an ENDTURN message had been sent
clientEndTurn();
}
}
// Not a message; what to do if a player disconnects or is killed
void die() {
// Unlike horror film bad guys, ClientHandlers only die once
if (!dead) {
dead = true;
// Drop any gold carried
server.map[y][x] = treasure * LODServer.TREASURE;
// BUG!
// Dropping gold will (correctly) destroy any item
// (i.e. sword, armour, lantern, health)
// however, it currently also (incorrectly) destroys
// any other gold or the exit if they are on the square
// that the gold is dropped on.
// The correct solution to this probably involves
// separate matrices for locations (walls, exits, etc.)
// items/treasure.
server.clients.remove(this);
// Note this does not disconnect the client
// but they will not get another turn
// nor effect the map,
// they can only shout and listen to messages
// To disconnect them as well:
// shutdown();
// Inform other players of their demise
for (ClientHandler c : server.clients) {
c.serverMessage(name + " is no more!");
}
sendChangeNotifications();
}
}
// A helper function which sends CHANGE messages
// when an actions changes the map
void sendChangeNotifications () {
for (ClientHandler c : server.clients) {
c.serverChangeNotification();
}
}
}
import java.net.*;
import java.io.*;
abstract class ConnectionBase
{
// A separate thread that listen on the socket and then calls the
// relevant abstract client* function to handle the message.
protected class ClientListenThread extends Thread
{
// Set to false to stop the thread listening
volatile boolean running = true;
public void run()
{
String tmp = null;
while (running) {
// Sanity checks
if (sock.isConnected() == false) {
clientDisconnected();
return;
}
if (sock.isClosed() == true) {
clientDisconnected();
return;
}
try {
tmp = in.readLine();
} catch (IOException e) {
clientDisconnected();
return;
}
if (tmp == null) {
break;
}
receiveMessage(tmp);
}
clientDisconnected();
}
}
protected Socket sock = null;
protected PrintWriter out = null;
protected BufferedReader in = null;
protected ClientListenThread clt = new ClientListenThread();
private int id;
private boolean logging;
// This variable may help you find certain concurrency problems
private final int evil_wait = 1;
public void init(Socket sock, int id, boolean logging)
{
this.sock = sock;
try {
in = new BufferedReader(
new InputStreamReader(sock.getInputStream()));
out = new PrintWriter(sock.getOutputStream(), true);
} catch (IOException e) {
shutdown();
}
this.id = id;
this.logging = logging;
clt.start();
}
/**
Implement this to handle the HELLO message.
@param name This is the name the client has specified.
*/
abstract void clientHello(String name);
/**
Implement this to handle the LOOK message.
*/
abstract void clientLook();
/**
Implement this to handle the PICKUP message.
*/
abstract void clientPickup();
/**
Implement this to handle the MOVE message.
@param direction Is one of 'N', 'E', 'S' or 'W'.
*/
abstract void clientMove(char direction);
/**
Implement this to handle the ATTACK message.
@param direction Is one of 'N', 'E', 'S' or 'W'.
*/
abstract void clientAttack(char direction);
/**
Implement this to handle the ENDTURN message.
*/
abstract void clientEndTurn();
/**
Implement this to handle the SHOUT message.
@param message Is the message received from the client.
*/
abstract void clientShout(String message);
/**
Implement this to handle a client disconnection.
*/
abstract void clientDisconnected();
/**
This method will shut down the connection to the client.
*/
public final void shutdown()
{
clt.running = false;
try {
sock.shutdownInput();
sock.shutdownOutput();
sock.close();
} catch (IOException e) {
System.err.println(e);
}
out.close();
}
/**
Sends the server message GOAL.
@param required_treasure Amount of treasure required to win the game.
*/
public final void serverGoal(int required_treasure)
{
sendMessage("GOAL "+required_treasure);
}
/**
Sends the server message SUCCEED.
*/
public final void serverSucceed()
{
sendMessage("SUCCEED");
}
/**
Sends the server message FAIL.
@param message An optional human-readable message to indicate why an
operation failed.
*/
public final void serverFail(String message)
{
sendMessage("FAIL "+sanitizeMessage(message));
}
/**
Sends the server message FAIL.
*/
public final void serverFail()
{
sendMessage("FAIL");
}
/**
Sends the server message STARTTURN.
*/
public final void serverStartTurn()
{
sendMessage("STARTTURN");
}
/**
Sends the server message HITMOD.
@param n Specifies how many hit points are gained (or lost, if
negative)
*/
public final void serverHitMod(int n)
{
sendMessage("HITMOD "+n);
}
/**
Sends the server message TREASUREMOD.
@param n Specifies how much treasure is gained (or lost, if negative)
*/
public final void serverTreasureMod(int n)
{
sendMessage("TREASUREMOD "+n);
}
/**
Sends the server message MESSAGE.
@param message A human-readable message.
*/
public final void serverMessage(String message)
{
sendMessage("MESSAGE "+sanitizeMessage(message));
}
/**
Sends the server message CHANGE.
*/
public final void serverChangeNotification()
{
sendMessage("CHANGE");
}
/**
Sends the server message WIN.
*/
public final void serverWin()
{
sendMessage("WIN");
}
/**
Sends the server message LOSE.
*/
public final void serverLose()
{
sendMessage("LOSE");
}
/**
Sends LOOKREPLY.
This function must be called before the other look replies are sent.
*/
public final void serverLookReplyBegin()
{
sendMessage("LOOKREPLY");
try {
Thread.currentThread().sleep(evil_wait);
} catch (InterruptedException e) {
}
}
/**
Sends one line of the LOOK REPLY.
This function must be called multiple times, once for each part of a
look reply.
@param reply A single line of the look reply message.
*/
public final void serverLookReply(String reply)
{
sendMessage(sanitizeMessage(reply));
try {
Thread.currentThread().sleep(evil_wait);
} catch (InterruptedException e) {
}
}
/**
Sends the server message RENDERHINT.
Indicates a number of renderhint messages to follow.
@param n Number of renderhints to follow.
*/
public final void serverRenderHint(int n)
{
sendMessage("RENDERHINT "+n);
try {
Thread.currentThread().sleep(evil_wait);
} catch (InterruptedException e) {
// Ignore
}
}
/**
Sends a RENDERHINT.
Note that the two position arguments are relative to the player, so
(0, 0) indicates the spot the player is standing on. It can be for many
things, but the most useful would be to indicate the name of another
player. For instance if player 2 is standing one square to the right of
player 1; player 1 could get the following render hint messages:
\code
RENDERHINT 1
1 0 playername:"Mr. Foobar"
\endcode
Alternatively it could be used to convey more information about the map
itself. For example the following renderhint could be used to further
describe the tile the player is standing on, and the immediate adjacent
tiles.
\code
RENDERHINT 5
0 0 floor:stone,marble
1 0 floor:stone,marble,broken
-1 0 wall:wood,moldy
0 -1 floor:stone,marble,scratched
0 1 wall:wood
\endcode
Note: Any of this is completely optional.
@param rel_x X position relative to the player the hint applies to.
@param rel_y Y position relative to the player the hint applies to.
@param hint The render hint.
*/
public final void serverRenderHint(int rel_x, int rel_y, String hint)
{
sendMessage(rel_x+" "+rel_y+" "+sanitizeMessage(hint));
try {
Thread.currentThread().sleep(evil_wait);
} catch (InterruptedException e) {
// Ignore
}
}
protected void sendMessage(String m)
{
if (logging) {
System.out.println("ConnectionBase " + id + " sent \"" +
m + "\"");
}
m += "\n";
out.print(m);
out.flush();
}
protected void receiveMessage(String m)
{
if (logging) {
System.out.println("ConnectionBase " + id +
" received \"" + m + "\"");
}
String tmp[] = m.split(" ", 2);
String command = tmp[0];
String arg = ((tmp.length == 2) ? tmp[1] : null);
if (command.equals("HELLO")) {
if (tmp.length != 2) {
return;
}
clientHello(sanitizeString(arg));
} else if (command.equals("LOOK")) {
clientLook();
} else if (command.equals("PICKUP")) {
clientPickup();
} else if (command.equals("MOVE")) {
if (tmp.length != 2) {
serverFail("Needs direction");
return;
}
String dir = sanitize(arg, "[NESW]");
if (dir.length() > 0) {
clientMove(dir.charAt(0));
} else {
serverFail("Invalid direction");
}
} else if (command.equals("ATTACK")) {
if (tmp.length != 2) {
serverFail("Needs direction");
return;
}
String dir = sanitize(arg, "[NESW]");
if (dir.length() > 0) {
clientAttack(dir.charAt(0));
} else {
serverFail("Invalid direction");
}
} else if (command.equals("ENDTURN")) {
clientEndTurn();
} else if (command.equals("SHOUT")) {
if (tmp.length != 2) {
serverFail("Needs message");
return;
}
clientShout(sanitizeMessage(arg));
} else {
serverFail("Invalid command");
}
}
public static String sanitize(String s, String regex)
{
String rv = "";
for (int i=0; i<s.length(); ++i) {
String tmp = s.substring(i, i+1);
if (tmp.matches(regex)) {
rv += tmp;
}
}
return rv;
}
/**
Convenience function to strip all non-letter characters from a string.
@param s Input
@return The string with any non-letter characters removed
*/
public static String sanitizeString(String s)
{
return sanitize(s, "[a-zA-Z0-9-_:,]");
}
/**
Convenience function to strip all non-letter characters (except space
and some puncuation) from a string.
@param s Input
@return The string with any non-letter characters (except space, .
and :) removed
*/
public static String sanitizeMessage(String s)
{
return sanitize(s, "[a-zA-Z0-9-_ \\.,:!\\(\\)#]");
}
}
|