Related
I do realize similar questions have been asked before, I looked at them before seeking help. But they were either not in Swift or too complex for me to decipher. My question is different from How do I shuffle an array in Swift? in that I have already done some of the work, like shuffling. The title was actually different from the question asked, which was "How do I randomize or shuffle the elements within an array in Swift?" I am only interested in iterating the resulting array and I couldn't separate that part from the rest of the code in the answers given for a question that encompassed so much more. That said, there are some great suggestions on that page so I think people like me will benefit from having both pages available. Maybe someone can set up a reciprocal link on that page as I have done here.
Admittedly, I am new to Swift and not a seasoned programmer in any language, but please don't assume I am coming here seeking help without trying to figure it out on my own. I am spending many hours learning the fundamentals of all C based languages and reading the Swift literature at developer.apple.com.
So the question will be more obvious, I and attempting to build the card game War. Thus far I have accomplished constructing the (an array) deck of cards and randomized it (shuffled). I am stuck at looping through the resulting array of 52 objects and assigning (moving) them to the two players hands (two new arrays). I'm not sure how much of my code I should display in order to help me but if you need more, I'll gladly provide it. Please note that this is only an exercise, practice for me to learn how to write complex programs, and some code, like the function to randomize, is not mine, I found it right here at stackoverflow. I'd almost prefer if you didn't just hand me the code that will work, I'm not likely going to learn as much that way, but if providing steps in plain English so I can figure out the syntax is too much trouble, so be it, provide an example, I'm sure I'll get plenty of chances to write/use the syntax later.
One more note, I'm only working in a playground at the moment, when and if I can get all the code working, I'll move to the UI stuff.
Thanks in advance, Rick
/* Skipping past everything I did to get here,
the array (shuffledDeck) has 52 shuffled cards (elements) in it.
The array is NSMutableArray and contains strings like
2Hearts, 5Spades, 14Clubs, etc. Each suit has 14 cards.*/
shuffledDeck
// create vars to hold shuffled hands
var playerOneHand = []
var playerTwoHand = []
/* Started a for loop to assign cards to each hand
but don't know which method(s) is/are best to use
to remove the first or last card and alternately
append (move) it to the (hopefully) initialized
variables playerOneHand and PlayerTwoHand.
Optionally, since the cards are already shuffled,
I could just split the deck using the range method,
whichever is easier. I tried and failed at both ways.*/
var i = 0
for dealtCard in shuffledDeck {
}
var shuffledDeck:[String] = ["2Hearts", "5Spades", "14Clubs", "etc"]
//shuffledDeck will of course be your shuffled deck
var playerOneHand:[String] = []
var playerTwoHand:[String] = []
for (index, cardString) in enumerate(shuffledDeck) {
if index % 2 == 0 {
playerOneHand.append(cardString)
}else{
playerTwoHand.append(cardString)
}
}
I’m looping through every item in the shuffledDeck, but with that I use the index of the array to get a number. I use this number to see if that number devided by 2 is equal to 0 (the number is even) or not (uneven) if a number is even, I get the item that is in the array at the given index and add that item to the hand of player one. If the index is uneven I add the item to the second player’s hand. This means the first item goed to player one’s hand, the second item goes to the hand of the second player. the third Item goes back to the first player and so on.
As mentioned by Martin R you can use the range method to assign the first half of the deck to the first player and the second to the second player as follow:
let cards:[String] = ["2♦️","3♦️","4♦️","5♦️","6♦️","7♦️","8♦️","9♦️","T♦️","J♦️","Q♦️","K♦️","A♦️","2♠️","3♠️","4♠️","5♠️","6♠️","7♠️","8♠️","9♠️","T♠️","J♠️","Q♠️","K♠️","A♠️","2♥️","3♥️","4♥️","5♥️","6♥️","7♥️","8♥️","9♥️","T♥️","J♥️","Q♥️","K♥️","A♥️","2♣️","3♣️","4♣️","5♣️","6♣️","7♣️","8♣️","9♣️","T♣️","J♣️","Q♣️","K♣️","A♣️"]
extension Array {
var shuffled:[T] {
var elements = self
for index in 0..<elements.count - 1 {
swap(&elements[index], &elements[Int(arc4random_uniform(UInt32(elements.count - 1 - index))) + index])
}
return elements
}
}
let cardsShuffled = cards.shuffled
let playerOneHand = cardsShuffled[0...25]
let playerTwoHand = cardsShuffled[26...51]
Note: The shuffle extension was created using this answer as reference
i mean is it possible to have a method that gets as its parameters an array of objects and another parameter which indicates which field of the objects we are using to sort the array ?
for example if the objects are contacts if we call sort(contacts , name) it would sort them with respect to name. if we call sort(contacts , number) it sorts them according to their numbers.
maybe by sending an String of the field we want !! something like :
class sorting {
public static bubble_sort(Object[] array , String field){
for(int i =0; i<array.length ; i++){
if(array[i].field > array[i+1].field)
swap(array ,i ,i+1);
}
}
(preferably in java) (and please include examples of the solutions you give !)
Assuming this is Java: yes, it is possible. You can use reflection to get the field type and value and then compare them. It would not be a good idea. Much better to use Comparator with the existing sort method.
A method that would work in pretty much any language is to pass in some kind of function object.
class sorting {
public static bubble_sort(Object[] array, FunctionObject ordering) {
for(int i =0; i<array.length ; i++){
if(ordering(array[i+1], array[i]))
swap(array ,i ,i+1);
}
};
different languages are going to have different syntaxes for such a function object -- what its type is, etc -- but pretty much every language is going to have some way to do it.
Generally the best signature for it is one that takes two different objects, and returns true if the left one is less than the right one.
Similarly, different languages are going to have different ways of invoking a function object. Some may require ordering.Invoke( array[i+1], array[i] ).
In that function object, compare the field in question. If the language/objects have reflection, you can sometimes do this via field name directly.
As this pattern is very useful, languages tend to make it easier as they mature. So the most recent version of your language may have a syntax to create such objects with far less syntax, and invoke them with less syntax as well.
I have a flash game that I'm building where I have an array keeping track of a bunch of power ups on the screen. When the player goes an grabs one it needs to disappear from the screen (which is easy) but it also needs to be removed from the array so that collision detection loops don't become really cumbersome. I tried using splice, but I keep get null reference errors, here's the relevant code.
public function collect():void {
try {
Main.powerUps.splice(index, 1);
stage.removeChild(this);
}catch (e:Error) {
trace("Error in splice");
}
}
}
Then when I create my PowerUp object I pass it a parameter that gets assigned to index which is the length of the array of Power Ups at the time. Can anyone see what's wrong with this code or (preferably) provide a more elegant solution? Thanks in advance for any help.
Elegant solution: use indexOf() and splice() together!
var index:int = Main.powerUps.indexOf( powerup );
Main.powerUps.splice(index, 1);
Where powerup is a reference to the object stored within the array Main.powerUps.
I also created a little class a while back that may be useful to you:
https://github.com/MartyWallace/Lotus/blob/master/Lotus/lotus/utils/Set.as
It has a .remove() method so you can just do:
powerUps.remove(powerup);
I'm using Google Docs Spreadsheet API to keep track of a competition between some of my friends. I have some big ideas, but I'm stumped right now. I'm trying to create 20 different arrays inside of loops (see below) and then evaluate each one outside of the loop, and I really don't want to write 20 "if...then" statements.
NOTE: the following SUMMARY may or may not help you answer my question. You might want to skip down to the code, then read this if you need it :)
Summary of the program: Each player assigns point values in favor of one possible outcome of a set of binary-outcome events. As the events happen, players either gain the points assigned if their outcome occurs, or gain no points if the opposite outcome occurs. My goal is to 1) figure out exactly when a player is eliminated, and 2) highlight all remaining events that must be won for them to have a chance at tying for first.
Instead of trying to somehow evaluate all possibilities (5 players picking, 2^16 outcomes... I have zero computer science knowledge, but this seems like an incredibly huge task even for the modern computer) I've come up with an alternate idea. The script loops through each player, against each other opponent. It calculates the maximum number of points a player can score based on their value assignments and the already determined game. For one player and one opponent, it checks the best possible outcome by the player against that opponent, and if there is any opponent he cannot beat, even in the best case, then he is eliminated.
This part is easy-- after the loop runs inside the loop, I just adjust a global variable that I created earlier, and when the outer loop is done, just grab those variables and write them to the sheet.
Unfortunately, this misses the case of where he could have a best case against each individual opponent, but not against multiple opponents at once.
So the next step is what I'm trying to do now. I'm not even sure I can give a good explanation without just showing you the entire spreadsheet w/script, but I'll try. So what I want to do now is calculate the "value" of each event for each player against a given other player. If both player and opponent assigned points in favor of the same event outcome for one event, the event's value is the difference between the picks (positive if player picked higher, negative if lower), and it's the SUM if they picked opposite event outcomes. Now, I do the same thing as before-- take a best-case scenario for a player against a given opponent-- but now I check by how much the player can beat the opponent in a best-case scenario. Then I evaluate the (absolute value of the) event value against this difference, and if it's greater, then the event is a must win (or must lose if the event value is negative). And, if an event is both a "must-win" and a "must lose" event, then the player is eliminated.
The problem is that this second step requires me to create a new array of values for each player-opponent combination, and then do things with the values after they're created.
I realize one approach would be to create 20 different arrays, and throughout the entire loops, keep checking "if (player == "1" && opponent == 2){}" and populate the arrays accordingly, but this seems kind of ridiculous. And more importantly, this entire project is my attempt at learning javascript, so what's the point in using a time-intensive workaround that doesn't teach me anything new?
I'm trying to understand square bracket notation, since it seems to be the answer to my question, but a lot of people are also suggesting that it's impossible to create variable names by concatenating with the value of another variable... so anyway, here's what I'm trying. I'd really appreciate either a fix to my approach, or a better approach.
for (var player=1; player<6; player++){
if(player==1){look up certain columns in the spreadsheet and save them to variables}
//ditto for other players
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
if(opponent==1){save more values to variables}
//ditto for other players
for(var row=9; row<24; row++) {
//Now the script goes down each row of an array containing the original
//spreadsheet info, and, based on information determined by the variables
//created above, get values corresponding to the player and opponent.
//So what I'd like to do here is create "array[1,2]==" and then "array[1,3]=="
//and so forth, creating them globally (I think I understand that term by now)
//so I can refer to them outside of the loops later to do some evaluatin'.
}
}}
//get array[1,2]...array[5,4] and do some operations with them.
Thanks for getting through this little novel... really looking forward to your advice and ideas!
How can I create arrays within a loop (within another loop)?
Code update 2
As you said: "i am trying to understand square bracket notation" You may take a look at my new demo and the code:
function getTeam(){
var array = [[1,2,3],[4,5,6],[7,8,9]]; // arrays within arrays
// array myTeam
var myTeam = [[],[],[],[]];
var playerNames = ["John", "Bert", "Dave", "Milton"];
var ages =[];
var weight = 104;
// loop over the team arrayadd each player (name, age and weight) to the team
for (i=0; i < myTeam.length; i++){
// fill the age array in a loop
for (j=0;j<myTeam.length;j++) {
ages[j] = 23 + j;
}
myTeam[i].push([playerNames[i], ages[i], weight]);
}
return myTeam;
}
And pass them back out in Javascript
Could you elaborate on this part?
Update
var valuesOfPlayers=[];
for (var player=1; player<6; player++){
// look up certain columns in the spreadsheet and save them to variables
// you could call a funcntion and return the values you
// collected in an array within an array as in the demo above
valuesOfPlayers[player] = lookupColumnValues(player);
for(var opponent=1; opponent<6; opponent++){
if(player!=opponent){
// save more values to variables
valuesOfPlayers[player] = addValuesToVar(player);
}
for(var row=9; row<24; row++) {
// if you collect the values in your first and second if clause
// what other information do you want to collect
// Please elaborate this part?
}
}}
One workaround:
I could create an array before the execution of the loops.
At the start of each loop, I could push a string literal to the array containing the value of player and opponent.
After the loops are done, I could split the array into multiple arrays, or just evaluate them in one big array using regular expressions.
I'd still rather create new arrays each time-- seems like it is a more universal way of doing this, and learning how would be more educational for me than using this workaround.
My project has classes which, unavoidably, contain hundreds upon hundreds of variables that I'm always having to keep straight. For example, I'm always having to keep track of specific kinds of variables for a recurring set of "items" that occur inside of a class, where placing those variables between multiple classes would cause a lot of confusion.
How do I better sort my variables to keep from going crazy, especially when it comes time to save my data?
Am I missing something? Actionscript is an Object Oriented language, so you might have hundreds of variables, but unless you've somehow treated it like a grab bag and dumped it all in one place, everything should be to hand. Without knowing what all you're keeping track of, it's hard to give concrete advice, but here's an example from a current project I'm working on, which is a platform for building pre-employment assessments.
The basic unit is a Question. A Question has a stem, text that can go in the status bar, a collection of answers, and a collection of measures of things we're tracking about what the user does in that particular type of questions.
The measures are, again, their own type of object, and come in two "flavors": one that is used to track a time limit and one that isn't. The measure has a name (so we know where to write back to the database) and a value (which tells us what). Timed ones also have a property for the time limit.
When we need to time the question, we hand that measure to yet another object that counts the time down and a separate object that displays the time (if appropriate for the situation). The answers, known as distractors, have a label and a value that they can impart to the appropriate measure based on the user selection. For example, if a user selects "d", its value, "4" is transferred to the measure that stores the user's selection.
Once the user submits his answer, we loop through all the measures for the question and send those to the database. If those were not treated as a collection (in this case, a Vector), we'd have to know exactly what specific measures are being stored for each question and each question would have a very different structure that we'd have to dig through. So if looping through collections is your issue, I think you should revisit that idea. It saves a lot of code and is FAR more efficient than "var1", "var2", "var3."
If the part you think is unweildy is the type checking you have to do because literally anything could be in there, then Vector could be a good solution for you as long as you're using at least Flash Player 10.
So, in summary:
When you have a lot of related properties, write a Class that keeps all of those related bits and pieces together (like my Question).
When objects have 0-n "things" that are all of the same or very similar, use a collection of some sort, such as an Array or Vector, to allow you to iterate through them as a group and perform the same operation on each (for example, each Question is part of a larger grouping that allows each question to be presented in turn, and each question has a collection of distractors and another of measures.
These two concepts, used together, should help keep your information tidy and organized.
While I'm certain there are numerous ways of keeping arrays straight, I have found a method that works well for me. Best of all, it collapses large amounts of information into a handful of arrays that I can parse to an XML file or other storage method. I call this method my "indexed array system".
There are actually multiple ways to do this: creating a handful of 1-dimensional arrays, or creating 2-dimensional (or higher) array(s). Both work equally well, so choose the one that works best for your code. I'm only going to show the 1-dimensional method here. Those of you who are familiar with arrays can probably figure out how to rewrite this to use higher dimensional arrays.
I use Actionscript 3, but this approach should work with almost any programming or scripting language.
In this example, I'm trying to keep various "properties" of different "activities" straight. In this case, we'll say these properties are Level, High Score, and Play Count. We'll call the activities Pinball, Word Search, Maze, and Memory.
This method involves creating multiple arrays, one for each property, and creating constants that hold the integer "key" used for each activity.
We'll start by creating the constants, as integers. Constants work for this, because we never change them after compile. The value we put into each constant is the index the corresponding data will always be stored at in the arrays.
const pinball:int = 0;
const wordsearch:int = 1;
const maze:int = 2;
const memory:int = 3;
Now, we create the arrays. Remember, arrays start counting from zero. Since we want to be able to modify the values, this should be a regular variable.
Note, I am constructing the array to be the specific length we need, with the default value for the desired data type in each slot. I've used all integers here, but you can use just about any data type you need.
var highscore:Array = [0, 0, 0, 0];
var level:Array = [0, 0, 0, 0];
var playcount:Array = [0, 0, 0, 0];
So, we have a consistent "address" for each property, and we only had to create four constants, and three arrays, instead of 12 variables.
Now we need to create the functions to read and write to the arrays using this system. This is where the real beauty of the system comes in. Be sure this function is written in public scope if you want to read/write the arrays from outside this class.
To create the function that gets data from the arrays, we need two arguments: the name of the activity and the name of the property. We also want to set up this function to return a value of any type.
GOTCHA WARNING: In Actionscript 3, this won't work in static classes or functions, as it relies on the "this" keyword.
public function fetchData(act:String, prop:String):*
{
var r:*;
r = this[prop][this[act]];
return r;
}
That queer bit of code, r = this[prop][this[act]], simply uses the provided strings "act" and "prop" as the names of the constant and array, and sets the resulting value to r. Thus, if you feed the function the parameters ("maze", "highscore"), that code will essentially act like r = highscore[2] (remember, this[act] returns the integer value assigned to it.)
The writing method works essentially the same way, except we need one additional argument, the data to be written. This argument needs to be able to accept any
GOTCHA WARNING: One significant drawback to this system with strict typing languages is that you must remember the data type for the array you're writing to. The compiler cannot catch these type errors, so your program will simply throw a fatal error if it tries to write the wrong value type.
One clever way around this is to create different functions for different data types, so passing the wrong data type in an argument will trigger a compile-time error.
public function writeData(act:String, prop:String, val:*):void
{
this[prop][this[act]] = val;
}
Now, we just have one additional problem. What happens if we pass an activity or property name that doesn't exist? To protect against this, we just need one more function.
This function will validate a provided constant or variable key by attempting to access it, and catching the resulting fatal error, returning false instead. If the key is valid, it will return true.
function validateName(ID:String):Boolean
{
var checkthis:*
var r:Boolean = true;
try
{
checkthis = this[ID];
}
catch (error:ReferenceError)
{
r = false;
}
return r;
}
Now, we just need to adjust our other two functions to take advantage of this. We'll wrap the function's code inside an if statement.
If one of the keys is invalid, the function will do nothing - it will fail silently. To get around this, just put a trace (a.k.a. print) statement or a non-fatal error in the else construct.
public function fetchData(act:String, prop:String):*
{
var r:*;
if(validateName(act) && validateName(prop))
{
r = this[prop][this[act]];
return r;
}
}
public function writeData(act:String, prop:String, val:*):void
{
if(validateName(act) && validateName(prop))
{
this[prop][this[act]] = val;
}
}
Now, to use these functions, you simply need to use one line of code each. For the example, we'll say we have a text object in the GUI that shows the high score, called txtHighScore. I've omitted the necessary typecasting for the sake of the example.
//Get the high score.
txtHighScore.text = fetchData("maze", "highscore");
//Write the new high score.
writeData("maze", "highscore", txtHighScore.text);
I hope ya'll will find this tutorial useful in sorting and managing your variables.
(Afternote: You can probably do something similar with dictionaries or databases, but I prefer the flexibility with this method.)