So in a simple arcade/platformer game, I'm making it so I have a .csv text file set out like so:
660, 25, 0
720, 15, 1
etc..
The first number being the x coordinate, the next being the y coordinate and the last being whether the block kills you or not. Loading this data externally is not a problem and works fine but when it comes to actually running the .swf by itself obviously the .csv file is not embedded into it so I cannot access any values from it.
Therefore my question is: How can I embed a .csv file into my project and then read out 3 values per line into a multi dimensional array with each line denoting a different obstacle?
(The multi dimensional array being [obstacleID][0 for x coord/1 for y coord/2 for whether it kills or not])
How to embed a text file in Flash
then you can try:
var csv:embedded_csv = new embedded_csv();
var csvLines:Array = csv.toString().split("\n"); // \n or File.lineSeparator or \r\n
for(i=0; i<csvLines.length; i++)
{
line:Array = String(csvLines[i]).split(", ");
x = line[0];
y = line[1];
kills = line[2];
...
}
Related
I tried to get a script to create a text file that could write/add the images name, but the function
FileID = CreateFileForWriting(filename) does not work, it shows that was used by other process
I did not get this, is this function not right format or something is wrong, thx
Number Totaln
totaln=countdocumentwindowsoftype(5)
String filename, text
Number fileID
if (!SaveasDialog( "save text file as",getapplicationdirectory(2,0) + "Imagename.txt", filename))exit(0)
fileID = CreateFileForWriting(filename)
number i
for(i = 0; i <totaln; i++)
{
image imgSRC
imgSRC := GetFrontImage()
string imgname=getname(imgSRC)
WriteFile(fileID,"imgname")
Result("imgname")
}
Your code is nearly fine, but if you use the low-level API for file I/O you need to ensure that you close files you've opened or created.
Your script doesn't. Therefore, it runs fine exactly 1 time but will fail on re-run (when the file is still considered open.)
To fix it, you need to have closefile(fileID) at the end.
( BTW, if you script exits or throws after opening a file but before closing it, you have the same problem. )
However, I would strongly recommend not using the low-level API but the file streaming object instead. It also provides an automated file-closing mechanism so that you don't run into this issue.
Doing what you do in your script would be written as:
void writeCurrentImageNamesToText()
{
number nDoc = CountImageDocuments()
string filename
if (!SaveasDialog( "save text file as",getapplicationdirectory(2,0) + "Imagename.txt", filename)) return
number fileID = CreateFileForWriting(filename)
object fStream = NewStreamFromFileReference(fileID,1) // 1 for auto-close file when out of scope
for( number i = 0; i <nDoc; i++ ){
string name = GetImageDocument(i).ImageDocumentGetName()
fStream.StreamWriteAsText( 0, name + "\n" ) // 0 = use system encoding for text
}
}
writeCurrentImageNamesToText()
I'm trying to get a random line from a file:
extern crate rand;
use rand::Rng;
use std::{
fs::File,
io::{prelude::*, BufReader},
};
const FILENAME: &str = "/etc/hosts";
fn find_word() -> String {
let f = File::open(FILENAME).expect(&format!("(;_;) file not found: {}", FILENAME));
let f = BufReader::new(f);
let lines: Vec<_> = f.lines().collect();
let n = rand::thread_rng().gen_range(0, lines.len());
let line = lines
.get(n)
.expect(&format!("(;_;) Couldn't get {}th line", n))
.unwrap_or(String::from(""));
line
}
This code doesn't work:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:18:16
|
18 | let line = lines
| ________________^
19 | | .get(n)
20 | | .expect(&format!("(;_;) Couldn't get {}th line", n))
| |____________________________________________________________^ cannot move out of borrowed content
I tried adding .clone() before .expect(...) and before .unwrap_or(...) but it gave the same error.
Is there a better way to get a random line from a file that doesn't involve collecting the whole file in a Vec?
Use IteratorRandom::choose to randomly sample from an iterator using reservoir sampling. This will scan through the entire file once, creating Strings for each line, but it will not create a giant vector for every line:
use rand::seq::IteratorRandom; // 0.7.3
use std::{
fs::File,
io::{BufRead, BufReader},
};
const FILENAME: &str = "/etc/hosts";
fn find_word() -> String {
let f = File::open(FILENAME)
.unwrap_or_else(|e| panic!("(;_;) file not found: {}: {}", FILENAME, e));
let f = BufReader::new(f);
let lines = f.lines().map(|l| l.expect("Couldn't read line"));
lines
.choose(&mut rand::thread_rng())
.expect("File had no lines")
}
Your original problem is that:
slice::get returns an optional reference into the vector.
You can either clone this or take ownership of the value:
let line = lines[n].cloned()
let line = lines.swap_remove(n)
Both of these panic if n is out-of-bounds, which is reasonable here as you know that you are in bounds.
BufRead::lines returns io::Result<String>, so you have to handle that error case.
Additionally, don't use format! with expect:
expect(&format!("..."))
This will unconditionally allocate memory. When there's no failure, that allocation is wasted. Use unwrap_or_else as shown.
Is there a better way to get a random line from a file that doesn't involve collecting the whole file in a Vec?
You will always need to read the whole file, if only to know the number of lines. However, you don't need to store everything in memory, you can read lines one by one and discard them as you go so that you only keep one in the end. Here is how it goes:
Read and store the first line;
Read the second line, draw a random choice and either:
keep the first line with a probability of 50%,
or discard the first line and store the second line with a probability of 50%,
Keep reading lines from the file and for line number n, draw a random choice and:
keep the currently stored line with a probability of (n-1)/n,
or replace the currently stored line with the current line with a probability of 1/n.
Note that this is more or less what sample_iter does, except that sample_iter is more generic since it can work on any iterator and it can pick samples of any size (eg. it can choose k items randomly).
I am trying to match image files to a specific row in an array.
In a first step I am selecting a folder that contain the tif files.
Then I am selecting a csv file with the information I would like to use.
I am opening each image one after the other. For an opened image I would like to retrieve the values from the line that correspond to the image name in the csv file. The header of the CSV file is FileName, XValue, YValue.
Here's my code so far... Any help would be appreciated.
// Make a pop up to select the input directory
InputDirPath=getDirectory("Select Input directory");
// Get the list of files in the input input directory selected above as an array
InputFileList=getFileList(InputDirPath);
// Defines cell separator and line separator
CellSeparator=",";
LineSeparator="\n";
// open the csv file as a string
FileCCValuesPath=File.openDialog("Select the file containing the coordinates");
FileCCValuesString=File.openAsString(FileCCValuesPath);
// Split each row into an array
FileCCValuesRows=split(FileCCValuesString, LineSeparator);
// Create new arrays for the content of column and for each row
FileNameArray=newArray(FileCCValuesRows.length);
XValueArray=newArray(FileCCValuesRows.length);
YValueArray =newArray(FileCCValuesRows.length);
// Start of the loop going through the list of image files in the input folder selected above
for (Filei = 0; Filei < InputFileList.length; Filei++)
{
InputFileNamei=InputFileList[Filei];
InputFilePathi = InputDirPath+InputFileNamei;
if(endsWith(InputFilePathi, ".tif"))
{
open(InputFilePathi);
//////////This is where I am stuck
//////////Get the XValue and Value from the CSV file for the row in which
//////////FileName=InputFileNamei
run("Translate...", "x=XValue y=YValue interpolation=None");
}//end if
}//end for File i loop
// Notice of end of process
waitForUser("Process is done");
You can add another for loop (after opening the current image) that goes through all lines and checks if the line starts with the current image name and then split the current line to get the x and y values:
for (i=0; i < FileCCValuesRows.length; i++) {
if (startsWith(FileCCValuesRows[i], InputFileNamei)) {
values = split(FileCCValuesRows[i], CellSeparator);
xValue = parseInt(values[1]);
yValue = parseInt(values[2]);
run("Translate...", "x=" + xValue+ " y=" + yValue + " interpolation=None");
}
}
Note that the "ImageJ" way of doing it would be to open your CSV file in a Results table and use the getResultString and getResult macro functions to get the required values. Here's a version of your macro using these:
// Make a pop up to select the input directory
InputDirPath=getDirectory("Select Input directory");
// Get the list of files in the input input directory selected above as an array
InputFileList=getFileList(InputDirPath);
// open the csv file in a Results table
FileCCValuesPath=File.openDialog("Select the file containing the coordinates");
open(FileCCValuesPath);
// Start of the loop going through the list of image files in the input folder selected above
for (Filei = 0; Filei < InputFileList.length; Filei++)
{
InputFileNamei=InputFileList[Filei];
InputFilePathi = InputDirPath+InputFileNamei;
if(endsWith(InputFilePathi, ".tif"))
{
open(InputFilePathi);
for (i=0; i < nResults; i++) {
if (getResultString("FileName", i) == InputFileNamei) {
xValue = getResult("XValue", i);
yValue = getResult("YValue", i);
run("Translate...", "x=" + xValue+ " y=" + yValue + " interpolation=None");
}
}
}//end if
}//end for File i loop
// Notice of end of process
waitForUser("Process is done");
Thank you very much for your replies
This is what I end up doing:
1-Split the array by row using
FileValuesRows=split(FileValuesString, LineSeparator);
2- Create new array for each column (I removed one line because of the header)
Column1Array=newArray(FileValuesRows.length-1);
Column2Array=newArray(FileValuesRows.length-1);
3- Create a for loop that screen each row and break it into each individual column (Starting at 1 because of the header)
for (Rowi=1;Rowi<FileCCValuesRows.length; Rowi++){
FileCCValuesRowi=split(FileCCValuesRows[Rowi], CellSeparator);
//Array.show(FileCCValuesRowi);
4- Add the content content of each row into the previously created array (-1 because of the header)
Column1Array[Rowi-1]=FileCCValuesRowi[0];
Column2Array[Rowi-1]=FileCCValuesRowi[1];
}
//end if for Rowi
5- In the next step the aim is to find the row number corresponding to current open image. This is done in two steps:
5.1- Screen the csv file for the number of occurrence of the string (in this case the filename)
5.2 if occurrence is non null add them to an Indices Array
5.3 Use this indice to get the value corresponding to that row in the array created before
//Returns the indices at which a value occurs within an array
Occurence=0;
// Screen the FileName Array row by row and count the number of occurence
for (Rowi=0; Rowi<lengthOf(FileNameArray); Rowi++) {
if (FileNameArray[Rowi]==InputFileName) {
Occurence++;
//print(Occurence);
} //end of if
} // end of for Rowi
// If found
if (Occurence>0) {
// Create an array of length the number of occurence
IndicesArray=newArray(Occurence);
Occurence=0;
// Screen the FileName Array row by row and add the row of occurence into the Indices Array
for (Rowi=0; Rowi<lengthOf(FileNameArray); Rowi++) {
if (FileNameArray[Rowi]==InputFileName) {
IndicesArray[Occurence]=Rowi;
Occurence++;
}
}
//Array.show(IndicesArray);
}
Final step
//Get the X and Y translation value for the File being processed
In this case I have only 1 occurrence so I will take the first line of the Indice array which is the line 0
XValue=Column1Array[(IndicesArray[0])];
YValue=Column2Array[IndicesArray[0]];
//Translate the picture
run("Translate...", "x=XValue y=YValue interpolation=None");
I want to read data from a file and save it into an array. Then insert some new data into this array and then save this new data back into the same file deleting what is already there. My code works perfectly, giving me my required data, when I have 'r+' in the fopen parameters, however when I write to the file again it does not delete the data already in the file just appends it to the end as expected. However when I change the permissions to 'w+' instead of 'r+', my code runs but no data is read in or wrote to the file! Anyone know why this might be the case? My code is as seen below.
N = 1021;
b = [0;0;0;0;0];
% Opens file specified by user.
fid = fopen('testing','w+');
% Read header data
Header = fread(fid, 140);
% Move to start of data
fseek(fid,140,'bof');
% Read from end of config header to end of file and save it in an array
% called data
Data = fread(fid,inf);
Data=reshape(Data,N,[]);
b=repmat(b,[1 size(Data,2)]);
r=[b ; Data];
r=r(:);
r = [Header;r];
% write new values into file
fwrite(fid,r);
fclose(fid);
% Opens file specified by user.
fid = fopen('test');
All = fread(fid,inf);
fclose(fid);
According to the documentation, the w+ option allows you to "Open or create new file for reading and writing. Discard existing contents, if any." The contents of the file are discarded, so Data and Header are empty.
You need to set the position indicator of the filehandle before writing. With frewind(fid) you can set it to the beginning of the file, otherwise the file is written / appended at the current position.
N = 1021;
b = [0;0;0;0;0];
% Opens file specified by user.
fid = fopen('testing','r+');
% Read header data
Header = fread(fid, 140);
% Move to start of data
fseek(fid,140,'bof');
% Read from end of config header to end of file and save it in an array
% called data
Data = fread(fid,inf);
Data=reshape(Data,N,[]);
b=repmat(b,[1 size(Data,2)]);
r=[b ; Data];
r=r(:);
r = [Header;r];
% write new values into file
frewind(fid);
fwrite(fid,r);
fclose(fid);
% Opens file specified by user.
fid = fopen('test');
All = fread(fid,inf);
fclose(fid);
I am trying to write a program that will recognize an image on the screen, compare it against a resource library, and then calculate based on the result of the image source.
The first thing that I did was to create the capture screen function which looks like this:
private Bitmap Screenshot()
{
System.Drawing.Bitmap Table = new System.Drawing.Bitmap(88, 40, PixelFormat.Format32bppArgb);
System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(RouletteTable);
g.CopyFromScreen(1047, 44, 0, 0, Screen.PrimaryScreen.Bounds.Size);
return Table;
}
Then, I analyze this picture. The first method I used was to create two for loops and analyze both the bitmaps pixel by pixel. The problem with this method was time, it took a long time to complete 37 times. I looked around and found the convert to bytes and the convert to hash methods. This is the result:
public enum CompareResult
{
ciCompareOk,
ciPixelMismatch,
ciSizeMismatch
};
public CompareResult Compare(Bitmap bmp1, Bitmap bmp2)
{
CompareResult cr = CompareResult.ciCompareOk;
//Test to see if we have the same size of image
if (bmp1.Size != bmp2.Size)
{
cr = CompareResult.ciSizeMismatch;
}
else
{
//Convert each image to a byte array
System.Drawing.ImageConverter ic = new System.Drawing.ImageConverter();
byte[] btImage1 = new byte[1];
btImage1 = (byte[])ic.ConvertTo(bmp1, btImage1.GetType());
byte[] btImage2 = new byte[1];
btImage2 = (byte[])ic.ConvertTo(bmp2, btImage2.GetType());
//Compute a hash for each image
SHA256Managed shaM = new SHA256Managed();
byte[] hash1 = shaM.ComputeHash(btImage1);
byte[] hash2 = shaM.ComputeHash(btImage2);
for (int i = 0; i < hash1.Length && i < hash2.Length&& cr == CompareResult.ciCompareOk; i++)
{
if (hash1[i] != hash2[i])
cr = CompareResult.ciPixelMismatch;
}
}
return cr;
}
After I analyze the two bitmaps in this function, I call it in my main form with the following:
Bitmap Table = Screenshot();
CompareResult success0 = Compare(Properties.Resources.Result0, Table);
if (success0 == CompareResult.ciCompareOk)
{ double result = 0; Num.Text = result.ToString(); goto end; }
The problem I am getting is that once this has all been accomplished, I am always getting a cr value of ciPixelMismatch. I cannot get the images to match, even though the images are identical.
To give you a bit more background on the two bitmaps, they are approximately 88 by 40 pixels, and located at 1047, 44 on the screen. I wrote a part of the program to automatically take a picture of that area so I did not have to worry about the wrong location or size being captured:
Table.Save("table.bmp");
After I took the picture and saved it, I moved it from the bin folder in the project directly to the resource folder and ran the program again. Despite all of this, the result is still ciPixelMismatch. I believe the problem lies within the format that the pictures are being saved as. I believe that despite them being the same image, they are being analyzed in different formats, maybe one of the pictures contains a bit more information than the other which is causing the mismatch. Can somebody please help me solve this problem? I am just beginning with my c# programming, I am 5 days into the learning process, and I am really at a loss for this.
Yours sincerely,
Samuel