Sorting an nsmutable array --> order is not being saved? - objective-c

kind of a noob question maybe: I'm trying to sort an nsmutablearray, but somehow the order is not being stored.
typedef struct {
float distance;
int index;
} DistanceAndIndex;
i = 0;
NSMutableArray *orderedDistances = [NSMutableArray arrayWithCapacity:(self.wayPoints.count)];
CLLocation* rwp2 = [[CLLocation alloc] initWithLatitude:52.080752 longitude:4.7527251];
latLonToEcef(rwp2.coordinate.latitude, rwp2.coordinate.longitude, 0.0, &myX, &myY, &myZ);
for (routeWayPoint *rwp in [[self wayPoints] objectEnumerator]) {
double poiX, poiY, poiZ, e, n, u;
latLonToEcef(rwp.location.coordinate.latitude, rwp.location.coordinate.longitude, 0.0, &poiX, &poiY, &poiZ);
ecefToEnu(rwp2.coordinate.latitude, rwp2.coordinate.longitude, myX, myY, myZ, poiX, poiY, poiZ, &e, &n, &u);
DistanceAndIndex distanceAndIndex;
distanceAndIndex.distance = sqrtf(n*n + e*e);
distanceAndIndex.index = i;
NSLog(#"Index = %i, %f", i, distanceAndIndex.distance);
[orderedDistances insertObject:[NSData dataWithBytes:&distanceAndIndex length:sizeof(distanceAndIndex)] atIndex:i++];
}
i=0;
[orderedDistances sortUsingComparator:(NSComparator)^(NSData *a, NSData *b) {
const DistanceAndIndex *aData = (const DistanceAndIndex *)a.bytes;
const DistanceAndIndex *bData = (const DistanceAndIndex *)b.bytes;
if (aData->distance < bData->distance) {
return NSOrderedAscending;
} else if (aData->distance > bData->distance) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
}];
for (NSData *d in [orderedDistances reverseObjectEnumerator]) {
const DistanceAndIndex *distanceAndIndex = (const DistanceAndIndex *)d.bytes;
NSLog(#"item: %i, %f", distanceAndIndex->index, distanceAndIndex->distance);
}
The output is the following:
[2021:907] Waypoints: 8
[2021:907] Index = 0, 230.078827
[2021:907] Index = 1, 171.626389
[2021:907] Index = 2, 36.015743
[2021:907] Index = 3, 103.174805
[2021:907] Index = 4, 238.837616
[2021:907] Index = 5, 278.074371
[2021:907] Index = 6, 288.319763
[2021:907] Index = 7, 321.953156
[2021:907] item: 7, 321.953156
[2021:907] item: 6, 288.319763
[2021:907] item: 5, 278.074371
[2021:907] item: 4, 238.837616
[2021:907] item: 3, 103.174805
[2021:907] item: 2, 36.015743
[2021:907] item: 1, 171.626389
[2021:907] item: 0, 230.078827
The array simply hasn't been reordered (for instance when looking at items 1,2 and 3). I feel like I'm overlooking something really basic. Any ideas?
Thanks!

You appear to be overlooking this typo:
if (aData->distance < bData->distance) {
return NSOrderedAscending;
} else if (aData->distance > bData->distance) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
The second one should be NSOrderedDescending, I think.

You seem to have two if statements that both return NSOrderedAscending

Related

How can I make a typed index in Zig

I have an algorithm that has two arrays with their respective indices. Only, it would be very easy to mix both indices and access one of the arrays with the wrong index. For example:
var array1 = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var index1 = 7; // the 8th element in array1, fine because array1 has a length of 10
var array2 = [_]u8{ 1, 2, 3, 4, 5 };
var index2 = 2; // the 3rd element in array2, fine because array2 has a length of 5
array2[index1] // woops, I used the wrong index with the wrong array
Is there a way to make a custom index type to associate an array with a specific type of index such that indexing an array with the wrong type of index will result in a compile error?
Such as:
var array1 = [_:Index1]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; // with index type 'Index1'
var index1 : Index1 = 7; // index of type 'Index1'
var array2 = [_:Index2]u8{ 1, 2, 3, 4, 5 }; // with index type 'Index2'
var index2 : Index2 = 2; // index of type 'Index2'
array2[index1] // ERROR: array2 expects Index2 type index but Index1 type is used
const std = #import("std");
fn PickyArray(comptime T: type, n: usize, extra: anytype) type {
_ = extra;
return struct {
const Self = #This();
pub const Index = struct {
idx: usize,
};
unsafe_items: [n]T,
pub fn init(xs: [n]T) Self {
return .{.unsafe_items = xs};
}
pub fn get(self: Self, idx: Index) T {
return self.unsafe_items[idx.idx];
}
pub fn set(self: *Self, idx: Index, v: T) void {
self.unsafe_items[idx.idx] = v;
}
pub fn getPtr(self: Self, idx: Index) *T {
return &self.unsafe_items[idx.idx];
}
pub fn getSlice(self: Self, lo: Index, hi: Index) []T {
return self.unsafe_items[lo.idx..hi.idx];
}
};
}
const Array1 = PickyArray(u8, 10, "Index1");
const Index1 = Array1.Index;
const Array2 = PickyArray(u8, 5, "Index2");
const Index2 = Array2.Index;
pub fn main() void {
var array1 = Array1.init([_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var index1 : Index1 = .{.idx=7}; // index of type 'Index1'
var array2 = Array2.init([_]u8{ 1, 2, 3, 4, 5 }); // with index type 'Index2'
var index2 : Index2 = .{.idx=2}; // index of type 'Index2'
_ = array2.get(index1); // ERROR: array2 expects Index2 type index but Index1 type is used
_ = array1;
_ = index1;
_ = array2;
_ = index2;
}
For extra credit, the type returned by getSlice should not be a normal slice and should refuse to accept integer indices.
Please do not do this.

For loop inside a Redis queue does not work as expected in NestJs

I have the following code, basically it is doing a bruteforce on a key of a hash in the first 4 bytes. Then I loop through each of these positions to test all possible combinations. If I put this code inside the service it runs normally and takes about 200 seconds to find all possible combinations of the first 4 bytes.
But when you're doing long operations, it's good to have a queue to do this in the background. That's what I did, I added it to a nestjs queue with redis but inside the queue when I use for it seems that they are shuffled and they all end together in less than 5 seconds, besides that I don't find the correct combination. And if I use a forEach it either doesn't work or the program crashes during execution.
Basically the first 4 bytes are [192, 156, 127, 0, ...] but it doesn't find it when it's inside a queue. How can I make the background queue run normally as if it were in the service?
import * as crypto from 'crypto';
const DIFFICULTY = {
legendary: {
maxValues: [255, 255, 255, 1],
},
hard: {
maxValues: [255, 255, 255, 0],
},
medium: {
maxValues: [255, 255, 127, 0],
},
easy: {
maxValues: [255, 255, 64, 0],
},
};
#Processor('decrypt-queue')
export class DecryptConsumer {
constructor(
#InjectRepository(Chest) private readonly repository: Repository<Chest>,
) {}
#Process('decrypt-job')
async decryptJob(job: Job) {
const code = job.data;
await job.progress(50);
const chest = await this.repository.findOne({
where: {
code: code,
},
});
await this.repository.save({
...chest,
status: ChestStatus.Oppening,
});
const iv = Buffer.from([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
const original = chest.key;
const range = ({
from = 0,
to,
step = 1,
length = Math.ceil((to - from) / step),
}): number[] => Array.from({ length }, (_, i) => from + i * step);
const first = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[0],
step: 1,
});
const second = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[1],
step: 1,
});
const third = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[2],
step: 1,
});
let four = range({
from: 0,
to: DIFFICULTY[chest.difficulty].maxValues[3],
step: 1,
});
four = [0];
// first.forEach(async (i) => {
// second.forEach(async (j) => {
// third.forEach(async (k) => {
// four.forEach(async (l) => {
// console.log(i, j, k, l);
// if (
// i === original[0] &&
// j === original[1] &&
// k === original[2] &&
// l === original[3]
// ) {
// console.log(i, j, k, l, end());
// const decipher = await crypto.createDecipheriv(
// 'aes-128-cbc',
// Buffer.from([i, j, k, l, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
// iv,
// );
// let decrypted = await decipher.update(code, 'hex', 'utf8');
// decrypted += decipher.final('utf8');
// if (decrypted.includes('Hello')) {
// await this.repository.save({
// ...chest,
// status: ChestStatus.Openned,
// });
// await job.progress(100);
// // return {
// // decrypted,
// // };
// } else {
// }
// }
// });
// });
// });
// });
for (let i = 0; i < DIFFICULTY[chest.difficulty].maxValues[0]; i++) {
for (let j = 0; j < DIFFICULTY[chest.difficulty].maxValues[1]; j++) {
for (let k = 0; k < DIFFICULTY[chest.difficulty].maxValues[2]; k++) {
for (let l = 0; l < DIFFICULTY[chest.difficulty].maxValues[3]; l++) {
if (
i === original[0] &&
j === original[1] &&
k === original[2] &&
l === original[3]
) {
console.log(i, j, k, l, end());
const decipher = await crypto.createDecipheriv(
'aes-128-cbc',
Buffer.from([i, j, k, l, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
iv,
);
let decrypted = await decipher.update(code, 'hex', 'utf8');
decrypted += decipher.final('utf8');
if (decrypted.includes('Hello')) {
await this.repository.save({
...chest,
status: ChestStatus.Openned,
});
await job.progress(100);
// return {
// decrypted,
// };
} else {
}
}
}
}
}
}
await this.repository.save({
...chest,
status: ChestStatus.Locked,
});
await job.progress(100);
// return {
// decrypted: false,
// };
}
}

IOS 7 - In App Purchase Tutorial

I am following this In App Purchase tutorial and I can see the product description and title I posted at my iTunesConnect IAP content. However, When I click on the buyButton I get a Thread 1:EXC_BAD_ACCESS(code=1, address=0xc) error at:
- (IBAction)buyProduct:(id)sender {
SKPayment *payment = [SKPayment paymentWithProduct:_product];//<-- This line course the error.
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
Someone suggest me to do a check on the _product before and after buyButton, and it did turn out different:
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *products = response.products;
if (products.count != 0)
{
_product = products[0];
_buyButton.enabled = YES;
_productTitle.text = _product.localizedTitle;
_productDescription.text = _product.localizedDescription;
NSLog(#"productsRequest: %#", _product);
//NSLog(#"productsRequest: %#", _product.localizedTitle);
} else {
_productTitle.text = #"Product not found";
}
products = response.invalidProductIdentifiers;
for (SKProduct *product in products)
{
NSLog(#"Product not found: %#", product);
}
}
- (IBAction)buyProduct:(id)sender {
NSLog(#"Product title: %#", _product);//<-- this give different result from productsRequest function.
}
From -(void)productsRequest, I get
productsRequest: <SKProduct: 0x17e8e3f0>
and from - (IBAction)buyProduct, I get
Product title: #<CGRegion 0x17e8e3f0 empty>
And sometime some random long result:
Product title: Length 11 (2 blocks, 1 used, block 0 is at 0)
11 0x165ae790 {
NSColor = "UIDeviceRGBColorSpace 0.838794 0.39337 1 1";
NSFont = "<UICTFont: 0x165ae010> font-family: \".HelveticaNeueInterface-M3\"; font-weight: normal; font-style: normal; font-size: 17.00pt";
NSParagraphStyle = "Alignment 1, LineSpacing 0, ParagraphSpacing 0, ParagraphSpacingBefore 0, HeadIndent 0, TailIndent 0, FirstLineHeadIndent 0, LineHeight 0/0, LineHeightMultiple 0, LineBreakMode 4, Tabs (\n 28L,\n 56L,\n 84L,\n 112L,\n 140L,\n 168L,\n 196L,\n 224L,\n 252L,\n 280L,\n 308L,\n 336L\n), DefaultTabInterval 0, Blocks (null), Lists (null), BaseWritingDirection -1, HyphenationFactor 0, TighteningFactor 0, HeaderLevel 0";
NSShadow = "NSShadow {0, -1} color = {(null)}";
}
Any idea how can I resolve this?

Is there are more elegant Solution for a large switch statement?

I have got map a lot of ranges to a value like 0-300 = 10 , 300-600 = 20, 600-900 = 30 ... 2500000-2700000 = 7000 .... So I could make a really large switch-statement/if-block but I wonder if there is a more elegant approach to solve this little problem.
Ok here is a small subset of the table with real data:
0-300 : 25
301-600. : 45
601-900 : 65
901-1200. : 85
1201-1500: 105
1501-2000 : 133
2001-2500 : 161
2501-3000: 189
3001-3500:217
3501-4000:245
4001-4500:273
4501-5000:301
5001-6000:338
The most common pattern for getting rid of a switch statement is to use a dictionary. In your case, since you're mapping ranges, you'll use an NSArray of range cutoffs instead. This is what it would look like if you're dealing with ints:
NSArray *rangeCutoffs = [NSArray arrayWithObjects:[NSNumber numberWithInt:300],[NSNumberWithInt:600],...,nil];
NSArray *values = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:20],...,nil];
int mappedInt;
for (int index=0; index <= [rangeCutoffs count]; index++) {
if (intToMap < [[rangeCutoffs objectAtIndex:index] intValue]) {
mappedInt = [[values objectAtIndex:index] intValue];
}
}
if (mappedInt == 0) {
mappedInt = [[values lastObject] intValue];
}
In practice you'd want to load rangeCutoffs and values from a plist instead of hardcoding them.
You could use a table. e.g.
struct Lookup
{
int min;
int max;
int value;
};
struct Lookup table[] =
{
{ 0, 300, 10 },
{ 301, 600, 20 },
{ 601, 900, 30 },
// other ranges
{ 2500000, 2700000, 7000 },
{ -1, -1, -1 } // marks the end of the table
};
And then simply iterate through it to find the right range
int result = -1;
for (int i = 0 ; table[i].min != -1 && result == -1 ; ++i)
{
if (table[i].min <= value && value <= table[i].max)
{
result = table[i].value;
}
}
If it's a really large table, you can use a binary search instead.
You could do something like this (C example):
#include <stdio.h>
#include <stdlib.h>
typedef int range_type;
typedef int value_type;
typedef struct {
range_type min;
range_type max;
value_type value;
} range_t;
const range_t *find_range(const range_t *ranges, size_t rangesSize,
value_type valueToFind)
{
for (size_t i = 0; i < rangesSize; ++i) {
if (ranges[i].min <= valueToFind && valueToFind <= ranges[i].max)
return &ranges[i];
}
return NULL;
}
int main() {
const range_t ranges[] = {
{ 0, 300, 10 },
{ 301, 600, 20 },
{ 601, 900, 30 },
{ 901, 1200, 40 }
// And so on...
};
value_type testValues[] = {
-1, // None
0, 299, 300, // [ 0, 300]
301, 599, 600, // [301, 600]
601, 899, 900, // [601, 900]
901, 1199, 1200, // [901, 1200]
// And so on...
};
for (size_t i = 0; i < sizeof(testValues) / sizeof(testValues[0]); ++i) {
const range_t *match = find_range(
ranges, sizeof(ranges) / sizeof(ranges[0]), testValues[i]);
if (match != NULL)
printf("%d found at [%d..%d]\n", testValues[i], match->min,
match->max);
else
printf("%d not found\n", testValues[i]);
}
return EXIT_SUCCESS;
}
Should output:
-1 not found
0 found at [0..300]
299 found at [0..300]
300 found at [0..300]
301 found at [301..600]
599 found at [301..600]
600 found at [301..600]
601 found at [601..900]
899 found at [601..900]
900 found at [601..900]
901 found at [901..1200]
1199 found at [901..1200]
1200 found at [901..1200]

cocos2d slot machine animation

I am trying to create an application that simulates a slot machine.
Now, I have all the images ready, with the vertical png file and the plist file. My question is, how do I simulate the spinning (when the user presses a button), and then the stopping of the slot machine (after around 1-2 seconds)?
Note that the png file has to wrap around somehow.
Everything else is all a matter of NSArrays and checking, what I want to figure out is the animation. I hope some can share some code or references to do this.
Thanks!
This is relatively straightforward: just repeat the png file as many times as you need to simulate the spinning action. So it's basically a vertical variation on parallax scrolling. If you have Steffan Itterheim's book, he talks about this type of thing in chapter 7 "Scrolling With Joy". You may also find some help here: Cocos2D vertically scrolling background
Hope this helps!
Mike
I am doing something like this:
#include <ctime>
#include <vector>
#include <cstdlib>
#include <iostream>
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
using namespace std;
static int last[5]={0, 0, 0, 0, 0};
static int stops[5];
static int reels[5][63] = {
{9,7,12,5,7,3,4,11,9,7,12,6,7,4,11,10,4,3,11,12,7,5,10,9,7,5,9,10,8,9,7,4,9,10,11,5,10,3,9,10,3,9,4,8,7,5,11,9,12,6,3,5,7,9,11,10,6,7,3,5,10,8,4,},
{11,5,4,7,6,8,4,9,7,8,3,11,6,5,11,7,12,5,8,6,10,9,5,6,8,7,12,11,5,6,10,3,4,5,9,12,8,9,6,5,12,8,9,12,7,8,5,10,12,7,11,3,4,8,7,4,5,9,8,6,12,4,6,},
{10,4,5,8,6,7,5,9,6,7,8,4,6,5,11,3,9,8,7,11,12,6,8,5,4,8,6,12,9,6,5,11,3,7,4,8,7,3,10,9,5,6,4,3,9,12,10,8,9,6,3,9,10,6,7,5,6,8,4,11,9,7,8,},
{9,3,6,5,3,10,6,9,5,12,4,8,11,10,7,6,5,9,7,3,8,6,12,4,5,7,3,12,10,6,9,7,8,5,6,4,9,6,11,5,8,12,6,7,3,6,10,3,7,5,10,8,9,6,12,4,7,9,5,6,8,3,10,},
{5,3,9,4,6,12,10,5,11,4,8,7,10,5,9,11,4,6,7,3,6,4,8,5,11,8,5,10,8,11,5,10,8,3,7,4,10,11,5,7,8,9,5,11,6,8,10,3,7,9,3,8,10,12,6,8,10,11,7,10,8,11,6,},
};
static SDL_Window *window = NULL;
static SDL_Surface *canvas = NULL;
static const SDL_Surface *backgroundSurface = IMG_Load("./Background.png");
static SDL_Rect backgroundCoordinates = { 0, 0, 0, 0 };
static const SDL_Surface *symbolsSurface[] = {
NULL,
NULL,
NULL,
IMG_Load("./Symbol03.png"),
IMG_Load("./Symbol04.png"),
IMG_Load("./Symbol05.png"),
IMG_Load("./Symbol06.png"),
IMG_Load("./Symbol07.png"),
IMG_Load("./Symbol08.png"),
IMG_Load("./Symbol09.png"),
IMG_Load("./Symbol10.png"),
IMG_Load("./Symbol11.png"),
IMG_Load("./Symbol12.png"),
NULL,
NULL,
NULL,
NULL,
};
static const SDL_Surface *reelsSurface[5] = {NULL, NULL, NULL, NULL, NULL};
static SDL_Rect symbolsCoordinates[5][3] = {
{ { 298, 118, 0, 0 }, { 298, 266, 0, 0 }, { 298, 414, 0, 0 } },
{ { 474, 118, 0, 0 }, { 474, 266, 0, 0 }, { 474, 414, 0, 0 } },
{ { 651, 118, 0, 0 }, { 651, 266, 0, 0 }, { 651, 414, 0, 0 } },
{ { 827, 118, 0, 0 }, { 827, 266, 0, 0 }, { 827, 414, 0, 0 } },
{ { 1003, 118, 0, 0 }, { 1003, 266, 0, 0 }, {1003, 414, 0, 0 } },
};
static unsigned long animationStart = 0;
static unsigned long animationEnd = 0;
static bool stopped[5] = {false, false, false, false, false};
void draw() {
static double y0 = 0;
static double v0[5] = {-9.5, -9.6, -9.7, -9.8, -9.9};
static long t = 0;
static double a = 0.0005;
static int y = 0;
SDL_BlitSurface((SDL_Surface*) backgroundSurface, NULL, canvas, &backgroundCoordinates);
for (int i = 0; i < 5 && animationStart!=animationEnd; i++) {
/*
* y = y0 + v0*t + 1/2*at^2
*/
y0 = last[i] * 140;
t = (1000 * clock() / CLOCKS_PER_SEC) - animationStart;
y = (int)(y0 + v0[i]*t + a*t*t/2) % (63*140);
if(y < 0) {
y += 63*140;
}
/*
* Stop near to the target position.
*/
if(i==0 && abs(y-stops[i]*140)<=140) {
last[i] = stops[i];
stopped[i] = true;
}else if(stopped[i-1] == true && stopped[i] == false && abs(y-stops[i]*140)<=140) {
last[i] = stops[i];
stopped[i] = true;
}
if(stopped[i] == true) {
SDL_SetSurfaceAlphaMod((SDL_Surface*) reelsSurface[i], 255);
y = stops[i] * 140;
} else {
SDL_SetSurfaceAlphaMod((SDL_Surface*) reelsSurface[i], 191);
}
const SDL_Rect frame = {0, y, 140, 3*140};
SDL_BlitSurface((SDL_Surface*) reelsSurface[i], &frame, canvas, &symbolsCoordinates[i][0]);
}
SDL_UpdateWindowSurface(window);
}
int main() {
SDL_Init(SDL_INIT_EVERYTHING);
/*
* Build long strips (two more images at the end).
*/
for(int i=0, index; i<5; i++) {
reelsSurface[i] = IMG_Load("./Reel.png");
for(int j=0; j<(63+2); j++) {
index = reels[i][j%63];
SDL_Rect coordinates = {0, 140*j, 0, 0};
SDL_BlitSurface((SDL_Surface*) symbolsSurface[index], NULL, (SDL_Surface*)reelsSurface[i], &coordinates);
}
}
//window = SDL_CreateWindow("Slot Reels Animation", 0, 0, 1280, 1024, SDL_WINDOW_FULLSCREEN_DESKTOP);
window = SDL_CreateWindow("Slot Reels Animation", 0, 0, 1440, 900, 0);
canvas = SDL_GetWindowSurface(window);
SDL_Event event;
bool done = false;
while (done == false) {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_QUIT:
done = true;
break;
case SDL_KEYDOWN:
switch (event.key.keysym.sym) {
case SDLK_ESCAPE:
done = true;
break;
case SDLK_RETURN:
//startAnimation();
memset(stopped, false, 5*sizeof(bool));
animationStart = 1000 * clock() / CLOCKS_PER_SEC;
for (int i = 0, r; i < 5; i++) {
stops[i] = rand() % 63;
}
break;
}
}
}
draw();
}
SDL_DestroyWindow(window);
for(int i=0; i<5; i++) {
SDL_FreeSurface((SDL_Surface*)reelsSurface[i]);
}
SDL_Quit();
return EXIT_SUCCESS;
}