Posts for Bobo_the_King

1 2
29 30 31
34 35
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Holy crap, an encode! Thanks, antd! Beginning was cut off, though. Take it down and upload it again...
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Twelvepack wrote:
Derakon wrote:
A cure isn't outside the realm of possibility.
The point he was trying to make (I think) is that cancer is a large class of diseases, and can not be cured categorically. A "cure for cancer" would be like saying a "cure for viruses". Any cure might work on some cancers, but probably wouldn't work on others. Just as there are no antibiotics that can cure all bacterial infections, there will be no universal cure for cancer.
Absolutely. Couldn't have put it better myself. By the way, for those who are interested, cancer is unregulated cell growth-- nothing more, nothing less. There is no single cancer gene in your DNA, nor is there a specific kind of cancer cell. Any mutation that alters a vital gene for inhibiting cell growth can cause cancer in any tissue. In particularly deadly strains of cancer, cancer cells are virtually indistinguishable from ordinary cells, except for their growth patterns. That is why there cannot be a single cure for cancer. I'd also like to point out what should be obvious: the FDA is run by people. Not cyborgs, not demons, not warlocks, not Klingons, but real human beings. These real human beings get cancer. Not only that, they have husbands and wives, they have children, they have neighbors, they have close friends, they have colleagues-- and the implication seems to be that if any of these people gets cancer, these FDA administrators will just sit on the supposed cure that they have rather than save their friends and loved ones. Oh, the conspiracy theorists might pipe in to say that they can administer the cure to their closest family or maybe even their friends, but then why has no one stepped forward to say that this is exactly what happened? If I took a miracle pill to cure cancer, I sure as hell would want everyone to know about it. Sheesh.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I'll do my best to not get sucked into this argument, but do any of you cancer cure conspiracy cooks know what cancer is? If you knew what it is, I think you'd understand that not only is there no cure, but there never will be a cure. I'll be waiting.
Post subject: Quicksave and quickload (FCEUX, possibly other emulators)
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Edit: adelikat informs me that the slowdown was due to the backup feature in FCEUX. This can be disabled through config -> enable -> backup savestates. That should render the script below unnecessary, but perhaps someone will still find a use for it. Oh well. Edit 2: After some quick testing, it seems that backup savestates are not related to the slowdown. * * * I'm working on a bot for a game that, as yet, shall go unmentioned. The game is rather long (about 400,000 frames or two hours) and this has caused problems. Whenever I use savestate.load (which is often, because it's a bot) it creates a new copy of the movie file. I believe this is because Lua cannot know if I have a savestate on the branch I'm leaving, so it preserves the old movie file in case savestate.load needs it at a later time. As the movie grew in size, I was losing about a second every time I opened an old state. This was unacceptable, as my bot took some eight hours to produce 250,000 frames. My goal was to create "quicksave" and "quickload" functions that instead of saving a branch, just goes back and rewrites over the movie file. I seem to have accomplished just that, although not as smoothly as possible. Here is my Lua script, called savetools.lua:
Language: lua

dofile("savetable.lua") function table.copy(t) local t2 = {} for k,v in pairs(t) do t2[k] = v end return t2 end savetools={} function savetools.quickcreate() state={} state[1]=savestate.create() state[2]=0 return state end function savetools.quicksave(state) savestate.save(state[1]) state[2]=frameindex return state end function savetools.quickload(state) savestate.load(state[1]) frameindex=state[2] end function savetools.create() state={} state[1]=savestate.create() state[2]=0 state[3]={} return state end function savetools.save(state) savestate.save(state[1]) state[2]=frameindex state[3]=table.copy(movievector) return state end function savetools.load(state) savestate.load(state[1]) frameindex=state[2] movievector=table.copy(state[3]) end function savetools.frameadvance(buttons) if not(buttons) then buttons={} end joypad.set(1,buttons) movievector[frameindex]=buttons emu.frameadvance() frameindex=frameindex+1 end --[[ --movie.record doesn't work function savetools.record(filename,startpoint,players,options) movie.record(filename,startpoint,players,options) for i=0,#movievector do joypad.set(1,movievector[i]) emu.frameadvance() end end ]]-- function savetools.savemovie(filename) assert( table.save( movievector, filename ) == 1 ) end function savetools.openmovie(filename) movievector = table.load( filename ) return movievector end function savetools.playmovie(filename) movievector = savetools.openmovie(filename) for i=0,#movievector do joypad.set(1,movievector[i]) emu.frameadvance() end end frameindex=0 movievector={}
There are nine notable functions in this script: •savetools.create, savetools.save, and savetools.load all work almost exactly the same way that the savestate.create, savestate.save, and savestate.load do. The only difference is that savetools.save returns the state, which has been updated, so the syntax is something like state1=savetools.save(state1) instead of the old savestate.save(state1). Someone with a little more experience with Lua can probably rewrite it to match the old syntax. I've tried to make it so that you can just do a search for "savestate" and replace all instances with "savetools" and it will (almost) still work. •savetools.quickcreate, savetools.quicksave, and savetools.quickload all work like their non-quick counterparts, except that they just backtrack and rewrite over the old movie file rather than saving it. This saves a lot of time with intensive botting because the movie file doesn't need to be copied. The state you quickload should be strictly in the past, however. I don't know exactly what would happen if you quickload a state on an alternate branch, but I'm certain that you'd end up producing garbage. •savetools.frameadvance works as a combination of joypad.set and emu.frameadvance. With no input arguments, it just advances a frame without pressing any buttons. It also takes an argument of the same format as the tables accepted by joypad.set. For example, savetools.frameadvance({A=1}) is equivalent to joypad.set({A=1}) emu.frameadvance(). •savetools.savemovie saves the movie to file. Note that the movie format is different from .fm2. I'll explain that in a second, but for now I'd just like to reassure you that you can fairly easily convert a movie of this format to .fm2 format. •savetools.playmovie plays the movie from the current point. •(savetools.openmovie is used by savetools.playmovie, but it otherwise isn't too useful. You can use it to read the movie file as a table directly, should you want to. Perhaps that can be useful as a crude form of hex editing...) There are just two important variables in the script: frameindex and movievector. The frameindex variable should always match the frame that the emulator is currently on while movievector is just a vector of button presses from the start of recording. Also of note is the dofile("savetable.lua") line at the top of the script. That's a script I downloaded from here and allows you to save and load Lua tables to file. In this case, it saves the movie file. I'll include a copy of that script shortly. To implement this file, include the line dofile("savetools.lua") (or whatever you call it) at the top of your bot. To create a .fm2 movie file, pause the game, power on, and run the bot, being sure to include the line savetools.savemovie("mymovie.tbl") (or whatever your movie's name) at the end of your script. Then write a second script that only executes savetools.playmovie("mymovie.tbl"). Pause the game, record a new movie, and then run the new script. The .tbl movie should execute flawlessly, producing a .fm2 movie. If movie.record worked, you would be able to do this all internally without writing a second script. The script could perhaps use a little bit of improvement. For one, I should probably make it so that it deletes (rather than just overwrites) the button presses in the old movie file. Second, I could probably make it so that for the save and load functions, it only records button presses after the save. This script should be extremely easy to port to other emulators. I would also like it to act directly on the native movie file. If any emulator developers would like to implement these features directly, I'd be quite honored. Here is the savetable.lua script:
Language: lua

--[[ Save Table to File/Stringtable Load Table from File/Stringtable v 0.94 Lua 5.1 compatible Userdata and indices of these are not saved Functions are saved via string.dump, so make sure it has no upvalues References are saved ---------------------------------------------------- table.save( table [, filename] ) Saves a table so it can be called via the table.load function again table must a object of type 'table' filename is optional, and may be a string representing a filename or true/1 table.save( table ) on success: returns a string representing the table (stringtable) (uses a string as buffer, ideal for smaller tables) table.save( table, true or 1 ) on success: returns a string representing the table (stringtable) (uses io.tmpfile() as buffer, ideal for bigger tables) table.save( table, "filename" ) on success: returns 1 (saves the table to file "filename") on failure: returns as second argument an error msg ---------------------------------------------------- table.load( filename or stringtable ) Loads a table that has been saved via the table.save function on success: returns a previously saved table on failure: returns as second argument an error msg ---------------------------------------------------- chillcode, http://lua-users.org/wiki/SaveTableToFile Licensed under the same terms as Lua itself. ]]-- do -- declare local variables --// exportstring( string ) --// returns a "Lua" portable version of the string local function exportstring( s ) s = string.format( "%q",s ) -- to replace s = string.gsub( s,"\\\n","\\n" ) s = string.gsub( s,"\r","\\r" ) s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" ) return s end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err -- create a pseudo file that writes to a string and return the string if not filename then file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" } charS,charE = "","" -- write table to tmpfile elseif filename == true or filename == 1 then charS,charE,file = "","",io.tmpfile() -- write table to file -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error else file,err = io.open( filename, "w" ) if err then return _,err end end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do if filename and filename ~= true and filename ~= 1 then file:write( "-- Table: {"..idx.."}"..charE ) end file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true -- escape functions and userdata if type( v ) ~= "userdata" then -- only handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( charS.."loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( charS..value..","..charE ) end end end for i,v in pairs( t ) do -- escape functions and userdata if (not thandled[i]) and type( v ) ~= "userdata" then -- handle index if type( i ) == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end file:write( charS.."[{"..lookup[i].."}]=" ) else local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i ) file:write( charS..index.."=" ) end -- handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( "{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( value..","..charE ) end end end file:write( "},"..charE ) end file:write( "}" ) -- Return Values -- return stringtable from string if not filename then -- set marker for stringtable return file.str.."--|" -- return stringttable from file elseif filename == true or filename == 1 then file:seek ( "set" ) -- no need to close file, it gets closed and removed automatically -- set marker for stringtable return file:read( "*a" ).."--|" -- close file and return 1 else file:close() return 1 end end --// The Load Function function table.load( sfile ) -- catch marker for stringtable if string.sub( sfile,-3,-1 ) == "--|" then tables,err = loadstring( sfile ) else tables,err = loadfile( sfile ) end if err then return _,err end tables = tables() for idx = 1,#tables do local tolinkv,tolinki = {},{} for i,v in pairs( tables[idx] ) do if type( v ) == "table" and tables[v[1]] then table.insert( tolinkv,{ i,tables[v[1]] } ) end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link values, first due to possible changes of indices for _,v in ipairs( tolinkv ) do tables[idx][v[1]] = v[2] end -- link indices for _,v in ipairs( tolinki ) do tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil end end return tables[1] end -- close do end
And finally, here's a function at the heart of my bots. All it does is execute "action" at different times until it finds the earliest it can do so to obtain the desired results. I'll explain it in more detail later if anyone is interested.
Language: lua

local function guessandcheck(action,condition,framedelay,lowguess,highguess,executeaction) worstpossible=highguess local state2=savetools.quickcreate() local oldstate={} for i=1,#condition.adr do oldstate[i]=memory.readbyte(condition.adr[i]) end local foundit=false state2=savetools.quicksave(state2) while not(foundit) do savetools.quickload(state2) guess=math.floor((highguess+lowguess)/2) for i=1,guess do savetools.frameadvance() end for i=1,#action do savetools.frameadvance(action[i]) end for i=1,framedelay do savetools.frameadvance() end if condition.fn(unpack(oldstate),unpack(condition)) then highguess=guess else lowguess=guess+1 end foundit = (highguess==lowguess) end savetools.quickload(state2) for i=1,lowguess do savetools.frameadvance() end if executeaction then for i=1,#action do savetools.frameadvance(action[i]) end end if highguess==worstpossible then print("BAD!") end --while not(condition["fn"](oldstate,unpack(condition))) do -- emu.frameadvance() --end end
Hope this helps others as much as it's helping me!
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
arflech wrote:
I'm guessing here that you meant sum(f(qi,qi-qi-1),i)...
Actually, no, I truly meant that f is (or may be) a function of i. Fortunately for you, this doesn't have any meaningful effect on the problem. Unfortunately for you, it therefore doesn't make the problem any easier. I misspoke, however, when I said that f is minimized. I should have said it's extremized. In the example of part 3, the sum happens to be maximized. I just am used to minimizing things because I'm a physicist.
arflech wrote:
1) The partial derivative with respect to qi of this sum is f1(qi,qi-qi-1)+f2(qi,qi-qi-1)-f2(qi+1,qi+1-qi) where 0<i<N, while the derivative with respect to qN is f1(qN,qN-qN-1)+f2(qN,qN-qN-1) and the derivative with respect to q0 is -f2(q1,q1-q0); here fn is the partial derivative with respect to the nth variable. Setting all of those partial derivatives equal to 0 and then adding the equations yields sum(f1(qi,qi-qi-1),i)=0; however I don't know how to derive a difference equation here... Maybe it would be better to take the Div of the aforementioned Grad, to get the Laplacian... Second partial in qi for 0<i<N is f1,1(qi,qi-qi-1)+f1,2(qi,qi-qi-1)+f2,1(qi,qi-qi-1)+f2,2(qi,qi-qi-1)+f2,2(qi+1,qi+1-qi), second partial in qN is f1,1(qN,qN-qN-1)+f1,2(qN,qN-qN-1)+f2,1(qN,qN-qN-1)+f2,2(qN,qN-qN-1), and second partial in q0 is f2,2(q1,q1-q0), so the Laplacian, assuming that all of the respective functions are sufficiently well-behaved, is sum(f1,1(qi,qi-qi-1)+2f1,2(qi,qi-qi-1)+2f2,2(qi,qi-qi-1),i) but I'm still not sure how to get any relations among the qi themselves...
You seem to be on the right track but it's a little hard to follow your work. I suggest taking the derivative with respect to qk so you don't get your is and ks mixed up. Big hint 1: Some Kronecker delta functions will pop out. Even bigger hint 2: Re-index one of the terms to obtain the final answer. Done carefully, the problem can be completed in about five lines of work, but it helps a lot to know what to look for. It's a tricky little bastard and a lesson in taking partial derivatives.
arflech wrote:
2) I'll try to take a variational derivative here... For a test function F, a perturbation is given by sum(f((qi,qi-qi-1)+E*F((qi,qi-qi-1),i) for some E greater than 0; its derivative with respect to E is sum(F((qi,qi-qi-1),i) and this is also the derivative when E=0, so I think the variational derivative with respect to f is N...I'm not sure how this helps with the problem.
Good guess, but make the perturbation in q, not f. This strategy will lead you to the answer the long way. I have a nine line proof, plus a small lemma. Hint related to hint 2 above: You'll need to re-index a sum at some point.
arflech wrote:
3) To make it easier, f(x,y)=2x-y2, so f1(x,y)=2 and f2(x,y)=-2y; then for 0<i<11, the partial of that sum with respect to qi is 2-2(qi-qi-1)+2(qi+1-qi), which is simplified to 2qi+1-4qi+2qi-1+2, the partial with respect to q0 is 2q1-2q0, and the partial with respect to q11 is 2-2q11+2q10. Setting all of these partials equal to 0 and adding equations yields 22=0, which is impossible; the Laplacian is 44, although I'm not sure of its significance.
This is correct up until you sum the equations together. The middle 10 terms do indeed sum to 20, but remember that q0 and q11 are fixed by the boundary conditions (both are zero) so you can't take partial derivatives with respect to them. I'm not 100% sure that's where the error lies, but that's my current guess. Edit: It seems that the real problem is that the terms don't cancel completely. If you sum over a long string of equations, all but four terms, not two, will cancel. Now go back and attempt parts 1 and 2 again. On another note, how do you guys make those snazzy-looking math formulas (like p4wn3r, a few posts back)? It would help to know how to do it if I'm going to write up a solution to my problem. If not, I'll just punch it up in LaTeX and copy a screenshot of the PDF. Edit: Fixed quotes. Edit 2: Effing hell. It doesn't want to format properly. Seems to be related to the inequalities in your quotes. Therefore, I've spelled out your "greater than" inequality in the second quote.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
The last problem reminded me of one that I dreamed up a while ago. 1) Find a difference equation for q such that the sum sum( f(qi, qi-qi-1, i) ) is minimized for an arbitrary function f. In the sum, i ranges from 1 to N and you may assume that q0 and qN are both given so that the problem is well-posed. (Hint: Take your partial derivatives carefully!) 2) Introduce a symbol (if you haven't already done so) that will make your solution to (1) instantly familiar to any physicist or mathematician with a background in calculus of variations. 3) Apply your solution to the function f=2qi - (qi-qi-1)^2 subject to the boundary conditions q0=0, qN=0, and N=11. What physical problem is this analogous to?
Post subject: Re: Barbie teaches cooking topless = great idea
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Kitsune wrote:
sonicpacker wrote:
Kitsune wrote:
bad games, aside from Super Paper Mario
What?
Super Paper Mario is a bad game. Yes, I said it. And I will always say it. It SUCKS SUCKS SUCKS SUCKS SUCKS! I can't stomach playing that game again. Only reason I keep it is so I can say I own the entire series.
Kitsune, you too frequently go out of your way to bash Super Paper Mario. I say this for your benefit: cool it. You sound like a troll. Now, with that out of the way, I 100% agree with you. It was by far the worst Mario game I've ever played and threw away everything that I loved about the first two games (particularly TTYD). The amount of backtracking was inexcusable. I've never seen a game that padded itself out so much with backtracking through bland environments. And whenever anyone criticizes the game, the response is invariably, "But the dialogue is so good!" Huh? I thought it was okay at some points, but nothing stuck out to me. If all I wanted were good dialogue, I'd have read a book. I wish I had. But this isn't the right forum for this discussion. I just hope it pleases you to know you're not alone in hating SPM. Let's hope the Wii U brings the Paper Mario series back to its glory days.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Derakon wrote:
As for the Wii library, it seems to me that the leader in any given console generation will get loads of shovelware. We've just forgotten all the unmemorably crap games that were produced for the PSX/PS2 and only remember the good ones. After all, just because a bad game is produced for a console doesn't mean you have to play it.
Bolded for truth! I demand everyone give Derakon's comment a second read-through. I think it's funny that people are saying the Wii leads in shovelware while turning a blind eye to the PS2, which to me reigns as the all-time shovelware champion. That doesn't mean it was a bad console by any means, but man, there was a lot of utter crap produced for it.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Kitsune wrote:
I'm optimistic that the price of the Wii U will be manageable. Maybe $250-$400. Whatever the price is, we still have a while to save up. Whatever the time it comes out, it'll still be cheaper than the 720 and PS4. I mean, when the 360 and PS4 first came out, they were both around $500-$600. I can imagine that 720 and PS4 on launch are likely to be somewhere around $600-$900.
Kitsune wrote:
And as far as affordability, I know no price has been mentioned yet, but I don't think it'll be more than $500 at the most on launch, if even that. Nintendo likes to keep their consoles and games affordable. Unlike Sony and Microsoft who seem to think people will buy their consoles no matter what they charge for them. Mark my words, the 720 and PS4 are going to be far more expensive at launch.
I'm skeptical on all fronts. I believe the lesson of the last two console generations was that the cheapest console sells the best. People want to have fun, and they want it cheap. Granted, corporate big-wigs are notorious for misreading the market, but I think that lesson has come across loud and clear by now. If all three companies know what they're doing, they'll keep the price in the $300 to $400 range or possibly less. If you're right about prices, Kitsune, I foresee Nintendo walloping the competition but the overall video game market contracting. As an aside, I believe we are currently living in a new golden age of video games, but most people are too blind to see it. There truly are games out there for just about everyone, from cheap casual games to graphically violent FPSs to some of the best platformers we've ever seen to fighters to puzzles to RPGs to TBSs to sports games-- you name a genre and with very rare exception, it's almost certainly present and accounted for and awesome to boot (I only mourn the death of the space sim and point-and-click adventure genres). It sure as hell beats the cookie-cutter FPSs that were dominating the market we had to endure for about ten years. In that light, it makes me kind of sad to see people complaining about shovelware or bickering over which console is best. I firmly believe we're going to look back on these past few years as "the good ol' days", just as we're nostalgic for the SNES era. Yeah, there are plenty of crappy games, but everyone knows that consoles and console eras are defined by their best games, not their worst. Live it up while you can.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I don't understand the argument here. All submitted runs-- published and unpublished alike-- are accessible via the search function. Here's Myst, Desert Bus, and Front Line. I could also link to obsolete runs and April Fools runs-- they're all here. Instead, the focus seems to be on the (largely arbitrary) distinction between published and unpublished runs. True, published runs get a small, brief boost in visibility, before being relegated to the archives, but are otherwise almost indistinct from unpublished runs. In fact, perhaps a moderator or someone who's knowledgeable could explicitly list all the differences between published and unpublished runs. I doubt there are all that many. The most valid complaint, in my eyes, is that the decision whether to publish a run is binary. A run is either published or it isn't. While it would be nice to have different "levels" of publication, this would seriously complicate the process and I think it would cause more disputes, not fewer. The system isn't perfect, but it's the world we live in and I think it's implemented very well here. I think the judges are very fair, there's lots of communication among members, and community response isn't the sole factor for publication. I wouldn't have it any other way. A Q Lian Huan Pao won't be published, but it will still be here.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Edit 3: Mapping complete! I have 190 maps in a .txt file that's 762 KB as well as a .tbl file that's 6.4 MB. Now I need to figure out what to do with them. --------------------- I made a mapper! Huge thanks to Acmlm and Ilari for pointing me in the right direction and even going so far as to find the map data in the RAM. This is a very simple version of the mapper-- its output is graphical (even though it's a .txt file), whereas the finished version will save the map as a table. I also plan on having it automatically detect room switches. With the game maps, I should be able to predict when we will fight our next battle. That should complete the walking script (with a little bit of work). Edit: New version of the mapper. You'll notice a "while not(beenthere[47])" statement. Room 47 corresponds to the Creator's plateau at the top of the tower. I ran my script with a different room number (corresponding to castle shield) and it worked fine. I tried running the updated version and got as far as the MACHINE in the power plant before being hit by a beam and killed. I've had problems like this before-- despite my "infinite health" cheat, it still decides to kill me. Because I didn't reach the Creator, no data was saved. Bummer. Next time, I'll use save states. (Also, in case anyone else wishes to use this script, some NPCs insist on getting in your way. You can shift them north by using VBA's built-in cheat functions and changing the corresponding addresses. Some other cheats are also necessary.) Note the "dofile("savetable.lua")" line at the top. That's a script I pilfered from this site. Seems to do the trick, but it's too early to say for sure (I haven't used its "load" function yet). Edit 2: I disabled the cheats and ran the script again with FatRatKnight's old run. The good news is that it worked fine, as you can see from this pastebin link with most of the maps. (I had to remove about 30 of the 140-or-so maps to get it under the 500 KB file size limit.) See how many of them you can identify! http://pastebin.com/SmLm8NP0 The bad news is that I still need to run it again, completing the game. The most glaring omission off the top of my head is the Northeast Town in World 2, which FatRatKnight didn't visit (it was before we re-evaluated the route). If anyone wants to run this script, tear through the game (while visiting as many rooms as possible), and send the resulting files to me, I'd be much obliged. If not, my project for tomorrow is pretty clear.
Language: lua

dofile("savetable.lua") local map={{{}}} local mapfile = io.open("map.txt","w+") local beenthere={} for i=0,255 do beenthere[i]=false end for room=0,255 do map[room]={{}} for i=0,61 do map[room][i]={} end end while not(beenthere[47]) do --Change all RNGs for i=0,0x7F do memory.writebyte(0xC300+i, 0xBE) end --Super characte*r memory.writeword(0xCC06, 60000) memory.writeword(0xCC08, 60000) memory.writebyte(0xCC0B, 240) memory.writebyte(0xCC0C, 240) memory.writebyte(0xCC0D, 240) memory.writebyte(0xCC0E, 240) local currroom=memory.readbyte(0xCCC7) if not(beenthere[currroom]) then for frames=1,30 do emu.frameadvance() end map[currroom]={{}} for i=0,61 do map[currroom][i]={} for j=0,63 do map[currroom][i][j]=memory.readbyte(0xD000+64*i+j) end end beenthere[currroom]=true end emu.frameadvance() end for room=0,255 do --draw maps to text file local charcounter=65 local isused={} if #map[room][1]>0 then for i=0,61 do for j=0,63 do tile=map[room][i][j] if isused[tile] then tilechar=isused[tile] else isused[tile]=string.char(charcounter) tilechar=isused[tile] charcounter=charcounter+1 end mapfile:write(tilechar) end mapfile:write("\n") end mapfile:write("\n\n\n\n\n") end end --flush files mapfile:flush() assert( table.save( map, "map.tbl" ) == 1 )
savetable.lua:
Language: lua

--[[ Save Table to File/Stringtable Load Table from File/Stringtable v 0.94 Lua 5.1 compatible Userdata and indices of these are not saved Functions are saved via string.dump, so make sure it has no upvalues References are saved ---------------------------------------------------- table.save( table [, filename] ) Saves a table so it can be called via the table.load function again table must a object of type 'table' filename is optional, and may be a string representing a filename or true/1 table.save( table ) on success: returns a string representing the table (stringtable) (uses a string as buffer, ideal for smaller tables) table.save( table, true or 1 ) on success: returns a string representing the table (stringtable) (uses io.tmpfile() as buffer, ideal for bigger tables) table.save( table, "filename" ) on success: returns 1 (saves the table to file "filename") on failure: returns as second argument an error msg ---------------------------------------------------- table.load( filename or stringtable ) Loads a table that has been saved via the table.save function on success: returns a previously saved table on failure: returns as second argument an error msg ---------------------------------------------------- chillcode, http://lua-users.org/wiki/SaveTableToFile Licensed under the same terms as Lua itself. ]]-- do -- declare local variables --// exportstring( string ) --// returns a "Lua" portable version of the string local function exportstring( s ) s = string.format( "%q",s ) -- to replace s = string.gsub( s,"\\\n","\\n" ) s = string.gsub( s,"\r","\\r" ) s = string.gsub( s,string.char(26),"\"..string.char(26)..\"" ) return s end --// The Save Function function table.save( tbl,filename ) local charS,charE = " ","\n" local file,err -- create a pseudo file that writes to a string and return the string if not filename then file = { write = function( self,newstr ) self.str = self.str..newstr end, str = "" } charS,charE = "","" -- write table to tmpfile elseif filename == true or filename == 1 then charS,charE,file = "","",io.tmpfile() -- write table to file -- use io.open here rather than io.output, since in windows when clicking on a file opened with io.output will create an error else file,err = io.open( filename, "w" ) if err then return _,err end end -- initiate variables for save procedure local tables,lookup = { tbl },{ [tbl] = 1 } file:write( "return {"..charE ) for idx,t in ipairs( tables ) do if filename and filename ~= true and filename ~= 1 then file:write( "-- Table: {"..idx.."}"..charE ) end file:write( "{"..charE ) local thandled = {} for i,v in ipairs( t ) do thandled[i] = true -- escape functions and userdata if type( v ) ~= "userdata" then -- only handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables, v ) lookup[v] = #tables end file:write( charS.."{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( charS.."loadstring("..exportstring (string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( charS..value..","..charE ) end end end for i,v in pairs( t ) do -- escape functions and userdata if (not thandled[i]) and type( v ) ~= "userdata" then -- handle index if type( i ) == "table" then if not lookup[i] then table.insert( tables,i ) lookup[i] = #tables end file:write( charS.."[{"..lookup[i].."}]=" ) else local index = ( type( i ) == "string" and "["..exportstring( i ).."]" ) or string.format( "[%d]",i ) file:write( charS..index.."=" ) end -- handle value if type( v ) == "table" then if not lookup[v] then table.insert( tables,v ) lookup[v] = #tables end file:write( "{"..lookup[v].."},"..charE ) elseif type( v ) == "function" then file:write( "loadstring("..exportstring(string.dump( v )).."),"..charE ) else local value = ( type( v ) == "string" and exportstring( v ) ) or tostring( v ) file:write( value..","..charE ) end end end file:write( "},"..charE ) end file:write( "}" ) -- Return Values -- return stringtable from string if not filename then -- set marker for stringtable return file.str.."--|" -- return stringttable from file elseif filename == true or filename == 1 then file:seek ( "set" ) -- no need to close file, it gets closed and removed automatically -- set marker for stringtable return file:read( "*a" ).."--|" -- close file and return 1 else file:close() return 1 end end --// The Load Function function table.load( sfile ) -- catch marker for stringtable if string.sub( sfile,-3,-1 ) == "--|" then tables,err = loadstring( sfile ) else tables,err = loadfile( sfile ) end if err then return _,err end tables = tables() for idx = 1,#tables do local tolinkv,tolinki = {},{} for i,v in pairs( tables[idx] ) do if type( v ) == "table" and tables[v[1]] then table.insert( tolinkv,{ i,tables[v[1]] } ) end if type( i ) == "table" and tables[i[1]] then table.insert( tolinki,{ i,tables[i[1]] } ) end end -- link values, first due to possible changes of indices for _,v in ipairs( tolinkv ) do tables[idx][v[1]] = v[2] end -- link indices for _,v in ipairs( tolinki ) do tables[idx][v[2]],tables[idx][v[1]] = tables[idx][v[1]],nil end end return tables[1] end -- close do end
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Flygon wrote:
Warp wrote:
5) The music rulez.
I am in full agreement with this.
Agreed! They're mostly Joplin rags. Select a game: Magnetic Rag (one of my favorites!) Select a character: Peachrine Rag Hallway: Maple Leaf Rag (I can even play it!) Quiz: Elite Syncopations I also downloaded the ROM and found these other rags: Game 1 overworld: Palm Leaf Rag Game 1 quiz: The Easy Winners Game 4 title: Solace (played unreasonably fast) Game 4: The Chrysanthemum
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
FatRatKnight: There we are. I found my favorite RNG to start 2-1 with. Now to actually get it. bobotheking: AH? Grunt: FatRatKnight: what are you working on? FatRatKnight: Alien Hominid. Grunt: Ah. Grunt: Cool. bobotheking: AH! ***Grunt kicks bobotheking >_>
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Tub wrote:
just a small aside, because I need to get to work: the game in question is an online-game, so I can neither add lua scripts, nor disassemble, nor observe the RNG. Conversely, I'm not interested in manipulating these drops (I wish I could!), but simply in having knowledge of the game; not for a guide but for a wiki. Tested drop rates are all I got.
Take option 5, then do your best to incorporate option 4 if you think you see a pattern emerging. If the game is even mildly popular, I'm sure there's a forum out there that would be willing to enlist their help.
Tub wrote:
[..]central limit theorem[/..]
Wouldn't that again require large amounts of samples?
Yep. My understanding of the central limit theorem is that it tends to apply to almost any distribution after 30 or more successes or failures (whichever is more rare). There may be pathological counterexamples, but those tend to be rare and uninteresting/unrealistic. I assure you, however, that if your sample size is small, you're SOL. That's why you'll need to enlist the help of some "friends".
Tub wrote:
Reading your post, it occurred to me that I could just formulate an infinite number of H0's and define my confidence range as "all possible drop rates I cannot exclude with p<5%". That does indeed get rid of the prior probabilities, I'll have to see how the math turns out and which values I get. Though the result wouldn't be a confidence interval any more, so it's a completely different statement I'm going to make.
Yeah... Although that isn't the most scientifically sound method, I believe it's technically valid as long as you don't say anything like, "There is a 90 percent chance that p is between 48 and 52." If nothing else, it's good that you specified the p-value you're looking for in advance. Once you start "moving the goalposts", your analysis loses much of its heft. Sounds like a fun project! Good luck!
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Been working on new scripts. Most useful one so far is a script that will increment a "bin" vector to eventually run through all the possibilities. Special thanks to Nitrodon for helping me make sense of the algorithm. Here it is in a quickly testable format:
Language: lua

local function sum(vector,low,high) if not(low) then low=1 end if not(high) then high=#vector end local total=0 for i=low,high do total=total+vector[i] end return total end local function incbins(vector) local i=1 local total=sum(vector) while (vector[i]==0 and not(vector[#vector]==total)) do i=i+1 end if vector[#vector]==total then vector={} elseif not(vector[i]==0) then vector[i+1]=vector[i+1]+1 vector[i]=0 vector[1]=total-sum(vector,2) end return vector end local vector={5,0,0,0,0} while #vector>0 do print(vector) vector=incbins(vector) emu.frameadvance() end emu.pause()
Give that a run and I'll explain it. Did you run it? Good. Given any vector of "bins", this script will increment it to the next permutation, eventually running through all possible permutations. Suppose the music changes three times in a segment and we wish to test all of the possible ways to manipulate luck that involve delaying input for three frames total. Then our initial bin vector will be {3, 0, 0} which signifies to delay input by three frames at the first change in the music, zero frames at the second change in the music, and zero frames again at the third change in the music. By repeatedly plugging this vector into the incbins function, all possible permutations will be exhausted. These should be {3, 0, 0}, {2, 1, 0}, {1, 2, 0}, {0, 3, 0}, {2, 0, 1}, {1, 1, 1}, {0, 2, 1}, {1, 0, 2}, {0, 1, 2}, {0, 0, 3} (you can check these by replacing the vector={5, 0, 0, 0, 0} line in my script). This script should be extremely useful to us. I've also been working on my "ultimate bot", which should essentially solve the game for us. As yet, I only have a very rough draft that does not run, but it helps simply to have the format down. Here it is: Edit: After a hard night's work, I've got the basic structure of the bot functional. You may run this script at power on to suboptimally run the game through naming the first character. Once I write the musicmanip function, we should be nearly ready to test it through the first reset. I think the real test will be running the bot through several segments to compare it with the input of our existing run. If we override some parameters (not sure exactly how...) we should be able to reproduce the existing run exactly. If the two don't match, we can compare their inputs and see where it went wrong. Progress is accelerating. If the bot executes in any reasonable amount of time (say, less than an hour for one segment), we should be able to solve this game (for our given route). There's still a whole lot of work to do, but I now feel like the end is within sight. Edit 2: New version, with the main (only?) addition being the musicmanip function. (Thanks to BrandonE for help debugging it.) Looking through what remains, the hardest parts will be the walk function (which will also save and reset for us) and my battlebot function, which still isn't finished because it doesn't scroll through the battle narration. After those are written, it should just be a matter of writing some specialized functions and cleaning the whole thing up.
Language: lua

local function sum(vector,low,high) if not(low) then low=1 end if not(high) then high=#vector end local total=0 for i=low,high do total=total+vector[i] end return total end local function incbins(vector) local i=1 local total=sum(vector) while (vector[i]==0 and not(vector[#vector]==total)) do i=i+1 end if vector[#vector]==total then vector={} elseif not(vector[i]==0) then vector[i+1]=vector[i+1]+1 vector[i]=0 vector[1]=total-sum(vector,2) end return vector end --condition is a table that takes the form {fn=condition function, adr={relevant addresses}, extra 1, extra 2, etc...} --If executeaction is true, it executes the actions specified, if false, it merely advances frames up to lowguess. Useful in conjunction with musicmanip. local function guessandcheck(action,condition,framedelay,lowguess,highguess,executeaction) local state2=savestate.create() local oldstate={} for i=1,#condition["adr"] do oldstate[i]=memory.readbyte(condition["adr"][i]) end local foundit=false savestate.save(state2) while not(foundit) do savestate.load(state2) guess=math.floor((highguess+lowguess)/2) for i=1,guess do emu.frameadvance() end for i=1,#action do joypad.set(1,action[i]) emu.frameadvance() end for i=1,framedelay do emu.frameadvance() end if condition["fn"](unpack(oldstate),unpack(condition)) then highguess=guess else lowguess=guess+1 end foundit = (highguess==lowguess) end savestate.load(state2) for i=1,lowguess do emu.frameadvance() end if executeaction then for i=1,#action do joypad.set(1,action[i]) emu.frameadvance() end end --while not(condition["fn"](oldstate,unpack(condition))) do -- emu.frameadvance() --end end local function idleframes(n) for i = 1,n do vba.frameadvance() end end local function holdA(n) for i=1,n do joypad.set(1, {A=1}) vba.frameadvance() end end local function gamestarted(startedflag) if not(memory.readbyte(0x9822)==startedflag) then --0x9822 may not be the best byte to use. Check others. return true else return false end end local function mutantfselected() if (memory.readbyte(0x8000)==3 and memory.readbyte(0x803E)==128) then --Check if these are the addresses you really want return true else return false end end local function selectmutantf() action={{down=1},{down=1, right=1},{down=1,right=1,A=1},{down=1,A=1}} condition={fn=mutantfselected,adr={}} guessandcheck(action,condition,10,0,40,true) end local function namedR() if (memory.readbyte(0xFF93)==16 and memory.readbyte(0xFF92)==8) then return true else return false end end local function namechar1() action={{right=1},{right=1, down=1},{right=1, down=1},{up=1, right=1},{up=1, right=1},{right=1, down=1},{right=1, down=1},{right=1, A=1},{right=1, A=1}} condition={fn=namedR,adr={}} guessandcheck(action,condition,10,0,40,true) end local function musicmanip(backgroundaction,delayedaction,framesdelay) local action={{}} local buttons={"A","B","select","start","down","up","left","right"} for i=#backgroundaction+1,#delayedaction+framesdelay do backgroundaction[i]={} end for i = 1,(framesdelay+#delayedaction) do action[i]={} if i<framesdelay then for j=1,#buttons do action[i][buttons[j]]=backgroundaction[i][buttons[j]] end else for j=1,#buttons do action[i][buttons[j]]=backgroundaction[i][buttons[j]] or delayedaction[i-framesdelay][buttons[j]] end end joypad.set(1,action[i]) emu.frameadvance() end end --anticipatebattle(waypointsx,waypointsy,waypoint,encounterrates) --Create an updated guessandcheck function that supports background actions --Change framesdelay to be a two-level table later on, based on the segment framesdelay = {0,0,0,0,0,0,0,0} pressA={{A=1},{A=1}} pressB={{B=1},{B=1}} pressselect={{select=1},{select=1}} pressstart={{start=1},{start=1}} pressdown={{down=1},{down=1}} pressup={{up=1},{up=1}} pressleft={{left=1},{left=1}} pressright={{right=1},{right=1}} local segment={} segment[1]={ {fn=idleframes,60}, {fn=guessandcheck,pressA,{fn=gamestarted, adr={0x9822}},10,0,20,true}, --guess and check when to start the game {fn=idleframes,5}, {fn=holdA,320}, {fn=selectmutantf}, {fn=namechar1}, --cursor should end on the letter R {fn=idleframes,5}, --change to guessandcheck function with pressstart and executaction=false {fn=musicmanip,{{}},pressstart,framesdelay[1]}, {fn=walk,1}, --walk to guild {fn=guessandcheck,...}, --guess and check when to press A to enter the guild {fn=guessandcheck,...}, --guess and check when to press down to select the second character slot {fn=guessandcheck,...}, --guess and check when to press A to select OK {fn=selectmutantf}, {fn=namechar2}, {fn=guessandcheck,...}, --select third character slot {fn=guessandcheck,...}, --press A {fn=selectmutantf}, {fn=namechar3}, {fn=guessandcheck,...}, --press up to select fourth character slot {fn=guessandcheck,...}, --press A {fn=namechar4}, {fn=guessandcheck,...}, --press B {fn=walk,2}, --walk out of town {fn=walk,3}} --the walk script should be modified to save and reset as it nears the encounter for i=1,#segment do for j=1,#segment[i] do segment[i][j]["fn"](unpack(segment[i][j])) end end --should be able to overwrite frame constraints --(reset) --save state --perform actions optimally until just before change of music --use default action until appropriate frame, then use delayed action (possible overlap to consider) --repeat previous two steps until "near" reset point (quantify "near") --pause, save, and reset, much like luckman2 script (also check near misses for holding B) --when a hit is found, add up total frames "wasted" and number of steps wasted, calculating the likelihood of an additional reset needed due to steps wasted, record these values to file --set new frame contraint equal to best result so far plus one --load state --repeat previous seven steps until frame constraint is reached --pseudocode (actions) to start the game -------------------------------------- --press A --hold A --select and name character (luck manipulation?) --walk to guild --press A --select and name supporting cast, leave guild menu --leave town, enter field (luck manipulation?) --(shuffle party?) --walk as far as possible, reset --press A to load game (luck manipulation?) --walk until battle (luck manipulation?) --fight --defeat enemy (luck manipulation?) --finish battle (luck manipulation?) --walk until need to reset
Okay, most of that is notes and garbage. The important part is the segment[1] vector, which outlines every action we will take in the first segment of the game. This vector also establishes the syntax I'd like to follow. All that really remains is writing the appropriate functions, then running the code. I'll then incorporate the frame delays for luck manipulation and find an appropriate way to output the results (I was thinking I'd save them to file). Most of the code has already been written (little functions like namechar1 should take no more than three or four lines), so I think we're deceptively close to the testing phase. Polishing the script, however, will take quite a bit of time.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
You are basically correct on all counts, FractalFusion, but there is the possibility that Tub wants to find the drop rate in a Wii, PS3, or X-Box 360 game (none of which have reliable emulators) so that he can make a guide, not a TAS. If that is the case, he is limited to options 1 and 5 and possibly option 4. I also re-evaluated the problem using the central limit theorem and assuming a normal distribution. The expected value for p=0.4 and 100 samples is 40 and the standard deviation is sqrt(100*0.4*0.6) = 4.899. Obtaining 48 successes is therefore (48-40)/4.899 = 1.633 standard deviations away from the expected value. We then integrate the standard normal distribution from 1.633 to infinity and multiply it by two (it's a two-tailed test) to obtain a p-value of 0.10, in decent agreement with my (more accurate) p-value of 0.12 obtained directly from the binomial distribution. I guess it wasn't as hard as I thought.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Let me summarize my viewpoints (the first three are interconnected): 1) The frequentist school of thought trumps the Bayesian school of thought. 2) As a corollary, always seek a p-value. Disregard any Bayesian analysis with uninformed priors. (Of course, Bayes' theorem holds, it's just that it often is underdetermined.) 3) Never speak of the probability of something that is not somehow randomized. If there is randomization, you must know what is being randomized and how. For a valuable illustration of this, see the Bertrand paradox (this is perhaps my favorite subject on the treachery of probability when the problem is not carefully defined). 4) All probability is ultimately quantum mechanical in nature. (I do not know if anyone else subscribes to this philosophy, but it makes sense to me. A thorough explanation of my belief would be too lengthy for this forum post.) So you're fighting battles and looking for monster drop rates. Suppose you fight 100 battles against a particular monster and it drops the item you want 48 times. You would like to know P(p=0.4) (or something), where p is the probability that a monster drops an item, given that you got 43 out of 100 drops. In standard notation, you're really looking for P(p=0.4 | 48 out of 100 drops). Hence the allure of the Bayesian analysis. Seems simple enough, right? No can do. That drop rate was not randomized-- it was chosen by a game designer-- and it therefore fails criterion number 3 listed above. Any discussion of the probability that p=0.4 is meaningless because it either is or it isn't according to the programming of the game. We can, however, analyze the problem with p-values. Let the null hypothesis be H0: p=0.4 and the alternative hypothesis Ha: p=/=0.4. Supposing the null hypothesis to be true, we would like to know the probability of obtaining a result at least as far out as 8 from the expected mean (40). Therefore, it is a two-tailed test. The p-value could almost certainly be obtained by application of the central limit theorem and estimation of the pdf as a normal distribution, but I'm just not feeling up to it right now, so I'll instead use the binomial distribution directly. We want P(X>47 or X<33 | p=0.4) where X is the number of successful drops and p is the probability of a successful drop. Now it's simply a matter of finding b(48; 100, 0.4), b(49; 100, 0.4), b(50; 100, 0.4)... as well as b(32; 100, 0.4), b(31; 100, 0.4), b(30; 100, 0.4)... and so on, where b is the binomial distribution function, and adding them all up. Doing so, I obtain a p-value of about 0.12, which is generally not low enough to reject the null hypothesis at a reasonable significance level. Take note of what happened here. I suggested that you fought 100 battles (a lot!) and even gave you a success rate close to 50% (which would be ideal) and yet you still couldn't reject the null hypothesis that the actual probability of a drop is 0.4. That sucks. What it means is that you have to fight a lot of battles-- maybe 1,000 or 10,000-- before you can start pinning down the probability with any reasonable certainty. I might have started this exercise with the null hypothesis that p=0.5 and although it would have given a larger p-value, it would by no means be conclusive over other theories. What should you do? You have a few options: 1) Just assume that p = (number of successes)/(number of trials) and be done with it. 2) Make a lua script that fights battles for you and run the game at a high speed overnight to dramatically increase your sample size. 3) Attempt to find and/or deconstruct the RNG so that you can pinpoint exactly what the drop rate is. This could be an hour's work or several months' work, depending on the game. 4) Attempt to characterize the drop rates. It's likely that the drop rates are not completely arbitrary (if they are, you are screwed!), but instead some integer fraction of 10 or some integer fraction of 256 or the reciprocal of an integer, etc. If you can characterize how they chose the drop rates based on your limited number of samples (beware of errors arising from small sample sizes), you may be able to pare down your null and alternative hypotheses to give you more definitive p-values. 5) Similar to option 2, find a few dozen close friends to run the game and report their drop rates, then take the aggregate statistics. Option 1 is useless for low drop rates. Options 2 and 3 depend on the game and system being emulated. Option 4 is nice, but would likely rely on option 2 being used in conjunction with it. I consider option 5 a last resort, but I think TASVideos would be happy to help if it seemed worthwhile. If I were running the game, I'd first try option 3, then option 2 and option 4, finally begging for option 5 before giving up and settling on option 1.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
In my experience, "low game complexity" trumps all. I'd therefore pick Mischief Makers, as it is the only 2D N64 game with a TAS.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I've only skimmed this conversation, but what Tub has brought up is a very important (and mildly controversial) topic in science. I don't know how much this overlaps what has already been said, but I'd like to offer some Wikipedia articles that perhaps strike more to the point. Tub seems to be interested in the Bayesian probability, the likelihood that a coin is fair given the data shown. I would like to warn you: Bayesian probability, and in particular, prior probability is controversial in sciences. (Personally, I would not use the word "controversial", but instead "garbage".) The central problem with prior probabilities comes from what is known as the principle of indifference, which roughly states that if we don't have reason to believe one hypothesis is true over another (mutually exclusive) hypothesis, we assign them equal probabilities of being true. Many otherwise great minds subscribe to the principle of indifference, but it should be unsettling to you right down to your bones that we use a lack of information to assign a probability. I first came across the principle of indifference in Martin Gardner's outstanding book "Aha! Gotcha", in which he rips it to shreds with numerous absurdities "proven" by the principle. Laplace once used the principle to show that the probability of the sun rising tomorrow is 1,826,214 to 1 against! Gardner offers other examples in which the principle of indifference is absurd and contradictory and I'll be happy to cover them if anyone is interested, but it is too far abreast of this topic. Bayesians have dug themselves into quite a hole with their willingness to assign a probability to any statement. For example, what is the probability that Newton's second law is correct? Is it 0.999999999999? This is a law of nature we're talking about, not some random variable! Therefore, the answer must be either 0 (the law is surely incorrect) or 1 (the law is surely correct). (The true answer appears to be 0, based on quantum mechanics.) In contrast with the Bayesian camp is the frequentist viewpoint, which holds that probability is just a reflection of the number of "successful" trials divided by the total number of trials. From this viewpoint, the scientifically popular statistical hypothesis testing takes shape. In this method, a null hypothesis is chosen and this hypothesis is tested to a previously specified significance level. In the case of flipping a coin, we might want to know with a confidence of at least 95% that the coin is not fair (please note that this doesn't mean there is a 95% probability that the coin is not fair-- the coin either is or is not fair). At the heart of statistical hypothesis testing is the calculation of the p-value, which is compared with the significance level in order to decide whether to reject the null hypothesis. In my opinion, statistical hypothesis testing is not perfect, but used properly, it is by far the best tool we have. The clash of the two schools of thought is clearest via the Jeffreys-Lindley paradox, which considers situations in which the two philosophies offer different conclusions about the supposed falsehood of the null hypothesis. If you read no other link in this post, I encourage you to study the Jeffreys-Lindley paradox. The frequentist approach requires the introduction of an arbitrary significance level, but the Bayesian approach requires the introduction of a (in my opinion) far more troubling prior probability, founded on the principle of indifference. Note from the example that this prior probability assigns equal likelihood to the possibilities that the probability of having a boy is 0.5036 and the probability that having a boy is 0. We know the probability of having a boy is not zero, so this is absurd. You are more than welcome to come to your own conclusion about these philosophies of probability, but I encourage you (Tub) to re-examine your coin flipping problem with a null hypothesis (that the coin is fair) and an alternative hypothesis, calculating the p-value. I am also happy to share my deeper thoughts on the principle of indifference, thought experiments that poke holes in the Bayesian viewpoint, and my own thoughts on probability, if anyone is interested.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I don't know if I should feel better that I narrowed it down to 6 and 14, one of which was the lossless version or worse that 14 had a lower bitrate and 8 had a relatively high bitrate. Ultimately, I just couldn't tell the difference between all 15.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I solved it by a different method from the suggestion: I just transformed it into an infinite series. For xy<1 (satisfied by the bounds of the integral), 1/(1-xy) = 1 + xy + (xy)^2 + (xy)^3 + ... From there, the integrals are straightforward and ultimately give 1 + 1/4 + 1/9 + 1/16 + 1/25 + ... which is the famous Basel problem (I'd post a link to Wikipedia, but it would stick out on top of the spoiler tag). Euler found the solution so I don't have to-- the answer is pi^2/6. The mathematical importance? Maybe you're hinting at the Basel problem itself, or perhaps this kind of problem can be generalized to relate to the Riemann zeta function. Assuming I didn't make any boneheaded mistakes, I'm rather proud to have figured out one of these problems as they're usually pretty hard.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I mentioned this in the other topic, but I'm using Harmon/Kardon speakers in my HP zd7260us laptop. They're nice speakers, but I probably would do better with headphones. I'm not much of an audiophile and my speakers aren't the greatest, but I gave it my best shot. I homed in on 00:40 in the piece, when the violin nears its highest pitch and volume. My reasoning was that the higher overtones tend to be underrepresented in the lossier formats. Therefore, in the lossless format, this section should be almost painful to listen to with the volume high enough. With this method, I had some success, but I admit it was mostly guesswork. Track 8 struck me as the worst (I hope I don't eat those words later) and tracks 6 and 14 were close to the best. I ultimately chose track 14 as the best among them, and I'd be interested to hear if track 8 is indeed one of the lossier formats. Honestly, though, this was very difficult for me and I think you could use whichever format has the highest compression ratio for encoding. Now I'd like to open these up in Audacity and subtract them from each other to see exactly where the differences lie. I expect this won't work well because the human ear isn't sensitive to phase differences, so the lossy formats won't necessarily be in phase with each other or the lossless format. In fact, from my understanding of signal processing, the clearest giveaway should be very sudden changes-- delta functions and finite impulses. I know it's a little soon to ask for another test, but for the next one, you might try a "song" with a lot of clicks in it. Even a track with a single click should illuminate very interesting differences between formats. Edit: (In reply to sgrunt.) Haha, I should have just picked "I can't tell". I'm no good at this.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
I have a suggestion for your next test. Post ten randomly named audio files, five identical pairs. For each of the five, use a different lossy (or lossless) encoding. In this case, the goal wouldn't strictly be to evaluate which is "best" among them, but rather to see if someone can distinguish any difference between them. Listeners would be asked to pair up the identical recordings. For the lossiest format(s), I expect they'll be able to do it, but I think the lossless and moderately lossy formats will be functionally indistinguishable. I also recommend that listeners post what speakers or headphones they're using. Although I haven't taken the test yet, I'm using a set of Harman/Kardon speakers that came with my HP zd7260us laptop.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Just re-encode them all in a lossless format. In other words do FLAC -> MP3 -> FLAC and give it a random name. I don't claim to know how to do it, though. You're the encoder, after all. Edit: What Aktan said.
Experienced Forum User, Published Author, Player (79)
Joined: 8/5/2007
Posts: 865
Here's a rough draft of my new bot I call "battlebot" (in honor of the show BattleBots that I briefly liked). Note that it uses the guessandcheck function I programmed earlier. As yet, this bot only executes the default commands and doesn't scroll through the text. With just a little bit of work, I can make it much better. Expect forthcoming edits... Edit: Updated version of my bot. This one always selects the second option for each character, though it can be easily modified to select either the first or second option. I had to insert idle frames between each action or it would "desync". With significant work, I can modify it so that any combination of actions can be chosen. I'd eventually like to organize them as a vector like {5,2,1,6}, which would signify that character 1 should execute option 5, character 2 should execute option 2, character 3 should execute option 1, and character 4 should execute option 6. This is nontrivial for a few reasons. First, we may not have four characters (that's simple enough to solve, but not at this hour). Second, I need to convert those options into actual actions. Third, I don't yet know how to optimally navigate the menu; I'll wait for feedback from FatRatKnight on that. In any case, load it up and give it a spin. It should work like a dream. Edit 2: Another new version of my script. This one just takes a vector of four specified actions in the format outlined in my previous edit. These should be input as actionvector near the bottom of the script. Currently, you can only select the default option, scroll down one option, or scroll down two options. In this default version, it always selects the second option. I've tested it and it seems to work fine with any options. (It wasn't able to "finish" the battle any faster with the default options than when selecting the second option. I don't know if that's an indication of success or not.) More thorough testing may come tomorrow. Edit 3: New version. This one works.
Language: lua

--Finds the earliest frame at which the RAM value at "address" is equal to "condition". --extra1, extra2, and extra3 are any extra information that needs to be used by the "condition" function. local function guessandcheck(action,condition,framedelay,lowguess,highguess,extra1,extra2,extra3) local state2=savestate.create() local oldstate={memory.readbyte(0xCCC9), --1) x coordinate memory.readbyte(0xCCC8), --2) y coordinate memory.readbyte(0xFFCE), --3) cursor x memory.readbyte(0xFFCF), --4) cursor y memory.readbyte(0x994A), --5) battle window changes memory.readbyte(0xC424), --6) battle window selection offset memory.readbyte(0xFF92)} --7) selection within battle window local foundit=false savestate.save(state2) while not(foundit) do savestate.load(state2) guess=math.floor((highguess+lowguess)/2) for i=1,guess do emu.frameadvance() end for i=1,#action do joypad.set(1,action[i]) emu.frameadvance() end for i=1,framedelay do emu.frameadvance() end if condition(oldstate,extra1,extra2,extra3) then highguess=guess else lowguess=guess+1 end foundit = (highguess==lowguess) end savestate.load(state2) for i=1,lowguess do emu.frameadvance() end for i=1,#action do joypad.set(1,action[i]) emu.frameadvance() end while not(condition(oldstate,extra1,extra2,extra3)) do emu.frameadvance() end end local function tookstep(oldstate) if not((memory.readbyte(0xCCC9)==oldstate[1]) and (memory.readbyte(0xCCC8)==oldstate[2])) then steptaken=true else steptaken=false end return steptaken end --Should be incorporated as a special case into selectedcorrect local function selecteddefault(oldstate) if not(memory.readbyte(0x994A)==oldstate[5]) then selected=true else selected=false end return selected end --Checks if the cursor was moved down the proper number of slots before the selection was made. --extra1 should be set to the character in question, extra2 should be the default actions, extra 3 should be the number of slots to scroll down. local function selectedcorrect(oldstate,character,defaultaction,scrolllength) local defaultselection=defaultaction[character] if memory.readbyte(0xD3EB + 4*character)==(defaultselection+scrolllength) then selected=true else selected=false end return selected end local function idleframes(n) for i = 1,n do vba.frameadvance() end end --Finds the slot of the first usable action by any character. local function firstusable(character) local foundit=false i=0 while not(foundit) do ability=memory.readbyte(0xCC0F + 2*i + 0x1F*(character-1)) uses=memory.readbyte(0xCC0F + 2*i + 0x1F*(character-1) + 1) if (uses<100) or (ability==0x13) or (ability==0x17) then foundit=true else i=i+1 end end return i end local function loadactions(numalive) local action={} for i = 1,4 do action[i]=firstusable(i) end return action end local function autofight(scroll,actionvector,targetvector) defaultactions=loadactions() print(defaultactions) difference={} for i=1,#defaultactions do difference[i]=actionvector[i]-defaultactions[i] end guessandcheck(scroll[1],selecteddefault,6,0,16) for i=1,#actionvector do guessandcheck(scroll[difference[i]+1],selectedcorrect,8,0,16,i,defaultactions,difference[i]) idleframes(2) --The following line should be updated to allow for selecting arbitrary targets (based on targetvector, which is unused). Doing so would obsolete selectdefault. guessandcheck(scroll[1],selecteddefault,6,0,16) end end scroll={{{A=1},{A=1}}, --don't scroll {{down=1},{down=1,A=1},{A=1}}, --scroll down 1 {{down=1},{down=1,right=1},{down=1,right=1},{A=1},{A=1}}} --scroll down 2 actionvector={6,2,2,6} targetvector={} --Unused, as yet. Should specify which enemy to target. autofight(scroll,actionvector,targetvector) vba.pause()
1 2
29 30 31
34 35