Öppen koppning på Da Matteo

Da Matteo (blogg, sida) bjöd till Öppen Koppning och Motaro skickade vidare en inbjudan till mig. Det blev en intressant tillställning som var mycket klurigt. Skulle behövt 10 minuter med varje kaffe och anteckningsblock (jag har minne som en guldfisk) för att komma till några slutsatser. Men det var lite roligt att se vad "proffsen" skrivit upp, på några av deras kommentarer kände man igen sig till 100% (om än jag inte kunnat formulera det själv) och på några andra var det väl mer, "hum, … jasså?".

Lite kul att se folket också. Ägaren talade lite om att en del var "nördar" (fast inte på ett negativt sätt) och tja, som insikt från att sett geocachare, hackers, datanördar, schackspelare, vindrickare, öppenkällkodsmaffios – visst fanns en del likheter. Hum… tidum…

  • Ingen verkade riktigt ha den muntra besatthet som vi geocachare har. Det var en lugnare form av nördar.
  • Det fanns en glad och positiv attityd där man gärna glatt lyssnade på andras åsikter. Mao, de var inte komplett galna "det finns bara en rätt väg och det är min väg" som flera av öppenkällkodsnördarna har.
  • Man var intresserade och nogramma, men samtidigt muntra och icke-pompösa. En kaffedrickare kan likt en öldrickare ha ett sunt förhållande till sin dryck… inte som en del vinkännare där man smått kreverar under överanalysering och term-fetishism. 
  • Stämningen var glad och positiv, dvs folk var socialt kompetenta.

På det hela taget så skulle jag nog anse att i skalor av nörderi så hamnar kaffeälskarna i samma fåra som lite mer kunniga öldrickare eller schackspelare. Dvs att intresset inte går ut över deras förmåga att utstråla en komplett verklighetsfrånvaro eller osund överfokusering på detaljer. De flesta kaffenördarna skulle nog bli chockade om de fick veta hur mycket nördigare företelser som finns. Eller så var helt enkelt de mest nördiga kaffenördarna inte på koppningen 🙂

Mobilfoton

Staty
Någon har busat med statyn… (det är ett mjukisdjur statyn håller i, och har slips, badmössa, och nått guldigt framför ögonen)


Kyrka

Boylan Creme: God tycker jag, men idag var jag i minoritet.

dricka
Welchs: varning. Det tar timmar att dricka upp 33cl Welchs. Den är helt enkelt otroligt äcklig.

Reflektion 1: Jag har alltid undrat vad folk ser i spelatomaterna. De verkar ju helt trista. Idag insåg jag att de nog är lite roliga ändå. Kanske alla som spelar minns SpaceQuest III och letar efter hemliga meddelanden a’la Astro Chicken?

Reflektion 2: Jag hoppas verkligen foik kollar wiki.X.Org innan de klagar på maskinen. Borde ju vara ett minimum innan man antar att den faktiskt är trasig? Den kanske skall se ut så här i denna versionen?

Svår sudoku

Jag tyckte det kunde vara kul att testa om min sudokulösare kunde knäcka sudokus från Minimum Sudoku listan. Det tog lite tid (och såg lite fräsigt ut när man ser hur den börjar försöka forcera fram rätt kombination…). Observera att sudokun jag löst är hämtat från en CC-licensierad lista.

Creative Commons License

Och btw… Nu kan man t.om mata in ledtrådarna direkt i GUI:t! Jag kommer gå till historien som en mästare på GUI design =)

/*
 * Blaufish’s Sudoku solver
 * http://blaufish.blogg.se/
 *
 * Some rights reserved;
 * http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 */

package sudoku;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.DefaultCellEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;

public class Sudoku extends AbstractTableModel implements ActionListener {

    private static final long serialVersionUID = 963848360009930832L;

    int[][] sudoku;

    public Sudoku() {
        sudoku = new int[9][];
        for (int i = 0; i < 9; i++) {
            sudoku[i] = new int[9];
        }
    }

    boolean found = false;

    void search(int colrow) {

        if (colrow == 81) {
            found = true;
        }
        if (found) {
            System.out.print(colrow + " ");
            return;
        }

        int hintRC = sudoku[colrow / 9][colrow % 9];
        if (hintRC != 0) {
            choose(colrow, hintRC, false);
        } else {
            for (int i = 1; i < 10; i++) {
                if (found)
                    break;
                choose(colrow, i, true);
            }
        }
    }

    void choose(int colrow, int value, boolean test) {

        int row = colrow / 9;
        int col = colrow % 9;

        if (test) {

            // Forward search, check hints
            for (int i = col + 1; i < 9; i++) {
                int hintRC = sudoku[row][i];
                if (hintRC != 0 && hintRC == value)
                    return;
            }

            // Forward search, check hints
            for (int i = row + 1; i < 9; i++) {
                int hintRC = sudoku[i][col];
                if (hintRC != 0 && hintRC == value)
                    return;
            }

            // Backward search, check previous choices
            for (int i = 0; i < col; i++)
                if (sudoku[row][i] == value)
                    return;

            // Backward search, check previous choices
            for (int i = 0; i < row; i++)
                if (sudoku[i][col] == value)
                    return;

            // Backward search, check previous choices
            int boxrow = row – row % 3;
            int boxcol = col – col % 3;
            for (int i = boxrow; i < boxrow + 3; i++)
                for (int j = boxcol; j < boxcol + 3; j++)
                    if (sudoku[i][j] == value && !(i == row && j == col))
                        return;

        }

        sudoku[row][col] = value;
        fireTableCellUpdated(row, col);
        search(colrow + 1);
        if (!found && test)
            sudoku[row][col] = 0;
    }

    @Override
    public boolean isCellEditable(int row, int col) {
        return editable;
    }

    @Override
    public void setValueAt(Object value, int row, int col) {
        sudoku[row][col] = (value==null) ? 0 : (Integer) value;
    }

   
    @Override
    public int getColumnCount() {
        return 9;
    }

    @Override
    public int getRowCount() {
        return 9;
    }

    @Override
    public Object getValueAt(int arg0, int arg1) {
        int i = sudoku[arg0][arg1];
        return (i == 0) ? null : new Integer(i);
    }

    private JButton button;

    private JTable table;

    private boolean editable = true;

    public void startGUI() {
        JFrame frame = new JFrame();
        Container pane = frame.getContentPane();
        pane.setLayout(new BorderLayout());
        table = new JTable(this);
       
        JComboBox comboBox = new JComboBox();
        comboBox.addItem(null);
        for(int i=0; i<9; i++) comboBox.addItem(1+i);
        for(int i=0; i<9; i++) table.getColumnModel().getColumn(i).setCellEditor(new DefaultCellEditor(comboBox));
   
       
        JScrollPane jsp = new JScrollPane(table);
        pane.add(jsp, BorderLayout.CENTER);
        button = new JButton("Start");
        button.addActionListener(this);
        pane.add(button, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.setVisible(true);
   
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        Sudoku s = new Sudoku();
        s.startGUI();
   
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        button.setEnabled(false);
        editable = false;
   
        DefaultTableCellRenderer renderer = new SimpleBackgroundCellRenderer();
   
        table.setDefaultRenderer(Integer.class, renderer);
        table.setDefaultRenderer(Object.class, renderer);
        fireTableDataChanged();
   
        new Thread() {
            @Override
            public void run() { search(0); }
        }.start();
    }

    private final class SimpleBackgroundCellRenderer extends
            DefaultTableCellRenderer {
        private static final long serialVersionUID = 2745037389041942434L;
        boolean[][] hint = new boolean[9][];
        {
            for (int r = 0; r < 9; r++) {
                hint[r] = new boolean[9];
                for (int c = 0; c < 9; c++) {
                    hint[r][c] = sudoku[r][c] != 0;
                }
            }
        }
   
        public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus,
                int row, int column) {
            Component cell = super.getTableCellRendererComponent(table,
                    value, isSelected, hasFocus, row, column);
   
            cell.setBackground(hint[row][column] ? Color.lightGray : Color.white);
   
            return cell;
        }
    }

}