debug version monopoly, feel free to finish it; the last version is available here
_N='Get out of jail' _M='Advance to Go' _L='Free from jail' _K='Go to jail!' _J='hyp' _I='code' _H='case' _G='Chance' _F='Community Chest' _E='name' _D='money' _C='terrains' _B=False _A=True from kandinsky import fill_rect as rect,draw_string as txt,set_pixel as pix from random import randint,choice from ion import keydown as k import time SKY=0,0,0 TXT=(255,)*3 IMP=0,0,255 SEL=255,255,0 PC=[(200,0,200),(0,255,255),(255,0,255),(255,200,0),(255,0,0),(255,255,0),(0,150,0),(0,0,255)] savefile='monopoly.sav' CASES=[['Start',1,20],['Mediterranean Ave',0,0,0,6,.2,1,3,9,16,25],[_F,5],['Baltic Avenue',0,1,0,6,.4,2,6,18,32,45],['Income Tax',1,-20],['Reading RR',0,22,1,20,2.5],['Oriental Avenue',0,2,1,10,.6,3,9,27,40,55],[_G,4],['Vermont Avenue',0,3,1,10,.6,3,9,27,40,55],['Connecticut Ave',0,4,1,12,.8,4,10,30,45,60],['Jail',6],['St Charles Place',0,5,2,14,1,5,15,45,62.5,75],['Electric Company',0,26,5,15],['States Avenue',0,6,2,14,1,5,15,45,62.5,75],['Virginia Avenue',0,7,2,16,1.2,6,18,50,70,90],['Pennsylvania RR',0,23,1,20,2.5],['St. James Place',0,8,3,18,1.4,7,20,55,75,95],[_F,5],['Tennessee Avenue',0,9,3,18,1.4,7,20,55,75,95],['New York Avenue',0,10,3,20,1.6,8,22,60,80,100],['Free Parking',8],['Kentucky Avenue',0,11,4,22,1.8,9,25,70,87.5,105],[_G,4],['Indiana Avenue',0,12,4,22,1.8,9,25,70,87.5,105],['Illinois Avenue',0,13,4,24,2,10,30,75,92.5,110],['B&O RR',0,24,1,20,2.5],['Atlantic Avenue',0,14,5,26,2.2,11,33,80,97.5,115],['Ventnor Avenue',0,15,5,26,2.2,11,33,80,97.5,115],['Water Works',0,27,5,15],['Marvin Gardens',0,16,5,28,2.4,12,36,85,102.5,120],['Go to Jail',7],['Pacific Avenue',0,17,6,30,2.6,13,39,90,110,127.5],['North Carolina Ave',0,18,6,30,2.6,13,39,90,110,127.5],[_F,5],['Pennsylvania Ave',0,19,6,32,2.8,15,45,100,120,140],['Short Line',0,25,1,20,2.5],[_G,4],['Park Place',0,20,7,35,3.5,17.5,50,110,130,150],['Luxury Tax',1,-10],['Boardwalk',0,21,7,40,5,20,60,140,170,200]] CHANCES=[[[_K],5],[[_L],0],[['Advance to Boardwalk'],2,21],[[_M],2,0],[['Advance to Illinois Ave'],2,19],[['Advance to St. Charles'],2,5],[['Bank pays you'],1,5],[[_N],0],[['Go back 3 spaces'],4],[['Go to Reading RR'],2,22],[['Make repairs'],3,[2.5,10]],[['Pay poor tax'],1,-15],[['Trip to Pennsylvania RR'],2,24],[['Building loan matures'],1,15],[['Win crossword contest'],1,10]] CHESTS=[[[_K],5],[[_L],0],[[_M],2,0],[['Bank error, collect'],1,20],[['Doctor fees, pay'],1,-10],[['Stock sale, get'],1,5],[[_N],0],[['Grand Opera Night'],1,5],[['Holiday fund matures'],1,10],[['Tax refund, collect'],1,2],[['Birthday, collect'],6,1],[['Life insurance matures'],1,10],[['Pay hospital fees'],1,-10],[['Pay school fees'],1,-5],[['Consultancy fee'],1,25],[['You inherit'],1,10]] def shuffle(l): n=len(l) for i in range(len(l)-1,0,-1):j=randint(0,i);l[i],l[j]=l[j],l[i] return l try:import os;OS=_A except:OS=_B clean=lambda:rect(0,0,320,222,SKY) txtc=lambda t,y,fc,bc:txt(t,160-len(t)*5,y,fc,bc) s=lambda:k(0)|k(1)|k(2)|k(3) v=lambda:k(4)|k(52) def popup(x,y,w,h,xso,yso,c,title,opt,types,result=[],frame=_A,padding=2,back=_B,retname=_B): if frame:rect(x,y,w,h,c[0]);rect(x+3,y+3,w-6,h-6,SKY);y+=2 else:rect(x,y,w,h,SKY) for(i,j)in enumerate(title):txtc(j,y+2+(18+padding)*i,c[1],SKY) ntv=_B for(i,o)in enumerate(opt): txt(o,xso,yso+(18+padding)*i,c[2],SKY) if types[i][0]==0:switch(types[i][1],yso+(18+padding)*i,result[i]);ntv=_A elif types[i][0]==1:rect(types[i][1],yso+(18+padding)*i+17,10*types[i][2],1,IMP);ntv=_A elif types[i][0]==2:txt('< >',types[i][1]-20,yso+(18+padding)*i,IMP,SKY) if ntv:txt('VALIDATE',xso,yso+(18+padding)*(i+1),(0,255,0),SKY);types.append([3]) r=0;first=_A;lastAct=-1 while v():0 while 1: if s()|first: lastAct=r;r=(r-k(1)+k(2))%len(types) if types[r][0]==2:result[r]=(result[r]-k(0)+k(3))%(types[r][3]-types[r][2]+1);txt(str(result[r]+types[r][2]),types[r][1],yso+(18+padding)*r,IMP,SKY) rect(xso-20,yso+(18+padding)*lastAct,10,18,SKY);txt('→',xso-20,yso+(18+padding)*r,SEL,SKY) if first:first=_B while s():0 elif v(): if not ntv: if retname:return opt[r] return r if types[r][0]==0: result[r]=not result[r];switch(types[r][1],yso+(18+padding)*r,result[r]) while v():0 elif types[r][0]==1:result[r]=kinput(types[r][1],yso+(18+padding)*r,types[r][2],types[r][3],types[r][4]) elif types[r][0]==3: if retname:return opt[r] return tuple(result) elif k(17)&back:return-1 def switch(x,y,on): rect(x,y,18,18,(200,)*3);rect(x+1,y+1,16,16,SKY) if on:c=0,255,0 else:c=(100,)*3 rect(x+3,y+3,12,12,c) def kinput(x,y,maxLenght=4,minLenght=4,onlynumbers=_A,ct=TXT): letters={29:'l',30:'m',31:'n',32:'o',33:'p',34:'q',36:'r',37:'s',38:'t',39:'u',40:'v',42:'w',43:'x',44:'y',45:'z',18:'a',19:'b',20:'c',21:'d',22:'e',23:'f',24:'g',25:'h',26:'i',27:'j',28:'k'};numbers={30:'7',31:'8',32:'9',42:'1',43:'2',44:'3',36:'4',37:'5',38:'6',48:'0'};Input='';rect(x,y,10*maxLenght,18,SKY);rect(x,y+17,10*maxLenght,1,IMP);rect(x,y+2,1,14,TXT) while v():0 while 1: for i in range(17,49): if k(i): if onlynumbers: if(i in numbers.keys())&(len(Input)<maxLenght):Input+=numbers[i] elif(i in letters.keys())&(len(Input)<maxLenght):Input+=letters[i] if(i==17)&(len(Input)>0):Input=Input[:-1];rect(x+len(Input)*10,y,12,18,SKY) rect(x,y+17,10*maxLenght,1,IMP);rect(x+len(Input)*10+1,y+2,1,14,TXT);txt(Input,x,y,ct,SKY) while k(i):0 if v(): if len(Input)>=minLenght:rect(x+len(Input)*10+1,y+2,1,14,SKY);return Input else:txt(Input,x,y,(255,0,0),SKY);time.sleep(.5);txt(Input,x,y,ct,SKY) def draw_case(x,y,id,rot=0): t=CASES[id][1];rect(x,y,20,20,TXT);rect(x+1,y+1,18,18,SKY) if t==0: if 21<CASES[id][2]<26:rect(x+2,y+2,16,16,(50,)*3);rect(x+4,y+4,12,12,SKY);rect(x+6,y+6,8,8,(50,)*3) elif CASES[id][2]>25: if CASES[id][2]==0:c=0,0,200 else:c=SEL txt('S',x+5,y+1,c,SKY) else: xs1,ys1,w1,h1,xs2,ys2,w2,h2=x+1,y+1,18,5,x+1,y+7,18,12 if rot==1:xs1,w1,h1,ys2,w2,h2=x+14,5,18,y+1,12,18 elif rot==2:ys1,ys2=y+14,y+1 elif rot==3:w1,h1,xs2,ys2,w2,h2=5,18,x+7,y+1,12,18 rect(xs1,ys1,w1,h1,PC[CASES[id][3]]) for i in range(N): if id in A[i][_C]:rect(xs2,ys2,w2,h2,PC[i]) if 0<A[-2][CASES[id][2]]<5: xi,yi=0,0 if w1>h1:xi=4 else:yi=4 for i in range(A[-2][CASES[id][2]]):rect(xs1+1+xi*i,ys1+1+yi*i,3,3,SKY) elif A[-2][CASES[id][2]]==5:rect(xs1+1,ys1+1,3,3,TXT) elif t==1: if CASES[id][2]>0:c=0,200,0 else:c=200,0,0 rect(x+2,y+2,16,16,c) elif 3<t<6: if t==4:c=0,0,255 else:c=255,0,0 txt('C',x+5,y+1,c,SKY) elif t==6:rect(x+1,y+1,18,18,(255,100,0));rect(x+1,y+7,12,12,(70,)*3) elif t==7:rect(x+3,y+3,14,14,(255,100,0)) elif t==8:rect(x+2,y+2,16,16,(0,255,0));rect(x+4,y+4,12,12,(0,180,0)) np=[] for i in range(N): if A[i][_H]==id:np.append(i) if len(np)>0: rect(x+5,y+7,10,6,SKY) for _ in range(2): for __ in range(4): if _*4+__ in np:rect(x+6+__*2,y+8+_*2,2,2,PC[_*4+__]) def menu(): global A;clean();c=0 if OS: if savefile in os.listdir(): c=popup(0,0,320,222,135,150,[PC[0],PC[3],IMP],['Savefile found!','Do you want to','continue the game?'],['YES','NO'],[[3],[3]]) if c==0: with open(savefile,'r')as f: A=eval(f.read()) if _I in A[0].keys():Password=_A else:Password=_B return len(A)-6,Password,_A opt=['Number of players:','Password protection:'];types=[[2,260,2,8],[0,260]] if OS:opt.append('Enable saving:');types.append([0,260]) params=popup(0,0,320,222,30,70,[PC[1],PC[3],IMP],['MONOPOLY - Made by Elnix'],opt,types,[0,_B,_B],padding=22);N=params[0]+2;A=[{_E:'',_D:150000,_C:[],_J:[],_H:0,'free':_B}for i in range(N)] for i in range(N): clean();txt('Player '+str(i+1),30,20,PC[i],SKY);txt(', enter your name:',110,20,TXT,SKY);A[i][_E]=kinput(110,70,10,_B) if params[1]: txt('Please set a up a pin code:',25,110,TXT,SKY) while 1: code=kinput(140,140) if len(code)<4:txt('Too short!',110,170,(255,0,0),SKY) else:A[i][_I]=code;break A.append([33,11]);A.append(shuffle([i for i in range(18)]));A.append(shuffle([i for i in range(18)]));A.append([i for i in range(22)]);A.append([0 for i in range(22)]);A.append(0);return N,params[1],params[2] def getHousePrice(id): if id<10:return 5000 elif id<20:return 10000 elif id<30:return 15000 else:return 20000 def draw_terrain(): id=0 for i in range(10):draw_case(1+i*20,1,id,0);id+=1 for i in range(10):draw_case(201,1+i*20,id,1);id+=1 for i in range(10):draw_case(201-i*20,201,id,2);id+=1 for i in range(10):draw_case(1,201-i*20,id,3);id+=1 txt('Total in',70,50,IMP,SKY);txt('Free park:',60,70,IMP,SKY);txt(str(A[-1]),110-len(str(A[-1]))*5,90,IMP,SKY) def calc_rent(id,All=_B,owner=None): global DR;p=[5000,2500,5000,10000,20000] if CASES[id][2]<26: if All: if CASES[id][2]<22:return CASES[id][4:] return p elif CASES[id][2]<22:return CASES[id][4+A[-2][CASES[id][2]]] else: nbts=0 for i in range(22,26): if i in A[owner][_C]:nbts+=1 return p[nbts+1] else: if All:return nbs=0 if 28 in A[owner][_C]:nbs+=1 if 27 in A[owner][_C]:nbs+=1 if nbs==1:return 400*DR return 1000*DR def draw_rent(x,y,id): r=calc_rent(id,_A) if CASES[id][2]<26: for(i,j)in enumerate(r): if i==0:txt('Base Price:',x,y,TXT,SKY) if CASES[id][2]<22: if i==1:txt('Terrain:',x,y+20,TXT,SKY) elif i==6:txt('Hotel:',x,y+120,TXT,SKY) elif i>0:txt(str(i-1)+' houses',x,y+20*i,TXT,SKY) txt(str(j),x+120,y+20*i,PC[4],SKY) else: if i>0:txt(str(i)+' stations:',x,y+20*i,TXT,SKY) txt(str(j),x+120,y+20*i,PC[4],SKY) else:txt('1 serv: 400*Dices',x,y,TXT,SKY);txt('2 serv: 1000*Dices',x,y+20,TXT,SKY) def selectP(l): clean();txtc('Select a propriety:',10,IMP,SKY);act=0;first=_A while v():0 while not v(): if s()|first: act=(act-k(0)+k(3))%len(l);clean();rect(0,40,320,18,SKY);txtc('< '+CASES[l[act]][0]+' >',40,TXT,SKY);draw_case(20,100,l[act]);draw_rent(110,75,l[act]) if first:first=_B while s():0 elif k(17):return-1 return l[act] def drawC(P,t): clean() if t:id=-5;txtc('CHANCE',10,IMP,SKY) else:id=-4;txtc('COMMUNITY CHEST',10,IMP,SKY) for(i,j)in enumerate(CHANCES[A[id][0]][0]):txtc(j,35+i*20,TXT,SKY) c=A[id][0][1] if c==0:A[P]['free']=_A elif c==1: if t:amount=CHANCES[A[-5][0]][2] else:amount=CHESTS[A[-4][0]][2] if amount>0:A[P][_D]+=amount else:pay(P,-1,amount,_A) elif c==2:0 elif c==3: nbhouses=0;nbhotels=0 for i in A[P][_C]: n=A[-2][CASES[i][2]] if 0<n<5:nbhouses+=n else:nbhotels=+n amount=nbhouses*CHANCES[A[-5][0]][2]+nbhotels*CHANCES[A[-5][0]][3];rp=pay(P,-1,amount) elif c==4:0 elif c==5:0 if c:A[id].append(A[id][0]) del[id][0];return rp def pay(p,r,amount,middle=_B,canCancel=_B): C='Mortgage';B='Sell houses' while A[p][_D]<amount: opt=[];houses={} for i in A[p][_C]: if CASES[i][2]<22:houses[i]=A[-2][CASES[i][2]] else:houses[i]=0 if sum(houses.values())>0:opt.append(B) if 0 in houses.values():opt.append(C) if len(opt)==0: if lose(p):return 1 else:return 2 code=popup(10,10,300,202,40,90,[PC[4],PC[4],IMP],['Warning! Not enough money!','Your money: '+str(A[p][_D]),'To pay: '+str(amount)],opt,[[3]for i in range(len(opt))],back=canCancel,retname=_A) if code==B: htcbs=[i for(i,j)in houses.items()if j>0];s=selectP(htcbs) if s==-1:continue else:A[-2][CASES[s][2]]-=1;A[p][_D]+=getHousePrice(s)//2;continue elif code==C: htcbs=[i for(i,j)in houses.items()if j==0];s=selectP(htcbs) if s==-1:continue else:A[p][_C].remove(s);A[p][_J].append(s);A[p][_D]+=CASES[s][4]//2 else:return-1 A[p][_D]-=amount if middle:A[-1]+=amount if r!=-1:A[r][_D]+=amount return 0 def lose(p): global N;N-=1 for i in A[p][_J]:A[-3].append(i) rect(20,20,280,182,PC[p]);rect(23,23,274,176,SKY) if N>1:txtc(A[p][_E]+' lose!',70,PC[p],SKY);txtc('BUT THE GAME CONTINUE!',110,TXT,SKY) del A[p] if N==1: txtc('Congrat to '+A[0][_E],70,PC[p],SKY);txtc('For winning this game!',110,TXT,SKY) while v():0 while not v():0 return _B else: while v():0 while not v():0 return _A def drawDice(x,y,n):rect(x,y,20,20,TXT);rect(x+1,y+1,18,18,SKY);txt(str(n),x+5,y+1,PC[5],SKY) def game(): B='You have to pay';global N,DR;N,Password,Save=menu();T=randint(0,N-1);DR=randint(1,6)+randint(1,6);clean();A[0][_C].append(1);A[0][_C].append(3);A[0][_C].append(5);A[0][_C].append(6);A[0][_C].append(12) for i in range(22):A[-2][i]=randint(1,5) draw_terrain();print(pay(0,1,9899999,canCancel=_A)) while 1: if Password: clean();txtc(A[T][_E]+', enter your password:') while int(kinput(140,110))!=A[T][_I]:txtc('Wrong password, retry in 3s...',130,PC[4],SKY) wasRewarded=0;d1,d2=randint(1,6),randint(1,6);t=time.monotonic() while time.monotonic()-t<.2:drawDice(80,150,randint(1,6));drawDice(120,150,randint(1,6)) drawDice(80,150,d1);drawDice(120,150,d2);DR=d1+d2 while time.monotonic()-t<.2:0 for i in range(DR): t=time.monotonic();cid=(cid+1)%40 if cid==0:wasRewarded=20000 draw_terrain() while time.monotonic()-t<.2:0 if cid==0:wasRewarded=40000;A[T][_D]+=20000 clean();cid=A[T][_H];a=CASES[cid][1];txt('Landed on '+CASES[cid][0],5,5,TXT,SKY) if wasRewarded:txtc('You were rewarded by '+str(wasRewarded),202,(0,255,0),SKY) draw_case(cid,295,10);draw_rent(110,60) if a==0: if cid in A[-3]: c=popup(-1,30,0,0,20,140,[0,(0,255,0),IMP],['Want you buy this propriety?','Price:'+str(CASES[cid][4])],['YES','NO'],[[3],[3]],frame=_B) if c==0:A[-3].remove(cid);A[T][_C].append(cid) elif cid not in A[T][_C]: for i in range(N): if cid in A[i][_C]:break amount=calc_rent(cid,owner=i);txtc(B+A[i][_E],30,(255,150,0),SKY);txtc(str(amount),50,(255,150,0),SKY) while v():0 while not v():0 rp=pay(T,i,amount) if rp!=0:continue elif a==1: amount=CASES[cid][2] if amount>0:txtc('You have been rewarded by',30,IMP,SKY);txtc(str(amount),50,(0,255,0),SKY);A[T][_D]+=amount else: txtc(B,30,IMP,SKY);txtc(str(amount),50,(255,0,0),SKY);rp=pay(T,-1,amount,_A) if rp!=0:continue elif 4:txtc('You draw a chance',30,IMP,SKY);drawC(1) elif 5:txtc('You draw a community chest',30,IMP,SKY);drawC(0) elif a==6:0 elif a==7:0 elif a==8:0 if Save: with open(savefile,'w')as f:f.write(str(A)) T=(T+1)%N if OS:os.remove(savefile) while 1:game()