Connect Four game in Scala - arrays

I'm trying to make a connect four game in scala. Currently i have the board print out and ask player 1 for a move, once player 1 choses a number a board prints out with an X in the column where player 1 chose. then player 2 picks a number. My problem is that once i pick a number that player's letter fills the whole column and you ant build on top of that.
heres an example of what happens
. X . O X . . .
. X . O X . . .
. X . O X . . .
. X . O X . . .
. X . O X . . .
. X . O X . . .
. X . O X . . .
. X . O X . . .
0 1 2 3 4 5 6 7
// Initialize the grid
val table = Array.fill(9,8)('.')
var i = 0;
while(i < 8){
table(8)(i) = (i+'0').toChar
i = i+1;
}
/* printGrid: Print out the grid provided */
def printGrid(table: Array[Array[Char]]) {
table.foreach( x => println(x.mkString(" ")))
}
/*//place of pieces X
def placeMarker(){
val move = readInt
//var currentRow = 7
while (currentRow >= 0)
if (table(currentRow)(move) != ('.')){
currentRow = (currentRow-1)
table(currentRow)(move) = ('X')
return (player2)}
else{
table(currentRow)(move) = ('X')
return (player2)
}
}
//place of pieces O
def placeMarker2(){
val move = readInt
//var currentRow = 7
while (currentRow >= 0)
if (table(currentRow)(move) != ('.')){
currentRow = (currentRow-1)
table(currentRow)(move) = ('O')
return (player1)}
else{
table(currentRow)(move) = ('O')
return (player1)
}
}
*/
def placeMarker1(){
val move = readInt
var currentRow = 7
while (currentRow >= 0)
if (table(currentRow)(move) !=('.'))
{currentRow = (currentRow-1)}
else{table(currentRow)(move) = ('X')}
}
def placeMarker2(){
val move = readInt
var currentRow = 7
while (currentRow >= 0)
if (table(currentRow)(move) !=('.'))
{currentRow = (currentRow-1)}
else{table(currentRow)(move) = ('O')}
}
//player 1
def player1(){
printGrid(table)
println("Player 1 it is your turn. Choose a column 0-7")
placeMarker1()
}
//player 2
def player2(){
printGrid(table)
println("Player 2 it is your turn. Choose a column 0-7")
placeMarker2()
}
for (turn <- 1 to 32){
player1
player2
}

Your global state is messing you up: var currentRow = 7
Instead of trying to keep track of a global "currentRow" across all columns, I'd recommend one of two things:
Keep a separate "currentRow" for each column in a currentRows array.
Just iterate through the column each time you place a piece to find the lowest empty slot.
Actually, it looks like you were originally doing the second suggestion, but you commented out your local currentRow variables and declared a global (instance-level) one instead.

Related

Repeat current poly reduce function on multiple objects that are selected?

I'm looping through multiple objects, but the loop stops before going to the next object.
Created a loop with condition. If condition is met, it calls a ReduceEdge() function. Problem is it will only iterate once and not go to the next object and repeat the procedure.
global proc ReduceEdge()
{
polySelectEdgesEveryN "edgeRing" 2;
polySelectEdgesEveryN "edgeLoop" 1;
polyDelEdge -cv on;
}
string $newSel[] = `ls -sl`;
for($i = 0; $i < size($newSel); $i++)
{
select $newSel[$i];
int $polyEval[] = `polyEvaluate -e $newSel[$i]`;
int $temp = $polyEval[0];
for($k = 0; $k < $temp; $k++)
{
string $polyInfo[] = `polyInfo -fn ($newSel[$i] + ".f[" + $k + "]")`;
$polyInfo = stringToStringArray($polyInfo[$i]," ");
float $vPosX = $polyInfo[2];
float $vPosY = $polyInfo[3];
float $vPosZ = $polyInfo[4];
if($vPosX == 0 && $vPosY == 0 && $vPosZ == 1.0)
{
select ($newSel[$i] + ".e[" + $k + "]");
ReduceEdge();
}
}
}
Expected results:
If I select 4 cylinders, all their edges will reduce by half the current amount.
Actual results:
When 4 cylinders are selected, only one reduces down to half the edges. The rest stay the same.
Since my comment did help you out, I'll try and give a more thorough explanation.
Your first loop (with $i) iterates over each object in your selection. This is fine.
Your second loop (with $k) iterates over the number of edges for the current object in the loop. So far, so good. Though, I'm wondering if it would be more correct to loop of the number of faces...
Now you ask for an array of all face normals of the face at index $k at object $i, with string $polyInfo[] = `polyInfo -fn ($newSel[$i] + ".f[" + $k + "]")`;.
If you try and print the size and values in $polyInfo, you'll realize you have an array with one element, which is the face normal of the particular face you queried just before. Therefore, it will always be element 0, and not $i, which would increases with every iteration.
I have made a Python/PyMEL version of the script, which may be nice for you to see.
import pymel.core as pm
import maya.mel as mel
def reduceEdge():
mel.eval('polySelectEdgesEveryN "edgeRing" 2;')
mel.eval('polySelectEdgesEveryN "edgeLoop" 1;')
pm.polyDelEdge(cv=True)
def reducePoly():
selection = pm.ls(sl=True)
for obj in selection:
for i, face in enumerate(obj.f):
normal = face.getNormal()
if (normal.x == 0.0 and normal.y == 0.0 and normal.z == 1.0):
pm.select(obj + '.e[' + str(i) + ']')
reduceEdge()
reducePoly()

Using Array.Count and match cases F#

I am not sure yet what the problem is, I am trying to go through a ResizeArray and matching the item with the data type, and depending on this, take away the value in a specific field (iSpace) from thespace(which is how much space the inventory has), before returning the final value.
A snippet of my code :
let spaceleft =
let mutable count = 0 //used to store the index to get item from array
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count //creates an error
while count < inventory.Count do
let item = inventory.[count]
match item with
|Weapon weapon ->
thespace <- (thespace - weapon.iSpace)
|Bomb bomb ->
thespace <-(thespace - bomb.iSpace)
|Potion pot ->
thespace <- (thespace - pot.iSpace)
|Armour arm ->
thespace <- (thespace - arm.iSpace)
count <- count+1
thespace
I get an error about Int32, that has to do with the
printf "Count: %i \n" inventory.Count
line
Another problem is that thespace doesn't seem to change, and always returns as 60, although I have checked and inventory is not empty, it always has at least two items, 1 weapon and 1 armour, so thespace should atleast decrease yet it never does.
Other snippets that may help:
let inventory = ResizeArray[]
let initialise =
let mutable listr = roominit
let mutable curroom = 3
let mutable dead = false
inventory.Add(Weapon weap1)
inventory.Add(Armour a1)
let spacetogo = spaceleft //returns 60, although it should not
Also, apart from the iniitialise function, other functions seem not to be able to add items to the inventory properly, eg:
let ok, input = Int32.TryParse(Console.ReadLine())
match ok with
|false ->
printf "The weapon was left here \n"
complete <- false
|true ->
if input = 1 && spaceleft>= a.iSpace then
inventory.Add(Weapon a)
printf "\n %s added to the inventory \n" a.name
complete <- true
else
printf "\n The weapon was left here \n"
complete <- false
complete
You have spaceLeft as a constant value. To make it a function you need to add unit () as a parameter. Here's that change including a modification to make it much simpler (I've included my dummy types):
type X = { iSpace : int }
type Item = Weapon of X | Bomb of X | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let spaceleft () =
let mutable thespace = 60 //the space left in the inventory
printf "Count: %i \n" inventory.Count
for item in inventory do
let itemSpace =
match item with
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace
thespace <- thespace - itemSpace
thespace
spaceleft () // 55
The above code is quite imperative. If you want to make it more functional (and simpler still) you can use Seq.sumBy:
let spaceleft_functional () =
printf "Count: %i \n" inventory.Count
let spaceUsed =
inventory
|> Seq.sumBy (function
| Weapon w -> w.iSpace
| Bomb b -> b.iSpace
| Potion p -> p.iSpace
| Armour a -> a.iSpace)
60 - spaceUsed
Just adding to the accepted answer: you can also match against record labels, as long as your inner types are records. Combine with an intrinsic type extension on the outer DU:
type X = { iSpace : int }
type Y = { iSpace : int }
type Item = Weapon of X | Bomb of Y | Potion of X | Armour of X
let inventory = ResizeArray [ Weapon {iSpace = 2}; Bomb {iSpace = 3} ]
let itemSpace = function
| Weapon { iSpace = s } | Bomb { iSpace = s }
| Potion { iSpace = s } | Armour { iSpace = s } -> s
type Item with static member (+) (a, b) = a + itemSpace b
60 - (Seq.fold (+) 0 inventory)
// val it : int = 55
Otherwise, you could resort to member constraint invocation expressions.
let inline space (x : ^t) = (^t : (member iSpace : int) (x))

Trying to summarize list in arcpy

I have a list of xy points that I'm trying to sum together and identify the centroid, but it only uses the last value in the row. I'm trying to create a centroid for each state, Here's the code:
Total_X1 = 0
Total_Y1 = 0
TotalPop1 = 0
#Cat = "cali"
cntyName1 = "cnty"
stateName1 = "statename"
for row in cursor:
#if row[0] >= : ### for condition that is met
#if row[0]== []:
TheStateName1 = row[0]
thecntyName1 = row[4]
idpoly1 = row[5]
idobject1 = row[6]
stateFIPS1 = row[7]
countyFIPS1 = row[8]
fips1 = row[9]
fipSnum1 = row[10]
fipsNumer1 = row[11]
#totarea = row[12]
XPoint = row [13]
YPoint = row[14]
#print Cat
print TheStateName1
print thecntyName1
print row ### do something with that value!
Total_X1 += row[2] *row[3]
print Total_X1
Total_Y1 += row[1] *row[3]
print Total_Y1
TotalPop1 += row[3]
print TotalPop1
print ""
print "X is: " , Total_X1
print "POP is: " , TotalPop1
centroid_X1 = Total_X1/TotalPop1
print "your x centroid is: ",centroid_X1
print ""
#print Cat
print thecntyName1
print TheStateName1
Any Suggestions, Thanks!
The cursor can only 'see' one row at a time, you have to pull info from that row and store it elsewhere.
loc_list = [(row[0], row[1]) for row in arcpy.da.SearchCursor(dataset, ['X_coord', 'Y_coord'])
Will give you a list of X,Y tuples from your attribute table.
After that you've got multiple options for turning that list of tuples into a spatial dataset before calculating the mean - start by reading the ESRI documentation for arcpy.Point and all the related topics linked, and go from there. If you have 10.3 or above you can use Mean Center once you have a point layer.
You'll probably get a wrong answer if you just take the mean of the X and Y without projecting first, so don't.

creating matrix/array with number and string

I am using matlab. I have a function which at the moment returns 5 arrays, but I want to join the array into a single matrix or just a cell array with heading of each being the output of the current function?
For instance, giving output like:
low_sec lowmid_sec
1 7
2 6
35 5
5 43
Any ideas?
function [low_sec ,lowmid_sec , middle_sec , upmid_sec , upper_sec]= sepfunc(intensdata)lengthofdata=length(intensdata);
count1=0;
count_2=0;
count_3=0;
count_4=0;
count_5=0;
for i= 1:lengthofdata %loop to seperate count number of data in 5 groups
if (intensdata(i,1)<0.05)
count1=count1+1;
elseif (intensdata(i,1)>=0.05 && intensdata(i,1)<0.1)
count_2=count_2+1;
elseif (0.1<=intensdata(i,1) && intensdata(i,1)<0.15)
count_3=count_3+1;
elseif (0.15<=intensdata(i,1) && intensdata(i,1)<0.2)
count_4=count_4+1;
elseif (intensdata(i,1)>=0.2 )
count_5=count_5+1;
end
end
disp(count1);
disp(count_2);
disp(count_3);
disp(count_4);
disp(count_5);
j=1;
k=1;
m=1;
n=1;
x=1;
low_sec=[count1];
lowmid_sec=[count_2];
middle_sec=[count_3];
upmid_sec=[count_4];
upper_sec=[count_5];
for i= 1:lengthofdata %to seperate original data into 5 different sub-groups.
if (intensdata(i,1)<0.05)
low_sec(j,1)=intensdata(i,1);
j=j+1 ;
elseif(0.05<=intensdata(i,1) && intensdata(i,1)<0.1)
lowmid_sec(k,1)=intensdata(i,1);
k=k+1;
elseif(0.1<=intensdata(i,1) && intensdata(i,1)<0.15)
middle_sec(m,1)=intensdata(i,1);
m=m+1;
elseif(0.15<=intensdata(i,1) && intensdata(i,1)<0.2)
upmid_sec(n,1)=intensdata(i,1);
n=n+1;
elseif( intensdata(i,1)>=0.2)
upper_sec(x,1)=intensdata(i,1);
x=x+1;
end
end
You have a few options, ues a cell array as you mentioned, use the new table structure or the easiest would be to just create a struct.
To do this, all you need is to add the following at the end of your function:
sec.low = low_sec;
sec.lowmid = lowmid_sec;
sec.middle = middle_sec;
sec.upmid = upmid_sec;
sec.upper = upper_sec;
and then to change your first line to be:
function sec = sepfunc(intensdata)

Matlab: stepping through an array and incrementing from one value to the next

I have an array:
step1 = [0,0;
0,1;
1,1;
2,3;
3,4;
3,5;
3,6;
3,7;
4,7;
5,7;
6,7;
6,6;
6,5;
6,4;
6,3;
6,2;
5,1];
I want to step through this array and create new arrays for the row and column that increment by 0.1 from one row to another. This is what I did:
z=1;
u=length(step1);
step_b4X = zeros(u,1);
step_b4Y = zeros(u,1);
while z <= length(step1)
step_b4X = step_presentX;
step_presentX(z,1) = step1(z,1);
step_b4Y = step_presentX;
step_presentY(z,1) = step1(z,2);
pathX = step_b4X:0.1:step_presentX;
pathY = step_b4Y:0.1:step_presentY;
z = z+1;
end
I get zeros.
I want pathX = 0:0.1:0....pathY = 0:0.1:1
next pathX = 0:0.1:1....pathY = 1:0.1:1... and so on
If you do
start:increment:end
where start == end, you'll get a scalar equal to start (which is logical).
If you want pathX and pathY to have the same length at each iteration, you'll have to do this:
z = 1;
while z <= length(step1)
currentX = step(z,1); nextX = step(z+1,1);
currentY = step(z,2); nextY = step(z+1,2);
pathX = currentX : 0.1 : nextX;
pathY = currentY : 0.1 : nextY;
if numel(pathX) == 1
pathX = repmat(pathX, numel(pathY),1); end
if numel(pathY) == 1
pathY = repmat(pathY, numel(pathX),1); end
z = z+1;
end
Now you'll have the right arrays at each iteration, that you'll use directly or save in a cell-array for later. If you want everything in one big array, add this to the end of the loop:
pathX_final = [pathX_final; pathX];
pathY_final = [pathY_final; pathY];
and initialize them as empty before the loop, of course.
Alternatively (much cleaner and possibly a bit faster), ditch the whole loop and use interp1:
x = step1(:,1);
y = step1(:,2);
xx = interp1(1:numel(x), x, 1:0.1:numel(x));
yy = interp1(1:numel(y), y, 1:0.1:numel(y));

Resources