| Official Hex/ASM/Etc. Help Thread |
|
Forum Index - SMW Hacking - General SMW Hacking Help - ASM & Related Topics - Official Hex/ASM/Etc. Help Thread |
|
|
|
|
| Posted on 2011-10-07 02:26:11 AM |
Link | Quote |
|
I have a couple of ASM troubles right now, but I'll only ask about the more important one right now, since it pertains to SMWCP2.
http://bin.smwcentral.net/u/1365/air_meter.asm
http://bin.smwcentral.net/u/1365/air_meter.cfg
Basically I'm trying to edit the tilemap of the air meter so it can be compatible with AFHBs but the way it's laid out is in a way I'm not familiar with at all. I could change these tiles easily
CodeFullTile:
LDA #$46
RTS
EmptyTile:
LDA #$47
RTS
EndPiece:
LDA #$46
RTS
but I can't find the countdown tiles (48-4A and 57-5A) at all.
|
|
| Posted on 2011-10-07 09:05:25 AM |
Link | Quote |
|
Code AND #$07
CLC
ADC #$47 ;Tile number
CMP #$4B ;\
BCC Return ; | Remove those lines to put all tiles on the same row
CLC ; |
ADC #$0C ;/
Poke around this.
|
|
| Posted on 2011-10-07 09:32:55 AM |
Link | Quote |
|
Originally posted by imameliaWhat would be a good way to generate a sequence of random numbers that contains each number exactly once? For instance, if I want a range of 00-1F, then the routine would output those 0x20 numbers in a random order, perhaps in a 0x20-byte-long RAM table. The output might be, say, "04 10 1A 0F 0C 16 18 1E 02 11 0D 1C 1F 03 07 15 14 00 05 1D 01 0E 12 19 0E 08 0B 17 06 1B 0A 13 09".
Conceptually, the best way I can think of is to start with an ordered list (00, 01, 02,...), randomly select two elements of the list, and swap them. Do that however many times you like and that should give you a decently randomized list.
|
|
| Posted on 2011-10-07 10:07:45 AM |
Link | Quote |
|
Better solution:
Start with an ordered list.
00 01 02 03 04 05 06 07
Pick a random element from the list and swap it with the first element. Picking the first one is allowed.
/¯¯¯¯¯¯¯¯¯¯¯¯¯\
05 01 02 03 04 00 06 07
Take a random element from the remaining list elements. Swap it with #2.
/¯¯¯¯¯¯¯\
05 04 02 03 01 00 06 07
Repeat for as many steps as your list has entries.
/\
05 04 02 03 01 00 06 07
/¯¯¯¯¯¯¯\
05 04 02 06 01 00 03 07
/¯¯¯¯\
05 04 02 06 03 00 01 07
/\
05 04 02 06 03 00 01 07
/¯\
05 04 02 06 03 00 07 01
/\
05 04 02 06 03 00 01 07
The improvement that (assuming your random number generator is perfect) it is guaranteed to give all lists with equal probability, while arnpoly's method usually favors lists closer to the sorted original if you do too few swaps, and takes longer than mine if you do too many swaps (and I'm pretty sure the range "too few" and "too many" overlaps for all larger lists).
|
| Last edited on 2011-10-07 02:25:52 PM by Alcaro. |
|
| Posted on 2011-10-07 04:04:52 PM |
Link | Quote |
|
While I do like Alcaro's method better than mine, there is a trade-off in that it is more difficult (in ASM anyway) to find a random value that isn't out of a power of 2. Choosing from 00-07 is easy (LDA RandomValue : AND #$07) but choosing from 01-07 requires a different and likely more complex method. I can't think of a good way to do that in ASM, but I would like to hear any ideas on that.
I think a good compromise is to take Alcaro's method of stepping through each element in the list but swap it with any element in the list, not just ones later in the list. That makes sure every element of the list has the chance to move out of its current spot in the list and has the added benefit of being easier to code.
EDIT: Fixed AND #$08 with the correct value #$07.
|
| Last edited on 2011-10-08 09:34:41 AM by arnpoly. |
|
| Posted on 2011-10-07 04:45:17 PM |
Link | Quote |
|
I decided to make a little script to test how often the different permutations appear with this hybrid algorithm for a four character sequence.
Originally posted by results1234: 2560 1243: 2560 1324: 2560 1342: 3584 1423: 2816 1432: 2304 2134: 2560 2143: 3840 2314: 3584 2341: 3584 2413: 2816 2431: 2816 3124: 2816 3142: 2816 3214: 2304 3241: 2816 3412: 2816 3421: 2560 4123: 2048 4132: 2304 4213: 2304 4231: 2048 4312: 2560 4321: 2560
It's not a perfectly straight line, but it's good enough for most situations.
If I run it twice, I get this:
Quote1234: 2750 1243: 2710 1324: 2710 1342: 2719 1423: 2762 1432: 2733 2134: 2710 2143: 2725 2314: 2719 2341: 2690 2413: 2723 2431: 2744 3124: 2762 3142: 2723 3214: 2733 3241: 2744 3412: 2763 3421: 2754 4123: 2724 4132: 2740 4213: 2740 4231: 2724 4312: 2706 4321: 2728
This is very smooth. It's still not 100% perfect, but we won't get perfect even with 50 runs of this algorithm. It should be good enough for all practical purposes.
With my own algorithm, the results are perfectly even, but if it's hard to implement, use this hybrid.
It would, of course, be possible to run my algorithm backwards and pick 0-6 instead of 1-7, if that's easier. It'd give the same results.
Just for fun, here's arnpoly's original method, with four swaps on a four-element list:
Quote1234: 4480 1243: 3072 1324: 3072 1342: 2880 1423: 2880 1432: 3072 2134: 3072 2143: 2432 2314: 2880 2341: 2048 2413: 2048 2431: 2880 3124: 2880 3142: 2048 3214: 3072 3241: 2880 3412: 2432 3421: 2048 4123: 2048 4132: 2880 4213: 2880 4231: 3072 4312: 2048 4321: 2432
It's better than I thought, but 1234 is indeed annoyingly common, and it's pretty inefficient. One run of this takes as many random numbers of two runs of our hybrid, and gives less smooth output than one run of the hybrid.
...oh, and picking a random value from 00-07 is AND #$07, not AND #$08.
|
|
| Posted on 2011-10-08 09:47:13 AM |
Link | Quote |
|
This is tremendous work, Alcaro. I admit defeat. I'm pretty sure we've beat this to death now but this is a really good investigation that I believe is useful.
I'm genuinely curious though, what would be a good method of finding a random value from a range of numbers that isn't a power of 2? I had this come up awhile back when I needed to find a random value between 00-0B. What I did was look for a random value from 00-0F and throw the results out until I found a value in the range I needed. It worked and it provides a uniformly random value, but it just seemed inefficient to me. To me this is the only hurdle between coding Alcaro's method and our "hybrid" method.
Originally posted by Alcaro
...oh, and picking a random value from 00-07 is AND #$07, not AND #$08.
Oops, good catch. I edited my previous post to correct that.
|
|
| Posted on 2011-10-08 09:59:14 AM |
Link | Quote |
|
Well, my implementation of Alcaro's version (not the hybrid) looks like this:
CodeGenerateRandomList:
LDA.b #!RAM_RandomList
STA $08
LDA.b #!RAM_RandomList>>8
STA $09
LDA.b #!RAM_RandomList>>16
STA $0A
LDX #$00
.Loop1
TXA
STA !RAM_RandomList,x
INX
BNE .Loop1
LDX #$00
.Loop2
LDA !RAM_RandomList,x
STA $0B
JSL !GetRand
TAY
LDA [$08],y
STA !RAM_RandomList,x
LDA $0B
STA [$08],y
INX
BNE .Loop2
RTS
I tested it and found that it works, although having a decent random number generator is definitely necessary.
|
|
| Posted on 2011-10-08 10:16:23 AM |
Link | Quote |
|
|
...and how does that random number generator work? Does it put a random number equal to or higher than X in A?
|
|
| Posted on 2011-10-08 10:41:33 AM |
Link | Quote |
|
|
Well, when I tested it, I just used $01ACF9. I'm sure there are better and more customizable random number generators out there.
|
|
| Posted on 2011-10-08 10:50:09 AM |
Link | Quote |
|
|
If it picks a random number from #$00 to #$FF, then you have implemented the hybrid algorithm.
|
|
| Posted on 2011-10-08 12:28:03 PM |
Link | Quote |
|
|
If you feel like wasting a good amount of RAM, you could make $100 flags that check if a value has already been picked or not.
|
|
| Posted on 2011-10-08 12:35:43 PM |
Link | Quote |
|
|
...and how would that be better than taking the values sequentially?
|
|
| Posted on 2011-10-08 07:27:21 PM |
Link | Quote |
|
|
Does anybody have any idea why this is happening?
|
|
| Posted on 2011-10-08 10:44:04 PM |
Link | Quote |
|
|
Fiddle with the "acts like" setting in the CFG until that stops happening.
|
|
| Posted on 2011-10-09 03:19:30 AM |
Link | Quote |
|
Originally posted by Alcaro...and how would that be better than taking the values sequentially?
No, I meant instead of making the list. have the random number generator pick any number from $00 to $FF, and see if it has already been picked. If yes, return to start. otherwise, use it.
However, I just realize this might cause extreme slowdown when $E0+ numbers have been selected and it has to fish around for the last ones. And when $FF numbers have been picked, the last one will need around 255 tries before being found :V
|
|
| Posted on 2011-10-09 03:23:52 AM |
Link | Quote |
|
Originally posted by AlcaroCode AND #$07
CLC
ADC #$47 ;Tile number
CMP #$4B ;\
BCC Return ; | Remove those lines to put all tiles on the same row
CLC ; |
ADC #$0C ;/
Poke around this.
Poking around with that gave me the desired result (just need to send the updated files to SNN). Thank you very much for your help.
|
|
| Posted on 2011-10-09 04:36:52 AM |
Link | Quote |
|
Originally posted by Sindextreme slowdown
Which is exactly why a shuffling algorithm with constant (and finite) time complexity is better.
|
|
| Posted on 2011-10-11 03:42:26 PM |
Link | Quote |
|
So for a while now, I have been using the RAM defines from all.log in my coding in place of writing out the RAM addresses, in an attempt to make the code easier to understand. Since copying the list to the start of every sprite I create takes up a lot of space and looks rather ugly, I thought that I'd try putting all the defines in a separate .asm file and then using the incbin command on it. However, when assembling my sprite, it seems like xkas didn't recognize any of my defines. Am I making a mistake somewhere, or does incbinning defines only work for ROM addresses?
In case it helps, this is the format of my defines file:
Code!RAM_FrameCounter = $13
!RAM_FrameCounterB = $14
!RAM_ControllerA = $15
!RAM_ControllerB = $17
!RAM_MarioPowerUp = $19
!RAM_ScreenBndryXLo = $1A
!RAM_ScreenBndryXHi = $1B
!RAM_ScreenBndryYLo = $1C
!RAM_ScreenBndryYHi = $1D
!RAM_IsVerticalLvl = $5B
; ...and so on
EDIT: Never mind. It's incsrc, not incbin. <_<
|
| Last edited on 2011-10-11 03:53:48 PM by yoshicookiezeus. |
|
| Posted on 2011-10-15 12:10:58 AM |
Link | Quote |
|
|
Barring using something like Super Status Bar or something similar that does a major overhaul of the status bar, is there a way to (permanently) write tiles onto the status bar outside of the normal editable range (for example, right below the points/score counter)?
|
|
|
|
|
|
|
Forum Index - SMW Hacking - General SMW Hacking Help - ASM & Related Topics - Official Hex/ASM/Etc. Help Thread |