Omnimaga
Calculator Community => Other Calc-Related Projects and Ideas => TI-Nspire => Topic started by: epic7 on January 06, 2012, 07:24:19 pm
-
I'm making mancala and in color for my first lua project :w00t:
I've got about 100 lines done so far, but I don't have any screenshots because I haven't made the game board since I heard ti image is extremely slow, and I fail at using drawing with drawRect, drawArc, etc.
Here it is on wikipedia if you're unfamiliar with the game. (http://en.wikipedia.org/wiki/Kalah)
I just started yesterday, so there isn't that much to post about it yet :P
Once I'm able to find a way to make the game board, I'll add some screenies of The Game :)
-
FillRect/FillArc isn't that hard. You just have to keep on trying different stuff on the emulator. Good luck on the project!
-
I'll just spend the night testing random stuff hopefully to some success :P
-
Good luck Epic! wow first lua game! Fun stuff :) Can't wait to see it in action!
-
THank you SO MUCH epic7 I LOVVVVVVEEEEEEEEEEE Mancala
-
Ok, I started making the mancala board. Here what it's looking like so far:
(http://i.pgu.me/tdZVjxpH_original.jpg)
-
cool, this will be fun, even though ive only played it once or twice :p
-
can I have a demo?
-
looks good epic7, seems that you managed to get every rect/arc on its place :)
and the colors are quite realistic, i like it
-
Great :)
Don't forget to share your code so we can help you on it if you have troubles or if we think you can optimize it :)
-
Good job, epic7! The boring testing is what you have to do sometimes. :P
-
Here all the rules, do these sound good?
1.At the beginning of the game, three seeds are placed in each house.
2.Each player controls the six houses and their seeds on his side of the board. His score is the number of seeds in the store to his right.
3.Players take turns sowing their seeds. On a turn, the player removes all seeds from one of the houses under his control. Moving counter-clockwise, the player drops one seed in each house in turn, including the player's own store but not his opponent's.
4.If the last sown seed lands in the player's store, the player gets an additional move. There is no limit on the number of moves a player can make in his turn.
5.If the last sown seed lands in an empty house owned by the player, and the opposite house contains seeds, both the last seed and the opposite seeds are captured and placed into the player's store.
6.When one player no longer has any seeds in any of his houses, the game ends. The other player moves all remaining seeds to his store, and the player with the most seeds in his store wins.
Should I keep rule 6? Rule 6 is sometimes not used in mancala.
-
I've personally never played with rule 5, but if that's official, then that'd probably be a good idea. I think rule 6 is probably good.
-
Actually, I've never played with rule 5 either. A variation wiki lists is to only capture the one seed that landed in the empty house.
-
I use rule 5
-
Hmm... Should I make a poll or just keep all the rules that are there?
-
Take a poll on taking a poll. ;D I think just keeping the rules should be fine.
-
Ya I'll keep them, and probably add an optioins menu :D
-
I'd have 2 player mode somewhat close to finished if it wasn't for errors...
Here is in the beginning
for a=1, 14 do
for b=1, 3 do
if a~=7 and a~=14 then
coord[a*3+b*3-5]=a
coord[a*3+b*3-4]=math.random(0,16)
coord[a*3+b*3-3]=math.random(0,14)
else
coord[a*3+b*3-5]=a
--coord[a*3+b*3-4] and coord[a*3+b*3-3 will be nil.
end
end
end
And here is where the error occurs
for a=1, 42 do
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
if coord[a*3-2]>7 then
gc:fillArc(coord[a*3-2]*38+coord[a*3-1],coord[a*3]+49,10,10,0,360)
-- (above) attempt to index global 'coord' (a nil value)
else
gc:fillArc(coord[a*3-2]*38+coord[a*3-1],coord[a*3]+141,10,10,0,360)
end
-- moar stuffs
Coord shouldn't be nil. The only times there will be a nil value in that is supposed to be only when coord[a*3-2] is equal to 7 or 14. That shouldn't happen because it is under
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
Unless coord[a*3+b*3-5] (from first code) isn't the same as coord[a*3-2]...
-
You may need a line to initialize coord as a table before you can index it in the for loops.
Try adding this at the beginning:
coord = {}
Hopefully an easy fix. :)
-
I already have that D:
-
Hmmm... That's usually the problem with "attempt to index global 'coord' (a nil value)."
If everything is spelled and capitalized correctly and the coord = {} is in the correct spot then the error might be in a different part of the code.
Is coord defined in a function? If so, on.paint may be called before coord is initialized.
-
Its defined inside on.create()
-
Are there any local coord variables?
-
I don't really know what that means.. So Im gonna say no :P
-
I always have problems with on.create(). I never use it, but I think it's just my fault.
-
I noticed that some values in the coord table are being overwritten. Like when a=1 and b=2 coord[4]==1 but when a=2 and b=1 coord[4]==2.
I'm running out of ideas for what is causing this error without seeing more code.
Local variables are variables that are initialized with the word local in front of them. They only last until the end of the block they are created in. They can share the name of global variables. A description of this can be found here: http://www.lua.org/pil/4.2.html
-
@cyan Idk, Nick edited a basic program of mine and added on create. I just assumed that was the right way :p
@3ric I guess that means I don't have any local vars. And with the overwriting, you're probably right :o
-
it doesn't really amtter if it's in on.create(), it doesn't have to be there, if you just initialize it it should be working..
the only reason for failure here might be that the value you try to create, the coord[a*3-2] or any other assignment, doesn't exist in the table itself.
The first time you do the loop, a is 1, so you get coord[1], but if this hasn't been initialized before, it has no value, and you cannot read/write to it..
if you want to add a value to a table, you have to use table.insert(tablename, position) to add it
-
I'd have 2 player mode somewhat close to finished if it wasn't for errors...
Here is in the beginning
for a=1, 14 do
for b=1, 3 do
if a~=7 and a~=14 then
coord[a*3+b*3-5]=a
coord[a*3+b*3-4]=math.random(0,16)
coord[a*3+b*3-3]=math.random(0,14)
else
coord[a*3+b*3-5]=a
--coord[a*3+b*3-4] and coord[a*3+b*3-3 will be nil.
end
end
end
And here is where the error occurs
for a=1, 42 do
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
if coord[a*3-2]>7 then
gc:fillArc(coord[a*3-2]*38+coord[a*3-1],coord[a*3]+49,10,10,0,360)
-- (above) attempt to index global 'coord' (a nil value)
else
gc:fillArc(coord[a*3-2]*38+coord[a*3-1],coord[a*3]+141,10,10,0,360)
end
-- moar stuffs
Coord shouldn't be nil. The only times there will be a nil value in that is supposed to be only when coord[a*3-2] is equal to 7 or 14. That shouldn't happen because it is under
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
Unless coord[a*3+b*3-5] (from first code) isn't the same as coord[a*3-2]...
Looks to me that on the first section of the code, you're populating what's inside coord[] more than once in several cases, so you might end with a lower size of an array than you wanted (e.g. when a=2 & b=1 you get on line 4 of the code the same as if a=1 & b=2)
Have you tried initializing the array like this?
coord = {}
for i=1, 128 do coord[i]=0 end
The 128 is because 128 > (14*3*3)
So, I think the correct formula should be:
for a=1, 14 do
for b=1, 3 do
if a%7 ~= 0 then
coord[9*(a-1)+3*(b-1)+1] = a
coord[9*(a-1)+3*(b-1)+2] = math.random(0,16)
coord[9*(a-1)+3*(b-1)+3] = math.random(0,14)
else
coord[9*(a-1)+3*(b-1)+1] = a
end
end
end
-
My intent wasn't to overwrite some things in the table. I think what you have is right.
I changed it to multiply a by 9 rather than 3, but still I get an error.
And nick, does that mean that something like
blah={}
blah[1]=1347
won't work? ???
-
yep, correct..
for that you have to do table.insert(blah,1,1347)
-
I made a test program without table insert and it still worked.
Also, it gets through writing to coord, and the error isn't until it reads from coord.
-
blah = {}
blah[1] = 1234
That code with work. I use it in my Hangman program.
I would try just removing the on.create function and just initializing all the variables in front of the rest of the program. I don't know if it'll work, but it doesn't hurt to try.
-
Looked through the code a bit more and edited a couple things
function on.create()
coord = {}
for a=1, 14 do
for b=1, 3 do
if a~=7 and a~=14 then
coord[a*9+b*3-11]=a --Changed all the 3s in front of the as to 9s also changed the 5, 4, and 3 to 11, 10, and 9 so that it would still start at coord[1]
coord[a*9+b*3-10]=math.random(0,16)
coord[a*9+b*3-9]=math.random(0,14)
else
coord[a*9+b*3-11]=a
end
end
end
end
function on.paint(gc)
for a=1, 42 do
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
if coord[a*3-2]>7 then
gc:fillArc((coord[a*3-2]-7)*38+coord[a*3-1],coord[a*3]+49,10,10,0,360) --subtracted 7 from coord[a*3-2] to line up the pieces
else
gc:fillArc(coord[a*3-2]*38+coord[a*3-1],coord[a*3]+141,10,10,0,360)
end
end
end
end
Using this code, I got the screenshot below. I made a couple extra tweaks to the numbers so that the pieces would line up.
As for adding things to tables, as long as the table has been initialized with a table constructor, any valid key can be paired with any valid value.
example = {}
example[1] = 1
example[1337] = 3.141592
example["The Game"] = on.paint
example[on.create] = "Never Gonna Give You Up"
example[true] = false
example.Omnimaga = {1, 2, 3, 4} --Same as example["Omnimaga"] = {1, 2, 3, 4}
Be wary though, #example ~= 1337 until example[2] through example[1336] have non-nil values
-
That was the pieces generating code! That looks pretty nice, I don't know about on.create, but personally I never use it. :P
-
@3rik
Why is the order of the variables before the letters? In Math you always see that constants go before variables, so that's a little confusing for me...
I prefer to make the code more readable, so IMO this is better:
function on.create()
local array=0
coord = {}
for a=1, 14 do
for b=1, 3 do
array = a*9+b*3-11
if a~=7 and a~=14 then
coord[array]=a
coord[array+1]=math.random(0,16)
coord[array+2]=math.random(0,14)
else
coord[array]=a
end
end
end
end
function on.paint(gc)
local array=0
for a=1, 42 do
array = a*3-2
if coord[array]~=7 and coord[array]~=14 then
if coord[array]>7 then
paintSeeds(gc,(coord[array]-7)*38+coord[array+1],coord[array+2]+ 49,10,10,0,360)
else
paintSeeds(gc,(coord[array]-0)*38+coord[array+1],coord[array+2]+141,10,10,0,360)
end
end
end
end
function paintSeeds(GC, x, y, width, height, startAngle, angle)
GC:setColorRGB(0, 0, 0) --change colors as pleased
GC:drawArc(x-1, y-1, width+1, height+1, startAngle, angle)
GC:setColorRGB(128,128,128) --change colors as pleased
GC:fillArc(x, y, width, height, startAngle, angle)
end
I've never played this game, so I want to see it soon :)
-
I still get the same error with 3ric's edits D:
Even though the a*9 was a something I did really need to add :D
It says
(http://img.removedfromgame.com/imgs/01-13-2012 Image001.jpg)
Line 43 is
if coord[a*3-2]~=7 and coord[a*3-2]~=14 then
Unless the "43:" means something else...
(entire code if anybody can spot anything) (http://willyou.typewith.me/p/Mancala%20Code)
-
As soon as I removed the on.create, it worked for me, screenie:
Just try putting all the information in on.create and move it outside. Please just try it...
-
Oh it works O.O
Thanks!
Now the coordinate range needs a bit of adjusting :P
Edit: Now they're aligned!
Also on the enter key function it says "stack overflow" What does that mean?"
Edit: I know now and what the problem is
And also, is there an easy way to add something to the end of the table and count the number of things in a table?
-
@someone I'd agree that that code looks neater. I was just being lazy and I only made the minimum amount of changes from epic7's code.
@ epic7 and cyanophycean314 I see that you're testing the program in oclua. By the time you paste the code in the program, the event on.create() has already been called so coord was never initialized.
-
Oh, is on create called once oclua opens up, not the pasted code?
/me goes to fix an error that he calls "function ping-pong" :P
-
And also, is there an easy way to add something to the end of the table and count the number of things in a table?
There are a few ways of determining the length of a table.
The most obvious way is using the operator #. It basically starts at 1 and keeps adding 1 until it reaches a nil value. If there are any holes in your table this will give a smaller value.
Another way to get a length is to use table.maxn(). It returns the key with the highest value. In my previous example #example == 1 but table.maxn(example) == 1337. This can also handle decimal numbers in the keys.
One way to count all the elements in a table would be to use a function like this:
function length(example)
local index = 0
for _, __ in pairs(example)
index = index + 1
end
return index
end
This will count every element in the table (except nil values, of course). I'll bet this way will be quite slow as the number of elements increases.
If you wanted to add signal to show the end you could do something like this:
stuffs = {1, 3, 5, 3, nil, "end"}
function length2(example)
local index = 1
while example[index] ~= "end" do
index = index + 1
end
return index - 1
end
length2(stuffs) would return 5. However, in order to place the "end" into the table, you would have had to know where to put it and if you add or take away any elements you would have to adjust where "end" goes.
-
And also, is there an easy way to add something to the end of the table and count the number of things in a table?
Yeah, table.insert() and the # operator.
-
table.getn(tablename) is also a good way to retrieve the number of items in a table in some cases of non-standard (?) (or just customized key/objects) tables. Indeed, for some multi-types tables, # won't get the right number...
-
Cool!
How much has to happen in order to get a stack overflow?
Its in an area where some functions call each other, so it kinda makes sense :P
-
@adriweb I thought table.getn was removed after Lua 5.0 and replaced with the # operator.
@epic7 It depends on how Lua was set up on the system. I don't know the details because that gets into complicated C stuff.
I can take a look at your code to see if I can spot an optimization.
-
on.create doesn't work with oclua? No wonder... That should be on Inspired Lua, it'd help a lot. Is there any advantage with using on.create?
-
Is there any advantage with using on.create?
This is what the Nspire Scripting Application Programming Interface document says.
15.13 create
on.create()
This routine is called when the script application is created. The window size and graphics context are valid at this point.
Use this routine to initialize graphical objects based on the window size. Don’t actually paint the screen in this routine since the on.paint event handler will be called soon after this routine finishes.
If you are making an app that depends on the screen size you can then use platform.window:height() or platform.window:width() to do calculations. I suppose you could call it later in the program again. I was just testing to see if I had any issues with it.
-
Ok. Thanks!
-
I never played that game so I have no clue how it goes on, but I'll probably give this a try once it's finished to see how it is. Glad to see you working on Nspire projects. :)
-
I never played that game so I have no clue how it goes on, but I'll probably give this a try once it's finished to see how it is. Glad to see you working on Nspire projects. :)
Same. I don't think I've ever even heard of it... Looks confusing O.O
-
Cool!
How much has to happen in order to get a stack overflow?
Its in an area where some functions call each other, so it kinda makes sense :P
Maybe you're using local variables like they where global variables...
Like in the following part of the code, who is "d"?
function turn() --function finished/near finished
get()
count[land]=0 --reset count
land=click --set to change table pos to click
for e=1, d do
land=land+1
set(find[e])
platform.window:invalidate()
for pause=1, 250 do
end
end
check()
end
Edit: I see now that there's a "d" inside the get() function... Try to set d=0 when the function turn() starts, maybe that's just what it needed... (Since is not reset on the other function...)
-
Hi there epic7, I wanted to PM you but couldn't find how to do it. (I wanted to ask about the progress of this game)
So, I was bored & decided to check the code & fix it (it was the problem I mentioned before that "d" was not reset). Also added a few functions & tweaks, hope you don't mind.
-- GLOBALS --
click=1
land=1
player1=true
extra=false
canMove=true
color={}
find={}
coord={}
coordL={0}
coordR={0}
count={3,3,3,3,3,3,nil,3,3,3,3,3,3,nil}
--------------------------------------------------------------------------------
--function on.create()
--------------------------------------------------------------------------------
local pos=0
for a=1, 14 do
for b=1, 3 do
pos=a*9+b*3-11
if a~=7 and a~=14 then
coord[pos]=a
coord[pos+1]=math.random(0,16)
coord[pos+2]=math.random(0,14)
else
coord[pos]=a
coord[pos+1]=nil
coord[pos+2]=nil
end
end
end
--For the beans colors
for i=1, 42 do
color[i]={math.random(0,255), math.random(0,255), math.random(0,255)}
end
--end
--------------------------------------------------------------------------------
function on.paint(gc)
--------------------------------------------------------------------------------
paintBoard(gc)
local pos=0
for a=1, 42 do
pos=a*3-2
if coord[pos]~=7 and coord[pos]~=14 then
if coord[pos]>7 then
paintSeeds(a, gc, (coord[pos]-7)*34+coord[pos+1]+25, coord[pos+2]+ 49, 10, 10, 0, 360)
else
paintSeeds(a, gc, (coord[pos]-0)*34+coord[pos+1]+25, coord[pos+2]+141, 10, 10, 0, 360)
end
elseif coord[pos]==7 then
if coordR[1]~=0 then
for c=2, coordR[1] do
if coordR[c]==nil then
coordR[c*2]=math.random(0,35)
coordR[c*2+1]=math.random(45,112)
end
paintSeeds(a, gc, coordR[c*2]+263, coordR[c*2+1], 10, 10, 0, 360)
end
end
elseif coord[pos]==14 then
if coordL[1]~=0 then
for c=2, coordL[1] do
if coordL[c]==nil then
coordL[c*2]=math.random(0,35)
coordL[c*2+1]=math.random(0,122)
end
paintSeeds(a, gc, coordL[c*2]+20, coordL[c*2+1], 10, 10, 360)
end
end
end
end
end
--------------------------------------------------------------------------------
function paintBoard(GC)
--------------------------------------------------------------------------------
--Background
GC:setColorRGB(210,240,255)
GC:fillRect(0,0,318,212)
--Text
GC:setColorRGB(0,30,60)
GC:setFont("serif","b",30)
GC:drawString("Mancala",95,0,"top")
GC:setFont("serif","b",10)
GC:drawString("by epic7",255,190,"top")
--Board Fill
GC:setColorRGB(245,222,179)
GC:fillRect(15,40,288,132)
--Board Details
GC:setColorRGB(125,102,59)
GC:drawRect(14,39,289,133) -- Outer border
GC:drawRect(20,45,35,122) -- Left pit
GC:drawRect(263,45,35,122) -- Right pit
--Circles
local width=30
local height=50
for row=0, 1 do
for circle=1, 6 do
GC:drawArc(circle*34+25, row*(122-height)+45, width, height, 0, 360)
end
end
end
--------------------------------------------------------------------------------
function paintSeeds(index, GC, x, y)
--------------------------------------------------------------------------------
local width=10
local height=6
GC:setColorRGB(0, 0, 0) --border
GC:drawArc(x-1, y-1, width+1, height+1, 0, 360)
GC:setColorRGB(unpack(color[index])) --Colored beans
GC:fillArc(x, y, width, height, 0, 360)
end
--------------------------------------------------------------------------------
function setClick() --function finished
--------------------------------------------------------------------------------
if player1 then
click=1
else
click=8
end
end
--------------------------------------------------------------------------------
function win(player)
--------------------------------------------------------------------------------
end
--------------------------------------------------------------------------------
function on.enterKey() --function finished
--------------------------------------------------------------------------------
if canMove then
turn()
canMove=false
end
end
--------------------------------------------------------------------------------
function on.arrowKey(arrow) --function unfinished
--------------------------------------------------------------------------------
if canMove then
if arrow=="left" then
if click>1 then
click=click-1
end
elseif arrow=="right" then
if click<6 then
click=click+1
end
end
end
end
--------------------------------------------------------------------------------
function turn() --function finished/near finished
--------------------------------------------------------------------------------
bean=0
get()
count[land]=0 --reset count
land=click --set to change table pos to click
for a=1, bean do
land=land+1
set(find[a])
platform.window:invalidate()
for pause=1, 250 do
end
end
check()
end
--------------------------------------------------------------------------------
function get() --function finished
--------------------------------------------------------------------------------
for a=1, 42 do
if coord[a*3-2]==click then
bean=1
while find[bean] do
bean=bean+1
end
find[bean]=a
end
end
end
--------------------------------------------------------------------------------
function set(num) --function finished
--------------------------------------------------------------------------------
toset=num*3-2
if land~=7 and land~=14 then --if not near mancala
count[land]=count[land]+1
coord[toset]=coord[toset]+1
setrand() --set random coordinates
elseif land==7 then --if before right side mancala
if player1 then --if player 1
coord[toset]=7 --go into mancala
coordR[1]=coordR[1]+1 --add one point
else --if player 2
count[8]=count[8]+1 --add to next slot
coord[toset]=8 --set to 8
land=8 --skip 7
setrand() --set random coordinates
end
elseif land==14 then --same but for left side mancala
if not player1 then
coord[toset]=14
coordL[1]=coordL[1]+1
else
count[1]=count[1]+1
coord[toset]=1
land=1
setrand()
end
end
end
--------------------------------------------------------------------------------
function setrand() --function finished
--------------------------------------------------------------------------------
coord[toset+1]=math.random(0,16)
coord[toset+2]=math.random(0,14)
end
--------------------------------------------------------------------------------
function check() --function unfinished
--------------------------------------------------------------------------------
if count[land]==0 then
--add capture
player1=not player1
canMove=true
setClick()
else
turn()
end
if land==7 or land==14 then
canMove=true
setClick()
end
filled=false
ch=1
while ch<7 and not filled do
if count[ch]==0 then
ch=ch+1
else
filled=true
end
end
if not filled then
win(1)
end
ch=8
filled=false
while ch<14 and not filled do
if count[ch]==0 then
ch=ch+1
else
filled=true
end
end
if not filled then
win(2)
end
end
-
I think you have to have made 5 posts before you gain the option to PM (to prevent spambots from sending messages to users and whatnot).
-
I think the progress of all Lua development has slowed. I'm really enjoying playing Game Boy games on my Nspire, you know? ;)
-
Cool! Ill put that in my code, which currently fails at some stack overflow errors
I haven't done much programming lately
-
Yea, usually that's why topics become inactive, so I wanted to send a PM since I added some tweaks to the code & wouldn't knew if it bothered you or was ok.
Anyway, keep it up epic7 & hope you can finish it soon :)
-
Gawd i used to play this game all the time!
Thanks for bringing back a classic! :D