TASVideos

Tool-assisted game movies
When human skills are just not enough

Fractal Fusion / Source / Monopoly

The following source is for a program used to determine which card combinations are feasible through luck-manipulation. This code is based off an RNG disassembly of the Monopoly ROM.

Most of this stuff is independent of the below project, because it was one of the earlier programs.

Note: Chance deck starts at $0472. Community Chest deck starts at $0482. Both are 16 bytes long.

Chance card values: 0 getoutofjailfree 1 adv to go 2 nearestrail 3 back3space 4 repairs 5 poortax 6 boardwalk 7 illinois 8 adv to stcharles 9 nearestrail 10 bankpays$50 11 nearestutil 12 rideonreading 13 buildingmatures$150 14 gotojail 15 chairman

Community Chest card values: 0 getoutofjailfree 1 inherit$100 2 doctorsfee$50 3 payhospital$100 4 repairs 5 salestock$45 6 schooltax 7 gotojail 8 incometaxrefund$20 9 adv to go 10 receiveservices$25 11 secondprize$10 12 bankerror 13 lifeinsur$100 14 xmasfundmatures$100 15 grandopera

monopoly.cc:

#include <stdio.h>
void rndfunc1(unsigned long *a);
void rndfunc1(unsigned long *a, int x);
void init(char *d);
void printarray(char *d);
void setupcards(unsigned long *a, char *chance, char *commchest);
int main()
{
   unsigned long a,b;
   char chance[16];
   char commchest[16];
   int x;

   a=0x64EEB2; //starting "random" seed (random as in used by the game's RNG)

   x=0;
   while(1)
   {
     b=a;

     setupcards(&b,chance,commchest);

     //testing for specific cards; change to suit requirements
     if(chance[0]==4 && commchest[1]==4 && commchest[0]!=7)
         break;
	 //chance first repairs; comm chest first not gotojail; second repairs

     // or for example: if(chance[0]==8 && commchest[0]==15 && chance[1]==3)
     // chance first advtostcharles; second back3space; comm chest first grandopera

     rndfunc1(&a);
     x++;
   }

   printarray(chance);
   printf("\n");
   printarray(commchest);
   printf("%X\n",a);

   printf("Delay: %d",x);


   getchar();
   return(0);
}
void rndfunc1q(unsigned long *a)
{
    long b,c;
    char x;
    b=*a;
    c=b<<1;
    c^=b;
    if (c&0x200000) x=1; else x=0;
    *a=((*a<<1)+x);
}
void rndfunc1(unsigned long *a, int x)
{
    for(int i=1;i<=x;i++)
            rndfunc1q(a);
}
void init(char *d)
{
    for(int i=0;i<=15;i++)
    {
    d[i]=0xFF;
    }
}
void printarray(char *d)
{
    for(int i=0;i<=15;i++)
            printf("%d\n",d[i]);
}
void setupcards(unsigned long *a, char *chance, char *commchest)
{
   unsigned char ramf7, r, cardno;
   init(chance);
   init(commchest);

   rndfunc1q(a);
   ramf7=0;
   cardno=15;
   while(1)   //chance //throw random array index from 0 to 15
   {
       rndfunc1(a,3);
       r=*a%256;
       r^=ramf7;
       r/=16;

       if(chance[r]>=0)     //spot already occupied
       {
          ramf7++;
          continue;
       }

       chance[r]=cardno;
       if(cardno==0) break;
       cardno--;
   }
   cardno=15;
   ramf7=16;

   while(1)  //commchest
   {
       rndfunc1(a,3);
       r=*a%256;
       r^=ramf7;
       r/=16;

       if(commchest[r]>=0)
       {
          ramf7++;
          continue;
       }

       commchest[r]=cardno;
       if(cardno==0) break;
       cardno--;

   }
}

This was the code for the main project during Monopoly TASing.

Header only.

monopolyfuncdef.h:

//in monopoly.h

void rndfunc1();
void random1(int x);
void rndfunc2();
void random2(int x);
void random3(int x);
void random4(int x);
void getdice();
void cpumove();
void cpumovedouble();
void playermove(int b, int c);
void playermovedouble(int b, int c);
void finishturn();
void cpumoveab();

//in monopolysolve.cc

void initabc();
void save();
void revert();
void trynext();
void nextabc();
void printdelay();
int calcdelay();
void drreset();

Actually a C file. Provides functionality

monopoly.h:

#include <stdio.h>
#include "monopolyfuncdef.h"


unsigned long rnda=0;
unsigned char rndb=0;
unsigned char rcnt=0;
unsigned char die1=0;
unsigned char die2=0;

//the linear feedback shift register
//corresponding to polynomial x^22 + x^21 + 1 in Z_2
void rndfunc1()
{
     long b,c;
     char x;
     b=rnda;
     c=b<<1;
     c^=b;
     if (c&0x200000) x=1; else x=0;
     rnda=((rnda<<1)+x);
}

void random1(int x)
{
     for(int i=1;i<=x;i++)
             rndfunc1();
}

void rndfunc2()
{
     random1(5);
     rndb+=35;
}

//reset rcnt before doing this

void random2(int x)
{
     for(int i=1;i<=x;i++)
     {
             random1(3);
             rndfunc2();
             rcnt++;
     }
}

//don't forget to rcnt++ between random2 and random3

void random3(int x)
{
     for(int i=1;i<=x;i++)
     {
             rndfunc1();
             rndfunc2();
             rndfunc2();
             rndfunc2();
             rcnt++;
             if(rcnt%4==0)
                          random1(2);   
     }
}

void random4(int x)
{
     for(int i=1;i<=x;i++)
     {
             rndfunc1();
             rndfunc2();
             rcnt++;
     }
}

void getdice()
{
     unsigned char c;
     random1(5);
     c=rnda%256;
     c^=rndb;
     c%=6;
     c++;
     die2=c;
     random1(5);
     c=rnda%256;
     c%=6;
     c++;
     die1=c;
}

void cpumove()
{
     rcnt=0;
     random2(40);
     rcnt++;
     random3(23);
     random4(27);
     getdice();
}

//somehow uses random4 this time
void cpumovedouble()
{
     rcnt=0;
     random4(40);
     rcnt++;
     random3(23);
     random4(27);
     getdice();
}

//"glitched" code; not used
void cpumoveab()
{
     rcnt=0;
     random4(1);
     random2(39);
     rcnt++;
     random3(23);
     random4(27);
     getdice();
}

void playermove(int b, int c)
{
     rcnt=0;
     random2(6+b);
     rcnt++;
     random3(2+c);
     random4(27);
     getdice();
}

//uses random4
void playermovedouble(int b, int c)
{
     rcnt=0;
     random4(6+b);
     rcnt++;
     random3(2+c);
     random4(27);
     getdice();
}

void finishturn()
{
     random4(31+(die1+die2)*6);
}

This is a program used to find input delay that produces the correct rolls, subject to 3 degrees of freedom per turn over multiple turns. Originally used to find optimal input for a game, this program has now been abused (in the //quickie section) to find input for one or two turns.

monopolysolve.cc:

#include "monopoly.h"

int a,b,c,ptr=1;

unsigned long rar[40];
unsigned char rbr[10];
int dr[10][3];
int f=0;
//int x[10]={0,5,20,10,150,0}; //delay 31
int x[10]={0,10,43,43,43,0};
unsigned long debug, debug3;
unsigned char debug2, debug4;
long rerecords=0;
char reverttag=0;
int delay=1000;
int ff;
int fg;

int main()
{
    //rnda=0x4BFFE3; //first strat
    //rnda=0x41D723; //ollie strat
    rnda=0x07D580; //starting seeds
    rndb=0x28; //starting seeds
    rar[1]=rnda;
    rbr[1]=rndb;
    initabc();
    drreset();
    
    while (1)
    {
          switch(ptr)
          {
                     case 1: //nd 6 to oriental
                          //random1(3+a);
                          a=-1;
                          playermove(b,c);
                          
                          //quickie
                          
                          if(die2+die1==2 && die1==1) //to get 1+1
                          {printf("%d %d %d", a,b,c); goto br;}
                          trynext();
                          break;
                          
                       /*   a=-1;
                          random2(1+b);
                          random1(32+c);
                          fg=rndb;
                          cpumove();
                          if(die1==die2 && die1!=2); //to get any double except 2+2
                          else {trynext(); break;}
                          ff=die1;
                          finishturn();
                          if(ff==6 || ff==5) random1(114); else if (ff==4) random1(120); else random1(116); //delays for whichever doubles
                          cpumovedouble();
                          if(die1+die2+2*ff==12 && die1!=die2)
                          {printf("%d %d %d %d %d %d %X", a,b,c, ff, die1, die2, fg); goto br;}
                          trynext();
                          break;*/
                          
                          
                          
                          
                          
                          
                          //\quickie
                          
                          if(die1+die2==6 && die1!=3)
                          {
                                          finishturn();
                                          debug=rnda;
                                          save();
                                          initabc();
                                          a=-1;
                                          b=-1;
                          }
                          else
                          {
                              trynext();
                          }
                          break;
                     case 2: //cpu nd 8 to vermont
                          random1(85+c);
                          cpumove();
                          if(die1+die2==8 && die1!=4)
                          {
                                          finishturn();
                                          random1(118);
                                          save();
                                          initabc();
                                          a=-1;
                          }
                          else
                          {
                              trynext();
                          }
                          break;
                     case 3: //3 to connecticut
                          playermove(b,c);
                          if(die1+die2==3)
                          {
                                          finishturn();
                                          //strategy#1 random1(492+350-5);
                                          //random1(524+350-5);
                                          random1(85);
                                          random2(7);
                                          debug3=rnda;
                                          debug4=rndb;
                                          /*2 prop mortgage random1(542);*/
                                          /*1 prop mortgage */ random1(528+8);
                                          //0 prop mortgage random1(524);
                                          //random1(184);

                                          save();
                                          initabc();
                                          a=-1;
                          }
                          else
                          {
                              trynext();
                          }
                          break;
                     case 4: //cpu roll double
                     //goto solution;
                          random2(b);
                          random1(c);
                          debug=rnda;
                          debug2=rndb;
                          random4(1);
                          
                          //strategy#1
                          ////random1(1801);
                          //random1(2279);
                          //random1(2109);
                          
                          //strategy#2
                          //random1(938);
                          random1(1250);
                          //random1(2275);
                          
                          cpumove();
                          if(die1!=die2)
                          {
                                        trynext();
                                        break;
                          }
                          finishturn();
                          
                          f=die1;
                          if(f==1 || f==6) random1(120); else random1(114);
                          cpumovedouble();
                          if(die1!=7-f || die2!=7-f)
                          {
                                           trynext();
                                           break;
                          }
                          finishturn();
                          if(f==1 || f==6) /*random1(987);*/ /*random1(983);*/ random1(234); else{ trynext();break;}//random1(1299);
                          cpumovedouble();
                          if(die1+die2==11) //solution
                          {
                                            save();
                                            if(calcdelay()<=delay)
                                            {
                                                                  delay=calcdelay();
                                                                  //solution:
                                                                  printdelay();
                                            }
                                            //goto br;
                                            revert();
                          }
                          else trynext();
                          
          }
          
          reverttag=0;
          
          if(ptr==0) break;
          //if(dr[1][0]>=1) break;
          
          //printf("%d, %d",die1,die2);
          
    }
    
    
    br:
    
    printf("\n%d rerecords\n", rerecords);
    
    printf("done");
    getchar();
    return 0;
}

void initabc()
{
     a=0;
     b=0;
     c=0;
}

void save()
{
     dr[ptr][0]=a;
     dr[ptr][1]=b;
     dr[ptr][2]=c;
     ptr++;
     rar[ptr]=rnda;
     rbr[ptr]=rndb;
}

void revert()
{
     //printf("sdf");
  /*   dr[ptr][0]=0;
     dr[ptr][1]=0;
     dr[ptr][2]=0;*/
     reverttag=1;
     ptr--;
     if(ptr!=0)
     {
               a=dr[ptr][0];
               b=dr[ptr][1];
               c=dr[ptr][2];
               trynext();
     }
}

void trynext()
{
     if(reverttag==0) rerecords++;
     rnda=rar[ptr];
     rndb=rbr[ptr];
     nextabc();
}

void nextabc()
{
    if(c>=x[ptr] || calcdelay()>delay)
             if(b>=x[ptr] || b==-1 || calcdelay()-c>delay)
                      if(a>=x[ptr] || a==-1 || calcdelay()-c-b>delay)
                               revert();
                      else{c=0; b=0; a++;}
             else{c=0; b++;}
    else c++;
  /*  dr[ptr][0]=a;
    dr[ptr][0]=b;
    dr[ptr][0]=c;*/
  //  if(calcdelay()>delay) revert();
}

void printdelay()
{
     for(int i=1;i<=4;i++)
     {
             for(int j=0;j<=2;j++)
                     if(dr[i][j]==-1) printf("x "); else printf("%d ", dr[i][j]);
             printf("%X %X\n",rar[i]&0xFFFFFF,rbr[i]);
             //if(i==1) printf("%X %X ", debug3&0xFFFFFF, debug4);
     }
     
     printf("%d %X %X     %d\n\n", f,debug&0xFFFFFF,debug2,delay);

}

void drreset()
{
     for(int i=1;i<=4;i++)
             for(int j=0;j<=2;j++)
                     dr[i][j]=0;
}

int calcdelay()
{
     int t=0;
     for(int i=1;i<=ptr-1;i++)
             for(int j=0;j<=2;j++)
                     if(dr[i][j]!=-1)
                                     t+=dr[i][j];
     if(ptr!=5)
     {
               
               if(a!=-1) t+=a; if(b!=-1) t+=b; if(c!=-1) t+=c;
     }
     return t;
}                                

This program searches for endings. Meaning that it searches for a random seed that generates automatic consecutive CPU losses after end of input.

Where the CPU players are is not important a priori. The important part is that a CPU rolls a double into an orange hotel group (St. James), and then 2 to Tennessee or 3 to New York. It is permitted for one CPU (at most) to go from either of these three to the next Chance, since the card is (manipulated to be) go back 3 spaces onto New York.

In other words each CPU must roll a double first, then 2 or 3 second, with at most one exception permitted to roll 4 or 6 second.

The program only searches over the first few RndVal1 (rnda) random values for all 256 values of RndVal2 (rndb). The period of RndVal1 is 2^22-1, or over 4 million, so most values of RndVal1 are impractical.

For manipulating 3 CPUs (6 rolls), there are many short-range solutions. For 4 CPUs (8 rolls), there are very few short-range solutions. No solution has been found for 5 CPUs (10 rolls) within a range of 100000 RndVal1 iterations.

There are two timing versions, one with hurry timing and one with relax timing.

monopolysolve2.cc:

#include "monopoly.h"
#define BEGINSEED 0x3E2AD2
#define SEARCHOFFSET 9000
#define LIMIT 20000
#define PLAYERS 2
//#define HURRY

#ifdef HURRY
unsigned int billtime=120;
#else
unsigned int billtime=464;
#endif


unsigned long c=BEGINSEED,cc,cc2,delay=0;
unsigned int i,f,f2,g,g2,h,h2,j,j2,k,k2,bb,bb2;
unsigned int cnt=0;

int main()
{
    //rnda=BEGINSEED;
    rnda=BEGINSEED;
    random1(SEARCHOFFSET);
    c=rnda;
    
    rnda=c;
    rndb=0;
    
    rcnt=0;
    random2(40);
    rcnt++;
    random3(23);
    random4(27);
            
    cc=rnda;
    bb=rndb;    
    
    random1(10);
    random4(31);
    random1(billtime);

    rcnt=0;
    random4(40);
    rcnt++;
    random3(23);
    random4(27);
    
    cc2=rnda;
    bb2=rndb;
    
    while(delay<=LIMIT)
    {
            delay++;
            
            rnda=c;
            random1(1);
            c=rnda;
            
            rnda=cc;
            random1(1);
            cc=rnda;
            
            rnda=cc2;
            random1(1);
            cc2=rnda;

            

            
            for(i=0;i<=255;i++)
            {
                               cnt=0;
                               
                               rnda=cc;
                               rndb=bb;
                               
                               rndb+=i;
                               getdice();

                               if(die1!=die2) continue;
                               f=die1;

                               rnda=cc2;
                               rndb=bb2;
                               rndb+=i;
                               
                               random4((die1+die2)*6);
                               getdice();
                               if(die1+die2!=3 && die1+die2!=2 && die1+die2!=4 && die1+die2!=6) continue;
                               f2=die1+die2;
                               if(f2==4 || f2==6){ cnt++; random1(114);}
                               //if(die1+die2==2 && f==3) continue;
                               finishturn();
                               random1(439);
                               
                               cpumove();
                               if(die1!=die2) continue;
                               finishturn();
                               g=die1;
                               random1(billtime);
                               cpumovedouble();
                               if(die1+die2!=3 && die1+die2!=2 && die1+die2!=4 && die1+die2!=6) continue;
                               g2=die1+die2;
                               if(g2==4 || g2==6){ cnt++; random1(114);}
                               //if(die1+die2==2 && g==3) continue;
                               finishturn();
                               random1(439);
                               
                               cpumove();
                               if(die1!=die2) continue;
                               finishturn();
                               h=die1;
                               random1(billtime);
                               cpumovedouble();
                               if(die1+die2!=3 && die1+die2!=2 && die1+die2!=4 && die1+die2!=6) continue;
                               h2=die1+die2;
                               if(h2==4 || h2==6){ cnt++; random1(114);}
                               //if(die1+die2==2 && h==3) continue;
                               finishturn();
                               random1(439);

                               cpumove();
                               if(die1!=die2) continue;
                               finishturn();
                               j=die1;
                               random1(billtime);
                               cpumovedouble();
                               if(die1+die2!=3 && die1+die2!=2 && die1+die2!=4 && die1+die2!=6) continue;
                               j2=die1+die2;
                               if(j2==4 || j2==6){ cnt++; random1(114);}
                               //if(die1+die2==2 && h==3) continue;
                               finishturn();
                               random1(439);
                                    /*                                                                                
                               cpumove();
                               if(die1!=die2) continue;
                               finishturn();
                               k=die1;
                               random1(billtime);
                               cpumovedouble();
                               if(die1+die2!=3 && die1+die2!=2 && die1+die2!=4 && die1+die2!=6) continue;
                               k2=die1+die2;
                               if(k2==4 || k2==6){ cnt++; random1(114);}
                               //if(die1+die2==2 && h==3) continue;
                               finishturn();
                               random1(439);
                               */
                               if(cnt>=2) continue;

                               printf("%d%d %d%d %d%d %d%d %d%d %X %X %d\n",f,f2,g,g2,h,h2,j,j2,k,k2,c&0xFFFFFF,i,delay);
            }
            
            if(delay%5000==0)
                              printf("Done delay %d\n",delay);
            
      }

    printf("done");
    getchar();
    return 0;
}


Combined RSS Feed
FractalFusion/Source/Monopoly last edited by FractalFusion on 2008-01-07 07:01:45
Page info and history | Latest diff | List referrers | View Source