Related
I have a system of n equations and n unknown variables under symbol sum. I want to create a loop to solve this system of equations when inputting n.
y := s -> 1/6cos(3s);
A := (k, s) -> piecewise(k <> 0, 1/2exp(ksI)/abs(k), k = 0, ln(2)exp(s0I) - sin(s));
s := (j, n) -> 2jPi/(2*n + 1);
n := 1;
for j from -n to n do
eqn[j] := sum((A(k, s(j, n))) . (a[k]), k = -n .. n) = y(s(j, n));
end do;
eqs := seq(eqn[i], i = -n .. n);
solve({eqs}, {a[i]});
enter image description here
Please help me out!
I added some missing multiplication symbols to your plaintext code, to reproduce it.
restart;
y:=s->1/6*cos(3*s):
A:=(k,s)->piecewise(k<>0,1/2*exp(k*s*I)/abs(k),
k=0,ln(2)*exp(s*I*0)-sin(s)):
s:=(j,n)->2*j*Pi/(2*n+1):
n:=1:
for j from -n to n do
eqn[j]:=add((A(k,s(j,n)))*a[k],k=-n..n)=y(s(j,n));
end do:
eqs:=seq(eqn[i],i=-n..n);
(-1/4+1/4*I*3^(1/2))*a[-1]+(ln(2)+1/2*3^(1/2))*a[0]+(-1/4-1/4*I*3^(1/2))*a[1] = 1/6,
1/2*a[-1]+ln(2)*a[0]+1/2*a[1] = 1/6,
(-1/4-1/4*I*3^(1/2))*a[-1]+(ln(2)-1/2*3^(1/2))*a[0]+(-1/4+1/4*I*3^(1/2))*a[1] = 1/6
You can pass the set of names (for which to solve) as an optional argument. But that has to contain the actual names, and not just the abstract placeholder a[i] as you tried it.
solve({eqs},{seq(a[i],i=-n..n)});
{a[-1] = 1/6*I/ln(2),
a[0] = 1/6/ln(2),
a[1] = -1/6*I/ln(2)}
You could also omit the indeterminate names here, as optional argument to solve (since you wish to solve for all of them, and no other names are present).
solve({eqs});
{a[-1] = 1/6*I/ln(2),
a[0] = 1/6/ln(2),
a[1] = -1/6*I/ln(2)}
For n:=3 and n:=4 it helps solve to get a result quicker here if exp calls are turned into trig calls. Ie,
solve(evalc({eqs}),{seq(a[i],i=-n..n)});
If n is higher than 4 you might have to wait long for an exact (symbolic) result. But even at n:=10 a floating-point result was fast for me. That is, calling fsolve instead of solve.
fsolve({eqs},{seq(a[i],i=-n..n)});
But even that might be unnecessary, as it seems that the following is a solution for n>=3. Here all the variables are set to zero, except a[-3] and a[3] which are both set to 1/2.
cand:={seq(a[i]=0,i=-n..-4),seq(a[i]=0,i=-2..2),
seq(a[i]=0,i=4..n),seq(a[i]=1/2,i=[-3,3])}:
simplify(eval((rhs-lhs)~({eqs}),cand));
{0}
I'm an economics student slowly switching from MATLAB to Julia.
Currently, my problem is that I don't know how to declare (preallocate) a vector that could store interpolations.
Specifically, when I execute something close to:
function MyFunction(i)
# x, y vectors are some functions of 'i' defined here
f = LinearInterpolation(x,y,extrapolation_bc=Line())
return f
end
g = Vector{Function}(undef, N)
for i = 1:N
g[i] = MyFunction(i)
end
I get:
ERROR: LoadError: MethodError: Cannot `convert` an object of type Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}} to an object of type Function
If I, instead of g=Vector{Function}(undef, N), declare g=zeros(N), I get a similar error message (ending with with ...Float64 rather than with ... Function).
When I, instead, declare:
g = Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(N)
I get:
LoadError: MethodError: no method matching Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(::Int64) Closest candidates are: Interpolations.Extrapolation{Float64,1,Interpolations.GriddedInterpolation{Float64,1,Float64,Gridded{Linear},Tuple{Array{Float64,1}}},Gridded{Linear},Line{Nothing}}(::Any, !Matched::Any) where {T, N, ITPT, IT, ET}
When I don't declare "g" at all, then I get:
ERROR: LoadError: UndefVarError: g not defined
Finally, when I declare:
g = Vector{Any}(undef, N)
the code works, though I'm afraid this might induce some type-change of a variable g, thereby slowing down my performance-sensitive code.
How, ideally then, should I declare g in this case?
EDIT:
In reality, my problem is a bit more complex, more like the following:
function MyFunction(i)
# x, y vectors are some functions of 'i' defined here
f = LinearInterpolation(x,y,extrapolation_bc=Line())
h = is a T-vector of some functions of x,y
A = is some matrix depending on x,y
return h, A, f
end
h = Matrix{Function}(undef, T, N)
A = zeros(T,I,N)
g = Vector{Any}(undef, N)
for i = 1:N
h[:,i], A[:,:,i], g[i] = MyFunction(i)
end
So, when I use either comprehension or broadcasting (like h, A, g = [MyFunction(i) for i in 1:N] or h, A, g = MyFunction.(1:N)), as users Benoit and DNS suggested below, the outputs of my function are 3 tuples, h, A, g, each containing {h[i], A[i], g[i]} for i=1,2,3. If I use only 1 output variable on the LHS, instead, i.e.: MyOutput = [MyFunction(i) for i in 1:N] or MyOutput[i] = MyFunction.(1:N), then MyOutput becomes a vector with N tuple entries, every tuple consisting of {h[i], A[i], g[i]} i=1,2,3,...,N. I bet there's a way of extracting these elements from the tuples in MyOutput and filling them inside h[:,i], A[:,:,i], g[i], but that seems a bit cumbersome and slow.
You could do
f = MyFunction(1)
g = Vector{typeof(f)}(undef, N)
g[1] = f
for i = 2:N
g[i] = MyFunction(i)
end
I think also map should figure out the type:
map(MyFunction, 1:N)
A simple solution is to use a comprehension:
g = [MyFunction(i) for i in 1:N]
or elegantly use the dot syntax:
g = MyFunction.(1:N)
(Credit to DNF for the dot-syntax solution suggested in the comments.)
I'm struggling to get some code running to explore the shared memory features to get a fast matrix multiply. But everytime I try this I seem to run into errors that I cannot fathom.
import numpy as np
from numba import cuda, types
m = 128
n = 32
a = np.arange(m*n).reshape(m,n).astype(np.int32)
b = np.arange(m*n).reshape(n,m).astype(np.int32)
c = np.zeros((m, n)).astype(np.int32)
d_a = cuda.to_device(a)
d_b = cuda.to_device(b)
d_c = cuda.to_device(c)
block_size = (m,n)
grid_size = (int(m/n),int(m/n))
#cuda.jit
def mm(a, b, c):
column, row = cuda.grid(2)
sum = 0
# `a_cache` and `b_cache` are already correctly defined
a_cache = cuda.shared.array(block_size, types.int32)
b_cache = cuda.shared.array(block_size, types.int32)
a_cache[cuda.threadIdx.y, cuda.threadIdx.x] = a[row, column]
b_cache[cuda.threadIdx.x, cuda.threadIdx.y] = b[column, row]
cuda.syncthreads()
for i in range(a.shape[1]):
sum += a_cache[row][i] * b_cache[i][column]
c[row][column] = sum
and testing
mm[grid_size, block_size](d_a, d_b, d_c)
solution = a#b
output = d_c.copy_to_host()
keeps resulting in the following error:
CudaAPIError: [700] Call to cuMemcpyDtoH results in UNKNOWN_CUDA_ERROR
After chatting with the provider of one answer, I've updated the function. But still cannot make this work. So for the computation of the sum for each element in the output c we need to loop over the columns of A and the rows of B, using i as the index. We have therefore n*n products. I think the i us correct in the sum, but I cannot seem to get the correct index for the row and column of a and b in the expression for the sum.
import numpy as np
from numba import cuda, types
#cuda.jit
def mm_shared(a, b, c):
column, row = cuda.grid(2)
sum = 0
# `a_cache` and `b_cache` are already correctly defined
a_cache = cuda.shared.array(block_size, types.int32)
b_cache = cuda.shared.array(block_size, types.int32)
a_cache[cuda.threadIdx.x, cuda.threadIdx.y] = a[row, column]
b_cache[cuda.threadIdx.x, cuda.threadIdx.y] = b[row, column]
cuda.syncthreads()
for i in range(a.shape[1]):
sum += a_cache[cuda.threadIdx.x, i] * b_cache[i, cuda.threadIdx.y]
c[row][column] = sum
Your block size is invalid. CUDA devices have a limit of 1024 threads per block. When I run your code I see this:
/opt/miniconda3/lib/python3.7/site-packages/numba/cuda/cudadrv/driver.py in _check_error(self, fname, retcode)
327 _logger.critical(msg, _getpid(), self.pid)
328 raise CudaDriverError("CUDA initialized before forking")
--> 329 raise CudaAPIError(retcode, msg)
330
331 def get_device(self, devnum=0):
CudaAPIError: [1] Call to cuLaunchKernel results in CUDA_ERROR_INVALID_VALUE
When I fix that I see this:
$ cuda-memcheck python somethingsometing.py
========= CUDA-MEMCHECK
========= Invalid __shared__ read of size 4
========= at 0x000008b0 in cudapy::__main__::mm$241(Array<int, int=2, A, mutable, aligned>, Array<int, int=2, A, mutable, aligned>, Array<int, int=2, A, mutable, aligned>)
========= by thread (15,11,0) in block (3,2,0)
========= Address 0x00000ec0 is out of bounds
The why is pretty obvious:
for i in range(a.shape[1]):
sum += a_cache[row][i] * b_cache[i][column]
row and column are dimensions in the execution grid, not the local share memory tile, and similarly i is bounded by the shape of a, not the shape of a_cache (note also that you seemed to lapse in C style 2D array indexing syntax about half way through the code, which is a potential bug if you don't understand the difference between the two in Python).
To fix it you will have to change the indexing and then implement the rest of the code for multiplication (i.e. you must iteratively load the whole row and column slices through the local shared tiles to compute the full dot product for each row/column pair which a block will process).
Note also that
The dimensions you have selected for c are wrong (should be m x m)
The grid size you run the kernel on is also wrong because the dimensions of C are wrong and so your code could never calculate the whole matrix
Even after fixing all of this, it is likely that the results of the multiplication will be incorrect at anything other than trivial sizes because of integer overflow.
#disruptive: Hi, did you find any solution to your problem?
I had the same problem as you but I solved it by restarting the kernel of Jupyter notebook.
My code is slightly different than yours:
def mm_shared(a, b, c):
sum = 0
# `a_cache` and `b_cache` are already correctly defined
a_cache = cuda.shared.array(block_size, types.int32)
b_cache = cuda.shared.array(block_size, types.int32)
col, row = cuda.grid(2)
row = cuda.blockIdx.x * cuda.blockDim.x + cuda.threadIdx.x
col = cuda.blockIdx.y * cuda.blockDim.y + cuda.threadIdx.y
a_cache[cuda.threadIdx.x, cuda.threadIdx.y] = a[row][col]
b_cache[cuda.threadIdx.y, cuda.threadIdx.x] = b[col][row]
for i in range(a.shape[1]):
a_cache[cuda.threadIdx.x, cuda.threadIdx.y] = a[row, cuda.threadIdx.y + i * N]
b_cache[cuda.threadIdx.x, cuda.threadIdx.y] = b[cuda.threadIdx.x + i * N, col]
cuda.syncthreads()
for j in range(N):
sum += a_cache[cuda.threadIdx.x, j] * b_cache[j, cuda.threadIdx.y]
# Wait until all threads finish computing
cuda.syncthreads()
c[row][col] = sum
Please let me know if you have any update.
This is the correct solution:
import numpy as np
from numba import cuda, types
#cuda.jit
def mm_shared(a, b, c):
sum = 0
# `a_cache` and `b_cache` are already correctly defined
a_cache = cuda.shared.array(block_size, types.int32)
b_cache = cuda.shared.array(block_size, types.int32)
# TODO: use each thread to populate one element each a_cache and b_cache
x,y = cuda.grid(2)
tx = cuda.threadIdx.x
ty = cuda.threadIdx.y
bpg = cuda.gridDim.x
TPB = int(N)
for i in range(a.shape[1] / TPB):
a_cache[tx, ty] = a[x, ty + i * TPB]
b_cache[tx, ty] = b[tx + i * TPB, y]
cuda.syncthreads()
for j in range(TPB):#a.shape[1]):
# TODO: calculate the `sum` value correctly using values from the cache
sum += a_cache[tx][j] * b_cache[j][ty]
cuda.syncthreads()
c[x][y] = sum
I am writing a function to compute the intersection between two sorted arrays (which may contain duplicates). So if the input is [0,3,7,7,7,9, 12] and [2,7,7,8, 12] the output should be [7,7,12] for example.
Here is my code:
cimport cython
#cython.wraparound(False)
#cython.cdivision(True)
#cython.boundscheck(False)
def sorting(int[:] A, int[:] B):
cdef Py_ssize_t i = 0
cdef Py_ssize_t j = 0
cdef int lenA = A.shape[0]
cdef int lenB = B.shape[0]
intersect = []
while (i < lenA and j < lenB):
if A[i] == B[j]:
intersect.append(A[i])
i += 1
j += 1
elif A[i] > B[j]:
j += 1
elif A[i] < B[j]:
i += 1
return intersect
As you will see, I use a list to store the answers and append to add the answers as they arrive. I am happy to return a python or numpy array if that will speed things up.
How can I avoid append to speed up the cython?
For this kind of thing you usually want to pre-allocate the array (it's basically free to shrink it later). In this case it can't be longer than the shortest of your input arrays, so that gives you a starting size:
cdef int[::1] intersect = np.array([A.shape[0] if A.shape[0]<B.shape[0] else B.shape[0]],dtype=np.int)
You then just keep a running total of how what index you're at on that array (say k), so append is replaced by:
intersect[k] = A[i]
k += 1
At the end you can either return the memoryview intersect[:k] or convert it to a numpy array with np.asarray(intersect[:k]).
As an aside: I'd remove the Cython directive #cython.cdivision(True) since you aren't doing any division. I believe you should be thinking about whether these directives are useful and if they apply to your code rather than blindly copying them in out of habit.
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
Code Golf: Rotating Maze
Make a program that takes in a file consisting of a maze. The maze has walls given by #. The maze must include a single ball, given by a o and any number of holes given by a #. The maze file can either be entered via command line or read in as a line through standard input. Please specify which in your solution.
Your program then does the following:
1: If the ball is not directly above a wall, drop it down to the nearest wall.
2: If the ball passes through a hole during step 1, remove the ball.
3: Display the maze in the standard output (followed by a newline).
Extraneous whitespace should not be displayed.
Extraneous whitespace is defined to be whitespace outside of a rectangle
that fits snugly around the maze.
4: If there is no ball in the maze, exit.
5: Read a line from the standard input.
Given a 1, rotate the maze counterclockwise.
Given a 2, rotate the maze clockwise.
Rotations are done by 90 degrees.
It is up to you to decide if extraneous whitespace is allowed.
If the user enters other inputs, repeat this step.
6: Goto step 1.
You may assume all input mazes are closed. Note: a hole effectively acts as a wall in this regard.
You may assume all input mazes have no extraneous whitespace.
The shortest source code by character count wins.
Example written in javascript:
http://trinithis.awardspace.com/rotatingMaze/maze.html
Example mazes:
######
#o ##
######
###########
#o #
# ####### #
#### #
#########
###########################
# #
# # # #
# # # ##
# # ####o####
# # #
# #
# #########
# #
######################
Perl, 143 (128) char
172 152 146 144 143 chars,
sub L{my$o;$o.=$/while s/.$/$o.=$&,""/meg;$_=$o}$_.=<>until/
/;{L;1while s/o / o/;s/o#/ #/;L;L;L;print;if(/o/){1-($z=<>)||L;$z-2||L&L&L;redo}}
Newlines are significant.
Uses standard input and expects input to contain the maze, followed by a blank line, followed by the instructions (1 or 2), one instruction per line.
Explanation:
sub L{my$o;$o.="\n"while s/.$/$o.=$&,""/meg;$_=$o}
L is a function that uses regular expressions to rotate the multi-line expression $_ counterclockwise by 90 degrees. The regular expression was used famously by hobbs in my favorite code golf solution of all time.
$_.=<>until/\n\n/;
Slurps the input up to the first pair of consecutive newlines (that is, the maze) into $_.
L;1 while s/o / o/;s/o#/ */;
L;L;L;print
To drop the ball, we need to move the o character down one line is there is a space under it. This is kind of hard to do with a single scalar expression, so what we'll do instead is rotate the maze counterclockwise, move the ball to the "right". If a hole ever appears to the "right" of the ball, then the ball is going to fall in the hole (it's not in the spec, but we can change the # to an * to show which hole the ball fell into). Then before we print, we need to rotate the board clockwise 90 degrees (or counterclockwise 3 times) so that down is "down" again.
if(/o/) { ... }
Continue if there is still a ball in the maze. Otherwise the block will end and the program will exit.
1-($z=<>)||L;$z-2||L+L+L;redo
Read an instruction into $z. Rotate the board counterclockwise once for instruction "1" and three times for instruction "2".
If we used 3 more characters and said +s/o[#*]/ */ instead of ;s/o#/ */, then we could support multiple balls.
A simpler version of this program, where the instructions are "2" for rotating the maze clockwise and any other instruction for rotating counterclockwise, can be done in 128 chars.
sub L{my$o;$o.=$/while s/.$/$o.=$&,""/meg;$_=$o}$_.=<>until/
/;L;{1while s/o / o/+s/o#/ #/;L,L,L;print;if(/o/){2-<>&&L,L;redo}}
GolfScript - 97 chars
n/['']/~{;(#"zip-1%":|3*~{{." o"/"o "*"#o"/"# "*.#>}do}%|~.n*."o"/,(}{;\~(2*)|*~\}/\[n*]+n.+*])\;
This isn't done as well as I hoped (maybe later).
(These are my notes and not an explanation)
n/['']/~ #[M I]
{
;(# #[I c M]
"zip-1%":|3*~ #rotate
{{." o"/"o "*"#o"/"# "*.#>}do}% #drop
|~ #rotate back
.n* #"display" -> [I c M d]
."o"/,( #any ball? -> [I c M d ?]
}{ #d is collected into an array -> [I c M]
;\~(2*)|*~ #rotate
\ #stack order
}/
\[n*]+n.+*])\; #output
Rebmu: 298 Characters
I'm tinkering with with my own experiment in Code Golf language design! I haven't thrown matrix tricks into the standard bag yet, and copying GolfScript's ideas will probably help. But right now I'm working on refining the basic gimmick.
Anyway, here's my first try. The four internal spaces are required in the code as it is, but the line breaks are not necessary:
.fFS.sSC L{#o#}W|[l?fM]H|[l?m]Z|[Tre[wH]iOD?j[rvT]t]
Ca|[st[xY]a KrePC[[yBKx][ntSBhXbkY][ntSBhYsbWx][xSBwY]]ntJskPCmFkSk]
Ga|[rtYsZ[rtXfZ[TaRE[xY]iTbr]iTbr]t]B|[gA|[ieSlFcA[rnA]]]
MeFI?a[rlA]aFV[NbIbl?n[ut[++n/2 TfCnIEfLtBRchCbSPieTHlTbrCHcNsLe?sNsZ]]
gA|[TfCaEEfZfA[prT][pnT]nn]ulBbr JmoADjPC[3 1]rK4]
It may look like a cat was on my keyboard. But once you get past a little space-saving trick (literally saving spaces) called "mushing" it's not so bad. The idea is that Rebmu is not case sensitive, so alternation of capitalization runs is used to compress the symbols. Instead of doing FooBazBar => foo baz bar I apply distinct meanings. FOObazBAR => foo: baz bar (where the first token is an assignment target) vs fooBAZbar => foo baz bar (all ordinary tokens).
When the unmush is run, you get something more readable, but expanded to 488 characters:
. f fs . s sc l: {#o#} w: | [l? f m] h: | [l? m] z: | [t: re [w h] i od?
j [rv t] t] c: a| [st [x y] a k: re pc [[y bk x] [nt sb h x bk y] [nt sb
h y sb w x] [x sb w y]] nt j sk pc m f k s k] g: a| [rt y s z [rt x f z
[t: a re [x y] i t br] i t br] rn t] b: | [g a| [ie s l f c a [rn a]]]
m: e fi? a [rl a] a fv [n: b i bl? n [ut [++ n/2 t: f c n ie f l t br
ch c b sp ie th l t br ch c n s l e? s n s z]] g a| [t: f c a ee f z f
a [pr t] [pn t] nn] ul b br j: mo ad j pc [3 1] r k 4]
Rebmu can run it expanded also. There are also verbose keywords as well (first instead of fs) and you can mix and match. Here's the function definitions with some comments:
; shortcuts f and s extracting the first and second series elements
. f fs
. s sc
; character constants are like #"a", this way we can do fL for #"#" etc
L: {#o#}
; width and height of the input data
W: | [l? f m]
H: | [l? m]
; dimensions adjusted for rotation (we don't rotate the array)
Z: | [t: re [w h] i od? j [rv t] t]
; cell extractor, gives series position (like an iterator) for coordinate
C: a| [
st [x y] a
k: re pc [[y bk x] [nt sb h x bk y] [nt sb h y sb w x] [x sb w y]] nt j
sk pc m f k s k
]
; grid enumerator, pass in function to run on each cell
G: a| [rt y s z [rt x f z [t: a re [x y] i t br] i t br] t]
; ball position function
B: | [g a| [ie sc l f c a [rn a]]]
W is the width function and H is the height of the original array data. The data is never rotated...but there is a variable j which tells us how many 90 degree right turns we should apply.
A function Z gives us the adjusted size for when rotation is taken into account, and a function C takes a coordinate pair parameter and returns a series position (kind of like a pointer or iterator) into the data for that coordinate pair.
There's an array iterator G which you pass a function to and it will call that function for each cell in the grid. If the function you supply ever returns a value it will stop the iteration and the iteration function will return that value. The function B scans the maze for a ball and returns coordinates if found, or none.
Here's the main loop with some commenting:
; if the command line argument is a filename, load it, otherwise use string
m: e fi? a [rl a] a
; forever (until break, anyway...)
fv [
; save ball position in n
n: B
; if n is a block type then enter a loop
i bl? n [
; until (i.e. repeat until)
ut [
; increment second element of n (the y coordinate)
++ n/2
; t = first(C(n))
t: f C n
; if-equal(first(L), t) then break
ie f l t br
; change(C(B), space)
ch C B sp
; if-equal(third(L),t) then break
ie th L t br
; change(C(n), second(L))
ch C n s L
; terminate loop if "equals(second(n), second(z))"
e? s n s z
]
]
; iterate over array and print each line
g a| [t: f c a ee f z f a [pr t] [pn t] nn]
; unless the ball is not none, we'll be breaking the loop here...
ul b br
; rotate according to input
j: mo ad j pc [3 1] r k 4
]
There's not all that much particularly clever about this program. Which is part of my idea, which is to see what kind of compression one could get on simple, boring approaches that don't rely on any tricks. I think it demonstrates some of Rebmu's novel potential.
It will be interesting to see how a better standard library could affect the brevity of solutions!
Latest up-to-date commented source available on GitHub: rotating-maze.rebmu
Ruby 1.9.1 p243
355 353 characters
I'm pretty new to Ruby, so I'm sure this could be a lot shorter - theres probably some nuances i'm missing.
When executed, the path to the map file is the first line it reads. I tried to make it part of the execution arguments (would have saved 3 characters), but had issues :)
The short version:
def b m;m.each_index{|r|i=m[r].index(?o);return r,i if i}end;def d m;x,y=b m;z=x;
while z=z+1;c=m[z][y];return if c==?#;m[z-1][y]=" "; return 1 if c==?#;m[z][y]=?o;end;end;
def r m;m.transpose.reverse;end;m=File.readlines(gets.chomp).map{|x|x.chomp.split(//)};
while a=0;w=d m;puts m.map(&:join);break if w;a=gets.to_i until 0<a&&a<3;
m=r a==1?m:r(r(m));end
The verbose version:
(I've changed a bit in the compressed version, but you get the idea)
def display_maze m
puts m.map(&:join)
end
def ball_pos m
m.each_index{ |r|
i = m[r].index("o")
return [r,i] if i
}
end
def drop_ball m
x,y = ball_pos m
z=x
while z=z+1 do
c=m[z][y]
return if c=="#"
m[z-1][y]=" "
return 1 if c=="#"
m[z][y]="o"
end
end
def rot m
m.transpose.reverse
end
maze = File.readlines(gets.chomp).map{|x|x.chomp.split(//)}
while a=0
win = drop_ball maze
display_maze maze
break if win
a=gets.to_i until (0 < a && a < 3)
maze=rot maze
maze=rot rot maze if a==1
end
Possible improvement areas:
Reading the maze into a clean 2D array (currently 55 chars)
Finding and returning (x,y) co-ordinates of the ball (currently 61 chars)
Any suggestions to improve are welcome.
Haskell: 577 509 527 244 230 228 chars
Massive new approach: Keep the maze as a single string!
import Data.List
d('o':' ':x)=' ':(d$'o':x)
d('o':'#':x)=" *"++x
d(a:x)=a:d x
d e=e
l=unlines.reverse.transpose.lines
z%1=z;z%2=l.l$z
t=putStr.l.l.l
a z|elem 'o' z=t z>>readLn>>=a.d.l.(z%)|0<1=t z
main=getLine>>=readFile>>=a.d.l
Nods to #mobrule's Perl solution for the idea of dropping the ball sideways!
Python 2.6: ~ 284 ~ characters
There is possibly still room for improvement (although I already got it down a lot since the first revisions).
All comments or suggestions more then welcome!
Supply the map file on the command line as the first argument:
python rotating_maze.py input.txt
import sys
t=[list(r)[:-1]for r in open(sys.argv[1])]
while t:
x=['o'in e for e in t].index(1);y=t[x].index('o')
while t[x+1][y]!="#":t[x][y],t[x+1][y]=" "+"o#"[t[x+1][y]>" "];x+=1
for l in t:print''.join(l)
t=t[x][y]=='o'and map(list,(t,zip(*t[::-1]),zip(*t)[::-1])[input()])or 0
C# 3.0 - 650 638 characters
(not sure how newlines being counted)
(leading whitespace for reading, not counted)
using System.Linq;
using S=System.String;
using C=System.Console;
namespace R
{
class R
{
static void Main(S[]a)
{
S m=S.Join("\n",a);
bool u;
do
{
m=L(m);
int b=m.IndexOf('o');
int h=m.IndexOf('#',b);
b=m.IndexOf('#',b);
m=m.Replace('o',' ');
u=(b!=-1&b<h|h==-1);
if (u)
m=m.Insert(b-1,"o").Remove(b,1);
m=L(L(L(m)));
C.WriteLine(m);
if (!u) return;
do
{
int.TryParse(C.ReadLine(),out b);
u=b==1|b==2;
m=b==1?L(L(L(m))):u?L(m):m;
}while(!u);
}while(u);
}
static S L(S s)
{
return S.Join("\n",
s.Split('\n')
.SelectMany(z => z.Select((c,i)=>new{c,i}))
.GroupBy(x =>x.i,x=>x.c)
.Select(g => new S(g.Reverse().ToArray()))
.ToArray());
}
}
}
Reads from commandline, here's the test line I used:
"###########" "#o #" "# ####### #" "#### #" " #########"
Relied heavily on mobrule's Perl answer for algorithm.
My Rotation method (L) can probably be improved.
Handles wall-less case.