【问题标题】:Assembly Random Number within Range using Easy 68K (68000)使用 Easy 68K (68000) 在范围内组装随机数
【发布时间】:2011-12-20 00:25:48
【问题描述】:

我正在使用 Easy 68K 模拟器创建一个简单的二十一点游戏,并且需要使用随机数来分配牌。我的牌必须在 2 到 11 的范围内。我似乎每次都得到相同的数字,而且不在我期望的范围内。我的卡值需要以 D3 结尾,所以我有以下随机数代码:

 CLR.L       D0
 CLR.L       D3
 MOVE.B      #8, D0         ;Access time
 TRAP        #15
 AND.L       #$5FFFFF,D1    ;prevent overflow in divu
 DIVU        #10, D1
 SWAP        D1
 ADDQ.W      #1, D1
 MOVE        D1, D3

我是通过修改本站代码得出的:https://notendur.hi.is/voe1/3.%20onn/Tolvuhogun/EASy68K/Examples/tutorial3.X68

我希望找到生成数字 2 到 11 的帮助。我已经在互联网上搜索了几个小时。我知道我需要使用 Move.B #8, D0 来访问时间,但除此之外,我没有取得太大进展。任何帮助将不胜感激!

【问题讨论】:

    标签: assembly random 68000


    【解决方案1】:

    AND.L 中使用的掩码(“防止 divu 溢出”)仅适用于除以 100 - 您需要使用0x7FFFF 进行掩码才能除以 10。

    为什么:

    0xFFFFFFFF / #100 = 0x28f5c28 - too big for a single word!
    0x5FFFFF   / #100 = 0xF5C2    - that fits
    
    0x5FFFFF / #10  = 0x99999 - too big for a single word!
    0x7FFFF  / #10  = 0xCCCC  - that fits
    

    此外,您拥有的代码将为您提供一个从 1 到 10 (0-9 + 1) 的数字。如果要 2 到 11,则必须加 2,而不是 1。


    这是一个更高级的随机数生成器,它是从 Mac OS QuickDraw 源代码中借用的。请注意,您可能需要对语法进行一些翻译(它是在 25 年前编写的!)和/或修改它加载和存储种子的方式。

    ;--------------------------------------------------------------
    ;
    ;  FUNCTION Random: INTEGER;
    ;
    ;  returns a signed 16 bit number, and updates unsigned 32 bit randSeed.
    ;
    ;  recursion is randSeed := (randSeed * 16807) MOD 2147483647.
    ;
    ;  See paper by Linus Schrage, A More Portable Fortran Random Number Generator
    ;  ACM Trans Math Software Vol 5, No. 2, June 1979, Pages 132-138.
    ;
    ;  Clobbers D0-D2, A0
    ;
    ;
    ;  GET LO 16 BITS OF SEED AND FORM LO PRODUCT
    ;  xalo := A * LoWord(seed)
    ;
            MOVE.L  GRAFGLOBALS(A5),A0      ;POINT TO QuickDraw GLOBALS
            MOVE    #16807,D0               ;GET A = 7^5
            MOVE    D0,D2                   ;GET A = 7^5
            MULU    RANDSEED+2(A0),D0       ;CALC LO PRODUCT = XALO
    ;
    ;  FORM 31 HIGHEST BITS OF LO PRODUCT
    ;  fhi:=HiWord(seed) * ORD4(a) + HiWord(xalo);
    ;
            MOVE.L  D0,D1                   ;COPY xalo
            CLR.W   D1
            SWAP    D1                      ;GET HiWord(xalo) as a long
            MULU    RANDSEED(A0),D2         ;MULT BY HiWord(seed)
            ADD.L   D1,D2                   ;ADD LEFTLO = FHI
    ;
    ;  GET OVERFLOW PAST 31ST BIT OF FULL PRODUCT
    ;  k:=fhi DIV 32768;
    ;
            MOVE.L  D2,D1                   ;COPY FHI
            ADD.L   D1,D1                   ;CALC 2 TIMES FHI
            CLR.W   D1
            SWAP    D1                      ;CALC FHI SHIFTED RIGHT 15 FOR K
    ;
    ;  ASSEMBLE ALL THE PARTS AND PRE-SUBTRACT P
    ;  seed:=((BitAnd(XALO,$0000FFFF) - P) + BitAnd(fhi,$00007FFF) * b16) + K;
    ;
            AND.L   #$0000FFFF,D0           ;GET LO WORD XALO
            SUB.L   #$7FFFFFFF,D0           ;SUBTRACT P = 2^31-1
            AND.L   #$00007FFF,D2           ;BitAnd(fhi,$00007FFF)
            SWAP    D2                      ;TIMES 64K
            ADD.L   D1,D2                   ;PLUS K
            ADD.L   D2,D0                   ;CALC TOTAL
    ;
    ;  IF seed < 0 THEN seed:=seed+p;
    ;
            BPL.S   UPDATE
            ADD.L   #$7FFFFFFF,D0
    UPDATE  MOVE.L  D0,RANDSEED(A0)         ;UPDATE SEED
            CMP.W   #$8000,D0               ;IS NUMBER -32768 ?
            BNE.S   NUMOK                   ;NO, CONTINUE
            CLR     D0                      ;YES, RETURN ZERO INSTEAD
    NUMOK   MOVE.W  D0,4(SP)                ;RETURN LO WORD AS RESULT
            RTS
    

    【讨论】:

    • 这似乎有效,虽然我似乎只在程序期间得到一个随机数。我所有的卡都是一样的。当我重新运行程序时,我得到一个不同的数字,但每张牌都等于那个数字(尽管我每次发牌时都在清除寄存器并调用 Move.B #8, D0)跨度>
    • 这是因为这些“随机”数字的基础在呼叫之间没有改变——MOVE.B #8, D0 只是让您获得自午夜以来的 1/100 秒的时间。由于运行代码可能需要不到 1/100 秒的时间,因此结果不会改变。我将在我的答案中添加另一个随机数函数。
    【解决方案2】:

    您需要根据您的间隔(最小值和最大值)使用正确的掩码,此代码将解决您的所有问题,它需要两个参数:D5 中的最小值和 D6 中的最大值,它还使用 D0、D7 和 A1。

    RAND_GEN
        SUB     D5,D6             ;You should give Min in D5 and Max in D6
        MOVE    D6,D7
        ADDI     #1,D6
        MULU    #$FFFF,D7
        LEA     SEED,A1
        MOVE.B  #8,d0
        TRAP    #15
        ADD    (A1),D1
        MULU  #$FFFF,D1
        EOR.L     #$F321F23A,D1
        MOVE    D1,(A1)
        AND.L   D7,D1    ;PREVENT OVERFLOW FOR (Max-Min)
        DIVU    D6,D1         ;time count / (Max-Min)
        SWAP    D1              ;swap upper and lower words of D1 to put remainder in low word
        ADD  D5,d1           ;D1.W contains number in the range of (Min,Max)
        RTS
    
    * Put variables and constants here
    SEED
        DC.W    1
    

    SEED 在程序开始时默认为 1,并在每次 RAND_GEN 调用后自动更新,您也可以随时更改。

    在 EASY68K 上测试。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-31
      • 2011-12-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-01
      • 1970-01-01
      相关资源
      最近更新 更多