Advertisement
Dermotb

Cards 1.0

Mar 17th, 2013
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.00 KB | None | 0 0
  1.  
  2. --# Main
  3. -- Cards
  4.  
  5. -- Use this function to perform your initial setup
  6. function setup()
  7. --b=Backup("Cards v101")
  8. img=readImage("Dropbox:Felix") --image for back of card
  9.  
  10. --=== UNCHECK ONE OF THE NEXT TWO LINES TO GET A DIFFERENT GAME =====
  11. --deal21() --simple version of 21 without betting, doesn't handle things like A being 1 or 11 properly
  12.  
  13. dealPatience() --deal a patience hand. Touching a card shows its value at left. Nothing else yet
  14.  
  15. end
  16.  
  17. --==== PATIENCE ======
  18. function dealPatience()
  19. c=Card(120,img) --small card to fit on screen
  20. --deal cards
  21. t=CardTable(10,HEIGHT-10,c,true,8,1)
  22. p=Pack()
  23. p:shuffle()
  24. for i=1,7 do
  25. for j=1,8-i do
  26. t:dealCard(p,j,i,j==8-i)
  27. end
  28. end
  29. end
  30.  
  31. --this code is just for patience
  32. function touched(touch)
  33. if touch.state==BEGAN then
  34. local crd=t:touched(touch)
  35. if crd~=nil then
  36. if crd=="pack" then
  37. print("Pack")
  38. else
  39. print(c:SuitValue(crd.c))
  40. end
  41. end
  42. end
  43. end
  44.  
  45. --===== 21 ========
  46. function deal21()
  47. parameter.watch("Score")
  48. parameter.watch("bankScore")
  49. parameter.action("Hold", function() playBank() end)
  50. parameter.action("Another card", function() AddMyCard() end)
  51. parameter.action("Play again",function() play21Again() end)
  52. c=Card(200,img) --big cards
  53. t=CardTable(10,HEIGHT-10,c,false,1,2.1)
  54. p=Pack()
  55. p:shuffle()
  56. Score=0
  57. bankScore=0
  58. cards=2
  59. for i=1,2 do
  60. local crd=t:dealCard(p,i,3.2,true) --lay out cards at fractional row intervals to look nice
  61. Score=GetScore(Score,crd)
  62. end
  63. status="PLAY"
  64. end
  65.  
  66. function playBank()
  67. bankCards=2
  68. bankScore=0
  69. for i=1,2 do
  70. local crd=t:dealCard(p,i,1,true)
  71. bankScore=GetScore(bankScore,crd)
  72. end
  73. while bankScore<16 do
  74. bankScore=addBankCard()
  75. end
  76. if bankScore>=Score and bankScore<=21 then status="LOSE" else status ="WIN" end
  77. end
  78.  
  79. function GetScore(score,crd)
  80. local i,j,v,s=c:SuitValue(crd.c)
  81. if v==1 then
  82. if score<=10 then score=score+11 else score=score+1 end
  83. else
  84. score=score+math.min(10,v)
  85. end
  86. return score
  87. end
  88.  
  89. function AddMyCard()
  90. cards = cards + 1
  91. local crd=t:dealCard(p,cards,3.2,true)
  92. Score=GetScore(Score,crd)
  93. if Score>21 then status="LOSE" end
  94. end
  95.  
  96. function addBankCard()
  97. bankCards = bankCards + 1
  98. local crd=t:dealCard(p,bankCards,1,true)
  99. bankScore=GetScore(bankScore,crd)
  100. return bankScore
  101. end
  102.  
  103. function play21Again()
  104. deal21()
  105. end
  106.  
  107. -- This function gets called once every frame
  108. function draw()
  109. background(69, 146, 59, 255)
  110. t:draw()
  111. if status=="LOSE" or status=="WIN" then
  112. pushStyle()
  113. font("Copperplate")
  114. fontSize(48)
  115. fill(255)
  116. text("You "..status.."!",300,50)
  117. popStyle()
  118. end
  119. end
  120.  
  121.  
  122.  
  123. --# Card
  124. Card = class()
  125. --[[
  126. this class builds and draws the card images from scratch and provides some utilities
  127.  
  128. --]]
  129.  
  130. --class initialises by creating card design
  131. --Parameters:
  132. --height of card in pixels
  133. --the image to be used on the back
  134. --background color on the face of the card
  135. --(optional) background color on the back of the card
  136. -- (optional) color along the border ofthe card
  137.  
  138. --returns nothing
  139. function Card:init(height,backImg,faceColor,backColor,borderColor)
  140. self.height = height
  141. self.backImg=backImg
  142. self.f=height/200 --scale font size to card size
  143. self.faceColor=faceColor or color(255)
  144. local x=100 --default border color
  145. self.borderColor=borderColor or color(x, x, x, 255)
  146. x=x*1.5 --corners are drawn with circles which appear darker than lines, so lighten colour for them
  147. self.cornerColor=borderColor or color(x,x,x, 150)
  148. self.backColor=backColor or color(154, 199, 203, 255)
  149. self:createCard()
  150. self:createSuits()
  151. self.value={"A","2","3","4","5","6","7","8","9","10","J","Q","K"}
  152. self.suit={"S","H","D","C"}
  153. end
  154.  
  155. --this and the next function build just the front and back of the card itself
  156. --the main problem is rounded corners
  157. --this is done by drawing circles at the corners and then overlapping rectangles forthe final effect
  158. function Card:createCard()
  159. self.cardFace=self:createOutline(true)
  160. self.cardBack=self:createOutline(false)
  161. end
  162.  
  163. function Card:createOutline(face)
  164. --use standard 25/35 ratio
  165. self.width=math.floor(self.height*25/35+.5)
  166. local img=image(self.width,self.height)
  167. --create rounded corner on top right
  168. local corner=0.05 --distance from end of card as percent of height
  169. local c=math.floor(corner*self.height+0.5)
  170. setContext(img)
  171. pushStyle()
  172. strokeWidth(1)
  173. stroke(self.cornerColor)
  174. if face then fill(self.faceColor) else fill(self.backColor) end
  175. ellipse(self.width-c,self.height-c,c*2)
  176. ellipse(self.width-c,c,c*2)
  177. ellipse(c,self.height-c,c*2)
  178. ellipse(c,c,c*2)
  179. if face then stroke(self.faceColor) else stroke(self.backColor) end
  180. rect(0,c,self.width,self.height-c*2)
  181. rect(c,0,self.width-c*2,self.height)
  182. stroke(self.borderColor)
  183. line(0,c,0,self.height-c)
  184. line(c,0,self.width-c,0)
  185. line(self.width,c,self.width,self.height-c)
  186. line(c,self.height,self.width-c,self.height)
  187. --do picture on back
  188. if face~=true then
  189. sprite(self.backImg,img.width/2,img.height/2,img.width*.9)
  190. end
  191. popStyle()
  192. setContext()
  193. return img
  194. end
  195.  
  196. --the suit images come from emoji
  197. function Card:createSuits()
  198. font("AppleColorEmoji")
  199. self.suits={unicode2UTF8(9824),unicode2UTF8(9829),unicode2UTF8(9830),unicode2UTF8(9827)}
  200. end
  201.  
  202. --draws a card at x,y with value of card (1-52), face=true if face up, a=angle in degrees (default 0)
  203. function Card:draw(x,y,card,face,a)
  204. pushMatrix()
  205. translate(x+self.width/2,y-self.height/2)
  206. if a==nil then a=0 end
  207. rotate(a)
  208. if face then
  209. self:drawDetails(card)
  210. else
  211. sprite(self.cardBack,0,0)
  212. end
  213. popMatrix()
  214. end
  215.  
  216. --draws the pack of cards at x,y (actually just 4 cards but it looks like a pack)
  217. function Card:drawPack(x,y)
  218. for i=1,4 do
  219. local s=(i-1)*3
  220. self:draw(x+s,y-s,1,false)
  221. end
  222. end
  223.  
  224. --draws the numbers and symbols on the front of the card
  225. --one parameter = card value
  226. function Card:drawDetails(card)
  227. sprite(self.cardFace,0,0)
  228. pushStyle()
  229. font("SourceSansPro-Regular")
  230. fontSize(24*self.f)
  231. --calculate suit and value of card
  232. card=card-1
  233. local v=card%13
  234. local s=(card-v)/13+1
  235. v=v+1
  236. local w=self.cardFace.width
  237. local h=self.cardFace.height
  238. if s==1 or s==4 then fill(0,0, 0, 255) else fill(255,0,0,255) end --fill is red or black
  239.  
  240. --half the images on a card are upside down
  241. --so we do them in two loops, turning the card upside down between them
  242. --where the card is not exactly symmetrical, eg for odd numbers, we only draw on the first loop
  243. for i=1,2 do
  244. if i==2 then rotate(180) end --turn 180 degrees to do second loop
  245. local u=self.suits[s]
  246. text(self.value[v],-w*.4,h*.4) --text in corner of card
  247. fontSize(16*self.f)
  248. text(u,-w*.4,h*.28) --suit image
  249. fontSize(28*self.f)
  250. local ss=.13*h
  251. --now all the symbols arranged in the middle of the card
  252. if v==1 then
  253. if i==1 then text(u,0,0) end
  254. elseif v==2 then
  255. text(u,0,.3*h)
  256. elseif v==3 then
  257. if i==1 then text(u,0,0) end
  258. text(u,0,.3*h)
  259. elseif v==4 then
  260. text(u,-w*.18,.3*h)
  261. text(u,w*.18,.3*h)
  262. elseif v==5 then
  263. text(u,-w*.18,.3*h)
  264. text(u,w*.18,.3*h)
  265. if i==1 then text(u,0,0) end
  266. elseif v==6 then
  267. text(u,-w*.18,.3*h)
  268. text(u,w*.18,.3*h)
  269. text(u,-w*.18,0)
  270. elseif v==7 then
  271. text(u,-w*.18,.3*h)
  272. text(u,w*.18,.3*h)
  273. text(u,-w*.18,0)
  274. if i==1 then text(u,0,.15*h) end
  275. elseif v==8 then
  276. text(u,-w*.18,.3*h)
  277. text(u,w*.18,.3*h)
  278. text(u,-w*.18,0)
  279. text(u,0,.15*h)
  280. elseif v==9 then
  281. text(u,-w*.18,.3*h)
  282. text(u,w*.18,.3*h)
  283. if i==1 then text(u,0,0) end
  284. text(u,-w*.18,.1*h)
  285. text(u,w*.18,.1*h)
  286. elseif v==10 then
  287. text(u,-w*.18,.3*h)
  288. text(u,w*.18,.3*h)
  289. text(u,-w*.18,.1*h)
  290. text(u,w*.18,.1*h)
  291. text(u,0,.2*h)
  292. else --royalty
  293. pushStyle()
  294. font("AppleColorEmoji")
  295. fill(255)
  296. fontSize(84*self.f)
  297. if i==1 then
  298. if v==11 then text(unicode2UTF8(128113))
  299. elseif v==12 then text(unicode2UTF8(128120))
  300. else text(unicode2UTF8(128116))
  301. end
  302. end
  303. popStyle()
  304. end
  305. end
  306. popStyle()
  307. end
  308.  
  309. --used by Main and other classes
  310. --given a value 1-52, it returns the value and suit in text and numbers, eg S,J,1,11
  311. function Card:SuitValue(c)
  312. local v=(c-1)%13
  313. local s=(c-1-v)/13+1
  314. v = v + 1
  315. return self.value[v],self.suit[s],v,s
  316. end
  317.  
  318. function unicode2UTF8(u) --needed for emoji
  319. u = math.max(0, math.floor(u)) -- A positive integer
  320. local UTF8
  321. if u < 0x80 then -- less than 8 bits
  322. UTF8 = string.char(u)
  323. elseif u < 0x800 then -- less than 12 bits
  324. local b2 = u % 0x40 + 0x80
  325. local b1 = math.floor(u/0x40) + 0xC0
  326. UTF8 = string.char(b1, b2)
  327. elseif u < 0x10000 then -- less than 16 bits
  328. local b3 = u % 0x40 + 0x80
  329. local b2 = math.floor(u/0x40) % 0x40 + 0x80
  330. local b1 = math.floor(u/0x1000) + 0xE0
  331. UTF8 = string.char(b1, b2, b3)
  332. elseif u < 0x200000 then -- less than 22 bits
  333. local b4 = u % 0x40 + 0x80
  334. local b3 = math.floor(u/0x40) % 0x40 + 0x80
  335. local b2 = math.floor(u/0x1000) % 0x40 + 0x80
  336. local b1 = math.floor(u/0x40000) + 0xF0
  337. UTF8 = string.char(b1, b2, b3, b4)
  338. elseif u < 0x800000 then -- less than 24 bits
  339. local b5 = u % 0x40 + 0x80
  340. local b4 = math.floor(u/0x40) % 0x40 + 0x80
  341. local b3 = math.floor(u/0x1000) % 0x40 + 0x80
  342. local b2 = math.floor(u/0x40000) % 0x40 + 0x80
  343. local b1 = math.floor(u/0x1000000) + 0xF8
  344. UTF8 = string.char(b1, b2, b3, b4, b5)
  345. else
  346. print("Error: Code point too large for Codea's Lua.")
  347. end
  348. return UTF8
  349. end
  350.  
  351.  
  352. --# CardTable
  353. CardTable = class()
  354. --[[
  355. This class handles tabular card games like patience, where all the cards are in columns and rows
  356.  
  357. Most position references are in cols and rows rather than pixels, and they can be fractional
  358. The class has two tables to keep track of cards on the table.
  359. cards - is simply a hash table so we can scroll through all the cards quickly
  360. tableMap - is a table laid out like the table itself, so tableMap[2][3] is the card in col 2, row 3
  361. Currently, what is stored in these tables is a "card" which is an array with
  362. self.counter=unique id (unused)
  363. x,y=actual pixel position
  364. col,row=column and row
  365. c=value of card (1-52)
  366. face=true if face showing
  367.  
  368. --]]
  369.  
  370. --x,y are top left of table
  371. --c is a reference to the card class
  372. --s=whether cards stack (overlay) on each other
  373. --pc,ps are the location of the pack, pc=col, ps=row
  374. function CardTable:init(x,y,c,s,pc,ps)
  375. self.x,self.y = x,y
  376. self.stacked=s
  377. self.card=c
  378. self.margin=4
  379. self.cards={}
  380. self.tableMap={}
  381. self.packCol,self.packRow=pc,ps
  382. self.counter=0
  383. end
  384.  
  385. --deals the next card to col,row, with face=true for face up, false for face down
  386. --returns the card dealt
  387. function CardTable:dealCard(pack,col,row,face)
  388. local c=pack:nextCard()
  389. if c==nil then return nil end
  390. local x=self:colToX(col)
  391. local y=self:rowToY(row)
  392. self.counter = self.counter + 1
  393. local crd={id=self.counter,x=x,y=y,col=col,row=row,c=c,face=face}
  394. table.insert(self.cards,crd)
  395. self:updateTable(crd,"ADD")
  396. return crd
  397. end
  398.  
  399. --tableMap
  400. function CardTable:updateTable(crd,action)
  401. if action=="ADD" then
  402. if self.tableMap[crd.col]==nil then self.tableMap[crd.col]={} end
  403. self.tableMap[crd.col][crd.row]={}
  404. self.tableMap[crd.col][crd.row]=crd
  405. end
  406. end
  407.  
  408. --helper function returns x value from a col reference
  409. --dontStack=true if cards don't overlay
  410. function CardTable:colToX(col,dontStack)
  411. local h
  412. if self.stacked and dontStack~=true then h=self.card.height*.25 else h=self.card.height end
  413. return self.x+(self.card.width+self.margin)*(col-1)
  414. end
  415. --helper function returns y value from a row reference
  416. function CardTable:rowToY(row,dontStack)
  417. local h
  418. if self.stacked and dontStack~=true then h=self.card.height*.25 else h=self.card.height end
  419. return self.y-(h+self.margin)*(row-1)
  420. end
  421.  
  422. --this finds which card is under x,y, very useful for touches on the screen
  423. --it is actually quite difficult to do this when cards overlap, because all the cards in
  424. --a column are truncated except the last one
  425. --however this can be overcome by looking at which card(s) are under x,yn and keeping
  426. --the card that is furthest down (lowest y value)
  427. function CardTable:cardFromXY(x,y)
  428. local w,h=self.card.width,self.card.height
  429. local c
  430. for i,crd in pairs(self.cards) do
  431. if x>=crd.x and x<=crd.x+w and y<=crd.y and y>=crd.y-h then
  432. if c==nil then c=crd elseif c.row<crd.row then c=crd end
  433. end
  434. end
  435. if c==nil then
  436. local px,py=self:colToX(self.packCol,true),self:rowToY(self.packRow,true)
  437. if x>=px and x<=px+w and y<=py and y>=py-h then
  438. c="pack"
  439. end
  440. end
  441. return c
  442. end
  443.  
  444. function CardTable:draw()
  445. for i,card in pairs(self.cards) do
  446. self.card:draw(card.x,card.y,card.c,card.face)
  447. end
  448. if self.packCol~=nil then
  449. local x,y=self:colToX(self.packCol,true),self:rowToY(self.packRow,true)
  450. self.card:drawPack(x,y)
  451. end
  452. end
  453.  
  454. function CardTable:touched(touch)
  455. local crd=self:cardFromXY(touch.x,touch.y)
  456. if crd~=nil then return(crd) else print("Nothing touched") end
  457. end
  458.  
  459.  
  460. --# Pack
  461. Pack = class()
  462. --[[
  463. Manages a pack of cards
  464. Functions:
  465.  
  466. shuffle - shuffles the pack
  467.  
  468. nextCard - returns the next card in the pack
  469. --]]
  470.  
  471. function Pack:init(p)
  472. self.pack={}
  473. self:shuffle()
  474. end
  475.  
  476. function Pack:shuffle()
  477. self.pack={}
  478. local t={}
  479. for i=1,52 do t[i]=i end
  480. for i=1,52 do
  481. local x=math.random(1,53-i)
  482. self.pack[i]=t[x]
  483. t[x]=53-i
  484. end
  485. return self.pack
  486. end
  487.  
  488. function Pack:nextCard()
  489. if #self.pack==0 then return nil end
  490. local c=self.pack[1]
  491. table.remove(self.pack,1)
  492. return c
  493. end
  494.  
  495.  
  496. --# Ideas
  497.  
  498. --[[
  499.  
  500. flip card over
  501. remove card
  502. move x layered cards
  503. fan cards like poker hand
  504. n packs or infinite pack, eg casino
  505. manage discard pile
  506.  
  507. --]]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement