Adding an #property in an NSObject as a pointer to an #property in another NSObject - iphone

I have a 1v1 game that I am updating to 3 players (eventually 4) and I am running into an issue with player tracking when the user is playing against 2 computer players.
I have a Game NSObject that handles all of the major code for the gameplay, and also controls the actions of the computer players. In the past, I have been good with 2 properties in Game.h (User and Opponent), and now I have 3 (User, Opponent, Opponent2). Declared like the following:
#property (retain) Player *user;
The problem comes in when I need to use a method that controls computer player actions. As an example, when the computer player needs to bid, it must know the bids and some other info about it's opponents. A snippet of the old code is:
- (void)computerBiddingObjects {
// ... other stuff
if (_opponentPoints == 110 && _userPoints >= 90 && _userDidBid != YES) {
bid = bidTwenty;
} else if (_opponentPoints == 115 && _userPoints >= 90 && _userDidBid != YES) {
bid = bidTwentyFive;
}
// ... other stuff
}
In order to get information for the opposing players, a thought I had was to add 2 new properties to Player.h in order to track each player's opponents (opponent1 and opponent2). My question is, if I set the properties for each Player as in:
_opponent.opponent = _user;
_opponent.opponent2 = _opponent2;
Can I refer to them and/or set their individual properties in both contexts? Would these statements be equivalent given the above:
_opponent.opponent.didBid = YES;
_user.didBid = YES;
Also, could I access the Player objects properties like this new version of the bidding code snippet?
- (void)computerBiddingObjectsForOpponent:(Player *)opponent {
// ... other stuff
if (opponent.points == 110 && self.currentBid < bidTwenty && ((opponent.opponent1.points >= 90 && opponent.opponent1.didBid != YES) || (opponent.opponent2.points >= 90 && opponent.opponent2.didBid != YES))) {
bid = bidTwenty;
} else if (opponent.points == 115 && self.currentBid < bidTwentyFive && ((opponent.opponent1.points >= 90 && opponent.opponent1.didBid != YES) || (opponent.opponent2.points >= 90 && opponent.opponent2.didBid != YES))) {
bid = bidTwentyFive;
}
// ... other stuff
opponent.bid = bid.
}
Am I way off base/off track? Is there an easier way to do this?

This is indeed equivalent.
But ...
The didBid will be set by the other players as well (as they hold the same reference to that player, overwriting what each player has set.
You are creating a retain cycle you might need to break manually (or set the opponents properties as weak).
It might be best if each player will keep a "Strategy" object for each opponent, and that strategy will have a reference to the player. This way, each player may have different strategy against any other player.

Related

How can I block a specific user in random match making by using Photon Engine ?

We are making random match making game by using Photon engine. We want to match players with different users in a certain amount of time. If PlayerA plays with PlayerB they cannot play again for 30 minutes. What is the best way of doing this kind of system ?
We try some algorithms but it doesn't fit well.
public override void OnJoinedRoom()
{
if(PhotonNetwork.isMasterClient)
StartCoroutine("StartWaiting");
theSameGame = false;
var photonPlayer = PhotonNetwork.Instantiate("PhotonPlayerKO", Vector3.zero, Quaternion.identity, 0) as GameObject;
photonPlayer.name = "Local Player";
if(PhotonNetwork.playerList.Count() > 1 && !PhotonNetwork.isMasterClient)
photonViewOfManager.RPC("MyNameIs", PhotonTargets.Others, PlayerInfos.thePlayersName);
//Sending player name to other player to check whether this name is playable or not ?
if(!PhotonNetwork.isMasterClient)
StartCoroutine("CheckError");
}
It works but there are some disadvantages such as time consuming vs.. Any ideas for better solutions ?
Solution can be found here: documentation
You need to use SQL Lobby Type:
Creating room:
RoomOptions roomOptions = new RoomOptions();
roomOptions.MaxPlayers = expectedMaxPlayers;
// in this example, C0 might be 0 or 1 for the two (fictional) game modes
roomOptions.customRoomProperties = new ExitGames.Client.Photon.Hashtable() { { "C0", 1 } };
roomOptions.customRoomPropertiesForLobby = new string[] { "C0" }; // this makes "C0" available in the lobby
// let's create this room in SqlLobby "myLobby" explicitly
TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby);
lbClient.OpCreateRoom(roomName, roomOptions, sqlLobby);
Joining room:
TypedLobby sqlLobby = new TypedLobby("myLobby", LobbyType.SqlLobby); // same as above
string sqlLobbyFilter = "C0 = 0"; // find a game with mode 0
lbClient.OpJoinRandomRoom(null, expectedMaxPlayers, matchmakingMode, sqlLobby, sqlLobbyFilter);
// more filter variations:
// "C0 = 1 AND C2 > 50"
// "C5 = \"Map2\" AND C2 > 10 AND C2 < 20"
In your case you just need to replace C0 with list of the players who are blocked, and updated this list every time new user plays the game, and removes him from the list after 30 minutes.
If you will face some other issues with that, let us know.

Doubly linked list: swap two adjacent nodes without a temp variable

This code is C++ - in so much as it uses classes/objects. In reality it is all just C, since I was playing around, implementing a doubly linked list without using the STL.
The language shouldn't matter. What is bothering me is that I used a temporary variable.
Can anyone improve this code so that no temporary variable is needed? It is a simple bubble sort, but what concerns me is swapping two adjacent nodes of a doubly linked list.
class LinkedListItem *linkedListItem;
bool swapped;
do
{
swapped = false;
for (linkedListItem = uniqueWords.GetHead();
linkedListItem != NULL;
linkedListItem = linkedListItem->GetNext())
{
if (linkedListItem->GetNext() != NULL)
{
if (linkedListItem->GetWordCount() < linkedListItem->GetNext()->GetWordCount())
{
// Swap items to bubble smaller value up.
// Rats!! I can't seem to do it by juggling pointers without a temp variable :-(
// ToDo: figure out how!
class LinkedListItem *itemAfterNext;
if (linkedListItem->GetNext() == NULL)
itemAfterNext = NULL;
else
itemAfterNext = linkedListItem->GetNext()->GetNext();
if (uniqueWords.GetHead() == linkedListItem)
uniqueWords.SetHead(linkedListItem->GetNext());
if (uniqueWords.GetTail() == linkedListItem->GetNext())
uniqueWords.SetTail(linkedListItem);
////--------- start swap -----------
if (linkedListItem->GetPrev() != NULL)
linkedListItem->GetPrev()->SetNext(linkedListItem->GetNext());
if (linkedListItem->GetNext()->GetNext() != NULL)
linkedListItem->GetNext()->GetNext()->SetPrev(linkedListItem);
linkedListItem->GetNext()->SetPrev(linkedListItem->GetPrev());
linkedListItem->GetNext()->SetNext(linkedListItem);
linkedListItem->SetPrev(linkedListItem->GetNext());
linkedListItem->SetNext(itemAfterNext);
////--------- end swap -----------
swapped = true;
}
}
}
} while (swapped == true);

Unity3D: Automatic target according to price

I've been working on a simulator in Unity3D and i need a customer object to be able to automatically find the shop object with the lowest price.
I've done a little testing on this myself and found it to be rather difficult to achive. So i was hoping someone could help me tweak my code a bit further in the right direction? :)
Here's the code i've got so far:
var cityName : String;
var shopScript : MarketScript;
function FindShopPlace () : GameObject //Make a queueing system
{
var max : float;
var target : GameObject;
var gos : GameObject[];
var goScript : MarketScript;
gos = GameObject.FindGameObjectsWithTag("market");
for (var go : GameObject in gos)
{
goScript = go.GetComponent(MarketScript);
if (goScript.cityName == cityName)
{
if (goScript.resalePrice >= max && goScript.cityName == cityName)
{
max = goScript.resalePrice;
}
if (goScript.resalePrice < max && goScript.cityName == cityName)
{
print ("test");
target = go;
}
}
}
shopScript = target.GetComponent(MarketScript);
return target;
}
Currently with this code, the target is never found and assigned. I get the following NullReferenceException from line number 3 from the bottom:
NullReferenceException: Object reference not set to an instance of an
object ConsumerScript.FindShopPlace () (at
Assets/_MyAssets/_Scripts/ConsumerScript.js:268) ConsumerScript.Update
() (at Assets/_MyAssets/_Scripts/ConsumerScript.js:96)
You get a NullReferenceException because target was never set to any object.
What you are doing in your loop is (1) finding the maximum price and (2) finding the last Object after maximum that is smaller than the maximum.
So if your prices in order are 1, 2, 3 target will never be set because in each step you are setting the maximum to the new value and are never setting target. Even when set its not necessarily the cheapest. Consider the prices 1, 3, 2.
First Step: Set maximum to 1
Second Step: Set maximum to 3
Third Step: Set target to the GameObject with price 2
If you get errors like this try out simple examples like this to get to the bottom of things. Also you are using the variable maximum(comparing the first time) without ever setting it to anything, not sure if this works in Javascript(it might) but its bad practice
What you really want isnt finding the maximum price or minimum price but the GameObject with the lowest resalePrice.
var min : float;
var success : boolean;
var firstHit : boolean;
...
success = false;
firstHit = true;
for (var go : GameObject in gos)
{
goScript = go.GetComponent(MarketScript);
if (goScript.cityName == cityName)
{
success = true;
if(firstHit) // alternatively to this would be to set minimum to a value that is higher than every possible price ( thats also what i meant with you shouldnt use max without setting it to anything)
{
min = goScript.resalePrice;
target = go;
}
else
{
if (goScript.resalePrice < min )
{
min = goScript.resalePrice;
target = go;
}
}
}
}
if(success)
{
shopScript = target.GetComponent(MarketScript);
return target;
}
else
{
// TODO: handle the case that there isnt a shop in the city.
// Maybe give an error Message with Debug.Log if this isnt supposed to happen
return null;
}

How can I add a way to track a collection of entities and flag them on/off (to signal if a process has been done to them)?

My first idea is extend the partial class 'Step' which is an entity. I could add a bool property and then set that true/false as I complete processing on them.. But then every time I regenerate the DBContext after making changes to the DB won't I have to manually keep doing this? OR is some other way.. The code below explains what I am trying to do
if ((si.StepID == 20) || (si.StepID == 23) || (si.StepID == 24))
{
//Step is a process. Each Step must be run in order
//get list of steps in tasks in RUN (1,2,3,4...) order
int stepToRun = 0;
var stepsInTask = InstanceExpert.GetAllStepsInTaskOrderedByRunOrder(ti.TaskInstanceID);
//Get which step is next to be processed
foreach (Step s in stepsInTask)
{
//get the stepToRun
//Need to extend STEP Entity property with a bool??
}
//Take that step and run the specific function
if (stepToRun == 20)
{
}
if (stepToRun == 23)
{
}
if (stepToRun == 24)
{
}

IsEqual Method Sent to Deallocated Instance When Trying to Add Object To MutableOrderedSet

I have an NSMutableOrdered set that holds two types of objects (that I created), Pieces and Others.
Piece and Other both have their isEqual method overridden like so:
Piece:
- (BOOL)isEqual:(Piece *)object
{
if (([title isEqualToString:[object title]])
&& ([composer isEqualToString:[object composer]])
&& (major == [object major])
&& (tempo == [object tempo])
&& (pieceKey == [object pieceKey])
&& (pieceTime == [object pieceTime]))
return YES;
else
return NO;
}
Other:
- (BOOL)isEqual:(Other *)object
{
if (([title isEqualToString:[object title]])
&& ([subTitle isEqualToString:[object subTitle]])
&& ([description isEqualToString:[object description]])
&& (otherTime == [object otherTime]))
return YES;
else
return NO;
}
I also override the hash of both classes to create a unique hash for each instance (by getting the int value of the ivars and adding them).
In my app, An Other is removed from the set, then when I try to add a piece to the set, I get this:
-[Other isEqual:]: message sent to deallocated instance 0x80d5680
here is the hash method:
- (NSUInteger)hash
{
NSUInteger prime = 31;
NSUInteger result = 1;
result = prime * (result + [title intValue]);
result = prime * (result + [composer intValue]);
result = prime * (result + major);
result = prime * (result + tempo);
result = prime * (result + pieceKey);
result = prime * (result + pieceTime);
return result;
}
If anybody knows why this is happening, I would really some help.
Thanks,
This is not really an answer, but it will help us to find the problem. Some questions:
Are you sure that 0x80d5680 is the instance that was previously removed?
How do you remove it from the set?
Do you modify the state of your objects after adding them?
Are you sure that your hashes are unique (sum of int value of ivars sound sounds suspicious).
Finally, make sure that your objects obey this rule:
If two objects are equal, they must have the same hash value. This last point is particularly important if you define isEqual: in a subclass and intend to put instances of that subclass into a collection. Make sure you also define hash in your subclass.
See NSObject Protocol Reference for more information.
I believe isEqual is called on members as part of the set comparison, as a set is a group of unique items. Perhaps you should add the member to the new set before removing from the old one?
Hope this helps!