I'm trying to load a file of integers, add them to a 2D array, iterate through the array, and add tiles to my level based on the integer(Tile ID)at the current index. My problem seems to be that the array is loaded/iterated through in the wrong order. This is the file I'm loading from:
test.txt
02 02 02 02 02 02 02 02 02 02 02 02 02 02 02
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
This is the level constructor:
Level::Level(std::string levelpath, int _width, int _height)
{
std::ifstream levelfile(levelpath);
width = _width;
height = _height;
int ids[15][9];
while (levelfile.is_open()) {
std::copy_n(std::istream_iterator<int>(levelfile), width * height, &ids[0][0]);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
tiles.push_back(getTile(ids[x][y], sf::Vector2f(x * Tile::SIZE, y * Tile::SIZE)));
std::cout << ids[x][y] << " ";
}
std::cout << std::endl;
}
levelfile.close();
}
}
And this is how I create the level:
level = std::unique_ptr<Level>(new Level("data/maps/test.txt", 15, 9));
Here's the output in the console:
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 2 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 1 1 1 1 1 1 1 1 1 1 1 1 1
As you can see the contents are the same as in test.txt, but in the wrong order.
The reason is that you swapped the dimensions of the array. Instead of
int ids[15][9];
...which is 15 lines of 9 elements, you want
int ids[9][15];
...which is 9 lines of 15 elements. The order of the extents in the declaration is the same as the order of indices in access.
EDIT: ...which you also swapped. Instead of
ids[x][y]
you need
ids[y][x]
That does rather better explain the output you get, come to think of it. 2D-Arrays in C++ are stored row-major, meaning that the innermost arrays (the ones stored contiguously) are the ones with the rightmost index. Put another way, ids[y][x] is stored directly before ids[y][x + 1], whereas there is some space between ids[y][x] and ids[y + 1][x].
If you read in a row-major array like you do with std::copy_n and interpret it as a column-major array, you get the transpose (a bit warped because of the changed dimensions, but recognizably so. If you swapped height and width, you'd see the real transpose).
int ids[9][15];
while (levelfile.is_open()) {
std::copy_n(std::istream_iterator<int>(levelfile), width * height, &ids[0][0]);
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
tiles.push_back(getTile(ids[y][x], sf::Vector2f(x * Tile::SIZE, y * Tile::SIZE)));
std::cout << ids[y][x] << " ";
}
std::cout << std::endl;
}
If you look you can see that your print the first 15 values (the need to be in the first line) in the first raw (and what doesn't fit in the second). You can understand that it start filling the rows before the lines and your file contain first the line. So load your map "on the side". Set the height as the width (15) and the opposite (the width is 9 and not 15). Now you will load the map correctly.
Not just print each row and "endl" before the second row (each row print as line). And you will see this ok.
Hope it was clear enough.
Related
In my program, I am trying to find the lowest values in the row of a matrix, then find the lowest value in the next row corresponding to the column it was found.
I wrote a function that does most of that work, however, I am confused on the algorithm:
Declare and define a function that computes the index where the lowest (non-zero) values are found in a given row.
It takes three parameters; the 2D array declared in the main function that is the matrix, the 1D array that contains the list of all rows that were visited and an integer that represents a row in the 2D array.
For each of the columns in a row, compute the lowest non-zero value only if that row wasn’t visited before.
I am lost on how to move to the next row of the column with the lowest value
int const SIZE = 10;
int lowest_level(int array_2D[][SIZE], int path[], int row /* current row*/)
{
for (int i = 0; i < SIZE; ++i)
{
int minValue = array_2D[i][0]; // sets min value every row
for(int j = 0; j < SIZE; ++j)
{
if (path_checker(path, row) == false) // if row was not
visited
{
if ((array_2D[i][j] < minValue) && array_2D[i][j] != 0) // if
value is less than min & value is not 0
{
minValue = array_2D[i][j];
//cout << minValue << " "; // for testing; crashes
}
else
{
break;
}
}
}
}
//return (minValue);
}
I expect something like this
A B C D E F G H I J
-----------------------------------------------
A | 00 08 15 01 10 05 19 19 03 05
B | 06 00 02 08 02 12 16 03 08 17
C | 12 05 00 14 13 03 02 17 19 16
D | 08 07 12 00 10 13 08 20 16 15
E | 04 12 03 14 00 05 02 12 14 09
F | 08 05 03 18 18 00 04 02 10 19
G | 17 16 11 03 09 07 00 03 05 09
H | 07 06 11 10 11 11 07 00 14 09
I | 10 04 05 15 17 01 07 17 00 09
J | 05 20 07 04 18 19 19 03 10 00
Path
A --> D --> B --> C --> G --> H --> J --> I --> F --> E (path by rows it takes)
1 7 2 2 3 9 10 1 18 (lowest values in each row, next value corresponding to the column (1 = coordinates (A, D))
I want to print the values in my 2D array with margins from A - J. My problem is that the margin does not increment from A.
I have tried moving the ++k around in the loop but the margin only repeats "A".
const int SIZE = 10;
int array_2D[SIZE][SIZE]; // declaring here for context; array was created in
// a separted function
for (int i = 0; i < SIZE; ++i)
{
int k = 65;
cout << char(k) << " | ";
++k;
for (int j = 0; j < SIZE; ++j)
{
cout << setw(2) << setfill('0') << array_2D[i][j] << " ";
}
cout << endl;
}
I expect the output to be:
A | 00 08 15 01 10 05 19 19 03 05
B | 06 00 02 08 02 12 16 03 08 17
C | 12 05 00 14 13 03 02 17 19 16
D | 08 07 12 00 10 13 08 20 16 15
E | 04 12 03 14 00 05 02 12 14 09
F | 08 05 03 18 18 00 04 02 10 19
G | 17 16 11 03 09 07 00 03 05 09
H | 07 06 11 10 11 11 07 00 14 09
I | 10 04 05 15 17 01 07 17 00 09
J | 05 20 07 04 18 19 19 03 10 00
But I'm getting this:
A | 00 08 15 01 10 05 19 19 03 05
A | 06 00 02 08 02 12 16 03 08 17
A | 12 05 00 14 13 03 02 17 19 16
A | 08 07 12 00 10 13 08 20 16 15
A | 04 12 03 14 00 05 02 12 14 09
A | 08 05 03 18 18 00 04 02 10 19
A | 17 16 11 03 09 07 00 03 05 09
A | 07 06 11 10 11 11 07 00 14 09
A | 10 04 05 15 17 01 07 17 00 09
A | 05 20 07 04 18 19 19 03 10 00
You're resetting k to 65 on each iteration through your loop. You need to move the initialisation outside the loop i.e.
int k = 65;
for (int i = 0; i < SIZE; ++i)
{
cout << char(k) << " | ";
++k;
for (int j = 0; j < SIZE; ++j)
{
cout << setw(2) << setfill('0') << array_2D[i][j] << " ";
// array is size [10][10]
// array was created in a separate function
}
cout << endl;
}
Want to make a regex to remove 2019 and 0 from left side of the string and last six zeroes from right side of the string.
original value Dtype : class 'str'
original value: 2019 01 10 00 00 00
expected output is : 1 10
Using str.split with list slicing.
Ex:
s = "2019 01 10 00 00 00"
print(" ".join(s.split()[1:3]).lstrip("0"))
Using re.match
Ex:
import re
s = "2019 01 10 00 00 00"
m = re.match(r"\d{4}\b\s(?P<value>\d{2}\b\s\d{2}\b)", s)
if m:
print(m.group("value").lstrip("0"))
Output:
1 10
Background
I'm reverse engineering a TCP stream that uses a Type-Length-Value approach to encoding data.
Example:
TCP Payload: b'0000001f001270622e416374696f6e4e6f74696679425243080310840718880e20901c'
---------------------------------------------------------------------------------------
Type: 00 00 # New function call
Length: 00 1f # Length of Value (Length of Function + Function + Data)
Value: 00 12 # Length of Function
Value: 70 62 2e 41 63 74 69 6f 6e 4e 6f 74 69 66 79 42 52 43 # Function ->(hex2ascii)-> pb.ActionNotifyBRC
Value: 08 03 10 84 07 18 88 0e 20 90 1c # Data
However the Data is a data object that can include multiple variables with variable data lengths.
Data: 08 05 10 04 10 64 18 c8 01 20 ef 0f
----------------------------------------------
Opcode : Value
08 : 05 # var1 : 1 byte
10 : 04 # var2 : 1 byte
18 : c8 01 # var3 : 1-10 bytes
20 : ef 0f # var4 : 1-10 bytes
Currently I am parsing the Data using the following Python3 code:
############################### NOTES ###############################
# Opcodes sometimes rotate starting positions but the general order is always held:
# Data: 20 ef 0f 08 05 10 04 10 64 18 c8 01
#####################################################################
import re
import binascii
def dataVariable(data, start, end):
p = re.compile(start + b'(.*?)' + end)
return p.findall(data + data)
data = bytearray.fromhex('08051004106418c80120ef0f')
var3 = dataVariable(data, b'\x18', b'\x20')
print("Variable 3:", end=' ')
for item in set(var3):
print(binascii.hexlify(item), end=' ')
----------------------------------------------------------------------------
[Output]: Variable 3: b'c801'
So far all good...
Problem
If an Opcode appears in the previous variables Value the code is no longer reliable.
Data: 08 05 10 04 10 64 18 c8 20 01 20 ef 0f
----------------------------------------------
Opcode : Value
08 : 05
10 : 04
18 : c8 20 01 # The Value includes the next opcode (20)
20 : ef 0f
----------------------------------------------------------------------------
[Output]: Variable 3: b'c8'
[Output]: Variable 4: b'0120ef0f'
I was expecting an output of:
[Output]: Variable 3: b'c8' b'c82001'
[Output]: Variable 4: b'0120ef0f' b'ef0f'
It seems like there is an issue with my regular expression?
Update
To further clarify, var3 and var4 are representing integers.
I have managed to figure out how the length of the Value was being encoded. The most significant bit was being used as a flag to inform me that another byte was coming. You can then strip the MSB of each byte, swap the endianness and convert to decimal.
data -> binary representation -> strip MSB and swap endianness -> decimal representation
ac d7 05 -> 10101100 11010111 00000101 -> 0001 01101011 10101100 -> 93100
e4 a6 04 -> 11100100 10100110 00000100 -> 0001 00010011 01100100 -> 70500
90 e1 02 -> 10010000 11100001 00000010 -> 10110000 10010000 -> 45200
dc 24 -> 11011100 00100100 -> 00010010 01011100 -> 4700
f0 60 -> 11110000 01100000 -> 00110000 01110000 -> 12400
You may use
def dataVariable(data, start, end):
p = re.compile(b'(?=(' + start + b'.*' + end + b'))')
res = []
for x in p.findall(data):
cur = b''
for i, m in enumerate([x[i:i+1] for i in range(len(x))]):
if i == 0:
continue
if m == end and cur:
res.append(cur)
cur = cur + m
return res
See the Python demo:
data = bytearray.fromhex('08051004106418c8200120ef0f0f') # => b'c82001' b'c8'
#data = bytearray.fromhex('185618205720') # => b'56182057' b'2057' b'5618'
var3 = dataVariable(data, b'\x18', b'\x20')
print("Variable 3:", end=' ')
for item in set(var3):
print(binascii.hexlify(item), end=' ')
Output is Variable 3: b'c8' b'c82001' for '08051004106418c8200120ef0f0f' string and b'56182057' b'2057' b'5618' for 185618205720 input.
The pattern is of (?=(...)) type to find all overlapping matches. If you do not need the overlapping feature, remove these parts from the regex.
The point here is:
match all substrings starting with start and up to the last end with start + b'.*' + end pattern
iterate through the match dropping the first start byte and add an item to the resulting list when the end byte is found, adding up found bytes at each iteration (thus, getting all inner substrings inside the match).
I am trying to convert my columns to diagonals using SAS.
For example
D C1 C2 C3 C4 C5
J 11 00 14 15 20
F 00 13 16 00 30
M 00 00 18 19 00
A 00 00 00 98 50
S 00 00 00 00 41
Want this converted to
D N1 N2 N3 N4 N5
J 11 00 14 15 20
F 13 16 00 30
M 18 19 00
A 98 50
M 41
Can anyone tell or help me with this?
Update base on new info: This just uses an array to shift the values starting from the diagonal to the left. Not dependent of on values in the lower triangle.
data havethis;
infile cards firstobs=2;
input D:$1. C1-C5;
cards;
D C1 C2 C3 C4 C5
J 11 00 14 15 20
F 00 13 16 00 30
M 00 00 18 19 00
A 00 00 00 98 50
S 00 00 00 00 41
;;;;
run;
data want;
set havethis;
array c[*] c:;
array N[&sysnobs];
j = 0;
do i = _n_ to dim(c);
j + 1;
n[j] = c[i];
end;
drop j i;
run;
This method use two transposes (flip/flop), it assumes only zeros are on the off diagonal (better if they were missing) and missing is what you get as result. I like this method because you don't have to know anything, like how many.
data havethis;
input D:$1. C1 C2 C3;
format c: z2.;
cards;
J 11 12 14
M 00 13 15
A 00 00 16
;;;;
run;
proc transpose data=havethis out=wantthis(drop=_name_ where=(col1 ne 0));
by D notsorted;
run;
proc transpose data=wantthis out=whatthismore(drop=_name_) prefix=N;
by d notsorted;
run;