Tic tac toe programming iOS - ios

For some reason the function the checkForWin is returning always a NO.
Because of that I am not able to retrieve the winner.
Else if suggest a different logic to judge winner
I am using this function every time user puts up a symbol
-(BOOL) checkForWin{
NSLog(#"yes");
// HORIZONTAL WINS
if((s1.image == s2.image) & (s2.image == s3.image) & (s1.image != NULL))
{
return YES;
}
else if((s4.image == s5.image) & (s5.image == s6.image) & (s4.image != NULL))
{
return YES;
}
else if((s7.image == s8.image) & (s8.image == s9.image) & (s7.image != NULL))
{
return YES;
}
// VERTICAL WINS
else if((s1.image == s4.image) & (s4.image == s7.image) & (s1.image != NULL))
{
return YES;
}
else if((s2.image == s5.image) & (s5.image == s8.image) & (s2.image != NULL))
{
return YES;
}
else if((s3.image == s6.image) & (s6.image == s9.image) & (s3.image != NULL))
{
return YES;
}
// DIAGONAL WINS
else if((s1.image == s5.image) & (s5.image == s9.image) & (s1.image != NULL))
{
return YES;
}
else if((s3.image == s5.image) & (s5.image == s7.image) & (s3.image != NULL))
{
return YES;
}
//right now return 1 becuase we havn't implemented this yet
else{
return NO;
}
}
-(void)displayWinner{
if([self checkForWin] == YES){
if(playerToken==1){
lbl2.text =#"X is the WINNER";
} else {
lbl2.text =#"O is the WINNER";
}
}
}

Maybe you can write
if([s1.image isEqual:s2.image2]){
}
this code instead of this control statement
if((s1.image == s2.image) & (s2.image == s3.image) & (s1.image != NULL))
{
return YES;
}

The answer by Yılmaz Gürsoy is probably correct.
The reason, is that you are comparing the references to the images, and not the image data. The references are probably not the same, while the data probably is.
He is suggesting that you compare the data instead of the references.
In my oppinion though, you should actually add a member to the s# object, containing a tristate value. could be an integer.
/**
s.x is avalue indicating which image is shown (x, O, or empty)
x > 0 means 'X'
x == 0 means 'O'
x < 0 means empty
**/
and then set it when you assign the image. and check against that.
otherwise you will be wasting time comparing data, to get the exact same end result.

Related

Application crash while accessing data element of linked list when data is NULL

I am using following code to traverse through linked list in objective c
const MSList *calls = linphone_core_get_calls(LC);
if (calls == NULL)
{
[self dismissCtrl];
//how to check current is which screen is on
// while ((currentView == CallView.compositeViewDescription) ||
// (currentView == CallIncomingView.compositeViewDescription) ||
// (currentView == CallOutgoingView.compositeViewDescription)) {
// [self popCurrentView];
// }
} else {
linphone_call_resume((LinphoneCall *)calls->data);
while (calls)
{
if(calls->data != NULL && calls->data != nil && calls->data != (__bridge void *)((id)[NSNull null]))
{
//crash
if (linphone_call_get_state((LinphoneCall *)calls->data) == LinphoneCallIncomingReceived ||
linphone_call_get_state((LinphoneCall *)calls->data) == LinphoneCallIncomingEarlyMedia) {
[self displayIncomingCall:(LinphoneCall *)calls->data];
break;
}
}
calls = calls->next;
}
Application is crashing when entire list is not null but its data,previous or next value is NULL. I have added code to check if data is NULL but if it(data) is NULL, then i will not be able to access it and in condition itself application is crashing. How to prevent this ? I have attached screen-shot for where application is crashing and what is the value that list contains at that time.
if (calls == NULL) {
[self dismissCtrl];
//how to check current is which screen is on
// while ((currentView == CallView.compositeViewDescription) ||
// (currentView == CallIncomingView.compositeViewDescription) ||
// (currentView == CallOutgoingView.compositeViewDescription)) {
// [self popCurrentView];
// }
}
else
{
size_t count = bctbx_list_size(calls);
linphone_call_resume((LinphoneCall *)calls->data);
int i = 0;
while (calls )
{
if(i < count)
{
if ( calls->data == (__bridge void *)((id)[NSNull null]) || calls->data == NULL || calls->data == nil )
{
return;
}
LinphoneCall *objCall = (LinphoneCall *)calls->data;
LinphoneCallState state = (objCall != NULL) ? linphone_call_get_state(call) : 0;
if (state == LinphoneCallIncomingReceived ||
state == LinphoneCallIncomingEarlyMedia)
{
[self displayIncomingCall:(LinphoneCall *)calls->data];
break;
}
//calls ? calls->data : NULL
// calls = calls ? calls->next : NULL;
calls = calls->next;
i = i+1;
}
else
{
break;
}
}

IONIC/AngularJs on IOS - wrong innerWidth and innerHeight when changing screen orientation

It's my first time asking a question on stackoverflow, so i'll try to be as specific as I can. Thanks for your help.
Currently I'm developing an application for Androïd and IOS with Angular/IONIC solution.
Actually I've developed a service using cordova-plugin-screen-orientation 1.4.2 version plugin to change the orientation of my screen for some views. In fact, that work perfectly on both OS. But I also need when it's done, to catch the width and height of my device.
So there is my problem. On Android everything works, but on IOS, it looks like when I change the orientation I catch always the old values. (if I change for a landscape, I catch the previous portrait orientation values).
I tried different algorythm like the more simple : change the orientation and when it's done catch the values.
Currently I'm trying with a watcher, for the same result.
Here is my code :
class WindowService extends Service {
constructor($resource,$config, $window, Watcher) {
'ngInject';
super();
this.orientations = {
1:"portrait",
2:"landscape"
}
//imported library
this.md = new MobileDetect($window.navigator.userAgent);
// if it's a tablet Android, md.tablet() != null && md.os() == 'AndroidOS'
// if it's an iPad md.tablet() == 'iPad'
// if it's an iPhone md.mobile() == 'iPhone'
// if it's an Android phone, md.phone() != null && md.os() == 'AndroidOS'
console.log("md > ", this.md.mobile());
this.maxHeight = "100vh";
this.maxWidth = "100vw";
if (this.isAndroid()){
this.maxHeight = $window.innerHeight + "px";
this.maxWidth = $window.innerWidth + "px";
this.maxHeightWatcher = Watcher.watch(() => $window.innerHeight, innerHeight => {
this.maxHeight = $window.innerHeight + "px";
this.maxWidth = $window.innerWidth + "px";
});
}
}
setOrientation(){
this.invoke(($window) => {
if ($window.screen.unlockOrientation){
$window.screen.unlockOrientation();
if ((this.md.phone() != null && this.md.os() == 'AndroidOS') || this.md.mobile() == 'iPhone'){
$window.screen.lockOrientation('portrait');
}else if ((this.md.tablet() != null && this.md.os() == 'AndroidOS') || this.md.tablet() == 'iPad'){
$window.screen.lockOrientation('landscape');
}else {
$window.screen.lockOrientation('landscape');
}
}
});
}
//THIS S THE FUNCTION I CALL
changeOrientation(orientationId){
this.invoke(($window) => {
this.lockScreenOrientation($window, orientationId).then(res => {
console.log("changeOrientation > ", res);
}).catch(err => {
console.log("changeOrientation > ", err);
});
});
}
lockScreenOrientation($window, orientationId){
if (this.orientations[orientationId] != undefined){
if (this.orientations[orientationId] != $window.screen.orientation){
if ($window.screen.unlockOrientation){
$window.screen.unlockOrientation();
console.log("lockOrientation > ", $window.screen.lockOrientation(this.orientations[orientationId]));
return Promise.resolve(this.orientations[orientationId]);
}else{
return Promise.reject("[ERROR] cordova-plugin-screen-orientation hadn't been loaded.")
}
}else{
return Promise.resolve(this.orientations[orientationId]);
}
}else{
return Promise.reject("[ERROR] The orientation specified is Unknown.")
}
}
getDevice(){
if ((this.md.phone() != null && this.md.os() == 'AndroidOS')){
return "Android Smartphone";
}else if (this.md.mobile() == 'iPhone'){
return "iPhone";
}else if ((this.md.tablet() != null && this.md.os() == 'AndroidOS')){
return "Android Tablet";
}else if (this.md.tablet() == 'iPad'){
return "iPad";
}else
return "Unknown";
}
isSmartphone(){
if ((this.md.phone() != null && this.md.os() == 'AndroidOS') || this.md.mobile() == 'iPhone'){
return true;
}
return false;
}
isTablet(){
if ((this.md.tablet() != null && this.md.os() == 'AndroidOS') || this.md.tablet() == 'iPad')
return true;
return false;
}
isIOS() {
if (this.md.mobile() == 'iPhone' || this.md.tablet() == 'iPad')
return true;
return false;
}
isAndroid() {
if ((this.md.phone() != null && this.md.os() == 'AndroidOS')
|| (this.md.tablet() != null && this.md.os() == 'AndroidOS'))
return true;
return false;
}
getMaxHeight(){
return this.maxHeight;
}
getMaxWidth(){
return this.maxWidth;
}
}
Service.register(WindowService);
<ion-side-menu-content drag-content="false" ng-controller="HeaderController" style="height:{{view.maxHeight}};width: {{view.maxWidth}};">
....
</ion-side-menu-content>
The class Watcher is just an little extension of the basic watcher of angular. It works the same way.
[edit] Sorry I forgot to specify something : as you can see in the js code, in the constructor method, if it's IOS I just put 100vh fr the height and 100vw for the width. And I have the same result : the change from portrait to landscape keep the portrait size values.

Including the max and offset criteria inside GORM criteriaBuilder returns an error

Can I make this code shorter?
if(count == null && from = null) {
creditAdviceList = CreditAdvice.findAll {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
}
}
else if(count != null && from == null) {
creditAdviceList = CreditAdvice.findAll(max: count) {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
}
}
else if(count == null && from != null) {
creditAdviceList = CreditAdvice.findAll(offset: from) {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
}
}
else if(count != null && from != null) {
creditAdviceList = CreditAdvice.findAll(max: count, offset: from) {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
}
}
You see, its a series if statement for each possible scenario. Imagine if one would to use also order and cache in the parameter- there will be basically 16 unique if statements!
I've tried this [more] shorter code:
creditAdviceList = CreditAdvice.findAll {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
if(count != null) {
maxResults(count)
}
if(from != null) {
firstResult(from)
}
}
But it gives me an error:
...No signature of method: grails.gorm.DetachedCriteria.maxResults() is applicable for argument types: (java.lang.Integer)...
I tried to convert offset to int, Integer, String, etc. I also omit the if statement inside the criteria, but the same error message occur.
findAll with a closure passed is using a DetachedCriteria internally, which is not the same as the result you would get from createCriteria mentioned in the docs. If groovy would find "something close" enough, it would tell you in the error message. The easiest way to deal with your max/from demands would be with simply with a map (which is the first argument passed). E.g.:
def qcfg = [:]
if (count) {
qcfg.count = count
}
if (from) {
qcfg.offset = from
}
creditAdviceList = CreditAdvice.findAll(qcfg) { ... }
mix, match, extract, shorten as you see fit
As far as I see, the only difference is the pagination options. If my eyes are not tricking me, yes, you can:
Map paginationArgs = [max: count, offset: from].findAll {
it.value != null
}
List<CreditAdvice> creditAdviceList = CreditAdvice.findAll(paginationArgs) {
ilike('id', "%$idFilter%")
.....
ilike('statusCode', statusCodeFilter)
}
You can style it differently, but basically you can build the pagination arguments first, and pass them to the findAll. No duplicated code, clearer responsability of the conditions. To clarify, I'm adding all the options and then filtering them to exclude the ones that are null.

If statement not calling all methods returning BOOL

I have code like this:
-(IBAction)send {
if ([self isCorrect1] && [self isCorrect2] && ...) {
[self sendRequest];
}
}
-(BOOL)isCorrect1 {
...
}
-(BOOL)isCorrect2 {
...
}
Every isCorrect method is checking some condition showing some message in the view and returning result of the checking. I noticed that if first condition is false it will only show error message for the first method (and I need all of them to be checked) and no breakpoint is triggered inside these methods. I thought it was some kind of LLVM optimization so I created code like this:
-(IBAction)send {
BOOL correct = [self isCorrect1];
correct = correct && [self isCorrect2];
...
if (correct) {
[self sendRequest];
}
}
And is still not working correctly. Do I have to create new BOOL variable to store result for the check or is there some other way?
Since the first condition is evaluated to false, it won't check for the rest of the conditions and will go to the else part straightaway.
Try this.
BOOL finalResult = [self isCorrect1];
finalResult = [self isCorrect2] && finalResult;
finalResult = [self isCorrect3] && finalResult;
finalResult = [self isCorrect4] && finalResult;
...
if (finalResult) {
}
This will go through all of the isCorrect tests and will let you know if it passed all of them in the end or not.
The behaviour you see is the expected behaviour of the &&, namely, it "short-circuits" the evaluation, if it can determine the result in advance, before having evaluated all conditions:
expression-yielding-false && something-else
The result of the above is completely determined by the first part; regardless of what the second operand yields, the final result is false. This allows you to write something like:
if (obj != null && obj->count == 3)
{
...
}
If the && did not have the short-circuit behaviour, you'd have to write
if (obj != null)
{
if (obj->count == 3)
{
...
}
}
The || has a similar behaviour. In case of
something-yielding-true || anything
the right-hand side cannot affect the result value, as the left-hand side already returned true.
One possible work-around would be:
int succeeses = 0;
succeesses += [self isCorrect1]? 1 : 0;
succeesses += [self isCorrect2]? 1 : 0;
succeesses += [self isCorrect3]? 1 : 0;
if (successes == 3)
{
// All tests did succeed
}
else
{
// At least one failed.
}
If you need to know, which tests passed, and which failed, you can try:
BOOL passed1 = [self isCorrect1];
BOOL passed2 = [self isCorrect2];
BOOL passed3 = [self isCorrect3];
if (passed1 && passed2 && passed3)
{
// All tests did succeed
}
else
{
// At least one failed.
}
A more dense version of the above would be
int passed = 0;
passed |= [self isCorrect1]? (1 << 0) : 0;
passed |= [self isCorrect2]? (1 << 1) : 0;
passed |= [self isCorrect3]? (1 << 2) : 0;
if (passed == 7)
{
// All tests did succeed
}
else
{
if (passed & (1 << 0))
{
// First test passed
}
else
{
// First test failed
}
if (passed & (1 << 1))
{
// Second test passed
}
else
{
// Second test failed
}
if (passed & (1 << 2))
{
// Third test passed
}
else
{
// Third test failed
}
}
which is simply a more occult formulation of the version with a boolean variable per test tried.

How to go through sequential steps inside a while loop?

I need to go through a series of steps one by one. In all, I have three steps to go through which are inside of a while loop. Once the three tests are completed, then and only then should the user be exited from the while loop. The catch is that these steps need to be done sequentially, and require the user to do each test in order, if they pass, then move on to the next step.
Here is the relevant code:
int passCount = 0;
BOOL flatPass = FALSE;
BOOL landscapePass = FALSE;
BOOL portraitPass = FALSE;
while (passCount < 3) {
if (flatPass == FALSE) {
if (device.orientation == UIDeviceOrientationFaceUp || device.orientation == UIDeviceOrientationFaceDown) {
[self pushSound];
}
}
else if (landscapePass == FALSE) {
if (device.orientation == UIDeviceOrientationLandscapeLeft || device.orientation == UIDeviceOrientationLandscapeRight) {
[self pushSound];
}
}
else if (portraitPass == FALSE) {
if (device.orientation == UIDeviceOrientationPortrait || device.orientation == UIDeviceOrientationPortraitUpsideDown) {
[self pushSound];
}
}
}
I need the user to position the iOS device in each position, and a beep sound is played to indicate a successful test. Once ALL of the three tests have been completed in order, I want the user to be exited from the loop. I figure each time a test has been cleared, I would increment the passCount counter by 1, until we reach 3 which would exit me from the loop. My issue though is how to go through each test, and in order.
Assuming this isn't running on the main UI thread, remove the while loop, replace each if and else if with a while condition, set the appropriate boolean flags to true when a test passes and you're done.
You could implement that in
deviceDidRotate()
you need a object variable for saving the current progress, or you use an enum like you have done:
int step;
then in deviceDidRotate you check:
if (step == 0 && device.orientation == UIDeviceOrientationFaceUp ) {
step = 1;
} else if (step == 1 && device.orientation == UIDeviceOrientationLandscapeLeft) {
step = 2;
} else if (step == 2 && device.orientation == UIDeviceOrientationPortrait ) {
// successful!
// now do action, reset step? call method
}

Resources