2016 Update

This commit is contained in:
Tina Müller 2016-12-05 22:15:40 +01:00
parent 948b86eafa
commit dcf5d15da3
7965 changed files with 139854 additions and 31002 deletions

View file

@ -8,10 +8,13 @@ columns at once, as one move.
In an inversion any 1 becomes 0, and any 0 becomes 1 for that
whole row or column.
;The Task:
The task is to create a program to score for the Flipping bits game.
;Task:
Create a program to score for the Flipping bits game.
# The game should create an original random target configuration and a starting configuration.
# Ensure that the starting position is ''never'' the target position.
# The target position must be guaranteed as reachable from the starting position. (One possible way to do this is to generate the start position by legal flips from a random target position. The flips will always be reversible back to the target from the given start position).
# The number of moves taken so far should be shown.
<br>
Show an example of a short game here, on this page, for a 3 by 3 array of bits.
<br><br>

View file

@ -0,0 +1,67 @@
defmodule Flip_game do
@az Enum.map(?a..?z, &List.to_string([&1]))
@in2i Enum.concat(Enum.map(1..26, fn i -> {to_string(i), i} end),
Enum.with_index(@az) |> Enum.map(fn {c,i} -> {c,-i-1} end))
|> Enum.into(Map.new)
def play(n) when n>2 do
target = generate_target(n)
display(n, "Target: ", target)
board = starting_config(n, target)
play(n, target, board, 1)
end
def play(n, target, board, moves) do
display(n, "Board: ", board)
ans = IO.gets("row/column to flip: ") |> String.strip |> String.downcase
new_board = case @in2i[ans] do
i when i in 1..n -> flip_row(n, board, i)
i when i in -1..-n -> flip_column(n, board, -i)
_ -> IO.puts "invalid input: #{ans}"
board
end
if target == new_board do
display(n, "Board: ", new_board)
IO.puts "You solved the game in #{moves} moves"
else
IO.puts ""
play(n, target, new_board, moves+1)
end
end
defp generate_target(n) do
for i <- 1..n, j <- 1..n, into: Map.new, do: {{i, j}, :rand.uniform(2)-1}
end
defp starting_config(n, target) do
Enum.concat(1..n, -1..-n)
|> Enum.take_random(n)
|> Enum.reduce(target, fn x,acc ->
if x>0, do: flip_row(n, acc, x),
else: flip_column(n, acc, -x)
end)
end
defp flip_row(n, board, row) do
Enum.reduce(1..n, board, fn col,acc ->
Map.update!(acc, {row,col}, fn bit -> 1 - bit end)
end)
end
defp flip_column(n, board, col) do
Enum.reduce(1..n, board, fn row,acc ->
Map.update!(acc, {row,col}, fn bit -> 1 - bit end)
end)
end
defp display(n, title, board) do
IO.puts title
IO.puts " #{Enum.join(Enum.take(@az,n), " ")}"
Enum.each(1..n, fn row ->
:io.fwrite "~2w ", [row]
IO.puts Enum.map_join(1..n, " ", fn col -> board[{row, col}] end)
end)
end
end
Flip_game.play(3)

View file

@ -0,0 +1,155 @@
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
public class FlippingBitsGame extends JPanel {
final int maxLevel = 7;
final int minLevel = 3;
private Random rand = new Random();
private int[][] grid, target;
private Rectangle box;
private int n = maxLevel;
private boolean solved = true;
FlippingBitsGame() {
setPreferredSize(new Dimension(640, 640));
setBackground(Color.white);
setFont(new Font("SansSerif", Font.PLAIN, 18));
box = new Rectangle(120, 90, 400, 400);
startNewGame();
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
if (solved) {
startNewGame();
} else {
int x = e.getX();
int y = e.getY();
if (box.contains(x, y))
return;
if (x > box.x && x < box.x + box.width) {
flipCol((x - box.x) / (box.width / n));
} else if (y > box.y && y < box.y + box.height)
flipRow((y - box.y) / (box.height / n));
if (solved(grid, target))
solved = true;
printGrid(solved ? "Solved!" : "The board", grid);
}
repaint();
}
});
}
void startNewGame() {
if (solved) {
n = (n == maxLevel) ? minLevel : n + 1;
grid = new int[n][n];
target = new int[n][n];
do {
shuffle();
for (int i = 0; i < n; i++)
target[i] = Arrays.copyOf(grid[i], n);
shuffle();
} while (solved(grid, target));
solved = false;
printGrid("The target", target);
printGrid("The board", grid);
}
}
void printGrid(String msg, int[][] g) {
System.out.println(msg);
for (int[] row : g)
System.out.println(Arrays.toString(row));
System.out.println();
}
boolean solved(int[][] a, int[][] b) {
for (int i = 0; i < n; i++)
if (!Arrays.equals(a[i], b[i]))
return false;
return true;
}
void shuffle() {
for (int i = 0; i < n * n; i++) {
if (rand.nextBoolean())
flipRow(rand.nextInt(n));
else
flipCol(rand.nextInt(n));
}
}
void flipRow(int r) {
for (int c = 0; c < n; c++) {
grid[r][c] ^= 1;
}
}
void flipCol(int c) {
for (int[] row : grid) {
row[c] ^= 1;
}
}
void drawGrid(Graphics2D g) {
g.setColor(getForeground());
if (solved)
g.drawString("Solved! Click here to play again.", 180, 600);
else
g.drawString("Click next to a row or a column to flip.", 170, 600);
int size = box.width / n;
for (int r = 0; r < n; r++)
for (int c = 0; c < n; c++) {
g.setColor(grid[r][c] == 1 ? Color.blue : Color.orange);
g.fillRect(box.x + c * size, box.y + r * size, size, size);
g.setColor(getBackground());
g.drawRect(box.x + c * size, box.y + r * size, size, size);
g.setColor(target[r][c] == 1 ? Color.blue : Color.orange);
g.fillRect(7 + box.x + c * size, 7 + box.y + r * size, 10, 10);
}
}
@Override
public void paintComponent(Graphics gg) {
super.paintComponent(gg);
Graphics2D g = (Graphics2D) gg;
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
drawGrid(g);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setTitle("Flipping Bits Game");
f.setResizable(false);
f.add(new FlippingBitsGame(), BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
});
}
}

View file

@ -0,0 +1,96 @@
function numOfRows(board) { return board.length; }
function numOfCols(board) { return board[0].length; }
function boardToString(board) {
// First the top-header
var header = ' ';
for (var c = 0; c < numOfCols(board); c++)
header += c + ' ';
// Then the side-header + board
var sideboard = [];
for (var r = 0; r < numOfRows(board); r++) {
sideboard.push(r + ' [' + board[r].join(' ') + ']');
}
return header + '\n' + sideboard.join('\n');
}
function flipRow(board, row) {
for (var c = 0; c < numOfCols(board); c++) {
board[row][c] = 1 - board[row][c];
}
}
function flipCol(board, col) {
for (var r = 0; r < numOfRows(board); r++) {
board[r][col] = 1 - board[r][col];
}
}
function playFlippingBitsGame(rows, cols) {
rows = rows | 3;
cols = cols | 3;
var targetBoard = [];
var manipulatedBoard = [];
// Randomly generate two identical boards.
for (var r = 0; r < rows; r++) {
targetBoard.push([]);
manipulatedBoard.push([]);
for (var c = 0; c < cols; c++) {
targetBoard[r].push(Math.floor(Math.random() * 2));
manipulatedBoard[r].push(targetBoard[r][c]);
}
}
// Naive-scramble one of the boards.
while (boardToString(targetBoard) == boardToString(manipulatedBoard)) {
var scrambles = rows * cols;
while (scrambles-- > 0) {
if (0 == Math.floor(Math.random() * 2)) {
flipRow(manipulatedBoard, Math.floor(Math.random() * rows));
}
else {
flipCol(manipulatedBoard, Math.floor(Math.random() * cols));
}
}
}
// Get the user to solve.
alert(
'Try to match both boards.\n' +
'Enter `r<num>` or `c<num>` to manipulate a row or col or enter `q` to quit.'
);
var input = '', letter, num, moves = 0;
while (boardToString(targetBoard) != boardToString(manipulatedBoard) && input != 'q') {
input = prompt(
'Target:\n' + boardToString(targetBoard) +
'\n\n\n' +
'Board:\n' + boardToString(manipulatedBoard)
);
try {
letter = input.charAt(0);
num = parseInt(input.slice(1));
if (letter == 'q')
break;
if (isNaN(num)
|| (letter != 'r' && letter != 'c')
|| (letter == 'r' && num >= rows)
|| (letter == 'c' && num >= cols)
) {
throw new Error('');
}
if (letter == 'r') {
flipRow(manipulatedBoard, num);
}
else {
flipCol(manipulatedBoard, num);
}
moves++;
}
catch(e) {
alert('Uh-oh, there seems to have been an input error');
}
}
if (input == 'q') {
alert('~~ Thanks for playing ~~');
}
else {
alert('Completed in ' + moves + ' moves.');
}
}

View file

@ -0,0 +1,107 @@
FlippingBits := module()
export ModuleApply;
local gameSetup, flip, printGrid, checkInput;
local board;
gameSetup := proc(n)
local r, c, i, toFlip, target;
randomize():
target := Array( 1..n, 1..n, rand(0..1) );
board := copy(target);
for i to rand(3..9)() do
toFlip := [0, 0];
toFlip[1] := StringTools[Random](1, "rc");
toFlip[2] := convert(rand(1..n)(), string);
flip(toFlip);
end do;
return target;
end proc;
flip := proc(line)
local i, lineNum;
lineNum := parse(op(line[2..-1]));
for i to upperbound(board)[1] do
if line[1] = "R" then
board[lineNum, i] := `if`(board[lineNum, i] = 0, 1, 0);
else
board[i, lineNum] := `if`(board[i, lineNum] = 0, 1, 0);
end if;
end do;
return NULL;
end proc;
printGrid := proc(grid)
local r, c;
for r to upperbound(board)[1] do
for c to upperbound(board)[1] do
printf("%a ", grid[r, c]);
end do;
printf("\n");
end do;
printf("\n");
return NULL;
end proc;
checkInput := proc(input)
try
if input[1] = "" then
return false, "";
elif not input[1] = "R" and not input[1] = "C" then
return false, "Please start with 'r' or 'c'.";
elif not type(parse(op(input[2..-1])), posint) then
error;
elif parse(op(input[2..-1])) < 1 or parse(op(input[2..-1])) > upperbound(board)[1] then
return false, "Row or column number too large or too small.";
end if;
catch:
return false, "Please indicate a row or column number."
end try;
return true, "";
end proc;
ModuleApply := proc(n)
local gameOver, toFlip, target, answer, restart;
restart := true;
while restart do
target := gameSetup(n);
while ArrayTools[IsEqual](target, board) do
target := gameSetup(n);
end do;
gameOver := false;
while not gameOver do
printf("The Target:\n");
printGrid(target);
printf("The Board:\n");
printGrid(board);
if ArrayTools[IsEqual](target, board) then
printf("You win!! Press enter to play again or type END to quit.\n\n");
answer := StringTools[UpperCase](readline());
gameOver := true;
if answer = "END" then
restart := false
end if;
else
toFlip := ["", ""];
while not checkInput(toFlip)[1] and not gameOver do
ifelse (not op(checkInput(toFlip)[2..-1]) = "", printf("%s\n\n", op(checkInput(toFlip)[2..-1])), NULL);
printf("Please enter a row or column to flip. (ex: r1 or c2) Press enter for a new game or type END to quit.\n\n");
answer := StringTools[UpperCase](readline());
if answer = "END" or answer = "" then
gameOver := true;
if answer = "END" then
restart := false;
end if;
end if;
toFlip := [substring(answer, 1), substring(answer, 2..-1)];
end do;
if not gameOver then
flip(toFlip);
end if;
end if;
end do;
end do;
printf("Game Over!\n");
end proc;
end module:
FlippingBits(3);

View file

@ -1,86 +1,85 @@
/*REXX program presents a "flipping bit" puzzle, user can solve via C.L.*/
parse arg N u on off . /*get optional arguments. */
if N=='' | N==',' then N=3 /*Size given? Then use default.*/
if u=='' | u==',' then u=N /*number of bits initialized ON.*/
if on =='' then on =1 /*character used for "on". */
if off=='' then off=0 /*character used for "off". */
col@='a b c d e f g h i j k l m n o p q r s t u v w x y z' /*for col id.*/
cols=space(col@,0); upper cols /*letters to be used for columns.*/
@.=off; !.=off /*set both arrays to "off" chars.*/
tries=0 /*# of player's attempts used. */
do while show(0) < u /* [↓] turn "on" U bits.*/
r=random(1,N); c=random(1,N) /*get a random row and column.*/
@.r.c=on ; !.r.c=on /*set (both) row & column to ON*/
end /*while*/ /* [↑] keep going 'til U bits set*/
oz=z /*keep the original array string.*/
call show 1, ' target' /*show target for user to attain.*/
/*REXX program presents a "flipping bit" puzzle. The user can solve via it via C.L. */
parse arg N u on off . /*get optional arguments from the C.L. */
if N=='' | N=="," then N =3 /*Size given? Then use default of 3.*/
if u=='' | u=="," then u =N /*the number of bits initialized to ON.*/
if on =='' then on =1 /*the character used for "on". */
if off=='' then off=0 /* " " " " "off". */
col@= 'a b c d e f g h i j k l m n o p q r s t u v w x y z' /*for the column id.*/
cols=space(col@,0); upper cols /*letters to be used for the columns. */
@.=off; !.=off /*set both arrays to "off" characters.*/
tries=0 /*number of player's attempts (so far).*/
do while show(0) < u /* [↓] turn "on" U number of bits.*/
r=random(1,N); c=random(1,N) /*get a random row and column. */
@.r.c=on ; !.r.c=on /*set (both) row and column to ON. */
end /*while*/ /* [↑] keep going 'til U bits set.*/
oz=z /*keep the original array string. */
call show 1, ' target' /*show target for user to attain. */
do random(1,2); call flip 'R',random(1,N) /*flip a row of bits*/
call flip 'C',random(1,N) /* " " col " " */
end /*random···*/ /* [↑] 1 or 2 times*/
do random(1,2); call flip 'R',random(1,N) /*flip a row of bits. */
call flip 'C',random(1,N) /* " " column " " */
end /*random···*/ /* [↑] just perform 1 or 2 times. */
if z==oz then call flip 'R',random(1,N) /*ensure it's not the target.*/
if z==oz then call flip 'R',random(1,N) /*ensure it's not target we're flipping*/
do until z==oz /*prompt until they get it right.*/
call prompt /*get a row or column # from C.L.*/
call flip left(?,1),substr(?,2) /*flip a user selected row or col*/
call show 0 /*get image (Z) of updated array.*/
do until z==oz /*prompt until they get it right. */
call prompt /*get a row or column number from C.L. */
call flip left(?,1),substr(?,2) /*flip a user selected row or column. */
call show 0 /*get image (Z) of the updated array. */
end /*until···*/
call show 1, ' your array' /*display the array to the screen*/
call show 1, ' your array' /*display the array to the terminal. */
say 'Congrats! You did it in' tries "tries."
exit tries /*stick a fork in it, we're done.*/
/*──────────────────────────────────FLIP subroutine────────────────────────*/
flip: parse arg x,# /*X is R or C, # is which one.*/
do c=1 for N while x=='R'; if @.#.c==on then @.#.c=off; else @.#.c=on; end
do r=1 for N while x=='C'; if @.r.#==on then @.r.#=off; else @.r.#=on; end
return /* [↑] the bits can be ON or OFF*/
/*──────────────────────────────────PROMPTER subroutine─────────────────*/
prompt: if tries\==0 then say 'bit array after play: ' tries
signal on halt /*another way for player to quit.*/
!='Please enter a row number or column letter, or Quit:'
call show 1, ' your array' /*display the array to the screen*/
exit tries /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
halt: say 'program was halted!'; exit /*the REXX program was halted by user. */
isInt: return datatype(arg(1),'W') /*returns 1 if arg is an integer.*/
isLet: return datatype(arg(1),'M') /*returns 1 if arg is a letter. */
terr: if ok then say '***error!***: illegal' arg(1); ok=0; return
/*──────────────────────────────────────────────────────────────────────────────────────*/
flip: parse arg x,# /*X is R or C; #: is which one.*/
do c=1 for N while x=='R'; if @.#.c==on then @.#.c=off; else @.#.c=on; end
do r=1 for N while x=='C'; if @.r.#==on then @.r.#=off; else @.r.#=on; end
return /* [↑] the bits can be ON or OFF. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
prompt: if tries\==0 then say 'bit array after play: ' tries
signal on halt /*another method for the player to quit*/
!='Please enter a row number or column letter, or Quit:'
call show 1, ' your array' /*display the array to the terminal. */
do forever; ok=1; say; say !; pull ? _ . 1 all /*prompt & get ans*/
if abbrev('QUIT',?,1) then do; say 'quitting···'; exit 0; end
if ?=='' then do; call show 1,' target',.; ok=0
call show 1,' your array'
end /* [↑] reshow targ*/
if _\=='' then call terr 'too many args entered:' all
if \isInt(?) & \isLet(?) then call terr 'row/column: ' ?
if isLet(?) then a=pos(?,cols)
if isLet(?) & (a<1 | a>N) then call terr 'column: ' ?
if isLet(?) & length(?)>1 then call terr 'column: ' ?
if isLet(?) then ?='C'pos(?,cols)
if isInt(?) & (?<1 | ?>N) then call terr 'row: ' ?
if isInt(?) then ?=?/1 /*normalize number*/
if isInt(?) then ?='R'?
if ok then leave /*No errors? Leave*/
end /*forever*/ /*endeth da checks*/
do forever; ok=1; say; say !; pull ? _ . 1 all /*prompt & get ans*/
if abbrev('QUIT',?,1) then do; say 'quitting···'; exit 0; end
if ?=='' then do; call show 1," ◄───target",.; ok=0
call show 1," ◄───your array"
end /* [↑] reshow targ*/
if _\=='' then call terr 'too many args entered:' all
if \isInt(?) & \isLet(?) then call terr 'row/column: ' ?
if isLet(?) then a=pos(?,cols)
if isLet(?) & (a<1 | a>N) then call terr 'column: ' ?
if isLet(?) & length(?)>1 then call terr 'column: ' ?
if isLet(?) then ?='C'pos(?,cols)
if isInt(?) & (?<1 | ?>N) then call terr 'row: ' ?
if isInt(?) then ?=?/1 /*normalize number*/
if isInt(?) then ?='R'?
if ok then leave /*No errors? Leave*/
end /*forever*/ /*end of da checks*/
tries=tries+1 /*bump da counter.*/
return ? /*return response.*/
/*──────────────────────────────────SHOW subroutine─────────────────────*/
show: $=0; _=; z=; parse arg tell,tx,o /*$: # of ON bits.*/
if tell then do /*are we telling? */
say /*show blank line.*/
say ' ' subword(col@,1,N) " column letter"
say 'row 'copies('',N+N+1) /*prepend col hdrs*/
end /* [↑] grid hdrs.*/
tries=tries+1 /*bump da counter.*/
return ? /*return response.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
show: $=0; _=; z=; parse arg tell,tx,o /*$: # of ON bits.*/
if tell then do; say /*are we telling? */
say ' ' subword(col@,1,N) " column letter"
say 'row 'copies('',N+N+1) /*prepend col hdrs*/
end /* [↑] grid hdrs.*/
do r=1 for N /*show grid rows.*/
do c=1 for N /*build grid cols.*/
if o==. then do; z=z || !.r.c; _=_ !.r.c; $=$+(!.r.c==on); end
else do; z=z || @.r.c; _=_ @.r.c; $=$+(@.r.c==on); end
end /*c*/ /*··· and sum ONs.*/
if tx\=='' then tar.r=_ tx /*build da target?*/
if tell then say right(r,2) ' '_ tx; _= /*show the grid? */
end /*r*/ /*show a grid row.*/
do r=1 for N /*show grid rows.*/
do c=1 for N /*build grid cols.*/
if o==. then do; z=z || !.r.c; _=_ !.r.c; $=$+(!.r.c==on); end
else do; z=z || @.r.c; _=_ @.r.c; $=$+(@.r.c==on); end
end /*c*/ /*··· and sum ONs.*/
if tx\=='' then tar.r=_ tx /*build da target?*/
if tell then say right(r,2) ' '_ tx; _= /*show the grid? */
end /*r*/ /*show a grid row.*/
if tell then say /*show blank line.*/
return $ /*$: # of ON bits.*/
/*──────────────────────────────────one-liner subroutines───────────────*/
halt: say 'program was halted!'; exit /*the REXX program was halted.*/
isInt: return datatype(arg(1),'W') /*returns 1 if arg is an int. */
isLet: return datatype(arg(1),'M') /*returns 1 if arg is a letter*/
terr: if ok then say '***error!***: illegal' arg(1); ok=0; return
if tell then say /*show blank line.*/
return $ /*$: # of ON bits.*/