Swift 2 arch4random [duplicate] - xcode

This question already has an answer here:
How to generate random numbers without repetition in Swift? [duplicate]
(1 answer)
Closed 7 years ago.
In my application, I use something like this to get random text on my label, except in my main let randomNumbercode, in xCode, it has over 300 cases, to much to paste in here.:
let randomNumber = Int(arc4random_uniform(23))
var textLabel = "" as NSString
switch (randomNumber){
case 1:
textLabel = "Kim."
break
case 2:
textLabel = "Phil."
break
case 3:
textLabel = "Tom"
break
case 4:
textLabel = "Jeff"
break
default:
textLabel = "Austin"
}
self.randomLabel.text = textLabel as String
But the problem is, that sometimes it shows the same text on the label 5-6 times, and other cases is not even used yet, because it choose randomly. So how can I choose randomly, but if case example case 1 is already shown, it wont show up again, until all other cases has been shown.

Have an array of Names instead of a gigantic switch case:
var names = ["Kim.", "Phil.", "Tom", "Jeff", "Austin"] // and all your remaining names
let originalNames = names
func getRandomName() -> String {
if (names.count == 0) {
names = originalNames
}
let randomNumber = Int(arc4random_uniform(UInt32(names.count)))
return names.removeAtIndex(randomNumber)
}
This ensures every name gets printed before starting from the beginning again. The sample output is:
Tom, Kim., Austin, Phil., Jeff
and then it starts again
Austin, Jeff, Phil. ...
Finally put something like the following wherever it fits your need:
self.randomLabel.text = getRandomName()

Related

time.sleep() not working as expected last

I have a canvas with 30 labels, the text is updated (always different) using a button. I have 2 questions:
1.-why the command time.sleep doesn't work as I expect?
i = 0
while len(words) >= 1:
if i = 1:
canvas.itemconfig(label1, text = "text")
time.sleep(3)
if i = 2:
canvas.itemconfig(label2, text = "text")
time.sleep(3)
if i = 3:
canvas.itemconfig(label3, text = "text")
time.sleep(3)
if i = 4:
canvas.itemconfig(label4, text = "text")
time.sleep(3)
if i = 5:
canvas.itemconfig(label5, text = "text")
time.sleep(3)
i+= 1
And so on until 30, I want to set the label and then wait 3 seconds to set the next label and so on, but the code waits 15 seconds and sets all the labels at the same time at the end.
2.-is there a way to refer to my labels using "for" to avoid writing 30 lines? All my labels are called label1, label2, label3... I have done this in other language with something like this
For i in range(1,31):
canvas.itemconfig(label[i], text = "text")
Sorry if I wrote something wrong since I did it in my phone
When you use sleep in tkinter, you're freezing the program so nothing happens. If you want to make a change after a given time, use the after method.
root.after(1000, myfunction) # call myfunction after 1 second
As for the label updates, you are correct. Creating a label array would make it easier.
With the current label names, you can add them all to a list then iterate the list.
lbllst = [label1, label2, label3, ......]
for lbl in lbllist:
canvas.itemconfig(lbl, text = "text")

Spritekit collisions between arrays of SpriteNodes

I'm developing a game that involves a number of Sprite Arrays and I want to detect collisions between them and specify functions depending on which etc.
So say I have an array of 16 balls ballArray[I] and 16 blocks blockaArray[I] which I can easily iterate through using the index number I.
I have given the balls a Physics Category - Balls and similar to for Blocks. Then I have 16 ID Physics categories say ID1, ID2, ID3, ID4
So I can detect a collision, know that is was a Ball hitting a Block but I then need to know which ball and which block.
What the best or easiest way to do this? I'm reading about enumerateChildNodes(withName) function but have not used it. Or can I create array of PhysicsCategories which I could iterate through along with the SpriteArray to compare and identify.
EDIT:
Thanks Everyone for the help. I have finally cracked it. Surprisingly in the end the code a lot simpler than I first thought. Still not fully understanding where the bits are sitting in my categories but have it working .
I'll try to post my final working code - you may have suggestions to improve. Many thanks again and apologies for my poor StackFlow etiquette - I am new here :-)
So my Physics Categories were defined.
struct PhysicsCategories {
static let BoxCategoryMask = UInt32(1<<7)
static let BallCategoryMask = UInt32(1<<8)
}
and then in my function to build an array of Sprites
boxBloqArray[i].physicsBody?.categoryBitMask = PhysicsCategories.BoxCategoryMask | UInt32(i)
boxBloqArray[i].physicsBody!.contactTestBitMask = PhysicsCategories.BallCategoryMask
and the same for the ball array but just the categoryBitMask
ballBloqArray[i].physicsBody?.categoryBitMask = PhysicsCategories.BallCategoryMask | UInt32(i)
I'm still not really sure why it has to be this way round but that was the final problem this evening that I had the two bodies the wrong way round in the && comparison in the final working detection code:
var body1 = SKPhysicsBody()
var body2 = SKPhysicsBody()
if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
body1 = contact.bodyA
body2 = contact.bodyB
}
else {
body1 = contact.bodyB
body2 = contact.bodyA
}
// Check node collisions
for n in 0...15 {
for i in 0...15 {
if body2.categoryBitMask == PhysicsCategories.BallCategoryMask | UInt32(n) && body1.categoryBitMask == PhysicsCategories.BoxCategoryMask | UInt32(i) {
//if body1.node != nil {
print("Ball\(n) hit Box\(i)")
//}
}
}
}
and that is now printing the correct collisions.... lovely!... onwards to
the next step... thanks again
Once you have the two nodes involved in the collision as discussed in the answer by #Luca Angeletti, you can turn those into an index in various ways.
If you've made each type of node a specialized subclass and you have the appropriate indexes stored as class members, then you can convert to the appropriate class and look at the index fields, e.g.,
if let block = nodeA as? BlockNode, let ball = nodeB as? BallNode {
print("block \(block.blockIndex) hit ball \(ball.ballIndex)")
}
Nodes are hashable, so you can have dictionaries to map them back to indexes:
if let blockIndex = blockIndexes[nodeA], let ballIndex = ballIndexes[nodeB] {
print("block \(blockIndex) hit ball \(ballIndex)")
}
You can use the userData property of nodes to store whatever you like, including the indexes. The mucking around with NS things gets kind of ugly though.
https://developer.apple.com/documentation/spritekit/sknode/1483121-userdata
You can do the linear scan through each array.
if let blockIndex = blocks.firstIndex(of: nodeA), let ballIndex = balls.firstIndex(of: nodeB) {
print("block \(blockIndex) hit ball \(ballIndex)")
}
It sounds like from your question that you might have a separate category bit mask for each individual block and each individual ball. Or if you don't, that is possible if there are at most 16 of each. Anyway, if that's the case, then you can do some bit flicking to take the categoryBitMask from the physics bodies, shift the ball/block one by 16 bits (whichever is using the high bits gets shifted), and then take log2 of the bit masks to get your indexes. You can find various bit flicking techniques for log2 here:
https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious
Given 16 things of each type, I'd say just do #4. If you already have subclass nodes, #1 is fine. Number 2 is spreading state around a bit, so I'm not such a fan of that. Number 3 I would not really recommend because of the NS stuff. Number 5 is too cute for its own good.
Edit: Now that I read again, it sounds like maybe you've got separate ID's for categories 1...16, so your block category bit masks are like:
blockCategoryMask | ID1, blockCategoryMask | ID2, etc. That can also work (basically a variant of #5). If you're going down that route though, you may as well just stick the index directly into the category masks:
let blockCategoryMask = UInt32(1<<4)
let ballCategoryMask = UInt32(1<<5)
Then the physics body for a block gets mask blockCategoryMask | UInt32(index), and similarly for a ball. In that case the index extraction is just categoryBitMask & UInt32(0xf). Or if you put the block and ball categories in bits 0 and 1 and the indexes in bits 2-5, then right shift by 2 to get the index.
Edit in response to comment:
OK, so let's take the case of 6 distinct categories of objects, and each object can fall into one of 16 distinct subcategories. To be able to control which contacts are reported, you'd assign a bit mask to each of the 6 main categories:
enum Category: UInt32 {
// Basic categories
case block = 0b000001
case ball = 0b000010
case shot = 0b000100
case obstacle = 0b001000
case wizard = 0b010000
case food = 0b100000
}
Since you've used 6 bits for the main category, you have 26 bits remaining. To encode the 16 subcategories needs 4 bits. You can put those in the category bit mask above the main 6 bits. Example manipulations:
func encodeObject(category: Category, subcategory: Int) -> UInt32 {
return category.rawValue | (UInt32(subcategory) << 6)
}
func nodeIsA(node: SKNode, category: Category) -> Bool {
guard let body = node.physicsBody else { return false }
return (body.categoryBitMask & category.rawValue) != 0
}
func subcategory(node: SKNode) -> Int {
guard let body = node.physicsBody else { fatalError("missing physicsbody") }
return Int(body.categoryBitMask >> 6)
}
Note that the subcategories are just sort of tagging along for the ride; all your contactBitMasks would deal only to the main categories.
Essentially you're using the fact that you've got some extra bits in the physics body category bit masks to just store random information. I've done that before with simple sprites. But if the information needed is going to get any more complex that a simple number or index, I'd recommend making subclasses of nodes rather than trying to squirrel stuff away in the unused bits.
Using contact.bodyA.node and contact.bodyB.node you can get the SKNode(s) which are involved in the contact
extension GameScene: SKPhysicsContactDelegate {
func didBegin(_ contact: SKPhysicsContact) {
switch (contact.bodyA.node, contact.bodyB.node) {
case (let ball as Ball, let block as Block):
didBeginContactBetween(ball: ball, andBlock: block)
case (let block as Block, let ball as Ball):
didBeginContactBetween(ball: ball, andBlock: block)
default:
break
}
}
func didBeginContactBetween(ball: Ball, andBlock block: Block) {
// TODO: put your code here
}
}

line spacing in dynamically created swift 3/xcode labels

I'm having an issue where I am getting a list of skills back from an api and I want them to stack one on top of the other in two different sections, a left column and a right column. It works well but if the skill is longer than the width of the label it drops to a new line with the same spacing as the rest of the labels. The skill Adobe Creative Suite looks like Adobe Creative as one and Suite as another. I would like Suite to be underneath Adobe Creative but much closer so you can tell it's all one skill.
My code is here:
lblLeft.text = ""
lblRight.text = ""
if let expertiseCount = helper.expertise {
for i in 0..<expertiseCount.count {
if i % 2 == 0 {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10
let attrString = NSMutableAttributedString(string: lblLeft.text! + "\(expertiseCount[i].name ?? "")\n")
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range: NSMakeRange(0, attrString.length))
lblLeft.attributedText = attrString
} else {
let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.lineSpacing = 10
let attrString = NSMutableAttributedString(string: lblRight.text! + "\(expertiseCount[i].name ?? "")\n")
attrString.addAttribute(NSParagraphStyleAttributeName, value:paragraphStyle, range: NSMakeRange(0, attrString.length))
lblRight.attributedText = attrString
}
}
}
I've already tried line spacing and that just changes the size between all lines so the space between Adobe Creative and Suite takes on that change as well.
Try:
lblLeft.numberOfLines = 0
lblLeft.lineBreakMode = .byWordWrapping
lblLeft.sizeToFit()
By setting number of lines to zero and turning word wrapping on, the label will grow to the required number of lines. sizeToFit() should size it properly.

XCode changing default behaviour of comment shortcuts

Is there a way to customise XCode comment actions. Example:
original
func thisfunc() {
var x = 5
}
when commented (cmd + /)
func thisfunc() {
// var x = 5
}
not
func thisfunc() {
// var x = 5
}
In the default behaviour XCode puts the comment in the beginning of the line but I want it to be like the first commented example (like sublime text comment blocks).
I don't think you can customize XCode the way you want. However there's still a way to do it by the steps are (1) selecting commented code (2) cmd + [ (3) cmd + / (4) ctrl + i. Have a try and this is not that complicated.

Select hyphenated word with double-click

UPDATE: Per the recommendation below, here's specifically what I'd like to do: If I double-click the mouse cursor anywhere from the "b" to the "n" of "blue-green", I want all of the word "blue-green" should be highlighted. How can this be done? Currently, depending on where you click, it treats "blue-green" as three separate character strings. So, if you double click between the "b" and "e" of "blue" it highlights only "blue" and not "-green." If you double-click the hyphen, it highlights the hyphen alone. And if you double-click between the "g" and "n" of "green" it highlights only "green" and not "blue-".
ORIGINAL: When I double-click a hyphenated word or set of characters (e.g. "123-abc" or "blue-green" etc.), only the part of the word that I double-clicked is highlighted. I'd like the whole word to be highlighted.
I'm using Windows 7 Pro. If it needs to be done on a per-application basis, I'm most interested in fixing it for Google Chrome, but any Windows-compatible web browser would be OK.
Old question, but I happen to have been working on the same issue. Here's my solution:
jsFiddle.net
"use strict"
// Tweak to make a double-click select words with hyphens
//
// As of 2016-0816, None of the major Mac browser selects whole words
// with hyphens, like "ad-lib". This tweak fixes the hypen issue.
//
// Note: Firefox 48.0 doesn't automatically select whole words with
// apostrophes like "doesn't". This tweak also treats that.
;(function selectWholeWordsWithHyphens(){
var pOutput = document.getElementById("output")
var selection = window.getSelection()
// Regex designed to find a word+hyphen before the selected word.
// Example: ad-|lib|
// It finds the last chunk with no non-word characters (except for
// ' and -) before the first selected character.
var startRegex = /(\w+'?-?)+-$/g
// Regex designed to find a hyphen+word after the selected word.
// Example: |ad|-lib
var endRegex = /^-('?-?\w+)+/
// Edge case: check if the selection contains no word
// characters. If so, then don't do anything to extend it.
var edgeRegex = /\w/
document.body.ondblclick = selectHyphenatedWords
function selectHyphenatedWords(event) {
if (!selection.rangeCount) {
return
}
var range = selection.getRangeAt(0)
var container = range.startContainer
var string = container.textContent
var selectionUpdated = false
if (string.substring(range.startOffset, range.endOffset)
.search(edgeRegex) < 0) {
// There are no word characters selected
return
}
extendSelectionBackBeforeHypen(string, range.startOffset)
extendSelectionForwardAfterHyphen(string, range.endOffset)
if (selectionUpdated) {
selection.removeAllRanges()
selection.addRange(range)
}
function extendSelectionBackBeforeHypen(string, offset) {
var lastIndex = 0
var result
, index
string = string.substring(0, offset)
while (result = startRegex.exec(string)) {
index = result.index
lastIndex = startRegex.lastIndex
}
if (lastIndex === offset) {
range.setStart(container, index)
selectionUpdated = true
}
}
function extendSelectionForwardAfterHyphen(string, offset) {
if (!offset) {
return
}
string = string.substring(offset)
var result = endRegex.exec(string)
if (result) {
range.setEnd(container, offset + result[0].length)
selectionUpdated = true
}
}
}
})()
It's a standard through all programs that it will do that because they all run off the operating system's typing configuration/program thing. To fix it you would need to do something in System32. I don't know what you would need to do but I suspect this is your problem. You should probably go into more detail though about specifically what it is you want.

Resources