I have a relatively simple database containing a Player table (a single field username) and a Game (a single field date) one. As a Player can take part in multiple Game and a Game can be played by multiple Player, I use a many-to-many relationship where an extra column score is added to the joined table to store the score of a Player in a Game.
In my Java code, I have obviously a Player class with field username and a Game one with field date. However, I do not know if I should create a third class for the join table or if I should add a List<Player>attribute within the Game class along with a list of List<Integer> to store the score.
EDIT: Example
Player table:
player_id player_name
1 Bob
2 Lea
3 John
Game table:
game_id game_date
1 20/08/2017
2 19/08/2017
Joined table:
game_id player_id score
1 1 50
1 2 35
2 1 50
2 3 29
I would not create a separate class for the joined table. I would go with a Map<Player, Integer> in the Game class to hold the players in the game and their respective scores.
Something like so (simple, no error checks):
class Game {
Map<Player, Integer> playerScores = new HashMap<>();
void addPlayer(Player p) {
playerScores.put(p, 0);
}
void incrementScore(Player p, int increment) {
int newScore = getScore(p) + increment;
playerScores.put(p, newScore);
}
int getScore(Player p) {
return playerScores.get(p);
}
// etc...
}
Why you don't add score attribute to Player class?
1 player probably can't be in 2 games at same time, right?
Reason why I say this is because you would then need only one list, with your approach you end up with 2 lists which are not directly connected. Yes I know that you will place player and his score at same index but this complicates things a lot.
Situation that I can think of just now is showing scoreboard, in other to show which player has highest score you need to sort it, how would you do it with your 2 lists?
In some complicated way for sure, you would first need to connect first and second list in some structure like map or something, probably you would need to use TreeMap<Integer, List<Players>>, where Integer would be the score and for each score you would need List of players because 2 or more players could have same score.
By having score in your Player class you avoid this complications and make accessing score of each player very easy, once they leave game you simply take score, save in database and set back to 0.
Related
I am an engineering student. I have just started Java with the school. We have an exam next week. I have some questions about our preparing project.
I'd be very happy IF you could patiently reply to them.
Create a Java class called Lane with three fields:
o days: a read-only string collection containing the names of days [ How to make a read-only string ]
How to put into my index file? ( Normally I learned like <% between those %> but get some error messages..
How do I make reservation Array?
reservations: a collection to store the reservations (e.g. a twodimensional string array or a
list of string lists), where the number
of rows equals the number of days, and the number of columns
equals the number of times. The i. row - j. column cell’s value is
„available” if the i-th day’s j-th time interval is still available, or
the username of the reserving person otherwise.
Last Question ; How to Make such as below the picture.
Reserved text if the lane is already reserved by someone else for
that day and time (different username than the user’s),
o a Reserve link if the lane is available,
o a Cancel link if the lane is reserved by this user.
If I understand correctly you are stuck on creating the reservations table?
This is the class I came up with that is pretty close to yours.
I'm not sure what you mean by read-only string, I just used constants (final keyword)
We create a 2d array the same way we would a normal array (using []), except we do it twice. When using 2d arrays in Java the first value refers to rows an the second one to columns (new String[number_of_rows][number_of_columns]).
We than set up 3 possible values for ReservedState
We populate our array in the constructor
We also set up 3 methods we can use to change values in the table.
import java.util.Arrays;
public class Lane {
final String[] days = {"Monday", "Tuesday", "..."};
final String[] times = {"5-6 PM", "6-7 PM"};
//this is where we create our reservations table
String[][] reservations = new String[days.length][times.length];
enum ReservedState {
RESERVED("Reserved"),
RESERVE("Reserve"),
CANCEL("Cancel");
private String name;
ReservedState(final String name){
this.name = name;
}
}
//constructor
public Lane(){
//Fill the table with default values
for (String[] row: reservations)
Arrays.fill(row, ReservedState.RESERVE.name);
}
public void SetReservationToReserved(int dayIndex, int timeIndex){
reservations[dayIndex][timeIndex] = ReservedState.RESERVED.name;
}
public void SetReservationToCancel(int dayIndex, int timeIndex){
reservations[dayIndex][timeIndex] = ReservedState.CANCEL.name;
}
public void SetReservationToReserve(int dayIndex, int timeIndex){
reservations[dayIndex][timeIndex] = ReservedState.RESERVE.name;
}
}
About Including your code in the index,
It would be very useful if you could show us the error you are getting. I think you just forgot to instantiate your class before using it.
<%
Lane lane = new Lane();
//lane.SetReservationToReserved(1,1); Call this to set a reservation
//lane.SetReservationToCancel(row number, column number); Call this to cancel a reservation
//lane.SetReservationToReserve(1,1);...
%>
As for rendering the table with html and jsp I would recommend this resource. It has several good examples on the topic.
https://www3.ntu.edu.sg/home/ehchua/programming/java/JSPByExample.html
I want to make a java application, which is addressed for an esports competition. Specifically this application will be for a teamspeak server.
I want users on a channel to be sorted into groups of 5 (they will be identified by a uniqid and a number representing the skill level).
Thus, when 5 users are between skill levels 1 - 3 to be placed in one group, the next ones in another group (each of 5), and until that list / map will no longer be able to be made groups of 5.
Can you help me with an idea? I know how to get the uniqid from the teamspeak server, as well as the skill level, but I don't know how to randomly group them and meet that skill level condition.
I tried a hashmap but it failed.
HashMap<Integer, Integer> teams = new HashMap<>();
for(Client c : api.getClients()){
if(c.getChannelId() == 2170){
if(api.getChannelByNameExact("[LOBBY] Cauta echipa",true).getTotalClients() >= 5) {
if (c.isInServerGroup(Integer.parseInt(Configuration.info().getProperty("SILVER1")))) {
teams.put(c.getId(), 1);
}
if (c.isInServerGroup(Integer.parseInt(Configuration.info().getProperty("SILVER2")))) {
teams.put(c.getId(), 2);
}
if (c.isInServerGroup(Integer.parseInt(Configuration.info().getProperty("SILVER3")))) {
teams.put(c.getId(), 3);
}
if (c.isInServerGroup(Integer.parseInt(Configuration.info().getProperty("SILVER4")))) {
teams.put(c.getId(), 4);
}
if (c.isInServerGroup(Integer.parseInt(Configuration.info().getProperty("SILVERE")))) {
teams.put(c.getId(), 5);
}
while(teams.size() >= 5){
teams.forEach((key, value) -> {
System.out.println("Key : " + key + " Value : " +value);
if(value > 1 && value < 5){
teams.
}
});
}
teams.clear();
}
}
}
Exemple:
If on a teamspeak channel there are 20 people with skill level in 1 lvl -18 lvl, the robot will build teams of 5 members with similar skill level (with a margin of + - 1 level).
For example, if I have skill level 5, and on the channel there are at least 4 people with skill level between 3-5, the 5 people (including myself) will be added to a list or array or whatever.
After we made the team of 5 people, the program will continue to run and form teams of 5 people with similar skill level, until it will no longer be possible (there will be no 5 people in the main room).
On my mind you should divide on two groups(ArrayLists) hightlevel and lowlevel, for this create function and check skills level(skills>3)=>hight else=>low;
After create HashMap team; where keys - ids; and value - numbers of group;
With operator for and function MathRandom complete first group; value++; Continue while you have available people.
Change value +1(it will be next group) complete HashMap with next Array, using MathRandom();
This is working, if ids - Integer and unique. of course you have to delete from Array element after putting in the map
Also you can try to manage with databases MongoDB:
1.Create two datas: high and low level
2. With Pagebale create page items on page 5; number of page will be your group number. Use method unsorted
I am working on a card game and I'm facing a problem regarding the gameplay. So basically the rules of the game are that who finishes the hand first gets placed first, second second and so on. I am keeping a list of the players in a List<Player, and if one finishes I just skip the turn from him (checks if >= 1 cards in hand), until 1 player is left. Now, the rule is that if one finishes with an unbeatable card/move or everyone else passes for example, the turn should be to the next player and he is free to make a move. I've been struggling and haven't found a proper solution yet. How to achieve this?
I am currently saving the waste (last played list of cards) cards into a List<Card>, and I am keeping a Player instance lastPlayed for the last playing player, and a Player instance hasTurn for the current player on turn.
The turns are shifted in this method inside the Game class:
public void determineNextPlayerTurn()
{
if(playersLeft() > 1)
{
int i = players.indexOf(hasTurn) + 1;
if(i == 4)
i = 0;
hasTurn = players.get(i);
if(hasTurn.isPlaying())
{
if(!isHumanTurn())
{
display.disableButtons();
AI temp = (AI)players.get(i);
temp.onPlayerTurn(this);
}
else
display.enableButtons();
}
else
{
determineNextPlayerTurn();
}
}
else
newGame(0);
The method of AI that is called when it is an ai's turn:
public void onPlayerTurn(Game game)
{
selectCardsToPlay(game.getWaste(), game.getLastPlayedPlayer());
if(getSelectedCards().isEmpty())
{
game.determineNextPlayerTurn();
}
else
{
if(Moves.canBePlayed(getSelectedCards(), game.getWaste(), this, game.getLastPlayedPlayer()))
{
playMove(game);
game.determineNextPlayerTurn();
}
else
game.determineNextPlayerTurn();
}
}
While for the user, nothing is called as the determineNextPlayerTurn() is called within the ActionListener of the playing buttons (Play, Pass).
Note: Currently like this, if the scenario occurs with the human last playing there will be a stackoverflow for the reason that every ai is doing a Pass. Every other code is fine for now, but I need help with implementing a simple solution to that specific case, and if I am doing something wrong I am open.
Why don't you have a counter for the number of "passes" that are executed and then compare that to the number of players. If the passes are equal to the number of players - 1 then that would mean that following player should be free to make a move. Also what is an "unbeatable move" if there is such a thing then wouldn't you be able to classify the turn as that and then attach a boolean that checks the player for whether or not they have made one of these types of moves?
i am facing problem with implementation of tree used for mini-max algorithm for my AI module.
The tree I need to write will have 4 levels: root(0) - AI move(1) - player move(2) and AI move(3). Every level will contain n of children and will have fields like(Board state, field rate and coordinates to move). With my calculations on the third level of tree possible number of children would be about 25.000. How should I implement this?
At the moment I've implemented 3 different ArrayLists of Objects, each list for specific level:
firstDepthList - contains Objects with possible board state, field rate and coordinates to move);
secondDepthList contains Objects with possible board state(for every element from firstDepthList), field rate and coordinates to move; and
thirdDepthList which contains Objects like above for every
element from secondDepthList. Of course I've linked lists together for
board and moves continuity.
Or maybe you would recommend better solution?
Mini-max algorithm needs only one value: max (or minimum, depends on level number). You don't have to store all tree.
It can be implemented as recursive function. And no creating many states, only one boardState using (for example, chess figure move from A to B may be reverted)
double getRating(BoardState state, int currentPlayer, int depth){
//current player has to be 1 or -1
if (depth <= 0){
return state.positionRating();
}
double bestRating = -Double.MAX_VALUE;
for(Move m: state.possibleMoves(currentPlayer)){
state.apply(m); // modify state
double rating = currentPlayer * getRating(state, -currentPlayer, depth-1);
// player 1 wants to have biggest number, player -1: lowest
bestRating = Math.max(bestRating, rating);
state.revert(m) // restore state
}
return bestState*currentPlayer;
}
I have a score board like so :
int time = 15;
private ScoreboardManager sbManager;
private Scoreboard scoreBoard;
private Objective obj;
private Score s0;
public void init(Player player) {
sbManager = Bukkit.getScoreboardManager();
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
player.setScoreboard(scoreBoard);
Bukkit.getScheduler().scheduleSyncRepeatingTask(this, new Runnable(){
public void run() {
time--;
updateScoreBoard(player);
System.out.println(time);
}
},20, 20);
}
And whenever I try to update it, it just dosen't work and btw my score board is a "fancy" one, so it should look like :
Time = time 6 <- the '6' is the default minecraft score.
Here's an example of my update method:
public void updateScoreBoard(Player p){
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time =" + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}
Because you're using scoreboards in an unconventional way, things are bound to get tricky. By "fancy" I assume you mean the scoreboards which display a score's name and value right next to each other on the left side, which is done by placing the actual score value inside the name String of the score (like you have already done).
The problem with your code specifically is that you are not actually changing the value of the existing score entry (since that value is set to 6 to keep the entry in the same row of the display) but creating a new score entry every time you update the display, since score entries are identified by their name and not their score value (this is required so that different score entries can have the same value, for example a player can have a "bank balance" score with a value of 2 and an "amount of deaths" score with a value of 2).
If this weren't the case for example, your new score entry with name "Time = 14" and a score value of 6 would override the previous score entry with name "Time = 15" because of the identical score value, but this is not the case.
When I tested your code snippet, more rows (score entries) were added until the display filled to maximum capacity. I can only assume this is what you meant by your code "acting weird" since you didn't elaborate on the expected and observed results of your code.
You'll want to remove the previous score entry with the outdated value. Because the API is not intended to be used this way, one cannot simply remove a score entry from an objective (resetting the score doesn't remove the entire entry).
You'll therefore need to create a new scoreboard with a new objective etc. every time you want to update a single "fancy" score entry. This also means that all scores displayed in the scoreboard need to be kept track of independently and re-added and re-set to the new scoreboard whenever any other "fancy" score is updated.
These changes to your updateScoreboard method did the trick for me:
public void updateScoreBoard(Player p) {
scoreBoard = sbManager.getNewScoreboard();
obj = scoreBoard.registerNewObjective("ScoreBoard", "dummy");
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
obj.setDisplayName("Test");
s0 = obj.getScore(Bukkit.getOfflinePlayer("Time = " + time));
s0.setScore(6);
p.setScoreboard(scoreBoard);
}
Note that this method only fixes the immediate issue of more entries being added, if you want more "fancy" and possibly even normal score entries, all of those will need to be handled respectively.
All this extra work and having meaningless numbers/values always on the right of the display seem like a large trade-off just to remove a little whitespace between a score's name and value.
Some other tips: You don't need to update the sbManager variable every time you initiate the scoreboard for a new player, the manager is always the same object, so using Bukkit.getScoreboardManager() once should suffice.