?
So hab das design komplett überarbeitet und neu angefangen. Ich bin endlich damit zufrieden und es funktioniert alles nur gibs noch keine KI.
Ich hab die verschmelzung von den ganzen managern zu einer klasse für sinvoll gehalten, da ich damit nur einen prozess,ein spiel beschreiben will und damit nicht mehrere spiele,prozesse vllt au von ganz anderen typen verwalten will.
Irgentwelche einwände gegen das klassendesign,algorithmen oder das steuerungssystem des spiels und verbesserungsvorschläge?
Wenn ich das nochmal in C++ mach hab ich sicher mehr leser xD
Version 2:
Symbol
public class Symbol
{
private char symbol;
public Symbol(char s) { symbol = s; }
public char GetSymbol() { return symbol; }
}
Player
public abstract class Player
{
private int points;
private Symbol symbol;
public Player(char s)
{
points = 0;
symbol = new Symbol(s);
}
// Wäre es vllt. sinnvoller das Symbol-Obj zurückzugeben?
public char GetSymbol() { return symbol.GetSymbol(); }
public void CountUp() { points++; }
public abstract void Turn(TicTacToe g);
}
Field
public class Field
{
private boolean visible;
private int rows, columns;
private char [][] table;
public Field(int r, int c)
{
rows = r;
columns = c;
table = new char[rows][columns];
visible = true;
Init();
}
public void Init()
{
for(int i=0 ; i<rows ; i++)
{
for(int j=0 ; j<columns ; j++)
{
table[i][j] = ' ';
}
}
}
// Statt einem char array könnte man ebenfalls auch ein symbol array nutzen doch wäre dies sinnvoll?
public void SetCell(Player p, int r, int c) { table[r][c] = p.GetSymbol(); }
public char GetCell(int r, int c) { return table[r][c]; }
public int GetRows() { return rows; }
public int GetColumns() { return columns; }
public int GetEmptyCells()
{
int CountOfEmptyCells = 0;
for(int i=0 ; i<rows ; i++)
{
for(int j=0 ; j<columns ; j++)
{
if(GetCell(i,j) == ' ') { CountOfEmptyCells += 1; }
}
}
return CountOfEmptyCells;
}
// Wäre es besseres OOP Design, wenn ich überall klassenintern Set und GetCell benutze statt direkt aufs array zuzugreifen?
public void Show()
{
if(visible == true)
{
for(int i=0 ; i<rows ; i++)
{
System.out.print("|");
for(int j=0 ; j<columns ; j++)
{
System.out.print(table[i][j]);
System.out.print("|");
}
System.out.print("\n");
}
}
}
public void SetVisibility(boolean status) { visible = status; }
public boolean IsVisible() { return visible; }
}
HumanPlayer
import java.util.Scanner;
public class HumanPlayer extends Player
{
private Scanner sc;
public HumanPlayer(char s)
{
super(s);
sc = new Scanner(System.in);
}
@Override
public void Turn(TicTacToe g)
{
int r,c;
System.out.print("Zeile: -- ");
r = sc.nextInt();
System.out.print("Spalte: - ");
c = sc.nextInt();
if( g.Turn(r-1,c-1) == false )
{
System.out.println("Ungültige Eingabe, nochmal der selbe Spieler! Etwas zum weiterspielen eingeben...");
sc.next(); // kann ich das noch anders verzögern damit es in Run() nicht sofort wegemacht wird durch \f ?
}
}
}
ComputerPlayer
public class ComputerPlayer extends Player
{
public ComputerPlayer(char s)
{
super(s);
}
@Override
public void Turn(TicTacToe g)
{
}
}
Main
public class Main
{
public Main()
{
main();
}
public void main()
{
HumanPlayer A = new HumanPlayer('X');
HumanPlayer B = new HumanPlayer('O');
Field Board = new Field(3,3);
TicTacToe game = new TicTacToe(A,B,Board);
if( game.Run() == false ) { System.out.println("Error!"); }
}
}
TicTacToe
public class TicTacToe
{
private Field f;
private Player p1, p2, current;
public TicTacToe(Player a, Player b, Field c)
{
p1 = a;
p2 = b;
current = p1;
f = c;
}
public boolean Turn(int r, int c)
{
if(f.GetCell(r,c) == ' ') { f.SetCell(current,r,c); }
else { return false; }
if(p1 == current) { current = p2; }
else { current = p1; }
return true;
}
public boolean IsEnd()
{
int CountOfEmptyCells = f.GetEmptyCells();
if( CheckSeries( p1.GetSymbol() ) == true )
{
System.out.println("Spieler "+p1.GetSymbol()+" hat gewonnen!");
p1.CountUp();
return true;
}
else if( CheckSeries( p2.GetSymbol() ) == true )
{
System.out.println("Spieler "+p2.GetSymbol()+" hat gewonnen!");
p2.CountUp();
return true;
}
if(CountOfEmptyCells > 0) { return false; }
else { return true; }
}
public boolean CheckSeries(char s)
{
/* Eigentlich wollte ich GetRows und GetColumns vermeiden, da die verwaltung die aufgabe von field ist, doch sah ich keine andere lösung wie seht ihr das? */
int needed = 3; // Zahl der benötigten Symbole in einer reihe zum sieg
// Von links nach rechts
for(int i=0 ; i<f.GetRows() ; i++)
{
for(int j=0 ; j<f.GetColumns() ; j++)
{
int count = 0;
char [] Cells = new char[needed];
for(int e=0 ; e<needed ; e++)
{
if(i >= 0 && i < f.GetRows())
{
if(j >= 0 && j+e < f.GetColumns())
{
Cells[e] = f.GetCell(i,j+e);
if(Cells[e] == s) { count++; }
}
}
}
if( count == needed ) { return true; }
}
}
// von oben nach unten
for(int i=0 ; i<f.GetRows() ; i++)
{
for(int j=0 ; j<f.GetColumns() ; j++)
{
int count = 0;
char [] Cells = new char[needed];
for(int e=0 ; e<needed ; e++)
{
if(i >= 0 && i+e < f.GetRows())
{
if(j >= 0 && j < f.GetColumns())
{
Cells[e] = f.GetCell(i+e,j);
if(Cells[e] == s) { count++; }
}
}
}
if( count == needed ) { return true; }
}
}
// diagonal
for(int i=0 ; i<f.GetRows() ; i++)
{
for(int j=0 ; j<f.GetColumns() ; j++)
{
int count = 0;
char [] Cells = new char[needed];
for(int e=0 ; e<needed ; e++)
{
if(i >= 0 && i+e < f.GetRows())
{
if(j >= 0 && j+e < f.GetColumns())
{
Cells[e] = f.GetCell(i+e,j+e);
if(Cells[e] == s) { count++; }
}
}
}
if( count == needed ) { return true; }
}
}
return false;
}
public boolean Run()
{
while(IsEnd() == false)
{
if(current == p1) { p1.Turn(this); }
else if(current == p2) { p2.Turn(this); }
else { return false; }
System.out.print("\f");
f.Show();
System.out.print("\n");
}
return true;
}
}
Mfg Progger33