Related
I'm using discord.js and I want to create a "server" with passcode. I want the passcode to be 6 letters long, so far I can only do one.
It has to be random as well. Like "ZSHWJK" Instead of "AAAAAA"
Code:
var serverPasscode = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
module.exports = {
name: "createserver",
description: "Creates a server",
run(message, args, client){
const newServer = new MessageEmbed()
.setTitle(`${message.author.name}'s server`)
.setFooter(`${serverPasscode[Math.floor(Math.random() * serverPasscode.length)]}`)
message.channel.send(newServer);
}
};
Right now this can only return one element which is not what I want.
You could use a for loop and create a function such as this:
function makeGuildPassword(length) {
var result = ''; // create empty string that you will add random characters to
var characters = // list of characters (you can change this however you want)
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < length; i++) { // create a loop
// add a random character to the string; restart the loop
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
};
console.log(makeGuildPassword(6))
Enumerable#map creates an array with the return values in the block after it's yielded.
In such case, say:
v = 'a'
26.times.map { |i| v.ord.+(i).chr }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
But why does the following codes fills the array with same elements?
v = '`'
26.times.map { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
v = '`'
Array.new(26) { v.next! }
# => ["z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z", "z"]
Shouldn't they all have elements a to z?
Again, this works:
v = '`'
Array.new(26) { v = v.succ }
# => ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
Actually I am trying to do:
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v = v.succ) }
# => {:a=>"𝓪", :b=>"𝓫", :c=>"𝓬", :d=>"𝓭", :e=>"𝓮", :f=>"𝓯", :g=>"𝓰", :h=>"𝓱", :i=>"𝓲", :j=>"𝓳", :k=>"𝓴", :l=>"𝓵", :m=>"𝓶", :n=>"𝓷", :o=>"𝓸", :p=>"𝓹", :q=>"𝓺", :r=>"𝓻", :s=>"𝓼", :t=>"𝓽", :u=>"𝓾", :v=>"𝓿", :w=>"𝔀", :x=>"𝔁", :y=>"𝔂", :z=>"𝔃"}
But I get all z's instead while using succ! / next!
v = "\xf0\x9d\x93\xa9"
('a'..'z').reduce({}) { |h, i| h.merge(i.intern => v.succ!) }
# => {:a=>"𝔃", :b=>"𝔃", :c=>"𝔃", :d=>"𝔃", :e=>"𝔃", :f=>"𝔃", :g=>"𝔃", :h=>"𝔃", :i=>"𝔃", :j=>"𝔃", :k=>"𝔃", :l=>"𝔃", :m=>"𝔃", :n=>"𝔃", :o=>"𝔃", :p=>"𝔃", :q=>"𝔃", :r=>"𝔃", :s=>"𝔃", :t=>"𝔃", :u=>"𝔃", :v=>"𝔃", :w=>"𝔃", :x=>"𝔃", :y=>"𝔃", :z=>"𝔃"}
Except succ! / next! doesn't change the memory location and object_id, aren't v.succ! and v = v.succ same?
When you call next! or succ! on a variable str, object assigned to this variable is mutated and a reference to this object is returned. If str = 'a' and you call str.next! 26 times, str becomes z. Every time next! is called, a reference to the same object is returned. As a result, you get an array of 26 references to the same object. That's why all of the elements in the array are the same.
You can test that by checking object_id of array elements:
pry(main)> str = 'a'
'a'
pry(main)> array = 3.times.map{ str.next!}
=> ["d", "d", "d"]
pry(main)> array.map(&:object_id)
=> [47056742362940, 47056742362940, 47056742362940]
pry(main)> array.map(&:object_id).uniq
=> [47056742362940]
When you edit str, all array elements are updated:
[39] pry(main)> str << "b"
=> "db"
[40] pry(main)> array
=> ["db", "db", "db"]
[41] pry(main)> str.replace
str.replace
[41] pry(main)> str.replace('a')
=> "a"
[42] pry(main)> array
=> ["a", "a", "a"]
If you want to have an array with the whole alphabet, you need to copy the string after changing current letter, see below:
[25] pry(main)> str = 'a'
=> "a"
[26] pry(main)> 25.times.map{ str.next!.dup}
=> ["b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"w",
"x",
"y",
"z"]
You can also use a range:
[32] pry(main)> ('a'..'z').to_a
=> ["a",
"b",
"c",
"d",
"e",
"f",
...
Here's an array:
scramble = [
"R", "U", "R' ", "U' ", "L", "L' ", "L2", "B", "B' ",
"B2", "F", "F' ", "F2", "R2", "U2", "D", "D' ", "D2"
]
I want to shuffle it with a condition such that "R", "R' ", and "R2" are not together while shuffled, and similar for other letters.
scramble.shuffle does shuffle it, but how can I set such conditions?
Lets derive a generic solution.
Given a 2D array of groups of elements, return an array of shuffled elements such that no two consecutive elements belong to same group.
For example:
all_groups = [
["R", "R'", "R2" ],
["L", "L'", "L2" ],
["U", "U'", "U2" ],
["D", "D'", "D2" ],
["F", "F'", "F2" ],
["B", "B'", "B2" ]
]
Expected output:
["F'", "U'", "R'", "L2", "R2", "D2", "F2", "R", "L", "B", "F", "L'", "D'", "B'", "U2", "B2", "U", "D"]
TL;DR Code:
all_groups = [
["R", "R'", "R2" ],
["L", "L'", "L2" ],
["U", "U'", "U2" ],
["D", "D'", "D2" ],
["F", "F'", "F2" ],
["B", "B'", "B2" ]
]
ans = []
total = all_groups.map(&:length).reduce(:+)
# Initial shuffling
all_groups = all_groups.each { |i| i.shuffle! }.shuffle
until all_groups.empty?
# Select and pop last group
last_group = all_groups.pop
# Insert last element to our ans, and remove from group
ans.push(last_group.pop)
total -= 1
# Shuffle remaining groups
all_groups.shuffle!
# Check if any group has reached critical state
length_of_longest_group = all_groups.reduce(0) { |len, i| [len, i.length].max }
if length_of_longest_group * 2 == total + 1
# Move that group to last
# This ensures that next element picked is from this group
longest_group = all_groups.detect { |i| i.length == length_of_longest_group }
all_groups.delete(longest_group)
all_groups.push(longest_group)
end
# Insert the last group at first place. This ensures that next element
# is not from this group.
all_groups.unshift(last_group) unless last_group.empty?
end
puts ans.inspect
Examples:
all_groups = [
["R", "R'", "R2" ],
["L", "L'", "L2" ],
["U", "U'", "U2" ],
["D", "D'", "D2" ],
["F", "F'", "F2" ],
["B", "B'", "B2" ]
]
# Output 1:
ans = ["B'", "U'", "L'", "U2", "R", "B2", "F2", "R2", "D2", "L2", "D", "R'", "U", "F'", "D'", "L", "F", "B"]
# Output 2:
ans = ["U'", "R", "D", "R'", "U", "D2", "B2", "D'", "L", "B", "L2", "B'", "U2", "F'", "L'", "F", "R2", "F2"]
# Output 3:
ans = ["B", "D", "R'", "D'", "B'", "R", "F2", "L", "D2", "B2", "F'", "R2", "U'", "F", "L'", "U2", "L2", "U"]
# Output 4:
ans = ["U'", "F'", "R2", "B2", "D", "L2", "B'", "U", "R", "B", "R'", "L'", "D'", "U2", "F", "D2", "F2", "L"]
# Output 5:
ans = ["U2", "F2", "L'", "F'", "R'", "F", "D'", "B2", "D2", "L", "B", "D", "L2", "B'", "R", "U", "R2", "U'"]
all_groups = [
['a', 'aa', 'aaa', 'A', 'AA', 'AAA'],
['b', 'bb', 'bbb', 'B', 'BB', 'BBB'],
['c', 'cc', 'ccc', 'C', 'CC', 'CCC']
]
ans = ["c", "AAA", "B", "ccc", "bbb", "C", "AA", "CC", "aa", "BB", "CCC", "bb", "cc", "A", "BBB", "a", "b", "aaa"]
all_groups = [
['r1', 'r2', 'r3', 'r4', 'r5', 'r6', 'r7', 'r8'],
['b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8']
]
# Output1:
ans = ["r2", "b7", "r1", "b5", "r7", "b6", "r3", "b8", "r4", "b3", "r5", "b1", "r6", "b4", "r8", "b2"]
# Output2:
ans = ["b6", "r8", "b2", "r1", "b4", "r2", "b8", "r7", "b3", "r4", "b5", "r5", "b7", "r3", "b1", "r6"]
Explanation:
To begin with, lets shuffle the input data. First we shuffle each group, then we shuffle the outer array.
all_groups = all_groups.each { |i| i.shuffle! }.shuffle
Now our array looks like this:
[["B", "B2", "B'"],
["F'", "F", "F2"],
["L", "L2", "L'"],
["R2", "R'", "R"],
["D", "D'", "D2"],
["U'", "U", "U2"]]
Now, if we traverse this array in column-major order, we get a prety decent shuffling of elements wherein no two consecutive elements belong to same group.
["B", "F'", "L", "R2", "D", "U'", "B2", "F", "L2", "R'", "D'", "U", "B'", "F2", "L'", "R", "D2", "U2"]
But only flaw in this is that all elements of a particular group are equidistant. Lets improve.
So we have a set of groups. Lets select any one of group and then select the last element from that group and add this element to our answer array. Now shuffle the 2D array and repeat until all elements are selected.
Also, we don't want any two consecutive elements to belong to same group, so we need to ensure that the next selection of element is from some other group. So how about this strategy:
Always pick the last group from our 2d array, and then once we shuffle we will ensure that this group is not the last group in 2d array.
In terms of psuedocode:
1. Select last group from 2d array.
2. Remove an element from this group.
3. Shuffle the order of other groups in 2d array
4. Insert the selected group at begining.
For example, lets start with this 2d array:
[["D", "D'", "D2"],
["U", "U'", "U2"],
["B2", "B", "B'"],
["F2", "F", "F'"],
["L'", "L", "L2"],
["R'", "R2", "R"]]
last group: ["R'", "R2", "R"]
Element removed: ("R")
Shuffle order of remaining groups of 2d array:
[["L'", "L", "L2"],
["B2", "B", "B'"],
["D", "D'", "D2"],
["U", "U'", "U2"],
["F2", "F", "F'"]]
2D array after inserting the popped group(the group from which we extracted an element)
[["R'", "R2"],
["L'", "L", "L2"],
["B2", "B", "B'"],
["D", "D'", "D2"],
["U", "U'", "U2"],
["F2", "F", "F'"]]
Now, since our logic selects the last group and then inserts it in the begining, we are insured that two elements of same group will never be picked in two consecutive turns.
A catch: There can be a possibility that there is a group which never reaches the last position, hence this group will never shrink, and its element will be forced to be picked consecutively once the number of elements is too less.
For example observe the output of 4 iterations of above algorithm on below input:
[['a', 'aa', 'aaa', 'A', 'AA', 'AAA'],
['b', 'bb', 'bbb', 'B', 'BB', 'BBB'],
['c', 'cc', 'ccc', 'C', 'CC', 'CCC']]
# Output 1: in this 'a' & 'aaa' are together
["CC", "bb", "C", "BB", "aa", "bbb", "AA", "CCC", "b", "c", "B", "cc", "A", "BBB", "AAA", "ccc", "a", "aaa"]
# Output 2: in this 'b' & 'BB' are together
["cc", "A", "B", "c", "AAA", "C", "a", "ccc", "bbb", "CCC", "aaa", "bb", "CC", "aa", "BBB", "AA", "b", "BB"]
# Output 3: this is perfect
["CCC", "BB", "a", "c", "BBB", "aa", "bbb", "A", "bb", "ccc", "B", "CC", "AAA", "b", "AA", "cc", "aaa", "C"]
# Output 4: in this 'c' & 'cc' are together
["CC", "bb", "AA", "b", "aa", "BBB", "aaa", "bbb", "CCC", "B", "A", "BB", "C", "a", "ccc", "AAA", "c", "cc"]
So, there are chances that when ratio of number of elements in a group to total no of elements increases, two elements of same group can be clubbed together. Hmm, lets improve further:
Since the group with maximum number of elements has most probability of having two elements combined consecutively, lets study such groups. i.e. group with maximum number of elements.
Lets say, there is a group with X number of elements in it. So what is the minimum number of other type of elements required that none of the X elements are consecutive? Simple right: insert a different element between each pair of element of this group.
x * x * x * x * x * x
So we realise, that if group has X elements it requires atleast (X-1) other type of elements so that no two elements of this group get consecutive.
Mathematically the condition can be represented as:
number_of_elements_in_longest_group == number_of_other_type_of_elements + 1
=> number_of_elements_in_longest_group == (total_number_of_elements - number_of_elements_in_longest_group) + 1
=> number_of_elements_in_longest_group * 2 == total_number_of_elements + 1
Going back to our algorithm, lets add a condition, that at any point of time, if number of remaining items is 1 less than the number of elements in largest group then we have to ensure that next element picked is from this largest group
Juksefantomet sent me this solution in discord, since he can't post here due to an account lock.
The below codeblock contains an alternative approach on how to tackle the problem at hand. This contains a fragmented solution to understand the steps on how you would normally approach a complex problem like the one presented above.
going through the various steps you can see how each condition has to be known in advance and specified to the point where your final array is not "illegal".
#illegal_order = ['1','2','3','4','5','6','7','8','9']
puts #illegal_order.count
puts "#{#illegal_order}"
#foo = []
# traverse the original array and append a random value from that into foo array
# this can of course and should be done in a loop where you check for duplicates
# this is done below in this example, fragmented to see the individual action
(0..#illegal_order.count).each do |add_value|
#temp = #illegal_order[rand(#illegal_order.count)]
unless #foo.count == #illegal_order.count
#foo.push(#temp)
end
end
# making sure it contains everything in the original array
#foo.each do |bar|
unless #illegal_order.include?(bar)
#approve = false
puts "Errored generation!"
end
end
# defining patterns, this can of course be extracted by the original array and be done alot cleaner
# but printing it out to better break it down
#pattern1 = [#illegal_order[0],#illegal_order[1],#illegal_order[2]]
#pattern2 = [#illegal_order[3],#illegal_order[4],#illegal_order[5]]
#pattern3 = [#illegal_order[6],#illegal_order[7],#illegal_order[8]]
# Let us step through the new array and use case to check for various conditions that would flag the new array as invalid
#foo.each do |step|
# setting a temp pattern based on current state
#temp_pattern = [#foo[step.to_i-1],#illegal_order[step.to_i],#illegal_order[step.to_i+1]]
case step
when #temp_pattern == #pattern1
#illegalpatterns = true
when #temp_pattern == #pattern2
#illegalpatterns = true
when #temp_pattern == #pattern3
#illegalpatterns = true
end
# checking the foo array if it contains duplicates, if yes, set conditional to true
#illegal_order.each do |count|
if #foo.count(count) > 1
#duplicates = true
end
end
end
# printing out feedback based on duplicates or not, this is where you rescramble the array if duplicate found
(#duplicates == true) ? (puts "dupes found") : (puts "looks clear. no duplicates")
# printing out feedback based on illegal patterns or not, this is where you rescramble the array if duplicate found
(#illegalpatterns == true) ? (puts "illegal patterns found") : (puts "looks clear, no illegal patterns")
puts "#{#foo}"
I have cars described in a file in this form:
CAR
Audi
1x1
XXX
XXXXX
_X
_X
I want to insert the cars from this file into a 10 x 10 nested array.
The second line are coordinates (R x C) from the left top point for the start of the car. Third to fifth lines show the shape of the car.
OUTPUT= [["O","O","O","O","O","O","O","O","O","O"],
["O","X","X","X","O","O","O","O","O","O"],
["O","X","X","X","X","X","O","O","O","O"],
["O","O","X","O","O","O","O","O","O","O"],
["O","O","X","O","O","O","O","O","O","O"]
["O","O","O","O","O","O","O","O","O","O"]
["O","O","O","O","O","O","O","O","O","O"]
["O","O","O","O","O","O","O","O","O","O"]
["O","O","O","O","O","O","O","O","O","O"]
["O","O","O","O","O","O","O","O","O","O"]
INPUT arr =[]
This should work, pretty tricky. Sure there is a better way.
First map the file into a hash.
car_array = []
File.open('car_array.txt').each_with_index do |line, idx|
car_array << line.chomp
end
p car_array
# => ["CAR", "Audi", "1x1", "XXX", "XXXXX", "_X", "_X", "CAR", "BMW", "5x1", "__X", "XXX", "X", "XX"]
car_hash = {}
key = nil
car_array.each_with_index do |e, index|
key = car_array[index-1].downcase.to_sym if car_array[index-2] == "CAR"
car_hash[key] = [e] if car_array[index-2] == "CAR"
car_hash[key] << e if car_hash[key] unless (car_array[index-2] == "CAR" || car_array[index-1] == "CAR" || car_array[index] == "CAR")
end
p car_hash
# => {:audi=>["1x1", "XXX", "XXXXX", "_X", "_X"], :bmw=>["5x1", "__X", "XXX", "X", "XX"]}
car_hash.transform_values do |array|
h = {start: [], points: []}
h[:start] = array[0].split('x').map(&:to_i).map!{ |e| e}
(array.size - 1).times do |n|
h[:points] << array[n+1]
end
array[0] = h
(array.size - 1).times do |n|
array.pop
end
end
car_hash.transform_values! {|v| v[0]}
p car_hash
# => {:audi=>{:start=>[1, 1], :points=>["XXX", "XXXXX", "_X", "_X"]}, :bmw=>{:start=>[5, 1], :points=>["__X", "XXX", "X", "XX"]}}
car_hash.each_value do |car|
car[:points].map! do |point|
point.scan(/./)
end
row = car[:start][0] - 1
col = car[:start][1] - 1
car[:points].map! do |points|
delta_col = 0
row += 1
points.map! do |point|
delta_col +=1
point == 'X' ? [row, col + delta_col] : nil
end
points.compact
end
car[:points] = car[:points].flatten(1)
end
p car_hash
# => {:audi=>{:start=>[1, 1], :points=>[[1, 1], [1, 2], [1, 3], [2, 1], [2, 2], [2, 3], [2, 4], [2, 5], [3, 2], [4, 2]]}, :bmw=>{:start=>[5, 1], :points=>[[5, 3], [6, 1], [6, 2], [6, 3], [7, 1], [8, 1], [8, 2]]}}
Then us the hash to build the table.
table_model = Array.new(10) {Array.new(10,'O')}
def print_table (table)
table.each {|row| p row}
end
audi_table = table_model.dup
car_hash[:audi][:points].each { |point| audi_table[point[0]][point[1]] = 'x' }
print_table audi_table
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "x", "x", "x", "O", "O", "O", "O", "O", "O"]
# => ["O", "x", "x", "x", "x", "x", "O", "O", "O", "O"]
# => ["O", "O", "x", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "x", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
# => ["O", "O", "O", "O", "O", "O", "O", "O", "O", "O"]
I aware to get random character from a string. From here is the code,
func randomString(_ length: Int) -> String {
let master = Array("abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_123456789".characters) //0...62 = 63
var randomString = ""
for _ in 1...length{
let random = arc4random_uniform(UInt32(master.count))
randomString.append(String(master[Int(random)]))
}
return randomString
}
Usage :
var randomArray1 = [String]()
for _ in 0...62{
randomArray1.append(self.randomString(1))
}
Here, If randomArray1.append(self.randomString(x)), then x = 1...N
Checking repeated elements :
var sameElementCatcher = [String]()
for x in 0...62{
let element = randomArray1[x]
randomArray1[x] = ""
if randomArray1.contains(element){
sameElementCatcher.append(element)
}
}
print("Same Elements")
print(sameElementCatcher.count != 0 ? sameElementCatcher : "Array count is zero")
Output:
Same Elements
["_", "u", "8", "7", "E", "P", "u", "y", "C", "-", "C", "x", "l", "j",
"t", "D", "U", "2", "e", "2"]
But I need to get array of 62 unique random characters from master by compared with randomArray1. i.e., Array count is zero
How can I achieve this without delay?
Note:
Also, I read this post also I have a answer for shuffling array. But this post different from shuffling only, Please, see usage.
Did you try like this?
What I understand from your question. generate a random text where all the characters are unique.
Before appending your random string to your array check is array have that char then append into your array.
func randomString(_ length: Int) -> String {
let master = Array("abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ_123456789".characters) //0...62 = 63
var randomString = ""
for _ in 1...length{
let random = arc4random_uniform(UInt32(master.count))
randomString.append(String(master[Int(random)]))
}
return randomString
}
var randomArray1 = [String]()
var tempRandomString = ""
let totalRandomCount = 62
var randomArrayCount = 0
while (totalRandomCount > randomArrayCount) {
tempRandomString = randomString(1)
if !randomArray1.contains(tempRandomString) {
randomArray1.append(tempRandomString)
randomArrayCount+=1
}
}
print(randomArray1)
Output: ["X", "u", "j", "1", "n", "E", "D", "q", "U", "6", "T", "O", "f", "J", "i", "c", "W", "V", "G", "R", "k", "7", "_", "8", "-", "l", "w", "4", "e", "Q", "C", "m", "M", "Y", "o", "S", "B", "2", "Z", "P", "p", "N", "y", "H", "a", "h", "z", "s", "b", "A", "3", "g", "x", "L", "v", "F", "d", "r", "t", "K", "9", "5"]
I tried this with playground. For this output 199 times loop executed.
If anyone knows better than this update yours.