/**
* The game class with functionality to display, to coordinate and
* to play the game.
*
* User: Pascal
* Version: 1.4
* Date: 18.04.13
*
* Changes:
* 0.1 (07.03.13)
* - First implementation
* 1.0 (15.04.13)
* - Add map output
* - Add user input
* 1.1 (16.04.13)
* - Fix some minor bugs.
* - Create exit possibility in game
* - Beautify output
* 1.2 (16.04.13)
* - Replace unicode characters with constants.
* 1.3 (17.04.13)
* - Add map output for two maps side by side.
* - Fix some minor bugs.
* 1.4 (18.04.13)
* - Refactor map output.
* - Beautify console output.
*/
package game;
import entities.Map.FieldMap;
import entities.artificialIntelligence.AI;
import io.in;
import other.Const;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* The game class with functionality to display, to coordinate and
* to play the game.
*
* @author Pascal
* @version 1.4
*/
public class Game
implements IGame
{
public boolean IsRunning = true;
Scanner scan = new Scanner (System.in);
String nextGameState;
AI ai;
FieldMap map;
List<List<Character>> stringMap;
@Override
public void Initialize()
{
Options.ReadOptionsToProperties();
IsRunning = true;
ai = new AI(Options.AIlevel);
map = new FieldMap();
map.SetShipsRandomly();
stringMap = new ArrayList<List<Character>>();
stringMap = map.MapAsCharList(false);
}
@Override
public void LoadContent()
{
ai.SetShips();
}
@Override
public String Run()
{
Initialize();
LoadContent();
Render();
while (IsRunning)
{
Update();
Render();
}
Dispose();
return nextGameState;
}
@Override
public void Update()
{
// Get Win state of ai or player and generate output.
if (ai.GetMap().Defeated())
{
System.out.printf("\nYou have won.\n\n");
EndGame("Menu");
return;
} else if (map.Defeated())
{
System.out.printf("\nThe enemy have won.\n\n");
EndGame("Menu");
return;
}
// Get user input an process it.
if (!map.getHasHit())
{
Point coordinates;
while (true)
{
System.out.printf("\n(Help: type 'exit' to end the game.)\n");
System.out.printf("Choose your target: ");
String input = scan.nextLine();
// The user give and the ai has automatically won the game.
if (input.equalsIgnoreCase("exit"))
{
System.out.printf("\n---------------------------------\n");
System.out.printf(" You give up. The enemy has won.\n");
System.out.printf("---------------------------------\n");
EndGame("Menu");
return;
}
coordinates = in.TranslateMapCoordinates(input);
if (coordinates.x == -1 || coordinates.y == -1 || coordinates.x > map.MapSize.x || coordinates.y > map.MapSize.y)
System.out.println("This was not a valid coordinate. Try again.");
else if (ai.GetMap().BombField(coordinates.x, coordinates.y))
break;
}
}
// The ai bom the field until he has a possible target (it' not coast or already bombed).
if (!ai.GetMap().getHasHit())
while (!map.BombField(ai.DoWork(map))) { }
ai.Update();
stringMap = map.MapAsCharList(false);
}
/**
* Set the variable to end the game and set a specific game state.
* @param gameState The next gameState
*/
private void EndGame(String gameState)
{
IsRunning = false;
nextGameState = gameState;
System.out.printf("Press any key to continue...");
scan.nextLine();
}
@Override
public void Render()
{
// If the game is no more running do not render the output.
if (!IsRunning) return;
System.out.printf("\n\n");
RenderTwoMaps(map, ai.GetMap());
System.out.printf("\n" + ai.GetMap().getBombState() + "\n");
System.out.printf("Enemy: \"" + ai.GetState() + "\"\n");
}
/**
* Render the map with a given map list.
* @param map A list with a list of characters.
*/
private void RenderOneMap(List<List<Character>> map)
{
for (int i = 0; i < map.size(); i++)
{
String out = "";
if (i == 0)
{
out += WriteFirstMapRow(map.size() -1, 1);
}
else
{
out += WriteBorderLines(map.size() -1, 1);
}
System.out.printf(out);
// Write map coordinates at the beginning of a row
if (i == 0 || i == map.size() -1)
out = " ";
else
out = WriteLetterCoordinate(i);
// Write fields with map data.
for (int j = 0; j < map.get(i).size(); j++)
{
if (j == 0)
System.out.printf("" + out + Const.DLineV);
System.out.printf(" " + map.get(i).get(j) + " " + Const.DLineV);
}
System.out.printf("\n");
out = "";
if (i == map.size() -1)
{
out += WriteLastMapRow(map.size() -1, 1);
}
System.out.printf(out);
}
}
/**
* Render two maps in one row.
* @param map The first map (mostly from the player).
* @param enemyMap The second map (mostly from the enemy).
*/
private void RenderTwoMaps(FieldMap map, FieldMap enemyMap)
{
List<List<Character>> stringMap = map.MapAsCharList(false);
List<List<Character>> stringEnemyMap = enemyMap.MapAsCharList(true);
for (int i = 0; i < stringMap.size(); i++)
{
String out = "";
if (i == 0)
{
out += "Your map:";
for (int j = 0; j < stringMap.size(); j++)
out += " ";
out += " The enemy's map:\n\n";
out += WriteFirstMapRow(stringMap.size() -1, 2);
}
else
{
out += WriteBorderLines(stringMap.size() -1, 2);
}
System.out.printf(out);
// Write map data for two maps side by side
for (int maps = 0; maps < 2; maps++)
{
if (maps == 1)
out = " ";
else
out = "";
// Write map coordinates at the beginning of a row
if (i == 0 || i == stringMap.size() -1)
out += " ";
else
out += WriteLetterCoordinate(i);
// Write fields with map data.
for (int j = 0; j < stringMap.get(i).size(); j++)
{
if (j == 0)
System.out.printf("" + out + Const.DLineV);
if (maps == 0)
System.out.printf(" " + stringMap.get(i).get(j) + " " + Const.DLineV);
else
System.out.printf(" " + stringEnemyMap.get(i).get(j) + " " + Const.DLineV);
}
}
System.out.printf("\n");
out = "";
if (i == stringMap.size() -1)
{
out += WriteLastMapRow(stringMap.size() -1, 2);
}
System.out.printf(out);
}
}
/**
* Create the first line of a map. The coordinates and the top border
* @param width Width of the map.
* @param maps Number of writing maps.
* @return Returns a string which can be written out on the console.
*/
private String WriteFirstMapRow(int width, int maps)
{
String out = "";
for (int i = 0; i < maps; i++)
{
// Write the coordinates on top of the map
out += " ";
for (int j = 0; j < width; j++)
{
if (j == 0)
out += " " + Const.DLineV;
else if (j > 9 && j < 100)
out += j + " " + Const.DLineV;
else if (j > 99)
out += j + Const.DLineV;
else
{
// Write numbers from 1-9
out += " " + j + " " + Const.DLineV;
}
}
out += " ";
}
out += "\n";
//Write the top border
for (int i = 0; i < maps; i++)
{
out += " " + Const.DCornerRD;
for (int j = 0; j < width; j++)
{
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCross;
}
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCornerLD;
out += " ";
}
out += "\n";
return out;
}
/**
* Write the borderlines between the field values;
* @param width Width of the map.
* @param maps Number of writing maps.
* @return Returns a string which can be written out on the console.
*/
private String WriteBorderLines(int width, int maps)
{
String out = "";
for (int i = 0; i < maps; i++)
{
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCross;
for (int j = 0; j < width; j++)
{
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCross;
}
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCrossL;
out += " ";
}
out += "\n";
return out;
}
/**
* Write the last row between the field values;
* @param width Width of the map.
* @param maps Number of writing maps.
* @return Returns a string which can be written out on the console.
*/
private String WriteLastMapRow(int width, int maps)
{
String out = "";
for (int i = 0; i < maps; i++)
{
out += " " + Const.DCornerUR;
for (int j = 0; j < width; j++)
{
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCrossU;
}
out += "" + Const.DLineH + Const.DLineH + Const.DLineH + Const.DCornerUL;
out += " ";
}
out += "\n";
return out;
}
/**
* Write the letter coordinates at the beginning of a row.
* @param row The row coordinate as a number.
* @return Returns a formatted string with the coordinates.
*/
private String WriteLetterCoordinate(int row)
{
String out;
if (row < 27)
out = " " + io.out.TranslateNumberCoordinate(row) + " ";
else if (row % 26 == 0)
{
out = io.out.TranslateNumberCoordinate((row / 26) - 1);
out += "Z ";
}
else
{
out = io.out.TranslateNumberCoordinate((row / 26));
out += io.out.TranslateNumberCoordinate((row % 26)) + " ";
}
return out;
}
/**
* Frees resources.
*/
@Override
public void Dispose()
{
ai.Dispose();
stringMap.clear();
map.Dispose();
}
}